Thread: [Ktutorial-commits] SF.net SVN: ktutorial:[151] trunk/ktutorial/ktutorial-editor (Page 2)
Status: Alpha
Brought to you by:
danxuliu
From: <dan...@us...> - 2010-03-13 18:54:41
|
Revision: 151 http://ktutorial.svn.sourceforge.net/ktutorial/?rev=151&view=rev Author: danxuliu Date: 2010-03-13 18:54:34 +0000 (Sat, 13 Mar 2010) Log Message: ----------- Add Reaction class to store the data of reactions (changing to a step or executing some code when an option is selected or a condition is met). Modified Paths: -------------- trunk/ktutorial/ktutorial-editor/src/CMakeLists.txt trunk/ktutorial/ktutorial-editor/tests/unit/CMakeLists.txt Added Paths: ----------- trunk/ktutorial/ktutorial-editor/src/Reaction.cpp trunk/ktutorial/ktutorial-editor/src/Reaction.h trunk/ktutorial/ktutorial-editor/tests/unit/ReactionTest.cpp Modified: trunk/ktutorial/ktutorial-editor/src/CMakeLists.txt =================================================================== --- trunk/ktutorial/ktutorial-editor/src/CMakeLists.txt 2010-03-13 18:38:49 UTC (rev 150) +++ trunk/ktutorial/ktutorial-editor/src/CMakeLists.txt 2010-03-13 18:54:34 UTC (rev 151) @@ -8,6 +8,7 @@ set(ktutorial_editor_SRCS KTutorialEditor.cpp + Reaction.cpp Step.cpp Tutorial.cpp WaitFor.cpp Added: trunk/ktutorial/ktutorial-editor/src/Reaction.cpp =================================================================== --- trunk/ktutorial/ktutorial-editor/src/Reaction.cpp (rev 0) +++ trunk/ktutorial/ktutorial-editor/src/Reaction.cpp 2010-03-13 18:54:34 UTC (rev 151) @@ -0,0 +1,93 @@ +/*************************************************************************** + * 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 "Reaction.h" +#include "WaitFor.h" + +//public: + +Reaction::Reaction(QObject* parent): + QObject(parent), + mWaitFor(0), + mTriggerType(OptionSelected), + mResponseType(NextStep) { +} + +Reaction::~Reaction() { + delete mWaitFor; +} + +Reaction::TriggerType Reaction::triggerType() const { + return mTriggerType; +} + +void Reaction::setTriggerType(TriggerType triggerType) { + mTriggerType = triggerType; + + emit dataChanged(this); +} + +QString Reaction::optionName() const { + return mOptionName; +} + +void Reaction::setOptionName(const QString& optionName) { + mOptionName = optionName; + + emit dataChanged(this); +} + +WaitFor* Reaction::waitFor() const { + return mWaitFor; +} + +void Reaction::setWaitFor(WaitFor* waitFor) { + mWaitFor = waitFor; + + emit dataChanged(this); +} + +Reaction::ResponseType Reaction::responseType() const { + return mResponseType; +} + +void Reaction::setResponseType(ResponseType responseType) { + mResponseType = responseType; + + emit dataChanged(this); +} + +QString Reaction::nextStepId() const { + return mNextStepId; +} + +void Reaction::setNextStepId(const QString& nextStepId) { + mNextStepId = nextStepId; + + emit dataChanged(this); +} + +QString Reaction::customCode() const { + return mCustomCode; +} + +void Reaction::setCustomCode(const QString& customCode) { + mCustomCode = customCode; + + emit dataChanged(this); +} Property changes on: trunk/ktutorial/ktutorial-editor/src/Reaction.cpp ___________________________________________________________________ Added: svn:eol-style + native Added: trunk/ktutorial/ktutorial-editor/src/Reaction.h =================================================================== --- trunk/ktutorial/ktutorial-editor/src/Reaction.h (rev 0) +++ trunk/ktutorial/ktutorial-editor/src/Reaction.h 2010-03-13 18:54:34 UTC (rev 151) @@ -0,0 +1,102 @@ +/*************************************************************************** + * 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 REACTION_H +#define REACTION_H + +#include <QObject> + +class WaitFor; + +/** + * Container for reaction data. + * It stores the data necessary to call addWaitFor and addOption methods in a + * KTutorial::Step. That is, it stores the data that defines how a step reacts. + * + * A reaction is composed by a trigger and a response. The trigger can be the + * user selecting an option of the step, or a condition to wait for that is met. + * The response can be changing to another step, or custom code for complexer + * behavior. + * + * When any attribute is modified, dataChanged(Step*) signal is emitted. + */ +class Reaction: public QObject { +Q_OBJECT +public: + + enum TriggerType { + OptionSelected, + ConditionMet + }; + + enum ResponseType { + NextStep, + CustomCode + }; + + Reaction(QObject* parent = 0); + virtual ~Reaction(); + + TriggerType triggerType() const; + void setTriggerType(TriggerType triggerType); + + QString optionName() const; + void setOptionName(const QString& optionName); + + WaitFor* waitFor() const; + + /** + * Sets the condition to wait for. + * The WaitFor will be destroyed when this Reaction is destroyed. However, + * if a WaitFor is set over a previous one, the previous one must be deleted + * explicitly. + * + * @param waitFor The condition to wait for. + */ + void setWaitFor(WaitFor* waitFor); + + ResponseType responseType() const; + void setResponseType(ResponseType responseType); + + QString nextStepId() const; + void setNextStepId(const QString& nextStepId); + + QString customCode() const; + void setCustomCode(const QString& customCode); + +Q_SIGNALS: + + /** + * Emitted when any data in the reaction changed. + * + * @param reaction This reaction. + */ + void dataChanged(Reaction* reaction); + +private: + + TriggerType mTriggerType; + QString mOptionName; + WaitFor* mWaitFor; + ResponseType mResponseType; + QString mNextStepId; + QString mCustomCode; + +}; + +#endif Property changes on: trunk/ktutorial/ktutorial-editor/src/Reaction.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-13 18:38:49 UTC (rev 150) +++ trunk/ktutorial/ktutorial-editor/tests/unit/CMakeLists.txt 2010-03-13 18:54:34 UTC (rev 151) @@ -15,6 +15,7 @@ ENDMACRO(UNIT_TESTS) unit_tests( + Reaction Step Tutorial WaitForComposed @@ -29,6 +30,7 @@ ENDMACRO(MEM_TESTS) mem_tests( + Reaction Step Tutorial WaitForComposed Added: trunk/ktutorial/ktutorial-editor/tests/unit/ReactionTest.cpp =================================================================== --- trunk/ktutorial/ktutorial-editor/tests/unit/ReactionTest.cpp (rev 0) +++ trunk/ktutorial/ktutorial-editor/tests/unit/ReactionTest.cpp 2010-03-13 18:54:34 UTC (rev 151) @@ -0,0 +1,168 @@ +/*************************************************************************** + * 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 "Reaction.h" +#include "WaitFor.h" + +class ReactionTest: public QObject { +Q_OBJECT + +private slots: + + void initTestCase(); + + void testConstructor(); + + void testSetTriggerType(); + + void testSetOptionName(); + + void testSetWaitFor(); + + void testSetResponseType(); + + void testSetNextStepId(); + + void testSetCustomCode(); + +private: + + int mReactionStarType; + + void assertDataChanged(const QSignalSpy& spy, int index, + Reaction* reaction) const; + +}; + +class MockWaitFor: public WaitFor { +Q_OBJECT +public: + + void emitDataChanged() { + emit dataChanged(this); + } + +}; + +void ReactionTest::initTestCase() { + //Reaction* must be registered in order to be used with QSignalSpy + mReactionStarType = qRegisterMetaType<Reaction*>("Reaction*"); +} + +void ReactionTest::testConstructor() { + QObject parent; + Reaction* reaction = new Reaction(&parent); + + QCOMPARE(reaction->parent(), &parent); + QCOMPARE(reaction->triggerType(), Reaction::OptionSelected); + QCOMPARE(reaction->responseType(), Reaction::NextStep); + QCOMPARE(reaction->waitFor(), (WaitFor*)0); +} + +void ReactionTest::testSetTriggerType() { + Reaction reaction; + + QSignalSpy dataChangedSpy(&reaction, SIGNAL(dataChanged(Reaction*))); + + reaction.setTriggerType(Reaction::ConditionMet); + + QCOMPARE(reaction.triggerType(), Reaction::ConditionMet); + QCOMPARE(dataChangedSpy.count(), 1); + assertDataChanged(dataChangedSpy, 0, &reaction); +} + +void ReactionTest::testSetOptionName() { + Reaction reaction; + + QSignalSpy dataChangedSpy(&reaction, SIGNAL(dataChanged(Reaction*))); + + reaction.setOptionName("The option name"); + + QCOMPARE(reaction.optionName(), QString("The option name")); + QCOMPARE(dataChangedSpy.count(), 1); + assertDataChanged(dataChangedSpy, 0, &reaction); +} + +void ReactionTest::testSetWaitFor() { + Reaction reaction; + + QSignalSpy dataChangedSpy(&reaction, SIGNAL(dataChanged(Reaction*))); + + MockWaitFor* waitFor = new MockWaitFor(); + reaction.setWaitFor(waitFor); + + QCOMPARE(reaction.waitFor(), waitFor); + QCOMPARE(dataChangedSpy.count(), 1); + assertDataChanged(dataChangedSpy, 0, &reaction); +} + +void ReactionTest::testSetResponseType() { + Reaction reaction; + + QSignalSpy dataChangedSpy(&reaction, SIGNAL(dataChanged(Reaction*))); + + reaction.setResponseType(Reaction::CustomCode); + + QCOMPARE(reaction.responseType(), Reaction::CustomCode); + QCOMPARE(dataChangedSpy.count(), 1); + assertDataChanged(dataChangedSpy, 0, &reaction); +} + +void ReactionTest::testSetNextStepId() { + Reaction reaction; + + QSignalSpy dataChangedSpy(&reaction, SIGNAL(dataChanged(Reaction*))); + + reaction.setNextStepId("The id"); + + QCOMPARE(reaction.nextStepId(), QString("The id")); + QCOMPARE(dataChangedSpy.count(), 1); + assertDataChanged(dataChangedSpy, 0, &reaction); +} + +void ReactionTest::testSetCustomCode() { + Reaction reaction; + + QSignalSpy dataChangedSpy(&reaction, SIGNAL(dataChanged(Reaction*))); + + reaction.setCustomCode("The custom code"); + + QCOMPARE(reaction.customCode(), QString("The custom code")); + QCOMPARE(dataChangedSpy.count(), 1); + assertDataChanged(dataChangedSpy, 0, &reaction); +} + +/////////////////////////////////// Helpers //////////////////////////////////// + +//Reaction* must be declared as a metatype to be used in qvariant_cast +Q_DECLARE_METATYPE(Reaction*); + +void ReactionTest::assertDataChanged(const QSignalSpy& spy, int index, + Reaction* reaction) const { + QCOMPARE(spy.at(index).count(), 1); + + QVariant argument = spy.at(index).at(0); + QCOMPARE(argument.userType(), mReactionStarType); + QCOMPARE(qvariant_cast<Reaction*>(argument), reaction); +} + +QTEST_MAIN(ReactionTest) + +#include "ReactionTest.moc" Property changes on: trunk/ktutorial/ktutorial-editor/tests/unit/ReactionTest.cpp ___________________________________________________________________ Added: svn:eol-style + native This was sent by the SourceForge.net collaborative development platform, the world's largest Open Source development site. |
From: <dan...@us...> - 2010-03-14 16:42:03
|
Revision: 152 http://ktutorial.svn.sourceforge.net/ktutorial/?rev=152&view=rev Author: danxuliu Date: 2010-03-14 16:41:56 +0000 (Sun, 14 Mar 2010) Log Message: ----------- Ooops, these files were missed in commit 150. Modified Paths: -------------- trunk/ktutorial/ktutorial-editor/src/view/CMakeLists.txt trunk/ktutorial/ktutorial-editor/tests/unit/view/CMakeLists.txt Modified: trunk/ktutorial/ktutorial-editor/src/view/CMakeLists.txt =================================================================== --- trunk/ktutorial/ktutorial-editor/src/view/CMakeLists.txt 2010-03-13 18:54:34 UTC (rev 151) +++ trunk/ktutorial/ktutorial-editor/src/view/CMakeLists.txt 2010-03-14 16:41:56 UTC (rev 152) @@ -5,6 +5,7 @@ EditionDialog.cpp EditionWidget.cpp LicenseWidget.cpp + NewWaitForWidget.cpp StepCustomCodeWidget.cpp StepDataWidget.cpp StepTreeItem.cpp @@ -19,14 +20,19 @@ WaitForComposedTreeItem.cpp WaitForNotTreeItem.cpp WaitForSignalTreeItem.cpp + WaitForSignalWidget.cpp WaitForTreeItem.cpp + WaitForWidget.cpp ) kde4_add_ui_files(ktutorial_editor_view_SRCS CustomCodeWidget.ui LicenseWidget.ui + NewWaitForWidget.ui StepDataWidget.ui TutorialInformationWidget.ui + WaitForSignalWidget.ui + WaitForWidget.ui ) kde4_add_library(ktutorial_editor_view ${ktutorial_editor_view_SRCS}) Modified: trunk/ktutorial/ktutorial-editor/tests/unit/view/CMakeLists.txt =================================================================== --- trunk/ktutorial/ktutorial-editor/tests/unit/view/CMakeLists.txt 2010-03-13 18:54:34 UTC (rev 151) +++ trunk/ktutorial/ktutorial-editor/tests/unit/view/CMakeLists.txt 2010-03-14 16:41:56 UTC (rev 152) @@ -20,6 +20,7 @@ ActionListWidget EditionDialog LicenseWidget + NewWaitForWidget StepCustomCodeWidget StepDataWidget StepTreeItem @@ -34,7 +35,9 @@ WaitForComposedTreeItem WaitForNotTreeItem WaitForSignalTreeItem + WaitForSignalWidget WaitForTreeItem + WaitForWidget ) MACRO(MEM_TESTS) @@ -47,6 +50,7 @@ ActionListWidget EditionDialog LicenseWidget + NewWaitForWidget StepCustomCodeWidget StepDataWidget StepTreeItem @@ -61,5 +65,7 @@ WaitForComposedTreeItem WaitForNotTreeItem WaitForSignalTreeItem + WaitForSignalWidget WaitForTreeItem + WaitForWidget ) This was sent by the SourceForge.net collaborative development platform, the world's largest Open Source development site. |
From: <dan...@us...> - 2010-03-14 18:10:30
|
Revision: 153 http://ktutorial.svn.sourceforge.net/ktutorial/?rev=153&view=rev Author: danxuliu Date: 2010-03-14 17:15:38 +0000 (Sun, 14 Mar 2010) Log Message: ----------- Add ReactionTreeItem to represent a Reaction in a TreeModel. Modified Paths: -------------- trunk/ktutorial/ktutorial-editor/src/view/CMakeLists.txt trunk/ktutorial/ktutorial-editor/tests/unit/view/CMakeLists.txt Added Paths: ----------- trunk/ktutorial/ktutorial-editor/src/view/ReactionTreeItem.cpp trunk/ktutorial/ktutorial-editor/src/view/ReactionTreeItem.h trunk/ktutorial/ktutorial-editor/tests/unit/view/ReactionTreeItemTest.cpp Modified: trunk/ktutorial/ktutorial-editor/src/view/CMakeLists.txt =================================================================== --- trunk/ktutorial/ktutorial-editor/src/view/CMakeLists.txt 2010-03-14 16:41:56 UTC (rev 152) +++ trunk/ktutorial/ktutorial-editor/src/view/CMakeLists.txt 2010-03-14 17:15:38 UTC (rev 153) @@ -6,6 +6,7 @@ EditionWidget.cpp LicenseWidget.cpp NewWaitForWidget.cpp + ReactionTreeItem.cpp StepCustomCodeWidget.cpp StepDataWidget.cpp StepTreeItem.cpp Added: trunk/ktutorial/ktutorial-editor/src/view/ReactionTreeItem.cpp =================================================================== --- trunk/ktutorial/ktutorial-editor/src/view/ReactionTreeItem.cpp (rev 0) +++ trunk/ktutorial/ktutorial-editor/src/view/ReactionTreeItem.cpp 2010-03-14 17:15:38 UTC (rev 153) @@ -0,0 +1,163 @@ +/*************************************************************************** + * 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 "ReactionTreeItem.h" + +#include <KLocalizedString> + +#include "TextTreeItem.h" +#include "WaitForTreeItem.h" +#include "../Reaction.h" + +//public: + +ReactionTreeItem::ReactionTreeItem(Reaction* reaction, TreeItem* parent): + TreeItem(parent), + mReaction(reaction) { + Q_ASSERT(reaction); + + mEmptyTriggerConditionItem = 0; + mTriggerConditionItem = 0; + mTriggerOptionItem = 0; + mResponseCustomCodeItem = 0; + mResponseNextStepItem = 0; + + //Add two dummy childs, as update method expects always to child items + appendChild(new TextTreeItem(this)); + appendChild(new TextTreeItem(this)); + update(reaction); + + connect(reaction, SIGNAL(dataChanged(Reaction*)), + this, SLOT(update(Reaction*))); +} + +QString ReactionTreeItem::text() const { + return i18nc("@item", "Reaction"); +} + +Reaction* ReactionTreeItem::reaction() const { + return mReaction; +} + +//private: + +void ReactionTreeItem::replaceItem(TreeItem* oldItem, TreeItem* newItem) { + Q_ASSERT(oldItem); + Q_ASSERT(newItem); + Q_ASSERT(oldItem->parent()); + Q_ASSERT(oldItem->parent() == newItem->parent()); + + int index = oldItem->childIndex(); + TreeItem* parent = oldItem->parent(); + + parent->removeChild(oldItem); + delete oldItem; + + parent->insertChild(newItem, index); +} + +void ReactionTreeItem::updateConditionItem(Reaction* reaction) { + if (!reaction->waitFor() && !mEmptyTriggerConditionItem) { + mEmptyTriggerConditionItem = new TextTreeItem(this); + mEmptyTriggerConditionItem->setText( + i18nc("@item", "(No condition set)")); + + replaceItem(child(0), mEmptyTriggerConditionItem); + } else if (reaction->waitFor()) { + mTriggerConditionItem = + WaitForTreeItem::treeItemForWaitFor(reaction->waitFor(), this); + + replaceItem(child(0), mTriggerConditionItem); + } +} + +void ReactionTreeItem::updateOptionItem(Reaction* reaction) { + if (!mTriggerOptionItem) { + mTriggerOptionItem = new TextTreeItem(this); + + replaceItem(child(0), mTriggerOptionItem); + } + + QString optionName = reaction->optionName(); + if (optionName.isEmpty()) { + optionName = i18nc("@item", "(option name not set)"); + } else { + optionName = '"' + reaction->optionName() + '"'; + } + + mTriggerOptionItem->setText( + i18nc("@item", "When the option %1 is selected", optionName)); +} + +void ReactionTreeItem::updateCustomCodeItem(Reaction* reaction) { + if (!mResponseCustomCodeItem) { + TextTreeItem* parent = new TextTreeItem(this); + parent->setText(i18nc("@item", "Execute the following code:")); + + mResponseCustomCodeItem = new TextTreeItem(parent); + parent->appendChild(mResponseCustomCodeItem); + + replaceItem(child(1), parent); + } + + if (reaction->customCode().isEmpty()) { + mResponseCustomCodeItem->setText("(No code set)"); + } else { + mResponseCustomCodeItem->setText(reaction->customCode()); + } +} + +void ReactionTreeItem::updateNextStepItem(Reaction* reaction) { + if (!mResponseNextStepItem) { + mResponseNextStepItem = new TextTreeItem(this); + + replaceItem(child(1), mResponseNextStepItem); + } + + QString nextStepId = reaction->nextStepId(); + if (nextStepId.isEmpty()) { + nextStepId = i18nc("@item", "(step id not set)"); + } else { + nextStepId = '"' + reaction->nextStepId() + '"'; + } + + mResponseNextStepItem->setText( + i18nc("@item", "Change to step %1", nextStepId)); +} + +//private slots: + +void ReactionTreeItem::update(Reaction* reaction) { + Q_ASSERT(reaction); + + if (reaction->triggerType() == Reaction::ConditionMet) { + updateConditionItem(reaction); + } + + if (reaction->triggerType() == Reaction::OptionSelected) { + updateOptionItem(reaction); + } + + if (reaction->responseType() == Reaction::CustomCode) { + updateCustomCodeItem(reaction); + } + + if (reaction->responseType() == Reaction::NextStep) { + updateNextStepItem(reaction); + } +} Property changes on: trunk/ktutorial/ktutorial-editor/src/view/ReactionTreeItem.cpp ___________________________________________________________________ Added: svn:eol-style + native Added: trunk/ktutorial/ktutorial-editor/src/view/ReactionTreeItem.h =================================================================== --- trunk/ktutorial/ktutorial-editor/src/view/ReactionTreeItem.h (rev 0) +++ trunk/ktutorial/ktutorial-editor/src/view/ReactionTreeItem.h 2010-03-14 17:15:38 UTC (rev 153) @@ -0,0 +1,191 @@ +/*************************************************************************** + * 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 REACTIONTREEITEM_H +#define REACTIONTREEITEM_H + +#include <QPointer> +#include "TreeItem.h" + +class Reaction; +class TextTreeItem; +class WaitForTreeItem; + +/** + * A TreeItem that represents a Reaction. + * The tree representation of a reaction is: + * Reaction + * |-Trigger + * --Response + * + * Trigger can be either: + * -When the option "optionName" is selected + * or the representation of a WaitFor, depending on the type of trigger. If the + * trigger is an option and there is no option name set, or if the trigger is a + * condition but there is no WaitFor, a placeholder is used instead. Option + * placeholder is "(option name not set)", and condition placeholder is "(No + * condition set)" (without quotes, but with parenthesis). + * + * Response can be either: + * -Change to step "stepId" + * or: + * -Execute the following code: + * -Custom code + * depending on the type of response. If there is no stepId or code set, a + * placeholder is used instead. Step id placeholder is "(step id not set)", and + * code placeholder is "(No code set)" (without quotes, but with parenthesis). + * + * Whenever the reaction data changes, the ReactionTreeItem and its child items + * are updated as needed. + */ +class ReactionTreeItem: public TreeItem { +Q_OBJECT +public: + + /** + * Creates a new ReactionTreeItem for the given Reaction and with the given + * parent. + * + * @param reaction The reaction to represent. + * @param parent The parent TreeItem. + */ + explicit ReactionTreeItem(Reaction* reaction, TreeItem* parent = 0); + + /** + * Returns "Reaction". + * + * @return The text for this TreeItem. + */ + virtual QString text() const; + + /** + * Returns the Reaction. + * + * @return The Reaction. + */ + Reaction* reaction() const; + +private: + + /** + * The Reaction. + */ + Reaction* mReaction; + + /** + * The child item containing the warning text when there is no condition + * but a condition type is used. + * The pointer is automatically set to 0 if the object is deleted anywhere + * (that is, not by deleting this pointer, but another one pointing to the + * object). + */ + QPointer<TextTreeItem> mEmptyTriggerConditionItem; + + /** + * The child item containing the WaitForTreeItem for the condition, when a + * condition type is used. + * The pointer is automatically set to 0 if the object is deleted anywhere + * (that is, not by deleting this pointer, but another one pointing to the + * object). + */ + QPointer<WaitForTreeItem> mTriggerConditionItem; + + /** + * The child item containing the trigger text, when an option type is used. + * The pointer is automatically set to 0 if the object is deleted anywhere + * (that is, not by deleting this pointer, but another one pointing to the + * object). + */ + QPointer<TextTreeItem> mTriggerOptionItem; + + /** + * The child item containing the response text, when the custom code type is + * used. + * This is a nested item. Its parent (and the direct child of this + * ReactionTreeItem) contains the "Execute the following code:" text. + * The pointer is automatically set to 0 if the object is deleted anywhere + * (that is, not by deleting this pointer, but another one pointing to the + * object). + */ + QPointer<TextTreeItem> mResponseCustomCodeItem; + + /** + * The child item containing the response text, when the next step type is + * used. + * The pointer is automatically set to 0 if the object is deleted anywhere + * (that is, not by deleting this pointer, but another one pointing to the + * object). + */ + QPointer<TextTreeItem> mResponseNextStepItem; + + /** + * Replaces the old item with the new item. + * The old item is destroyed. + * + * @param oldItem The item to remove. + * @param newItem The item to insert. + */ + void replaceItem(TreeItem* oldItem, TreeItem* newItem); + + /** + * Sets a new WaitForTreeItem for the WaitFor of the reaction, or a + * TextTreeItem if there is no WaitFor. + * + * @param reaction The reaction to get the WaitFor from. + */ + void updateConditionItem(Reaction* reaction); + + /** + * Sets a new TextTreeItem or modifies the current one with the option name. + * + * @param reaction The reaction to get the option name from. + */ + void updateOptionItem(Reaction* reaction); + + /** + * Sets a new nested TextTreeItem or modifies the current one with the + * custom code. + * + * @param reaction The reaction to get the custom code from. + */ + void updateCustomCodeItem(Reaction* reaction); + + /** + * Sets a new TextTreeItem or modifies the current one with the step id. + * + * @param reaction The reaction to get the step id from. + */ + void updateNextStepItem(Reaction* reaction); + +private Q_SLOTS: + + /** + * Updates this ReactionTreeItem when the data of its reaction changed. + * If a child item is needed to show some data, it is inserted or updated + * (depending on whether it existed previously or not). + * If the child item is no longer needed, it is removed. + * + * Items may be flat or nested, depending on the data to show. + * + * @param reaction The reaction. + */ + void update(Reaction* reaction); + +}; + +#endif Property changes on: trunk/ktutorial/ktutorial-editor/src/view/ReactionTreeItem.h ___________________________________________________________________ Added: svn:eol-style + native Modified: trunk/ktutorial/ktutorial-editor/tests/unit/view/CMakeLists.txt =================================================================== --- trunk/ktutorial/ktutorial-editor/tests/unit/view/CMakeLists.txt 2010-03-14 16:41:56 UTC (rev 152) +++ trunk/ktutorial/ktutorial-editor/tests/unit/view/CMakeLists.txt 2010-03-14 17:15:38 UTC (rev 153) @@ -21,6 +21,7 @@ EditionDialog LicenseWidget NewWaitForWidget + ReactionTreeItem StepCustomCodeWidget StepDataWidget StepTreeItem @@ -51,6 +52,7 @@ EditionDialog LicenseWidget NewWaitForWidget + ReactionTreeItem StepCustomCodeWidget StepDataWidget StepTreeItem Added: trunk/ktutorial/ktutorial-editor/tests/unit/view/ReactionTreeItemTest.cpp =================================================================== --- trunk/ktutorial/ktutorial-editor/tests/unit/view/ReactionTreeItemTest.cpp (rev 0) +++ trunk/ktutorial/ktutorial-editor/tests/unit/view/ReactionTreeItemTest.cpp 2010-03-14 17:15:38 UTC (rev 153) @@ -0,0 +1,465 @@ +/*************************************************************************** + * 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 "ReactionTreeItem.h" + +#include <KLocalizedString> + +#include "WaitForTreeItem.h" +#include "../Reaction.h" +#include "../WaitForSignal.h" + +class ReactionTreeItemTest: public QObject { +Q_OBJECT + +private slots: + + void initTestCase(); + + void testConstructorConditionCustomCode(); + void testConstructorOptionNextStep(); + void testConstructorConditionCustomCodeFull(); + void testConstructorOptionNextStepFull(); + + void testReactionSetOptionName(); + void testReactionSetOptionNameChange(); + void testReactionSetOptionNameEmpty(); + + void testReactionSetWaitFor(); + void testReactionSetWaitForChange(); + void testReactionSetWaitForNull(); + + void testReactionSetNextStepId(); + void testReactionSetNextStepIdChange(); + void testReactionSetNextStepIdEmpty(); + + void testReactionSetCustomCode(); + void testReactionSetCustomCodeChange(); + void testReactionSetCustomCodeEmpty(); + + void testReactionSetTriggerTypeToOptionSelected(); + void testReactionSetTriggerTypeToConditionMet(); + + void testReactionSetResponseTypeToNextStep(); + void testReactionSetResponseTypeToCustomCode(); + +private: + + int mTreeItemStarType; + + void assertText(TreeItem* textItem, const QString& licenseText) const; + + void assertWaitFor(TreeItem* item, WaitFor* waitFor) const; + + void assertCustomCode(TreeItem* textItem, const QString& code) const; + + void assertDataChanged(const QSignalSpy& spy, int index, + TreeItem* item) const; + +}; + +class StubTreeItem: public TreeItem { +public: + virtual QString text() const { + return ""; + } +}; + +void ReactionTreeItemTest::initTestCase() { + //TreeItem* must be registered in order to be used with QSignalSpy + mTreeItemStarType = qRegisterMetaType<TreeItem*>("TreeItem*"); +} + +void ReactionTreeItemTest::testConstructorConditionCustomCode() { + Reaction reaction; + reaction.setTriggerType(Reaction::ConditionMet); + reaction.setResponseType(Reaction::CustomCode); + + StubTreeItem parent; + ReactionTreeItem item(&reaction, &parent); + + QCOMPARE(item.parent(), &parent); + QCOMPARE(item.text(), i18nc("@item", "Reaction")); + QCOMPARE(item.reaction(), &reaction); + QCOMPARE(item.childCount(), 2); + assertWaitFor(item.child(0), 0); + assertCustomCode(item.child(1), i18nc("@item", "(No code set)")); +} + +void ReactionTreeItemTest::testConstructorOptionNextStep() { + Reaction reaction; + reaction.setTriggerType(Reaction::OptionSelected); + reaction.setResponseType(Reaction::NextStep); + + StubTreeItem parent; + ReactionTreeItem item(&reaction, &parent); + + QCOMPARE(item.parent(), &parent); + QCOMPARE(item.text(), i18nc("@item", "Reaction")); + QCOMPARE(item.reaction(), &reaction); + QCOMPARE(item.childCount(), 2); + assertText(item.child(0), i18nc("@item", "When the option (option name not " + "set) is selected")); + assertText(item.child(1), i18nc("@item", "Change to step (step id not " + "set)")); +} + +void ReactionTreeItemTest::testConstructorConditionCustomCodeFull() { + WaitFor* waitFor = new WaitForSignal(); + Reaction reaction; + reaction.setTriggerType(Reaction::ConditionMet); + reaction.setWaitFor(waitFor); + reaction.setResponseType(Reaction::CustomCode); + reaction.setCustomCode("The custom code"); + + StubTreeItem parent; + ReactionTreeItem item(&reaction, &parent); + + QCOMPARE(item.parent(), &parent); + QCOMPARE(item.text(), i18nc("@item", "Reaction")); + QCOMPARE(item.reaction(), &reaction); + QCOMPARE(item.childCount(), 2); + assertWaitFor(item.child(0), waitFor); + assertCustomCode(item.child(1), "The custom code"); +} + +void ReactionTreeItemTest::testConstructorOptionNextStepFull() { + Reaction reaction; + reaction.setTriggerType(Reaction::OptionSelected); + reaction.setOptionName("The option name"); + reaction.setResponseType(Reaction::NextStep); + reaction.setNextStepId("The step id"); + + StubTreeItem parent; + ReactionTreeItem item(&reaction, &parent); + + QCOMPARE(item.parent(), &parent); + QCOMPARE(item.text(), i18nc("@item", "Reaction")); + QCOMPARE(item.reaction(), &reaction); + QCOMPARE(item.childCount(), 2); + assertText(item.child(0), i18nc("@item", "When the option \"The option " + "name\" is selected")); + assertText(item.child(1), i18nc("@item", "Change to step \"The step id\"")); +} + +void ReactionTreeItemTest::testReactionSetOptionName() { + Reaction reaction; + reaction.setTriggerType(Reaction::OptionSelected); + + ReactionTreeItem item(&reaction); + + QSignalSpy dataChangedSpy(item.child(0), SIGNAL(dataChanged(TreeItem*))); + + reaction.setOptionName("The option name"); + + QCOMPARE(item.childCount(), 2); + assertText(item.child(0), i18nc("@item", "When the option \"The option " + "name\" is selected")); + QCOMPARE(dataChangedSpy.count(), 1); + assertDataChanged(dataChangedSpy, 0, item.child(0)); +} + +void ReactionTreeItemTest::testReactionSetOptionNameChange() { + Reaction reaction; + reaction.setTriggerType(Reaction::OptionSelected); + + ReactionTreeItem item(&reaction); + + reaction.setOptionName("The option name"); + + QSignalSpy dataChangedSpy(item.child(0), SIGNAL(dataChanged(TreeItem*))); + + reaction.setOptionName("The new option name"); + + QCOMPARE(item.childCount(), 2); + assertText(item.child(0), i18nc("@item", "When the option \"The new option " + "name\" is selected")); + QCOMPARE(dataChangedSpy.count(), 1); + assertDataChanged(dataChangedSpy, 0, item.child(0)); +} + +void ReactionTreeItemTest::testReactionSetOptionNameEmpty() { + Reaction reaction; + reaction.setTriggerType(Reaction::OptionSelected); + reaction.setOptionName("The option name"); + + ReactionTreeItem item(&reaction); + + QSignalSpy dataChangedSpy(item.child(0), SIGNAL(dataChanged(TreeItem*))); + + reaction.setOptionName(""); + + QCOMPARE(item.childCount(), 2); + assertText(item.child(0), i18nc("@item", "When the option (option name not " + "set) is selected")); + QCOMPARE(dataChangedSpy.count(), 1); + assertDataChanged(dataChangedSpy, 0, item.child(0)); +} + +void ReactionTreeItemTest::testReactionSetWaitFor() { + WaitForSignal* waitFor = new WaitForSignal(); + Reaction reaction; + reaction.setTriggerType(Reaction::ConditionMet); + + ReactionTreeItem item(&reaction); + + reaction.setWaitFor(waitFor); + + QCOMPARE(item.childCount(), 2); + assertWaitFor(item.child(0), waitFor); +} + +void ReactionTreeItemTest::testReactionSetWaitForChange() { + //It will be removed and not deleted by the Reaction, so it is created in + //stack + WaitForSignal waitFor; + + WaitForSignal* waitFor2 = new WaitForSignal(); + Reaction reaction; + reaction.setTriggerType(Reaction::ConditionMet); + + ReactionTreeItem item(&reaction); + + reaction.setWaitFor(&waitFor); + reaction.setWaitFor(waitFor2); + + QCOMPARE(item.childCount(), 2); + assertWaitFor(item.child(0), waitFor2); +} + +void ReactionTreeItemTest::testReactionSetWaitForNull() { + //It will be removed and not deleted by the Reaction, so it is created in + //stack + WaitForSignal waitFor; + + Reaction reaction; + reaction.setTriggerType(Reaction::ConditionMet); + reaction.setWaitFor(&waitFor); + + ReactionTreeItem item(&reaction); + + reaction.setWaitFor(0); + + QCOMPARE(item.childCount(), 2); + assertWaitFor(item.child(0), 0); +} + +void ReactionTreeItemTest::testReactionSetNextStepId() { + Reaction reaction; + reaction.setResponseType(Reaction::NextStep); + + ReactionTreeItem item(&reaction); + + QSignalSpy dataChangedSpy(item.child(1), SIGNAL(dataChanged(TreeItem*))); + + reaction.setNextStepId("The step id"); + + QCOMPARE(item.childCount(), 2); + assertText(item.child(1), i18nc("@item", "Change to step \"The step id\"")); + QCOMPARE(dataChangedSpy.count(), 1); + assertDataChanged(dataChangedSpy, 0, item.child(1)); +} + +void ReactionTreeItemTest::testReactionSetNextStepIdChange() { + Reaction reaction; + reaction.setResponseType(Reaction::NextStep); + + ReactionTreeItem item(&reaction); + + reaction.setNextStepId("The step id"); + + QSignalSpy dataChangedSpy(item.child(1), SIGNAL(dataChanged(TreeItem*))); + + reaction.setNextStepId("The new step id"); + + QCOMPARE(item.childCount(), 2); + assertText(item.child(1), i18nc("@item", "Change to step \"The new step " + "id\"")); + QCOMPARE(dataChangedSpy.count(), 1); + assertDataChanged(dataChangedSpy, 0, item.child(1)); +} + +void ReactionTreeItemTest::testReactionSetNextStepIdEmpty() { + Reaction reaction; + reaction.setResponseType(Reaction::NextStep); + reaction.setNextStepId("The step id"); + + ReactionTreeItem item(&reaction); + + QSignalSpy dataChangedSpy(item.child(1), SIGNAL(dataChanged(TreeItem*))); + + reaction.setNextStepId(""); + + QCOMPARE(item.childCount(), 2); + assertText(item.child(1), i18nc("@item", "Change to step (step id not " + "set)")); + QCOMPARE(dataChangedSpy.count(), 1); + assertDataChanged(dataChangedSpy, 0, item.child(1)); +} + +void ReactionTreeItemTest::testReactionSetCustomCode() { + Reaction reaction; + reaction.setResponseType(Reaction::CustomCode); + + ReactionTreeItem item(&reaction); + + QSignalSpy dataChangedSpy(item.child(1)->child(0), + SIGNAL(dataChanged(TreeItem*))); + + reaction.setCustomCode("The custom code"); + + QCOMPARE(item.childCount(), 2); + assertCustomCode(item.child(1), "The custom code"); + QCOMPARE(dataChangedSpy.count(), 1); + assertDataChanged(dataChangedSpy, 0, item.child(1)->child(0)); +} + +void ReactionTreeItemTest::testReactionSetCustomCodeChange() { + Reaction reaction; + reaction.setResponseType(Reaction::CustomCode); + + ReactionTreeItem item(&reaction); + + reaction.setCustomCode("The custom code"); + + QSignalSpy dataChangedSpy(item.child(1)->child(0), + SIGNAL(dataChanged(TreeItem*))); + + reaction.setCustomCode("The new custom code"); + + QCOMPARE(item.childCount(), 2); + assertCustomCode(item.child(1), "The new custom code"); + QCOMPARE(dataChangedSpy.count(), 1); + assertDataChanged(dataChangedSpy, 0, item.child(1)->child(0)); +} + +void ReactionTreeItemTest::testReactionSetCustomCodeEmpty() { + Reaction reaction; + reaction.setResponseType(Reaction::CustomCode); + reaction.setCustomCode("The custom code"); + + ReactionTreeItem item(&reaction); + + QSignalSpy dataChangedSpy(item.child(1)->child(0), + SIGNAL(dataChanged(TreeItem*))); + + reaction.setCustomCode(""); + + QCOMPARE(item.childCount(), 2); + assertCustomCode(item.child(1), i18nc("@item", "(No code set)")); + QCOMPARE(dataChangedSpy.count(), 1); + assertDataChanged(dataChangedSpy, 0, item.child(1)->child(0)); +} + +void ReactionTreeItemTest::testReactionSetTriggerTypeToOptionSelected() { + Reaction reaction; + reaction.setTriggerType(Reaction::ConditionMet); + reaction.setOptionName("The option name"); + + ReactionTreeItem item(&reaction); + + reaction.setTriggerType(Reaction::OptionSelected); + + QCOMPARE(item.childCount(), 2); + assertText(item.child(0), i18nc("@item", "When the option \"The option " + "name\" is selected")); +} + +void ReactionTreeItemTest::testReactionSetTriggerTypeToConditionMet() { + WaitForSignal* waitFor = new WaitForSignal(); + Reaction reaction; + reaction.setTriggerType(Reaction::OptionSelected); + reaction.setWaitFor(waitFor); + + ReactionTreeItem item(&reaction); + + reaction.setTriggerType(Reaction::ConditionMet); + + QCOMPARE(item.childCount(), 2); + assertWaitFor(item.child(0), waitFor); +} + +void ReactionTreeItemTest::testReactionSetResponseTypeToNextStep() { + Reaction reaction; + reaction.setResponseType(Reaction::CustomCode); + reaction.setNextStepId("The step id"); + + ReactionTreeItem item(&reaction); + + reaction.setResponseType(Reaction::NextStep); + + QCOMPARE(item.childCount(), 2); + assertText(item.child(1), i18nc("@item", "Change to step \"The step id\"")); +} + +void ReactionTreeItemTest::testReactionSetResponseTypeToCustomCode() { + Reaction reaction; + reaction.setResponseType(Reaction::NextStep); + reaction.setCustomCode("The custom code"); + + ReactionTreeItem item(&reaction); + + reaction.setResponseType(Reaction::CustomCode); + + QCOMPARE(item.childCount(), 2); + assertCustomCode(item.child(1), "The custom code"); +} + +/////////////////////////////////// Helpers //////////////////////////////////// + +void ReactionTreeItemTest::assertText(TreeItem* textItem, + const QString& name) const { + QCOMPARE(textItem->text(), i18nc("@item", "%1", name)); +} + +void ReactionTreeItemTest::assertWaitFor(TreeItem* item, + WaitFor* waitFor) const { + if (!waitFor) { + QCOMPARE(item->text(), i18nc("@item", "(No condition set)")); + return; + } + + WaitForTreeItem* waitForItem = qobject_cast<WaitForTreeItem*>(item); + QVERIFY(waitForItem); + QCOMPARE(waitForItem->waitFor(), waitFor); +} + +void ReactionTreeItemTest::assertCustomCode(TreeItem* textItem, + const QString& code) const { + QCOMPARE(textItem->text(), i18nc("@item", "Execute the following code:")); + QCOMPARE(textItem->childCount(), 1); + QCOMPARE(textItem->child(0)->text(), i18nc("@item", code.toAscii())); +} + +//TreeItem* must be declared as a metatype to be used in qvariant_cast +Q_DECLARE_METATYPE(TreeItem*); + +void ReactionTreeItemTest::assertDataChanged(const QSignalSpy& spy, int index, + TreeItem* item) const { + QCOMPARE(spy.at(index).count(), 1); + + QVariant argument = spy.at(index).at(0); + QCOMPARE(argument.userType(), mTreeItemStarType); + QCOMPARE(qvariant_cast<TreeItem*>(argument), item); +} + +QTEST_MAIN(ReactionTreeItemTest) + +#include "ReactionTreeItemTest.moc" Property changes on: trunk/ktutorial/ktutorial-editor/tests/unit/view/ReactionTreeItemTest.cpp ___________________________________________________________________ Added: svn:eol-style + native This was sent by the SourceForge.net collaborative development platform, the world's largest Open Source development site. |
From: <dan...@us...> - 2010-03-15 06:56:22
|
Revision: 154 http://ktutorial.svn.sourceforge.net/ktutorial/?rev=154&view=rev Author: danxuliu Date: 2010-03-15 06:56:15 +0000 (Mon, 15 Mar 2010) Log Message: ----------- Add clone() and equals(const WaitFor&) methods to WaitFor and subclasses. Modified Paths: -------------- trunk/ktutorial/ktutorial-editor/src/WaitFor.cpp trunk/ktutorial/ktutorial-editor/src/WaitFor.h trunk/ktutorial/ktutorial-editor/src/WaitForComposed.cpp trunk/ktutorial/ktutorial-editor/src/WaitForComposed.h trunk/ktutorial/ktutorial-editor/src/WaitForNot.cpp trunk/ktutorial/ktutorial-editor/src/WaitForNot.h trunk/ktutorial/ktutorial-editor/src/WaitForSignal.cpp trunk/ktutorial/ktutorial-editor/src/WaitForSignal.h trunk/ktutorial/ktutorial-editor/tests/unit/CMakeLists.txt trunk/ktutorial/ktutorial-editor/tests/unit/WaitForComposedTest.cpp trunk/ktutorial/ktutorial-editor/tests/unit/WaitForNotTest.cpp trunk/ktutorial/ktutorial-editor/tests/unit/WaitForSignalTest.cpp Added Paths: ----------- trunk/ktutorial/ktutorial-editor/tests/unit/WaitForTest.cpp Modified: trunk/ktutorial/ktutorial-editor/src/WaitFor.cpp =================================================================== --- trunk/ktutorial/ktutorial-editor/src/WaitFor.cpp 2010-03-14 17:15:38 UTC (rev 153) +++ trunk/ktutorial/ktutorial-editor/src/WaitFor.cpp 2010-03-15 06:56:15 UTC (rev 154) @@ -22,3 +22,11 @@ WaitFor::WaitFor(QObject* parent): QObject(parent) { } + +bool WaitFor::operator==(const WaitFor& waitFor) const { + return equals(waitFor); +} + +bool WaitFor::operator!=(const WaitFor& waitFor) const { + return !equals(waitFor); +} Modified: trunk/ktutorial/ktutorial-editor/src/WaitFor.h =================================================================== --- trunk/ktutorial/ktutorial-editor/src/WaitFor.h 2010-03-14 17:15:38 UTC (rev 153) +++ trunk/ktutorial/ktutorial-editor/src/WaitFor.h 2010-03-15 06:56:15 UTC (rev 154) @@ -22,14 +22,19 @@ #include <QObject> /** - * Base class for conditions to wait for to be met. + * Abstract base class for conditions to wait for to be met. * Its subclasses store the data used in KTutorial wait for subclasses, but they * have nothing to do with them (they don't even know each others). Its purpose * is store the data needed to generate the code to initialize a true * KTutorial::WaitFor subclass object. * - * Subclasses must emit dataChanged(Step*) signal when their data is modified - * (including the data of child conditions). + * Subclass must implement clone() and equals(const WaitFor&) methods, which + * perform a deep copy and a comparison of the WaitFor. Operators == and != are + * provided for convenience in this base class and it isn't needed to define + * them in subclasses. + * + * Subclasses must also emit dataChanged(Step*) signal when their data is + * modified (including the data of child conditions). */ class WaitFor: public QObject { Q_OBJECT @@ -42,6 +47,49 @@ */ WaitFor(QObject* parent = 0); + /** + * Deep copy of this WaitFor. + * If this WaitFor has child WaitFor, they are also cloned in the returned + * WaitFor. + * + * Subclasses must implement this method. + * + * @return A deep copy of this WaitFor. + */ + virtual WaitFor* clone() const = 0; + + /** + * Deep comparison of this WaitFor to the given one. + * Two WaitFor are equal if they contain the same data and, if they contain + * child WaitFor, if their child WaitFor are equal one to one. The child + * WaitFor aren't checked for identity, but for equality (that is, it is + * checked if they are equal, no matter whether they are the same object or + * not). + * + * Subclasses must implement this method. + * + * @param waitFor The WaitFor to compare to. + * @return True if this WaitFor is equal to the given one, false otherwise. + */ + virtual bool equals(const WaitFor& waitFor) const = 0; + + /** + * Equality operator. + * + * @param waitFor The WaitFor to compare to. + * @return True if this WaitFor is equal to the given one, false otherwise. + */ + bool operator==(const WaitFor& waitFor) const; + + /** + * Inequality operator. + * + * @param waitFor The WaitFor to compare to. + * @return True if this WaitFor is not equal to the given one, false + * otherwise. + */ + bool operator!=(const WaitFor& waitFor) const; + Q_SIGNALS: /** Modified: trunk/ktutorial/ktutorial-editor/src/WaitForComposed.cpp =================================================================== --- trunk/ktutorial/ktutorial-editor/src/WaitForComposed.cpp 2010-03-14 17:15:38 UTC (rev 153) +++ trunk/ktutorial/ktutorial-editor/src/WaitForComposed.cpp 2010-03-15 06:56:15 UTC (rev 154) @@ -29,6 +29,41 @@ qDeleteAll(mWaitFors); } +WaitFor* WaitForComposed::clone() const { + WaitForComposed* cloned = new WaitForComposed(); + cloned->setCompositionType(mCompositionType); + + foreach (WaitFor* waitFor, mWaitFors) { + cloned->addWaitFor(waitFor->clone()); + } + + return cloned; +} + +bool WaitForComposed::equals(const WaitFor& waitFor) const { + if (!qobject_cast<const WaitForComposed*>(&waitFor)) { + return false; + } + + const WaitForComposed* waitForComposed = + static_cast<const WaitForComposed*>(&waitFor); + if (waitForComposed->compositionType() != mCompositionType) { + return false; + } + + if (waitForComposed->waitFors().count() != mWaitFors.count()) { + return false; + } + + for (int i=0; i<mWaitFors.count(); ++i) { + if (*waitForComposed->waitFors()[i] != *mWaitFors[i]) { + return false; + } + } + + return true; +} + WaitForComposed::CompositionType WaitForComposed::compositionType() const { return mCompositionType; } Modified: trunk/ktutorial/ktutorial-editor/src/WaitForComposed.h =================================================================== --- trunk/ktutorial/ktutorial-editor/src/WaitForComposed.h 2010-03-14 17:15:38 UTC (rev 153) +++ trunk/ktutorial/ktutorial-editor/src/WaitForComposed.h 2010-03-15 06:56:15 UTC (rev 154) @@ -49,6 +49,9 @@ WaitForComposed(QObject* parent = 0); virtual ~WaitForComposed(); + virtual WaitFor* clone() const; + virtual bool equals(const WaitFor& waitFor) const; + CompositionType compositionType() const; void setCompositionType(CompositionType compositionType); Modified: trunk/ktutorial/ktutorial-editor/src/WaitForNot.cpp =================================================================== --- trunk/ktutorial/ktutorial-editor/src/WaitForNot.cpp 2010-03-14 17:15:38 UTC (rev 153) +++ trunk/ktutorial/ktutorial-editor/src/WaitForNot.cpp 2010-03-15 06:56:15 UTC (rev 154) @@ -29,6 +29,36 @@ delete mNegatedWaitFor; } +WaitFor* WaitForNot::clone() const { + WaitForNot* cloned = new WaitForNot(); + if (mNegatedWaitFor) { + cloned->setNegatedWaitFor(mNegatedWaitFor->clone()); + } + + return cloned; +} + +bool WaitForNot::equals(const WaitFor& waitFor) const { + if (!qobject_cast<const WaitForNot*>(&waitFor)) { + return false; + } + + const WaitForNot* waitForNot = static_cast<const WaitForNot*>(&waitFor); + if (waitForNot->negatedWaitFor() == 0 && mNegatedWaitFor == 0) { + return true; + } + + if (waitForNot->negatedWaitFor() == 0 || mNegatedWaitFor == 0) { + return false; + } + + if (*waitForNot->negatedWaitFor() != *mNegatedWaitFor) { + return false; + } + + return true; +} + WaitFor* WaitForNot::negatedWaitFor() const { return mNegatedWaitFor; } Modified: trunk/ktutorial/ktutorial-editor/src/WaitForNot.h =================================================================== --- trunk/ktutorial/ktutorial-editor/src/WaitForNot.h 2010-03-14 17:15:38 UTC (rev 153) +++ trunk/ktutorial/ktutorial-editor/src/WaitForNot.h 2010-03-15 06:56:15 UTC (rev 154) @@ -43,6 +43,9 @@ WaitForNot(QObject* parent = 0); virtual ~WaitForNot(); + virtual WaitFor* clone() const; + virtual bool equals(const WaitFor& waitFor) const; + WaitFor* negatedWaitFor() const; /** Modified: trunk/ktutorial/ktutorial-editor/src/WaitForSignal.cpp =================================================================== --- trunk/ktutorial/ktutorial-editor/src/WaitForSignal.cpp 2010-03-14 17:15:38 UTC (rev 153) +++ trunk/ktutorial/ktutorial-editor/src/WaitForSignal.cpp 2010-03-15 06:56:15 UTC (rev 154) @@ -23,6 +23,32 @@ WaitForSignal::WaitForSignal(QObject* parent): WaitFor(parent) { } +WaitFor* WaitForSignal::clone() const { + WaitForSignal* cloned = new WaitForSignal(); + cloned->setEmitterName(mEmitterName); + cloned->setSignalName(mSignalName); + + return cloned; +} + +bool WaitForSignal::equals(const WaitFor& waitFor) const { + if (!qobject_cast<const WaitForSignal*>(&waitFor)) { + return false; + } + + const WaitForSignal* waitForSignal = + static_cast<const WaitForSignal*>(&waitFor); + if (waitForSignal->emitterName() != mEmitterName) { + return false; + } + + if (waitForSignal->signalName() != mSignalName) { + return false; + } + + return true; +} + QString WaitForSignal::emitterName() const { return mEmitterName; } Modified: trunk/ktutorial/ktutorial-editor/src/WaitForSignal.h =================================================================== --- trunk/ktutorial/ktutorial-editor/src/WaitForSignal.h 2010-03-14 17:15:38 UTC (rev 153) +++ trunk/ktutorial/ktutorial-editor/src/WaitForSignal.h 2010-03-15 06:56:15 UTC (rev 154) @@ -41,6 +41,9 @@ */ WaitForSignal(QObject* parent = 0); + virtual WaitFor* clone() const; + virtual bool equals(const WaitFor& waitFor) const; + QString emitterName() const; void setEmitterName(const QString& emitterName); Modified: trunk/ktutorial/ktutorial-editor/tests/unit/CMakeLists.txt =================================================================== --- trunk/ktutorial/ktutorial-editor/tests/unit/CMakeLists.txt 2010-03-14 17:15:38 UTC (rev 153) +++ trunk/ktutorial/ktutorial-editor/tests/unit/CMakeLists.txt 2010-03-15 06:56:15 UTC (rev 154) @@ -18,6 +18,7 @@ Reaction Step Tutorial + WaitFor WaitForComposed WaitForNot WaitForSignal @@ -33,6 +34,7 @@ Reaction Step Tutorial + WaitFor WaitForComposed WaitForNot WaitForSignal Modified: trunk/ktutorial/ktutorial-editor/tests/unit/WaitForComposedTest.cpp =================================================================== --- trunk/ktutorial/ktutorial-editor/tests/unit/WaitForComposedTest.cpp 2010-03-14 17:15:38 UTC (rev 153) +++ trunk/ktutorial/ktutorial-editor/tests/unit/WaitForComposedTest.cpp 2010-03-15 06:56:15 UTC (rev 154) @@ -29,6 +29,11 @@ void testConstructor(); + void testClone(); + void testCloneEmpty(); + + void testEquals(); + void testSetCompositionType(); void testAddWaitFor(); @@ -43,6 +48,28 @@ }; +class StubWaitFor: public WaitFor { +Q_OBJECT +public: + + int mValue; + + StubWaitFor(int value = 0): mValue(value) { + } + + virtual WaitFor* clone() const { + return new StubWaitFor(mValue); + } + + virtual bool equals(const WaitFor& waitFor) const { + if (!qobject_cast<const StubWaitFor*>(&waitFor)) { + return false; + } + + return mValue == static_cast<const StubWaitFor*>(&waitFor)->mValue; + } +}; + void WaitForComposedTest::initTestCase() { //WaitFor* must be registered in order to be used with QSignalSpy mWaitForStarType = qRegisterMetaType<WaitFor*>("WaitFor*"); @@ -56,6 +83,89 @@ QCOMPARE(waitForComposed->compositionType(), WaitForComposed::And); } +void WaitForComposedTest::testClone() { + WaitForComposed waitForComposed; + waitForComposed.setCompositionType(WaitForComposed::Or); + StubWaitFor* waitFor1 = new StubWaitFor(4); + waitForComposed.addWaitFor(waitFor1); + StubWaitFor* waitFor2 = new StubWaitFor(8); + waitForComposed.addWaitFor(waitFor2); + StubWaitFor* waitFor3 = new StubWaitFor(15); + waitForComposed.addWaitFor(waitFor3); + + WaitForComposed* cloned = + static_cast<WaitForComposed*>(waitForComposed.clone()); + + QVERIFY(cloned != &waitForComposed); + QCOMPARE(cloned->compositionType(), WaitForComposed::Or); + QCOMPARE(cloned->waitFors().count(), 3); + QVERIFY(cloned->waitFors()[0] != waitFor1); + QVERIFY(*cloned->waitFors()[0] == *waitFor1); + QVERIFY(cloned->waitFors()[1] != waitFor2); + QVERIFY(*cloned->waitFors()[1] == *waitFor2); + QVERIFY(cloned->waitFors()[2] != waitFor3); + QVERIFY(*cloned->waitFors()[2] == *waitFor3); + delete cloned; +} + +void WaitForComposedTest::testCloneEmpty() { + WaitForComposed waitForComposed; + waitForComposed.setCompositionType(WaitForComposed::Or); + + WaitForComposed* cloned = + static_cast<WaitForComposed*>(waitForComposed.clone()); + + QVERIFY(cloned != &waitForComposed); + QCOMPARE(cloned->compositionType(), WaitForComposed::Or); + QCOMPARE(cloned->waitFors().count(), 0); + delete cloned; +} + +void WaitForComposedTest::testEquals() { + WaitForComposed waitForComposed1; + WaitForComposed waitForComposed2; + + QCOMPARE(waitForComposed1 == waitForComposed2, true); + + waitForComposed1.setCompositionType(WaitForComposed::Or); + + QCOMPARE(waitForComposed1 == waitForComposed2, false); + QCOMPARE(waitForComposed2 == waitForComposed1, false); + + waitForComposed2.setCompositionType(WaitForComposed::Or); + + QCOMPARE(waitForComposed1 == waitForComposed2, true); + + StubWaitFor* waitFor1_1 = new StubWaitFor(4); + waitForComposed1.addWaitFor(waitFor1_1); + StubWaitFor* waitFor1_2 = new StubWaitFor(8); + waitForComposed1.addWaitFor(waitFor1_2); + StubWaitFor* waitFor1_3 = new StubWaitFor(15); + waitForComposed1.addWaitFor(waitFor1_3); + + QCOMPARE(waitForComposed1 == waitForComposed2, false); + QCOMPARE(waitForComposed2 == waitForComposed1, false); + + StubWaitFor* waitFor2_1 = new StubWaitFor(4); + waitForComposed2.addWaitFor(waitFor2_1); + StubWaitFor* waitFor2_2 = new StubWaitFor(8); + waitForComposed2.addWaitFor(waitFor2_2); + StubWaitFor* waitFor2_3 = new StubWaitFor(16); + waitForComposed2.addWaitFor(waitFor2_3); + + QCOMPARE(waitForComposed1 == waitForComposed2, false); + QCOMPARE(waitForComposed2 == waitForComposed1, false); + + waitFor2_3->mValue = 15; + + QCOMPARE(waitForComposed1 == waitForComposed2, true); + QCOMPARE(waitForComposed2 == waitForComposed1, true); + + StubWaitFor stubWaitFor; + + QCOMPARE(waitForComposed1 == stubWaitFor, false); +} + void WaitForComposedTest::testSetCompositionType() { WaitForComposed waitForComposed; @@ -70,9 +180,9 @@ void WaitForComposedTest::testAddWaitFor() { WaitForComposed waitForComposed; - WaitFor* waitFor1 = new WaitFor(); - WaitFor* waitFor2 = new WaitFor(); - WaitFor* waitFor3 = new WaitFor(); + WaitFor* waitFor1 = new StubWaitFor(); + WaitFor* waitFor2 = new StubWaitFor(); + WaitFor* waitFor3 = new StubWaitFor(); QSignalSpy waitForAddedSpy(&waitForComposed, SIGNAL(waitForAdded(WaitFor*))); @@ -96,9 +206,9 @@ //They will be removed and not deleted by the WaitForComposed, so they are //created in stack - WaitFor waitFor1; - WaitFor waitFor2; - WaitFor waitFor3; + StubWaitFor waitFor1; + StubWaitFor waitFor2; + StubWaitFor waitFor3; waitForComposed.addWaitFor(&waitFor1); waitForComposed.addWaitFor(&waitFor2); Modified: trunk/ktutorial/ktutorial-editor/tests/unit/WaitForNotTest.cpp =================================================================== --- trunk/ktutorial/ktutorial-editor/tests/unit/WaitForNotTest.cpp 2010-03-14 17:15:38 UTC (rev 153) +++ trunk/ktutorial/ktutorial-editor/tests/unit/WaitForNotTest.cpp 2010-03-15 06:56:15 UTC (rev 154) @@ -27,10 +27,37 @@ void testConstructor(); + void testClone(); + void testCloneEmpty(); + + void testEquals(); + void testSetNegatedWaitFor(); }; +class StubWaitFor: public WaitFor { +Q_OBJECT +public: + + int mValue; + + StubWaitFor(int value = 0): mValue(value) { + } + + virtual WaitFor* clone() const { + return new StubWaitFor(mValue); + } + + virtual bool equals(const WaitFor& waitFor) const { + if (!qobject_cast<const StubWaitFor*>(&waitFor)) { + return false; + } + + return mValue == static_cast<const StubWaitFor*>(&waitFor)->mValue; + } +}; + void WaitForNotTest::testConstructor() { QObject parent; WaitForNot* waitForNot = new WaitForNot(&parent); @@ -39,12 +66,63 @@ QCOMPARE(waitForNot->negatedWaitFor(), (WaitFor*)0); } +void WaitForNotTest::testClone() { + WaitForNot waitForNot; + StubWaitFor* negatedWaitFor = new StubWaitFor(16); + waitForNot.setNegatedWaitFor(negatedWaitFor); + + WaitForNot* cloned = static_cast<WaitForNot*>(waitForNot.clone()); + + QVERIFY(cloned != &waitForNot); + QVERIFY(cloned->negatedWaitFor() != negatedWaitFor); + QVERIFY(*cloned->negatedWaitFor() == *negatedWaitFor); + delete cloned; +} + +void WaitForNotTest::testCloneEmpty() { + WaitForNot waitForNot; + + WaitForNot* cloned = static_cast<WaitForNot*>(waitForNot.clone()); + + QVERIFY(cloned != &waitForNot); + QCOMPARE(cloned->negatedWaitFor(), (WaitFor*)0); + delete cloned; +} + +void WaitForNotTest::testEquals() { + WaitForNot waitForNot1; + WaitForNot waitForNot2; + + QCOMPARE(waitForNot1 == waitForNot2, true); + + StubWaitFor* negatedWaitFor1 = new StubWaitFor(4); + waitForNot1.setNegatedWaitFor(negatedWaitFor1); + + QCOMPARE(waitForNot1 == waitForNot2, false); + QCOMPARE(waitForNot2 == waitForNot1, false); + + StubWaitFor* negatedWaitFor2 = new StubWaitFor(); + waitForNot2.setNegatedWaitFor(negatedWaitFor2); + + QCOMPARE(waitForNot1 == waitForNot2, false); + QCOMPARE(waitForNot2 == waitForNot1, false); + + negatedWaitFor2->mValue = 4; + + QCOMPARE(waitForNot1 == waitForNot2, true); + QCOMPARE(waitForNot2 == waitForNot1, true); + + StubWaitFor stubWaitFor; + + QCOMPARE(waitForNot1 == stubWaitFor, false); +} + //WaitFor* must be declared as a metatype to be used in qvariant_cast Q_DECLARE_METATYPE(WaitFor*); void WaitForNotTest::testSetNegatedWaitFor() { WaitForNot waitForNot; - WaitFor* negatedWaitFor = new WaitFor(); + WaitFor* negatedWaitFor = new StubWaitFor(); //WaitFor* must be registered in order to be used with QSignalSpy int waitForStarType = qRegisterMetaType<WaitFor*>("WaitFor*"); Modified: trunk/ktutorial/ktutorial-editor/tests/unit/WaitForSignalTest.cpp =================================================================== --- trunk/ktutorial/ktutorial-editor/tests/unit/WaitForSignalTest.cpp 2010-03-14 17:15:38 UTC (rev 153) +++ trunk/ktutorial/ktutorial-editor/tests/unit/WaitForSignalTest.cpp 2010-03-15 06:56:15 UTC (rev 154) @@ -29,6 +29,10 @@ void testConstructor(); + void testClone(); + + void testEquals(); + void testSetEmitterName(); void testSetSignalName(); @@ -42,6 +46,28 @@ }; +class StubWaitFor: public WaitFor { +Q_OBJECT +public: + + int mValue; + + StubWaitFor(int value = 0): mValue(value) { + } + + virtual WaitFor* clone() const { + return new StubWaitFor(mValue); + } + + virtual bool equals(const WaitFor& waitFor) const { + if (!qobject_cast<const StubWaitFor*>(&waitFor)) { + return false; + } + + return mValue == static_cast<const StubWaitFor*>(&waitFor)->mValue; + } +}; + void WaitForSignalTest::initTestCase() { //WaitFor* must be registered in order to be used with QSignalSpy mWaitForStarType = qRegisterMetaType<WaitFor*>("WaitFor*"); @@ -54,6 +80,37 @@ QCOMPARE(waitForSignal->parent(), &parent); } +void WaitForSignalTest::testClone() { + WaitForSignal waitForSignal; + + WaitForSignal* cloned = static_cast<WaitForSignal*>(waitForSignal.clone()); + + QVERIFY(cloned != &waitForSignal); + QCOMPARE(cloned->emitterName(), waitForSignal.emitterName()); + QCOMPARE(cloned->signalName(), waitForSignal.signalName()); + delete cloned; +} + +void WaitForSignalTest::testEquals() { + WaitForSignal waitForSignal1; + waitForSignal1.setEmitterName("The emitter name"); + waitForSignal1.setSignalName("The signal name"); + WaitForSignal waitForSignal2; + + QCOMPARE(waitForSignal1 == waitForSignal2, false); + QCOMPARE(waitForSignal2 == waitForSignal1, false); + + waitForSignal2.setEmitterName("The emitter name"); + waitForSignal2.setSignalName("The signal name"); + + QCOMPARE(waitForSignal1 == waitForSignal2, true); + QCOMPARE(waitForSignal2 == waitForSignal1, true); + + StubWaitFor stubWaitFor; + + QCOMPARE(waitForSignal1 == stubWaitFor, false); +} + void WaitForSignalTest::testSetEmitterName() { WaitForSignal waitForSignal; Added: trunk/ktutorial/ktutorial-editor/tests/unit/WaitForTest.cpp =================================================================== --- trunk/ktutorial/ktutorial-editor/tests/unit/WaitForTest.cpp (rev 0) +++ trunk/ktutorial/ktutorial-editor/tests/unit/WaitForTest.cpp 2010-03-15 06:56:15 UTC (rev 154) @@ -0,0 +1,64 @@ +/*************************************************************************** + * 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 "WaitFor.h" + +class WaitForTest: public QObject { +Q_OBJECT + +private slots: + + void testOperatorEqual(); + + void testOperatorNotEqual(); + +}; + +class StubWaitFor: public WaitFor { +public: + + virtual WaitFor* clone() const { + return 0; + } + + virtual bool equals(const WaitFor& waitFor) const { + Q_UNUSED(waitFor); + return false; + } + +}; + +void WaitForTest::testOperatorEqual() { + StubWaitFor waitFor1; + StubWaitFor waitFor2; + + QCOMPARE(waitFor1 == waitFor2, false); +} + +void WaitForTest::testOperatorNotEqual() { + StubWaitFor waitFor1; + StubWaitFor waitFor2; + + QCOMPARE(waitFor1 != waitFor2, true); +} + +QTEST_MAIN(WaitForTest) + +#include "WaitForTest.moc" Property changes on: trunk/ktutorial/ktutorial-editor/tests/unit/WaitForTest.cpp ___________________________________________________________________ Added: svn:eol-style + native This was sent by the SourceForge.net collaborative development platform, the world's largest Open Source development site. |
From: <dan...@us...> - 2010-03-15 09:06:55
|
Revision: 156 http://ktutorial.svn.sourceforge.net/ktutorial/?rev=156&view=rev Author: danxuliu Date: 2010-03-15 09:06:46 +0000 (Mon, 15 Mar 2010) Log Message: ----------- Add ReactionWidget to edit reactions. Modified Paths: -------------- trunk/ktutorial/ktutorial-editor/src/view/CMakeLists.txt trunk/ktutorial/ktutorial-editor/tests/unit/view/CMakeLists.txt Added Paths: ----------- trunk/ktutorial/ktutorial-editor/src/view/ReactionWidget.cpp trunk/ktutorial/ktutorial-editor/src/view/ReactionWidget.h trunk/ktutorial/ktutorial-editor/src/view/ReactionWidget.ui trunk/ktutorial/ktutorial-editor/tests/unit/view/ReactionWidgetTest.cpp Modified: trunk/ktutorial/ktutorial-editor/src/view/CMakeLists.txt =================================================================== --- trunk/ktutorial/ktutorial-editor/src/view/CMakeLists.txt 2010-03-15 08:24:21 UTC (rev 155) +++ trunk/ktutorial/ktutorial-editor/src/view/CMakeLists.txt 2010-03-15 09:06:46 UTC (rev 156) @@ -7,6 +7,7 @@ LicenseWidget.cpp NewWaitForWidget.cpp ReactionTreeItem.cpp + ReactionWidget.cpp StepCustomCodeWidget.cpp StepDataWidget.cpp StepTreeItem.cpp @@ -30,6 +31,7 @@ CustomCodeWidget.ui LicenseWidget.ui NewWaitForWidget.ui + ReactionWidget.ui StepDataWidget.ui TutorialInformationWidget.ui WaitForSignalWidget.ui Added: trunk/ktutorial/ktutorial-editor/src/view/ReactionWidget.cpp =================================================================== --- trunk/ktutorial/ktutorial-editor/src/view/ReactionWidget.cpp (rev 0) +++ trunk/ktutorial/ktutorial-editor/src/view/ReactionWidget.cpp 2010-03-15 09:06:46 UTC (rev 156) @@ -0,0 +1,157 @@ +/*************************************************************************** + * 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 "ReactionWidget.h" + +#include "ui_ReactionWidget.h" +#include "WaitForWidget.h" +#include "../Reaction.h" +#include "../WaitFor.h" + +//public: + +ReactionWidget::ReactionWidget(Reaction* reaction, QWidget* parent): + EditionWidget(parent), + mReaction(reaction), + mWaitForClone(0) { + + ui = new Ui::ReactionWidget(); + ui->setupUi(this); + + if (reaction->waitFor()) { + mWaitForClone = reaction->waitFor()->clone(); + } + + mWaitForWidget = new WaitForWidget(mWaitForClone, this); + mWaitForWidget->setObjectName("triggerConditionWaitForWidget"); + ui->triggerConditionVerticalLayout->addWidget(mWaitForWidget); + + connect(ui->triggerConditionRadioButton, SIGNAL(toggled(bool)), + this, SLOT(selectTriggerCondition(bool))); + connect(ui->triggerOptionRadioButton, SIGNAL(toggled(bool)), + this, SLOT(selectTriggerOption(bool))); + connect(ui->responseCodeRadioButton, SIGNAL(toggled(bool)), + this, SLOT(selectResponseCode(bool))); + connect(ui->responseStepRadioButton, SIGNAL(toggled(bool)), + this, SLOT(selectResponseStep(bool))); + + if (reaction->triggerType() == Reaction::ConditionMet) { + ui->triggerConditionRadioButton->setChecked(true); + } else { + ui->triggerOptionRadioButton->setChecked(true); + } + + if (reaction->responseType() == Reaction::CustomCode) { + ui->responseCodeRadioButton->setChecked(true); + } else { + ui->responseStepRadioButton->setChecked(true); + } + + ui->triggerOptionLineEdit->setText(reaction->optionName()); + ui->responseCodeTextEdit->setText(reaction->customCode()); + ui->responseStepLineEdit->setText(reaction->nextStepId()); +} + +ReactionWidget::~ReactionWidget() { + delete mWaitForClone; + delete ui; +} + +void ReactionWidget::saveChanges() { + if (mReaction->optionName() != ui->triggerOptionLineEdit->text()) { + mReaction->setOptionName(ui->triggerOptionLineEdit->text()); + } + + if (*mReaction->waitFor() != *mWaitForWidget->waitFor()) { + WaitFor* oldWaitFor = mReaction->waitFor(); + mReaction->setWaitFor(mWaitForWidget->waitFor()); + delete oldWaitFor; + + //Don't delete the cloned WaitFor when this ReactionWidget is deleted if + //it was set to the reaction + if (mWaitForClone == mReaction->waitFor()) { + mWaitForClone = 0; + } + } + + if (mReaction->customCode() != ui->responseCodeTextEdit->toPlainText()) { + mReaction->setCustomCode(ui->responseCodeTextEdit->toPlainText()); + } + + if (mReaction->nextStepId() != ui->responseStepLineEdit->text()) { + mReaction->setNextStepId(ui->responseStepLineEdit->text()); + } + + if (mReaction->triggerType() != Reaction::ConditionMet && + ui->triggerConditionRadioButton->isChecked()) { + mReaction->setTriggerType(Reaction::ConditionMet); + } + + if (mReaction->triggerType() != Reaction::OptionSelected && + ui->triggerOptionRadioButton->isChecked()) { + mReaction->setTriggerType(Reaction::OptionSelected); + } + + if (mReaction->responseType() != Reaction::CustomCode && + ui->responseCodeRadioButton->isChecked()) { + mReaction->setResponseType(Reaction::CustomCode); + } + + if (mReaction->responseType() != Reaction::NextStep && + ui->responseStepRadioButton->isChecked()) { + mReaction->setResponseType(Reaction::NextStep); + } +} + +//private slots: + +void ReactionWidget::selectTriggerCondition(bool checked) { + if (!checked) { + return; + } + + ui->triggerOptionLineEdit->setEnabled(false); + mWaitForWidget->setEnabled(true); +} + +void ReactionWidget::selectTriggerOption(bool checked) { + if (!checked) { + return; + } + + mWaitForWidget->setEnabled(false); + ui->triggerOptionLineEdit->setEnabled(true); +} + +void ReactionWidget::selectResponseStep(bool checked) { + if (!checked) { + return; + } + + ui->responseCodeTextEdit->setEnabled(false); + ui->responseStepLineEdit->setEnabled(true); +} + +void ReactionWidget::selectResponseCode(bool checked) { + if (!checked) { + return; + } + + ui->responseStepLineEdit->setEnabled(false); + ui->responseCodeTextEdit->setEnabled(true); +} Property changes on: trunk/ktutorial/ktutorial-editor/src/view/ReactionWidget.cpp ___________________________________________________________________ Added: svn:eol-style + native Added: trunk/ktutorial/ktutorial-editor/src/view/ReactionWidget.h =================================================================== --- trunk/ktutorial/ktutorial-editor/src/view/ReactionWidget.h (rev 0) +++ trunk/ktutorial/ktutorial-editor/src/view/ReactionWidget.h 2010-03-15 09:06:46 UTC (rev 156) @@ -0,0 +1,122 @@ +/*************************************************************************** + * 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 REACTIONWIDGET_H +#define REACTIONWIDGET_H + +#include <QPointer> + +#include "EditionWidget.h" + +class Reaction; +class WaitFor; +class WaitForWidget; + +namespace Ui { +class ReactionWidget; +} + +/** + * Edition widget for a Reaction. + */ +class ReactionWidget: public EditionWidget { +Q_OBJECT +public: + + /** + * Creates a new ReactionWidget for the given Reaction. + * + * @param reaction The reaction to edit. + * @param parent The parent QWidget. + */ + explicit ReactionWidget(Reaction* reaction, QWidget* parent = 0); + + /** + * Destroys this widget. + */ + virtual ~ReactionWidget(); + + /** + * Saves the data in the reaction. + */ + virtual void saveChanges(); + +private: + + /** + * The reaction to edit. + */ + Reaction* mReaction; + + /** + * The cloned WaitFor to be edited in the WaitForWidget. + * A cloned WaitFor instead of the one from the Reaction is used because + * working on it would modify it even if saveChanges() wasn't called. + * The pointer is automatically set to 0 if the object is deleted anywhere + * (that is, not by deleting this pointer, but another one pointing to the + * object). + */ + QPointer<WaitFor> mWaitForClone; + + /** + * The widget to edit the WaitFor. + */ + WaitForWidget* mWaitForWidget; + + /** + * The Ui Designer generated class. + */ + Ui::ReactionWidget* ui; + +private Q_SLOTS: + + /** + * When the condition radio button is selected, it enables and disables the + * appropriate widgets. + * + * @param checked Whether the radio button was checked or unchecked. + */ + void selectTriggerCondition(bool checked); + + /** + * When the option radio button is selected, it enables and disables the + * appropriate widgets. + * + * @param checked Whether the radio button was checked or unchecked. + */ + void selectTriggerOption(bool checked); + + /** + * When the custom code radio button is selected, it enables and disables + * the appropriate widgets. + * + * @param checked Whether the radio button was checked or unchecked. + */ + void selectResponseCode(bool checked); + + /** + * When the next step radio button is selected, it enables and disables the + * appropriate widgets. + * + * @param checked Whether the radio button was checked or unchecked. + */ + void selectResponseStep(bool checked); + +}; + +#endif Property changes on: trunk/ktutorial/ktutorial-editor/src/view/ReactionWidget.h ___________________________________________________________________ Added: svn:eol-style + native Added: trunk/ktutorial/ktutorial-editor/src/view/ReactionWidget.ui =================================================================== --- trunk/ktutorial/ktutorial-editor/src/view/ReactionWidget.ui (rev 0) +++ trunk/ktutorial/ktutorial-editor/src/view/ReactionWidget.ui 2010-03-15 09:06:46 UTC (rev 156) @@ -0,0 +1,123 @@ +<?xml version="1.0" encoding="UTF-8"?> +<ui version="4.0"> + <class>ReactionWidget</class> + <widget class="QWidget" name="ReactionWidget"> + <property name="geometry"> + <rect> + <x>0</x> + <y>0</y> + <width>400</width> + <height>300</height> + </rect> + </property> + <property name="windowTitle"> + <string comment="@title">Edit reaction</string> + </property> + <property name="whatsThis"> + <string comment="@info:whatsthis"><para>Edit the response of a step to certain trigger.</para> +<para>When a step is active, the actions of the user can trigger a response in the tutorial. A trigger can be an option in the step selected by the user, or a condition that was met. The response can be changing to another step, or executing some custom code.</para></string> + </property> + <layout class="QVBoxLayout" name="reactionWidgetVerticalLayout"> + <item> + <widget class="QGroupBox" name="triggerGroupBox"> + <property name="title"> + <string comment="@title:group Something that causes a response">Trigger</string> + </property> + <layout class="QVBoxLayout" name="triggerGroupBoxVerticalLayout"> + <item> + <layout class="QHBoxLayout" name="triggerOptionHorizontalLayout"> + <item> + <widget class="QRadioButton" name="triggerOptionRadioButton"> + <property name="text"> + <string comment="@option:radio">Option:</string> + </property> + </widget> + </item> + <item> + <widget class="KLineEdit" name="triggerOptionLineEdit"> + <property name="whatsThis"> + <string comment="@info:whatsthis"><para>The name of the option.</para> +<para>An option with this name will be added to the step, so the same name set here will be shown to the user.</para></string> + </property> + </widget> + </item> + </layout> + </item> + <item> + <layout class="QVBoxLayout" name="triggerConditionVerticalLayout"> + <item> + <widget class="QRadioButton" name="triggerConditionRadioButton"> + <property name="text"> + <string comment="@option:radio">Condition met:</string> + </property> + </widget> + </item> + </layout> + </item> + </layout> + </widget> + </item> + <item> + <widget class="QGroupBox" name="responseGroupBox"> + <property name="title"> + <string comment="@title:group">Response</string> + </property> + <layout class="QVBoxLayout" name="responseGroupBoxVerticalLayout"> + <item> + <layout class="QHBoxLayout" name="responseStepHorizontalLayout"> + <item> + <widget class="QRadioButton" name="responseStepRadioButton"> + <property name="text"> + <string comment="@option:radio">Change to step:</string> + </property> + </widget> + </item> + <item> + <widget class="KLineEdit" name="responseStepLineEdit"> + <property name="whatsThis"> + <string comment="@info:whatsthis"><para>The id of the step to change to.</para></string> + </property> + </widget> + </item> + </layout> + </item> + <item> + <layout class="QVBoxLayout" name="responseCodeVerticalLayout"> + <item> + <widget class="QRadioButton" name="responseCodeRadioButton"> + <property name="text"> + <string comment="@option:radio">Custom response code:</string> + </property> + </widget> + </item> + <item> + <widget class="KTextEdit" name="responseCodeTextEdit"> + <property name="whatsThis"> + <string comment="@info:whatsthis"><para>The custom code to execute.</para> +<para>The code will be written as is into a new function called when the response is triggered. This means that the code must be written in the same programming language the tutorial will be exported to.</para> +<para>Also note that you only have to provide the body of the function. The signature is automatically generated.</para></string> + </property> + </widget> + </item> + </layout> + </item> + </layout> + </widget> + </item> + </layout> + </widget> + <customwidgets> + <customwidget> + <class>KLineEdit</class> + <extends>QLineEdit</extends> + <header>klineedit.h</header> + </customwidget> + <customwidget> + <class>KTextEdit</class> + <extends>QTextEdit</extends> + <header>ktextedit.h</header> + </customwidget> + </customwidgets> + <resources/> + <connections/> +</ui> Modified: trunk/ktutorial/ktutorial-editor/tests/unit/view/CMakeLists.txt =================================================================== --- trunk/ktutorial/ktutorial-editor/tests/unit/view/CMakeLists.txt 2010-03-15 08:24:21 UTC (rev 155) +++ trunk/ktutorial/ktutorial-editor/tests/unit/view/CMakeLists.txt 2010-03-15 09:06:46 UTC (rev 156) @@ -22,6 +22,7 @@ LicenseWidget NewWaitForWidget ReactionTreeItem + ReactionWidget StepCustomCodeWidget StepDataWidget StepTreeItem @@ -53,6 +54,7 @@ LicenseWidget NewWaitForWidget ReactionTreeItem + ReactionWidget StepCustomCodeWidget StepDataWidget StepTreeItem Added: trunk/ktutorial/ktutorial-editor/tests/unit/view/ReactionWidgetTest.cpp =================================================================== --- trunk/ktutorial/ktutorial-editor/tests/unit/view/ReactionWidgetTest.cpp (rev 0) +++ trunk/ktutorial/ktutorial-editor/tests/unit/view/ReactionWidgetTest.cpp 2010-03-15 09:06:46 UTC (rev 156) @@ -0,0 +1,268 @@ +/*************************************************************************** + * 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 "ReactionWidget.h" + +#include <QRadioButton> +#include <QTreeView> + +#include <KComboBox> +#include <KDialog> +#include <KLineEdit> +#include <KPushButton> +#include <KTextEdit> + +#include "WaitForWidget.h" +#include "../WaitForComposed.h" +#include "../WaitForSignal.h" +#include "../Reaction.h" + +class ReactionWidgetTest: public QObject { +Q_OBJECT + +private slots: + + void testConstructor(); + + void testSelectTriggerTypeOption(); + void testSelectTriggerTypeCondition(); + + void testSelectResponseTypeStep(); + void testSelectResponseTypeCustomCode(); + + void testSaveChanges(); + +private: + + QRadioButton* triggerOptionRadioButton(ReactionWidget* widget) const; + KLineEdit* triggerOptionLineEdit(ReactionWidget* widget) const; + QRadioButton* triggerConditionRadioButton(ReactionWidget* widget) const; + WaitForWidget* triggerConditionWidget(ReactionWidget* widget) const; + QRadioButton* responseStepRadioButton(ReactionWidget* widget) const; + KLineEdit* responseStepLineEdit(ReactionWidget* widget) const; + QRadioButton* responseCodeRadioButton(ReactionWidget* widget) const; + KTextEdit* responseCodeTextEdit(ReactionWidget* widget) const; + + void addWaitForSignalToRootWaitFor(ReactionWidget* widget); + +}; + +void ReactionWidgetTest::testConstructor() { + WaitFor* waitFor = new WaitForSignal(); + Reaction reaction; + reaction.setTriggerType(Reaction::ConditionMet); + reaction.setWaitFor(waitFor); + reaction.setOptionName("The option name"); + reaction.setResponseType(Reaction::CustomCode); + reaction.setCustomCode("The custom code"); + reaction.setNextStepId("The step id"); + + QWidget parent; + ReactionWidget* widget = new ReactionWidget(&reaction, &parent); + + QCOMPARE(widget->parentWidget(), &parent); + QVERIFY(!triggerOptionRadioButton(widget)->isChecked()); + QVERIFY(!triggerOptionLineEdit(widget)->isEnabled()); + QCOMPARE(triggerOptionLineEdit(widget)->text(), QString("The option name")); + QVERIFY(triggerConditionRadioButton(widget)->isChecked()); + QVERIFY(triggerConditionWidget(widget)->isEnabled()); + QVERIFY(triggerConditionWidget(widget)->waitFor() != waitFor); + QVERIFY(*triggerConditionWidget(widget)->waitFor() == *waitFor); + QVERIFY(!responseStepRadioButton(widget)->isChecked()); + QVERIFY(!responseStepLineEdit(widget)->isEnabled()); + QCOMPARE(responseStepLineEdit(widget)->text(), QString("The step id")); + QVERIFY(responseCodeRadioButton(widget)->isChecked()); + QVERIFY(responseCodeTextEdit(widget)->isEnabled()); + QCOMPARE(responseCodeTextEdit(widget)->toPlainText(), + QString("The custom code")); +} + +void ReactionWidgetTest::testSelectTriggerTypeOption() { + Reaction reaction; + reaction.setTriggerType(Reaction::ConditionMet); + + ReactionWidget widget(&reaction); + + triggerOptionRadioButton(&widget)->setChecked(true); + + QVERIFY(!triggerConditionRadioButton(&widget)->isChecked()); + QVERIFY(!triggerConditionWidget(&widget)->isEnabled()); + QVERIFY(triggerOptionLineEdit(&widget)->isEnabled()); +} + +void ReactionWidgetTest::testSelectTriggerTypeCondition() { + Reaction reaction; + reaction.setTriggerType(Reaction::OptionSelected); + + ReactionWidget widget(&reaction); + + triggerConditionRadioButton(&widget)->setChecked(true); + + QVERIFY(!triggerOptionRadioButton(&widget)->isChecked()); + QVERIFY(!triggerOptionLineEdit(&widget)->isEnabled()); + QVERIFY(triggerConditionWidget(&widget)->isEnabled()); +} + +void ReactionWidgetTest::testSelectResponseTypeStep() { + Reaction reaction; + reaction.setResponseType(Reaction::CustomCode); + + ReactionWidget widget(&reaction); + + responseStepRadioButton(&widget)->setChecked(true); + + QVERIFY(!responseCodeRadioButton(&widget)->isChecked()); + QVERIFY(!responseCodeTextEdit(&widget)->isEnabled()); + QVERIFY(responseStepLineEdit(&widget)->isEnabled()); +} + +void ReactionWidgetTest::testSelectResponseTypeCustomCode() { + Reaction reaction; + reaction.setResponseType(Reaction::NextStep); + + ReactionWidget widget(&reaction); + + responseCodeRadioButton(&widget)->setChecked(true); + + QVERIFY(!responseStepRadioButton(&widget)->isChecked()); + QVERIFY(!responseStepLineEdit(&widget)->isEnabled()); + QVERIFY(responseCodeTextEdit(&widget)->isEnabled()); +} + +void ReactionWidgetTest::testSaveChanges() { + WaitFor* oldWaitFor = new WaitForComposed(); + Reaction reaction; + reaction.setTriggerType(Reaction::ConditionMet); + reaction.setResponseType(Reaction::CustomCode); + reaction.setWaitFor(oldWaitFor); + + ReactionWidget widget(&reaction); + + addWaitForSignalToRootWaitFor(&widget); + triggerOptionRadioButton(&widget)->setChecked(true); + triggerOptionLineEdit(&widget)->setText("The option name"); + + responseCodeTextEdit(&widget)->setText("The custom code"); + responseStepRadioButton(&widget)->setChecked(true); + responseStepLineEdit(&widget)->setText("The step id"); + + widget.saveChanges(); + + QCOMPARE(reaction.triggerType(), Reaction::OptionSelected); + QCOMPARE(reaction.optionName(), QString("The option name")); + QVERIFY(reaction.waitFor() != oldWaitFor); + WaitForComposed* waitFor = + qobject_cast<WaitForComposed*>(reaction.waitFor()); + QVERIFY(waitFor); + QCOMPARE(waitFor->waitFors().count(), 1); + QVERIFY(qobject_cast<WaitForSignal*>(waitFor->waitFors()[0])); + QCOMPARE(reaction.responseType(), Reaction::NextStep); + QCOMPARE(reaction.nextStepId(), QString("The step id")); + QCOMPARE(reaction.customCode(), QString("The custom code")); +} + +/////////////////////////////////// Helpers //////////////////////////////////// + +QRadioButton* ReactionWidgetTest::triggerOptionRadioButton( + ReactionWidget* widget) const { + return widget->findChild<QRadioButton*>("triggerOptionRadioButton"); +} + +KLineEdit* ReactionWidgetTest::triggerOptionLineEdit( + ReactionWidget* widget) const { + return widget->findChild<KLineEdit*>("triggerOptionLineEdit"); +} + +QRadioButton* ReactionWidgetTest::triggerConditionRadioButton( + ReactionWidget* widget) const { + return widget->findChild<QRadioButton*>("triggerConditionRadioButton"); +} + +WaitForWidget* ReactionWidgetTest::triggerConditionWidget( + ReactionWidget* widget) const { + return widget->findChild<WaitForWidget*>("triggerConditionWaitForWidget"); +} + +QRadioButton* ReactionWidgetTest::responseStepRadioButton( + ReactionWidget* widget) const { + return widget->findChild<QRadioButton*>("responseStepRadioButton"); +} + +KLineEdit* ReactionWidgetTest::responseStepLineEdit( + ReactionWidget* widget) const { + return widget->findChild<KLineEdit*>("responseStepLineEdit"); +} + +QRadioButton* ReactionWidgetTest::responseCodeRadioButton( + ReactionWidget* widget) const { + return widget->findChild<QRadioButton*>("responseCodeRadioButton"); +} + +KTextEdit* ReactionWidgetTest::responseCodeTextEdit( + ReactionWidget* widget) const { + return widget->findChild<KTextEdit*>("responseCodeTextEdit"); +} + +class AddWaitForSignalHelper: public QObject { +Q_OBJECT +public: + + AddWaitForSignalHelper(QWidget* widget, QObject* parent): + QObject(parent), + mWidget(widget) { + } + +public slots: + + void addWaitForSignal() const { + KComboBox* comboBox = + mWidget->findChild<KComboBox*>("waitForTypeComboBox"); + QVERIFY(comboBox); + comboBox->setCurrentIndex(3); + + KDialog* dialog = mWidget->findChild<KDialog*>("addWaitForDialog"); + QVERIFY(dialog); + dialog->button(KDialog::Ok)->click(); + } + +private: + + QWidget* mWidget; + +}; + +void ReactionWidgetTest::addWaitForSignalToRootWaitFor(ReactionWidget* widget) { + QTreeView* tree = widget->findChild<QTreeView*>("waitForTreeView"); + QModelIndex index = tree->model()->index(0, 0); + tree->selectionModel()->select(index, QItemSelectionModel::SelectCurrent); + + AddWaitForSignalHelper* helper = new AddWaitForSignalHelper(widget, this); + + //The dialog is modal, so it won't return to the test code until it is + //closed. Thus, the commands to execute on the dialog must be "queued", + //as calling addWaitForSignal after the button click won't work. + QTimer::singleShot(500, helper, SLOT(addWaitForSignal())); + + widget->findChild<KPushButton*>("addButton")->click(); +} + +QTEST_MAIN(ReactionWidgetTest) + +#include "ReactionWidgetTest.moc" Property changes on: trunk/ktutorial/ktutorial-editor/tests/unit/view/ReactionWidgetTest.cpp ___________________________________________________________________ Added: svn:eol-style + native This was sent by the SourceForge.net collaborative development platform, the world's largest Open Source development site. |
From: <dan...@us...> - 2010-03-15 18:58:31
|
Revision: 157 http://ktutorial.svn.sourceforge.net/ktutorial/?rev=157&view=rev Author: danxuliu Date: 2010-03-15 18:58:22 +0000 (Mon, 15 Mar 2010) Log Message: ----------- Remove "Steps" item that contained all the steps in a tutorial in its tree model. Now steps hang directly from the tutorial, as the intermediate item wasn't really useful. Modified Paths: -------------- trunk/ktutorial/ktutorial-editor/src/view/TutorialTreeItem.cpp trunk/ktutorial/ktutorial-editor/src/view/TutorialTreeItem.h trunk/ktutorial/ktutorial-editor/tests/unit/view/TutorialTreeItemTest.cpp trunk/ktutorial/ktutorial-editor/tests/unit/view/TutorialTreeSelectionManagerTest.cpp Modified: trunk/ktutorial/ktutorial-editor/src/view/TutorialTreeItem.cpp =================================================================== --- trunk/ktutorial/ktutorial-editor/src/view/TutorialTreeItem.cpp 2010-03-15 09:06:46 UTC (rev 156) +++ trunk/ktutorial/ktutorial-editor/src/view/TutorialTreeItem.cpp 2010-03-15 18:58:22 UTC (rev 157) @@ -135,33 +135,15 @@ } void TutorialTreeItem::addStep(Step* step) { - TreeItem* rootStepItem; - - if (mStepTreeItems.isEmpty()) { - TextTreeItem* textRootStepItem = new TextTreeItem(this); - textRootStepItem->setText(i18nc("@item", "Steps:")); - appendChild(textRootStepItem); - - rootStepItem = textRootStepItem; - } else { - rootStepItem = mStepTreeItems.at(0)->parent(); - } - - StepTreeItem* stepTreeItem = new StepTreeItem(step, rootStepItem); - rootStepItem->appendChild(stepTreeItem); + StepTreeItem* stepTreeItem = new StepTreeItem(step, this); + appendChild(stepTreeItem); mStepTreeItems.append(stepTreeItem); } void TutorialTreeItem::removeStep(Step* step) { StepTreeItem* stepTreeItem = stepTreeItemForStep(step); - TreeItem* rootStepItem = stepTreeItem->parent(); - rootStepItem->removeChild(stepTreeItem); + removeChild(stepTreeItem); mStepTreeItems.removeOne(stepTreeItem); delete stepTreeItem; - - if (mStepTreeItems.isEmpty()) { - removeChild(rootStepItem); - delete rootStepItem; - } } Modified: trunk/ktutorial/ktutorial-editor/src/view/TutorialTreeItem.h =================================================================== --- trunk/ktutorial/ktutorial-editor/src/view/TutorialTreeItem.h 2010-03-15 09:06:46 UTC (rev 156) +++ trunk/ktutorial/ktutorial-editor/src/view/TutorialTreeItem.h 2010-03-15 18:58:22 UTC (rev 157) @@ -38,12 +38,11 @@ * | -The custom setup code * |-Tear down: * | -The custom tear down code - * --Steps: - * -Step first step added - * ... - * -Step second step added - * ... - * ... + * |-Step first step added + * | ... + * |-Step second step added + * | ... + * ... * * The items only appear if they have some data to show. For example, if only * the name of the Tutorial is set, its representation is: @@ -150,7 +149,6 @@ /** * Adds a new StepTreeItem when a Step is added in the tutorial. - * If there were no other steps yet, the parent "Steps:" item is also added. * * @param step The Step added in the Tutorial. */ @@ -158,7 +156,6 @@ /** * Removes the StepTreeItem for the Step removed in the tutorial. - * If there are no other steps, the parent "Steps:" item is also removed. * * @param step The Step removed in the Tutorial. */ Modified: trunk/ktutorial/ktutorial-editor/tests/unit/view/TutorialTreeItemTest.cpp =================================================================== --- trunk/ktutorial/ktutorial-editor/tests/unit/view/TutorialTreeItemTest.cpp 2010-03-15 09:06:46 UTC (rev 156) +++ trunk/ktutorial/ktutorial-editor/tests/unit/view/TutorialTreeItemTest.cpp 2010-03-15 18:58:22 UTC (rev 157) @@ -75,8 +75,7 @@ void assertCustomSetupCode(TreeItem* setupItem, const QString& code) const; void assertCustomTearDownCode(TreeItem* tearDownItem, const QString& code) const; - void assertStep(TreeItem* rootStepItem, int index, - const QString& stepId) const; + void assertStep(TreeItem* stepItem, const QString& stepId) const; void assertDataChanged(const QSignalSpy& spy, int index, TreeItem* item) const; @@ -127,15 +126,14 @@ QCOMPARE(item.parent(), &parent); QCOMPARE(item.text(), i18nc("@item", "Tutorial %1", "theName")); - QCOMPARE(item.childCount(), 6); + QCOMPARE(item.childCount(), 7); assertName(item.child(0), "The name"); assertDescription(item.child(1), "The description"); assertLicenseText(item.child(2), "The license text"); assertCustomSetupCode(item.child(3), "The setup code"); assertCustomTearDownCode(item.child(4), "The tear down code"); - QCOMPARE(item.child(5)->childCount(), 2); - assertStep(item.child(5), 0, "First step"); - assertStep(item.child(5), 1, "Second step"); + assertStep(item.child(5), "First step"); + assertStep(item.child(6), "Second step"); } //TreeItem* must be declared as a metatype to be used in qvariant_cast @@ -350,7 +348,7 @@ tutorial.addStep(step); QCOMPARE(item.childCount(), 1); - assertStep(item.child(0), 0, "Step id"); + assertStep(item.child(0), "Step id"); } void TutorialTreeItemTest::testTutorialRemoveStep() { @@ -401,8 +399,7 @@ assertDescription(item.child(0), "The description"); assertCustomSetupCode(item.child(1), "The setup code"); assertCustomTearDownCode(item.child(2), "The tear down code"); - QCOMPARE(item.child(3)->childCount(), 1); - assertStep(item.child(3), 0, "First step"); + assertStep(item.child(3), "First step"); tutorial.setName("The name"); @@ -412,35 +409,32 @@ assertDescription(item.child(1), "The description"); assertCustomSetupCode(item.child(2), "The setup code"); assertCustomTearDownCode(item.child(3), "The tear down code"); - QCOMPARE(item.child(4)->childCount(), 1); - assertStep(item.child(4), 0, "First step"); + assertStep(item.child(4), "First step"); Step* step2 = new Step(); step2->setId("Second step"); tutorial.addStep(step2); QCOMPARE(item.text(), i18nc("@item", "Tutorial %1", "theName")); - QCOMPARE(item.childCount(), 5); + QCOMPARE(item.childCount(), 6); assertName(item.child(0), "The name"); assertDescription(item.child(1), "The description"); assertCustomSetupCode(item.child(2), "The setup code"); assertCustomTearDownCode(item.child(3), "The tear down code"); - QCOMPARE(item.child(4)->childCount(), 2); - assertStep(item.child(4), 0, "First step"); - assertStep(item.child(4), 1, "Second step"); + assertStep(item.child(4), "First step"); + assertStep(item.child(5), "Second step"); tutorial.setLicenseText("The license text"); QCOMPARE(item.text(), i18nc("@item", "Tutorial %1", "theName")); - QCOMPARE(item.childCount(), 6); + QCOMPARE(item.childCount(), 7); assertName(item.child(0), "The name"); assertDescription(item.child(1), "The description"); assertLicenseText(item.child(2), "The license text"); assertCustomSetupCode(item.child(3), "The setup code"); assertCustomTearDownCode(item.child(4), "The tear down code"); - QCOMPARE(item.child(5)->childCount(), 2); - assertStep(item.child(5), 0, "First step"); - assertStep(item.child(5), 1, "Second step"); + assertStep(item.child(5), "First step"); + assertStep(item.child(6), "Second step"); } void TutorialTreeItemTest::testChildOrderWhenUnsettingDataInTutorial() { @@ -466,25 +460,23 @@ tutorial.setLicenseText(""); QCOMPARE(item.text(), i18nc("@item", "Tutorial %1", "theName")); - QCOMPARE(item.childCount(), 5); + QCOMPARE(item.childCount(), 6); assertName(item.child(0), "The name"); assertDescription(item.child(1), "The description"); assertCustomSetupCode(item.child(2), "The setup code"); assertCustomTearDownCode(item.child(3), "The tear down code"); - QCOMPARE(item.child(4)->childCount(), 2); - assertStep(item.child(4), 0, "First step"); - assertStep(item.child(4), 1, "Second step"); + assertStep(item.child(4), "First step"); + assertStep(item.child(5), "Second step"); tutorial.setName(""); QCOMPARE(item.text(), i18nc("@item", "Tutorial")); - QCOMPARE(item.childCount(), 4); + QCOMPARE(item.childCount(), 5); assertDescription(item.child(0), "The description"); assertCustomSetupCode(item.child(1), "The setup code"); assertCustomTearDownCode(item.child(2), "The tear down code"); - QCOMPARE(item.child(3)->childCount(), 2); - assertStep(item.child(3), 0, "First step"); - assertStep(item.child(3), 1, "Second step"); + assertStep(item.child(3), "First step"); + assertStep(item.child(4), "Second step"); tutorial.removeStep(&step1); @@ -493,8 +485,7 @@ assertDescription(item.child(0), "The description"); assertCustomSetupCode(item.child(1), "The setup code"); assertCustomTearDownCode(item.child(2), "The tear down code"); - QCOMPARE(item.child(3)->childCount(), 1); - assertStep(item.child(3), 0, "Second step"); + assertStep(item.child(3), "Second step"); tutorial.setCustomTearDownCode(""); @@ -502,23 +493,20 @@ QCOMPARE(item.childCount(), 3); assertDescription(item.child(0), "The description"); assertCustomSetupCode(item.child(1), "The setup code"); - QCOMPARE(item.child(2)->childCount(), 1); - assertStep(item.child(2), 0, "Second step"); + assertStep(item.child(2), "Second step"); tutorial.setDescription(""); QCOMPARE(item.text(), i18nc("@item", "Tutorial")); QCOMPARE(item.childCount(), 2); assertCustomSetupCode(item.child(0), "The setup code"); - QCOMPARE(item.child(1)->childCount(), 1); - assertStep(item.child(1), 0, "Second step"); + assertStep(item.child(1), "Second step"); tutorial.setCustomSetupCode(""); QCOMPARE(item.text(), i18nc("@item", "Tutorial")); QCOMPARE(item.childCount(), 1); - QCOMPARE(item.child(0)->childCount(), 1); - assertStep(item.child(0), 0, "Second step"); + assertStep(item.child(0), "Second step"); tutorial.removeStep(&step2); @@ -561,12 +549,10 @@ QCOMPARE(tearDownItem->child(0)->text(), i18nc("@item", code.toAscii())); } -void TutorialTreeItemTest::assertStep(TreeItem* rootStepItem, int index, +void TutorialTreeItemTest::assertStep(TreeItem* stepItem, const QString& stepId) const { - QCOMPARE(rootStepItem->text(), i18nc("@item", "Steps:")); - QVERIFY(qobject_cast<StepTreeItem*>(rootStepItem->child(index))); - QCOMPARE(rootStepItem->child(index)->text(), - i18nc("@item", "Step %1", stepId)); + QVERIFY(qobject_cast<StepTreeItem*>(stepItem)); + QCOMPARE(stepItem->text(), i18nc("@item", "Step %1", stepId)); } void TutorialTreeItemTest::assertDataChanged(const QSignalSpy& spy, int index, Modified: trunk/ktutorial/ktutorial-editor/tests/unit/view/TutorialTreeSelectionManagerTest.cpp =================================================================== --- trunk/ktutorial/ktutorial-editor/tests/unit/view/TutorialTreeSelectionManagerTest.cpp 2010-03-15 09:06:46 UTC (rev 156) +++ trunk/ktutorial/ktutorial-editor/tests/unit/view/TutorialTreeSelectionManagerTest.cpp 2010-03-15 18:58:22 UTC (rev 157) @@ -131,23 +131,21 @@ //Tear down select(mTreeModel->index(4, 0)); select(mTreeModel->index(0, 0, mTreeModel->index(4, 0))); - //Steps root - select(mTreeModel->index(5, 0)); QCOMPARE(mStepSelectedSpy->count(), 0); } void TutorialTreeSelectionManagerTest:: testSelectStepOrChildrenChangingToOtherItems() { - QModelIndex step1Index = mTreeModel->index(0, 0, mTreeModel->index(5, 0)); + QModelIndex step1Index = mTreeModel->index(5, 0); select(step1Index); QCOMPARE(mStepSelectedSpy->count(), 1); assertStepSignal(mStepSelectedSpy, 0, mStep1); - //Steps root - select(mTreeModel->index(5, 0)); + //Tutorial name + select(mTreeModel->index(0, 0)); QCOMPARE(mStepSelectedSpy->count(), 2); assertStepSignal(mStepSelectedSpy, 1, 0); @@ -158,7 +156,7 @@ QCOMPARE(mStepSelectedSpy->count(), 3); assertStepSignal(mStepSelectedSpy, 2, mStep1); - select(mTreeModel->index(5, 0)); + select(mTreeModel->index(0, 0)); QCOMPARE(mStepSelectedSpy->count(), 4); assertStepSignal(mStepSelectedSpy, 3, 0); @@ -169,7 +167,7 @@ QCOMPARE(mStepSelectedSpy->count(), 5); assertStepSignal(mStepSelectedSpy, 4, mStep1); - select(mTreeModel->index(5, 0)); + select(mTreeModel->index(0, 0)); QCOMPARE(mStepSelectedSpy->count(), 6); assertStepSignal(mStepSelectedSpy, 5, 0); @@ -180,7 +178,7 @@ QCOMPARE(mStepSelectedSpy->count(), 7); assertStepSignal(mStepSelectedSpy, 6, mStep1); - select(mTreeModel->index(5, 0)); + select(mTreeModel->index(0, 0)); QCOMPARE(mStepSelectedSpy->count(), 8); assertStepSignal(mStepSelectedSpy, 7, 0); @@ -191,7 +189,7 @@ QCOMPARE(mStepSelectedSpy->count(), 9); assertStepSignal(mStepSelectedSpy, 8, mStep1); - select(mTreeModel->index(5, 0)); + select(mTreeModel->index(0, 0)); QCOMPARE(mStepSelectedSpy->count(), 10); assertStepSignal(mStepSelectedSpy, 9, 0); @@ -202,7 +200,7 @@ QCOMPARE(mStepSelectedSpy->count(), 11); assertStepSignal(mStepSelectedSpy, 10, mStep1); - select(mTreeModel->index(5, 0)); + select(mTreeModel->index(0, 0)); QCOMPARE(mStepSelectedSpy->count(), 12); assertStepSignal(mStepSelectedSpy, 11, 0); @@ -210,7 +208,7 @@ void TutorialTreeSelectionManagerTest:: testSelectStepOrChildrenWithoutChangingStep() { - QModelIndex step1Index = mTreeModel->index(0, 0, mTreeModel->index(5, 0)); + QModelIndex step1Index = mTreeModel->index(5, 0); select(step1Index); @@ -245,8 +243,8 @@ void TutorialTreeSelectionManagerTest:: testSelectStepOrChildrenChangingToAnotherStep() { - QModelIndex step1Index = mTreeModel->index(0, 0, mTreeModel->index(5, 0)); - QModelIndex step2Index = mTreeModel->index(1, 0, mTreeModel->index(5, 0)); + QModelIndex step1Index = mTreeModel->index(5, 0); + QModelIndex step2Index = mTreeModel->index(6, 0); select(step1Index); This was sent by the SourceForge.net collaborative development platform, the world's largest Open Source development site. |
From: <dan...@us...> - 2010-03-15 19:02:12
|
Revision: 158 http://ktutorial.svn.sourceforge.net/ktutorial/?rev=158&view=rev Author: danxuliu Date: 2010-03-15 19:02:05 +0000 (Mon, 15 Mar 2010) Log Message: ----------- Include a list of Reactions in Step, and adapt StepTreeItem to show them. Modified Paths: -------------- trunk/ktutorial/ktutorial-editor/src/Step.cpp trunk/ktutorial/ktutorial-editor/src/Step.h trunk/ktutorial/ktutorial-editor/src/view/StepTreeItem.cpp trunk/ktutorial/ktutorial-editor/src/view/StepTreeItem.h trunk/ktutorial/ktutorial-editor/tests/unit/StepTest.cpp trunk/ktutorial/ktutorial-editor/tests/unit/view/StepTreeItemTest.cpp Modified: trunk/ktutorial/ktutorial-editor/src/Step.cpp =================================================================== --- trunk/ktutorial/ktutorial-editor/src/Step.cpp 2010-03-15 18:58:22 UTC (rev 157) +++ trunk/ktutorial/ktutorial-editor/src/Step.cpp 2010-03-15 19:02:05 UTC (rev 158) @@ -17,12 +17,17 @@ ***************************************************************************/ #include "Step.h" +#include "Reaction.h" //public: Step::Step(QObject* parent): QObject(parent) { } +Step::~Step() { + qDeleteAll(mReactions); +} + QString Step::id() const { return mId; } @@ -62,3 +67,23 @@ emit dataChanged(this); } + +void Step::addReaction(Reaction* reaction) { + Q_ASSERT(!mReactions.contains(reaction)); + + mReactions.append(reaction); + + emit reactionAdded(reaction); +} + +QList<Reaction*> Step::reactions() const { + return mReactions; +} + +void Step::removeReaction(Reaction* reaction) { + Q_ASSERT(mReactions.contains(reaction)); + + mReactions.removeOne(reaction); + + emit reactionRemoved(reaction); +} Modified: trunk/ktutorial/ktutorial-editor/src/Step.h =================================================================== --- trunk/ktutorial/ktutorial-editor/src/Step.h 2010-03-15 18:58:22 UTC (rev 157) +++ trunk/ktutorial/ktutorial-editor/src/Step.h 2010-03-15 19:02:05 UTC (rev 158) @@ -21,13 +21,17 @@ #include <QObject> +class Reaction; + /** * Container for step data. * It stores the data used in KTutorial steps, but it has nothing to do with * them (they don't even know each other). Its purpose is store the data needed to * generate the code to create a true KTutorial::Step. * - * When any attribute is modified, dataChanged(Step*) signal is emitted. + * When any attribute is modified, dataChanged(Step*) signal is emitted. When + * reactions are added or removed, reactionAdded(Reaction*) and + * reactionRemoved(Reaction*) are emitted. */ class Step: public QObject { Q_OBJECT @@ -35,6 +39,11 @@ Step(QObject* parent = 0); + /** + * Destroys this Step and all its reactions. + */ + virtual ~Step(); + QString id() const; void setId(const QString& id); @@ -47,6 +56,24 @@ QString customTearDownCode() const; void setCustomTearDownCode(const QString& code); + /** + * Adds a new reaction to this Step. + * The Step gets ownership of the Reaction, so it is deleted when the + * Step is deleted. + * + * @param reaction The reaction to add. + */ + void addReaction(Reaction* reaction); + QList<Reaction*> reactions() const; + + /** + * Removes a reaction from this Step. + * The Reaction must be deleted explicitly. + * + * @param reaction The reaction to remove. + */ + void removeReaction(Reaction* reaction); + Q_SIGNALS: /** @@ -56,12 +83,27 @@ */ void dataChanged(Step* step); + /** + * Emitted when the reaction is added to this Step. + * + * @param reaction The reaction added. + */ + void reactionAdded(Reaction* reaction); + + /** + * Emitted when the reaction is removed from this Step. + * + * @param reaction The reaction removed. + */ + void reactionRemoved(Reaction* reaction); + private: QString mId; QString mText; QString mCustomSetupCode; QString mCustomTearDownCode; + QList<Reaction*> mReactions; }; Modified: trunk/ktutorial/ktutorial-editor/src/view/StepTreeItem.cpp =================================================================== --- trunk/ktutorial/ktutorial-editor/src/view/StepTreeItem.cpp 2010-03-15 18:58:22 UTC (rev 157) +++ trunk/ktutorial/ktutorial-editor/src/view/StepTreeItem.cpp 2010-03-15 19:02:05 UTC (rev 158) @@ -20,6 +20,7 @@ #include <KLocalizedString> +#include "ReactionTreeItem.h" #include "TextTreeItem.h" #include "TreeItemUtil.h" #include "../Step.h" @@ -38,6 +39,14 @@ update(step); connect(step, SIGNAL(dataChanged(Step*)), this, SLOT(update(Step*))); + + foreach(Reaction* reaction, step->reactions()) { + addReaction(reaction); + } + connect(step, SIGNAL(reactionAdded(Reaction*)), + this, SLOT(addReaction(Reaction*))); + connect(step, SIGNAL(reactionRemoved(Reaction*)), + this, SLOT(removeReaction(Reaction*))); } QString StepTreeItem::text() const { @@ -52,6 +61,19 @@ return mStep; } +//private: + +ReactionTreeItem* StepTreeItem::reactionTreeItemForReaction( + Reaction* reaction) const { + foreach (ReactionTreeItem* reactionTreeItem, mReactionTreeItems) { + if (reactionTreeItem->reaction() == reaction) { + return reactionTreeItem; + } + } + + return 0; +} + //private slots: void StepTreeItem::update(Step* step) { @@ -96,3 +118,17 @@ childIndex++; } } + +void StepTreeItem::addReaction(Reaction* reaction) { + ReactionTreeItem* reactionTreeItem = new ReactionTreeItem(reaction, this); + appendChild(reactionTreeItem); + mReactionTreeItems.append(reactionTreeItem); +} + +void StepTreeItem::removeReaction(Reaction* reaction) { + ReactionTreeItem* reactionTreeItem = reactionTreeItemForReaction(reaction); + + removeChild(reactionTreeItem); + mReactionTreeItems.removeOne(reactionTreeItem); + delete reactionTreeItem; +} Modified: trunk/ktutorial/ktutorial-editor/src/view/StepTreeItem.h =================================================================== --- trunk/ktutorial/ktutorial-editor/src/view/StepTreeItem.h 2010-03-15 18:58:22 UTC (rev 157) +++ trunk/ktutorial/ktutorial-editor/src/view/StepTreeItem.h 2010-03-15 19:02:05 UTC (rev 158) @@ -21,6 +21,8 @@ #include "TreeItem.h" +class Reaction; +class ReactionTreeItem; class Step; class TextTreeItem; @@ -32,7 +34,12 @@ * |-Setup: * | -The custom setup code * --Tear down: - * -The custom tear down code + * | -The custom tear down code + * |-Reaction + * | ... + * |-Reaction + * | ... + * ... * * The items only appear if they have some data to show. For example, if only * the text of the Step is set, its representation is: @@ -48,6 +55,8 @@ * Also note that the order of the child elements is always the same. Even if, * for example, the setup code is set first and then the text, the text item * will appear first and then the setup code item. + * + * @see ReactionTreeItem */ class StepTreeItem: public TreeItem { Q_OBJECT @@ -108,6 +117,19 @@ */ TextTreeItem* mTearDownItem; + /** + * The ReactionTreeItems for each Reaction in the Step. + */ + QList<ReactionTreeItem*> mReactionTreeItems; + + /** + * Returns the ReactionTreeItem for the given Reaction. + * + * @param reaction The Reaction to get its ReactionTreeItem. + * @return The ReactionTreeItem. + */ + ReactionTreeItem* reactionTreeItemForReaction(Reaction* reaction) const; + private Q_SLOTS: /** @@ -122,6 +144,20 @@ */ void update(Step* step); + /** + * Adds a new ReactionTreeItem when a Reaction is added in the step. + * + * @param step The Reaction added in the Step. + */ + void addReaction(Reaction* reaction); + + /** + * Removes the ReactionTreeItem for the Reaction removed in the step. + * + * @param reaction The Reaction removed in the Step. + */ + void removeReaction(Reaction* reaction); + }; #endif Modified: trunk/ktutorial/ktutorial-editor/tests/unit/StepTest.cpp =================================================================== --- trunk/ktutorial/ktutorial-editor/tests/unit/StepTest.cpp 2010-03-15 18:58:22 UTC (rev 157) +++ trunk/ktutorial/ktutorial-editor/tests/unit/StepTest.cpp 2010-03-15 19:02:05 UTC (rev 158) @@ -19,12 +19,15 @@ #include <QtTest> #include "Step.h" +#include "Reaction.h" class StepTest: public QObject { Q_OBJECT private slots: + void initTestCase(); + void testConstructor(); void testSetId(); @@ -35,8 +38,22 @@ void testSetCustomTearDownCode(); + void testAddReaction(); + void testRemoveReaction(); + +private: + + int mReactionStarType; + + void assertReactionSignal(const QSignalSpy& spy, int index, + Reaction* reaction) const; }; +void StepTest::initTestCase() { + //Reaction* must be registered in order to be used with QSignalSpy + mReactionStarType = qRegisterMetaType<Reaction*>("Reaction*"); +} + void StepTest::testConstructor() { QObject parent; Step* step = new Step(&parent); @@ -111,6 +128,74 @@ QCOMPARE(qvariant_cast<Step*>(argument), &step); } +void StepTest::testAddReaction() { + Step step; + Reaction* reaction1 = new Reaction(); + Reaction* reaction2 = new Reaction(); + Reaction* reaction3 = new Reaction(); + + QSignalSpy reactionAddedSpy(&step, SIGNAL(reactionAdded(Reaction*))); + + step.addReaction(reaction1); + step.addReaction(reaction2); + step.addReaction(reaction3); + + QCOMPARE(step.reactions().count(), 3); + QCOMPARE(step.reactions()[0], reaction1); + QCOMPARE(step.reactions()[1], reaction2); + QCOMPARE(step.reactions()[2], reaction3); + QCOMPARE(reactionAddedSpy.count(), 3); + assertReactionSignal(reactionAddedSpy, 0, reaction1); + assertReactionSignal(reactionAddedSpy, 1, reaction2); + assertReactionSignal(reactionAddedSpy, 2, reaction3); +} + +void StepTest::testRemoveReaction() { + Step step; + + //They will be removed and not deleted by the Step, so they are created in + //stack + Reaction reaction1; + Reaction reaction2; + Reaction reaction3; + + step.addReaction(&reaction1); + step.addReaction(&reaction2); + step.addReaction(&reaction3); + + QSignalSpy reactionRemovedSpy(&step, SIGNAL(reactionRemoved(Reaction*))); + + step.removeReaction(&reaction2); + + QCOMPARE(step.reactions().count(), 2); + QCOMPARE(step.reactions()[0], &reaction1); + QCOMPARE(step.reactions()[1], &reaction3); + QCOMPARE(reactionRemovedSpy.count(), 1); + assertReactionSignal(reactionRemovedSpy, 0, &reaction2); + + step.removeReaction(&reaction1); + step.removeReaction(&reaction3); + + QCOMPARE(step.reactions().count(), 0); + QCOMPARE(reactionRemovedSpy.count(), 3); + assertReactionSignal(reactionRemovedSpy, 1, &reaction1); + assertReactionSignal(reactionRemovedSpy, 2, &reaction3); +} + +/////////////////////////////////// Helpers //////////////////////////////////// + +//Reaction* must be declared as a metatype to be used in qvariant_cast +Q_DECLARE_METATYPE(Reaction*); + +void StepTest::assertReactionSignal(const QSignalSpy& spy, int index, + Reaction* reaction) const { + QCOMPARE(spy.at(index).count(), 1); + + QVariant argument = spy.at(index).at(0); + QCOMPARE(argument.userType(), mReactionStarType); + QCOMPARE(qvariant_cast<Reaction*>(argument), reaction); +} + QTEST_MAIN(StepTest) #include "StepTest.moc" Modified: trunk/ktutorial/ktutorial-editor/tests/unit/view/StepTreeItemTest.cpp =================================================================== --- trunk/ktutorial/ktutorial-editor/tests/unit/view/StepTreeItemTest.cpp 2010-03-15 18:58:22 UTC (rev 157) +++ trunk/ktutorial/ktutorial-editor/tests/unit/view/StepTreeItemTest.cpp 2010-03-15 19:02:05 UTC (rev 158) @@ -22,7 +22,9 @@ #include <KLocalizedString> +#include "ReactionTreeItem.h" #include "../Step.h" +#include "../Reaction.h" class StepTreeItemTest: public QObject { Q_OBJECT @@ -50,6 +52,10 @@ void testStepSetCustomTearDownCodeChange(); void testStepSetCustomTearDownCodeEmpty(); + void testStepAddReaction(); + + void testStepRemoveReaction(); + void testChildOrderWhenSettingDataInStep(); void testChildOrderWhenUnsettingDataInStep(); @@ -61,6 +67,7 @@ void assertCustomSetupCode(TreeItem* setupItem, const QString& code) const; void assertCustomTearDownCode(TreeItem* tearDownItem, const QString& code) const; + void assertReaction(TreeItem* reactionItem, const Reaction* reaction) const; void assertDataChanged(const QSignalSpy& spy, int index, TreeItem* item) const; @@ -98,16 +105,24 @@ step.setCustomSetupCode("The setup code"); step.setCustomTearDownCode("The tear down code"); + Reaction* reaction1 = new Reaction(); + step.addReaction(reaction1); + + Reaction* reaction2 = new Reaction(); + step.addReaction(reaction2); + StubTreeItem parent; StepTreeItem item(&step, &parent); QCOMPARE(item.parent(), &parent); QCOMPARE(item.text(), i18nc("@item", "Step %1", "The id")); QCOMPARE(item.step(), &step); - QCOMPARE(item.childCount(), 3); + QCOMPARE(item.childCount(), 5); assertText(item.child(0), "The text"); assertCustomSetupCode(item.child(1), "The setup code"); assertCustomTearDownCode(item.child(2), "The tear down code"); + assertReaction(item.child(3), reaction1); + assertReaction(item.child(4), reaction2); } //TreeItem* must be declared as a metatype to be used in qvariant_cast @@ -271,6 +286,30 @@ QCOMPARE(item.childCount(), 0); } +void StepTreeItemTest::testStepAddReaction() { + Step step; + StepTreeItem item(&step); + + Reaction* reaction = new Reaction(); + step.addReaction(reaction); + + QCOMPARE(item.childCount(), 1); + assertReaction(item.child(0), reaction); +} + +void StepTreeItemTest::testStepRemoveReaction() { + Step step; + StepTreeItem item(&step); + + //It will be removed and not deleted by the Step, so it is created in + //stack + Reaction reaction; + step.addReaction(&reaction); + step.removeReaction(&reaction); + + QCOMPARE(item.childCount(), 0); +} + void StepTreeItemTest::testChildOrderWhenSettingDataInStep() { Step step; StepTreeItem item(&step); @@ -288,21 +327,44 @@ assertText(item.child(0), "The text"); assertCustomSetupCode(item.child(1), "The setup code"); - step.setCustomTearDownCode("The tear down code"); + Reaction* reaction1 = new Reaction(); + step.addReaction(reaction1); QCOMPARE(item.text(), i18nc("@item", "Step")); QCOMPARE(item.childCount(), 3); assertText(item.child(0), "The text"); assertCustomSetupCode(item.child(1), "The setup code"); + assertReaction(item.child(2), reaction1); + + step.setCustomTearDownCode("The tear down code"); + + QCOMPARE(item.text(), i18nc("@item", "Step")); + QCOMPARE(item.childCount(), 4); + assertText(item.child(0), "The text"); + assertCustomSetupCode(item.child(1), "The setup code"); assertCustomTearDownCode(item.child(2), "The tear down code"); + assertReaction(item.child(3), reaction1); + Reaction* reaction2 = new Reaction(); + step.addReaction(reaction2); + + QCOMPARE(item.text(), i18nc("@item", "Step")); + QCOMPARE(item.childCount(), 5); + assertText(item.child(0), "The text"); + assertCustomSetupCode(item.child(1), "The setup code"); + assertCustomTearDownCode(item.child(2), "The tear down code"); + assertReaction(item.child(3), reaction1); + assertReaction(item.child(4), reaction2); + step.setId("The id"); QCOMPARE(item.text(), i18nc("@item", "Step %1", "The id")); - QCOMPARE(item.childCount(), 3); + QCOMPARE(item.childCount(), 5); assertText(item.child(0), "The text"); assertCustomSetupCode(item.child(1), "The setup code"); assertCustomTearDownCode(item.child(2), "The tear down code"); + assertReaction(item.child(3), reaction1); + assertReaction(item.child(4), reaction2); } void StepTreeItemTest::testChildOrderWhenUnsettingDataInStep() { @@ -312,30 +374,54 @@ step.setCustomSetupCode("The setup code"); step.setCustomTearDownCode("The tear down code"); + Reaction reaction1; + step.addReaction(&reaction1); + + Reaction reaction2; + step.addReaction(&reaction2); + StepTreeItem item(&step); step.setText(""); QCOMPARE(item.text(), i18nc("@item", "Step %1", "The id")); - QCOMPARE(item.childCount(), 2); + QCOMPARE(item.childCount(), 4); assertCustomSetupCode(item.child(0), "The setup code"); assertCustomTearDownCode(item.child(1), "The tear down code"); + assertReaction(item.child(2), &reaction1); + assertReaction(item.child(3), &reaction2); + step.removeReaction(&reaction1); + + QCOMPARE(item.text(), i18nc("@item", "Step %1", "The id")); + QCOMPARE(item.childCount(), 3); + assertCustomSetupCode(item.child(0), "The setup code"); + assertCustomTearDownCode(item.child(1), "The tear down code"); + assertReaction(item.child(2), &reaction2); + step.setCustomTearDownCode(""); QCOMPARE(item.text(), i18nc("@item", "Step %1", "The id")); - QCOMPARE(item.childCount(), 1); + QCOMPARE(item.childCount(), 2); assertCustomSetupCode(item.child(0), "The setup code"); + assertReaction(item.child(1), &reaction2); step.setId(""); QCOMPARE(item.text(), i18nc("@item", "Step")); - QCOMPARE(item.childCount(), 1); + QCOMPARE(item.childCount(), 2); assertCustomSetupCode(item.child(0), "The setup code"); + assertReaction(item.child(1), &reaction2); step.setCustomSetupCode(""); QCOMPARE(item.text(), i18nc("@item", "Step")); + QCOMPARE(item.childCount(), 1); + assertReaction(item.child(0), &reaction2); + + step.removeReaction(&reaction2); + + QCOMPARE(item.text(), i18nc("@item", "Step")); QCOMPARE(item.childCount(), 0); } @@ -360,6 +446,13 @@ QCOMPARE(tearDownItem->child(0)->text(), i18nc("@item", code.toAscii())); } +void StepTreeItemTest::assertReaction(TreeItem* reactionItem, + const Reaction* reaction) const { + QVERIFY(qobject_cast<ReactionTreeItem*>(reactionItem)); + QCOMPARE(static_cast<ReactionTreeItem*>(reactionItem)->reaction(), + reaction); +} + void StepTreeItemTest::assertDataChanged(const QSignalSpy& spy, int index, TreeItem* item) const { QCOMPARE(spy.at(index).count(), 1); This was sent by the SourceForge.net collaborative development platform, the world's largest Open Source development site. |
From: <dan...@us...> - 2010-03-16 00:16:39
|
Revision: 159 http://ktutorial.svn.sourceforge.net/ktutorial/?rev=159&view=rev Author: danxuliu Date: 2010-03-16 00:16:31 +0000 (Tue, 16 Mar 2010) Log Message: ----------- -Fix adding and removing the root WaitForTreeItem when the root WaitFor was added or removed. -Fix disabling add button when the root WaitFor was added or when a negated WaitFor was added to a WaitForNot. -Fix cancelling the addWaitFor dialog. -Fix the window title for the addWaitFor dialog. Modified Paths: -------------- trunk/ktutorial/ktutorial-editor/src/view/WaitForWidget.cpp trunk/ktutorial/ktutorial-editor/src/view/WaitForWidget.h trunk/ktutorial/ktutorial-editor/tests/unit/view/WaitForWidgetTest.cpp Modified: trunk/ktutorial/ktutorial-editor/src/view/WaitForWidget.cpp =================================================================== --- trunk/ktutorial/ktutorial-editor/src/view/WaitForWidget.cpp 2010-03-15 19:02:05 UTC (rev 158) +++ trunk/ktutorial/ktutorial-editor/src/view/WaitForWidget.cpp 2010-03-16 00:16:31 UTC (rev 159) @@ -64,14 +64,15 @@ //private: void WaitForWidget::setupTreeView(WaitFor* waitFor) { - TextTreeItem* rootItem = new TextTreeItem(); + mRootItem = new TextTreeItem(); if (waitFor) { - TreeItem* item = WaitForTreeItem::treeItemForWaitFor(waitFor, rootItem); - rootItem->appendChild(item); + TreeItem* item = WaitForTreeItem::treeItemForWaitFor(waitFor, + mRootItem); + mRootItem->appendChild(item); } QTreeView* treeView = ui->waitForTreeView; - TreeModel* model = new TreeModel(rootItem, treeView); + TreeModel* model = new TreeModel(mRootItem, treeView); QAbstractItemModel* oldModel = treeView->model(); treeView->setModel(model); @@ -156,14 +157,26 @@ KDialog* dialog = new KDialog(this); NewWaitForWidget* widget = new NewWaitForWidget(dialog); dialog->setMainWidget(widget); + dialog->setWindowTitle(widget->windowTitle()); dialog->setObjectName("addWaitForDialog"); if (dialog->exec() == QDialog::Accepted) { newWaitFor = widget->waitFor(); } dialog->deleteLater(); + if (!newWaitFor) { + return; + } + if (!mWaitFor) { + ui->addButton->setEnabled(false); + + TreeItem* item = WaitForTreeItem::treeItemForWaitFor(newWaitFor, + mRootItem); + mRootItem->appendChild(item); + mWaitFor = newWaitFor; + return; } @@ -176,6 +189,8 @@ } if (qobject_cast<WaitForNot*>(mCurrentWaitFor)) { + ui->addButton->setEnabled(false); + WaitForNot* waitForNot = static_cast<WaitForNot*>(mCurrentWaitFor); waitForNot->setNegatedWaitFor(newWaitFor); @@ -208,6 +223,10 @@ delete mWaitFor; mWaitFor = 0; + TreeItem* item = static_cast<TreeItem*>(index.internalPointer()); + mRootItem->removeChild(item); + delete item; + return; } Modified: trunk/ktutorial/ktutorial-editor/src/view/WaitForWidget.h =================================================================== --- trunk/ktutorial/ktutorial-editor/src/view/WaitForWidget.h 2010-03-15 19:02:05 UTC (rev 158) +++ trunk/ktutorial/ktutorial-editor/src/view/WaitForWidget.h 2010-03-16 00:16:31 UTC (rev 159) @@ -22,6 +22,7 @@ #include <QWidget> class QItemSelection; +class TreeItem; class WaitFor; namespace Ui { @@ -81,6 +82,13 @@ WaitFor* mCurrentWaitFor; /** + * The root tree item in the tree view. + * It provides the header in the tree view, and acts as parent item for the + * tree item that represents mWaitFor. + */ + TreeItem* mRootItem; + + /** * The Ui Designer generated class. */ Ui::WaitForWidget* ui; @@ -113,7 +121,10 @@ /** * Shows a dialog with a NewWaitForWidget and adds the new WaitFor. * The WaitFor is added to the selected WaitFor, or as the root WaitFor if - * there is none. + * there is none (a new WaitForTreeItem is also added in that case). + * + * When a WaitFor is added the selection doesn't change, so some buttons are + * updated as needed. */ void addWaitFor(); @@ -124,6 +135,8 @@ /** * Removes the selected WaitFor. + * If the root WaitFor is removed, its tree item is also removed from the + * root item. */ void removeWaitFor(); Modified: trunk/ktutorial/ktutorial-editor/tests/unit/view/WaitForWidgetTest.cpp =================================================================== --- trunk/ktutorial/ktutorial-editor/tests/unit/view/WaitForWidgetTest.cpp 2010-03-15 19:02:05 UTC (rev 158) +++ trunk/ktutorial/ktutorial-editor/tests/unit/view/WaitForWidgetTest.cpp 2010-03-16 00:16:31 UTC (rev 159) @@ -36,6 +36,7 @@ public slots: void addWaitForSignal() const; + void cancelAddWaitForDialog() const; void setSignalData() const; @@ -57,6 +58,7 @@ void testAddWaitForWhenEmpty(); void testAddWaitForToWaitForComposed(); void testAddWaitForToWaitForNot(); + void testAddWaitForCancellingDialog(); void testEditWaitForSignal(); @@ -189,6 +191,9 @@ QVERIFY(mWidget->waitFor()); QVERIFY(qobject_cast<WaitForSignal*>(mWidget->waitFor())); + QVERIFY(getIndex(0).isValid()); + //No item is selected after adding the WaitFor + assertButtonEnabled(false, false, false); delete mWidget->waitFor(); } @@ -235,8 +240,28 @@ QCOMPARE(mWaitFor->waitFors()[2], mWaitFor3); QCOMPARE(mWaitFor->waitFors()[3], mWaitFor4); QVERIFY(qobject_cast<WaitForSignal*>(mWaitFor4->negatedWaitFor())); + //The WaitForNot item is selected after adding the negated WaitFor, so "Add" + //button must be disabled + assertButtonEnabled(false, false, true); } +void WaitForWidgetTest::testAddWaitForCancellingDialog() { + delete mWidget; + mWidget = new WaitForWidget(0); + + //The dialog is modal, so it won't return to the test code until it is + //closed. Thus, the commands to execute on the dialog must be "queued", + //as calling cancelAddWaitForDialog after the button click won't work. + QTimer::singleShot(500, this, SLOT(cancelAddWaitForDialog())); + + button("addButton")->click(); + + QVERIFY(!mWidget->waitFor()); + QVERIFY(!getIndex(0).isValid()); + //Buttons shouldn't change after cancelling the dialog + assertButtonEnabled(true, false, false); +} + void WaitForWidgetTest::testEditWaitForSignal() { selectItem(getIndex(0, getIndex(0))); @@ -260,6 +285,8 @@ button("removeButton")->click(); QVERIFY(!mWidget->waitFor()); + QVERIFY(!getIndex(0).isValid()); + assertButtonEnabled(true, false, false); } void WaitForWidgetTest::testRemoveWaitForFromWaitForComposed() { @@ -296,6 +323,12 @@ dialog->button(KDialog::Ok)->click(); } +void WaitForWidgetTest::cancelAddWaitForDialog() const { + KDialog* dialog = mWidget->findChild<KDialog*>("addWaitForDialog"); + QVERIFY(dialog); + dialog->button(KDialog::Cancel)->click(); +} + void WaitForWidgetTest::setSignalData() const { KLineEdit* emitterNameLineEdit = mWidget->findChild<KLineEdit*>("emitterNameLineEdit"); This was sent by the SourceForge.net collaborative development platform, the world's largest Open Source development site. |
From: <dan...@us...> - 2010-03-16 02:12:09
|
Revision: 160 http://ktutorial.svn.sourceforge.net/ktutorial/?rev=160&view=rev Author: danxuliu Date: 2010-03-16 02:12:03 +0000 (Tue, 16 Mar 2010) Log Message: ----------- Fix crash when a reaction was saved and there was no WaitFor in the reaction or in the data to save. Modified Paths: -------------- trunk/ktutorial/ktutorial-editor/src/view/ReactionWidget.cpp trunk/ktutorial/ktutorial-editor/tests/unit/view/ReactionWidgetTest.cpp Modified: trunk/ktutorial/ktutorial-editor/src/view/ReactionWidget.cpp =================================================================== --- trunk/ktutorial/ktutorial-editor/src/view/ReactionWidget.cpp 2010-03-16 00:16:31 UTC (rev 159) +++ trunk/ktutorial/ktutorial-editor/src/view/ReactionWidget.cpp 2010-03-16 02:12:03 UTC (rev 160) @@ -77,7 +77,8 @@ mReaction->setOptionName(ui->triggerOptionLineEdit->text()); } - if (*mReaction->waitFor() != *mWaitForWidget->waitFor()) { + if (!mReaction->waitFor() || !mWaitForWidget->waitFor() || + *mReaction->waitFor() != *mWaitForWidget->waitFor()) { WaitFor* oldWaitFor = mReaction->waitFor(); mReaction->setWaitFor(mWaitForWidget->waitFor()); delete oldWaitFor; Modified: trunk/ktutorial/ktutorial-editor/tests/unit/view/ReactionWidgetTest.cpp =================================================================== --- trunk/ktutorial/ktutorial-editor/tests/unit/view/ReactionWidgetTest.cpp 2010-03-16 00:16:31 UTC (rev 159) +++ trunk/ktutorial/ktutorial-editor/tests/unit/view/ReactionWidgetTest.cpp 2010-03-16 02:12:03 UTC (rev 160) @@ -48,6 +48,7 @@ void testSelectResponseTypeCustomCode(); void testSaveChanges(); + void testSaveChangesWithNoWaitFor(); private: @@ -60,6 +61,7 @@ QRadioButton* responseCodeRadioButton(ReactionWidget* widget) const; KTextEdit* responseCodeTextEdit(ReactionWidget* widget) const; + void addWaitForSignal(ReactionWidget* widget); void addWaitForSignalToRootWaitFor(ReactionWidget* widget); }; @@ -178,6 +180,23 @@ QCOMPARE(reaction.customCode(), QString("The custom code")); } +void ReactionWidgetTest::testSaveChangesWithNoWaitFor() { + Reaction reaction; + reaction.setTriggerType(Reaction::ConditionMet); + + ReactionWidget widget(&reaction); + + widget.saveChanges(); + + QCOMPARE(reaction.waitFor(), (WaitFor*)0); + + addWaitForSignal(&widget); + widget.saveChanges(); + + QVERIFY(reaction.waitFor() != 0); + QVERIFY(qobject_cast<WaitForSignal*>(reaction.waitFor())); +} + /////////////////////////////////// Helpers //////////////////////////////////// QRadioButton* ReactionWidgetTest::triggerOptionRadioButton( @@ -248,11 +267,7 @@ }; -void ReactionWidgetTest::addWaitForSignalToRootWaitFor(ReactionWidget* widget) { - QTreeView* tree = widget->findChild<QTreeView*>("waitForTreeView"); - QModelIndex index = tree->model()->index(0, 0); - tree->selectionModel()->select(index, QItemSelectionModel::SelectCurrent); - +void ReactionWidgetTest::addWaitForSignal(ReactionWidget* widget) { AddWaitForSignalHelper* helper = new AddWaitForSignalHelper(widget, this); //The dialog is modal, so it won't return to the test code until it is @@ -263,6 +278,14 @@ widget->findChild<KPushButton*>("addButton")->click(); } +void ReactionWidgetTest::addWaitForSignalToRootWaitFor(ReactionWidget* widget) { + QTreeView* tree = widget->findChild<QTreeView*>("waitForTreeView"); + QModelIndex index = tree->model()->index(0, 0); + tree->selectionModel()->select(index, QItemSelectionModel::SelectCurrent); + + addWaitForSignal(widget); +} + QTEST_MAIN(ReactionWidgetTest) #include "ReactionWidgetTest.moc" This was sent by the SourceForge.net collaborative development platform, the world's largest Open Source development site. |
From: <dan...@us...> - 2010-03-16 03:00:41
|
Revision: 161 http://ktutorial.svn.sourceforge.net/ktutorial/?rev=161&view=rev Author: danxuliu Date: 2010-03-16 03:00:35 +0000 (Tue, 16 Mar 2010) Log Message: ----------- -Add actions to add, edit and remove reactions. -Adapt TutorialTreeSelectionManager to emit reactionSelected(Reaction*) when a reaction is selected. Modified Paths: -------------- trunk/ktutorial/ktutorial-editor/src/KTutorialEditor.cpp trunk/ktutorial/ktutorial-editor/src/KTutorialEditor.h trunk/ktutorial/ktutorial-editor/src/ktutorial-editorui.rc trunk/ktutorial/ktutorial-editor/src/view/TutorialTreeSelectionManager.cpp trunk/ktutorial/ktutorial-editor/src/view/TutorialTreeSelectionManager.h trunk/ktutorial/ktutorial-editor/tests/unit/view/TutorialTreeSelectionManagerTest.cpp Modified: trunk/ktutorial/ktutorial-editor/src/KTutorialEditor.cpp =================================================================== --- trunk/ktutorial/ktutorial-editor/src/KTutorialEditor.cpp 2010-03-16 02:12:03 UTC (rev 160) +++ trunk/ktutorial/ktutorial-editor/src/KTutorialEditor.cpp 2010-03-16 03:00:35 UTC (rev 161) @@ -26,11 +26,13 @@ #include <KApplication> #include <KLocalizedString> +#include "Reaction.h" #include "Step.h" #include "Tutorial.h" #include "view/ActionListWidget.h" #include "view/EditionDialog.h" #include "view/LicenseWidget.h" +#include "view/ReactionWidget.h" #include "view/StepCustomCodeWidget.h" #include "view/StepDataWidget.h" #include "view/TreeModel.h" @@ -71,6 +73,8 @@ new TutorialTreeSelectionManager(mTreeView->selectionModel(), this); connect(selectionManager, SIGNAL(stepSelected(Step*)), this, SLOT(selectStep(Step*))); + connect(selectionManager, SIGNAL(reactionSelected(Reaction*)), + this, SLOT(selectReaction(Reaction*))); } void KTutorialEditor::setupDocks() { @@ -82,6 +86,11 @@ mStepActionDock = new QDockWidget(i18nc("@title", "Edit step"), this); mStepActionDock->setObjectName("editStepDock"); addDockWidget(Qt::RightDockWidgetArea, mStepActionDock); + + mReactionActionDock = new QDockWidget(i18nc("@title", "Edit reaction"), + this); + mReactionActionDock->setObjectName("editReactionDock"); + addDockWidget(Qt::RightDockWidgetArea, mReactionActionDock); } void KTutorialEditor::setupActions() { @@ -181,11 +190,46 @@ actionListWidget->addAction(action); mStepActionDock->setWidget(actionListWidget); + actionListWidget = new ActionListWidget(mReactionActionDock); + action = new KAction(this); + action->setText(i18nc("@action", "Add reaction...")); + action->setStatusTip(i18nc("@info:status", "Add a new reaction to the " +"selected step.")); + action->setIcon(KIcon("list-add")); + action->setEnabled(false); + actionCollection()->addAction("addReaction", action); + connect(action, SIGNAL(triggered(bool)), this, SLOT(addReaction())); + actionListWidget->addAction(action); + + action = new KAction(this); + action->setText(i18nc("@action", "Set reaction data...")); + action->setStatusTip(i18nc("@info:status", "Set the trigger and the " +"response of the currently selected reaction.")); + action->setIcon(KIcon("document-edit")); + action->setEnabled(false); + actionCollection()->addAction("setReactionData", action); + connect(action, SIGNAL(triggered(bool)), this, SLOT(setReactionData())); + actionListWidget->addAction(action); + + action = new KAction(this); + action->setText(i18nc("@action", "Remove reaction")); + action->setStatusTip(i18nc("@info:status", "Removes the currently selected " +"reaction from its step.")); + action->setIcon(KIcon("list-remove")); + action->setEnabled(false); + actionCollection()->addAction("removeReaction", action); + connect(action, SIGNAL(triggered(bool)), this, SLOT(removeReaction())); + actionListWidget->addAction(action); + + mReactionActionDock->setWidget(actionListWidget); + actionCollection()->addAction("showEditTutorialDock", mTutorialActionDock->toggleViewAction()); actionCollection()->addAction("showEditStepDock", mStepActionDock->toggleViewAction()); + actionCollection()->addAction("showEditReactionDock", + mReactionActionDock->toggleViewAction()); } void KTutorialEditor::showEditionDialog(EditionWidget* editionWidget) { @@ -205,14 +249,28 @@ actionCollection()->action("setStepSetup")->setEnabled(true); actionCollection()->action("setStepTearDown")->setEnabled(true); actionCollection()->action("removeStep")->setEnabled(true); + actionCollection()->action("addReaction")->setEnabled(true); } else { actionCollection()->action("setStepData")->setEnabled(false); actionCollection()->action("setStepSetup")->setEnabled(false); actionCollection()->action("setStepTearDown")->setEnabled(false); actionCollection()->action("removeStep")->setEnabled(false); + actionCollection()->action("addReaction")->setEnabled(false); } } +void KTutorialEditor::selectReaction(Reaction* reaction) { + mCurrentReaction = reaction; + + if (mCurrentReaction) { + actionCollection()->action("setReactionData")->setEnabled(true); + actionCollection()->action("removeReaction")->setEnabled(true); + } else { + actionCollection()->action("setReactionData")->setEnabled(false); + actionCollection()->action("removeReaction")->setEnabled(false); + } +} + void KTutorialEditor::setTutorialInformation() { showEditionDialog(new TutorialInformationWidget(mTutorial)); } @@ -264,3 +322,30 @@ mTutorial->removeStep(stepToRemove); stepToRemove->deleteLater(); } + +void KTutorialEditor::addReaction() { + Q_ASSERT(mCurrentStep); + + Reaction* reaction = new Reaction(); + mCurrentStep->addReaction(reaction); + + showEditionDialog(new ReactionWidget(reaction)); +} + +void KTutorialEditor::setReactionData() { + Q_ASSERT(mCurrentReaction); + + showEditionDialog(new ReactionWidget(mCurrentReaction)); +} + +void KTutorialEditor::removeReaction() { + Q_ASSERT(mCurrentStep); + + //When the reaction is removed, mCurrentReaction is changed because the + //selected item in the tree view changes. As mCurrentReaction is one of the + //valid reactions in the step, deleting it leads to a crash the next time it + //is used. + Reaction* reactionToRemove = mCurrentReaction; + mCurrentStep->removeReaction(reactionToRemove); + reactionToRemove->deleteLater(); +} Modified: trunk/ktutorial/ktutorial-editor/src/KTutorialEditor.h =================================================================== --- trunk/ktutorial/ktutorial-editor/src/KTutorialEditor.h 2010-03-16 02:12:03 UTC (rev 160) +++ trunk/ktutorial/ktutorial-editor/src/KTutorialEditor.h 2010-03-16 03:00:35 UTC (rev 161) @@ -23,6 +23,7 @@ class EditionWidget; class QTreeView; +class Reaction; class Step; class Tutorial; @@ -57,6 +58,11 @@ QDockWidget* mStepActionDock; /** + * Dock with the actions to edit a reaction. + */ + QDockWidget* mReactionActionDock; + + /** * The tutorial being edited. */ Tutorial* mTutorial; @@ -67,6 +73,11 @@ Step* mCurrentStep; /** + * The currently selected reaction. + */ + Reaction* mCurrentReaction; + + /** * Sets up the tutorial to be edited. * It creates a new tutorial, prepares the tree view to represent it and * handles the selection of items. @@ -101,6 +112,15 @@ void selectStep(Step* step); /** + * Sets the current reaction and enables or disables the actions that depend + * on a reaction as needed. + * + * @param reaction The reaction to select, or null to deselect the current + * one. + */ + void selectReaction(Reaction* reaction); + + /** * Shows a TutorialInformationWidget for the tutorial. */ void setTutorialInformation(); @@ -145,6 +165,22 @@ */ void removeStep(); + /** + * Adds a new reaction to the current step and shows a ReactionWidget for + * it. + */ + void addReaction(); + + /** + * Shows a ReactionWidget for the current reaction. + */ + void setReactionData(); + + /** + * Removes the current reaction from its step. + */ + void removeReaction(); + }; #endif Modified: trunk/ktutorial/ktutorial-editor/src/ktutorial-editorui.rc =================================================================== --- trunk/ktutorial/ktutorial-editor/src/ktutorial-editorui.rc 2010-03-16 02:12:03 UTC (rev 160) +++ trunk/ktutorial/ktutorial-editor/src/ktutorial-editorui.rc 2010-03-16 03:00:35 UTC (rev 161) @@ -18,12 +18,19 @@ <Action name="setStepTearDown"/> <Action name="removeStep"/> </Menu> + <Menu name="editReactions"> + <Text context="@title:menu Noun, a reaction in a step">Reaction</Text> + <Action name="addReaction"/> + <Action name="setReactionData"/> + <Action name="removeReaction"/> + </Menu> </Menu> <Menu name="view"> <Menu name="panels"> <Text context="@title:menu">Panels</Text> <Action name="showEditTutorialDock"/> <Action name="showEditStepDock"/> + <Action name="showEditReactionDock"/> </Menu> </Menu> </MenuBar> Modified: trunk/ktutorial/ktutorial-editor/src/view/TutorialTreeSelectionManager.cpp =================================================================== --- trunk/ktutorial/ktutorial-editor/src/view/TutorialTreeSelectionManager.cpp 2010-03-16 02:12:03 UTC (rev 160) +++ trunk/ktutorial/ktutorial-editor/src/view/TutorialTreeSelectionManager.cpp 2010-03-16 03:00:35 UTC (rev 161) @@ -18,6 +18,7 @@ #include "TutorialTreeSelectionManager.h" +#include "ReactionTreeItem.h" #include "StepTreeItem.h" #include "TreeItem.h" @@ -62,6 +63,34 @@ return getStepForTreeItem(item->parent()); } +void TutorialTreeSelectionManager::updateReactionSelection(TreeItem* selected, + TreeItem* deselected) { + Reaction* selectedReaction = getReactionForTreeItem(selected); + Reaction* deselectedReaction = getReactionForTreeItem(deselected); + + if (selectedReaction && selectedReaction != deselectedReaction) { + emit reactionSelected(selectedReaction); + return; + } + + if (!selectedReaction && deselectedReaction) { + emit reactionSelected(0); + return; + } +} + +Reaction* TutorialTreeSelectionManager::getReactionForTreeItem(TreeItem* item) { + if (qobject_cast<ReactionTreeItem*>(item)) { + return static_cast<ReactionTreeItem*>(item)->reaction(); + } + + if (item == 0 || item->parent() == 0) { + return 0; + } + + return getReactionForTreeItem(item->parent()); +} + //private slots: void TutorialTreeSelectionManager::handleSelectionChanged( @@ -89,4 +118,5 @@ } updateStepSelection(selectedItem, deselectedItem); + updateReactionSelection(selectedItem, deselectedItem); } Modified: trunk/ktutorial/ktutorial-editor/src/view/TutorialTreeSelectionManager.h =================================================================== --- trunk/ktutorial/ktutorial-editor/src/view/TutorialTreeSelectionManager.h 2010-03-16 02:12:03 UTC (rev 160) +++ trunk/ktutorial/ktutorial-editor/src/view/TutorialTreeSelectionManager.h 2010-03-16 03:00:35 UTC (rev 161) @@ -22,14 +22,20 @@ #include <QItemSelectionModel> #include <QObject> +class Reaction; class Step; class TreeItem; /** * Watches the QItemSelectionModel of a TreeModel for changes in the selection. * When an item is selected in the TreeModel, it is checked what kind of data it - * represents. If it is a Step, stepSelected(Step*) signal is emitted. + * represents. An item can represent several types of data (for example, a + * reaction item represents a reaction, but also a step as it is part of it). * + * When the data represented by the item is a Step, stepSelected(Step*) signal + * is emitted. When it is a Reaction, reactionSelected(Reaction*) signal is + * emitted. + * * Only single item selections are supported. */ class TutorialTreeSelectionManager: public QObject { @@ -60,6 +66,17 @@ */ void stepSelected(Step* step); + /** + * Emitted when a Reaction (or any of its child items) is selected. + * If the Reaction is deselected and the new selected item isn't a Reaction, + * the signal is emitted with a null pointer. + * No signal is emitted if the selected item changes to another item that + * selects the same Reaction already selected. + * + * @param reaction The selected Reaction, or null if it was deselected. + */ + void reactionSelected(Reaction* reaction); + private: /** @@ -84,6 +101,28 @@ */ Step* getStepForTreeItem(TreeItem* item); + /** + * Emits reactionSelected(Reaction*) signal based on the selected and + * deselected items. + * + * @param selected The selected item, if any. + * @param deselected The deselected item, if any. + */ + void updateReactionSelection(TreeItem* selected, TreeItem* deselected); + + /** + * Returns the Reaction represented by the given item. + * Any recursive child item of a ReactionTreeItem, or a ReactionTreeItem + * itself, represents a Reaction. + * + * If the item doesn't represent a Reaction or there is no item, a null + * pointer is returned. + * + * @param item The item to get its represented Reaction. + * @return The Reaction. + */ + Reaction* getReactionForTreeItem(TreeItem* item); + private Q_SLOTS: /** Modified: trunk/ktutorial/ktutorial-editor/tests/unit/view/TutorialTreeSelectionManagerTest.cpp =================================================================== --- trunk/ktutorial/ktutorial-editor/tests/unit/view/TutorialTreeSelectionManagerTest.cpp 2010-03-16 02:12:03 UTC (rev 160) +++ trunk/ktutorial/ktutorial-editor/tests/unit/view/TutorialTreeSelectionManagerTest.cpp 2010-03-16 03:00:35 UTC (rev 161) @@ -22,8 +22,10 @@ #include "TreeModel.h" #include "TutorialTreeItem.h" +#include "../Reaction.h" #include "../Step.h" #include "../Tutorial.h" +#include "../WaitForComposed.h" class TutorialTreeSelectionManagerTest: public QObject { Q_OBJECT @@ -43,22 +45,34 @@ void testSelectStepOrChildrenWithoutChangingStep(); void testSelectStepOrChildrenChangingToAnotherStep(); + void testSelectReactionOrChildrenChangingToOtherItems(); + void testSelectReactionOrChildrenWithoutChangingReaction(); + void testSelectReactionOrChildrenChangingToAnotherReaction(); + private: int mStepStarType; + int mReactionStarType; Tutorial* mTutorial; Step* mStep1; + Reaction* mReaction1; + WaitForComposed* mWaitFor1; + WaitForComposed* mWaitFor1_1; Step* mStep2; + Reaction* mReaction2; TreeModel* mTreeModel; QItemSelectionModel* mSelectionModel; TutorialTreeSelectionManager* mSelectionManager; QSignalSpy* mStepSelectedSpy; + QSignalSpy* mReactionSelectedSpy; void select(const QModelIndex& index); void assertStepSignal(const QSignalSpy* spy, int index, Step* step) const; + void assertReactionSignal(const QSignalSpy* spy, int index, + Reaction* reaction) const; }; @@ -66,6 +80,9 @@ //Step* must be registered in order to be used with QSignalSpy mStepStarType = qRegisterMetaType<Step*>("Step*"); + //Reaction* must be registered in order to be used with QSignalSpy + mReactionStarType = qRegisterMetaType<Reaction*>("Reaction*"); + mTutorial = new Tutorial(); mTutorial->setName("The name"); mTutorial->setDescription("The description"); @@ -80,6 +97,16 @@ mStep1->setCustomTearDownCode("Tear down 1"); mTutorial->addStep(mStep1); + mReaction1 = new Reaction(); + mReaction1->setTriggerType(Reaction::ConditionMet); + mReaction1->setResponseType(Reaction::CustomCode); + mStep1->addReaction(mReaction1); + + mWaitFor1 = new WaitForComposed(); + mWaitFor1_1 = new WaitForComposed(); + mWaitFor1->addWaitFor(mWaitFor1_1); + mReaction1->setWaitFor(mWaitFor1); + mStep2 = new Step(); mStep2->setId("Second step"); mStep2->setText("Text 2"); @@ -87,6 +114,9 @@ mStep2->setCustomTearDownCode("Tear down 2"); mTutorial->addStep(mStep2); + mReaction2 = new Reaction(); + mStep2->addReaction(mReaction2); + mTreeModel = new TreeModel(new TutorialTreeItem(mTutorial)); } @@ -96,9 +126,13 @@ mStepSelectedSpy = new QSignalSpy(mSelectionManager, SIGNAL(stepSelected(Step*))); + + mReactionSelectedSpy = new QSignalSpy(mSelectionManager, + SIGNAL(reactionSelected(Reaction*))); } void TutorialTreeSelectionManagerTest::cleanup() { + delete mReactionSelectedSpy; delete mStepSelectedSpy; delete mSelectionManager; delete mSelectionModel; @@ -133,6 +167,7 @@ select(mTreeModel->index(0, 0, mTreeModel->index(4, 0))); QCOMPARE(mStepSelectedSpy->count(), 0); + QCOMPARE(mReactionSelectedSpy->count(), 0); } void TutorialTreeSelectionManagerTest:: @@ -204,6 +239,17 @@ QCOMPARE(mStepSelectedSpy->count(), 12); assertStepSignal(mStepSelectedSpy, 11, 0); + + //Reaction + select(mTreeModel->index(3, 0, step1Index)); + + QCOMPARE(mStepSelectedSpy->count(), 13); + assertStepSignal(mStepSelectedSpy, 12, mStep1); + + select(mTreeModel->index(0, 0)); + + QCOMPARE(mStepSelectedSpy->count(), 14); + assertStepSignal(mStepSelectedSpy, 13, 0); } void TutorialTreeSelectionManagerTest:: @@ -239,6 +285,11 @@ select(mTreeModel->index(0, 0, mTreeModel->index(2, 0, step1Index))); QCOMPARE(mStepSelectedSpy->count(), 1); + + //Reaction + select(mTreeModel->index(3, 0, step1Index)); + + QCOMPARE(mStepSelectedSpy->count(), 1); } void TutorialTreeSelectionManagerTest:: @@ -310,8 +361,173 @@ QCOMPARE(mStepSelectedSpy->count(), 12); assertStepSignal(mStepSelectedSpy, 11, mStep2); + + //Reaction + select(mTreeModel->index(3, 0, step1Index)); + + QCOMPARE(mStepSelectedSpy->count(), 13); + assertStepSignal(mStepSelectedSpy, 12, mStep1); + + select(mTreeModel->index(3, 0, step2Index)); + + QCOMPARE(mStepSelectedSpy->count(), 14); + assertStepSignal(mStepSelectedSpy, 13, mStep2); } +void TutorialTreeSelectionManagerTest:: + testSelectReactionOrChildrenChangingToOtherItems() { + QModelIndex step1Index = mTreeModel->index(5, 0); + QModelIndex reaction1_1Index = mTreeModel->index(3, 0, step1Index); + + select(reaction1_1Index); + + QCOMPARE(mReactionSelectedSpy->count(), 1); + assertReactionSignal(mReactionSelectedSpy, 0, mReaction1); + + //Tutorial name + select(mTreeModel->index(0, 0)); + + QCOMPARE(mReactionSelectedSpy->count(), 2); + assertReactionSignal(mReactionSelectedSpy, 1, 0); + + //Reaction trigger + select(mTreeModel->index(0, 0, reaction1_1Index)); + + QCOMPARE(mReactionSelectedSpy->count(), 3); + assertReactionSignal(mReactionSelectedSpy, 2, mReaction1); + + select(mTreeModel->index(0, 0)); + + QCOMPARE(mReactionSelectedSpy->count(), 4); + assertReactionSignal(mReactionSelectedSpy, 3, 0); + + //Reaction child condition trigger + select(mTreeModel->index(0, 0, mTreeModel->index(0, 0, reaction1_1Index))); + + QCOMPARE(mReactionSelectedSpy->count(), 5); + assertReactionSignal(mReactionSelectedSpy, 4, mReaction1); + + select(mTreeModel->index(0, 0)); + + QCOMPARE(mReactionSelectedSpy->count(), 6); + assertReactionSignal(mReactionSelectedSpy, 5, 0); + + //Reaction response + select(mTreeModel->index(1, 0, reaction1_1Index)); + + QCOMPARE(mReactionSelectedSpy->count(), 7); + assertReactionSignal(mReactionSelectedSpy, 6, mReaction1); + + select(mTreeModel->index(0, 0)); + + QCOMPARE(mReactionSelectedSpy->count(), 8); + assertReactionSignal(mReactionSelectedSpy, 7, 0); + + //Reaction custom code response + select(mTreeModel->index(0, 0, mTreeModel->index(1, 0, reaction1_1Index))); + + QCOMPARE(mReactionSelectedSpy->count(), 9); + assertReactionSignal(mReactionSelectedSpy, 8, mReaction1); + + select(mTreeModel->index(0, 0)); + + QCOMPARE(mReactionSelectedSpy->count(), 10); + assertReactionSignal(mReactionSelectedSpy, 9, 0); +} + +void TutorialTreeSelectionManagerTest:: + testSelectReactionOrChildrenWithoutChangingReaction() { + QModelIndex step1Index = mTreeModel->index(5, 0); + QModelIndex reaction1_1Index = mTreeModel->index(3, 0, step1Index); + + select(reaction1_1Index); + + QCOMPARE(mReactionSelectedSpy->count(), 1); + assertReactionSignal(mReactionSelectedSpy, 0, mReaction1); + + //Reaction trigger + select(mTreeModel->index(0, 0, reaction1_1Index)); + + QCOMPARE(mReactionSelectedSpy->count(), 1); + + //Reaction child condition trigger + select(mTreeModel->index(0, 0, mTreeModel->index(0, 0, reaction1_1Index))); + + QCOMPARE(mReactionSelectedSpy->count(), 1); + + //Reaction response + select(mTreeModel->index(1, 0, reaction1_1Index)); + + QCOMPARE(mReactionSelectedSpy->count(), 1); + + //Reaction custom code response + select(mTreeModel->index(0, 0, mTreeModel->index(1, 0, reaction1_1Index))); + + QCOMPARE(mReactionSelectedSpy->count(), 1); +} + +void TutorialTreeSelectionManagerTest:: + testSelectReactionOrChildrenChangingToAnotherReaction() { + QModelIndex step1Index = mTreeModel->index(5, 0); + QModelIndex reaction1_1Index = mTreeModel->index(3, 0, step1Index); + QModelIndex step2Index = mTreeModel->index(6, 0); + QModelIndex reaction2_1Index = mTreeModel->index(3, 0, step2Index); + + select(reaction1_1Index); + + QCOMPARE(mReactionSelectedSpy->count(), 1); + assertReactionSignal(mReactionSelectedSpy, 0, mReaction1); + + select(reaction2_1Index); + + QCOMPARE(mReactionSelectedSpy->count(), 2); + assertReactionSignal(mReactionSelectedSpy, 1, mReaction2); + + //Reaction trigger + select(mTreeModel->index(0, 0, reaction1_1Index)); + + QCOMPARE(mReactionSelectedSpy->count(), 3); + assertReactionSignal(mReactionSelectedSpy, 2, mReaction1); + + select(mTreeModel->index(0, 0, reaction2_1Index)); + + QCOMPARE(mReactionSelectedSpy->count(), 4); + assertReactionSignal(mReactionSelectedSpy, 3, mReaction2); + + //Reaction nested condition trigger + select(mTreeModel->index(0, 0, mTreeModel->index(0, 0, reaction1_1Index))); + + QCOMPARE(mReactionSelectedSpy->count(), 5); + assertReactionSignal(mReactionSelectedSpy, 4, mReaction1); + + select(mTreeModel->index(0, 0, reaction2_1Index)); + + QCOMPARE(mReactionSelectedSpy->count(), 6); + assertReactionSignal(mReactionSelectedSpy, 5, mReaction2); + + //Reaction response + select(mTreeModel->index(1, 0, reaction1_1Index)); + + QCOMPARE(mReactionSelectedSpy->count(), 7); + assertReactionSignal(mReactionSelectedSpy, 6, mReaction1); + + select(mTreeModel->index(1, 0, reaction2_1Index)); + + QCOMPARE(mReactionSelectedSpy->count(), 8); + assertReactionSignal(mReactionSelectedSpy, 7, mReaction2); + + //Reaction custom code response + select(mTreeModel->index(0, 0, mTreeModel->index(1, 0, reaction1_1Index))); + + QCOMPARE(mReactionSelectedSpy->count(), 9); + assertReactionSignal(mReactionSelectedSpy, 8, mReaction1); + + select(reaction2_1Index); + + QCOMPARE(mReactionSelectedSpy->count(), 10); + assertReactionSignal(mReactionSelectedSpy, 9, mReaction2); +} + /////////////////////////////////// Helpers //////////////////////////////////// void TutorialTreeSelectionManagerTest::select(const QModelIndex& index) { @@ -331,6 +547,20 @@ QCOMPARE(qvariant_cast<Step*>(argument), step); } +//Reaction* must be declared as a metatype to be used in qvariant_cast +Q_DECLARE_METATYPE(Reaction*); + +void TutorialTreeSelectionManagerTest::assertReactionSignal( + const QSignalSpy* spy, + int index, + Reaction* reaction) const { + QCOMPARE(spy->at(index).count(), 1); + + QVariant argument = spy->at(index).at(0); + QCOMPARE(argument.userType(), mReactionStarType); + QCOMPARE(qvariant_cast<Reaction*>(argument), reaction); +} + QTEST_MAIN(TutorialTreeSelectionManagerTest) #include "TutorialTreeSelectionManagerTest.moc" This was sent by the SourceForge.net collaborative development platform, the world's largest Open Source development site. |
From: <dan...@us...> - 2010-03-16 05:43:03
|
Revision: 162 http://ktutorial.svn.sourceforge.net/ktutorial/?rev=162&view=rev Author: danxuliu Date: 2010-03-16 05:42:56 +0000 (Tue, 16 Mar 2010) Log Message: ----------- Add WaitForEvent to store the data of conditions to wait for events. The classes and changes needed to make them work at application level are also included. Modified Paths: -------------- trunk/ktutorial/ktutorial-editor/src/CMakeLists.txt trunk/ktutorial/ktutorial-editor/src/view/CMakeLists.txt trunk/ktutorial/ktutorial-editor/src/view/NewWaitForWidget.cpp trunk/ktutorial/ktutorial-editor/src/view/NewWaitForWidget.ui trunk/ktutorial/ktutorial-editor/src/view/WaitForTreeItem.cpp trunk/ktutorial/ktutorial-editor/src/view/WaitForWidget.cpp trunk/ktutorial/ktutorial-editor/tests/unit/CMakeLists.txt trunk/ktutorial/ktutorial-editor/tests/unit/view/CMakeLists.txt trunk/ktutorial/ktutorial-editor/tests/unit/view/NewWaitForWidgetTest.cpp trunk/ktutorial/ktutorial-editor/tests/unit/view/WaitForTreeItemTest.cpp trunk/ktutorial/ktutorial-editor/tests/unit/view/WaitForWidgetTest.cpp Added Paths: ----------- trunk/ktutorial/ktutorial-editor/src/WaitForEvent.cpp trunk/ktutorial/ktutorial-editor/src/WaitForEvent.h trunk/ktutorial/ktutorial-editor/src/view/WaitForEventTreeItem.cpp trunk/ktutorial/ktutorial-editor/src/view/WaitForEventTreeItem.h trunk/ktutorial/ktutorial-editor/src/view/WaitForEventWidget.cpp trunk/ktutorial/ktutorial-editor/src/view/WaitForEventWidget.h trunk/ktutorial/ktutorial-editor/src/view/WaitForEventWidget.ui trunk/ktutorial/ktutorial-editor/tests/unit/WaitForEventTest.cpp trunk/ktutorial/ktutorial-editor/tests/unit/view/WaitForEventTreeItemTest.cpp trunk/ktutorial/ktutorial-editor/tests/unit/view/WaitForEventWidgetTest.cpp Modified: trunk/ktutorial/ktutorial-editor/src/CMakeLists.txt =================================================================== --- trunk/ktutorial/ktutorial-editor/src/CMakeLists.txt 2010-03-16 03:00:35 UTC (rev 161) +++ trunk/ktutorial/ktutorial-editor/src/CMakeLists.txt 2010-03-16 05:42:56 UTC (rev 162) @@ -13,6 +13,7 @@ Tutorial.cpp WaitFor.cpp WaitForComposed.cpp + WaitForEvent.cpp WaitForNot.cpp WaitForSignal.cpp ) Added: trunk/ktutorial/ktutorial-editor/src/WaitForEvent.cpp =================================================================== --- trunk/ktutorial/ktutorial-editor/src/WaitForEvent.cpp (rev 0) +++ trunk/ktutorial/ktutorial-editor/src/WaitForEvent.cpp 2010-03-16 05:42:56 UTC (rev 162) @@ -0,0 +1,70 @@ +/*************************************************************************** + * 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 "WaitForEvent.h" + +//public: + +WaitForEvent::WaitForEvent(QObject* parent): WaitFor(parent) { +} + +WaitFor* WaitForEvent::clone() const { + WaitForEvent* cloned = new WaitForEvent(); + cloned->setReceiverName(mReceiverName); + cloned->setEventName(mEventName); + + return cloned; +} + +bool WaitForEvent::equals(const WaitFor& waitFor) const { + if (!qobject_cast<const WaitForEvent*>(&waitFor)) { + return false; + } + + const WaitForEvent* waitForEvent = + static_cast<const WaitForEvent*>(&waitFor); + if (waitForEvent->receiverName() != mReceiverName) { + return false; + } + + if (waitForEvent->eventName() != mEventName) { + return false; + } + + return true; +} + +QString WaitForEvent::receiverName() const { + return mReceiverName; +} + +void WaitForEvent::setReceiverName(const QString& receiverName) { + mReceiverName = receiverName; + + emit dataChanged(this); +} + +QString WaitForEvent::eventName() const { + return mEventName; +} + +void WaitForEvent::setEventName(const QString& eventName) { + mEventName = eventName; + + emit dataChanged(this); +} Property changes on: trunk/ktutorial/ktutorial-editor/src/WaitForEvent.cpp ___________________________________________________________________ Added: svn:eol-style + native Added: trunk/ktutorial/ktutorial-editor/src/WaitForEvent.h =================================================================== --- trunk/ktutorial/ktutorial-editor/src/WaitForEvent.h (rev 0) +++ trunk/ktutorial/ktutorial-editor/src/WaitForEvent.h 2010-03-16 05:42:56 UTC (rev 162) @@ -0,0 +1,60 @@ +/*************************************************************************** + * 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 WAITFOREVENT_H +#define WAITFOREVENT_H + +#include "WaitFor.h" + +/** + * Container for conditions that wait for an event to be received data. + * It stores the data used in KTutorial WaitForEvent, but it has nothing to do + * with it (they don't even know each other). Its purpose is store the data + * needed to generate the code to initialize a true KTutorial::WaitForEvent + * object. + * + * When any attribute is modified, dataChanged(WaitFor*) signal is emitted. + */ +class WaitForEvent: public WaitFor { +Q_OBJECT +public: + + /** + * Creates a new WaitForEvent. + * + * @param parent The parent QObject. + */ + WaitForEvent(QObject* parent = 0); + + virtual WaitFor* clone() const; + virtual bool equals(const WaitFor& waitFor) const; + + QString receiverName() const; + void setReceiverName(const QString& receiverName); + + QString eventName() const; + void setEventName(const QString& eventName); + +private: + + QString mReceiverName; + QString mEventName; + +}; + +#endif Property changes on: trunk/ktutorial/ktutorial-editor/src/WaitForEvent.h ___________________________________________________________________ Added: svn:eol-style + native Modified: trunk/ktutorial/ktutorial-editor/src/view/CMakeLists.txt =================================================================== --- trunk/ktutorial/ktutorial-editor/src/view/CMakeLists.txt 2010-03-16 03:00:35 UTC (rev 161) +++ trunk/ktutorial/ktutorial-editor/src/view/CMakeLists.txt 2010-03-16 05:42:56 UTC (rev 162) @@ -20,6 +20,8 @@ TutorialTreeItem.cpp TutorialTreeSelectionManager.cpp WaitForComposedTreeItem.cpp + WaitForEventTreeItem.cpp + WaitForEventWidget.cpp WaitForNotTreeItem.cpp WaitForSignalTreeItem.cpp WaitForSignalWidget.cpp @@ -34,6 +36,7 @@ ReactionWidget.ui StepDataWidget.ui TutorialInformationWidget.ui + WaitForEventWidget.ui WaitForSignalWidget.ui WaitForWidget.ui ) Modified: trunk/ktutorial/ktutorial-editor/src/view/NewWaitForWidget.cpp =================================================================== --- trunk/ktutorial/ktutorial-editor/src/view/NewWaitForWidget.cpp 2010-03-16 03:00:35 UTC (rev 161) +++ trunk/ktutorial/ktutorial-editor/src/view/NewWaitForWidget.cpp 2010-03-16 05:42:56 UTC (rev 162) @@ -20,6 +20,7 @@ #include "ui_NewWaitForWidget.h" #include "../WaitForComposed.h" +#include "../WaitForEvent.h" #include "../WaitForNot.h" #include "../WaitForSignal.h" @@ -49,6 +50,8 @@ return new WaitForNot(); } else if (index == 3) { return new WaitForSignal(); + } else if (index == 4) { + return new WaitForEvent(); } return 0; Modified: trunk/ktutorial/ktutorial-editor/src/view/NewWaitForWidget.ui =================================================================== --- trunk/ktutorial/ktutorial-editor/src/view/NewWaitForWidget.ui 2010-03-16 03:00:35 UTC (rev 161) +++ trunk/ktutorial/ktutorial-editor/src/view/NewWaitForWidget.ui 2010-03-16 05:42:56 UTC (rev 162) @@ -61,6 +61,11 @@ <string comment="@item:inlistbox">The specified signal is emitted</string> </property> </item> + <item> + <property name="text"> + <string comment="@item:inlistbox">The specified event is received</string> + </property> + </item> </widget> </item> </layout> Added: trunk/ktutorial/ktutorial-editor/src/view/WaitForEventTreeItem.cpp =================================================================== --- trunk/ktutorial/ktutorial-editor/src/view/WaitForEventTreeItem.cpp (rev 0) +++ trunk/ktutorial/ktutorial-editor/src/view/WaitForEventTreeItem.cpp 2010-03-16 05:42:56 UTC (rev 162) @@ -0,0 +1,64 @@ +/*************************************************************************** + * 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 "WaitForEventTreeItem.h" + +#include <KLocalizedString> + +#include "../WaitForEvent.h" + +//public: + +WaitForEventTreeItem::WaitForEventTreeItem(WaitForEvent* waitForEvent, + TreeItem* parent): + WaitForTreeItem(waitForEvent, parent) { + mReceiverName = waitForEvent->receiverName(); + mEventName = waitForEvent->eventName(); + + connect(waitForEvent, SIGNAL(dataChanged(WaitFor*)), + this, SLOT(update(WaitFor*))); +} + +QString WaitForEventTreeItem::text() const { + QString receiverName; + if (mReceiverName.isEmpty()) { + receiverName = i18nc("@item", "(object not set)"); + } else { + receiverName = "\"" + mReceiverName + "\""; + } + + QString eventName; + if (mEventName.isEmpty()) { + eventName = i18nc("@item", "(event not set)"); + } else { + eventName = "\"" + mEventName + "\""; + } + + return i18nc("@item", "When the event %1 is received by object %2", + eventName, receiverName); +} + +//private: + +void WaitForEventTreeItem::update(WaitFor* waitFor) { + WaitForEvent* waitForEvent = static_cast<WaitForEvent*>(waitFor); + mReceiverName = waitForEvent->receiverName(); + mEventName = waitForEvent->eventName(); + + emit dataChanged(this); +} Property changes on: trunk/ktutorial/ktutorial-editor/src/view/WaitForEventTreeItem.cpp ___________________________________________________________________ Added: svn:eol-style + native Added: trunk/ktutorial/ktutorial-editor/src/view/WaitForEventTreeItem.h =================================================================== --- trunk/ktutorial/ktutorial-editor/src/view/WaitForEventTreeItem.h (rev 0) +++ trunk/ktutorial/ktutorial-editor/src/view/WaitForEventTreeItem.h 2010-03-16 05:42:56 UTC (rev 162) @@ -0,0 +1,84 @@ +/*************************************************************************** + * 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 WAITFOREVENTTREEITEM_H +#define WAITFOREVENTTREEITEM_H + +#include "WaitForTreeItem.h" + +class WaitForEvent; + +/** + * A TreeItem that represents a WaitForEvent. + * The tree representation of a WaitForEvent is a plain text: + * When the event "event name" is received by the object "object name" + * + * If the event or the receiver name aren't set yet, a placeholder is put + * instead. Event placeholder is "(event not set)", and the receiver name + * placeholder is "(object name not set)" (without quotes, but with + * parenthesis). + * + * Whenever the WaitForEvent data changes, the WaitForEventTreeItem text is + * updated as needed. + */ +class WaitForEventTreeItem: public WaitForTreeItem { +Q_OBJECT +public: + + /** + * Creates a new WaitForEventTreeItem for the given WaitForEvent and with + * the given parent. + * + * @param waitForEvent The WaitForEvent to represent. + * @param parent The parent TreeItem. + */ + explicit WaitForEventTreeItem(WaitForEvent* waitForEvent, + TreeItem* parent = 0); + + /** + * Returns the description of the WaitForEvent. + * + * @return The text for this TreeItem. + */ + virtual QString text() const; + +private: + + /** + * The receiver name of the WaitForEvent. + */ + QString mReceiverName; + + /** + * The event name of the WaitForEvent. + */ + QString mEventName; + +private Q_SLOTS: + + /** + * Updates this WaitForEventTreeItem when the data of its WaitForEvent + * changed. + * + * @param waitFor The WaitForEvent. + */ + void update(WaitFor* waitFor); + +}; + +#endif Property changes on: trunk/ktutorial/ktutorial-editor/src/view/WaitForEventTreeItem.h ___________________________________________________________________ Added: svn:eol-style + native Added: trunk/ktutorial/ktutorial-editor/src/view/WaitForEventWidget.cpp =================================================================== --- trunk/ktutorial/ktutorial-editor/src/view/WaitForEventWidget.cpp (rev 0) +++ trunk/ktutorial/ktutorial-editor/src/view/WaitForEventWidget.cpp 2010-03-16 05:42:56 UTC (rev 162) @@ -0,0 +1,52 @@ +/*************************************************************************** + * 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 "WaitForEventWidget.h" + +#include "ui_WaitForEventWidget.h" +#include "../WaitForEvent.h" + +//public: + +WaitForEventWidget::WaitForEventWidget(WaitForEvent* waitForEvent, + QWidget* parent): + EditionWidget(parent), + mWaitForEvent(waitForEvent) { + + ui = new Ui::WaitForEventWidget(); + ui->setupUi(this); + + ui->receiverNameLineEdit->setText(waitForEvent->receiverName()); + ui->eventNameLineEdit->setText(waitForEvent->eventName()); +} + +WaitForEventWidget::~WaitForEventWidget() { + delete ui; +} + +void WaitForEventWidget::saveChanges() { + QString receiverName = ui->receiverNameLineEdit->text(); + if (mWaitForEvent->receiverName() != receiverName) { + mWaitForEvent->setReceiverName(receiverName); + } + + QString eventName = ui->eventNameLineEdit->text(); + if (mWaitForEvent->eventName() != eventName) { + mWaitForEvent->setEventName(eventName); + } +} Property changes on: trunk/ktutorial/ktutorial-editor/src/view/WaitForEventWidget.cpp ___________________________________________________________________ Added: svn:eol-style + native Added: trunk/ktutorial/ktutorial-editor/src/view/WaitForEventWidget.h =================================================================== --- trunk/ktutorial/ktutorial-editor/src/view/WaitForEventWidget.h (rev 0) +++ trunk/ktutorial/ktutorial-editor/src/view/WaitForEventWidget.h 2010-03-16 05:42:56 UTC (rev 162) @@ -0,0 +1,70 @@ +/*************************************************************************** + * 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 WAITFOREVENTWIDGET_H +#define WAITFOREVENTWIDGET_H + +#include "EditionWidget.h" + +class WaitForEvent; + +namespace Ui { +class WaitForEventWidget; +} + +/** + * Edition widget for the condition to wait for an event. + */ +class WaitForEventWidget: public EditionWidget { +Q_OBJECT +public: + + /** + * Creates a new WaitForEventWidget for the given WaitForEvent. + * + * @param waitForEvent The WaitForEvent to set its data. + * @param parent The parent QWidget. + */ + explicit WaitForEventWidget(WaitForEvent* waitForEvent, + QWidget* parent = 0); + + /** + * Destroys this widget. + */ + virtual ~WaitForEventWidget(); + + /** + * Saves the receiver name and the event name in the WaitForEvent. + */ + virtual void saveChanges(); + +private: + + /** + * The WaitForEvent to edit. + */ + WaitForEvent* mWaitForEvent; + + /** + * The Ui Designer generated class. + */ + Ui::WaitForEventWidget* ui; + +}; + +#endif Property changes on: trunk/ktutorial/ktutorial-editor/src/view/WaitForEventWidget.h ___________________________________________________________________ Added: svn:eol-style + native Added: trunk/ktutorial/ktutorial-editor/src/view/WaitForEventWidget.ui =================================================================== --- trunk/ktutorial/ktutorial-editor/src/view/WaitForEventWidget.ui (rev 0) +++ trunk/ktutorial/ktutorial-editor/src/view/WaitForEventWidget.ui 2010-03-16 05:42:56 UTC (rev 162) @@ -0,0 +1,103 @@ +<?xml version="1.0" encoding="UTF-8"?> +<ui version="4.0"> + <class>WaitForEventWidget</class> + <widget class="QWidget" name="WaitForEventWidget"> + <property name="geometry"> + <rect> + <x>0</x> + <y>0</y> + <width>400</width> + <height>300</height> + </rect> + </property> + <property name="windowTitle"> + <string comment="@title">Edit event to wait for</string> + </property> + <property name="whatsThis"> + <string comment="@info:whatsthis"><para>Set the receiver name and the event to wait for.</para></string> + </property> + <layout class="QVBoxLayout" name="WaitForEventlVerticalLayout"> + <item> + <widget class="QGroupBox" name="waitForEventGroupBox"> + <property name="title"> + <string comment="@title:group">Wait for event</string> + </property> + <layout class="QHBoxLayout" name="waitForEventGroupBoxHorizontalLayout"> + <item> + <layout class="QVBoxLayout" name="labelVerticalLayout"> + <item> + <widget class="QLabel" name="receiverNameLabel"> + <property name="text"> + <string comment="@label:textbox">Receiver name:</string> + </property> + <property name="alignment"> + <set>Qt::AlignRight|Qt::AlignTrailing|Qt::AlignVCenter</set> + </property> + <property name="buddy"> + <cstring>receiverNameLineEdit</cstring> + </property> + </widget> + </item> + <item> + <widget class="QLabel" name="eventNameLabel"> + <property name="text"> + <string comment="@label:textbox">Event name:</string> + </property> + <property name="alignment"> + <set>Qt::AlignRight|Qt::AlignTrailing|Qt::AlignVCenter</set> + </property> + <property name="buddy"> + <cstring>eventNameLineEdit</cstring> + </property> + </widget> + </item> + </layout> + </item> + <item> + <layout class="QVBoxLayout" name="lineEditVerticalLayout"> + <item> + <widget class="KLineEdit" name="receiverNameLineEdit"> + <property name="whatsThis"> + <string comment="@info:whatsthis"><para>The name of the QObject that receives the event.</para> +<para>Note that the name is not the class of the object, but the string returned by its objectName() method.</para></string> + </property> + </widget> + </item> + <item> + <widget class="KLineEdit" name="eventNameLineEdit"> + <property name="whatsThis"> + <string comment="@info:whatsthis"><para>The name of the event.</para> +<para>The name must not contain the "QEvent::" prefix, only the pure name of the event.</para></string> + </property> + </widget> + </item> + </layout> + </item> + </layout> + </widget> + </item> + <item> + <spacer name="waitForEventWidgetSpacer"> + <property name="orientation"> + <enum>Qt::Vertical</enum> + </property> + <property name="sizeHint" stdset="0"> + <size> + <width>20</width> + <height>182</height> + </size> + </property> + </spacer> + </item> + </layout> + </widget> + <customwidgets> + <customwidget> + <class>KLineEdit</class> + <extends>QLineEdit</extends> + <header>klineedit.h</header> + </customwidget> + </customwidgets> + <resources/> + <connections/> +</ui> Modified: trunk/ktutorial/ktutorial-editor/src/view/WaitForTreeItem.cpp =================================================================== --- trunk/ktutorial/ktutorial-editor/src/view/WaitForTreeItem.cpp 2010-03-16 03:00:35 UTC (rev 161) +++ trunk/ktutorial/ktutorial-editor/src/view/WaitForTreeItem.cpp 2010-03-16 05:42:56 UTC (rev 162) @@ -18,9 +18,11 @@ #include "WaitForTreeItem.h" #include "WaitForComposedTreeItem.h" +#include "WaitForEventTreeItem.h" #include "WaitForNotTreeItem.h" #include "WaitForSignalTreeItem.h" #include "../WaitForComposed.h" +#include "../WaitForEvent.h" #include "../WaitForNot.h" #include "../WaitForSignal.h" @@ -33,6 +35,11 @@ static_cast<WaitForComposed*>(waitFor), parent); } + if (qobject_cast<WaitForEvent*>(waitFor)) { + return new WaitForEventTreeItem(static_cast<WaitForEvent*>(waitFor), + parent); + } + if (qobject_cast<WaitForNot*>(waitFor)) { return new WaitForNotTreeItem(static_cast<WaitForNot*>(waitFor), parent); Modified: trunk/ktutorial/ktutorial-editor/src/view/WaitForWidget.cpp =================================================================== --- trunk/ktutorial/ktutorial-editor/src/view/WaitForWidget.cpp 2010-03-16 03:00:35 UTC (rev 161) +++ trunk/ktutorial/ktutorial-editor/src/view/WaitForWidget.cpp 2010-03-16 05:42:56 UTC (rev 162) @@ -23,9 +23,11 @@ #include "NewWaitForWidget.h" #include "TextTreeItem.h" #include "TreeModel.h" +#include "WaitForEventWidget.h" #include "WaitForSignalWidget.h" #include "WaitForTreeItem.h" #include "../WaitForComposed.h" +#include "../WaitForEvent.h" #include "../WaitForNot.h" #include "../WaitForSignal.h" @@ -107,6 +109,14 @@ return; } + if (qobject_cast<WaitForEvent*>(selectedWaitFor)) { + ui->addButton->setEnabled(false); + ui->editButton->setEnabled(true); + ui->removeButton->setEnabled(true); + + return; + } + if (qobject_cast<WaitForNot*>(selectedWaitFor)) { if (static_cast<WaitForNot*>(selectedWaitFor)->negatedWaitFor()) { ui->addButton->setEnabled(false); @@ -200,6 +210,12 @@ void WaitForWidget::editWaitFor() { EditionWidget* editionWidget = 0; + if (qobject_cast<WaitForEvent*>(mCurrentWaitFor)) { + WaitForEvent* waitForEvent = + static_cast<WaitForEvent*>(mCurrentWaitFor); + editionWidget = new WaitForEventWidget(waitForEvent, this); + } + if (qobject_cast<WaitForSignal*>(mCurrentWaitFor)) { WaitForSignal* waitForSignal = static_cast<WaitForSignal*>(mCurrentWaitFor); Modified: trunk/ktutorial/ktutorial-editor/tests/unit/CMakeLists.txt =================================================================== --- trunk/ktutorial/ktutorial-editor/tests/unit/CMakeLists.txt 2010-03-16 03:00:35 UTC (rev 161) +++ trunk/ktutorial/ktutorial-editor/tests/unit/CMakeLists.txt 2010-03-16 05:42:56 UTC (rev 162) @@ -20,6 +20,7 @@ Tutorial WaitFor WaitForComposed + WaitForEvent WaitForNot WaitForSignal ) @@ -36,6 +37,7 @@ Tutorial WaitFor WaitForComposed + WaitForEvent WaitForNot WaitForSignal ) Added: trunk/ktutorial/ktutorial-editor/tests/unit/WaitForEventTest.cpp =================================================================== --- trunk/ktutorial/ktutorial-editor/tests/unit/WaitForEventTest.cpp (rev 0) +++ trunk/ktutorial/ktutorial-editor/tests/unit/WaitForEventTest.cpp 2010-03-16 05:42:56 UTC (rev 162) @@ -0,0 +1,154 @@ +/*************************************************************************** + * 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 "WaitForEvent.h" + +class WaitForEventTest: public QObject { +Q_OBJECT + +private slots: + + void initTestCase(); + + void testConstructor(); + + void testClone(); + + void testEquals(); + + void testSetReceiverName(); + + void testSetEventName(); + +private: + + int mWaitForStarType; + + void assertWaitForEvent(const QSignalSpy& spy, int index, + WaitFor* waitFor); + +}; + +class StubWaitFor: public WaitFor { +Q_OBJECT +public: + + int mValue; + + StubWaitFor(int value = 0): mValue(value) { + } + + virtual WaitFor* clone() const { + return new StubWaitFor(mValue); + } + + virtual bool equals(const WaitFor& waitFor) const { + if (!qobject_cast<const StubWaitFor*>(&waitFor)) { + return false; + } + + return mValue == static_cast<const StubWaitFor*>(&waitFor)->mValue; + } +}; + +void WaitForEventTest::initTestCase() { + //WaitFor* must be registered in order to be used with QSignalSpy + mWaitForStarType = qRegisterMetaType<WaitFor*>("WaitFor*"); +} + +void WaitForEventTest::testConstructor() { + QObject parent; + WaitForEvent* waitForEvent = new WaitForEvent(&parent); + + QCOMPARE(waitForEvent->parent(), &parent); +} + +void WaitForEventTest::testClone() { + WaitForEvent waitForEvent; + + WaitForEvent* cloned = static_cast<WaitForEvent*>(waitForEvent.clone()); + + QVERIFY(cloned != &waitForEvent); + QCOMPARE(cloned->receiverName(), waitForEvent.receiverName()); + QCOMPARE(cloned->eventName(), waitForEvent.eventName()); + delete cloned; +} + +void WaitForEventTest::testEquals() { + WaitForEvent waitForEvent1; + waitForEvent1.setReceiverName("The receiver name"); + waitForEvent1.setEventName("The event name"); + WaitForEvent waitForEvent2; + + QCOMPARE(waitForEvent1 == waitForEvent2, false); + QCOMPARE(waitForEvent2 == waitForEvent1, false); + + waitForEvent2.setReceiverName("The receiver name"); + waitForEvent2.setEventName("The event name"); + + QCOMPARE(waitForEvent1 == waitForEvent2, true); + QCOMPARE(waitForEvent2 == waitForEvent1, true); + + StubWaitFor stubWaitFor; + + QCOMPARE(waitForEvent1 == stubWaitFor, false); +} + +void WaitForEventTest::testSetReceiverName() { + WaitForEvent waitForEvent; + + QSignalSpy dataChangedSpy(&waitForEvent, SIGNAL(dataChanged(WaitFor*))); + + waitForEvent.setReceiverName("The receiver name"); + + QCOMPARE(waitForEvent.receiverName(), QString("The receiver name")); + QCOMPARE(dataChangedSpy.count(), 1); + assertWaitForEvent(dataChangedSpy, 0, &waitForEvent); +} + +void WaitForEventTest::testSetEventName() { + WaitForEvent waitForEvent; + + QSignalSpy dataChangedSpy(&waitForEvent, SIGNAL(dataChanged(WaitFor*))); + + waitForEvent.setEventName("The event name"); + + QCOMPARE(waitForEvent.eventName(), QString("The event name")); + QCOMPARE(dataChangedSpy.count(), 1); + assertWaitForEvent(dataChangedSpy, 0, &waitForEvent); +} + +//WaitFor* must be declared as a metatype to be used in qvariant_cast +Q_DECLARE_METATYPE(WaitFor*); + +/////////////////////////////////// Helpers //////////////////////////////////// + +void WaitForEventTest::assertWaitForEvent(const QSignalSpy& spy, int index, + WaitFor* waitFor) { + QCOMPARE(spy.at(index).count(), 1); + + QVariant argument = spy.at(index).at(0); + QCOMPARE(argument.userType(), mWaitForStarType); + QCOMPARE(qvariant_cast<WaitFor*>(argument), waitFor); +} + +QTEST_MAIN(WaitForEventTest) + +#include "WaitForEventTest.moc" Property changes on: trunk/ktutorial/ktutorial-editor/tests/unit/WaitForEventTest.cpp ___________________________________________________________________ Added: svn:eol-style + native Modified: trunk/ktutorial/ktutorial-editor/tests/unit/view/CMakeLists.txt =================================================================== --- trunk/ktutorial/ktutorial-editor/tests/unit/view/CMakeLists.txt 2010-03-16 03:00:35 UTC (rev 161) +++ trunk/ktutorial/ktutorial-editor/tests/unit/view/CMakeLists.txt 2010-03-16 05:42:56 UTC (rev 162) @@ -35,6 +35,8 @@ TutorialTreeItem TutorialTreeSelectionManager WaitForComposedTreeItem + WaitForEventTreeItem + WaitForEventWidget WaitForNotTreeItem WaitForSignalTreeItem WaitForSignalWidget @@ -67,6 +69,8 @@ TutorialTreeItem TutorialTreeSelectionManager WaitForComposedTreeItem + WaitForEventTreeItem + WaitForEventWidget WaitForNotTreeItem WaitForSignalTreeItem WaitForSignalWidget Modified: trunk/ktutorial/ktutorial-editor/tests/unit/view/NewWaitForWidgetTest.cpp =================================================================== --- trunk/ktutorial/ktutorial-editor/tests/unit/view/NewWaitForWidgetTest.cpp 2010-03-16 03:00:35 UTC (rev 161) +++ trunk/ktutorial/ktutorial-editor/tests/unit/view/NewWaitForWidgetTest.cpp 2010-03-16 05:42:56 UTC (rev 162) @@ -23,6 +23,7 @@ #include <KComboBox> #include "../WaitForComposed.h" +#include "../WaitForEvent.h" #include "../WaitForNot.h" #include "../WaitForSignal.h" @@ -37,6 +38,7 @@ void testWaitForWhenOrConditionIsSelected(); void testWaitForWhenNotConditionIsSelected(); void testWaitForWhenSignalConditionIsSelected(); + void testWaitForWhenEventConditionIsSelected(); private: @@ -93,6 +95,16 @@ delete waitFor; } +void NewWaitForWidgetTest::testWaitForWhenEventConditionIsSelected() { + NewWaitForWidget widget; + + selectOption(&widget, 4); + + WaitForEvent* waitFor = qobject_cast<WaitForEvent*>(widget.waitFor()); + QVERIFY(waitFor); + delete waitFor; +} + /////////////////////////////////// Helpers //////////////////////////////////// void NewWaitForWidgetTest::selectOption(NewWaitForWidget* widget, Added: trunk/ktutorial/ktutorial-editor/tests/unit/view/WaitForEventTreeItemTest.cpp =================================================================== --- trunk/ktutorial/ktutorial-editor/tests/unit/view/WaitForEventTreeItemTest.cpp (rev 0) +++ trunk/ktutorial/ktutorial-editor/tests/unit/view/WaitForEventTreeItemTest.cpp 2010-03-16 05:42:56 UTC (rev 162) @@ -0,0 +1,164 @@ +/*************************************************************************** + * 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 "WaitForEventTreeItem.h" + +#include <KLocalizedString> + +#include "../WaitForEvent.h" + +class WaitForEventTreeItemTest: public QObject { +Q_OBJECT + +private slots: + + void initTestCase(); + + void testConstructor(); + void testConstructorFull(); + + void testWaitForEventSetReceiverName(); + void testWaitForEventSetReceiverNameChange(); + + void testWaitForEventSetEventName(); + void testWaitForEventSetEventNameChange(); + +private: + + int mTreeItemStarType; + + void assertDataChanged(const QSignalSpy& spy, int index, + TreeItem* item) const; + +}; + +class StubTreeItem: public TreeItem { +public: + virtual QString text() const { + return ""; + } +}; + +void WaitForEventTreeItemTest::initTestCase() { + //TreeItem* must be registered in order to be used with QSignalSpy + mTreeItemStarType = qRegisterMetaType<TreeItem*>("TreeItem*"); +} + +void WaitForEventTreeItemTest::testConstructor() { + WaitForEvent waitForEvent; + + StubTreeItem parent; + WaitForEventTreeItem item(&waitForEvent, &parent); + + QCOMPARE(item.parent(), &parent); + QCOMPARE(item.waitFor(), &waitForEvent); + QCOMPARE(item.text(), i18nc("@item", "When the event (event not set) is " + "received by object (object not " + "set)")); +} + +void WaitForEventTreeItemTest::testConstructorFull() { + WaitForEvent waitForEvent; + waitForEvent.setReceiverName("receiverName"); + waitForEvent.setEventName("eventName"); + + StubTreeItem parent; + WaitForEventTreeItem item(&waitForEvent, &parent); + + QCOMPARE(item.parent(), &parent); + QCOMPARE(item.waitFor(), &waitForEvent); + QCOMPARE(item.text(), i18nc("@item", "When the event \"eventName\" is " + "received by object " + "\"receiverName\"")); +} + +void WaitForEventTreeItemTest::testWaitForEventSetReceiverName() { + WaitForEvent waitForEvent; + waitForEvent.setReceiverName("receiverName"); + + WaitForEventTreeItem item(&waitForEvent); + + QCOMPARE(item.text(), i18nc("@item", "When the event (event not set) is " + "received by object \"receiverName\"")); +} + +void WaitForEventTreeItemTest::testWaitForEventSetReceiverNameChange() { + WaitForEvent waitForEvent; + WaitForEventTreeItem item(&waitForEvent); + + waitForEvent.setReceiverName("receiverName"); + + QSignalSpy dataChangedSpy(&item, SIGNAL(dataChanged(TreeItem*))); + + waitForEvent.setReceiverName("receiverNameChanged"); + + QCOMPARE(item.text(), i18nc("@item", "When the event (event not set) is " + "received by object " + "\"receiverNameChanged\"")); + QCOMPARE(dataChangedSpy.count(), 1); + assertDataChanged(dataChangedSpy, 0, &item); +} + +void WaitForEventTreeItemTest::testWaitForEventSetEventName() { + WaitForEvent waitForEvent; + waitForEvent.setEventName("eventName"); + + WaitForEventTreeItem item(&waitForEvent); + + QCOMPARE(item.text(), i18nc("@item", "When the event \"eventName\" is " + "received by object (object not " + "set)")); +} + +void WaitForEventTreeItemTest::testWaitForEventSetEventNameChange() { + WaitForEvent waitForEvent; + WaitForEventTreeItem item(&waitForEvent); + + waitForEvent.setEventName("eventName"); + + QSignalSpy dataChangedSpy(&item, SIGNAL(dataChanged(TreeItem*))); + + waitForEvent.setEventName("eventNameChanged"); + + QCOMPARE(item.text(), i18nc("@item", "When the event " + "\"eventNameChanged\" is received by " + "object (object not set)")); + QCOMPARE(dataChangedSpy.count(), 1); + assertDataChanged(dataChangedSpy, 0, &item); +} + +/////////////////////////////////// Helpers //////////////////////////////////// + +//TreeItem* must be declared as a metatype to be used in qvariant_cast +Q_DECLARE_METATYPE(TreeItem*); + +void WaitForEventTreeItemTest::assertDataChanged(const QSignalSpy& spy, + int index, + TreeItem* item) const { + QCOMPARE(spy.at(index).count(), 1); + + QVariant argument = spy.at(index).at(0); + QCOMPARE(argument.userType(), mTreeItemStarType); + QCOMPARE(qvariant_cast<TreeItem*>(argument), item); +} + +QTEST_MAIN(WaitForEventTreeItemTest) + +#include "WaitForEventTreeItemTest.moc" Property changes on: trunk/ktutorial/ktutorial-editor/tests/unit/view/WaitForEventTreeItemTest.cpp ___________________________________________________________________ Added: svn:eol-style + native Added: trunk/ktutorial/ktutorial-editor/tests/unit/view/WaitForEventWidgetTest.cpp =================================================================== --- trunk/ktutorial/ktutorial-editor/tests/unit/view/WaitForEventWidgetTest.cpp (rev 0) +++ trunk/ktutorial/ktutorial-editor/tests/unit/view/WaitForEventWidgetTest.cpp 2010-03-16 05:42:56 UTC (rev 162) @@ -0,0 +1,86 @@ +/*************************************************************************** + * 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 "WaitForEventWidget.h" + +#include <KLineEdit> + +#include "../WaitForEvent.h" + +class WaitForEventWidgetTest: public QObject { +Q_OBJECT + +private slots: + + void testConstructor(); + + void testSaveChanges(); + +private: + + KLineEdit* receiverNameLineEdit(WaitForEventWidget* widget) const; + KLineEdit* eventNameLineEdit(WaitForEventWidget* widget) const; + +}; + +void WaitForEventWidgetTest::testConstructor() { + WaitForEvent waitFor; + waitFor.setReceiverName("The receiver name"); + waitFor.setEventName("The event name"); + + QWidget parent; + WaitForEventWidget* widget = new WaitForEventWidget(&waitFor, &parent); + + QCOMPARE(widget->parentWidget(), &parent); + QCOMPARE(receiverNameLineEdit(widget)->text(), + QString("The receiver name")); + QCOMPARE(eventNameLineEdit(widget)->text(), QString("The event name")); +} + +void WaitForEventWidgetTest::testSaveChanges() { + WaitForEvent waitFor; + waitFor.setReceiverName("The receiver name"); + waitFor.setEventName("The event name"); + + WaitForEventWidget widget(&waitFor); + receiverNameLineEdit(&widget)->setText("The new receiver name"); + eventNameLineEdit(&widget)->setText("The new event name"); + + widget.saveChanges(); + + QCOMPARE(waitFor.receiverName(), QString("The new receiver name")); + QCOMPARE(waitFor.eventName(), QString("The new event name")); +} + +/////////////////////////////////// Helpers //////////////////////////////////// + +KLineEdit* WaitForEventWidgetTest::receiverNameLineEdit( + WaitForEventWidget* widget) const { + return widget->findChild<KLineEdit*>("receiverNameLineEdit"); +} + +KLineEdit* WaitForEventWidgetTest::eventNameLineEdit( + WaitForEventWidget* widget) const { + return widget->findChild<KLineEdit*>("eventNameLineEdit"); +} + +QTEST_MAIN(WaitForEventWidgetTest) + +#include "WaitForEventWidgetTest.moc" Property changes on: trunk/ktutorial/ktutorial-editor/tests/unit/view/WaitForEventWidgetTest.cpp ___________________________________________________________________ Added: svn:eol-style + native Modified: trunk/ktutorial/ktutorial-editor/tests/unit/view/WaitForTreeItemTest.cpp =================================================================== --- trunk/ktutorial/ktutorial-editor/tests/unit/view/WaitForTreeItemTest.cpp 2010-03-16 03:00:35 UTC (rev 161) +++ trunk/ktutorial/ktutorial-editor/tests/unit/view/WaitForTreeItemTest.cpp 2010-03-16 05:42:56 UTC (rev 162) @@ -21,10 +21,12 @@ #include "WaitForTreeItem.h" #include "WaitForComposedTreeItem.h" +#include "WaitForEventTreeItem.h" #include "WaitForNotTreeItem.h" #include "WaitForSignalTreeItem.h" #include "../WaitFor.h" #include "../WaitForComposed.h" +#include "../WaitForEvent.h" #include "../WaitForNot.h" #include "../WaitForSignal.h" @@ -36,6 +38,7 @@ void testConstructor(); void testTreeItemForWaitForComposed(); + void testTreeItemForWaitForEvent(); void testTreeItemForWaitForNot(); void testTreeItemForWaitForSignal(); @@ -99,6 +102,20 @@ delete item; } +void WaitForTreeItemTest::testTreeItemForWaitForEvent() { + WaitForEvent waitFor; + StubTreeItem parent; + + WaitForTreeItem* item = WaitForTreeItem::treeItemForWaitFor(&waitFor, + &parent); + + QVERIFY(qobject_cast<WaitForEventTreeItem*>(item)); + QCOMPARE(item->parent(), &parent); + QCOMPARE(item->waitFor(), &waitFor); + + delete item; +} + void WaitForTreeItemTest::testTreeItemForWaitForNot() { WaitForNot waitFor; StubTreeItem parent; Modified: trunk/ktutorial/ktutorial-editor/tests/unit/view/WaitForWidgetTest.cpp =================================================================== --- trunk/ktutorial/ktutorial-editor/tests/unit/view/WaitForWidgetTest.cpp 2010-03-16 03:00:35 UTC (rev 161) +++ trunk/ktutorial/ktutorial-editor/tests/unit/view/WaitForWidgetTest.cpp 2010-03-16 05:42:56 UTC (rev 162) @@ -28,6 +28,7 @@ #include "EditionDialog.h" #include "../WaitForComposed.h" +#include "../WaitForEvent.h" #include "../WaitForNot.h" #include "../WaitForSignal.h" @@ -38,6 +39,7 @@ void addWaitForSignal() const; void cancelAddWaitForDialog() const; + void setEventData() const; void setSignalData() const; private slots: @@ -52,6 +54,7 @@ void testSelectWaitForOr(); void testSelectWaitForNot(); void testSelectWaitForNotEmpty(); + void testSelectWaitForEvent(); void testSelectWaitForSignal(); void testClearSelection(); @@ -60,6 +63,7 @@ void testAddWaitForToWaitForNot(); void testAddWaitForCancellingDialog(); + void testEditWaitForEvent(); void testEditWaitForSignal(); void testRemoveWaitForFromRoot(); @@ -71,6 +75,7 @@ WaitForComposed* mWaitFor; WaitForSignal* mWaitFor1; WaitForComposed* mWaitFor2; + WaitForEvent* mWaitFor2_1; WaitForNot* mWaitFor3; WaitForSignal* mWaitFor3_1; WaitForNot* mWaitFor4; @@ -104,6 +109,11 @@ mWaitFor2->setCompositionType(WaitForComposed::Or); mWaitFor->addWaitFor(mWaitFor2); + mWaitFor2_1 = new WaitForEvent(); + mWaitFor2_1->setReceiverName("receiver"); + mWaitFor2_1->setEventName("event"); + mWaitFor2->addWaitFor(mWaitFor2_1); + mWaitFor3 = new WaitForNot(); mWaitFor->addWaitFor(mWaitFor3); @@ -165,6 +175,12 @@ assertButtonEnabled(true, false, true); } +void WaitForWidgetTest::testSelectWaitForEvent() { + selectItem(getIndex(0, getIndex(1, getIndex(0)))); + + assertButtonEnabled(false, true, true); +} + void WaitForWidgetTest::testSelectWaitForSignal() { selectItem(getIndex(0, getIndex(0))); @@ -219,9 +235,10 @@ QCOMPARE(mWaitFor->waitFors()[2], mWaitFor3); QCOMPARE(mWaitFor->waitFors()[3], mWaitFor4); QVERIFY(qobject_cast<WaitForSignal*>(mWaitFor->waitFors()[4])); - QCOMPARE(mWaitFor2->waitFors().count(), 1); - QVERIFY(qobject_cast<WaitForSignal*>(mWaitFor2->waitFors()[0])); - QVERIFY(mWaitFor->waitFors()[4] != mWaitFor2->waitFors()[0]); + QCOMPARE(mWaitFor2->waitFors().count(), 2); + QCOMPARE(mWaitFor2->waitFors()[0], mWaitFor2_1); + QVERIFY(qobject_cast<WaitForSignal*>(mWaitFor2->waitFors()[1])); + QVERIFY(mWaitFor->waitFors()[4] != mWaitFor2->waitFors()[1]); } void WaitForWidgetTest::testAddWaitForToWaitForNot() { @@ -262,6 +279,20 @@ assertButtonEnabled(true, false, false); } +void WaitForWidgetTest::testEditWaitForEvent() { + selectItem(getIndex(0, getIndex(1, getIndex(0)))); + + //The dialog is modal, so it won't return to the test code until it is + //closed. Thus, the commands to execute on the dialog must be "queued", + //as calling setEventData after the button click won't work. + QTimer::singleShot(500, this, SLOT(setEventData())); + + button("editButton")->click(); + + QCOMPARE(mWaitFor2_1->receiverName(), QString("The new receiver name")); + QCOMPARE(mWaitFor2_1->eventName(), QString("The new event name")); +} + void WaitForWidgetTest::testEditWaitForSignal() { selectItem(getIndex(0, getIndex(0))); @@ -329,6 +360,22 @@ dialog->button(KDialog::Cancel)->click(); } +void WaitForWidgetTest::setEventData() const { + KLineEdit* receiverNameLineEdit = + mWidget->findChild<KLineEdit*>("receiverNameLineEdit"); + QVERIFY(receiverNameLineEdit); + receiverNameLineEdit->setText("The new receiver name"); + + KLineEdit* eventNameLineEdit = + mWidget->findChild<KLineEdit*>("eventNameLineEdit"); + QVERIFY(eventNameLineEdit); + eventNameLineEdit->setText("The new event name"); + + EditionDialog* dialog = mWidget->findChild<EditionDialog*>("editionDialog"); + QVERIFY(dialog); + dialog->button(KDialog::Ok)->click(); +} + void WaitForWidgetTest::setSignalData() const { KLineEdit* emitterNameLineEdit = mWidget->findChild<KLineEdit*>("emitterNameLineEdit"); This was sent by the SourceForge.net collaborative development platform, the world's largest Open Source development site. |
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] |
From: <dan...@us...> - 2010-03-19 18:14:22
|
Revision: 166 http://ktutorial.svn.sourceforge.net/ktutorial/?rev=166&view=rev Author: danxuliu Date: 2010-03-19 18:14:11 +0000 (Fri, 19 Mar 2010) Log Message: ----------- Add Serialization class to act as a facade for the serialization subsystem. Right now it only abstracts exporting a tutorial to some file, but in the future it will provide a way to load and save tutorials. Modified Paths: -------------- trunk/ktutorial/ktutorial-editor/src/serialization/CMakeLists.txt trunk/ktutorial/ktutorial-editor/tests/unit/serialization/CMakeLists.txt Added Paths: ----------- trunk/ktutorial/ktutorial-editor/src/serialization/Serialization.cpp trunk/ktutorial/ktutorial-editor/src/serialization/Serialization.h trunk/ktutorial/ktutorial-editor/tests/unit/serialization/SerializationTest.cpp Modified: trunk/ktutorial/ktutorial-editor/src/serialization/CMakeLists.txt =================================================================== --- trunk/ktutorial/ktutorial-editor/src/serialization/CMakeLists.txt 2010-03-19 07:12:21 UTC (rev 165) +++ trunk/ktutorial/ktutorial-editor/src/serialization/CMakeLists.txt 2010-03-19 18:14:11 UTC (rev 166) @@ -2,6 +2,7 @@ set(ktutorial_editor_serialization_SRCS JavascriptExporter.cpp + Serialization.cpp ) kde4_add_library(ktutorial_editor_serialization ${ktutorial_editor_serialization_SRCS}) Added: trunk/ktutorial/ktutorial-editor/src/serialization/Serialization.cpp =================================================================== --- trunk/ktutorial/ktutorial-editor/src/serialization/Serialization.cpp (rev 0) +++ trunk/ktutorial/ktutorial-editor/src/serialization/Serialization.cpp 2010-03-19 18:14:11 UTC (rev 166) @@ -0,0 +1,71 @@ +/*************************************************************************** + * 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 "Serialization.h" + +#include <KLocalizedString> +#include <KTemporaryFile> +#include <KUrl> +#include <KIO/NetAccess> + +#include "JavascriptExporter.h" + +//public: + +QString Serialization::availableExporterTypes() { + QStringList typeList = availableExporterTypeList(); + + QString types; + for (int i=0; i<typeList.count() - 1; ++i) { + types += typeList[i] + '\n'; + } + types += typeList[typeList.count()-1]; + + return types; +} + +bool Serialization::exportTutorial(const Tutorial* tutorial, + const QString& type, const KUrl& url) { + Q_ASSERT(tutorial); + Q_ASSERT(url.isValid()); + + QString exportedCode; + if (type == "*.js") { + exportedCode = JavascriptExporter().exportTutorial(tutorial); + } else { + Q_ASSERT(false); + } + + KTemporaryFile temporaryFile; + temporaryFile.open(); + QTextStream out(&temporaryFile); + out << exportedCode; + out.flush(); + temporaryFile.close(); + + return KIO::NetAccess::upload(temporaryFile.fileName(), url, 0); +} + +//private: + +QStringList Serialization::availableExporterTypeList() { + QStringList types; + types << i18nc("@item:combobox A KFileDialog filter", + "*.js|Javascript file"); + return types; +} Property changes on: trunk/ktutorial/ktutorial-editor/src/serialization/Serialization.cpp ___________________________________________________________________ Added: svn:eol-style + native Added: trunk/ktutorial/ktutorial-editor/src/serialization/Serialization.h =================================================================== --- trunk/ktutorial/ktutorial-editor/src/serialization/Serialization.h (rev 0) +++ trunk/ktutorial/ktutorial-editor/src/serialization/Serialization.h 2010-03-19 18:14:11 UTC (rev 166) @@ -0,0 +1,76 @@ +/*************************************************************************** + * 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 SERIALIZATION_H +#define SERIALIZATION_H + +#include <QStringList> + +class KUrl; +class Tutorial; + +/** + * Facade for serialization system. + * It provides the methods needed to know the available exporters and export a + * tutorial using one of them. + */ +class Serialization { +public: + + /** + * Returns the available exporter types. + * The string has the format expected by KFileDialog setFilter method, that + * is, "*.fileExtension1|Human readable name1\n*.fileExtension2|Human + * readable name2\n...". + * The first type in the list is the default type, Javascript. + * + * @return The available exporter types. + */ + static QString availableExporterTypes(); + + /** + * Exports the tutorial to the file specified by the url using the given + * exporter type. + * The type must be the extension fragment of one of the types returned by + * availableExporterTypes(). It is the value returned by KDialog + * currentFilter() method. + * + * The url can be local or remote. If the file can't be saved, false is + * returned. In that case, KIO::NetAccess can be asked for the error code + * and string. + * + * @param tutorial The tutorial to export. + * @param type The type of the exporter to use. + * @param url The url to save the script file to. + * @return True if the exported tutorial was saved, false otherwise. + */ + static bool exportTutorial(const Tutorial* tutorial, const QString& type, + const KUrl& url); + +private: + + /** + * Returns a list of strings with the available exporter types. + * + * @return A list with the available exporter types. + */ + static QStringList availableExporterTypeList(); + +}; + +#endif Property changes on: trunk/ktutorial/ktutorial-editor/src/serialization/Serialization.h ___________________________________________________________________ Added: svn:eol-style + native Modified: trunk/ktutorial/ktutorial-editor/tests/unit/serialization/CMakeLists.txt =================================================================== --- trunk/ktutorial/ktutorial-editor/tests/unit/serialization/CMakeLists.txt 2010-03-19 07:12:21 UTC (rev 165) +++ trunk/ktutorial/ktutorial-editor/tests/unit/serialization/CMakeLists.txt 2010-03-19 18:14:11 UTC (rev 166) @@ -13,6 +13,7 @@ unit_tests( JavascriptExporter + Serialization ) MACRO(MEM_TESTS) @@ -23,4 +24,5 @@ mem_tests( JavascriptExporter + Serialization ) Added: trunk/ktutorial/ktutorial-editor/tests/unit/serialization/SerializationTest.cpp =================================================================== --- trunk/ktutorial/ktutorial-editor/tests/unit/serialization/SerializationTest.cpp (rev 0) +++ trunk/ktutorial/ktutorial-editor/tests/unit/serialization/SerializationTest.cpp 2010-03-19 18:14:11 UTC (rev 166) @@ -0,0 +1,162 @@ +/*************************************************************************** + * 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 "Serialization.h" + +#include <QFile> + +#include <KLocalizedString> +#include <KStandardDirs> +#include <KUrl> + +#include "../Tutorial.h" + +class SerializationTest: public QObject { +Q_OBJECT + +private slots: + + void init(); + void cleanup(); + + void testAvailableExporterTypes(); + + void testExportJavascript(); + + void testExportToExistingUrl(); + void testExportToUnwritableUrl(); + +private: + + QFile* mExportedFile; + + QString readFile(QFile* file); + void writeFile(QFile* file, const QString& contents); + +}; + +void SerializationTest::init() { + mExportedFile = 0; +} + +void SerializationTest::cleanup() { + if (mExportedFile) { + mExportedFile->remove(); + } + delete mExportedFile; +} + +void SerializationTest::testAvailableExporterTypes() { + QString types = Serialization::availableExporterTypes(); + + QCOMPARE(types, i18nc("@item:combobox A KFileDialog filter", + "*.js|Javascript file")); +} + +void SerializationTest::testExportJavascript() { + Tutorial tutorial; + tutorial.setName("The name"); + tutorial.setDescription("The description"); + + KUrl url = KGlobal::dirs()->saveLocation("tmp") + "/SerializationTest.js"; + + QVERIFY(Serialization::exportTutorial(&tutorial, "*.js", url)); + + mExportedFile = new QFile(url.toLocalFile()); + QVERIFY(mExportedFile->exists()); + QVERIFY(mExportedFile->open(QIODevice::ReadOnly | QIODevice::Text)); + + QString actualContents = readFile(mExportedFile); + QString expectedContents = +"t = Kross.module(\"kdetranslation\");\n" +"\n" +"tutorial.tutorialInformationAsObject().setName(t.i18n(\"The name\"));\n" +"tutorial.tutorialInformationAsObject().setDescription(" + "t.i18n(\"The description\"));\n" +"\n"; + + QCOMPARE(actualContents, expectedContents); +} + +void SerializationTest::testExportToExistingUrl() { + Tutorial tutorial; + tutorial.setName("The name"); + tutorial.setDescription("The description"); + + KUrl url = KGlobal::dirs()->saveLocation("tmp") + "/SerializationTest.js"; + mExportedFile = new QFile(url.toLocalFile()); + mExportedFile->open(QIODevice::WriteOnly | QIODevice::Text); + writeFile(mExportedFile, "Hello world!"); + + QVERIFY(Serialization::exportTutorial(&tutorial, "*.js", url)); + + QVERIFY(mExportedFile->exists()); + QVERIFY(mExportedFile->open(QIODevice::ReadOnly | QIODevice::Text)); + + QString actualContents = readFile(mExportedFile); + QString expectedContents = +"t = Kross.module(\"kdetranslation\");\n" +"\n" +"tutorial.tutorialInformationAsObject().setName(t.i18n(\"The name\"));\n" +"tutorial.tutorialInformationAsObject().setDescription(" + "t.i18n(\"The description\"));\n" +"\n"; + + QCOMPARE(actualContents, expectedContents); +} + +void SerializationTest::testExportToUnwritableUrl() { + Tutorial tutorial; + tutorial.setName("The name"); + tutorial.setDescription("The description"); + + KUrl url = KGlobal::dirs()->saveLocation("tmp") + "/SerializationTest.js"; + mExportedFile = new QFile(url.toLocalFile()); + mExportedFile->open(QIODevice::WriteOnly | QIODevice::Text); + writeFile(mExportedFile, "Hello world!"); + QVERIFY(QFile::setPermissions(mExportedFile->fileName(), 0)); + + QVERIFY(!Serialization::exportTutorial(&tutorial, "*.js", url)); +} + +/////////////////////////////////// Helpers //////////////////////////////////// + +QString SerializationTest::readFile(QFile* file) { + QString data; + + QTextStream in(file); + while (!in.atEnd()) { + data += in.readAll(); + } + file->close(); + + return data; +} + +void SerializationTest::writeFile(QFile* file, const QString& contents) { + QTextStream out(file); + out << contents; + + file->close(); +} + +QTEST_MAIN(SerializationTest) + +#include "SerializationTest.moc" Property changes on: trunk/ktutorial/ktutorial-editor/tests/unit/serialization/SerializationTest.cpp ___________________________________________________________________ Added: svn:eol-style + native This was sent by the SourceForge.net collaborative development platform, the world's largest Open Source development site. |
From: <dan...@us...> - 2010-03-21 01:03:49
|
Revision: 172 http://ktutorial.svn.sourceforge.net/ktutorial/?rev=172&view=rev Author: danxuliu Date: 2010-03-21 01:03:42 +0000 (Sun, 21 Mar 2010) Log Message: ----------- Fix unescaped sequences in Javascript code when the source string contained quote, tabulator or new line characters. Also ensure that generated function and variable names contain only letters, digits or underscores. Modified Paths: -------------- trunk/ktutorial/ktutorial-editor/src/serialization/JavascriptExporter.cpp trunk/ktutorial/ktutorial-editor/src/serialization/JavascriptExporter.h trunk/ktutorial/ktutorial-editor/tests/unit/serialization/JavascriptExporterTest.cpp Modified: trunk/ktutorial/ktutorial-editor/src/serialization/JavascriptExporter.cpp =================================================================== --- trunk/ktutorial/ktutorial-editor/src/serialization/JavascriptExporter.cpp 2010-03-19 19:06:00 UTC (rev 171) +++ trunk/ktutorial/ktutorial-editor/src/serialization/JavascriptExporter.cpp 2010-03-21 01:03:42 UTC (rev 172) @@ -81,14 +81,14 @@ out() << "//Error: Tutorial without name!\n"; } else { out() << "tutorial.tutorialInformationAsObject().setName(t.i18n(\"" - << tutorial->name() <<"\"));\n"; + << escape(tutorial->name()) <<"\"));\n"; } if (tutorial->description().isEmpty()) { out() << "//Error: Tutorial without description!\n"; } else { out() << "tutorial.tutorialInformationAsObject().setDescription(" - << "t.i18n(\"" << tutorial->description() <<"\"));\n"; + << "t.i18n(\"" << escape(tutorial->description()) <<"\"));\n"; } mOut << "\n"; @@ -131,14 +131,14 @@ out() << "//Step " << step->id() << "\n"; QString stepVariable = toLowerCamelCase(step->id()) + "Step"; - out() << stepVariable << " = ktutorial.newStep(\"" << step->id() + out() << stepVariable << " = ktutorial.newStep(\"" << escape(step->id()) << "\");\n"; if (step->text().isEmpty()) { out() << "//Error: Step without text!\n"; } else { out() << stepVariable << ".setText(t.i18nc(\"@info\", \"" - << step->text() << "\"));\n"; + << escape(step->text()) << "\"));\n"; } mOut << '\n'; @@ -218,8 +218,8 @@ if (reaction->triggerType() == Reaction::OptionSelected && reaction->responseType() == Reaction::NextStep) { out() << "step.addOption(ktutorial.newOption(\"" - << reaction->optionName() << "\"), \"" << reaction->nextStepId() - << "\");\n"; + << escape(reaction->optionName()) << "\"), \"" + << escape(reaction->nextStepId()) << "\");\n"; return; } @@ -229,8 +229,8 @@ toUpperCamelCase(reaction->optionName()) + "OptionSelected"; out() << "step.addOption(ktutorial.newOption(\"" - << reaction->optionName() << "\"), self, \"" << functionName - << "()\");\n"; + << escape(reaction->optionName()) << "\"), self, \"" + << functionName << "()\");\n"; addFunction(functionName, reaction->customCode()); return; } @@ -242,7 +242,7 @@ if (reaction->responseType() == Reaction::NextStep) { out() << "step.addWaitFor(" << variableName << ", \"" - << reaction->nextStepId() << "\");\n"; + << escape(reaction->nextStepId()) << "\");\n"; return; } @@ -313,8 +313,8 @@ out() << variable << " = ktutorial.newWaitFor(\"WaitForEvent\");\n"; out() << variable << ".setEvent(ktutorial.findObject(\"" - << waitForEvent->receiverName() << "\"), \"" - << waitForEvent->eventName() << "\");\n"; + << escape(waitForEvent->receiverName()) << "\"), \"" + << escape(waitForEvent->eventName()) << "\");\n"; return variable; } @@ -356,8 +356,8 @@ out() << variable << " = ktutorial.newWaitFor(\"WaitForSignal\");\n"; out() << variable << ".setSignal(ktutorial.findObject(\"" - << waitForSignal->emitterName() << "\"), \"" - << waitForSignal->signalName() << "\");\n"; + << escape(waitForSignal->emitterName()) << "\"), \"" + << escape(waitForSignal->signalName()) << "\");\n"; return variable; } @@ -407,6 +407,14 @@ return variable + QString().setNum(mVariables.value(variable)); } +QString JavascriptExporter::escape(QString text) { + text.replace('\n', "\\n"); + text.replace('\t', "\\t"); + text.replace('"', "\\\""); + + return text; +} + QString JavascriptExporter::toIndentedCode(const QString& code) { if (code.isEmpty()) { return ""; @@ -439,11 +447,12 @@ return lowerCamelCase; } -QString JavascriptExporter::toUpperCamelCase(const QString& text) const { +QString JavascriptExporter::toUpperCamelCase(QString text) const { if (text.isEmpty()) { return ""; } + text.replace(QRegExp("[^\\w ]"), ""); QStringList words = text.split(' ', QString::SkipEmptyParts); QString upperCamelCase; Modified: trunk/ktutorial/ktutorial-editor/src/serialization/JavascriptExporter.h =================================================================== --- trunk/ktutorial/ktutorial-editor/src/serialization/JavascriptExporter.h 2010-03-19 19:06:00 UTC (rev 171) +++ trunk/ktutorial/ktutorial-editor/src/serialization/JavascriptExporter.h 2010-03-21 01:03:42 UTC (rev 172) @@ -263,6 +263,16 @@ QString addVariable(const QString& variable); /** + * Returns the same text, but with Javascript escape sequences where needed. + * Some special characters (new line, tab and quotes) are written as their + * escape squence. + * + * @param text The text to escape. + * @return The Javascript text. + */ + QString escape(QString text); + + /** * Returns the same code, but with each line indented and ending in a new * line. * @@ -273,6 +283,8 @@ /** * Returns the lowerCamelCase version of the given text. + * Note that the returned text contains only letters, digits or underscores. + * Any other character is removed. * * @param text The string to get its lowerCamelCase version. * @return The lowerCamelCase version of the text. @@ -281,11 +293,13 @@ /** * Returns the UpperCamelCase version of the given text. + * Note that the returned text contains only letters, digits or underscores. + * Any other character is removed. * * @param text The string to get its UpperCamelCase version. * @return The UpperCamelCase version of the text. */ - QString toUpperCamelCase(const QString& text) const; + QString toUpperCamelCase(QString text) const; }; Modified: trunk/ktutorial/ktutorial-editor/tests/unit/serialization/JavascriptExporterTest.cpp =================================================================== --- trunk/ktutorial/ktutorial-editor/tests/unit/serialization/JavascriptExporterTest.cpp 2010-03-19 19:06:00 UTC (rev 171) +++ trunk/ktutorial/ktutorial-editor/tests/unit/serialization/JavascriptExporterTest.cpp 2010-03-21 01:03:42 UTC (rev 172) @@ -57,11 +57,13 @@ void testTutorialLicense(); void testTutorialInformation(); + void testTutorialInformationWithEscapeSequences(); void testTutorialSetupCode(); void testTutorialTearDownCode(); void testTutorialWithSeveralSteps(); void testStep(); + void testStepWithEscapeSequences(); void testStepSetupCode(); void testStepSetupCodeWithReactions(); void testStepTearDownCode(); @@ -69,17 +71,23 @@ void testStepWithSeveralReactions(); void testReactionOptionNextStep(); + void testReactionOptionNextStepWithEscapeSequences(); void testReactionOptionNextStepWithoutOptionNameOrStepId(); void testReactionOptionCustomCode(); + void testReactionOptionCustomCodeWithEscapeSequences(); void testReactionOptionCustomCodeWithoutOptionNameOrCustomCode(); void testReactionConditionNextStep(); + void testReactionConditionNextStepWithEscapeSequences(); void testReactionConditionNextStepWithoutConditionOrStepId(); void testReactionConditionCustomCode(); + void testReactionConditionCustomCodeWithEscapeSequences(); void testReactionConditionCustomCodeWithoutConditionOrCustomCode(); void testWaitForEvent(); + void testWaitForEventWithEscapeSequences(); void testWaitForEventWithoutReceiverNameOrEventName(); void testWaitForSignal(); + void testWaitForSignalWithEscapeSequences(); void testWaitForSignalWithoutEmitterNameOrSignalName(); void testWaitForComposed(); void testWaitForComposedWithInvalidChildWaitFor(); @@ -126,6 +134,25 @@ QCOMPARE(exportedTutorial, expected); } +void JavascriptExporterTest::testTutorialInformationWithEscapeSequences() { + Tutorial tutorial; + tutorial.setName("The \"name\""); + tutorial.setDescription("The\tdescription\nwith \"escape\" sequences"); + + 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\\tdescription\\nwith \\\"escape\\\" sequences\"));\n" +"\n"; + + QCOMPARE(exportedTutorial, expected); +} + void JavascriptExporterTest::testTutorialSetupCode() { Tutorial tutorial; tutorial.setCustomSetupCode("The custom setup\ncode"); @@ -278,6 +305,29 @@ QCOMPARE(exportedTutorial, expected); } +void JavascriptExporterTest::testStepWithEscapeSequences() { + Tutorial tutorial; + Step* step = new Step(); + step->setId("The \"id\""); + step->setText("The\ttext\nwith \"escape\" sequences"); + 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\\ttext\\nwith \\\"escape\\\" sequences\"));\n" +"\n" +"tutorial.addStep(theIdStep);\n" +"\n"; + + QCOMPARE(exportedTutorial, expected); +} + void JavascriptExporterTest::testStepSetupCode() { Tutorial tutorial; Step* step = new Step(); @@ -477,6 +527,35 @@ QCOMPARE(exportedTutorial, expected); } +void JavascriptExporterTest::testReactionOptionNextStepWithEscapeSequences() { + 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; @@ -553,6 +632,40 @@ QCOMPARE(exportedTutorial, expected); } +void JavascriptExporterTest::testReactionOptionCustomCodeWithEscapeSequences() { + 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; @@ -638,6 +751,46 @@ } void JavascriptExporterTest:: + testReactionConditionNextStepWithEscapeSequences() { + 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(); @@ -726,6 +879,51 @@ } void JavascriptExporterTest:: + testReactionConditionCustomCodeWithEscapeSequences() { + 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(); @@ -817,6 +1015,43 @@ QCOMPARE(exportedTutorial, expected); } +void JavascriptExporterTest::testWaitForEventWithEscapeSequences() { + 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(); @@ -899,6 +1134,44 @@ QCOMPARE(exportedTutorial, expected); } +void JavascriptExporterTest::testWaitForSignalWithEscapeSequences() { + 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::testWaitForSignalWithoutEmitterNameOrSignalName() { Tutorial tutorial; Step* step = new Step(); This was sent by the SourceForge.net collaborative development platform, the world's largest Open Source development site. |
From: <dan...@us...> - 2010-03-22 18:13:57
|
Revision: 175 http://ktutorial.svn.sourceforge.net/ktutorial/?rev=175&view=rev Author: danxuliu Date: 2010-03-22 18:13:49 +0000 (Mon, 22 Mar 2010) Log Message: ----------- When mandatory data in tutorial and step isn't set (name and information in tutorial, and id and text in step), show a placeholder instead of completly hidding it in the tree view to keep consistency with how mandatory data is shown in reactions and conditions to wait for. Modified Paths: -------------- trunk/ktutorial/ktutorial-editor/src/view/StepTreeItem.cpp trunk/ktutorial/ktutorial-editor/src/view/StepTreeItem.h trunk/ktutorial/ktutorial-editor/src/view/TutorialTreeItem.cpp trunk/ktutorial/ktutorial-editor/src/view/TutorialTreeItem.h trunk/ktutorial/ktutorial-editor/tests/unit/view/StepTreeItemTest.cpp trunk/ktutorial/ktutorial-editor/tests/unit/view/TutorialTreeItemTest.cpp Modified: trunk/ktutorial/ktutorial-editor/src/view/StepTreeItem.cpp =================================================================== --- trunk/ktutorial/ktutorial-editor/src/view/StepTreeItem.cpp 2010-03-21 16:08:40 UTC (rev 174) +++ trunk/ktutorial/ktutorial-editor/src/view/StepTreeItem.cpp 2010-03-22 18:13:49 UTC (rev 175) @@ -32,7 +32,8 @@ mStep(step) { Q_ASSERT(step); - mTextItem = 0; + mTextItem = new TextTreeItem(this); + appendChild(mTextItem); mSetupItem = 0; mTearDownItem = 0; @@ -50,11 +51,12 @@ } QString StepTreeItem::text() const { + QString id = mStepId; if (mStepId.isEmpty()) { - return i18nc("@item Noun, a step in a tutorial", "Step"); + id = i18nc("@item", "(id not set)"); } - return i18nc("@item Noun, a step in a tutorial", "Step %1", mStepId); + return i18nc("@item Noun, a step in a tutorial", "Step %1", id); } Step* StepTreeItem::step() const { @@ -77,8 +79,6 @@ //private slots: void StepTreeItem::update(Step* step) { - int childIndex = 0; - if (step->id().isEmpty()) { if (!mStepId.isEmpty()) { mStepId.clear(); @@ -89,15 +89,16 @@ emit dataChanged(this); } + QString text; if (step->text().isEmpty()) { - TreeItemUtil::removeFlatItemIfNeeded(mTextItem); + text = i18nc("@item", "(text not set)"); } else { - TreeItemUtil::addFlatItemIfNeeded(this, mTextItem, childIndex); - mTextItem->setText(i18nc("@item", "Text: %1", step->text())); - - childIndex++; + text = step->text(); } + mTextItem->setText(i18nc("@item", "Text: %1", text)); + int childIndex = 1; + if (step->customSetupCode().isEmpty()) { TreeItemUtil::removeNestedItemIfNeeded(mSetupItem); } else { Modified: trunk/ktutorial/ktutorial-editor/src/view/StepTreeItem.h =================================================================== --- trunk/ktutorial/ktutorial-editor/src/view/StepTreeItem.h 2010-03-21 16:08:40 UTC (rev 174) +++ trunk/ktutorial/ktutorial-editor/src/view/StepTreeItem.h 2010-03-22 18:13:49 UTC (rev 175) @@ -41,9 +41,13 @@ * | ... * ... * - * The items only appear if they have some data to show. For example, if only - * the text of the Step is set, its representation is: - * Step + * If the id or the text aren't set yet, a placeholder is used instead. Id + * placeholder is "(id not set)", and the text placeholder is "(text not set)" + * (without quotes, but with parenthesis). + * + * The other items only appear if they have some data to show. For example, if + * only the text of the Step is set, its representation is: + * Step (id not set) * -The text * * Note that composed elements like custom setup code don't appear at all, not @@ -53,8 +57,8 @@ * are updated as needed. * * Also note that the order of the child elements is always the same. Even if, - * for example, the setup code is set first and then the text, the text item - * will appear first and then the setup code item. + * for example, the tear down code is set first and then the setup code, the + * setup code item will appear first and then the tear down code item. * * @see ReactionTreeItem */ @@ -72,8 +76,8 @@ explicit StepTreeItem(Step* step, TreeItem* parent = 0); /** - * Returns "Step " and the id of the step, or just "Step" if - * there is no id. + * Returns "Step " and the id of the step, or "Step (id not set)" if there + * is no id. * * @return The text for this TreeItem. */ Modified: trunk/ktutorial/ktutorial-editor/src/view/TutorialTreeItem.cpp =================================================================== --- trunk/ktutorial/ktutorial-editor/src/view/TutorialTreeItem.cpp 2010-03-21 16:08:40 UTC (rev 174) +++ trunk/ktutorial/ktutorial-editor/src/view/TutorialTreeItem.cpp 2010-03-22 18:13:49 UTC (rev 175) @@ -31,8 +31,10 @@ TreeItem(parent) { Q_ASSERT(tutorial); - mNameItem = 0; - mDescriptionItem = 0; + mNameItem = new TextTreeItem(this); + appendChild(mNameItem); + mDescriptionItem = new TextTreeItem(this); + appendChild(mDescriptionItem); mLicenseItem = 0; mSetupItem = 0; mTearDownItem = 0; @@ -73,36 +75,33 @@ //private slots: void TutorialTreeItem::update(Tutorial* tutorial) { - int childIndex = 0; - + QString name; if (tutorial->name().isEmpty()) { - TreeItemUtil::removeFlatItemIfNeeded(mNameItem); + name = i18nc("@item", "(name not set)"); if (!mTutorialId.isEmpty()) { mTutorialId.clear(); emit dataChanged(this); } } else { - TreeItemUtil::addFlatItemIfNeeded(this, mNameItem, childIndex); - mNameItem->setText(i18nc("@item Noun, the name of a tutorial", - "Name: %1", tutorial->name())); + name = tutorial->name(); mTutorialId = tutorial->id(); emit dataChanged(this); - - childIndex++; } + mNameItem->setText(i18nc("@item Noun, the name of a tutorial", + "Name: %1", name)); + QString description; if (tutorial->description().isEmpty()) { - TreeItemUtil::removeFlatItemIfNeeded(mDescriptionItem); + description = i18nc("@item", "(description not set)"); } else { - TreeItemUtil::addFlatItemIfNeeded(this, mDescriptionItem, childIndex); - mDescriptionItem->setText(i18nc("@item", "Description: %1", - tutorial->description())); - - childIndex++; + description = tutorial->description(); } + mDescriptionItem->setText(i18nc("@item", "Description: %1", description)); + int childIndex = 2; + if (tutorial->licenseText().isEmpty()) { TreeItemUtil::removeNestedItemIfNeeded(mLicenseItem); } else { Modified: trunk/ktutorial/ktutorial-editor/src/view/TutorialTreeItem.h =================================================================== --- trunk/ktutorial/ktutorial-editor/src/view/TutorialTreeItem.h 2010-03-21 16:08:40 UTC (rev 174) +++ trunk/ktutorial/ktutorial-editor/src/view/TutorialTreeItem.h 2010-03-22 18:13:49 UTC (rev 175) @@ -44,10 +44,15 @@ * | ... * ... * - * The items only appear if they have some data to show. For example, if only - * the name of the Tutorial is set, its representation is: - * Tutorial theId + * If the name or the description aren't set yet, a placeholder is used instead. + * Name placeholder is "(name not set)", and the description placeholder is + * "(description not set)" (without quotes, but with parenthesis). + * + * The other items only appear if they have some data to show. For example, if + * only the name of the Tutorial is set, its representation is: + * Tutorial theName * -Name: the name + * -Description: (description not set) * * Note that composed elements like license don't appear at all, not even the * parent item with just "License:". @@ -56,8 +61,8 @@ * are updated as needed. * * Also note that the order of the child elements is always the same. Even if, - * for example, the setup code is set first and then the name, the name item - * will appear first and then the setup code item. + * for example, the tear down code is set first and then the license, the + * license item will appear first and then the tear down code item. * * @see StepTreeItem */ Modified: trunk/ktutorial/ktutorial-editor/tests/unit/view/StepTreeItemTest.cpp =================================================================== --- trunk/ktutorial/ktutorial-editor/tests/unit/view/StepTreeItemTest.cpp 2010-03-21 16:08:40 UTC (rev 174) +++ trunk/ktutorial/ktutorial-editor/tests/unit/view/StepTreeItemTest.cpp 2010-03-22 18:13:49 UTC (rev 175) @@ -63,6 +63,7 @@ int mTreeItemStarType; + void assertEmptyText(TreeItem* textItem) const; void assertText(TreeItem* textItem, const QString& licenseText) const; void assertCustomSetupCode(TreeItem* setupItem, const QString& code) const; void assertCustomTearDownCode(TreeItem* tearDownItem, @@ -93,9 +94,10 @@ StepTreeItem item(&step, &parent); QCOMPARE(item.parent(), &parent); - QCOMPARE(item.text(), i18nc("@item", "Step")); + QCOMPARE(item.text(), i18nc("@item", "Step (id not set)")); QCOMPARE(item.step(), &step); - QCOMPARE(item.childCount(), 0); + QCOMPARE(item.childCount(), 1); + assertEmptyText(item.child(0)); } void StepTreeItemTest::testConstructorFullStep() { @@ -139,7 +141,8 @@ step.setId("The id"); QCOMPARE(item.text(), i18nc("@item", "Step %1", "The id")); - QCOMPARE(item.childCount(), 0); + QCOMPARE(item.childCount(), 1); + assertEmptyText(item.child(0)); QCOMPARE(dataChangedSpy.count(), 1); assertDataChanged(dataChangedSpy, 0, &item); } @@ -155,7 +158,8 @@ step.setId("The id changed"); QCOMPARE(item.text(), i18nc("@item", "Step %1", "The id changed")); - QCOMPARE(item.childCount(), 0); + QCOMPARE(item.childCount(), 1); + assertEmptyText(item.child(0)); QCOMPARE(dataChangedSpy.count(), 1); assertDataChanged(dataChangedSpy, 0, &item); } @@ -170,8 +174,9 @@ step.setId(""); - QCOMPARE(item.text(), i18nc("@item", "Step")); - QCOMPARE(item.childCount(), 0); + QCOMPARE(item.text(), i18nc("@item", "Step (id not set)")); + QCOMPARE(item.childCount(), 1); + assertEmptyText(item.child(0)); QCOMPARE(dataChangedSpy.count(), 1); assertDataChanged(dataChangedSpy, 0, &item); } @@ -180,10 +185,14 @@ Step step; StepTreeItem item(&step); + QSignalSpy dataChangedSpy(item.child(0), SIGNAL(dataChanged(TreeItem*))); + step.setText("The text"); QCOMPARE(item.childCount(), 1); assertText(item.child(0), "The text"); + QCOMPARE(dataChangedSpy.count(), 1); + assertDataChanged(dataChangedSpy, 0, item.child(0)); } void StepTreeItemTest::testStepSetTextChange() { @@ -207,9 +216,15 @@ StepTreeItem item(&step); step.setText("The text"); + + QSignalSpy dataChangedSpy(item.child(0), SIGNAL(dataChanged(TreeItem*))); + step.setText(""); - QCOMPARE(item.childCount(), 0); + QCOMPARE(item.childCount(), 1); + assertEmptyText(item.child(0)); + QCOMPARE(dataChangedSpy.count(), 1); + assertDataChanged(dataChangedSpy, 0, item.child(0)); } void StepTreeItemTest::testStepSetCustomSetupCode() { @@ -218,8 +233,9 @@ step.setCustomSetupCode("The setup code"); - QCOMPARE(item.childCount(), 1); - assertCustomSetupCode(item.child(0), "The setup code"); + QCOMPARE(item.childCount(), 2); + assertEmptyText(item.child(0)); + assertCustomSetupCode(item.child(1), "The setup code"); } void StepTreeItemTest::testStepSetCustomSetupCodeChange() { @@ -228,15 +244,16 @@ step.setCustomSetupCode("The setup code"); - QSignalSpy dataChangedSpy(item.child(0)->child(0), + QSignalSpy dataChangedSpy(item.child(1)->child(0), SIGNAL(dataChanged(TreeItem*))); step.setCustomSetupCode("The setup code changed"); - QCOMPARE(item.childCount(), 1); - assertCustomSetupCode(item.child(0), "The setup code changed"); + QCOMPARE(item.childCount(), 2); + assertEmptyText(item.child(0)); + assertCustomSetupCode(item.child(1), "The setup code changed"); QCOMPARE(dataChangedSpy.count(), 1); - assertDataChanged(dataChangedSpy, 0, item.child(0)->child(0)); + assertDataChanged(dataChangedSpy, 0, item.child(1)->child(0)); } void StepTreeItemTest::testStepSetCustomSetupCodeEmpty() { @@ -246,7 +263,8 @@ step.setCustomSetupCode("The setup code"); step.setCustomSetupCode(""); - QCOMPARE(item.childCount(), 0); + QCOMPARE(item.childCount(), 1); + assertEmptyText(item.child(0)); } void StepTreeItemTest::testStepSetCustomTearDownCode() { @@ -255,8 +273,9 @@ step.setCustomTearDownCode("The tear down code"); - QCOMPARE(item.childCount(), 1); - assertCustomTearDownCode(item.child(0), "The tear down code"); + QCOMPARE(item.childCount(), 2); + assertEmptyText(item.child(0)); + assertCustomTearDownCode(item.child(1), "The tear down code"); } void StepTreeItemTest::testStepSetCustomTearDownCodeChange() { @@ -265,15 +284,16 @@ step.setCustomTearDownCode("The tear down code"); - QSignalSpy dataChangedSpy(item.child(0)->child(0), + QSignalSpy dataChangedSpy(item.child(1)->child(0), SIGNAL(dataChanged(TreeItem*))); step.setCustomTearDownCode("The tear down code changed"); - QCOMPARE(item.childCount(), 1); - assertCustomTearDownCode(item.child(0), "The tear down code changed"); + QCOMPARE(item.childCount(), 2); + assertEmptyText(item.child(0)); + assertCustomTearDownCode(item.child(1), "The tear down code changed"); QCOMPARE(dataChangedSpy.count(), 1); - assertDataChanged(dataChangedSpy, 0, item.child(0)->child(0)); + assertDataChanged(dataChangedSpy, 0, item.child(1)->child(0)); } void StepTreeItemTest::testStepSetCustomTearDownCodeEmpty() { @@ -283,7 +303,8 @@ step.setCustomTearDownCode("The tear down code"); step.setCustomTearDownCode(""); - QCOMPARE(item.childCount(), 0); + QCOMPARE(item.childCount(), 1); + assertEmptyText(item.child(0)); } void StepTreeItemTest::testStepAddReaction() { @@ -293,8 +314,9 @@ Reaction* reaction = new Reaction(); step.addReaction(reaction); - QCOMPARE(item.childCount(), 1); - assertReaction(item.child(0), reaction); + QCOMPARE(item.childCount(), 2); + assertEmptyText(item.child(0)); + assertReaction(item.child(1), reaction); } void StepTreeItemTest::testStepRemoveReaction() { @@ -307,7 +329,8 @@ step.addReaction(&reaction); step.removeReaction(&reaction); - QCOMPARE(item.childCount(), 0); + QCOMPARE(item.childCount(), 1); + assertEmptyText(item.child(0)); } void StepTreeItemTest::testChildOrderWhenSettingDataInStep() { @@ -316,13 +339,14 @@ step.setCustomSetupCode("The setup code"); - QCOMPARE(item.text(), i18nc("@item", "Step")); - QCOMPARE(item.childCount(), 1); - assertCustomSetupCode(item.child(0), "The setup code"); + QCOMPARE(item.text(), i18nc("@item", "Step (id not set)")); + QCOMPARE(item.childCount(), 2); + assertEmptyText(item.child(0)); + assertCustomSetupCode(item.child(1), "The setup code"); step.setText("The text"); - QCOMPARE(item.text(), i18nc("@item", "Step")); + QCOMPARE(item.text(), i18nc("@item", "Step (id not set)")); QCOMPARE(item.childCount(), 2); assertText(item.child(0), "The text"); assertCustomSetupCode(item.child(1), "The setup code"); @@ -330,7 +354,7 @@ Reaction* reaction1 = new Reaction(); step.addReaction(reaction1); - QCOMPARE(item.text(), i18nc("@item", "Step")); + QCOMPARE(item.text(), i18nc("@item", "Step (id not set)")); QCOMPARE(item.childCount(), 3); assertText(item.child(0), "The text"); assertCustomSetupCode(item.child(1), "The setup code"); @@ -338,7 +362,7 @@ step.setCustomTearDownCode("The tear down code"); - QCOMPARE(item.text(), i18nc("@item", "Step")); + QCOMPARE(item.text(), i18nc("@item", "Step (id not set)")); QCOMPARE(item.childCount(), 4); assertText(item.child(0), "The text"); assertCustomSetupCode(item.child(1), "The setup code"); @@ -348,7 +372,7 @@ Reaction* reaction2 = new Reaction(); step.addReaction(reaction2); - QCOMPARE(item.text(), i18nc("@item", "Step")); + QCOMPARE(item.text(), i18nc("@item", "Step (id not set)")); QCOMPARE(item.childCount(), 5); assertText(item.child(0), "The text"); assertCustomSetupCode(item.child(1), "The setup code"); @@ -385,48 +409,58 @@ step.setText(""); QCOMPARE(item.text(), i18nc("@item", "Step %1", "The id")); - QCOMPARE(item.childCount(), 4); - assertCustomSetupCode(item.child(0), "The setup code"); - assertCustomTearDownCode(item.child(1), "The tear down code"); - assertReaction(item.child(2), &reaction1); - assertReaction(item.child(3), &reaction2); + QCOMPARE(item.childCount(), 5); + assertEmptyText(item.child(0)); + assertCustomSetupCode(item.child(1), "The setup code"); + assertCustomTearDownCode(item.child(2), "The tear down code"); + assertReaction(item.child(3), &reaction1); + assertReaction(item.child(4), &reaction2); step.removeReaction(&reaction1); QCOMPARE(item.text(), i18nc("@item", "Step %1", "The id")); - QCOMPARE(item.childCount(), 3); - assertCustomSetupCode(item.child(0), "The setup code"); - assertCustomTearDownCode(item.child(1), "The tear down code"); - assertReaction(item.child(2), &reaction2); + QCOMPARE(item.childCount(), 4); + assertEmptyText(item.child(0)); + assertCustomSetupCode(item.child(1), "The setup code"); + assertCustomTearDownCode(item.child(2), "The tear down code"); + assertReaction(item.child(3), &reaction2); step.setCustomTearDownCode(""); QCOMPARE(item.text(), i18nc("@item", "Step %1", "The id")); - QCOMPARE(item.childCount(), 2); - assertCustomSetupCode(item.child(0), "The setup code"); - assertReaction(item.child(1), &reaction2); + QCOMPARE(item.childCount(), 3); + assertEmptyText(item.child(0)); + assertCustomSetupCode(item.child(1), "The setup code"); + assertReaction(item.child(2), &reaction2); step.setId(""); - QCOMPARE(item.text(), i18nc("@item", "Step")); - QCOMPARE(item.childCount(), 2); - assertCustomSetupCode(item.child(0), "The setup code"); - assertReaction(item.child(1), &reaction2); + QCOMPARE(item.text(), i18nc("@item", "Step (id not set)")); + QCOMPARE(item.childCount(), 3); + assertEmptyText(item.child(0)); + assertCustomSetupCode(item.child(1), "The setup code"); + assertReaction(item.child(2), &reaction2); step.setCustomSetupCode(""); - QCOMPARE(item.text(), i18nc("@item", "Step")); - QCOMPARE(item.childCount(), 1); - assertReaction(item.child(0), &reaction2); + QCOMPARE(item.text(), i18nc("@item", "Step (id not set)")); + QCOMPARE(item.childCount(), 2); + assertEmptyText(item.child(0)); + assertReaction(item.child(1), &reaction2); step.removeReaction(&reaction2); - QCOMPARE(item.text(), i18nc("@item", "Step")); - QCOMPARE(item.childCount(), 0); + QCOMPARE(item.text(), i18nc("@item", "Step (id not set)")); + QCOMPARE(item.childCount(), 1); + assertEmptyText(item.child(0)); } /////////////////////////////////// Helpers //////////////////////////////////// +void StepTreeItemTest::assertEmptyText(TreeItem* textItem) const { + QCOMPARE(textItem->text(), i18nc("@item", "Text: (text not set)")); +} + void StepTreeItemTest::assertText(TreeItem* textItem, const QString& name) const { QCOMPARE(textItem->text(), i18nc("@item", "Text: %1", name)); Modified: trunk/ktutorial/ktutorial-editor/tests/unit/view/TutorialTreeItemTest.cpp =================================================================== --- trunk/ktutorial/ktutorial-editor/tests/unit/view/TutorialTreeItemTest.cpp 2010-03-21 16:08:40 UTC (rev 174) +++ trunk/ktutorial/ktutorial-editor/tests/unit/view/TutorialTreeItemTest.cpp 2010-03-22 18:13:49 UTC (rev 175) @@ -67,7 +67,9 @@ int mTreeItemStarType; + void assertEmptyName(TreeItem* nameItem) const; void assertName(TreeItem* nameItem, const QString& name) const; + void assertEmptyDescription(TreeItem* descriptionItem) const; void assertDescription(TreeItem* descriptionItem, const QString& description) const; void assertLicenseText(TreeItem* licenseItem, @@ -102,7 +104,9 @@ QCOMPARE(item.parent(), &parent); QCOMPARE(item.text(), i18nc("@item", "Tutorial")); - QCOMPARE(item.childCount(), 0); + QCOMPARE(item.childCount(), 2); + assertEmptyName(item.child(0)); + assertEmptyDescription(item.child(1)); } void TutorialTreeItemTest::testConstructorFullTutorial() { @@ -145,15 +149,19 @@ //Setting the name changes the data returned by text() in the //TutorialTreeItem itself, as the id is based on the name - QSignalSpy dataChangedSpy(&item, SIGNAL(dataChanged(TreeItem*))); + QSignalSpy dataChangedRootSpy(&item, SIGNAL(dataChanged(TreeItem*))); + QSignalSpy dataChangedSpy(item.child(0), SIGNAL(dataChanged(TreeItem*))); tutorial.setName("The name"); QCOMPARE(item.text(), i18nc("@item", "Tutorial %1", "theName")); - QCOMPARE(item.childCount(), 1); + QCOMPARE(item.childCount(), 2); assertName(item.child(0), "The name"); + assertEmptyDescription(item.child(1)); + QCOMPARE(dataChangedRootSpy.count(), 1); + assertDataChanged(dataChangedRootSpy, 0, &item); QCOMPARE(dataChangedSpy.count(), 1); - assertDataChanged(dataChangedSpy, 0, &item); + assertDataChanged(dataChangedSpy, 0, item.child(0)); } void TutorialTreeItemTest::testTutorialSetNameChange() { @@ -168,8 +176,9 @@ tutorial.setName("The name changed"); QCOMPARE(item.text(), i18nc("@item", "Tutorial %1", "theNameChanged")); - QCOMPARE(item.childCount(), 1); + QCOMPARE(item.childCount(), 2); assertName(item.child(0), "The name changed"); + assertEmptyDescription(item.child(1)); QCOMPARE(dataChangedRootSpy.count(), 1); assertDataChanged(dataChangedRootSpy, 0, &item); QCOMPARE(dataChangedSpy.count(), 1); @@ -182,24 +191,34 @@ tutorial.setName("The name"); - QSignalSpy dataChangedSpy(&item, SIGNAL(dataChanged(TreeItem*))); + QSignalSpy dataChangedRootSpy(&item, SIGNAL(dataChanged(TreeItem*))); + QSignalSpy dataChangedSpy(item.child(0), SIGNAL(dataChanged(TreeItem*))); tutorial.setName(""); QCOMPARE(item.text(), i18nc("@item", "Tutorial")); - QCOMPARE(item.childCount(), 0); + QCOMPARE(item.childCount(), 2); + assertEmptyName(item.child(0)); + assertEmptyDescription(item.child(1)); + QCOMPARE(dataChangedRootSpy.count(), 1); + assertDataChanged(dataChangedRootSpy, 0, &item); QCOMPARE(dataChangedSpy.count(), 1); - assertDataChanged(dataChangedSpy, 0, &item); + assertDataChanged(dataChangedSpy, 0, item.child(0)); } void TutorialTreeItemTest::testTutorialSetDescription() { Tutorial tutorial; TutorialTreeItem item(&tutorial); + QSignalSpy dataChangedSpy(item.child(1), SIGNAL(dataChanged(TreeItem*))); + tutorial.setDescription("The description"); - QCOMPARE(item.childCount(), 1); - assertDescription(item.child(0), "The description"); + QCOMPARE(item.childCount(), 2); + assertEmptyName(item.child(0)); + assertDescription(item.child(1), "The description"); + QCOMPARE(dataChangedSpy.count(), 1); + assertDataChanged(dataChangedSpy, 0, item.child(1)); } void TutorialTreeItemTest::testTutorialSetDescriptionChange() { @@ -208,14 +227,15 @@ tutorial.setDescription("The description"); - QSignalSpy dataChangedSpy(item.child(0), SIGNAL(dataChanged(TreeItem*))); + QSignalSpy dataChangedSpy(item.child(1), SIGNAL(dataChanged(TreeItem*))); tutorial.setDescription("The description changed"); - QCOMPARE(item.childCount(), 1); - assertDescription(item.child(0), "The description changed"); + QCOMPARE(item.childCount(), 2); + assertEmptyName(item.child(0)); + assertDescription(item.child(1), "The description changed"); QCOMPARE(dataChangedSpy.count(), 1); - assertDataChanged(dataChangedSpy, 0, item.child(0)); + assertDataChanged(dataChangedSpy, 0, item.child(1)); } void TutorialTreeItemTest::testTutorialSetDescriptionEmpty() { @@ -223,9 +243,16 @@ TutorialTreeItem item(&tutorial); tutorial.setDescription("The description"); + + QSignalSpy dataChangedSpy(item.child(1), SIGNAL(dataChanged(TreeItem*))); + tutorial.setDescription(""); - QCOMPARE(item.childCount(), 0); + QCOMPARE(item.childCount(), 2); + assertEmptyName(item.child(0)); + assertEmptyDescription(item.child(1)); + QCOMPARE(dataChangedSpy.count(), 1); + assertDataChanged(dataChangedSpy, 0, item.child(1)); } void TutorialTreeItemTest::testTutorialSetLicenseText() { @@ -234,8 +261,10 @@ tutorial.setLicenseText("The license text"); - QCOMPARE(item.childCount(), 1); - assertLicenseText(item.child(0), "The license text"); + QCOMPARE(item.childCount(), 3); + assertEmptyName(item.child(0)); + assertEmptyDescription(item.child(1)); + assertLicenseText(item.child(2), "The license text"); } void TutorialTreeItemTest::testTutorialSetLicenseTextChange() { @@ -244,15 +273,17 @@ tutorial.setLicenseText("The license text"); - QSignalSpy dataChangedSpy(item.child(0)->child(0), + QSignalSpy dataChangedSpy(item.child(2)->child(0), SIGNAL(dataChanged(TreeItem*))); tutorial.setLicenseText("The license text changed"); - QCOMPARE(item.childCount(), 1); - assertLicenseText(item.child(0), "The license text changed"); + QCOMPARE(item.childCount(), 3); + assertEmptyName(item.child(0)); + assertEmptyDescription(item.child(1)); + assertLicenseText(item.child(2), "The license text changed"); QCOMPARE(dataChangedSpy.count(), 1); - assertDataChanged(dataChangedSpy, 0, item.child(0)->child(0)); + assertDataChanged(dataChangedSpy, 0, item.child(2)->child(0)); } void TutorialTreeItemTest::testTutorialSetLicenseTextEmpty() { @@ -262,7 +293,9 @@ tutorial.setLicenseText("The license text"); tutorial.setLicenseText(""); - QCOMPARE(item.childCount(), 0); + QCOMPARE(item.childCount(), 2); + assertEmptyName(item.child(0)); + assertEmptyDescription(item.child(1)); } void TutorialTreeItemTest::testTutorialSetCustomSetupCode() { @@ -271,8 +304,10 @@ tutorial.setCustomSetupCode("The setup code"); - QCOMPARE(item.childCount(), 1); - assertCustomSetupCode(item.child(0), "The setup code"); + QCOMPARE(item.childCount(), 3); + assertEmptyName(item.child(0)); + assertEmptyDescription(item.child(1)); + assertCustomSetupCode(item.child(2), "The setup code"); } void TutorialTreeItemTest::testTutorialSetCustomSetupCodeChange() { @@ -281,15 +316,17 @@ tutorial.setCustomSetupCode("The setup code"); - QSignalSpy dataChangedSpy(item.child(0)->child(0), + QSignalSpy dataChangedSpy(item.child(2)->child(0), SIGNAL(dataChanged(TreeItem*))); tutorial.setCustomSetupCode("The setup code changed"); - QCOMPARE(item.childCount(), 1); - assertCustomSetupCode(item.child(0), "The setup code changed"); + QCOMPARE(item.childCount(), 3); + assertEmptyName(item.child(0)); + assertEmptyDescription(item.child(1)); + assertCustomSetupCode(item.child(2), "The setup code changed"); QCOMPARE(dataChangedSpy.count(), 1); - assertDataChanged(dataChangedSpy, 0, item.child(0)->child(0)); + assertDataChanged(dataChangedSpy, 0, item.child(2)->child(0)); } void TutorialTreeItemTest::testTutorialSetCustomSetupCodeEmpty() { @@ -299,7 +336,9 @@ tutorial.setCustomSetupCode("The setup code"); tutorial.setCustomSetupCode(""); - QCOMPARE(item.childCount(), 0); + QCOMPARE(item.childCount(), 2); + assertEmptyName(item.child(0)); + assertEmptyDescription(item.child(1)); } void TutorialTreeItemTest::testTutorialSetCustomTearDownCode() { @@ -308,8 +347,10 @@ tutorial.setCustomTearDownCode("The tear down code"); - QCOMPARE(item.childCount(), 1); - assertCustomTearDownCode(item.child(0), "The tear down code"); + QCOMPARE(item.childCount(), 3); + assertEmptyName(item.child(0)); + assertEmptyDescription(item.child(1)); + assertCustomTearDownCode(item.child(2), "The tear down code"); } void TutorialTreeItemTest::testTutorialSetCustomTearDownCodeChange() { @@ -318,15 +359,17 @@ tutorial.setCustomTearDownCode("The tear down code"); - QSignalSpy dataChangedSpy(item.child(0)->child(0), + QSignalSpy dataChangedSpy(item.child(2)->child(0), SIGNAL(dataChanged(TreeItem*))); tutorial.setCustomTearDownCode("The tear down code changed"); - QCOMPARE(item.childCount(), 1); - assertCustomTearDownCode(item.child(0), "The tear down code changed"); + QCOMPARE(item.childCount(), 3); + assertEmptyName(item.child(0)); + assertEmptyDescription(item.child(1)); + assertCustomTearDownCode(item.child(2), "The tear down code changed"); QCOMPARE(dataChangedSpy.count(), 1); - assertDataChanged(dataChangedSpy, 0, item.child(0)->child(0)); + assertDataChanged(dataChangedSpy, 0, item.child(2)->child(0)); } void TutorialTreeItemTest::testTutorialSetCustomTearDownCodeEmpty() { @@ -336,7 +379,9 @@ tutorial.setCustomTearDownCode("The tear down code"); tutorial.setCustomTearDownCode(""); - QCOMPARE(item.childCount(), 0); + QCOMPARE(item.childCount(), 2); + assertEmptyName(item.child(0)); + assertEmptyDescription(item.child(1)); } void TutorialTreeItemTest::testTutorialAddStep() { @@ -347,8 +392,10 @@ step->setId("Step id"); tutorial.addStep(step); - QCOMPARE(item.childCount(), 1); - assertStep(item.child(0), "Step id"); + QCOMPARE(item.childCount(), 3); + assertEmptyName(item.child(0)); + assertEmptyDescription(item.child(1)); + assertStep(item.child(2), "Step id"); } void TutorialTreeItemTest::testTutorialRemoveStep() { @@ -362,7 +409,9 @@ tutorial.addStep(&step); tutorial.removeStep(&step); - QCOMPARE(item.childCount(), 0); + QCOMPARE(item.childCount(), 2); + assertEmptyName(item.child(0)); + assertEmptyDescription(item.child(1)); } void TutorialTreeItemTest::testChildOrderWhenSettingDataInTutorial() { @@ -372,34 +421,39 @@ tutorial.setCustomSetupCode("The setup code"); QCOMPARE(item.text(), i18nc("@item", "Tutorial")); - QCOMPARE(item.childCount(), 1); - assertCustomSetupCode(item.child(0), "The setup code"); + QCOMPARE(item.childCount(), 3); + assertEmptyName(item.child(0)); + assertEmptyDescription(item.child(1)); + assertCustomSetupCode(item.child(2), "The setup code"); tutorial.setDescription("The description"); QCOMPARE(item.text(), i18nc("@item", "Tutorial")); - QCOMPARE(item.childCount(), 2); - assertDescription(item.child(0), "The description"); - assertCustomSetupCode(item.child(1), "The setup code"); + QCOMPARE(item.childCount(), 3); + assertEmptyName(item.child(0)); + assertDescription(item.child(1), "The description"); + assertCustomSetupCode(item.child(2), "The setup code"); tutorial.setCustomTearDownCode("The tear down code"); QCOMPARE(item.text(), i18nc("@item", "Tutorial")); - QCOMPARE(item.childCount(), 3); - assertDescription(item.child(0), "The description"); - assertCustomSetupCode(item.child(1), "The setup code"); - assertCustomTearDownCode(item.child(2), "The tear down code"); + QCOMPARE(item.childCount(), 4); + assertEmptyName(item.child(0)); + assertDescription(item.child(1), "The description"); + assertCustomSetupCode(item.child(2), "The setup code"); + assertCustomTearDownCode(item.child(3), "The tear down code"); Step* step1 = new Step(); step1->setId("First step"); tutorial.addStep(step1); QCOMPARE(item.text(), i18nc("@item", "Tutorial")); - QCOMPARE(item.childCount(), 4); - assertDescription(item.child(0), "The description"); - assertCustomSetupCode(item.child(1), "The setup code"); - assertCustomTearDownCode(item.child(2), "The tear down code"); - assertStep(item.child(3), "First step"); + QCOMPARE(item.childCount(), 5); + assertEmptyName(item.child(0)); + assertDescription(item.child(1), "The description"); + assertCustomSetupCode(item.child(2), "The setup code"); + assertCustomTearDownCode(item.child(3), "The tear down code"); + assertStep(item.child(4), "First step"); tutorial.setName("The name"); @@ -471,56 +525,75 @@ tutorial.setName(""); QCOMPARE(item.text(), i18nc("@item", "Tutorial")); - QCOMPARE(item.childCount(), 5); - assertDescription(item.child(0), "The description"); - assertCustomSetupCode(item.child(1), "The setup code"); - assertCustomTearDownCode(item.child(2), "The tear down code"); - assertStep(item.child(3), "First step"); - assertStep(item.child(4), "Second step"); + QCOMPARE(item.childCount(), 6); + assertEmptyName(item.child(0)); + assertDescription(item.child(1), "The description"); + assertCustomSetupCode(item.child(2), "The setup code"); + assertCustomTearDownCode(item.child(3), "The tear down code"); + assertStep(item.child(4), "First step"); + assertStep(item.child(5), "Second step"); tutorial.removeStep(&step1); QCOMPARE(item.text(), i18nc("@item", "Tutorial")); - QCOMPARE(item.childCount(), 4); - assertDescription(item.child(0), "The description"); - assertCustomSetupCode(item.child(1), "The setup code"); - assertCustomTearDownCode(item.child(2), "The tear down code"); - assertStep(item.child(3), "Second step"); + QCOMPARE(item.childCount(), 5); + assertEmptyName(item.child(0)); + assertDescription(item.child(1), "The description"); + assertCustomSetupCode(item.child(2), "The setup code"); + assertCustomTearDownCode(item.child(3), "The tear down code"); + assertStep(item.child(4), "Second step"); tutorial.setCustomTearDownCode(""); QCOMPARE(item.text(), i18nc("@item", "Tutorial")); - QCOMPARE(item.childCount(), 3); - assertDescription(item.child(0), "The description"); - assertCustomSetupCode(item.child(1), "The setup code"); - assertStep(item.child(2), "Second step"); + QCOMPARE(item.childCount(), 4); + assertEmptyName(item.child(0)); + assertDescription(item.child(1), "The description"); + assertCustomSetupCode(item.child(2), "The setup code"); + assertStep(item.child(3), "Second step"); tutorial.setDescription(""); QCOMPARE(item.text(), i18nc("@item", "Tutorial")); - QCOMPARE(item.childCount(), 2); - assertCustomSetupCode(item.child(0), "The setup code"); - assertStep(item.child(1), "Second step"); + QCOMPARE(item.childCount(), 4); + assertEmptyName(item.child(0)); + assertEmptyDescription(item.child(1)); + assertCustomSetupCode(item.child(2), "The setup code"); + assertStep(item.child(3), "Second step"); tutorial.setCustomSetupCode(""); QCOMPARE(item.text(), i18nc("@item", "Tutorial")); - QCOMPARE(item.childCount(), 1); - assertStep(item.child(0), "Second step"); + QCOMPARE(item.childCount(), 3); + assertEmptyName(item.child(0)); + assertEmptyDescription(item.child(1)); + assertStep(item.child(2), "Second step"); tutorial.removeStep(&step2); QCOMPARE(item.text(), i18nc("@item", "Tutorial")); - QCOMPARE(item.childCount(), 0); + QCOMPARE(item.childCount(), 2); + assertEmptyName(item.child(0)); + assertEmptyDescription(item.child(1)); } /////////////////////////////////// Helpers //////////////////////////////////// +void TutorialTreeItemTest::assertEmptyName(TreeItem* nameItem) const { + QCOMPARE(nameItem->text(), i18nc("@item", "Name: (name not set)")); +} + void TutorialTreeItemTest::assertName(TreeItem* nameItem, const QString& name) const { QCOMPARE(nameItem->text(), i18nc("@item", "Name: %1", name)); } +void TutorialTreeItemTest::assertEmptyDescription( + TreeItem* descriptionItem) const { + QCOMPARE(descriptionItem->text(), + i18nc("@item", "Description: (description not set)")); +} + void TutorialTreeItemTest::assertDescription(TreeItem* descriptionItem, const QString& description) const { QCOMPARE(descriptionItem->text(), This was sent by the SourceForge.net collaborative development platform, the world's largest Open Source development site. |
From: <dan...@us...> - 2010-03-22 23:02:34
|
Revision: 180 http://ktutorial.svn.sourceforge.net/ktutorial/?rev=180&view=rev Author: danxuliu Date: 2010-03-22 23:02:27 +0000 (Mon, 22 Mar 2010) Log Message: ----------- Rename "Set reaction data" action to "Set data" to keep consistency with other action names Modified Paths: -------------- trunk/ktutorial/ktutorial-editor/po/es.po trunk/ktutorial/ktutorial-editor/po/ktutorial-editor.pot trunk/ktutorial/ktutorial-editor/src/KTutorialEditor.cpp Modified: trunk/ktutorial/ktutorial-editor/po/es.po =================================================================== --- trunk/ktutorial/ktutorial-editor/po/es.po 2010-03-22 19:24:36 UTC (rev 179) +++ trunk/ktutorial/ktutorial-editor/po/es.po 2010-03-22 23:02:27 UTC (rev 180) @@ -7,9 +7,9 @@ msgid "" msgstr "" "Project-Id-Version: ktutorial-editor\n" -"Report-Msgid-Bugs-To: http://sourceforge." -"net/tracker/?group_id=301227&atid=1270278\n" -"POT-Creation-Date: 2010-03-22 20:21+0100\n" +"Report-Msgid-Bugs-To: http://sourceforge.net/tracker/?" +"group_id=301227&atid=1270278\n" +"POT-Creation-Date: 2010-03-22 23:59+0100\n" "PO-Revision-Date: 2010-03-22 20:22-0400\n" "Last-Translator: Daniel Calviño Sánchez <dan...@gm...>\n" "Language-Team: Spanish <>\n" @@ -96,7 +96,7 @@ msgid "Add a new step to the tutorial." msgstr "Añadir un nuevo paso al tutorial." -#: KTutorialEditor.cpp:165 +#: KTutorialEditor.cpp:165 KTutorialEditor.cpp:219 msgctxt "@action" msgid "Set data..." msgstr "Establecer datos..." @@ -144,11 +144,6 @@ msgid "Add a new reaction to the selected step." msgstr "Añadir una nueva reacción al paso seleccionado actualmente." -#: KTutorialEditor.cpp:219 -msgctxt "@action" -msgid "Set reaction data..." -msgstr "Establecer datos de la reacción..." - #: KTutorialEditor.cpp:220 msgctxt "@info:status" msgid "Set the trigger and the response of the currently selected reaction." @@ -886,6 +881,10 @@ msgid "Your emails" msgstr "dan...@gm..." +#~ msgctxt "@action" +#~ msgid "Set reaction data..." +#~ msgstr "Establecer datos de la reacción..." + #~ msgctxt "@item Noun, a step in a tutorial" #~ msgid "Step" #~ msgstr "Paso" Modified: trunk/ktutorial/ktutorial-editor/po/ktutorial-editor.pot =================================================================== --- trunk/ktutorial/ktutorial-editor/po/ktutorial-editor.pot 2010-03-22 19:24:36 UTC (rev 179) +++ trunk/ktutorial/ktutorial-editor/po/ktutorial-editor.pot 2010-03-22 23:02:27 UTC (rev 180) @@ -9,7 +9,7 @@ "Project-Id-Version: PACKAGE VERSION\n" "Report-Msgid-Bugs-To: http://sourceforge.net/tracker/?" "group_id=301227&atid=1270278\n" -"POT-Creation-Date: 2010-03-22 20:21+0100\n" +"POT-Creation-Date: 2010-03-22 23:59+0100\n" "PO-Revision-Date: YEAR-MO-DA HO:MI+ZONE\n" "Last-Translator: FULL NAME <EMAIL@ADDRESS>\n" "Language-Team: LANGUAGE <LL...@li...>\n" @@ -92,7 +92,7 @@ msgid "Add a new step to the tutorial." msgstr "" -#: KTutorialEditor.cpp:165 +#: KTutorialEditor.cpp:165 KTutorialEditor.cpp:219 msgctxt "@action" msgid "Set data..." msgstr "" @@ -136,11 +136,6 @@ msgid "Add a new reaction to the selected step." msgstr "" -#: KTutorialEditor.cpp:219 -msgctxt "@action" -msgid "Set reaction data..." -msgstr "" - #: KTutorialEditor.cpp:220 msgctxt "@info:status" msgid "Set the trigger and the response of the currently selected reaction." Modified: trunk/ktutorial/ktutorial-editor/src/KTutorialEditor.cpp =================================================================== --- trunk/ktutorial/ktutorial-editor/src/KTutorialEditor.cpp 2010-03-22 19:24:36 UTC (rev 179) +++ trunk/ktutorial/ktutorial-editor/src/KTutorialEditor.cpp 2010-03-22 23:02:27 UTC (rev 180) @@ -216,7 +216,7 @@ actionListWidget->addAction(action); action = new KAction(this); - action->setText(i18nc("@action", "Set reaction data...")); + action->setText(i18nc("@action", "Set data...")); action->setStatusTip(i18nc("@info:status", "Set the trigger and the " "response of the currently selected reaction.")); action->setIcon(KIcon("document-edit")); This was sent by the SourceForge.net collaborative development platform, the world's largest Open Source development site. |
From: <dan...@us...> - 2010-03-23 22:22:11
|
Revision: 186 http://ktutorial.svn.sourceforge.net/ktutorial/?rev=186&view=rev Author: danxuliu Date: 2010-03-23 22:22:03 +0000 (Tue, 23 Mar 2010) Log Message: ----------- Add KTutorial editor English handbook Modified Paths: -------------- trunk/ktutorial/ktutorial-editor/CMakeLists.txt Added Paths: ----------- trunk/ktutorial/ktutorial-editor/doc/ trunk/ktutorial/ktutorial-editor/doc/CMakeLists.txt trunk/ktutorial/ktutorial-editor/doc/en/ trunk/ktutorial/ktutorial-editor/doc/en/CMakeLists.txt trunk/ktutorial/ktutorial-editor/doc/en/commands.docbook trunk/ktutorial/ktutorial-editor/doc/en/index.docbook trunk/ktutorial/ktutorial-editor/doc/en/installation.docbook trunk/ktutorial/ktutorial-editor/doc/en/main-window.png trunk/ktutorial/ktutorial-editor/doc/en/new-condition.png trunk/ktutorial/ktutorial-editor/doc/en/set-reaction-data.png trunk/ktutorial/ktutorial-editor/doc/en/set-step-data.png trunk/ktutorial/ktutorial-editor/doc/en/set-tutorial-information.png trunk/ktutorial/ktutorial-editor/doc/en/using.docbook Modified: trunk/ktutorial/ktutorial-editor/CMakeLists.txt =================================================================== --- trunk/ktutorial/ktutorial-editor/CMakeLists.txt 2010-03-23 08:02:59 UTC (rev 185) +++ trunk/ktutorial/ktutorial-editor/CMakeLists.txt 2010-03-23 22:22:03 UTC (rev 186) @@ -4,6 +4,7 @@ include(KDE4Defaults) +add_subdirectory(doc) add_subdirectory(po) add_subdirectory(src) add_subdirectory(tests) Added: trunk/ktutorial/ktutorial-editor/doc/CMakeLists.txt =================================================================== --- trunk/ktutorial/ktutorial-editor/doc/CMakeLists.txt (rev 0) +++ trunk/ktutorial/ktutorial-editor/doc/CMakeLists.txt 2010-03-23 22:22:03 UTC (rev 186) @@ -0,0 +1 @@ +add_subdirectory(en) Property changes on: trunk/ktutorial/ktutorial-editor/doc/CMakeLists.txt ___________________________________________________________________ Added: svn:eol-style + native Added: trunk/ktutorial/ktutorial-editor/doc/en/CMakeLists.txt =================================================================== --- trunk/ktutorial/ktutorial-editor/doc/en/CMakeLists.txt (rev 0) +++ trunk/ktutorial/ktutorial-editor/doc/en/CMakeLists.txt 2010-03-23 22:22:03 UTC (rev 186) @@ -0,0 +1,3 @@ +########### install files ################ + +kde4_create_handbook(index.docbook INSTALL_DESTINATION ${HTML_INSTALL_DIR}/en SUBDIR ktutorial-editor) Property changes on: trunk/ktutorial/ktutorial-editor/doc/en/CMakeLists.txt ___________________________________________________________________ Added: svn:eol-style + native Added: trunk/ktutorial/ktutorial-editor/doc/en/commands.docbook =================================================================== --- trunk/ktutorial/ktutorial-editor/doc/en/commands.docbook (rev 0) +++ trunk/ktutorial/ktutorial-editor/doc/en/commands.docbook 2010-03-23 22:22:03 UTC (rev 186) @@ -0,0 +1,356 @@ +<!--<?xml version="1.0" ?> +<!DOCTYPE book PUBLIC "-//KDE//DTD DocBook XML V4.2-Based Variant V1.1//EN" "dtd/kdex.dtd"> --> +<!-- Uncomment the previous two lines to validate this document --> +<!-- standalone. Be sure to recomment them before attempting to --> +<!-- process index.docbook --> + +<chapter id="commands"> + <title>Command Reference</title> + + <sect1 id="commands-mainwindow"> + <title>The main &ktutorial-editor; window</title> + + <sect2> + <title>The <guimenu>File</guimenu> Menu</title> + <para> + <variablelist> + <varlistentry> + <term> + <menuchoice> + <guimenu>File</guimenu> + <guimenuitem>Export...</guimenuitem> + </menuchoice> + </term> + <listitem> + <para> + <action>Exports the tutorial to a script.</action> + </para> + </listitem> + </varlistentry> + <varlistentry> + <term> + <menuchoice> + <shortcut> + <keycombo action="simul">&Ctrl;<keycap>Q</keycap></keycombo> + </shortcut> + <guimenu>File</guimenu> + <guimenuitem>Quit</guimenuitem> + </menuchoice> + </term> + <listitem> + <para> + <action>Quits &ktutorial-editor;.</action> + </para> + </listitem> + </varlistentry> + </variablelist> + </para> + </sect2> + + <sect2> + <title>The <guimenu>Edit</guimenu> Menu</title> + <para> + <variablelist> + <varlistentry> + <term> + <menuchoice> + <guimenu>Edit</guimenu> + <guimenu>Tutorial</guimenu> + <guimenuitem>Set information...</guimenuitem> + </menuchoice> + </term> + <listitem> + <para> + <action>Opens the dialog to set the name and description of the tutorial.</action> + </para> + </listitem> + </varlistentry> + <varlistentry> + <term> + <menuchoice> + <guimenu>Edit</guimenu> + <guimenu>Tutorial</guimenu> + <guimenuitem>Set license...</guimenuitem> + </menuchoice> + </term> + <listitem> + <para> + <action>Opens the dialog to set the license text of the tutorial.</action> + </para> + </listitem> + </varlistentry> + <varlistentry> + <term> + <menuchoice> + <guimenu>Edit</guimenu> + <guimenu>Tutorial</guimenu> + <guimenuitem>Set setup code...</guimenuitem> + </menuchoice> + </term> + <listitem> + <para> + <action>Opens the dialog to set the custom code to be executed when the tutorial starts.</action> + </para> + </listitem> + </varlistentry> + <varlistentry> + <term> + <menuchoice> + <guimenu>Edit</guimenu> + <guimenu>Tutorial</guimenu> + <guimenuitem>Set tear down code...</guimenuitem> + </menuchoice> + </term> + <listitem> + <para> + <action>Opens the dialog to set the custom code to be executed when the tutorial finishes.</action> + </para> + </listitem> + </varlistentry> + <varlistentry> + <term> + <menuchoice> + <guimenu>Edit</guimenu> + <guimenu>Step</guimenu> + <guimenuitem>Add step...</guimenuitem> + </menuchoice> + </term> + <listitem> + <para> + <action>Opens the dialog to add a new step to the tutorial</action> + </para> + </listitem> + </varlistentry> + <varlistentry> + <term> + <menuchoice> + <guimenu>Edit</guimenu> + <guimenu>Step</guimenu> + <guimenuitem>Set data...</guimenuitem> + </menuchoice> + </term> + <listitem> + <para> + <action>Opens the dialog to set the name and text of the currently selected step.</action> + </para> + </listitem> + </varlistentry> + <varlistentry> + <term> + <menuchoice> + <guimenu>Edit</guimenu> + <guimenu>Step</guimenu> + <guimenuitem>Set setup code...</guimenuitem> + </menuchoice> + </term> + <listitem> + <para> + <action>Opens the dialog to set the custom code to be executed when the tutorial passes to the currently selected step.</action> + </para> + </listitem> + </varlistentry> + <varlistentry> + <term> + <menuchoice> + <guimenu>Edit</guimenu> + <guimenu>Step</guimenu> + <guimenuitem>Set tear down code...</guimenuitem> + </menuchoice> + </term> + <listitem> + <para> + <action>Opens the dialog to set the custom code to be executed when the tutorial changes from the currently selected step to another step.</action> + </para> + </listitem> + </varlistentry> + <varlistentry> + <term> + <menuchoice> + <guimenu>Edit</guimenu> + <guimenu>Step</guimenu> + <guimenuitem>Remove step</guimenuitem> + </menuchoice> + </term> + <listitem> + <para> + <action>Removes the currently selected step from the tutorial.</action> + </para> + </listitem> + </varlistentry> + <varlistentry> + <term> + <menuchoice> + <guimenu>Edit</guimenu> + <guimenu>Reaction</guimenu> + <guimenuitem>Add reaction...</guimenuitem> + </menuchoice> + </term> + <listitem> + <para> + <action>Opens the dialog to add a new reaction to the selected step.</action> + </para> + </listitem> + </varlistentry> + <varlistentry> + <term> + <menuchoice> + <guimenu>Edit</guimenu> + <guimenu>Reaction</guimenu> + <guimenuitem>Set data...</guimenuitem> + </menuchoice> + </term> + <listitem> + <para> + <action>Opens the dialog to set the trigger and response of the currently selected reaction.</action> + </para> + </listitem> + </varlistentry> + <varlistentry> + <term> + <menuchoice> + <guimenu>Edit</guimenu> + <guimenu>Reaction</guimenu> + <guimenuitem>Remove reaction</guimenuitem> + </menuchoice> + </term> + <listitem> + <para> + <action>Removes the currently selected reaction from its step.</action> + </para> + </listitem> + </varlistentry> + </variablelist> + </para> + </sect2> + + <sect2> + <title>The <guimenu>View</guimenu> Menu</title> + <para> + <variablelist> + <varlistentry> + <term> + <menuchoice> + <guimenu>View</guimenu> + <guimenuitem>Panels</guimenuitem> + <guimenuitem>Edit tutorial</guimenuitem> + </menuchoice> + </term> + <listitem> + <para> + <action>Shows or hides the panel with the shorcuts to tutorial edition actions.</action> + </para> + </listitem> + </varlistentry> + <varlistentry> + <term> + <menuchoice> + <guimenu>View</guimenu> + <guimenuitem>Panels</guimenuitem> + <guimenuitem>Edit step</guimenuitem> + </menuchoice> + </term> + <listitem> + <para> + <action>Shows or hides the panel with the shorcuts to step edition actions.</action> + </para> + </listitem> + </varlistentry> + <varlistentry> + <term> + <menuchoice> + <guimenu>View</guimenu> + <guimenuitem>Panels</guimenuitem> + <guimenuitem>Edit reaction</guimenuitem> + </menuchoice> + </term> + <listitem> + <para> + <action>Shows or hides the panel with the shorcuts to reaction edition actions.</action> + </para> + </listitem> + </varlistentry> + </variablelist> + </para> + </sect2> + + <sect2> + <title>The <guimenu>Settings</guimenu> Menu</title> + <para> + <variablelist> + <varlistentry> + <term> + <menuchoice> + <guimenu>Settings</guimenu> + <guimenuitem>Show Toolbar</guimenuitem> + </menuchoice> + </term> + <listitem> + <para> + <action>Shows or hides the main toolbar.</action> + </para> + </listitem> + </varlistentry> + <varlistentry> + <term> + <menuchoice> + <guimenu>Settings</guimenu> + <guimenuitem>Show Statusbar</guimenuitem> + </menuchoice> + </term> + <listitem> + <para> + <action>Shows or hides the statusbar.</action> + </para> + </listitem> + </varlistentry> + <varlistentry> + <term> + <menuchoice> + <guimenu>Settings</guimenu> + <guimenuitem>Configure Shortcuts...</guimenuitem> + </menuchoice> + </term> + <listitem> + <para> + <action>Opens a configure dialog for binding keys to actions.</action> + </para> + </listitem> + </varlistentry> + <varlistentry> + <term> + <menuchoice> + <guimenu>Settings</guimenu> + <guimenuitem>Configure Toolbars...</guimenuitem> + </menuchoice> + </term> + <listitem> + <para> + <action>Opens a configure dialog for selecting the actions to show in the toolbar.</action> + </para> + </listitem> + </varlistentry> + </variablelist> + </para> + </sect2> + + <sect2> + <title>The <guimenu>Help</guimenu> Menu</title> + + &help.menu.documentation; + + </sect2> + </sect1> +</chapter> + +<!-- +Local Variables: +mode: xml +sgml-minimize-attributes:nil +sgml-general-insert-case:lower +sgml-indent-step:0 +sgml-indent-data:nil +End: + +vim:tabstop=4:shiftwidth=4:expandtab +kate: space-indent on; indent-width 4; tab-width 4; indent-mode none; +--> Added: trunk/ktutorial/ktutorial-editor/doc/en/index.docbook =================================================================== --- trunk/ktutorial/ktutorial-editor/doc/en/index.docbook (rev 0) +++ trunk/ktutorial/ktutorial-editor/doc/en/index.docbook 2010-03-23 22:22:03 UTC (rev 186) @@ -0,0 +1,125 @@ +<?xml version="1.0" ?> +<!DOCTYPE book PUBLIC "-//KDE//DTD DocBook XML V4.2-Based Variant V1.1//EN" "dtd/kdex.dtd" [ + <!ENTITY ktutorial-editor "<application>KTutorial editor</application>"> + <!ENTITY kappname "&ktutorial-editor;"> + <!ENTITY package "kde-module"> + <!ENTITY % addindex "IGNORE"> + <!ENTITY % English "INCLUDE"> + + <!ENTITY using SYSTEM "using.docbook"> + <!ENTITY commands SYSTEM "commands.docbook"> + <!ENTITY installation SYSTEM "installation.docbook"> +]> + +<!-- ................................................................ --> + +<book lang="&language;"> + +<!-- This header contains all of the meta-information for the document such +as Authors, publish date, the abstract, and Keywords --> + +<bookinfo> + <title>The &ktutorial-editor; Handbook</title> + + <authorgroup> + <author> + <personname> + <firstname>Daniel</firstname> + <surname>Calviño Sánchez</surname> + </personname> + <email>dan...@gm...</email> + </author> + </authorgroup> + + <!-- TRANS:ROLES_OF_TRANSLATORS --> + + <copyright> + <year>2010</year> + <holder>Daniel Calviño Sánchez</holder> + </copyright> + <!-- Translators: put here the copyright notice of the translation --> + <!-- Put here the FDL notice. Read the explanation in fdl-notice.docbook + and in the FDL itself on how to use it. --> + <legalnotice>&FDLNotice;</legalnotice> + + <!-- Date and version information of the documentation + Don't forget to include this last date and this last revision number, we + need them for translation coordination ! + Please respect the format of the date (YYYY-MM-DD) and of the version + (V.MM.LL), it could be used by automation scripts. + Do NOT change these in the translation. --> + + <date>2010-03-23</date> + <releaseinfo>0.1</releaseinfo> + + <!-- Abstract about this handbook --> + + <abstract> + <para>&ktutorial-editor; is a graphical editor for KTutorial tutorials.</para> + </abstract> + + <keywordset> + <keyword>KDE</keyword> + <keyword>KTutorial editor</keyword> + <keyword>KTutorial</keyword> + <keyword>tutorial</keyword> + <keyword>editor</keyword> + </keywordset> + +</bookinfo> + +<chapter id="introduction"> + <title>Introduction</title> + + <para>&ktutorial-editor; is a graphical editor for KTutorial tutorials.</para> + <para>KTutorial is a interactive tutorial system for KDE 4. You can get more information about KTutorial in its webpage: <ulink url="http://ktutorial.sourceforge.net">http://ktutorial.sourceforge.net</ulink>.</para> + <para>Using &ktutorial-editor; you can design a tutorial for some application specifying the steps that it will be composed of. For each step, you can specify how the tutorial will react, for example, when the user selects an option, closes a dialog, writes some text...</para> + <para>Once the tutorial has been designed, it can be exported by &ktutorial-editor; to a scripted tutorial. Once the scripted tutorial is placed in the appropriate directory, it can be read by KTutorial library and started by the user of the application. </para> + <para>Tutorials created by &ktutorial-editor; are not as powerful as fully hand made tutorials. However, they are way easier to create and the generated source code can be used as a skeleton to be manually completed if the tutorial requires something not supported by &ktutorial-editor;.</para> +</chapter> + +&using; +&commands; + +<chapter id="credits"> + + <!-- Include credits for the programmers, documentation writers, and + contributors here. --> + + <title>Credits and License</title> + + <para> + &ktutorial-editor; + </para> + <para> + Program Copyright 2010 Daniel Calviño Sánchez <email>dan...@gm...</email> + </para> + + <para> + Documentation Copyright 2010 Daniel Calviño Sánchez <email>dan...@gm...</email> + </para> + + <!-- TRANS:CREDIT_FOR_TRANSLATORS --> + + &underFDL; + &underGPL; + +</chapter> + +&installation; + +&documentation.index; +</book> + +<!-- +Local Variables: +mode: xml +sgml-minimize-attributes:nil +sgml-general-insert-case:lower +sgml-indent-step:0 +sgml-indent-data:nil +End: + +vim:tabstop=4:shiftwidth=4:expandtab +kate: space-indent on; indent-width 4; tab-width 4; indent-mode none; +--> Added: trunk/ktutorial/ktutorial-editor/doc/en/installation.docbook =================================================================== --- trunk/ktutorial/ktutorial-editor/doc/en/installation.docbook (rev 0) +++ trunk/ktutorial/ktutorial-editor/doc/en/installation.docbook 2010-03-23 22:22:03 UTC (rev 186) @@ -0,0 +1,97 @@ +<!--<?xml version="1.0" ?> +<!DOCTYPE book PUBLIC "-//KDE//DTD DocBook XML V4.2-Based Variant V1.1//EN" "dtd/kdex.dtd"> --> +<!-- Uncomment the previous two lines to validate this document --> +<!-- standalone. Be sure to recomment them before attempting to --> +<!-- process index.docbook --> + +<appendix id="installation"> + <title>Installation</title> + + <sect1 id="getting-klusi"> + <title>How to obtain &ktutorial-editor;</title> + + <para>&ktutorial-editor; is part of KTutorial package, which is hosted at <ulink url="http://sourceforge.net/">SourceForge.net</ulink>.</para> + + <para>KTutorial can be downloaded from the <ulink url="http://sourceforge.net/projects/ktutorial/files/">files section</ulink> of the <ulink url="http://sourceforge.net/projects/ktutorial/">KTutorial project in SourceForge.net</ulink>.</para> + + <para>You are encouraged to visit, however, the <ulink url="http://ktutorial.sourceforge.net/download.html">download section</ulink> of the <ulink url="http://ktutorial.sourceforge.net/">webpage</ulink>, as a lot more information can be found there apart of only the files.</para> + + <para>If you are brave enough, in the download section you will also find instructions to install KTutorial from <acronym>SVN</acronym>. However, this is only recommended for developers.</para> + </sect1> + + <sect1 id="requirements"> + <title>Requirements</title> + + <para>In order to successfully build and use KTutorial, you need &kde; (at least version 4.3) and, therefore, &Qt; (at least version 4.5.3).</para> + + <para>Also, <application>CMake</application> build system is required to build KTutorial, as required to build any other &kde; application.</para> + </sect1> + + <sect1 id="compilation"> + <title>Compilation and Installation</title> + + <para>In order to compile KTutorial on your system, extract the KTutorial package you downloaded and type the following in the base directory of the extracted package:</para> + + <screen> + <prompt>$</prompt> <userinput><command>mkdir</command> build && <command>cd</command> build</userinput> + <prompt>$</prompt> <userinput><command>cmake</command> ..</userinput> + <prompt>$</prompt> <userinput><command>make</command></userinput> + </screen> + + <para>That will create a <filename>build</filename> directory, change to it, prepare the build directory to build KTutorial on it and finally build KTutorial. If <command>cmake</command> complains, you have to install the required dependencies asked in the error message.</para> + + <para>To install KTutorial, become root user and run:</para> + + <screen> + <prompt>#</prompt> <userinput><command>make</command> install</userinput> + </screen> + + <tip> + <title>Installing &ktutorial-editor; in <filename class="directory">/usr/local/</filename></title> + + <para>In order to keep a proper organization of your system and not mess up the packages installed by your distribution package manager and those installed manually by you, you are encouraged to install KTutorial in <filename class="directory">/usr/local/</filename>.</para> + + <para>This is the directory that should be used for manually installed packages. To do this, instead of executing <command>cmake</command> as stated before, execute this:</para> + + <screen> + <prompt>$</prompt> <userinput><command>cmake</command> <parameter class="command">-DCMAKE_INSTALL_PREFIX=<filename class="directory">/usr/local/</filename></parameter></userinput> + </screen> + </tip> + </sect1> + + <sect1 id="configuration"> + <title>Configuration</title> + + <para>Depending on your distribution and where KTutorial was installed (if you installed it from sourcecode), you may need a last step before being able to make KTutorial run properly.</para> + + <para>To check this, launch &ktutorial-editor; and take a look to the help. If &ktutorial-editor; manual cannot be found, go on reading to know what must be configured. If the manual is shown, congratulations, just enjoy! :)</para> + + <para>If the manual wasn't found, you must configure your &kde; prefixes. To do this, create the file <filename>/etc/kderc</filename> and add the following content:</para> + +<programlisting> +[Directories] +prefixes=/the/prefix/where/ktutorial/was/installed/ +</programlisting> + + <para>If <filename>/etc/kderc</filename> already existed and had a prefixes rule, add the prefix of KTutorial separating it from the previous prefixes with a "," like this:</para> + +<programlisting> +[Directories] +prefixes=/previous/prefixes/,/the/prefix/where/ktutorial/was/installed/ +</programlisting> + </sect1> +</appendix> + +<!-- +Local Variables: +mode: xml +sgml-minimize-attributes:nil +sgml-general-insert-case:lower +sgml-indent-step:0 +sgml-indent-data:nil +End: + +vim:tabstop=4:shiftwidth=4:expandtab +kate: space-indent on; indent-width 4; tab-width 4; indent-mode none; +--> + Added: trunk/ktutorial/ktutorial-editor/doc/en/main-window.png =================================================================== (Binary files differ) Property changes on: trunk/ktutorial/ktutorial-editor/doc/en/main-window.png ___________________________________________________________________ Added: svn:mime-type + image/png Added: trunk/ktutorial/ktutorial-editor/doc/en/new-condition.png =================================================================== (Binary files differ) Property changes on: trunk/ktutorial/ktutorial-editor/doc/en/new-condition.png ___________________________________________________________________ Added: svn:mime-type + image/png Added: trunk/ktutorial/ktutorial-editor/doc/en/set-reaction-data.png =================================================================== (Binary files differ) Property changes on: trunk/ktutorial/ktutorial-editor/doc/en/set-reaction-data.png ___________________________________________________________________ Added: svn:mime-type + image/png Added: trunk/ktutorial/ktutorial-editor/doc/en/set-step-data.png =================================================================== (Binary files differ) Property changes on: trunk/ktutorial/ktutorial-editor/doc/en/set-step-data.png ___________________________________________________________________ Added: svn:mime-type + image/png Added: trunk/ktutorial/ktutorial-editor/doc/en/set-tutorial-information.png =================================================================== (Binary files differ) Property changes on: trunk/ktutorial/ktutorial-editor/doc/en/set-tutorial-information.png ___________________________________________________________________ Added: svn:mime-type + image/png Added: trunk/ktutorial/ktutorial-editor/doc/en/using.docbook =================================================================== --- trunk/ktutorial/ktutorial-editor/doc/en/using.docbook (rev 0) +++ trunk/ktutorial/ktutorial-editor/doc/en/using.docbook 2010-03-23 22:22:03 UTC (rev 186) @@ -0,0 +1,279 @@ +<!--<?xml version="1.0" ?> +<!DOCTYPE book PUBLIC "-//KDE//DTD DocBook XML V4.2-Based Variant V1.1//EN" "dtd/kdex.dtd"> --> +<!-- Uncomment the previous two lines to validate this document --> +<!-- standalone. Be sure to recomment them before attempting to --> +<!-- process index.docbook --> + +<chapter id="using"> + <title>Using &ktutorial-editor;</title> + + <para>In this chapter you should find all the information you need to use &ktutorial-editor;. However, some general information about KTutorial is also given here, as it is needed to fully understand the purpose of &ktutorial-editor;.</para> + + <tip> + <title>Getting extended information</title> + + <para>You can also get extended information about a lot of widgets throughout &ktutorial-editor; using the <emphasis>What's This?</emphasis> help. <emphasis>What's This?</emphasis> help can be shown with the keyboard shortcut <keycombo action="simul">&Shift;<keycap>F1</keycap></keycombo>, selecting <guimenuitem>What's This?</guimenuitem> from the <guimenu>Help</guimenu> menu or, with some window decorations, clicking on the What's This? button in the window's titlebar (usually a question mark), and then clicking on the widget to get its extended help.</para> + </tip> + + <sect1 id="understanding-ktutorial"> + <title>Understanding KTutorial</title> + + <para>&ktutorial-editor; is just a graphical editor to create tutorials to be used by KTutorial. That is why you should at least have some little notions of how KTutorial works to fully understand the purpose of &ktutorial-editor;.</para> + + <para>A tutorial is a little guide to help the user to learn how to use an application. For example, it shows the user how some feature works, or how to accomplish some task. A tutorial is composed of several steps, each one containing a bit of information.</para> + + <para>The most interesting feature is that, with KTutorial, applications can explain to the user how to do something in an interactive way. Each step contains one or more reactions. A reaction is composed by a trigger and a response: when the reaction is triggered, the response is executed.</para> + + <para>There are two types of triggers: options and conditions to wait for. Options are shown to the user as buttons below the text of the step, and the response is executed when the user selects the option. Conditions to wait for are not show in any way to the user, and the response is executed when the condition is met. For example, when an object receives an event, or when an object emits a signal.</para> + + <para>There are also two types of responses: changing to another step, or executing some custom code.</para> + + <para>Finally, KTutorial provides a system to execute some actions when a tutorial starts or finishes, or when the tutorial enters or exists from a step.</para> + + <para>All this abstract concepts are fine but, how do you tell KTutorial all those things? KTutorial is a software package, how does it know that it has to wait for something to happen, or show the user some text, or whatever? KTutorial tutorials are specified as source code, be it C++ or a script language.</para> + + <para>C++ tutorials must be embedded in the application source code itself, and they have to be compiled with it when the application is compiled.</para> + + <para>On the other hand, scripted tutorials are external data to the application. When an application that supports KTutorial starts, it looks for scripted tutorials in some specific directories and loads those found. If you add new scripted tutorials to the directories, the next time the application starts they will be available. You don't have to compile again the application, not even to reinstall it.</para> + + <para>Scripted tutorials are looked for in the <filename>tutorials/</filename> subdirectory of the application data directory. The application data directory is <filename>KDE_PREFIX/share/apps/applicationName/</filename>. Special cases aside, the <emphasis>KDE_PREFIX</emphasis> can be the KDE installation prefix (usually <filename>/usr/</filename>) or the user KDE4 configuration directory (<filename>/home/userName/.kde4/</filename>).</para> + + <para>When the scripted tutorial is part of an application (it is installed with the rest of the application data when the application is installed), the strings in the scripted tutorial can be extracted to be localized before the installation like any other string in the C++ code, as explained in KTutorial documentation. Scripted tutorials that are added after the application was installed, however, can not be localized, as KTutorial uses the same translation file as the rest of the application where it is used.</para> + + <para>As you may have guessed already, KTutorial editor creates scripted tutorials. Right now, only Javascript is supported, as KDE libraries offer out of the box support for Javascript scripts. Python or Ruby, on the other hand, require some specific packages to be installed in the system.</para> + </sect1> + + <sect1 id="main-window"> + <title>Main Window</title> + + <para>&ktutorial-editor; main window shows the tutorial being worked on, and provides actions to modify it.</para> + + <para>A tutorial can be seen as a hierarchical structure: a tutorial contains several steps, each step may contain several reactions, and each reaction may contain a composed condition. Also, tutorial, step and reactions contain other properties, like the name in a tutorial or the response code in a reaction, that can be seen as children of their element. With all this, a tutorial is shown as a tree in the main window.</para> + + <para>The tree only shows properties already set. For example, if there is no custom setup code for a step, no item is shown, not even to say that there is no setup code. The exception to this behavior happens when a property is mandatory, for example, the id of a step. In that case, if the property is not set, an item with a warning is shown.</para> + + <para>The actions to modify the tutorial and its elements can be always accessed from the <guimenu>Edit</guimenu> menu. Most actions will open a edition dialog to edit the desired element, which means that, in some cases, you have to select an element before being able to use an action. For example, to use <action>Set reaction data</action>, you first have to select the reaction to edit in the tutorial. Otherwise, the action will be disabled and it could not be executed (which is logical, as it will not know which reaction to edit).</para> + + <para>As well as being shown in the <guimenu>Edit</guimenu> menu, the actions to edit a tutorial, a step and a reaction are shown in three panels provided for convenience. The panels can be shown or hidden from <guimenu>View</guimenu> menu, and can be docked to the top, bottom, right or left side of the main window. If desired, they can also be dragged out of the window to make them floating panels.</para> + + <screenshot> + <screeninfo>The main window of &ktutorial-editor; with a tutorial being worked on</screeninfo> + <mediaobject> + <imageobject> + <imagedata fileref="main-window.png" format="PNG"/> + </imageobject> + <textobject> + <phrase>&ktutorial-editor; Main Window</phrase> + </textobject> + </mediaobject> + </screenshot> + </sect1> + + <sect1 id="edition-dialogs"> + <title>Edition dialogs</title> + + <para>There are several edition dialogs, each one to set some property or properties of an element.</para> + + <sect2 id="edition-dialogs-tutorial"> + <title>Tutorial edition</title> + + <para>The tutorial information dialog is used to set the name and description of a tutorial. The name and description are mandatory properties, as through the name the user can identify a tutorial and with the description he can know the purpose of the tutorial.</para> + + <screenshot> + <screeninfo>The dialog to set the name and description of a tutorial</screeninfo> + <mediaobject> + <imageobject> + <imagedata fileref="set-tutorial-information.png" format="PNG"/> + </imageobject> + <textobject> + <phrase>Tutorial information edition dialog</phrase> + </textobject> + </mediaobject> + </screenshot> + + <para>The license text dialog is used to set a license for the tutorial, for example, if the exported scripted tutorial is going to be distributed with its application. When the tutorial is exported, the license text is automatically wrapped in comments appropriate for the script language. For example, the following license text: +<programlisting>The license text, which should be +wrapped +</programlisting> is exported to Javascript as: +<programlisting>/***************************************** + * The license text, which should be * + * wrapped * + *****************************************/ +</programlisting> + </para> + + <para>The setup and tear down code dialogs just provide a text editor to write the custom code to be executed when the tutorial starts or finishes. Note that you have to provide just the body of the function, as the signature is automatically written when exported. For example, the following setup code: +<programlisting>alert("Hello world!");</programlisting> is exported to Javascript as: +<programlisting>function tutorialSetup(tutorial) { + alert("Hello world!"); +} +</programlisting> + </para> + </sect2> + + <sect2 id="edition-dialogs-step"> + <title>Step edition</title> + + <para>The step data dialog is used to set the id and text of a tutorial. The id and text are mandatory properties, as the id is used by other steps to change to this step, and the text is shown to the user to explain him what must be done. Thus, the id must be unique for every step in the same tutorial.</para> + <para>The step data dialog is also shown when a new step is added. If the dialog is accepted, the step is added. If the dialog is cancelled, the step is not added.</para> + <para>Also note that, in every tutorial, there must be one step with id <emphasis>start</emphasis>, so KTutorial knows where to start the tutorial.</para> + + <screenshot> + <screeninfo>The dialog to set the id and text of a step</screeninfo> + <mediaobject> + <imageobject> + <imagedata fileref="set-step-data.png" format="PNG"/> + </imageobject> + <textobject> + <phrase>Step data edition dialog</phrase> + </textobject> + </mediaobject> + </screenshot> + + <para>The setup and tear down code dialogs behave like the tutorial ones. The only difference is that the code is executed when the tutorial changes to the step or when the tutorial changes from this step to another one.</para> + <para>Also note that the exported scripted tutorial creates all the reactions in the setup method of a step. The custom setup code is added after that code.</para> + </sect2> + + <sect2 id="edition-dialogs-reaction"> + <title>Reaction edition</title> + + <para>The reaction dialog is used to set the trigger and response of a step. The trigger and response are mandatory properties, as they define how the reaction behaves.</para> + <para>The trigger can be either an option selected or a condition met, but not both. If the trigger type is the option, its name will be shown to the user in the step and the response will be executed when the user selects it. If the type is the condition, the response will be executed when the condition is met.</para> + <para>Likely, the response can be changing to another step or executing some custom code, but not both. If the response type is the custom code, it will be used as the body of a function called when the reaction is triggered. Again, the signature of the function is automatically provided and you have to set only the body.</para> + + <screenshot> + <screeninfo>The dialog to set the trigger and response of a reaction</screeninfo> + <mediaobject> + <imageobject> + <imagedata fileref="set-reaction-data.png" format="PNG"/> + </imageobject> + <textobject> + <phrase>Set reaction data edition dialog</phrase> + </textobject> + </mediaobject> + </screenshot> + + <sect3 id="edition-dialogs-reaction-condition"> + <title>Condition edition</title> + + <para>The condition that acts as a trigger of a reaction can be a simple condition or a composed condition. Simple conditions wait for something to happen, like a signal emitted by an object. Composed conditions wait for its child conditions. For example, waiting until a signal is emitted by an object or an event is received in another object, whatever comes first.</para> + <para>Due to this, conditions are represented in a tree, and it also affects how they are edited.</para> + <para>A condition can be added as the root condition when there are no other conditions set, or as a child of the selected composed condition, but not when a simple condition is selected. When a new condition is added, you must select its type. Note that the type of the condition can not be changed later, you will have to remove the condition.</para> + + <screenshot> + <screeninfo>The dialog to select the type of the new condition to add</screeninfo> + <mediaobject> + <imageobject> + <imagedata fileref="new-condition.png" format="PNG"/> + </imageobject> + <textobject> + <phrase>New condition dialog</phrase> + </textobject> + </mediaobject> + </screenshot> + + <para>Only simple conditions (waiting for an event and waiting for a signal) can be edited, showing specific dialogs for it. Composed conditions only group other conditions, so they don't have properties to be edited.</para> + <para>Any condition can be removed from its parent composed condition, or from the reaction if it is the root condition.</para> + + <para>There is a special type of condition that verifies that its negated condition wasn't met which purpose is to be used only as a child of a composed condition that waits until all its child conditions were met. The idea is that, when the negated condition wasn't met, the special condition is met. When the negated condition is met, the special condition is no longer met. It can be used, for example, to make a reaction wait for the user to write something in a text line, provided he has not pressed a button before. Note that a fallback reaction should be added in cases like this one.</para> + </sect3> + </sect2> + </sect1> + + <sect1 id="export-tutorial"> + <title>Exporting the tutorial</title> + + <para>Once you have finished designing the tutorial you can export it to a scripted tutorial. To do this, just use <menuchoice><guimenu>File</guimenu><guimenuitem>Export...</guimenuitem></menuchoice>, select where to save the file and you are done. Remember that you have to export the file to some specific directory to be found by KTutorial, as explained in <xref linkend="understanding-ktutorial"/>.</para> + <para>The export dialog supports exporting to remote directories (via FTP, SSH, etc), although it will be very strange that you need to use that.</para> + </sect1> + + <sect1 id="command-line-options"> + <title>Command Line Options</title> + + <para>Though &ktutorial-editor; will be usually started from the &kde; program menu, or a desktop icon, it can also be opened from the command line prompt of a terminal window. There are a few options that are available when doing this.</para> + + <sect2 id="other-command-line-options"> + <title>Default KDE4 Command Line Options</title> + + <para>The following command line help options are available:</para> + + <variablelist> + <varlistentry> + <term> + <command>ktutorial-editor <option>--help</option></command> + </term> + <listitem> + <para>This lists the most basic options available at the command line.</para> + </listitem> + </varlistentry> + + <varlistentry> + <term> + <command>ktutorial-editor <option>--help-qt</option></command> + </term> + <listitem> + <para>This lists the options available for changing the way &ktutorial-editor; interacts with &Qt;.</para> + </listitem> + </varlistentry> + + <varlistentry> + <term> + <command>ktutorial-editor <option>--help-kde</option></command> + </term> + <listitem> + <para>This lists the options available for changing the way &ktutorial-editor; interacts with &kde;.</para> + </listitem> + </varlistentry> + + <varlistentry> + <term> + <command>ktutorial-editor <option>--help-all</option></command> + </term> + <listitem> + <para>This lists all of the command line options.</para> + </listitem> + </varlistentry> + + <varlistentry> + <term> + <command>ktutorial-editor <option>--author</option></command> + </term> + <listitem> + <para>Lists &ktutorial-editor;'s author in the terminal window.</para> + </listitem> + </varlistentry> + + <varlistentry> + <term> + <command>ktutorial-editor <option>--version</option></command> + </term> + <listitem> + <para>Lists version information for &Qt;, &kde;, and &ktutorial-editor;. Also available through <command>ktutorial-editor <option>-v</option></command>.</para> + </listitem> + </varlistentry> + + <varlistentry> + <term> + <command>ktutorial-editor <option>--license</option></command> + </term> + <listitem> + <para>Shows &ktutorial-editor;'s license text in the terminal window.</para> + </listitem> + </varlistentry> + </variablelist> + </sect2> + </sect1> +</chapter> + +<!-- +Local Variables: +mode: xml +sgml-minimize-attributes:nil +sgml-general-insert-case:lower +sgml-indent-step:0 +sgml-indent-data:nil +End: + +vim:tabstop=4:shiftwidth=4:expandtab +kate: space-indent on; indent-width 4; tab-width 4; indent-mode none; +--> This was sent by the SourceForge.net collaborative development platform, the world's largest Open Source development site. |
From: <dan...@us...> - 2010-03-26 08:49:20
|
Revision: 195 http://ktutorial.svn.sourceforge.net/ktutorial/?rev=195&view=rev Author: danxuliu Date: 2010-03-26 08:49:10 +0000 (Fri, 26 Mar 2010) Log Message: ----------- -Add TutorialReader class to deserialize a Tutorial in XML. -Enable exceptions. Modified Paths: -------------- trunk/ktutorial/ktutorial-editor/CMakeLists.txt trunk/ktutorial/ktutorial-editor/src/serialization/CMakeLists.txt trunk/ktutorial/ktutorial-editor/tests/unit/serialization/CMakeLists.txt Added Paths: ----------- trunk/ktutorial/ktutorial-editor/src/serialization/DeserializationException.cpp trunk/ktutorial/ktutorial-editor/src/serialization/DeserializationException.h trunk/ktutorial/ktutorial-editor/src/serialization/TutorialReader.cpp trunk/ktutorial/ktutorial-editor/src/serialization/TutorialReader.h trunk/ktutorial/ktutorial-editor/tests/unit/serialization/DeserializationExceptionTest.cpp trunk/ktutorial/ktutorial-editor/tests/unit/serialization/TutorialReaderTest.cpp Modified: trunk/ktutorial/ktutorial-editor/CMakeLists.txt =================================================================== --- trunk/ktutorial/ktutorial-editor/CMakeLists.txt 2010-03-26 01:10:24 UTC (rev 194) +++ trunk/ktutorial/ktutorial-editor/CMakeLists.txt 2010-03-26 08:49:10 UTC (rev 195) @@ -3,6 +3,7 @@ find_package(KDE4 REQUIRED) include(KDE4Defaults) +set(CMAKE_CXX_FLAGS "${CMAKE_CXX_FLAGS} ${KDE4_ENABLE_EXCEPTIONS}") add_subdirectory(doc) add_subdirectory(po) Modified: trunk/ktutorial/ktutorial-editor/src/serialization/CMakeLists.txt =================================================================== --- trunk/ktutorial/ktutorial-editor/src/serialization/CMakeLists.txt 2010-03-26 01:10:24 UTC (rev 194) +++ trunk/ktutorial/ktutorial-editor/src/serialization/CMakeLists.txt 2010-03-26 08:49:10 UTC (rev 195) @@ -1,8 +1,10 @@ include_directories(${KDE4_INCLUDES}) set(ktutorial_editor_serialization_SRCS + DeserializationException.cpp JavascriptExporter.cpp Serialization.cpp + TutorialReader.cpp TutorialWriter.cpp ) Added: trunk/ktutorial/ktutorial-editor/src/serialization/DeserializationException.cpp =================================================================== --- trunk/ktutorial/ktutorial-editor/src/serialization/DeserializationException.cpp (rev 0) +++ trunk/ktutorial/ktutorial-editor/src/serialization/DeserializationException.cpp 2010-03-26 08:49:10 UTC (rev 195) @@ -0,0 +1,33 @@ +/*************************************************************************** + * 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 "DeserializationException.h" + +//public: + +DeserializationException::DeserializationException(const QString& message): + std::exception(), + mMessage(message) { +} + +DeserializationException::~DeserializationException() throw() { +} + +const char* DeserializationException::what() const throw() { + return mMessage.toUtf8(); +} Property changes on: trunk/ktutorial/ktutorial-editor/src/serialization/DeserializationException.cpp ___________________________________________________________________ Added: svn:eol-style + native Added: trunk/ktutorial/ktutorial-editor/src/serialization/DeserializationException.h =================================================================== --- trunk/ktutorial/ktutorial-editor/src/serialization/DeserializationException.h (rev 0) +++ trunk/ktutorial/ktutorial-editor/src/serialization/DeserializationException.h 2010-03-26 08:49:10 UTC (rev 195) @@ -0,0 +1,48 @@ +/*************************************************************************** + * 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 DESERIALIZATIONEXCEPTION_H +#define DESERIALIZATIONEXCEPTION_H + +#include <exception> +#include <QString> + +/** + * Thrown when the XML can't be deserialized (for example, when it isn't well + * formed). + */ +class DeserializationException: public std::exception { +public: + + explicit DeserializationException(const QString& message = QString()); + virtual ~DeserializationException() throw(); + + /** + * Returns the exception message. + * + * @return The exception message. + */ + virtual const char* what() const throw(); + +private: + + QString mMessage; + +}; + +#endif Property changes on: trunk/ktutorial/ktutorial-editor/src/serialization/DeserializationException.h ___________________________________________________________________ Added: svn:eol-style + native Added: trunk/ktutorial/ktutorial-editor/src/serialization/TutorialReader.cpp =================================================================== --- trunk/ktutorial/ktutorial-editor/src/serialization/TutorialReader.cpp (rev 0) +++ trunk/ktutorial/ktutorial-editor/src/serialization/TutorialReader.cpp 2010-03-26 08:49:10 UTC (rev 195) @@ -0,0 +1,242 @@ +/*************************************************************************** + * 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 "TutorialReader.h" + +#include <QDomDocument> + +#include "../Reaction.h" +#include "../Step.h" +#include "../Tutorial.h" +#include "../WaitForComposed.h" +#include "../WaitForEvent.h" +#include "../WaitForNot.h" +#include "../WaitForSignal.h" + +//public: + +TutorialReader::TutorialReader() { +} + +Tutorial* TutorialReader::readTutorial(const QString& data) +throw (DeserializationException) { + QDomDocument document; + + QString errorMessage; + int errorLine; + int errorColumn; + + if (!document.setContent(data, &errorMessage, &errorLine, &errorColumn) || + document.documentElement().tagName() != "tutorial") { + throw DeserializationException(errorMessage); + } + + return readTutorial(document.documentElement()); +} + +//private: + +Tutorial* TutorialReader::readTutorial(const QDomElement& element) { + Tutorial* tutorial = new Tutorial(); + + if (element.hasAttribute("name")) { + tutorial->setName(element.attribute("name")); + } + + QDomElement childElement = element.firstChildElement(); + while (!childElement.isNull()) { + if (childElement.tagName() == "description") { + tutorial->setDescription(childElement.text()); + } else if (childElement.tagName() == "license") { + tutorial->setLicenseText(childElement.text()); + } else if (childElement.tagName() == "setup") { + tutorial->setCustomSetupCode(childElement.text()); + } else if (childElement.tagName() == "tearDown") { + tutorial->setCustomTearDownCode(childElement.text()); + } else if (childElement.tagName() == "step") { + tutorial->addStep(readStep(childElement)); + } + + childElement = childElement.nextSiblingElement(); + } + + return tutorial; +} + +Step* TutorialReader::readStep(const QDomElement& element) { + Step* step = new Step; + + if (element.hasAttribute("id")) { + step->setId(element.attribute("id")); + } + + QDomElement childElement = element.firstChildElement(); + while (!childElement.isNull()) { + if (childElement.tagName() == "text") { + step->setText(childElement.text()); + } else if (childElement.tagName() == "setup") { + step->setCustomSetupCode(childElement.text()); + } else if (childElement.tagName() == "tearDown") { + step->setCustomTearDownCode(childElement.text()); + } else if (childElement.tagName() == "reaction") { + step->addReaction(readReaction(childElement)); + } + + childElement = childElement.nextSiblingElement(); + } + + return step; +} + +Reaction* TutorialReader::readReaction(const QDomElement& element) { + Reaction* reaction = new Reaction(); + + if (element.hasAttribute("triggerType")) { + Reaction::TriggerType triggerType = Reaction::OptionSelected; + if (element.attribute("triggerType") == "ConditionMet") { + triggerType = Reaction::ConditionMet; + } + + reaction->setTriggerType(triggerType); + } + + if (element.hasAttribute("responseType")) { + Reaction::ResponseType responseType = Reaction::NextStep; + if (element.attribute("responseType") == "CustomCode") { + responseType = Reaction::CustomCode; + } + + reaction->setResponseType(responseType); + } + + QDomElement childElement = element.firstChildElement(); + while (!childElement.isNull()) { + if (childElement.tagName() == "option") { + if (childElement.hasAttribute("name")) { + reaction->setOptionName(childElement.attribute("name")); + } + } else if (isWaitForElement(childElement)) { + reaction->setWaitFor(readWaitFor(childElement)); + } else if (childElement.tagName() == "customCode") { + reaction->setCustomCode(childElement.text()); + } else if (childElement.tagName() == "nextStep") { + if (childElement.hasAttribute("id")) { + reaction->setNextStepId(childElement.attribute("id")); + } + } + + childElement = childElement.nextSiblingElement(); + } + + return reaction; +} + +WaitFor* TutorialReader::readWaitFor(const QDomElement& element) { + if (element.tagName() == "waitForComposed") { + return readWaitForComposed(element); + } + if (element.tagName() == "waitForEvent") { + return readWaitForEvent(element); + } + if (element.tagName() == "waitForNot") { + return readWaitForNot(element); + } + if (element.tagName() == "waitForSignal") { + return readWaitForSignal(element); + } + + Q_ASSERT(false); + return 0; +} + +WaitFor* TutorialReader::readWaitForComposed(const QDomElement& element) { + WaitForComposed* waitForComposed = new WaitForComposed(); + + if (element.hasAttribute("compositionType")) { + WaitForComposed::CompositionType compositionType = WaitForComposed::And; + if (element.attribute("compositionType") == "Or") { + compositionType = WaitForComposed::Or; + } + + waitForComposed->setCompositionType(compositionType); + } + + QDomElement childElement = element.firstChildElement(); + while (!childElement.isNull()) { + if (isWaitForElement(childElement)) { + waitForComposed->addWaitFor(readWaitFor(childElement)); + } + + childElement = childElement.nextSiblingElement(); + } + + return waitForComposed; +} + +WaitFor* TutorialReader::readWaitForEvent(const QDomElement& element) { + WaitForEvent* waitForEvent = new WaitForEvent(); + + if (element.hasAttribute("receiverName")) { + waitForEvent->setReceiverName(element.attribute("receiverName")); + } + if (element.hasAttribute("eventName")) { + waitForEvent->setEventName(element.attribute("eventName")); + } + + return waitForEvent; +} + +WaitFor* TutorialReader::readWaitForNot(const QDomElement& element) { + WaitForNot* waitForNot = new WaitForNot(); + + QDomElement childElement = element.firstChildElement(); + while (!childElement.isNull()) { + if (isWaitForElement(childElement)) { + delete waitForNot->negatedWaitFor(); + waitForNot->setNegatedWaitFor(readWaitFor(childElement)); + } + + childElement = childElement.nextSiblingElement(); + } + + return waitForNot; +} + +WaitFor* TutorialReader::readWaitForSignal(const QDomElement& element) { + WaitForSignal* waitForSignal = new WaitForSignal(); + + if (element.hasAttribute("emitterName")) { + waitForSignal->setEmitterName(element.attribute("emitterName")); + } + if (element.hasAttribute("signalName")) { + waitForSignal->setSignalName(element.attribute("signalName")); + } + + return waitForSignal; +} + +bool TutorialReader::isWaitForElement(const QDomElement& element) { + if (element.tagName() != "waitForComposed" && + element.tagName() != "waitForEvent" && + element.tagName() != "waitForNot" && + element.tagName() != "waitForSignal") { + return false; + } + + return true; +} Property changes on: trunk/ktutorial/ktutorial-editor/src/serialization/TutorialReader.cpp ___________________________________________________________________ Added: svn:eol-style + native Added: trunk/ktutorial/ktutorial-editor/src/serialization/TutorialReader.h =================================================================== --- trunk/ktutorial/ktutorial-editor/src/serialization/TutorialReader.h (rev 0) +++ trunk/ktutorial/ktutorial-editor/src/serialization/TutorialReader.h 2010-03-26 08:49:10 UTC (rev 195) @@ -0,0 +1,147 @@ +/*************************************************************************** + * 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 TUTORIALREADER_H +#define TUTORIALREADER_H + +#include <QXmlStreamWriter> + +#include "DeserializationException.h" + +class QDomElement; +class Reaction; +class Step; +class Tutorial; +class WaitFor; +class WaitForComposed; +class WaitForEvent; +class WaitForNot; +class WaitForSignal; + +/** + * Deserializer for tutorials stored in XML. + * Creates a new Tutorial from the XML data generated by TutorialWriter. Anyway, + * if the XML data is not valid (see Tutorial.xsd for the W3C Schema), it + * ignores unknown attributes and elements, and uses those known to create the + * tutorial. + * + * @see TutorialWriter + */ +class TutorialReader { +public: + + /** + * Creates a new TutorialReader. + */ + TutorialReader(); + + /** + * Returns the Tutorial stored in the given XML serialization. + * The tutorial must be deleted explicitly. + * + * If the XML is not well formed or its root element is not a "tutorial" + * element, a DeserializationException is thrown. In any other case, even if + * the XML is not valid, the deserializer tries to do its best: it ignores + * unknown attributes and elements and deserializes all the attributes and + * elements it knows. + * + * @param data The XML serialization. + * @return The Tutorial stored in the given XML serialization. + * @throw DeserializationException If there was a problem deserializing the + * tutorial. + */ + Tutorial* readTutorial(const QString& data) + throw (DeserializationException); + +private: + + /** + * Reads a new Tutorial from the "tutorial" XML element. + * + * @param element The element to read the Tutorial from. + * @return The new Tutorial. + */ + Tutorial* readTutorial(const QDomElement& element); + + /** + * Reads a new Step from the "step" XML element. + * + * @param element The element to read the Step from. + * @return The new Step. + */ + Step* readStep(const QDomElement& element); + + /** + * Reads a new Reaction from the "reaction" XML element. + * + * @param element The element to read the Reaction from. + * @return The new Reaction. + */ + Reaction* readReaction(const QDomElement& element); + + /** + * Returns a new WaitFor object from the appropriate subclass. + * + * @param element The element to read the WaitFor from. + * @return The new WaitFor. + */ + WaitFor* readWaitFor(const QDomElement& element); + + /** + * Reads a new WaitForComposed from the "waitForComposed" XML element. + * + * @param element The element to read the WaitForComposed from. + * @return The new WaitForComposed. + */ + WaitFor* readWaitForComposed(const QDomElement& element); + + /** + * Reads a new WaitForEvent from the "waitForEvent" XML element. + * + * @param element The element to read the WaitForEvent from. + * @return The new WaitForEvent. + */ + WaitFor* readWaitForEvent(const QDomElement& element); + + /** + * Reads a new WaitForNot from the "waitForNot" XML element. + * + * @param element The element to read the WaitForNot from. + * @return The new WaitForNot. + */ + WaitFor* readWaitForNot(const QDomElement& element); + + /** + * Reads a new WaitForSignal from the "waitForSignal" XML element. + * + * @param element The element to read the WaitForSignal from. + * @return The new WaitForSignal. + */ + WaitFor* readWaitForSignal(const QDomElement& element); + + /** + * Returns whether the given element is one of the WaitFor elements or not. + * + * @param element The element to check. + * @return Whether the given element is one of the WaitFor elements or not. + */ + bool isWaitForElement(const QDomElement& element); + +}; + +#endif Property changes on: trunk/ktutorial/ktutorial-editor/src/serialization/TutorialReader.h ___________________________________________________________________ Added: svn:eol-style + native Modified: trunk/ktutorial/ktutorial-editor/tests/unit/serialization/CMakeLists.txt =================================================================== --- trunk/ktutorial/ktutorial-editor/tests/unit/serialization/CMakeLists.txt 2010-03-26 01:10:24 UTC (rev 194) +++ trunk/ktutorial/ktutorial-editor/tests/unit/serialization/CMakeLists.txt 2010-03-26 08:49:10 UTC (rev 195) @@ -12,6 +12,7 @@ ENDMACRO(UNIT_TESTS) unit_tests( + DeserializationException JavascriptExporter Serialization TutorialReader @@ -25,6 +26,7 @@ ENDMACRO(MEM_TESTS) mem_tests( + DeserializationException JavascriptExporter Serialization TutorialReader Added: trunk/ktutorial/ktutorial-editor/tests/unit/serialization/DeserializationExceptionTest.cpp =================================================================== --- trunk/ktutorial/ktutorial-editor/tests/unit/serialization/DeserializationExceptionTest.cpp (rev 0) +++ trunk/ktutorial/ktutorial-editor/tests/unit/serialization/DeserializationExceptionTest.cpp 2010-03-26 08:49:10 UTC (rev 195) @@ -0,0 +1,47 @@ +/*************************************************************************** + * 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 "DeserializationException.h" + +class DeserializationExceptionTest: public QObject { +Q_OBJECT + +private slots: + + void testConstructor(); + void testConstructorEmpty(); + +}; + +void DeserializationExceptionTest::testConstructor() { + DeserializationException exception(QString("The message")); + + QCOMPARE(exception.what(), "The message"); +} + +void DeserializationExceptionTest::testConstructorEmpty() { + DeserializationException exception; + + QCOMPARE(exception.what(), ""); +} + +QTEST_MAIN(DeserializationExceptionTest) + +#include "DeserializationExceptionTest.moc" Property changes on: trunk/ktutorial/ktutorial-editor/tests/unit/serialization/DeserializationExceptionTest.cpp ___________________________________________________________________ Added: svn:eol-style + native Added: trunk/ktutorial/ktutorial-editor/tests/unit/serialization/TutorialReaderTest.cpp =================================================================== --- trunk/ktutorial/ktutorial-editor/tests/unit/serialization/TutorialReaderTest.cpp (rev 0) +++ trunk/ktutorial/ktutorial-editor/tests/unit/serialization/TutorialReaderTest.cpp 2010-03-26 08:49:10 UTC (rev 195) @@ -0,0 +1,658 @@ +/*************************************************************************** + * 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 "TutorialReader.h" + +#include "../Reaction.h" +#include "../Step.h" +#include "../Tutorial.h" +#include "../WaitForComposed.h" +#include "../WaitForEvent.h" +#include "../WaitForNot.h" +#include "../WaitForSignal.h" + +#define HEADER_XML \ + "<?xml version=\"1.0\" encoding=\"utf-8\"?>\n" + +#define TUTORIAL_ELEMENTS \ +" <description>The description,\nwith < and >\n</description>\n" \ +" <license>The license text,\nwith < and >\n</license>\n" \ +" <setup>The setup code,\nwith < and >\n</setup>\n" \ +" <tearDown>The tear down code,\nwith < and >\n</tearDown>\n" + +#define STEP_PARENT_START \ +HEADER_XML \ +"<tutorial>\n" + +#define STEP_PARENT_END \ +"</tutorial>\n" + +#define STEP_ELEMENTS \ +" <text>The text,\nwith < and >\n</text>\n" \ +" <setup>The setup code,\nwith < and >\n</setup>\n" \ +" <tearDown>The tear down code,\nwith < and >\n</tearDown>\n" + +#define REACTION_PARENT_START \ +STEP_PARENT_START \ +" <step>\n" + +#define REACTION_PARENT_END \ +" </step>\n" \ +STEP_PARENT_END + +#define WAITFOR_PARENT_START \ +REACTION_PARENT_START \ +" <reaction triggerType=\"ConditionMet\" responseType=\"NextStep\">\n" + +#define WAITFOR_PARENT_END \ +" </reaction>\n" \ +REACTION_PARENT_END + +class TutorialReaderTest: public QObject { +Q_OBJECT + +private slots: + + void testTutorial(); + void testTutorialEmpty(); + void testTutorialWithSeveralSteps(); + + void testStep(); + void testStepEmpty(); + void testStepWithSeveralReactions(); + + void testReactionConditionCustomCode(); + void testReactionOptionNextStep(); + void testReactionEmpty(); + + void testWaitForEvent(); + void testWaitForEventEmpty(); + void testWaitForSignal(); + void testWaitForSignalEmpty(); + void testWaitForComposed(); + void testWaitForComposedEmpty(); + void testWaitForNot(); + void testWaitForNotWithoutNegatedWaitFor(); + + void testXmlNotWellFormed(); + void testXmlWithoutRootTutorialElement(); + void testXmlWithGarbageElementsAndAttributes(); + +private: + + void assertWaitForSignal(WaitFor* waitFor, const QString& emitterName, + const QString& signalName) const; + + QString addGarbageToXmlData(const QString& data) const; + +}; + +void TutorialReaderTest::testTutorial() { + QString data = +HEADER_XML +"<tutorial name=\"The "name"\">\n" +" <description>The description,\nwith < and >\n</description>\n" +" <license>The license text,\nwith < and >\n</license>\n" +" <setup>The setup code,\nwith < and >\n</setup>\n" +" <tearDown>The tear down code,\nwith < and >\n</tearDown>\n" +"</tutorial>\n"; + + TutorialReader reader; + QScopedPointer<Tutorial> tutorial(reader.readTutorial(data)); + + QVERIFY(tutorial); + QCOMPARE(tutorial->name(), QString("The \"name\"")); + QCOMPARE(tutorial->description(), + QString("The description,\nwith < and >\n")); + QCOMPARE(tutorial->licenseText(), + QString("The license text,\nwith < and >\n")); + QCOMPARE(tutorial->customSetupCode(), + QString("The setup code,\nwith < and >\n")); + QCOMPARE(tutorial->customTearDownCode(), + QString("The tear down code,\nwith < and >\n")); + QCOMPARE(tutorial->steps().count(), 0); +} + +void TutorialReaderTest::testTutorialEmpty() { + QString data = +HEADER_XML +"<tutorial/>\n"; + + TutorialReader reader; + QScopedPointer<Tutorial> tutorial(reader.readTutorial(data)); + + QVERIFY(tutorial); + QCOMPARE(tutorial->name(), QString("")); + QCOMPARE(tutorial->description(), QString("")); + QCOMPARE(tutorial->licenseText(), QString("")); + QCOMPARE(tutorial->customSetupCode(), QString("")); + QCOMPARE(tutorial->customTearDownCode(), QString("")); + QCOMPARE(tutorial->steps().count(), 0); +} + +void TutorialReaderTest::testTutorialWithSeveralSteps() { + QString data = +HEADER_XML +"<tutorial name=\"The "name"\">\n" +TUTORIAL_ELEMENTS +" <step id=\"The id1\">\n" +" <text>The text1</text>\n" +" </step>\n" +" <step id=\"The id2\">\n" +" <text>The text2</text>\n" +" </step>\n" +"</tutorial>\n"; + + TutorialReader reader; + QScopedPointer<Tutorial> tutorial(reader.readTutorial(data)); + + QVERIFY(tutorial); + QCOMPARE(tutorial->name(), QString("The \"name\"")); + QCOMPARE(tutorial->description(), + QString("The description,\nwith < and >\n")); + QCOMPARE(tutorial->licenseText(), + QString("The license text,\nwith < and >\n")); + QCOMPARE(tutorial->customSetupCode(), + QString("The setup code,\nwith < and >\n")); + QCOMPARE(tutorial->customTearDownCode(), + QString("The tear down code,\nwith < and >\n")); + QCOMPARE(tutorial->steps().count(), 2); + Step* step = tutorial->steps()[0]; + QVERIFY(step); + QCOMPARE(step->id(), QString("The id1")); + QCOMPARE(step->text(), QString("The text1")); + step = tutorial->steps()[1]; + QVERIFY(step); + QCOMPARE(step->id(), QString("The id2")); + QCOMPARE(step->text(), QString("The text2")); +} + +void TutorialReaderTest::testStep() { + QString data = +STEP_PARENT_START +" <step id=\"The "id"\">\n" +" <text>The text,\nwith < and >\n</text>\n" +" <setup>The setup code,\nwith < and >\n</setup>\n" +" <tearDown>The tear down code,\nwith < and >\n</tearDown>\n" +" </step>\n" +STEP_PARENT_END; + + TutorialReader reader; + QScopedPointer<Tutorial> tutorial(reader.readTutorial(data)); + Step* step = tutorial->steps()[0]; + + QVERIFY(step); + QCOMPARE(step->id(), QString("The \"id\"")); + QCOMPARE(step->text(), QString("The text,\nwith < and >\n")); + QCOMPARE(step->customSetupCode(), + QString("The setup code,\nwith < and >\n")); + QCOMPARE(step->customTearDownCode(), + QString("The tear down code,\nwith < and >\n")); + QCOMPARE(step->reactions().count(), 0); +} + +void TutorialReaderTest::testStepEmpty() { + QString data = +STEP_PARENT_START +" <step/>\n" +STEP_PARENT_END; + + TutorialReader reader; + QScopedPointer<Tutorial> tutorial(reader.readTutorial(data)); + Step* step = tutorial->steps()[0]; + + QVERIFY(step); + QCOMPARE(step->id(), QString("")); + QCOMPARE(step->text(), QString("")); + QCOMPARE(step->customSetupCode(), QString("")); + QCOMPARE(step->customTearDownCode(), QString("")); + QCOMPARE(step->reactions().count(), 0); +} + +void TutorialReaderTest::testStepWithSeveralReactions() { + QString data = +STEP_PARENT_START +" <step id=\"The "id"\">\n" +STEP_ELEMENTS +" <reaction triggerType=\"ConditionMet\" responseType=\"CustomCode\"/>\n" +" <reaction triggerType=\"OptionSelected\" responseType=\"NextStep\">\n" +" <option name=\"The option name\"/>\n" +" <nextStep id=\"Another id\"/>\n" +" </reaction>\n" +" </step>\n" +STEP_PARENT_END; + + TutorialReader reader; + QScopedPointer<Tutorial> tutorial(reader.readTutorial(data)); + Step* step = tutorial->steps()[0]; + + QVERIFY(step); + QCOMPARE(step->id(), QString("The \"id\"")); + QCOMPARE(step->text(), QString("The text,\nwith < and >\n")); + QCOMPARE(step->customSetupCode(), + QString("The setup code,\nwith < and >\n")); + QCOMPARE(step->customTearDownCode(), + QString("The tear down code,\nwith < and >\n")); + QCOMPARE(step->reactions().count(), 2); + Reaction* reaction = step->reactions()[0]; + QVERIFY(reaction); + QCOMPARE(reaction->triggerType(), Reaction::ConditionMet); + QCOMPARE(reaction->responseType(), Reaction::CustomCode); + reaction = step->reactions()[1]; + QVERIFY(reaction); + QCOMPARE(reaction->triggerType(), Reaction::OptionSelected); + QCOMPARE(reaction->optionName(), QString("The option name")); + QCOMPARE(reaction->responseType(), Reaction::NextStep); + QCOMPARE(reaction->nextStepId(), QString("Another id")); +} + +void TutorialReaderTest::testReactionConditionCustomCode() { + QString data = +REACTION_PARENT_START +" <reaction triggerType=\"ConditionMet\" responseType=\"CustomCode\">\n" +" <option name=\"The "option" name\"/>\n" +" <waitForSignal emitterName=\"The emitter name\" \ +signalName=\"theSignalName(Argument1Type, Argument2Type)\"/>\n" +" <customCode>The custom code,\nwith < and >\n</customCode>\n" +" <nextStep id=\"Another "id"\"/>\n" +" </reaction>\n" +REACTION_PARENT_END; + + TutorialReader reader; + QScopedPointer<Tutorial> tutorial(reader.readTutorial(data)); + Reaction* reaction = tutorial->steps()[0]->reactions()[0]; + + QVERIFY(reaction); + QCOMPARE(reaction->triggerType(), Reaction::ConditionMet); + QCOMPARE(reaction->optionName(), QString("The \"option\" name")); + assertWaitForSignal(reaction->waitFor(), "The emitter name", + "theSignalName(Argument1Type, Argument2Type)"); + QCOMPARE(reaction->responseType(), Reaction::CustomCode); + QCOMPARE(reaction->customCode(), + QString("The custom code,\nwith < and >\n")); + QCOMPARE(reaction->nextStepId(), QString("Another \"id\"")); +} + +void TutorialReaderTest::testReactionOptionNextStep() { + QString data = +REACTION_PARENT_START +" <reaction triggerType=\"OptionSelected\" responseType=\"NextStep\">\n" +" <option name=\"The "option" name\"/>\n" +" <waitForSignal emitterName=\"The emitter name\" \ +signalName=\"theSignalName(Argument1Type, Argument2Type)\"/>\n" +" <customCode>The custom code,\nwith < and >\n</customCode>\n" +" <nextStep id=\"Another "id"\"/>\n" +" </reaction>\n" +REACTION_PARENT_END; + + TutorialReader reader; + QScopedPointer<Tutorial> tutorial(reader.readTutorial(data)); + Reaction* reaction = tutorial->steps()[0]->reactions()[0]; + + QVERIFY(reaction); + QCOMPARE(reaction->triggerType(), Reaction::OptionSelected); + QCOMPARE(reaction->optionName(), QString("The \"option\" name")); + assertWaitForSignal(reaction->waitFor(), "The emitter name", + "theSignalName(Argument1Type, Argument2Type)"); + QCOMPARE(reaction->responseType(), Reaction::NextStep); + QCOMPARE(reaction->customCode(), + QString("The custom code,\nwith < and >\n")); + QCOMPARE(reaction->nextStepId(), QString("Another \"id\"")); +} + +void TutorialReaderTest::testReactionEmpty() { + QString data = +REACTION_PARENT_START +" <reaction triggerType=\"ConditionMet\" responseType=\"CustomCode\"/>\n" +REACTION_PARENT_END; + + TutorialReader reader; + QScopedPointer<Tutorial> tutorial(reader.readTutorial(data)); + Reaction* reaction = tutorial->steps()[0]->reactions()[0]; + + QVERIFY(reaction); + QCOMPARE(reaction->triggerType(), Reaction::ConditionMet); + QCOMPARE(reaction->optionName(), QString("")); + QCOMPARE(reaction->waitFor(), (WaitFor*)0); + QCOMPARE(reaction->responseType(), Reaction::CustomCode); + QCOMPARE(reaction->customCode(), QString("")); + QCOMPARE(reaction->nextStepId(), QString("")); +} + +void TutorialReaderTest::testWaitForEvent() { + QString data = +WAITFOR_PARENT_START +" <waitForEvent receiverName=\"The "receiver" name\" \ +eventName=\"The"Event"Name\"/>\n" +WAITFOR_PARENT_END; + + TutorialReader reader; + QScopedPointer<Tutorial> tutorial(reader.readTutorial(data)); + WaitFor* waitFor = tutorial->steps()[0]->reactions()[0]->waitFor(); + + WaitForEvent* waitForEvent = qobject_cast<WaitForEvent*>(waitFor); + QVERIFY(waitForEvent); + QCOMPARE(waitForEvent->receiverName(), QString("The \"receiver\" name")); + QCOMPARE(waitForEvent->eventName(), QString("The\"Event\"Name")); +} + +void TutorialReaderTest::testWaitForEventEmpty() { + QString data = +WAITFOR_PARENT_START +" <waitForEvent/>\n" +WAITFOR_PARENT_END; + + TutorialReader reader; + QScopedPointer<Tutorial> tutorial(reader.readTutorial(data)); + WaitFor* waitFor = tutorial->steps()[0]->reactions()[0]->waitFor(); + + WaitForEvent* waitForEvent = qobject_cast<WaitForEvent*>(waitFor); + QVERIFY(waitForEvent); + QCOMPARE(waitForEvent->receiverName(), QString("")); + QCOMPARE(waitForEvent->eventName(), QString("")); +} + +void TutorialReaderTest::testWaitForSignal() { + QString data = +WAITFOR_PARENT_START +" <waitForSignal emitterName=\"The "emitter" name\" \ +signalName=\"theSignalName("Argument1Type")\"/>\n" +WAITFOR_PARENT_END; + + TutorialReader reader; + QScopedPointer<Tutorial> tutorial(reader.readTutorial(data)); + WaitFor* waitFor = tutorial->steps()[0]->reactions()[0]->waitFor(); + + assertWaitForSignal(waitFor, "The \"emitter\" name", + "theSignalName(\"Argument1Type\")"); +} + +void TutorialReaderTest::testWaitForSignalEmpty() { + QString data = +WAITFOR_PARENT_START +" <waitForSignal/>\n" +WAITFOR_PARENT_END; + + TutorialReader reader; + QScopedPointer<Tutorial> tutorial(reader.readTutorial(data)); + WaitFor* waitFor = tutorial->steps()[0]->reactions()[0]->waitFor(); + + assertWaitForSignal(waitFor, "", ""); +} + +void TutorialReaderTest::testWaitForComposed() { + QString data = +WAITFOR_PARENT_START +" <waitForComposed compositionType=\"And\">\n" +" <waitForSignal emitterName=\"The emitter name1\" \ +signalName=\"theSignalName1()\"/>\n" +" <waitForComposed compositionType=\"Or\">\n" +" <waitForSignal emitterName=\"The emitter name2\" \ +signalName=\"theSignalName2()\"/>\n" +" <waitForSignal emitterName=\"The emitter name3\" \ +signalName=\"theSignalName3()\"/>\n" +" </waitForComposed>\n" +" </waitForComposed>\n" +WAITFOR_PARENT_END; + + TutorialReader reader; + QScopedPointer<Tutorial> tutorial(reader.readTutorial(data)); + WaitFor* waitFor = tutorial->steps()[0]->reactions()[0]->waitFor(); + + WaitForComposed* waitForAnd = qobject_cast<WaitForComposed*>(waitFor); + QVERIFY(waitForAnd); + QCOMPARE(waitForAnd->compositionType(), WaitForComposed::And); + QCOMPARE(waitForAnd->waitFors().count(), 2); + assertWaitForSignal(waitForAnd->waitFors()[0], "The emitter name1", + "theSignalName1()"); + + WaitForComposed* waitForOr = + qobject_cast<WaitForComposed*>(waitForAnd->waitFors()[1]); + QVERIFY(waitForOr); + QCOMPARE(waitForOr->compositionType(), WaitForComposed::Or); + QCOMPARE(waitForOr->waitFors().count(), 2); + assertWaitForSignal(waitForOr->waitFors()[0], "The emitter name2", + "theSignalName2()"); + assertWaitForSignal(waitForOr->waitFors()[1], "The emitter name3", + "theSignalName3()"); +} + +void TutorialReaderTest::testWaitForComposedEmpty() { + QString data = +WAITFOR_PARENT_START +" <waitForComposed compositionType=\"And\">\n" +" <waitForComposed compositionType=\"And\"/>\n" +" <waitForComposed compositionType=\"Or\"/>\n" +" </waitForComposed>\n" +WAITFOR_PARENT_END; + + TutorialReader reader; + QScopedPointer<Tutorial> tutorial(reader.readTutorial(data)); + WaitFor* waitFor = tutorial->steps()[0]->reactions()[0]->waitFor(); + + WaitForComposed* waitForAnd = qobject_cast<WaitForComposed*>(waitFor); + QVERIFY(waitForAnd); + QCOMPARE(waitForAnd->compositionType(), WaitForComposed::And); + QCOMPARE(waitForAnd->waitFors().count(), 2); + + WaitForComposed* waitForAndChild = + qobject_cast<WaitForComposed*>(waitForAnd->waitFors()[0]); + QVERIFY(waitForAndChild); + QCOMPARE(waitForAndChild->compositionType(), WaitForComposed::And); + QCOMPARE(waitForAndChild->waitFors().count(), 0); + + WaitForComposed* waitForOrChild = + qobject_cast<WaitForComposed*>(waitForAnd->waitFors()[1]); + QVERIFY(waitForOrChild); + QCOMPARE(waitForOrChild->compositionType(), WaitForComposed::Or); + QCOMPARE(waitForOrChild->waitFors().count(), 0); +} + +void TutorialReaderTest::testWaitForNot() { + QString data = +WAITFOR_PARENT_START +" <waitForNot>\n" +" <waitForSignal emitterName=\"The emitter name\" \ +signalName=\"theSignalName()\"/>\n" +" </waitForNot>\n" +WAITFOR_PARENT_END; + + TutorialReader reader; + QScopedPointer<Tutorial> tutorial(reader.readTutorial(data)); + WaitFor* waitFor = tutorial->steps()[0]->reactions()[0]->waitFor(); + + WaitForNot* waitForNot = qobject_cast<WaitForNot*>(waitFor); + QVERIFY(waitForNot); + WaitForSignal* waitForSignal = + qobject_cast<WaitForSignal*>(waitForNot->negatedWaitFor()); + QVERIFY(waitForSignal); + QCOMPARE(waitForSignal->emitterName(), QString("The emitter name")); + QCOMPARE(waitForSignal->signalName(), QString("theSignalName()")); +} + +void TutorialReaderTest::testWaitForNotWithoutNegatedWaitFor() { + QString data = +WAITFOR_PARENT_START +" <waitForNot/>\n" +WAITFOR_PARENT_END; + + TutorialReader reader; + QScopedPointer<Tutorial> tutorial(reader.readTutorial(data)); + WaitFor* waitFor = tutorial->steps()[0]->reactions()[0]->waitFor(); + + WaitForNot* waitForNot = qobject_cast<WaitForNot*>(waitFor); + QVERIFY(waitForNot); + QCOMPARE(waitForNot->negatedWaitFor(), (WaitFor*)0); +} + +void TutorialReaderTest::testXmlNotWellFormed() { + QString data = +HEADER_XML +"<tutorial>\n" +" <step>\n" +" </invalidEndElement>\n" +"</tutorial>\n"; + + TutorialReader reader; + try { + QScopedPointer<Tutorial> tutorial(reader.readTutorial(data)); + QFAIL("Expected DeserializationException not thrown"); + } catch (DeserializationException e) { + } +} + +void TutorialReaderTest::testXmlWithoutRootTutorialElement() { + QString data = +HEADER_XML +"<unknownRootElement>\n" +"</unknownRootElement>\n"; + + TutorialReader reader; + try { + QScopedPointer<Tutorial> tutorial(reader.readTutorial(data)); + QFAIL("Expected DeserializationException not thrown"); + } catch (DeserializationException e) { + } +} + +void TutorialReaderTest::testXmlWithGarbageElementsAndAttributes() { + QString data = +HEADER_XML +"<tutorial name=\"The "name"\">\n" +TUTORIAL_ELEMENTS +" <step id=\"The id1\">\n" +STEP_ELEMENTS +" </step>\n" +" <step id=\"The id2\">\n" +" <text>The text2</text>\n" +" <reaction triggerType=\"OptionSelected\" responseType=\"NextStep\">\n" +" <option name=\"The "option" name\"/>\n" +" <customCode>The custom code,\nwith < and >\n</customCode>\n" +" <nextStep id=\"Another "id"\"/>\n" +" </reaction>\n" +" <reaction triggerType=\"ConditionMet\" responseType=\"CustomCode\">\n" +" <waitForComposed compositionType=\"And\">\n" +" <waitForSignal emitterName=\"The emitter name1\" \ +signalName=\"theSignalName1()\"/>\n" +" <waitForComposed compositionType=\"Or\">\n" +" <waitForSignal emitterName=\"The emitter name2\" \ +signalName=\"theSignalName2()\"/>\n" +" <waitForSignal emitterName=\"The emitter name3\" \ +signalName=\"theSignalName3()\"/>\n" +" </waitForComposed>\n" +" </waitForComposed>\n" +" </reaction>\n" +" </step>\n" +"</tutorial>\n"; + + data = addGarbageToXmlData(data); + + TutorialReader reader; + QScopedPointer<Tutorial> tutorial(reader.readTutorial(data)); + + QVERIFY(tutorial); + QCOMPARE(tutorial->name(), QString("The \"name\"")); + QCOMPARE(tutorial->description(), + QString("The description,\nwith < and >\n")); + QCOMPARE(tutorial->licenseText(), + QString("The license text,\nwith < and >\n")); + QCOMPARE(tutorial->customSetupCode(), + QString("The setup code,\nwith < and >\n")); + QCOMPARE(tutorial->customTearDownCode(), + QString("The tear down code,\nwith < and >\n")); + QCOMPARE(tutorial->steps().count(), 2); + + Step* step = tutorial->steps()[0]; + QVERIFY(step); + QCOMPARE(step->id(), QString("The id1")); + QCOMPARE(step->text(), QString("The text,\nwith < and >\n")); + QCOMPARE(step->customSetupCode(), + QString("The setup code,\nwith < and >\n")); + QCOMPARE(step->customTearDownCode(), + QString("The tear down code,\nwith < and >\n")); + QCOMPARE(step->reactions().count(), 0); + + step = tutorial->steps()[1]; + QVERIFY(step); + QCOMPARE(step->id(), QString("The id2")); + QCOMPARE(step->text(), QString("The text2")); + QCOMPARE(step->reactions().count(), 2); + + Reaction* reaction = step->reactions()[0]; + QCOMPARE(reaction->triggerType(), Reaction::OptionSelected); + QCOMPARE(reaction->optionName(), QString("The \"option\" name")); + QCOMPARE(reaction->waitFor(), (WaitFor*)0); + QCOMPARE(reaction->responseType(), Reaction::NextStep); + QCOMPARE(reaction->customCode(), + QString("The custom code,\nwith < and >\n")); + QCOMPARE(reaction->nextStepId(), QString("Another \"id\"")); + + reaction = step->reactions()[1]; + QCOMPARE(reaction->triggerType(), Reaction::ConditionMet); + QCOMPARE(reaction->optionName(), QString("")); + QCOMPARE(reaction->responseType(), Reaction::CustomCode); + QCOMPARE(reaction->customCode(), QString("")); + QCOMPARE(reaction->nextStepId(), QString("")); + WaitFor* waitFor = reaction->waitFor(); + + WaitForComposed* waitForAnd = qobject_cast<WaitForComposed*>(waitFor); + QVERIFY(waitForAnd); + QCOMPARE(waitForAnd->compositionType(), WaitForComposed::And); + QCOMPARE(waitForAnd->waitFors().count(), 2); + assertWaitForSignal(waitForAnd->waitFors()[0], "The emitter name1", + "theSignalName1()"); + + WaitForComposed* waitForOr = + qobject_cast<WaitForComposed*>(waitForAnd->waitFors()[1]); + QVERIFY(waitForOr); + QCOMPARE(waitForOr->compositionType(), WaitForComposed::Or); + QCOMPARE(waitForOr->waitFors().count(), 2); + assertWaitForSignal(waitForOr->waitFors()[0], "The emitter name2", + "theSignalName2()"); + assertWaitForSignal(waitForOr->waitFors()[1], "The emitter name3", + "theSignalName3()"); +} + +/////////////////////////////////// Helpers //////////////////////////////////// + +void TutorialReaderTest::assertWaitForSignal(WaitFor* waitFor, + const QString& emitterName, + const QString& signalName) const { + WaitForSignal* waitForSignal = qobject_cast<WaitForSignal*>(waitFor); + QVERIFY(waitForSignal); + QCOMPARE(waitForSignal->emitterName(), emitterName); + QCOMPARE(waitForSignal->signalName(), signalName); +} + +QString TutorialReaderTest::addGarbageToXmlData(const QString& data) const { + QString garbagedData = data; + //Add a " garbage=\"trash\"" attribute to every element + garbagedData.replace(QRegExp("(<\\w+( \\w+=\"[ &;\"\\w]*\")*)(>|/>)"), + "\\1 garbage=\"trash\"\\3"); + //Add a "<garbage/>" element after each start element (even for text + //elements) + garbagedData.replace(QRegExp("(<\\w+( \\w+=\"[ &;\"\\w]*\")*>)"), + "\\1<garbage/>"); + return garbagedData; +} + +QTEST_MAIN(TutorialReaderTest) + +#include "TutorialReaderTest.moc" Property changes on: trunk/ktutorial/ktutorial-editor/tests/unit/serialization/TutorialReaderTest.cpp ___________________________________________________________________ Added: svn:eol-style + native This was sent by the SourceForge.net collaborative development platform, the world's largest Open Source development site. |
From: <dan...@us...> - 2010-03-26 19:34:28
|
Revision: 196 http://ktutorial.svn.sourceforge.net/ktutorial/?rev=196&view=rev Author: danxuliu Date: 2010-03-26 19:34:21 +0000 (Fri, 26 Mar 2010) Log Message: ----------- Fix message of DeserializationException thrown by TutorialReader Modified Paths: -------------- trunk/ktutorial/ktutorial-editor/src/serialization/DeserializationException.cpp trunk/ktutorial/ktutorial-editor/src/serialization/DeserializationException.h trunk/ktutorial/ktutorial-editor/src/serialization/TutorialReader.cpp trunk/ktutorial/ktutorial-editor/tests/unit/serialization/DeserializationExceptionTest.cpp trunk/ktutorial/ktutorial-editor/tests/unit/serialization/TutorialReaderTest.cpp Modified: trunk/ktutorial/ktutorial-editor/src/serialization/DeserializationException.cpp =================================================================== --- trunk/ktutorial/ktutorial-editor/src/serialization/DeserializationException.cpp 2010-03-26 08:49:10 UTC (rev 195) +++ trunk/ktutorial/ktutorial-editor/src/serialization/DeserializationException.cpp 2010-03-26 19:34:21 UTC (rev 196) @@ -31,3 +31,7 @@ const char* DeserializationException::what() const throw() { return mMessage.toUtf8(); } + +QString DeserializationException::message() const throw() { + return mMessage; +} Modified: trunk/ktutorial/ktutorial-editor/src/serialization/DeserializationException.h =================================================================== --- trunk/ktutorial/ktutorial-editor/src/serialization/DeserializationException.h 2010-03-26 08:49:10 UTC (rev 195) +++ trunk/ktutorial/ktutorial-editor/src/serialization/DeserializationException.h 2010-03-26 19:34:21 UTC (rev 196) @@ -39,6 +39,13 @@ */ virtual const char* what() const throw(); + /** + * Returns the exception message. + * + * @return The exception message. + */ + QString message() const throw(); + private: QString mMessage; Modified: trunk/ktutorial/ktutorial-editor/src/serialization/TutorialReader.cpp =================================================================== --- trunk/ktutorial/ktutorial-editor/src/serialization/TutorialReader.cpp 2010-03-26 08:49:10 UTC (rev 195) +++ trunk/ktutorial/ktutorial-editor/src/serialization/TutorialReader.cpp 2010-03-26 19:34:21 UTC (rev 196) @@ -20,6 +20,8 @@ #include <QDomDocument> +#include <KLocalizedString> + #include "../Reaction.h" #include "../Step.h" #include "../Tutorial.h" @@ -41,11 +43,17 @@ int errorLine; int errorColumn; - if (!document.setContent(data, &errorMessage, &errorLine, &errorColumn) || - document.documentElement().tagName() != "tutorial") { - throw DeserializationException(errorMessage); + if (!document.setContent(data, &errorMessage, &errorLine, &errorColumn)) { + throw DeserializationException(i18n("XML document is not well formed: " +"%1, line %2, column %3", errorMessage, errorLine, errorColumn)); } + if (document.documentElement().tagName() != "tutorial") { + throw DeserializationException(i18n("Unknown root element, " +"<emphasis>tutorial</emphasis> expected, got: %1", +document.documentElement().tagName())); + } + return readTutorial(document.documentElement()); } Modified: trunk/ktutorial/ktutorial-editor/tests/unit/serialization/DeserializationExceptionTest.cpp =================================================================== --- trunk/ktutorial/ktutorial-editor/tests/unit/serialization/DeserializationExceptionTest.cpp 2010-03-26 08:49:10 UTC (rev 195) +++ trunk/ktutorial/ktutorial-editor/tests/unit/serialization/DeserializationExceptionTest.cpp 2010-03-26 19:34:21 UTC (rev 196) @@ -34,12 +34,14 @@ DeserializationException exception(QString("The message")); QCOMPARE(exception.what(), "The message"); + QCOMPARE(exception.message(), QString("The message")); } void DeserializationExceptionTest::testConstructorEmpty() { DeserializationException exception; QCOMPARE(exception.what(), ""); + QCOMPARE(exception.message(), QString("")); } QTEST_MAIN(DeserializationExceptionTest) Modified: trunk/ktutorial/ktutorial-editor/tests/unit/serialization/TutorialReaderTest.cpp =================================================================== --- trunk/ktutorial/ktutorial-editor/tests/unit/serialization/TutorialReaderTest.cpp 2010-03-26 08:49:10 UTC (rev 195) +++ trunk/ktutorial/ktutorial-editor/tests/unit/serialization/TutorialReaderTest.cpp 2010-03-26 19:34:21 UTC (rev 196) @@ -20,6 +20,8 @@ #include "TutorialReader.h" +#include <KLocalizedString> + #include "../Reaction.h" #include "../Step.h" #include "../Tutorial.h" @@ -515,6 +517,7 @@ QScopedPointer<Tutorial> tutorial(reader.readTutorial(data)); QFAIL("Expected DeserializationException not thrown"); } catch (DeserializationException e) { + QVERIFY(e.message().contains(i18n("XML document is not well formed"))); } } @@ -529,6 +532,7 @@ QScopedPointer<Tutorial> tutorial(reader.readTutorial(data)); QFAIL("Expected DeserializationException not thrown"); } catch (DeserializationException e) { + QVERIFY(e.message().contains(i18n("Unknown root element"))); } } This was sent by the SourceForge.net collaborative development platform, the world's largest Open Source development site. |
From: <dan...@us...> - 2010-03-26 19:41:02
|
Revision: 197 http://ktutorial.svn.sourceforge.net/ktutorial/?rev=197&view=rev Author: danxuliu Date: 2010-03-26 19:40:54 +0000 (Fri, 26 Mar 2010) Log Message: ----------- Add loadTutorial and saveTutorial methods to Serialization facade. Modified Paths: -------------- trunk/ktutorial/ktutorial-editor/src/serialization/Serialization.cpp trunk/ktutorial/ktutorial-editor/src/serialization/Serialization.h trunk/ktutorial/ktutorial-editor/tests/unit/serialization/SerializationTest.cpp Modified: trunk/ktutorial/ktutorial-editor/src/serialization/Serialization.cpp =================================================================== --- trunk/ktutorial/ktutorial-editor/src/serialization/Serialization.cpp 2010-03-26 19:34:21 UTC (rev 196) +++ trunk/ktutorial/ktutorial-editor/src/serialization/Serialization.cpp 2010-03-26 19:40:54 UTC (rev 197) @@ -24,9 +24,41 @@ #include <KIO/NetAccess> #include "JavascriptExporter.h" +#include "TutorialReader.h" +#include "TutorialWriter.h" //public: +Tutorial* Serialization::loadTutorial(const KUrl& url) +throw (DeserializationException) { + Q_ASSERT(url.isValid()); + + QString temporaryFileName; + if (!KIO::NetAccess::download(url, temporaryFileName, 0)) { + return 0; + } + + QFile temporaryFile(temporaryFileName); + temporaryFile.open(QIODevice::ReadOnly | QIODevice::Text); + + QString data; + QTextStream in(&temporaryFile); + while (!in.atEnd()) { + data += in.readAll(); + } + temporaryFile.close(); + + return TutorialReader().readTutorial(data); +} + +bool Serialization::saveTutorial(Tutorial* tutorial, const KUrl& url) { + Q_ASSERT(tutorial); + Q_ASSERT(url.isValid()); + + QString serializedTutorial = TutorialWriter().writeTutorial(tutorial); + return writeFile(serializedTutorial, url); +} + QString Serialization::availableExporterTypes() { QStringList typeList = availableExporterTypeList(); @@ -51,14 +83,7 @@ Q_ASSERT(false); } - KTemporaryFile temporaryFile; - temporaryFile.open(); - QTextStream out(&temporaryFile); - out << exportedCode; - out.flush(); - temporaryFile.close(); - - return KIO::NetAccess::upload(temporaryFile.fileName(), url, 0); + return writeFile(exportedCode, url); } //private: @@ -69,3 +94,14 @@ "*.js|Javascript file"); return types; } + +bool Serialization::writeFile(const QString& data, const KUrl& url) { + KTemporaryFile temporaryFile; + temporaryFile.open(); + QTextStream out(&temporaryFile); + out << data; + out.flush(); + temporaryFile.close(); + + return KIO::NetAccess::upload(temporaryFile.fileName(), url, 0); +} Modified: trunk/ktutorial/ktutorial-editor/src/serialization/Serialization.h =================================================================== --- trunk/ktutorial/ktutorial-editor/src/serialization/Serialization.h 2010-03-26 19:34:21 UTC (rev 196) +++ trunk/ktutorial/ktutorial-editor/src/serialization/Serialization.h 2010-03-26 19:40:54 UTC (rev 197) @@ -21,18 +21,55 @@ #include <QStringList> +#include "DeserializationException.h" + class KUrl; class Tutorial; /** * Facade for serialization system. - * It provides the methods needed to know the available exporters and export a - * tutorial using one of them. + * It provides the methods needed to save and load a tutorial to a XML file, and + * to know the available exporters and export a tutorial to a script file using + * one of them. */ class Serialization { public: /** + * Loads a tutorial from the file specified by the given url. + * The file must be a XML file that validates against the W3C Schema in + * Tutorial.xsd. + * + * The url can be local or remote. If the file can't be saved, null is + * returned. In that case, KIO::NetAccess can be asked for the error code + * and string. + * + * @param url The url to load the tutorial from. + * @return The loaded tutorial. + * @throw DeserializationException If there was a problem deserializing the + * tutorial. + * @see TutorialReader + */ + static Tutorial* loadTutorial(const KUrl& url) + throw (DeserializationException); + + /** + * Saves the tutorial to the file specified by the given url. + * The file will be a XML file that validates against the W3C Schema in + * Tutorial.xsd. + * + * The url can be local or remote. If the file can't be saved, false is + * returned. In that case, KIO::NetAccess can be asked for the error code + * and string. + * + * @param tutorial The tutorial to save. + * @param url The url to save the tutorial to. + * @return True if the exported tutorial was saved, false otherwise. + * @see TutorialWriter + */ + static bool saveTutorial(Tutorial* tutorial, const KUrl& url); + + /** * Returns the available exporter types. * The string has the format expected by KFileDialog setFilter method, that * is, "*.fileExtension1|Human readable name1\n*.fileExtension2|Human @@ -71,6 +108,17 @@ */ static QStringList availableExporterTypeList(); + /** + * Writes the data to the file specified by the given url. + * The url can be local or remote. If the file can't be saved, false is + * returned. In that case, KIO::NetAccess can be asked for the error code + * and string. + * + * @param data The data to write to the file. + * @return True if the data was saved, false otherwise. + */ + static bool writeFile(const QString& data, const KUrl& url); + }; #endif Modified: trunk/ktutorial/ktutorial-editor/tests/unit/serialization/SerializationTest.cpp =================================================================== --- trunk/ktutorial/ktutorial-editor/tests/unit/serialization/SerializationTest.cpp 2010-03-26 19:34:21 UTC (rev 196) +++ trunk/ktutorial/ktutorial-editor/tests/unit/serialization/SerializationTest.cpp 2010-03-26 19:40:54 UTC (rev 197) @@ -36,6 +36,16 @@ void init(); void cleanup(); + void testSaveAndLoad(); + + void testLoadFromUnreadableUrl(); + void testLoadNotAnXmlFile(); + void testLoadXmlNotWellFormed(); + void testLoadXmlWithoutRootTutorialElement(); + + void testSaveToExistingUrl(); + void testSaveToUnwritableUrl(); + void testAvailableExporterTypes(); void testExportJavascript(); @@ -45,7 +55,7 @@ private: - QFile* mExportedFile; + QFile* mFile; QString readFile(QFile* file); void writeFile(QFile* file, const QString& contents); @@ -53,16 +63,120 @@ }; void SerializationTest::init() { - mExportedFile = 0; + mFile = 0; } void SerializationTest::cleanup() { - if (mExportedFile) { - mExportedFile->remove(); + if (mFile) { + mFile->remove(); } - delete mExportedFile; + delete mFile; } +void SerializationTest::testSaveAndLoad() { + Tutorial tutorial; + tutorial.setName("The name"); + tutorial.setDescription("The description"); + + KUrl url = KGlobal::dirs()->saveLocation("tmp") + "/SerializationTest.xml"; + + QVERIFY(Serialization::saveTutorial(&tutorial, url)); + + QScopedPointer<Tutorial> loadedTutorial(Serialization::loadTutorial(url)); + + QVERIFY(loadedTutorial); + QCOMPARE(loadedTutorial->name(), tutorial.name()); + QCOMPARE(loadedTutorial->description(), tutorial.description()); +} + +void SerializationTest::testLoadFromUnreadableUrl() { + KUrl url = KGlobal::dirs()->saveLocation("tmp") + "/SerializationTest.xml"; + mFile = new QFile(url.toLocalFile()); + mFile->open(QIODevice::WriteOnly | QIODevice::Text); + writeFile(mFile, "<tutorial name=\"The name\"></tutorial>"); + QVERIFY(QFile::setPermissions(mFile->fileName(), 0)); + + QVERIFY(!Serialization::loadTutorial(url)); +} + +void SerializationTest::testLoadNotAnXmlFile() { + KUrl url = KGlobal::dirs()->saveLocation("tmp") + "/SerializationTest.txt"; + mFile = new QFile(url.toLocalFile()); + mFile->open(QIODevice::WriteOnly | QIODevice::Text); + writeFile(mFile, "Not an XML file"); + + try { + QScopedPointer<Tutorial> tutorial(Serialization::loadTutorial(url)); + QFAIL("Expected DeserializationException not thrown"); + } catch (DeserializationException e) { + } +} + +void SerializationTest::testLoadXmlNotWellFormed() { + KUrl url = KGlobal::dirs()->saveLocation("tmp") + "/SerializationTest.xml"; + mFile = new QFile(url.toLocalFile()); + mFile->open(QIODevice::WriteOnly | QIODevice::Text); + writeFile(mFile, "<tutorial><step></invalidEndElement></tutorial>"); + + try { + QScopedPointer<Tutorial> tutorial(Serialization::loadTutorial(url)); + QFAIL("Expected DeserializationException not thrown"); + } catch (DeserializationException e) { + } +} + +void SerializationTest::testLoadXmlWithoutRootTutorialElement() { + KUrl url = KGlobal::dirs()->saveLocation("tmp") + "/SerializationTest.xml"; + mFile = new QFile(url.toLocalFile()); + mFile->open(QIODevice::WriteOnly | QIODevice::Text); + writeFile(mFile, "<unknownRootElement></unknownRootElement>"); + + try { + QScopedPointer<Tutorial> tutorial(Serialization::loadTutorial(url)); + QFAIL("Expected DeserializationException not thrown"); + } catch (DeserializationException e) { + } +} + +void SerializationTest::testSaveToExistingUrl() { + Tutorial tutorial; + tutorial.setName("The name"); + tutorial.setDescription("The description"); + + KUrl url = KGlobal::dirs()->saveLocation("tmp") + "/SerializationTest.xml"; + mFile = new QFile(url.toLocalFile()); + mFile->open(QIODevice::WriteOnly | QIODevice::Text); + writeFile(mFile, "Hello world!"); + + QVERIFY(Serialization::saveTutorial(&tutorial, url)); + + QVERIFY(mFile->exists()); + QVERIFY(mFile->open(QIODevice::ReadOnly | QIODevice::Text)); + + QString actualContents = readFile(mFile); + QString expectedContents = +"<?xml version=\"1.0\" encoding=\"utf-8\"?>\n" +"<tutorial name=\"The name\">\n" +" <description>The description</description>\n" +"</tutorial>\n"; + + QCOMPARE(actualContents, expectedContents); +} + +void SerializationTest::testSaveToUnwritableUrl() { + Tutorial tutorial; + tutorial.setName("The name"); + tutorial.setDescription("The description"); + + KUrl url = KGlobal::dirs()->saveLocation("tmp") + "/SerializationTest.xml"; + mFile = new QFile(url.toLocalFile()); + mFile->open(QIODevice::WriteOnly | QIODevice::Text); + writeFile(mFile, "Hello world!"); + QVERIFY(QFile::setPermissions(mFile->fileName(), 0)); + + QVERIFY(!Serialization::saveTutorial(&tutorial, url)); +} + void SerializationTest::testAvailableExporterTypes() { QString types = Serialization::availableExporterTypes(); @@ -79,11 +193,11 @@ QVERIFY(Serialization::exportTutorial(&tutorial, "*.js", url)); - mExportedFile = new QFile(url.toLocalFile()); - QVERIFY(mExportedFile->exists()); - QVERIFY(mExportedFile->open(QIODevice::ReadOnly | QIODevice::Text)); + mFile = new QFile(url.toLocalFile()); + QVERIFY(mFile->exists()); + QVERIFY(mFile->open(QIODevice::ReadOnly | QIODevice::Text)); - QString actualContents = readFile(mExportedFile); + QString actualContents = readFile(mFile); QString expectedContents = "t = Kross.module(\"kdetranslation\");\n" "\n" @@ -101,16 +215,16 @@ tutorial.setDescription("The description"); KUrl url = KGlobal::dirs()->saveLocation("tmp") + "/SerializationTest.js"; - mExportedFile = new QFile(url.toLocalFile()); - mExportedFile->open(QIODevice::WriteOnly | QIODevice::Text); - writeFile(mExportedFile, "Hello world!"); + mFile = new QFile(url.toLocalFile()); + mFile->open(QIODevice::WriteOnly | QIODevice::Text); + writeFile(mFile, "Hello world!"); QVERIFY(Serialization::exportTutorial(&tutorial, "*.js", url)); - QVERIFY(mExportedFile->exists()); - QVERIFY(mExportedFile->open(QIODevice::ReadOnly | QIODevice::Text)); + QVERIFY(mFile->exists()); + QVERIFY(mFile->open(QIODevice::ReadOnly | QIODevice::Text)); - QString actualContents = readFile(mExportedFile); + QString actualContents = readFile(mFile); QString expectedContents = "t = Kross.module(\"kdetranslation\");\n" "\n" @@ -128,10 +242,10 @@ tutorial.setDescription("The description"); KUrl url = KGlobal::dirs()->saveLocation("tmp") + "/SerializationTest.js"; - mExportedFile = new QFile(url.toLocalFile()); - mExportedFile->open(QIODevice::WriteOnly | QIODevice::Text); - writeFile(mExportedFile, "Hello world!"); - QVERIFY(QFile::setPermissions(mExportedFile->fileName(), 0)); + mFile = new QFile(url.toLocalFile()); + mFile->open(QIODevice::WriteOnly | QIODevice::Text); + writeFile(mFile, "Hello world!"); + QVERIFY(QFile::setPermissions(mFile->fileName(), 0)); QVERIFY(!Serialization::exportTutorial(&tutorial, "*.js", url)); } This was sent by the SourceForge.net collaborative development platform, the world's largest Open Source development site. |
From: <dan...@us...> - 2010-03-26 21:03:33
|
Revision: 198 http://ktutorial.svn.sourceforge.net/ktutorial/?rev=198&view=rev Author: danxuliu Date: 2010-03-26 21:03:26 +0000 (Fri, 26 Mar 2010) Log Message: ----------- -Use IOExceptions instead of return values to report errors. -Create base class Exception to be inherited by all the exceptions. It is just a subclass of std::exception using QString for the messages. Modified Paths: -------------- trunk/ktutorial/ktutorial-editor/src/CMakeLists.txt trunk/ktutorial/ktutorial-editor/src/KTutorialEditor.cpp trunk/ktutorial/ktutorial-editor/src/serialization/CMakeLists.txt trunk/ktutorial/ktutorial-editor/src/serialization/DeserializationException.cpp trunk/ktutorial/ktutorial-editor/src/serialization/DeserializationException.h trunk/ktutorial/ktutorial-editor/src/serialization/Serialization.cpp trunk/ktutorial/ktutorial-editor/src/serialization/Serialization.h trunk/ktutorial/ktutorial-editor/tests/unit/CMakeLists.txt trunk/ktutorial/ktutorial-editor/tests/unit/serialization/CMakeLists.txt trunk/ktutorial/ktutorial-editor/tests/unit/serialization/SerializationTest.cpp Added Paths: ----------- trunk/ktutorial/ktutorial-editor/src/Exception.cpp trunk/ktutorial/ktutorial-editor/src/Exception.h trunk/ktutorial/ktutorial-editor/src/serialization/IOException.cpp trunk/ktutorial/ktutorial-editor/src/serialization/IOException.h trunk/ktutorial/ktutorial-editor/tests/unit/ExceptionTest.cpp trunk/ktutorial/ktutorial-editor/tests/unit/serialization/IOExceptionTest.cpp Modified: trunk/ktutorial/ktutorial-editor/src/CMakeLists.txt =================================================================== --- trunk/ktutorial/ktutorial-editor/src/CMakeLists.txt 2010-03-26 19:40:54 UTC (rev 197) +++ trunk/ktutorial/ktutorial-editor/src/CMakeLists.txt 2010-03-26 21:03:26 UTC (rev 198) @@ -8,6 +8,7 @@ include_directories(${KDE4_INCLUDES}) set(ktutorial_editor_SRCS + Exception.cpp KTutorialEditor.cpp Reaction.cpp Step.cpp Added: trunk/ktutorial/ktutorial-editor/src/Exception.cpp =================================================================== --- trunk/ktutorial/ktutorial-editor/src/Exception.cpp (rev 0) +++ trunk/ktutorial/ktutorial-editor/src/Exception.cpp 2010-03-26 21:03:26 UTC (rev 198) @@ -0,0 +1,36 @@ +/*************************************************************************** + * 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 "Exception.h" + +//public: + +Exception::Exception(const QString& message): std::exception(), + mMessage(message) { +} + +Exception::~Exception() throw() { +} + +const char* Exception::what() const throw() { + return mMessage.toUtf8(); +} + +QString Exception::message() const throw() { + return mMessage; +} Property changes on: trunk/ktutorial/ktutorial-editor/src/Exception.cpp ___________________________________________________________________ Added: svn:eol-style + native Added: trunk/ktutorial/ktutorial-editor/src/Exception.h =================================================================== --- trunk/ktutorial/ktutorial-editor/src/Exception.h (rev 0) +++ trunk/ktutorial/ktutorial-editor/src/Exception.h 2010-03-26 21:03:26 UTC (rev 198) @@ -0,0 +1,54 @@ +/*************************************************************************** + * 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 EXCEPTION_H +#define EXCEPTION_H + +#include <exception> +#include <QString> + +/** + * Base class for exceptions. + */ +class Exception: public std::exception { +public: + + explicit Exception(const QString& message = QString()); + virtual ~Exception() throw(); + + /** + * Returns the exception message. + * + * @return The exception message. + */ + virtual const char* what() const throw(); + + /** + * Returns the exception message. + * + * @return The exception message. + */ + QString message() const throw(); + +private: + + QString mMessage; + +}; + +#endif Property changes on: trunk/ktutorial/ktutorial-editor/src/Exception.h ___________________________________________________________________ Added: svn:eol-style + native Modified: trunk/ktutorial/ktutorial-editor/src/KTutorialEditor.cpp =================================================================== --- trunk/ktutorial/ktutorial-editor/src/KTutorialEditor.cpp 2010-03-26 19:40:54 UTC (rev 197) +++ trunk/ktutorial/ktutorial-editor/src/KTutorialEditor.cpp 2010-03-26 21:03:26 UTC (rev 198) @@ -301,10 +301,12 @@ return; } - if (!Serialization::exportTutorial(mTutorial, dialog->currentFilter(), - dialog->selectedUrl())) { + try { + Serialization::exportTutorial(mTutorial, dialog->currentFilter(), + dialog->selectedUrl()); + } catch (IOException e) { QString text = i18nc("@label", "There was a problem when trying to " -"save the exported tutorial:<nl/>%1", KIO::NetAccess::lastErrorString()); +"save the exported tutorial:<nl/>%1", e.message()); QString caption = i18nc("@title:window", "Exported tutorial could not " "be saved"); KMessageBox::error(this, text, caption); Modified: trunk/ktutorial/ktutorial-editor/src/serialization/CMakeLists.txt =================================================================== --- trunk/ktutorial/ktutorial-editor/src/serialization/CMakeLists.txt 2010-03-26 19:40:54 UTC (rev 197) +++ trunk/ktutorial/ktutorial-editor/src/serialization/CMakeLists.txt 2010-03-26 21:03:26 UTC (rev 198) @@ -2,6 +2,7 @@ set(ktutorial_editor_serialization_SRCS DeserializationException.cpp + IOException.cpp JavascriptExporter.cpp Serialization.cpp TutorialReader.cpp Modified: trunk/ktutorial/ktutorial-editor/src/serialization/DeserializationException.cpp =================================================================== --- trunk/ktutorial/ktutorial-editor/src/serialization/DeserializationException.cpp 2010-03-26 19:40:54 UTC (rev 197) +++ trunk/ktutorial/ktutorial-editor/src/serialization/DeserializationException.cpp 2010-03-26 21:03:26 UTC (rev 198) @@ -21,17 +21,8 @@ //public: DeserializationException::DeserializationException(const QString& message): - std::exception(), - mMessage(message) { + Exception(message) { } DeserializationException::~DeserializationException() throw() { } - -const char* DeserializationException::what() const throw() { - return mMessage.toUtf8(); -} - -QString DeserializationException::message() const throw() { - return mMessage; -} Modified: trunk/ktutorial/ktutorial-editor/src/serialization/DeserializationException.h =================================================================== --- trunk/ktutorial/ktutorial-editor/src/serialization/DeserializationException.h 2010-03-26 19:40:54 UTC (rev 197) +++ trunk/ktutorial/ktutorial-editor/src/serialization/DeserializationException.h 2010-03-26 21:03:26 UTC (rev 198) @@ -19,37 +19,18 @@ #ifndef DESERIALIZATIONEXCEPTION_H #define DESERIALIZATIONEXCEPTION_H -#include <exception> -#include <QString> +#include "../Exception.h" /** * Thrown when the XML can't be deserialized (for example, when it isn't well * formed). */ -class DeserializationException: public std::exception { +class DeserializationException: public Exception { public: explicit DeserializationException(const QString& message = QString()); virtual ~DeserializationException() throw(); - /** - * Returns the exception message. - * - * @return The exception message. - */ - virtual const char* what() const throw(); - - /** - * Returns the exception message. - * - * @return The exception message. - */ - QString message() const throw(); - -private: - - QString mMessage; - }; #endif Added: trunk/ktutorial/ktutorial-editor/src/serialization/IOException.cpp =================================================================== --- trunk/ktutorial/ktutorial-editor/src/serialization/IOException.cpp (rev 0) +++ trunk/ktutorial/ktutorial-editor/src/serialization/IOException.cpp 2010-03-26 21:03:26 UTC (rev 198) @@ -0,0 +1,27 @@ +/*************************************************************************** + * 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 "IOException.h" + +//public: + +IOException::IOException(const QString& message): Exception(message) { +} + +IOException::~IOException() throw() { +} Property changes on: trunk/ktutorial/ktutorial-editor/src/serialization/IOException.cpp ___________________________________________________________________ Added: svn:eol-style + native Added: trunk/ktutorial/ktutorial-editor/src/serialization/IOException.h =================================================================== --- trunk/ktutorial/ktutorial-editor/src/serialization/IOException.h (rev 0) +++ trunk/ktutorial/ktutorial-editor/src/serialization/IOException.h 2010-03-26 21:03:26 UTC (rev 198) @@ -0,0 +1,36 @@ +/*************************************************************************** + * 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 IOEXCEPTION_H +#define IOEXCEPTION_H + +#include "../Exception.h" + +/** + * Thrown when an input/ouput operation fails (for example, writing to an + * unwritable file, or reading from a file that does not exist). + */ +class IOException: public Exception { +public: + + explicit IOException(const QString& message = QString()); + virtual ~IOException() throw(); + +}; + +#endif Property changes on: trunk/ktutorial/ktutorial-editor/src/serialization/IOException.h ___________________________________________________________________ Added: svn:eol-style + native Modified: trunk/ktutorial/ktutorial-editor/src/serialization/Serialization.cpp =================================================================== --- trunk/ktutorial/ktutorial-editor/src/serialization/Serialization.cpp 2010-03-26 19:40:54 UTC (rev 197) +++ trunk/ktutorial/ktutorial-editor/src/serialization/Serialization.cpp 2010-03-26 21:03:26 UTC (rev 198) @@ -30,12 +30,12 @@ //public: Tutorial* Serialization::loadTutorial(const KUrl& url) -throw (DeserializationException) { +throw (DeserializationException, IOException) { Q_ASSERT(url.isValid()); QString temporaryFileName; if (!KIO::NetAccess::download(url, temporaryFileName, 0)) { - return 0; + throw IOException(KIO::NetAccess::lastErrorString()); } QFile temporaryFile(temporaryFileName); @@ -51,12 +51,13 @@ return TutorialReader().readTutorial(data); } -bool Serialization::saveTutorial(Tutorial* tutorial, const KUrl& url) { +void Serialization::saveTutorial(Tutorial* tutorial, const KUrl& url) +throw (IOException) { Q_ASSERT(tutorial); Q_ASSERT(url.isValid()); QString serializedTutorial = TutorialWriter().writeTutorial(tutorial); - return writeFile(serializedTutorial, url); + writeFile(serializedTutorial, url); } QString Serialization::availableExporterTypes() { @@ -71,8 +72,9 @@ return types; } -bool Serialization::exportTutorial(const Tutorial* tutorial, - const QString& type, const KUrl& url) { +void Serialization::exportTutorial(const Tutorial* tutorial, + const QString& type, const KUrl& url) +throw (IOException) { Q_ASSERT(tutorial); Q_ASSERT(url.isValid()); @@ -83,7 +85,7 @@ Q_ASSERT(false); } - return writeFile(exportedCode, url); + writeFile(exportedCode, url); } //private: @@ -95,7 +97,8 @@ return types; } -bool Serialization::writeFile(const QString& data, const KUrl& url) { +void Serialization::writeFile(const QString& data, const KUrl& url) +throw (IOException) { KTemporaryFile temporaryFile; temporaryFile.open(); QTextStream out(&temporaryFile); @@ -103,5 +106,7 @@ out.flush(); temporaryFile.close(); - return KIO::NetAccess::upload(temporaryFile.fileName(), url, 0); + if (!KIO::NetAccess::upload(temporaryFile.fileName(), url, 0)) { + throw IOException(KIO::NetAccess::lastErrorString()); + } } Modified: trunk/ktutorial/ktutorial-editor/src/serialization/Serialization.h =================================================================== --- trunk/ktutorial/ktutorial-editor/src/serialization/Serialization.h 2010-03-26 19:40:54 UTC (rev 197) +++ trunk/ktutorial/ktutorial-editor/src/serialization/Serialization.h 2010-03-26 21:03:26 UTC (rev 198) @@ -22,6 +22,7 @@ #include <QStringList> #include "DeserializationException.h" +#include "IOException.h" class KUrl; class Tutorial; @@ -38,36 +39,32 @@ /** * Loads a tutorial from the file specified by the given url. * The file must be a XML file that validates against the W3C Schema in - * Tutorial.xsd. + * Tutorial.xsd. The url can be local or remote. * - * The url can be local or remote. If the file can't be saved, null is - * returned. In that case, KIO::NetAccess can be asked for the error code - * and string. - * * @param url The url to load the tutorial from. * @return The loaded tutorial. * @throw DeserializationException If there was a problem deserializing the * tutorial. + * @throw IOException If there was a problem reading the contents from the + * file. * @see TutorialReader */ static Tutorial* loadTutorial(const KUrl& url) - throw (DeserializationException); + throw (DeserializationException, IOException); /** * Saves the tutorial to the file specified by the given url. * The file will be a XML file that validates against the W3C Schema in - * Tutorial.xsd. + * Tutorial.xsd. The url can be local or remote. * - * The url can be local or remote. If the file can't be saved, false is - * returned. In that case, KIO::NetAccess can be asked for the error code - * and string. - * * @param tutorial The tutorial to save. * @param url The url to save the tutorial to. - * @return True if the exported tutorial was saved, false otherwise. + * @throw IOException If there was a problem writing the contents to the + * file. * @see TutorialWriter */ - static bool saveTutorial(Tutorial* tutorial, const KUrl& url); + static void saveTutorial(Tutorial* tutorial, const KUrl& url) + throw (IOException); /** * Returns the available exporter types. @@ -86,18 +83,16 @@ * The type must be the extension fragment of one of the types returned by * availableExporterTypes(). It is the value returned by KDialog * currentFilter() method. + * The url can be local or remote. * - * The url can be local or remote. If the file can't be saved, false is - * returned. In that case, KIO::NetAccess can be asked for the error code - * and string. - * * @param tutorial The tutorial to export. * @param type The type of the exporter to use. * @param url The url to save the script file to. - * @return True if the exported tutorial was saved, false otherwise. + * @throw IOException If there was a problem writing the contents to the + * file. */ - static bool exportTutorial(const Tutorial* tutorial, const QString& type, - const KUrl& url); + static void exportTutorial(const Tutorial* tutorial, const QString& type, + const KUrl& url) throw (IOException); private: @@ -110,14 +105,15 @@ /** * Writes the data to the file specified by the given url. - * The url can be local or remote. If the file can't be saved, false is - * returned. In that case, KIO::NetAccess can be asked for the error code - * and string. + * The url can be local or remote. * * @param data The data to write to the file. - * @return True if the data was saved, false otherwise. + * @param url The url of the file to save the data to. + * @throw IOException If there was a problem writing the contents to the + * file. */ - static bool writeFile(const QString& data, const KUrl& url); + static void writeFile(const QString& data, const KUrl& url) + throw (IOException); }; Modified: trunk/ktutorial/ktutorial-editor/tests/unit/CMakeLists.txt =================================================================== --- trunk/ktutorial/ktutorial-editor/tests/unit/CMakeLists.txt 2010-03-26 19:40:54 UTC (rev 197) +++ trunk/ktutorial/ktutorial-editor/tests/unit/CMakeLists.txt 2010-03-26 21:03:26 UTC (rev 198) @@ -16,6 +16,7 @@ ENDMACRO(UNIT_TESTS) unit_tests( + Exception Reaction Step Tutorial @@ -33,6 +34,7 @@ ENDMACRO(MEM_TESTS) mem_tests( + Exception Reaction Step Tutorial Added: trunk/ktutorial/ktutorial-editor/tests/unit/ExceptionTest.cpp =================================================================== --- trunk/ktutorial/ktutorial-editor/tests/unit/ExceptionTest.cpp (rev 0) +++ trunk/ktutorial/ktutorial-editor/tests/unit/ExceptionTest.cpp 2010-03-26 21:03:26 UTC (rev 198) @@ -0,0 +1,49 @@ +/*************************************************************************** + * 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 "Exception.h" + +class ExceptionTest: public QObject { +Q_OBJECT + +private slots: + + void testConstructor(); + void testConstructorEmpty(); + +}; + +void ExceptionTest::testConstructor() { + Exception exception(QString("The message")); + + QCOMPARE(exception.what(), "The message"); + QCOMPARE(exception.message(), QString("The message")); +} + +void ExceptionTest::testConstructorEmpty() { + Exception exception; + + QCOMPARE(exception.what(), ""); + QCOMPARE(exception.message(), QString("")); +} + +QTEST_MAIN(ExceptionTest) + +#include "ExceptionTest.moc" Property changes on: trunk/ktutorial/ktutorial-editor/tests/unit/ExceptionTest.cpp ___________________________________________________________________ Added: svn:eol-style + native Modified: trunk/ktutorial/ktutorial-editor/tests/unit/serialization/CMakeLists.txt =================================================================== --- trunk/ktutorial/ktutorial-editor/tests/unit/serialization/CMakeLists.txt 2010-03-26 19:40:54 UTC (rev 197) +++ trunk/ktutorial/ktutorial-editor/tests/unit/serialization/CMakeLists.txt 2010-03-26 21:03:26 UTC (rev 198) @@ -13,6 +13,7 @@ unit_tests( DeserializationException + IOException JavascriptExporter Serialization TutorialReader @@ -27,6 +28,7 @@ mem_tests( DeserializationException + IOException JavascriptExporter Serialization TutorialReader Added: trunk/ktutorial/ktutorial-editor/tests/unit/serialization/IOExceptionTest.cpp =================================================================== --- trunk/ktutorial/ktutorial-editor/tests/unit/serialization/IOExceptionTest.cpp (rev 0) +++ trunk/ktutorial/ktutorial-editor/tests/unit/serialization/IOExceptionTest.cpp 2010-03-26 21:03:26 UTC (rev 198) @@ -0,0 +1,49 @@ +/*************************************************************************** + * 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 "IOException.h" + +class IOExceptionTest: public QObject { +Q_OBJECT + +private slots: + + void testConstructor(); + void testConstructorEmpty(); + +}; + +void IOExceptionTest::testConstructor() { + IOException exception(QString("The message")); + + QCOMPARE(exception.what(), "The message"); + QCOMPARE(exception.message(), QString("The message")); +} + +void IOExceptionTest::testConstructorEmpty() { + IOException exception; + + QCOMPARE(exception.what(), ""); + QCOMPARE(exception.message(), QString("")); +} + +QTEST_MAIN(IOExceptionTest) + +#include "IOExceptionTest.moc" Property changes on: trunk/ktutorial/ktutorial-editor/tests/unit/serialization/IOExceptionTest.cpp ___________________________________________________________________ Added: svn:eol-style + native Modified: trunk/ktutorial/ktutorial-editor/tests/unit/serialization/SerializationTest.cpp =================================================================== --- trunk/ktutorial/ktutorial-editor/tests/unit/serialization/SerializationTest.cpp 2010-03-26 19:40:54 UTC (rev 197) +++ trunk/ktutorial/ktutorial-editor/tests/unit/serialization/SerializationTest.cpp 2010-03-26 21:03:26 UTC (rev 198) @@ -28,6 +28,17 @@ #include "../Tutorial.h" +#define EXPECT_EXCEPTION(statement, exception) \ +do {\ + try {\ + statement;\ + QFAIL("Expected " #exception " not thrown");\ + } catch (exception e) {\ + } catch (Exception e) {\ + QFAIL("Expected " #exception " not thrown");\ + }\ +} while (0) + class SerializationTest: public QObject { Q_OBJECT @@ -80,8 +91,7 @@ KUrl url = KGlobal::dirs()->saveLocation("tmp") + "/SerializationTest.xml"; - QVERIFY(Serialization::saveTutorial(&tutorial, url)); - + Serialization::saveTutorial(&tutorial, url); QScopedPointer<Tutorial> loadedTutorial(Serialization::loadTutorial(url)); QVERIFY(loadedTutorial); @@ -96,7 +106,7 @@ writeFile(mFile, "<tutorial name=\"The name\"></tutorial>"); QVERIFY(QFile::setPermissions(mFile->fileName(), 0)); - QVERIFY(!Serialization::loadTutorial(url)); + EXPECT_EXCEPTION(Serialization::loadTutorial(url), IOException); } void SerializationTest::testLoadNotAnXmlFile() { @@ -105,11 +115,8 @@ mFile->open(QIODevice::WriteOnly | QIODevice::Text); writeFile(mFile, "Not an XML file"); - try { - QScopedPointer<Tutorial> tutorial(Serialization::loadTutorial(url)); - QFAIL("Expected DeserializationException not thrown"); - } catch (DeserializationException e) { - } + EXPECT_EXCEPTION(Serialization::loadTutorial(url), + DeserializationException); } void SerializationTest::testLoadXmlNotWellFormed() { @@ -118,11 +125,8 @@ mFile->open(QIODevice::WriteOnly | QIODevice::Text); writeFile(mFile, "<tutorial><step></invalidEndElement></tutorial>"); - try { - QScopedPointer<Tutorial> tutorial(Serialization::loadTutorial(url)); - QFAIL("Expected DeserializationException not thrown"); - } catch (DeserializationException e) { - } + EXPECT_EXCEPTION(Serialization::loadTutorial(url), + DeserializationException); } void SerializationTest::testLoadXmlWithoutRootTutorialElement() { @@ -131,11 +135,8 @@ mFile->open(QIODevice::WriteOnly | QIODevice::Text); writeFile(mFile, "<unknownRootElement></unknownRootElement>"); - try { - QScopedPointer<Tutorial> tutorial(Serialization::loadTutorial(url)); - QFAIL("Expected DeserializationException not thrown"); - } catch (DeserializationException e) { - } + EXPECT_EXCEPTION(Serialization::loadTutorial(url), + DeserializationException); } void SerializationTest::testSaveToExistingUrl() { @@ -148,7 +149,7 @@ mFile->open(QIODevice::WriteOnly | QIODevice::Text); writeFile(mFile, "Hello world!"); - QVERIFY(Serialization::saveTutorial(&tutorial, url)); + Serialization::saveTutorial(&tutorial, url); QVERIFY(mFile->exists()); QVERIFY(mFile->open(QIODevice::ReadOnly | QIODevice::Text)); @@ -174,7 +175,7 @@ writeFile(mFile, "Hello world!"); QVERIFY(QFile::setPermissions(mFile->fileName(), 0)); - QVERIFY(!Serialization::saveTutorial(&tutorial, url)); + EXPECT_EXCEPTION(Serialization::saveTutorial(&tutorial, url), IOException); } void SerializationTest::testAvailableExporterTypes() { @@ -191,7 +192,7 @@ KUrl url = KGlobal::dirs()->saveLocation("tmp") + "/SerializationTest.js"; - QVERIFY(Serialization::exportTutorial(&tutorial, "*.js", url)); + Serialization::exportTutorial(&tutorial, "*.js", url); mFile = new QFile(url.toLocalFile()); QVERIFY(mFile->exists()); @@ -219,7 +220,7 @@ mFile->open(QIODevice::WriteOnly | QIODevice::Text); writeFile(mFile, "Hello world!"); - QVERIFY(Serialization::exportTutorial(&tutorial, "*.js", url)); + Serialization::exportTutorial(&tutorial, "*.js", url); QVERIFY(mFile->exists()); QVERIFY(mFile->open(QIODevice::ReadOnly | QIODevice::Text)); @@ -247,7 +248,8 @@ writeFile(mFile, "Hello world!"); QVERIFY(QFile::setPermissions(mFile->fileName(), 0)); - QVERIFY(!Serialization::exportTutorial(&tutorial, "*.js", url)); + EXPECT_EXCEPTION(Serialization::exportTutorial(&tutorial, "*.js", url), + IOException); } /////////////////////////////////// Helpers //////////////////////////////////// This was sent by the SourceForge.net collaborative development platform, the world's largest Open Source development site. |
From: <dan...@us...> - 2010-03-28 00:50:59
|
Revision: 202 http://ktutorial.svn.sourceforge.net/ktutorial/?rev=202&view=rev Author: danxuliu Date: 2010-03-28 00:50:53 +0000 (Sun, 28 Mar 2010) Log Message: ----------- Ooops, add files missed in commit 201 Added Paths: ----------- trunk/ktutorial/ktutorial-editor/src/data/CMakeLists.txt trunk/ktutorial/ktutorial-editor/tests/unit/data/CMakeLists.txt Added: trunk/ktutorial/ktutorial-editor/src/data/CMakeLists.txt =================================================================== --- trunk/ktutorial/ktutorial-editor/src/data/CMakeLists.txt (rev 0) +++ trunk/ktutorial/ktutorial-editor/src/data/CMakeLists.txt 2010-03-28 00:50:53 UTC (rev 202) @@ -0,0 +1,12 @@ +set(ktutorial_editor_data_SRCS + Reaction.cpp + Step.cpp + Tutorial.cpp + WaitFor.cpp + WaitForComposed.cpp + WaitForEvent.cpp + WaitForNot.cpp + WaitForSignal.cpp +) + +kde4_add_library(ktutorial_editor_data ${ktutorial_editor_data_SRCS}) Property changes on: trunk/ktutorial/ktutorial-editor/src/data/CMakeLists.txt ___________________________________________________________________ Added: svn:eol-style + native Added: trunk/ktutorial/ktutorial-editor/tests/unit/data/CMakeLists.txt =================================================================== --- trunk/ktutorial/ktutorial-editor/tests/unit/data/CMakeLists.txt (rev 0) +++ trunk/ktutorial/ktutorial-editor/tests/unit/data/CMakeLists.txt 2010-03-28 00:50:53 UTC (rev 202) @@ -0,0 +1,40 @@ +# Used by kde4_add_unit_test to set the full path to test executables +set(EXECUTABLE_OUTPUT_PATH ${CMAKE_CURRENT_BINARY_DIR}) + +include_directories(${ktutorial-editor_SOURCE_DIR}/src/data ${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_data ${QT_QTTEST_LIBRARY}) + ENDFOREACH(_className) +ENDMACRO(UNIT_TESTS) + +unit_tests( + Reaction + Step + Tutorial + WaitFor + WaitForComposed + WaitForEvent + WaitForNot + WaitForSignal +) + +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( + Reaction + Step + Tutorial + WaitFor + WaitForComposed + WaitForEvent + WaitForNot + WaitForSignal +) Property changes on: trunk/ktutorial/ktutorial-editor/tests/unit/data/CMakeLists.txt ___________________________________________________________________ Added: svn:eol-style + native This was sent by the SourceForge.net collaborative development platform, the world's largest Open Source development site. |
From: <dan...@us...> - 2010-03-28 00:53:47
|
Revision: 203 http://ktutorial.svn.sourceforge.net/ktutorial/?rev=203&view=rev Author: danxuliu Date: 2010-03-28 00:53:41 +0000 (Sun, 28 Mar 2010) Log Message: ----------- CMakeLists.txt cleanups Modified Paths: -------------- trunk/ktutorial/ktutorial-editor/src/CMakeLists.txt trunk/ktutorial/ktutorial-editor/src/serialization/CMakeLists.txt trunk/ktutorial/ktutorial-editor/src/view/CMakeLists.txt trunk/ktutorial/ktutorial-editor/tests/unit/CMakeLists.txt trunk/ktutorial/ktutorial-editor/tests/unit/serialization/CMakeLists.txt trunk/ktutorial/ktutorial-editor/tests/unit/view/CMakeLists.txt Modified: trunk/ktutorial/ktutorial-editor/src/CMakeLists.txt =================================================================== --- trunk/ktutorial/ktutorial-editor/src/CMakeLists.txt 2010-03-28 00:50:53 UTC (rev 202) +++ trunk/ktutorial/ktutorial-editor/src/CMakeLists.txt 2010-03-28 00:53:41 UTC (rev 203) @@ -2,12 +2,12 @@ # In order to work, they must be compiled using -fPIC add_definitions("-fPIC") +include_directories(${KDE4_INCLUDES}) + add_subdirectory(data) add_subdirectory(serialization) add_subdirectory(view) -include_directories(${KDE4_INCLUDES}) - set(ktutorial_editor_SRCS Exception.cpp KTutorialEditor.cpp @@ -23,7 +23,6 @@ ktutorial_editor_data ktutorial_editor_serialization ktutorial_editor_view - ${KDE4_KIO_LIBS} ) kde4_add_executable(ktutorial-editor main.cpp) Modified: trunk/ktutorial/ktutorial-editor/src/serialization/CMakeLists.txt =================================================================== --- trunk/ktutorial/ktutorial-editor/src/serialization/CMakeLists.txt 2010-03-28 00:50:53 UTC (rev 202) +++ trunk/ktutorial/ktutorial-editor/src/serialization/CMakeLists.txt 2010-03-28 00:53:41 UTC (rev 203) @@ -1,5 +1,3 @@ -include_directories(${KDE4_INCLUDES}) - set(ktutorial_editor_serialization_SRCS DeserializationException.cpp IOException.cpp @@ -11,4 +9,4 @@ kde4_add_library(ktutorial_editor_serialization ${ktutorial_editor_serialization_SRCS}) -target_link_libraries(ktutorial_editor_serialization ktutorial_editor ${KDE4_LIBS}) +target_link_libraries(ktutorial_editor_serialization ktutorial_editor ${KDE4_KIO_LIBS}) Modified: trunk/ktutorial/ktutorial-editor/src/view/CMakeLists.txt =================================================================== --- trunk/ktutorial/ktutorial-editor/src/view/CMakeLists.txt 2010-03-28 00:50:53 UTC (rev 202) +++ trunk/ktutorial/ktutorial-editor/src/view/CMakeLists.txt 2010-03-28 00:53:41 UTC (rev 203) @@ -1,5 +1,3 @@ -include_directories(${KDE4_INCLUDES}) - set(ktutorial_editor_view_SRCS ActionListWidget.cpp EditionDialog.cpp Modified: trunk/ktutorial/ktutorial-editor/tests/unit/CMakeLists.txt =================================================================== --- trunk/ktutorial/ktutorial-editor/tests/unit/CMakeLists.txt 2010-03-28 00:50:53 UTC (rev 202) +++ trunk/ktutorial/ktutorial-editor/tests/unit/CMakeLists.txt 2010-03-28 00:53:41 UTC (rev 203) @@ -5,7 +5,6 @@ # 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/view ${ktutorial-editor_BINARY_DIR}/src/view ${KDE4_INCLUDES}) include_directories(${ktutorial-editor_SOURCE_DIR}/src/ ${KDE4_INCLUDES}) MACRO(UNIT_TESTS) Modified: trunk/ktutorial/ktutorial-editor/tests/unit/serialization/CMakeLists.txt =================================================================== --- trunk/ktutorial/ktutorial-editor/tests/unit/serialization/CMakeLists.txt 2010-03-28 00:50:53 UTC (rev 202) +++ trunk/ktutorial/ktutorial-editor/tests/unit/serialization/CMakeLists.txt 2010-03-28 00:53:41 UTC (rev 203) @@ -1,7 +1,7 @@ # 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}) +include_directories(${ktutorial-editor_SOURCE_DIR}/src/serialization ${KDE4_INCLUDES}) MACRO(UNIT_TESTS) FOREACH(_className ${ARGN}) Modified: trunk/ktutorial/ktutorial-editor/tests/unit/view/CMakeLists.txt =================================================================== --- trunk/ktutorial/ktutorial-editor/tests/unit/view/CMakeLists.txt 2010-03-28 00:50:53 UTC (rev 202) +++ trunk/ktutorial/ktutorial-editor/tests/unit/view/CMakeLists.txt 2010-03-28 00:53:41 UTC (rev 203) @@ -1,7 +1,7 @@ # 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/view ${ktutorial-editor_BINARY_DIR}/src/view ${KDE4_INCLUDES}) +include_directories(${ktutorial-editor_SOURCE_DIR}/src/view ${KDE4_INCLUDES}) # Since Qt 4.6.0, this definition is needed for GUI testing. # It is backwards compatible with previous Qt versions, unlike the alternative This was sent by the SourceForge.net collaborative development platform, the world's largest Open Source development site. |
From: <dan...@us...> - 2010-03-29 00:36:20
|
Revision: 205 http://ktutorial.svn.sourceforge.net/ktutorial/?rev=205&view=rev Author: danxuliu Date: 2010-03-29 00:36:12 +0000 (Mon, 29 Mar 2010) Log Message: ----------- Add undo/redo support for every edit action Modified Paths: -------------- trunk/ktutorial/ktutorial-editor/src/CMakeLists.txt trunk/ktutorial/ktutorial-editor/src/KTutorialEditor.cpp trunk/ktutorial/ktutorial-editor/src/KTutorialEditor.h trunk/ktutorial/ktutorial-editor/src/view/CMakeLists.txt trunk/ktutorial/ktutorial-editor/src/view/LicenseWidget.cpp trunk/ktutorial/ktutorial-editor/src/view/LicenseWidget.h trunk/ktutorial/ktutorial-editor/src/view/ReactionWidget.cpp trunk/ktutorial/ktutorial-editor/src/view/ReactionWidget.h trunk/ktutorial/ktutorial-editor/src/view/StepCustomCodeWidget.cpp trunk/ktutorial/ktutorial-editor/src/view/StepCustomCodeWidget.h trunk/ktutorial/ktutorial-editor/src/view/StepDataWidget.cpp trunk/ktutorial/ktutorial-editor/src/view/StepDataWidget.h trunk/ktutorial/ktutorial-editor/src/view/TutorialCustomCodeWidget.cpp trunk/ktutorial/ktutorial-editor/src/view/TutorialCustomCodeWidget.h trunk/ktutorial/ktutorial-editor/src/view/TutorialInformationWidget.cpp trunk/ktutorial/ktutorial-editor/src/view/TutorialInformationWidget.h trunk/ktutorial/ktutorial-editor/tests/unit/CMakeLists.txt trunk/ktutorial/ktutorial-editor/tests/unit/view/CMakeLists.txt Added Paths: ----------- trunk/ktutorial/ktutorial-editor/src/commands/ trunk/ktutorial/ktutorial-editor/src/commands/CMakeLists.txt trunk/ktutorial/ktutorial-editor/src/commands/ReactionCommands.cpp trunk/ktutorial/ktutorial-editor/src/commands/ReactionCommands.h trunk/ktutorial/ktutorial-editor/src/commands/StepCommands.cpp trunk/ktutorial/ktutorial-editor/src/commands/StepCommands.h trunk/ktutorial/ktutorial-editor/src/commands/TutorialCommands.cpp trunk/ktutorial/ktutorial-editor/src/commands/TutorialCommands.h trunk/ktutorial/ktutorial-editor/src/view/CommandWidget.cpp trunk/ktutorial/ktutorial-editor/src/view/CommandWidget.h trunk/ktutorial/ktutorial-editor/tests/unit/commands/ trunk/ktutorial/ktutorial-editor/tests/unit/commands/CMakeLists.txt trunk/ktutorial/ktutorial-editor/tests/unit/commands/ReactionCommandsTest.cpp trunk/ktutorial/ktutorial-editor/tests/unit/commands/StepCommandsTest.cpp trunk/ktutorial/ktutorial-editor/tests/unit/commands/TutorialCommandsTest.cpp trunk/ktutorial/ktutorial-editor/tests/unit/view/CommandWidgetTest.cpp Modified: trunk/ktutorial/ktutorial-editor/src/CMakeLists.txt =================================================================== --- trunk/ktutorial/ktutorial-editor/src/CMakeLists.txt 2010-03-28 07:46:36 UTC (rev 204) +++ trunk/ktutorial/ktutorial-editor/src/CMakeLists.txt 2010-03-29 00:36:12 UTC (rev 205) @@ -4,6 +4,7 @@ include_directories(${KDE4_INCLUDES}) +add_subdirectory(commands) add_subdirectory(data) add_subdirectory(serialization) add_subdirectory(view) Modified: trunk/ktutorial/ktutorial-editor/src/KTutorialEditor.cpp =================================================================== --- trunk/ktutorial/ktutorial-editor/src/KTutorialEditor.cpp 2010-03-28 07:46:36 UTC (rev 204) +++ trunk/ktutorial/ktutorial-editor/src/KTutorialEditor.cpp 2010-03-29 00:36:12 UTC (rev 205) @@ -28,8 +28,11 @@ #include <KFileFilterCombo> #include <KLocalizedString> #include <KMessageBox> +#include <KUndoStack> #include <KIO/NetAccess> +#include "commands/StepCommands.h" +#include "commands/TutorialCommands.h" #include "data/Reaction.h" #include "data/Step.h" #include "data/Tutorial.h" @@ -57,6 +60,7 @@ mTreeView->setObjectName("centralTreeView"); setCentralWidget(mTreeView); + mUndoStack = new KUndoStack(this); setTutorialToBeEdited(); setupDocks(); @@ -105,6 +109,8 @@ connect(selectionManager, SIGNAL(reactionSelected(Reaction*)), this, SLOT(selectReaction(Reaction*))); + mUndoStack->clear(); + delete mTutorial; mTutorial = tutorial; } @@ -162,6 +168,10 @@ KStandardAction::quit(kapp, SLOT(quit()), actionCollection()); + mUndoStack->createUndoAction(actionCollection()); + + mUndoStack->createRedoAction(actionCollection()); + ActionListWidget* actionListWidget = new ActionListWidget(mTutorialActionDock); @@ -298,8 +308,10 @@ mReactionActionDock->toggleViewAction()); } -int KTutorialEditor::showEditionDialog(EditionWidget* editionWidget) { - EditionDialog* dialog = new EditionDialog(editionWidget, this); +int KTutorialEditor::showEditionDialog(CommandWidget* commandWidget) { + commandWidget->setUndoStack(mUndoStack); + + EditionDialog* dialog = new EditionDialog(commandWidget, this); dialog->setObjectName("editionDialog"); int dialogCode = dialog->exec(); dialog->deleteLater(); @@ -468,10 +480,14 @@ void KTutorialEditor::addStep() { Step* step = new Step(); - if (showEditionDialog(new StepDataWidget(step)) == QDialog::Accepted) { - mTutorial->addStep(step); - } else { - delete step; + QUndoCommand* parentCommand = new QUndoCommand(); + parentCommand->setText(i18nc("@action", "Add step")); + TutorialCommands(mTutorial).addStep(step, parentCommand); + + CommandWidget* widget = new StepDataWidget(step); + widget->setParentUndoCommand(parentCommand); + if (showEditionDialog(widget) == QDialog::Rejected) { + delete parentCommand; } } @@ -494,12 +510,7 @@ void KTutorialEditor::removeStep() { Q_ASSERT(mCurrentStep); - //When the step is removed, mCurrentStep is changed because the selected - //item in the tree view changes. As mCurrentStep is one of the valid steps - //in the tutorial, deleting it leads to a crash the next time it is used. - Step* stepToRemove = mCurrentStep; - mTutorial->removeStep(stepToRemove); - stepToRemove->deleteLater(); + mUndoStack->push(TutorialCommands(mTutorial).removeStep(mCurrentStep)); } void KTutorialEditor::addReaction() { @@ -507,10 +518,14 @@ Reaction* reaction = new Reaction(); - if (showEditionDialog(new ReactionWidget(reaction)) == QDialog::Accepted) { - mCurrentStep->addReaction(reaction); - } else { - delete reaction; + QUndoCommand* parentCommand = new QUndoCommand(); + parentCommand->setText(i18nc("@action", "Add reaction")); + StepCommands(mCurrentStep).addReaction(reaction, parentCommand); + + CommandWidget* widget = new ReactionWidget(reaction); + widget->setParentUndoCommand(parentCommand); + if (showEditionDialog(widget) == QDialog::Rejected) { + delete parentCommand; } } @@ -523,11 +538,6 @@ void KTutorialEditor::removeReaction() { Q_ASSERT(mCurrentStep); - //When the reaction is removed, mCurrentReaction is changed because the - //selected item in the tree view changes. As mCurrentReaction is one of the - //valid reactions in the step, deleting it leads to a crash the next time it - //is used. - Reaction* reactionToRemove = mCurrentReaction; - mCurrentStep->removeReaction(reactionToRemove); - reactionToRemove->deleteLater(); + mUndoStack->push(StepCommands(mCurrentStep).removeReaction( + mCurrentReaction)); } Modified: trunk/ktutorial/ktutorial-editor/src/KTutorialEditor.h =================================================================== --- trunk/ktutorial/ktutorial-editor/src/KTutorialEditor.h 2010-03-28 07:46:36 UTC (rev 204) +++ trunk/ktutorial/ktutorial-editor/src/KTutorialEditor.h 2010-03-29 00:36:12 UTC (rev 205) @@ -22,7 +22,9 @@ #include <KXmlGuiWindow> #include <KUrl> +class CommandWidget; class EditionWidget; +class KUndoStack; class QTreeView; class Reaction; class Step; @@ -64,6 +66,11 @@ QDockWidget* mReactionActionDock; /** + * The stack of undoable commands. + */ + KUndoStack* mUndoStack; + + /** * The tutorial being edited. */ Tutorial* mTutorial; @@ -115,13 +122,14 @@ void setupActions(); /** - * Shows an EditionDialog for the given EditionWidget. + * Shows an EditionDialog for the given CommandWidget. + * The undo stack used in the CommandWidget is mUndoStack. * - * @param editionWidget The EditionWidget to wrap. + * @param commandWidget The CommandWidget to wrap. * @return QDialog::Accepted if the dialog was accepted, or * QDialog::Rejected if the dialog was rejected. */ - int showEditionDialog(EditionWidget* editionWidget); + int showEditionDialog(CommandWidget* commandWidget); private Q_SLOTS: Added: trunk/ktutorial/ktutorial-editor/src/commands/CMakeLists.txt =================================================================== --- trunk/ktutorial/ktutorial-editor/src/commands/CMakeLists.txt (rev 0) +++ trunk/ktutorial/ktutorial-editor/src/commands/CMakeLists.txt 2010-03-29 00:36:12 UTC (rev 205) @@ -0,0 +1,9 @@ +set(ktutorial_editor_commands_SRCS + ReactionCommands.cpp + StepCommands.cpp + TutorialCommands.cpp +) + +kde4_add_library(ktutorial_editor_commands ${ktutorial_editor_commands_SRCS}) + +target_link_libraries(ktutorial_editor_commands ktutorial_editor_data ${KDE4_KDEUI_LIBS}) Property changes on: trunk/ktutorial/ktutorial-editor/src/commands/CMakeLists.txt ___________________________________________________________________ Added: svn:eol-style + native Added: trunk/ktutorial/ktutorial-editor/src/commands/ReactionCommands.cpp =================================================================== --- trunk/ktutorial/ktutorial-editor/src/commands/ReactionCommands.cpp (rev 0) +++ trunk/ktutorial/ktutorial-editor/src/commands/ReactionCommands.cpp 2010-03-29 00:36:12 UTC (rev 205) @@ -0,0 +1,226 @@ +/*************************************************************************** + * 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 "ReactionCommands.h" + +#include <QUndoCommand> + +#include <KLocalizedString> + +#include "../data/Reaction.h" +#include "../data/WaitFor.h" + +class SetReactionTriggerType: public QUndoCommand { +public: + + Reaction* mReaction; + Reaction::TriggerType mOldTriggerType; + Reaction::TriggerType mNewTriggerType; + + SetReactionTriggerType(QUndoCommand* parent = 0): QUndoCommand(parent) { + setText(i18nc("@action", "Set reaction trigger type")); + } + + virtual void redo() { + mOldTriggerType = mReaction->triggerType(); + mReaction->setTriggerType(mNewTriggerType); + } + + virtual void undo() { + mReaction->setTriggerType(mOldTriggerType); + } + +}; + +class SetReactionOptionName: public QUndoCommand { +public: + + Reaction* mReaction; + QString mOldOptionName; + QString mNewOptionName; + + SetReactionOptionName(QUndoCommand* parent = 0): QUndoCommand(parent) { + setText(i18nc("@action", "Set reaction option name")); + } + + virtual void redo() { + mOldOptionName = mReaction->optionName(); + mReaction->setOptionName(mNewOptionName); + } + + virtual void undo() { + mReaction->setOptionName(mOldOptionName); + } + +}; + +class SetReactionWaitFor: public QUndoCommand { +public: + + Reaction* mReaction; + WaitFor* mOldWaitFor; + WaitFor* mNewWaitFor; + bool mRedoDone; + + SetReactionWaitFor(QUndoCommand* parent = 0): QUndoCommand(parent), + mRedoDone(false) { + setText(i18nc("@action", "Set reaction condition to wait for")); + } + + virtual ~SetReactionWaitFor() { + if (mRedoDone) { + delete mOldWaitFor; + } else { + delete mNewWaitFor; + } + } + + virtual void redo() { + mRedoDone = true; + mOldWaitFor = mReaction->waitFor(); + mReaction->setWaitFor(mNewWaitFor); + } + + virtual void undo() { + mRedoDone = false; + mReaction->setWaitFor(mOldWaitFor); + } + +}; + +class SetReactionResponseType: public QUndoCommand { +public: + + Reaction* mReaction; + Reaction::ResponseType mOldResponseType; + Reaction::ResponseType mNewResponseType; + + SetReactionResponseType(QUndoCommand* parent = 0): QUndoCommand(parent) { + setText(i18nc("@action", "Set reaction response type")); + } + + virtual void redo() { + mOldResponseType = mReaction->responseType(); + mReaction->setResponseType(mNewResponseType); + } + + virtual void undo() { + mReaction->setResponseType(mOldResponseType); + } + +}; + +class SetReactionNextStepId: public QUndoCommand { +public: + + Reaction* mReaction; + QString mOldNextStepId; + QString mNewNextStepId; + + SetReactionNextStepId(QUndoCommand* parent = 0): QUndoCommand(parent) { + setText(i18nc("@action", "Set reaction next step id")); + } + + virtual void redo() { + mOldNextStepId = mReaction->nextStepId(); + mReaction->setNextStepId(mNewNextStepId); + } + + virtual void undo() { + mReaction->setNextStepId(mOldNextStepId); + } + +}; + +class SetReactionCustomCode: public QUndoCommand { +public: + + Reaction* mReaction; + QString mOldCustomCode; + QString mNewCustomCode; + + SetReactionCustomCode(QUndoCommand* parent = 0): QUndoCommand(parent) { + setText(i18nc("@action", "Set reaction custom code")); + } + + virtual void redo() { + mOldCustomCode = mReaction->customCode(); + mReaction->setCustomCode(mNewCustomCode); + } + + virtual void undo() { + mReaction->setCustomCode(mOldCustomCode); + } + +}; + +//public: + +ReactionCommands::ReactionCommands(Reaction* reaction): + mReaction(reaction) { +} + +QUndoCommand* ReactionCommands::setTriggerType( + Reaction::TriggerType triggerType, + QUndoCommand* parent) { + SetReactionTriggerType* command = new SetReactionTriggerType(parent); + command->mReaction = mReaction; + command->mNewTriggerType = triggerType; + return command; +} + +QUndoCommand* ReactionCommands::setOptionName(const QString& optionName, + QUndoCommand* parent) { + SetReactionOptionName* command = new SetReactionOptionName(parent); + command->mReaction = mReaction; + command->mNewOptionName = optionName; + return command; +} + +QUndoCommand* ReactionCommands::setWaitFor(WaitFor* waitFor, + QUndoCommand* parent) { + SetReactionWaitFor* command = new SetReactionWaitFor(parent); + command->mReaction = mReaction; + command->mNewWaitFor = waitFor; + return command; +} + +QUndoCommand* ReactionCommands::setResponseType( + Reaction::ResponseType responseType, + QUndoCommand* parent) { + SetReactionResponseType* command = new SetReactionResponseType(parent); + command->mReaction = mReaction; + command->mNewResponseType = responseType; + return command; +} + +QUndoCommand* ReactionCommands::setNextStepId(const QString& nextStepId, + QUndoCommand* parent) { + SetReactionNextStepId* command = new SetReactionNextStepId(parent); + command->mReaction = mReaction; + command->mNewNextStepId = nextStepId; + return command; +} + +QUndoCommand* ReactionCommands::setCustomCode(const QString& customCode, + QUndoCommand* parent) { + SetReactionCustomCode* command = new SetReactionCustomCode(parent); + command->mReaction = mReaction; + command->mNewCustomCode = customCode; + return command; +} Property changes on: trunk/ktutorial/ktutorial-editor/src/commands/ReactionCommands.cpp ___________________________________________________________________ Added: svn:eol-style + native Added: trunk/ktutorial/ktutorial-editor/src/commands/ReactionCommands.h =================================================================== --- trunk/ktutorial/ktutorial-editor/src/commands/ReactionCommands.h (rev 0) +++ trunk/ktutorial/ktutorial-editor/src/commands/ReactionCommands.h 2010-03-29 00:36:12 UTC (rev 205) @@ -0,0 +1,118 @@ +/*************************************************************************** + * 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 REACTIONCOMMANDS_H +#define REACTIONCOMMANDS_H + +#include <QString> + +#include "../data/Reaction.h" + +class QUndoCommand; +class WaitFor; + +/** + * Factory for reaction edition commands. + * This class provides methods to create undoable commands to edit a reaction. + * A different command is provided for each data modification method in the + * Reaction class. + * + * Note that each method just creates and returns the command. It does not + * execute it before returning. + * + * @see QUndoCommand + */ +class ReactionCommands { +public: + + /** + * Creates a new ReactionCommands for the given reaction. + * + * @param reaction The reaction to create the commands for. + */ + explicit ReactionCommands(Reaction* reaction); + + /** + * Creates a new undoable command to set the trigger type. + * + * @param triggerType The trigger type of the reaction to set. + * @param parent The parent QUndoCommand. + * @return The new QUndoCommand. + */ + QUndoCommand* setTriggerType(Reaction::TriggerType triggerType, + QUndoCommand* parent = 0); + + /** + * Creates a new undoable command to set the option name. + * + * @param optionName The option name of the reaction to set. + * @param parent The parent QUndoCommand. + * @return The new QUndoCommand. + */ + QUndoCommand* setOptionName(const QString& optionName, + QUndoCommand* parent = 0); + + /** + * Creates a new undoable command to set the condition to wait for. + * + * @param waitFor The condition to wait for of the reaction to set. + * @param parent The parent QUndoCommand. + * @return The new QUndoCommand. + */ + QUndoCommand* setWaitFor(WaitFor* waitFor, QUndoCommand* parent = 0); + + /** + * Creates a new undoable command to set the response type. + * + * @param responseType The response type of the reaction to set. + * @param parent The parent QUndoCommand. + * @return The new QUndoCommand. + */ + QUndoCommand* setResponseType(Reaction::ResponseType responseType, + QUndoCommand* parent = 0); + + /** + * Creates a new undoable command to set the next step id. + * + * @param nextStepId The next step id of the reaction to set. + * @param parent The parent QUndoCommand. + * @return The new QUndoCommand. + */ + QUndoCommand* setNextStepId(const QString& nextStepId, + QUndoCommand* parent = 0); + + /** + * Creates a new undoable command to set the custom response code. + * + * @param customCode The custom response code of the reaction to set. + * @param parent The parent QUndoCommand. + * @return The new QUndoCommand. + */ + QUndoCommand* setCustomCode(const QString& customCode, + QUndoCommand* parent = 0); + +private: + + /** + * The reaction to create the commands for. + */ + Reaction* mReaction; + +}; + +#endif Property changes on: trunk/ktutorial/ktutorial-editor/src/commands/ReactionCommands.h ___________________________________________________________________ Added: svn:eol-style + native Added: trunk/ktutorial/ktutorial-editor/src/commands/StepCommands.cpp =================================================================== --- trunk/ktutorial/ktutorial-editor/src/commands/StepCommands.cpp (rev 0) +++ trunk/ktutorial/ktutorial-editor/src/commands/StepCommands.cpp 2010-03-29 00:36:12 UTC (rev 205) @@ -0,0 +1,227 @@ +/*************************************************************************** + * 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 "StepCommands.h" + +#include <QUndoCommand> + +#include <KLocalizedString> + +#include "../data/Reaction.h" +#include "../data/Step.h" + +class SetStepId: public QUndoCommand { +public: + + Step* mStep; + QString mOldId; + QString mNewId; + + SetStepId(QUndoCommand* parent = 0): QUndoCommand(parent) { + setText(i18nc("@action", "Set step id")); + } + + virtual void redo() { + mOldId = mStep->id(); + mStep->setId(mNewId); + } + + virtual void undo() { + mStep->setId(mOldId); + } + +}; + +class SetStepText: public QUndoCommand { +public: + + Step* mStep; + QString mOldText; + QString mNewText; + + SetStepText(QUndoCommand* parent = 0): QUndoCommand(parent) { + setText(i18nc("@action", "Set step text")); + } + + virtual void redo() { + mOldText = mStep->text(); + mStep->setText(mNewText); + } + + virtual void undo() { + mStep->setText(mOldText); + } + +}; + +class SetStepCustomSetupCode: public QUndoCommand { +public: + + Step* mStep; + QString mOldCustomSetupCode; + QString mNewCustomSetupCode; + + SetStepCustomSetupCode(QUndoCommand* parent = 0): QUndoCommand(parent) { + setText(i18nc("@action", "Set step setup code")); + } + + virtual void redo() { + mOldCustomSetupCode = mStep->customSetupCode(); + mStep->setCustomSetupCode(mNewCustomSetupCode); + } + + virtual void undo() { + mStep->setCustomSetupCode(mOldCustomSetupCode); + } + +}; + +class SetStepCustomTearDownCode: public QUndoCommand { +public: + + Step* mStep; + QString mOldCustomTearDownCode; + QString mNewCustomTearDownCode; + + SetStepCustomTearDownCode(QUndoCommand* parent = 0): QUndoCommand(parent) { + setText(i18nc("@action", "Set step tear down code")); + } + + virtual void redo() { + mOldCustomTearDownCode = mStep->customTearDownCode(); + mStep->setCustomTearDownCode(mNewCustomTearDownCode); + } + + virtual void undo() { + mStep->setCustomTearDownCode(mOldCustomTearDownCode); + } + +}; + +class BaseReactionCommand: public QUndoCommand { +public: + + Step* mStep; + Reaction* mReaction; + bool mDeleteReactionInDestructor; + + BaseReactionCommand(QUndoCommand* parent = 0): QUndoCommand(parent), + mStep(0), + mReaction(0), + mDeleteReactionInDestructor(false) { + } + + virtual ~BaseReactionCommand() { + if (mDeleteReactionInDestructor) { + delete mReaction; + } + } + +}; + +class AddReaction: public BaseReactionCommand { +public: + + AddReaction(QUndoCommand* parent = 0): BaseReactionCommand(parent) { + setText(i18nc("@action", "Add reaction")); + mDeleteReactionInDestructor = true; + } + + virtual void redo() { + mDeleteReactionInDestructor = false; + mStep->addReaction(mReaction); + } + + virtual void undo() { + mDeleteReactionInDestructor = true; + mStep->removeReaction(mReaction); + } + +}; + +class RemoveReaction: public BaseReactionCommand { +public: + + RemoveReaction(QUndoCommand* parent = 0): BaseReactionCommand(parent) { + setText(i18nc("@action", "Remove reaction")); + mDeleteReactionInDestructor = false; + } + + virtual void redo() { + mDeleteReactionInDestructor = true; + mStep->removeReaction(mReaction); + } + + virtual void undo() { + mDeleteReactionInDestructor = false; + mStep->addReaction(mReaction); + } + +}; + +//public: + +StepCommands::StepCommands(Step* step): + mStep(step) { +} + +QUndoCommand* StepCommands::setId(const QString& id, QUndoCommand* parent) { + SetStepId* command = new SetStepId(parent); + command->mStep = mStep; + command->mNewId = id; + return command; +} + +QUndoCommand* StepCommands::setText(const QString& text, QUndoCommand* parent) { + SetStepText* command = new SetStepText(parent); + command->mStep = mStep; + command->mNewText = text; + return command; +} + +QUndoCommand* StepCommands::setCustomSetupCode(const QString& code, + QUndoCommand* parent) { + SetStepCustomSetupCode* command = new SetStepCustomSetupCode(parent); + command->mStep = mStep; + command->mNewCustomSetupCode = code; + return command; +} + +QUndoCommand* StepCommands::setCustomTearDownCode(const QString& code, + QUndoCommand* parent) { + SetStepCustomTearDownCode* command = new SetStepCustomTearDownCode(parent); + command->mStep = mStep; + command->mNewCustomTearDownCode = code; + return command; +} + +QUndoCommand* StepCommands::addReaction(Reaction* reaction, + QUndoCommand* parent) { + AddReaction* command = new AddReaction(parent); + command->mStep = mStep; + command->mReaction = reaction; + return command; +} + +QUndoCommand* StepCommands::removeReaction(Reaction* reaction, + QUndoCommand* parent) { + RemoveReaction* command = new RemoveReaction(parent); + command->mStep = mStep; + command->mReaction = reaction; + return command; +} Property changes on: trunk/ktutorial/ktutorial-editor/src/commands/StepCommands.cpp ___________________________________________________________________ Added: svn:eol-style + native Added: trunk/ktutorial/ktutorial-editor/src/commands/StepCommands.h =================================================================== --- trunk/ktutorial/ktutorial-editor/src/commands/StepCommands.h (rev 0) +++ trunk/ktutorial/ktutorial-editor/src/commands/StepCommands.h 2010-03-29 00:36:12 UTC (rev 205) @@ -0,0 +1,119 @@ +/*************************************************************************** + * 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 STEPCOMMANDS_H +#define STEPCOMMANDS_H + +#include <QString> + +class QUndoCommand; +class Reaction; +class Step; + +/** + * Factory for step edition commands. + * This class provides methods to create undoable commands to edit a step. + * A different command is provided for each data modification method in the Step + * class. + * + * Note that each method just creates and returns the command. It does not + * execute it before returning. + * + * @see QUndoCommand + */ +class StepCommands { +public: + + /** + * Creates a new StepCommands for the given step. + * + * @param step The step to create the commands for. + */ + explicit StepCommands(Step* step); + + /** + * Creates a new undoable command to set the step id. + * + * @param id The id of the step to set. + * @param parent The parent QUndoCommand. + * @return The new QUndoCommand. + */ + QUndoCommand* setId(const QString& id, QUndoCommand* parent = 0); + + /** + * Creates a new undoable command to set the step text. + * + * @param text The text of the step to set. + * @param parent The parent QUndoCommand. + * @return The new QUndoCommand. + */ + QUndoCommand* setText(const QString& text, QUndoCommand* parent = 0); + + /** + * Creates a new undoable command to set the step custom setup code. + * + * @param code The custom setup code of the step to set. + * @param parent The parent QUndoCommand. + * @return The new QUndoCommand. + */ + QUndoCommand* setCustomSetupCode(const QString& code, + QUndoCommand* parent = 0); + + /** + * Creates a new undoable command to set the step custom tear down code. + * + * @param code The custom tear down code of the step to set. + * @param parent The parent QUndoCommand. + * @return The new QUndoCommand. + */ + QUndoCommand* setCustomTearDownCode(const QString& code, + QUndoCommand* parent = 0); + + /** + * Creates a new undoable command to add the given reaction to the step. + * If the command was not executed yet, or it was undone, the reaction is + * deleted when the command is deleted. + * + * @param reaction The reaction to add to the step. + * @param parent The parent QUndoCommand. + * @return The new QUndoCommand. + */ + QUndoCommand* addReaction(Reaction* reaction, QUndoCommand* parent = 0); + + /** + * Creates a new undoable command to remove the given reaction from the + * step. + * If the command was executed and not undone, the reaction is deleted when + * the command is deleted. + * + * @param reaction The reaction to remove from the step. + * @param parent The parent QUndoCommand. + * @return The new QUndoCommand. + */ + QUndoCommand* removeReaction(Reaction* reaction, QUndoCommand* parent = 0); + +private: + + /** + * The step to create the commands for. + */ + Step* mStep; + +}; + +#endif Property changes on: trunk/ktutorial/ktutorial-editor/src/commands/StepCommands.h ___________________________________________________________________ Added: svn:eol-style + native Added: trunk/ktutorial/ktutorial-editor/src/commands/TutorialCommands.cpp =================================================================== --- trunk/ktutorial/ktutorial-editor/src/commands/TutorialCommands.cpp (rev 0) +++ trunk/ktutorial/ktutorial-editor/src/commands/TutorialCommands.cpp 2010-03-29 00:36:12 UTC (rev 205) @@ -0,0 +1,260 @@ +/*************************************************************************** + * 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 "TutorialCommands.h" + +#include <QUndoCommand> + +#include <KLocalizedString> + +#include "../data/Step.h" +#include "../data/Tutorial.h" + +class SetTutorialName: public QUndoCommand { +public: + + Tutorial* mTutorial; + QString mOldName; + QString mNewName; + + SetTutorialName(QUndoCommand* parent = 0): QUndoCommand(parent) { + setText(i18nc("@action", "Set tutorial name")); + } + + virtual void redo() { + mOldName = mTutorial->name(); + mTutorial->setName(mNewName); + } + + virtual void undo() { + mTutorial->setName(mOldName); + } + +}; + +class SetTutorialDescription: public QUndoCommand { +public: + + Tutorial* mTutorial; + QString mOldDescription; + QString mNewDescription; + + SetTutorialDescription(QUndoCommand* parent = 0): QUndoCommand(parent) { + setText(i18nc("@action", "Set tutorial description")); + } + + virtual void redo() { + mOldDescription = mTutorial->description(); + mTutorial->setDescription(mNewDescription); + } + + virtual void undo() { + mTutorial->setDescription(mOldDescription); + } + +}; + +class SetTutorialLicenseText: public QUndoCommand { +public: + + Tutorial* mTutorial; + QString mOldLicenseText; + QString mNewLicenseText; + + SetTutorialLicenseText(QUndoCommand* parent = 0): QUndoCommand(parent) { + setText(i18nc("@action", "Set tutorial license")); + } + + virtual void redo() { + mOldLicenseText = mTutorial->licenseText(); + mTutorial->setLicenseText(mNewLicenseText); + } + + virtual void undo() { + mTutorial->setLicenseText(mOldLicenseText); + } + +}; + +class SetTutorialCustomSetupCode: public QUndoCommand { +public: + + Tutorial* mTutorial; + QString mOldCustomSetupCode; + QString mNewCustomSetupCode; + + SetTutorialCustomSetupCode(QUndoCommand* parent = 0): QUndoCommand(parent) { + setText(i18nc("@action", "Set tutorial setup code")); + } + + virtual void redo() { + mOldCustomSetupCode = mTutorial->customSetupCode(); + mTutorial->setCustomSetupCode(mNewCustomSetupCode); + } + + virtual void undo() { + mTutorial->setCustomSetupCode(mOldCustomSetupCode); + } + +}; + +class SetTutorialCustomTearDownCode: public QUndoCommand { +public: + + Tutorial* mTutorial; + QString mOldCustomTearDownCode; + QString mNewCustomTearDownCode; + + SetTutorialCustomTearDownCode(QUndoCommand* parent = 0): + QUndoCommand(parent) { + setText(i18nc("@action", "Set tutorial tear down code")); + } + + virtual void redo() { + mOldCustomTearDownCode = mTutorial->customTearDownCode(); + mTutorial->setCustomTearDownCode(mNewCustomTearDownCode); + } + + virtual void undo() { + mTutorial->setCustomTearDownCode(mOldCustomTearDownCode); + } + +}; + +class BaseStepCommand: public QUndoCommand { +public: + + Tutorial* mTutorial; + Step* mStep; + bool mDeleteStepInDestructor; + + BaseStepCommand(QUndoCommand* parent = 0): QUndoCommand(parent), + mTutorial(0), + mStep(0), + mDeleteStepInDestructor(false) { + } + + virtual ~BaseStepCommand() { + if (mDeleteStepInDestructor) { + delete mStep; + } + } + +}; + +class AddStep: public BaseStepCommand { +public: + + AddStep(QUndoCommand* parent = 0): BaseStepCommand(parent) { + setText(i18nc("@action", "Add step")); + mDeleteStepInDestructor = true; + } + + virtual void redo() { + mDeleteStepInDestructor = false; + mTutorial->addStep(mStep); + } + + virtual void undo() { + mDeleteStepInDestructor = true; + mTutorial->removeStep(mStep); + } + +}; + +class RemoveStep: public BaseStepCommand { +public: + + RemoveStep(QUndoCommand* parent = 0): BaseStepCommand(parent) { + setText(i18nc("@action", "Remove step")); + mDeleteStepInDestructor = false; + } + + virtual void redo() { + mDeleteStepInDestructor = true; + mTutorial->removeStep(mStep); + } + + virtual void undo() { + mDeleteStepInDestructor = false; + mTutorial->addStep(mStep); + } + +}; + +//public: + +TutorialCommands::TutorialCommands(Tutorial* tutorial): + mTutorial(tutorial) { +} + +QUndoCommand* TutorialCommands::setName(const QString& name, + QUndoCommand* parent) { + SetTutorialName* command = new SetTutorialName(parent); + command->mTutorial = mTutorial; + command->mNewName = name; + return command; +} + +QUndoCommand* TutorialCommands::setDescription(const QString& description, + QUndoCommand* parent) { + SetTutorialDescription* command = new SetTutorialDescription(parent); + command->mTutorial = mTutorial; + command->mNewDescription = description; + return command; +} + +QUndoCommand* TutorialCommands::setLicenseText(const QString& licenseText, + QUndoCommand* parent) { + SetTutorialLicenseText* command = new SetTutorialLicenseText(parent); + command->mTutorial = mTutorial; + command->mNewLicenseText = licenseText; + return command; +} + +QUndoCommand* TutorialCommands::setCustomSetupCode(const QString& code, + QUndoCommand* parent) { + SetTutorialCustomSetupCode* command = + new SetTutorialCustomSetupCode(parent); + command->mTutorial = mTutorial; + command->mNewCustomSetupCode = code; + return command; +} + +QUndoCommand* TutorialCommands::setCustomTearDownCode(const QString& code, + QUndoCommand* parent) { + SetTutorialCustomTearDownCode* command = + new SetTutorialCustomTearDownCode(parent); + command->mTutorial = mTutorial; + command->mNewCustomTearDownCode = code; + return command; +} + +QUndoCommand* TutorialCommands::addStep(Step* step, QUndoCommand* parent) { + AddStep* command = new AddStep(parent); + command->mTutorial = mTutorial; + command->mStep = step; + return command; +} + +QUndoCommand* TutorialCommands::removeStep(Step* step, QUndoCommand* parent) { + RemoveStep* command = new RemoveStep(parent); + command->mTutorial = mTutorial; + command->mStep = step; + return command; +} Property changes on: trunk/ktutorial/ktutorial-editor/src/commands/TutorialCommands.cpp ___________________________________________________________________ Added: svn:eol-style + native Added: trunk/ktutorial/ktutorial-editor/src/commands/TutorialCommands.h =================================================================== --- trunk/ktutorial/ktutorial-editor/src/commands/TutorialCommands.h (rev 0) +++ trunk/ktutorial/ktutorial-editor/src/commands/TutorialCommands.h 2010-03-29 00:36:12 UTC (rev 205) @@ -0,0 +1,130 @@ +/*************************************************************************** + * 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 TUTORIALCOMMANDS_H +#define TUTORIALCOMMANDS_H + +#include <QString> + +class QUndoCommand; +class Step; +class Tutorial; + +/** + * Factory for tutorial edition commands. + * This class provides methods to create undoable commands to edit a tutorial. + * A different command is provided for each data modification method in the + * Tutorial class. + * + * Note that each method just creates and returns the command. It does not + * execute it before returning. + * + * @see QUndoCommand + */ +class TutorialCommands { +public: + + /** + * Creates a new TutorialCommands for the given tutorial. + * + * @param tutorial The tutorial to create the commands for. + */ + explicit TutorialCommands(Tutorial* tutorial); + + /** + * Creates a new undoable command to set the tutorial name. + * + * @param name The name of the tutorial to set. + * @param parent The parent QUndoCommand. + * @return The new QUndoCommand. + */ + QUndoCommand* setName(const QString& name, QUndoCommand* parent = 0); + + /** + * Creates a new undoable command to set the tutorial description. + * + * @param description The description of the tutorial to set. + * @param parent The parent QUndoCommand. + * @return The new QUndoCommand. + */ + QUndoCommand* setDescription(const QString& description, + QUndoCommand* parent = 0); + + /** + * Creates a new undoable command to set the tutorial license text. + * + * @param licenseText The license text of the tutorial to set. + * @param parent The parent QUndoCommand. + * @return The new QUndoCommand. + */ + QUndoCommand* setLicenseText(const QString& licenseText, + QUndoCommand* parent = 0); + + /** + * Creates a new undoable command to set the tutorial custom setup code. + * + * @param code The custom setup code of the tutorial to set. + * @param parent The parent QUndoCommand. + * @return The new QUndoCommand. + */ + QUndoCommand* setCustomSetupCode(const QString& code, + QUndoCommand* parent = 0); + + /** + * Creates a new undoable command to set the tutorial custom tear down code. + * + * @param code The custom tear down code of the tutorial to set. + * @param parent The parent QUndoCommand. + * @return The new QUndoCommand. + */ + QUndoCommand* setCustomTearDownCode(const QString& code, + QUndoCommand* parent = 0); + + /** + * Creates a new undoable command to add the given step to the tutorial. + * If the command was not executed yet, or it was undone, the step is + * deleted when the command is deleted. + * + * @param step The step to add to the tutorial. + * @param parent The parent QUndoCommand. + * @return The new QUndoCommand. + */ + QUndoCommand* addStep(Step* step, QUndoCommand* parent = 0); + + /** + * Creates a new undoable command to remove the given step from the + * tutorial. + * If the command was executed and not undone, the step is deleted when the + * command is deleted. + * + * @param step The step to remove from the tutorial. + * @param parent The parent QUndoCommand. + * @return The new QUndoCommand. + */ + QUndoCommand* removeStep(Step* step, QUndoCommand* parent = 0); + +private: + + /** + * The tutorial to create the commands for. + */ + Tutorial* mTutorial; + +}; + +#endif Property changes on: trunk/ktutorial/ktutorial-editor/src/commands/TutorialCommands.h ___________________________________________________________________ Added: svn:eol-style + native Modified: trunk/ktutorial/ktutorial-editor/src/view/CMakeLists.txt =================================================================== --- trunk/ktutorial/ktutorial-editor/src/view/CMakeLists.txt 2010-03-28 07:46:36 UTC (rev 204) +++ trunk/ktutorial/ktutorial-editor/src/view/CMakeLists.txt 2010-03-29 00:36:12 UTC (rev 205) @@ -1,5 +1,6 @@ set(ktutorial_editor_view_SRCS ActionListWidget.cpp + CommandWidget.cpp EditionDialog.cpp EditionWidget.cpp LicenseWidget.cpp @@ -41,4 +42,8 @@ kde4_add_library(ktutorial_editor_view ${ktutorial_editor_view_SRCS}) -target_link_libraries(ktutorial_editor_view ktutorial_editor_data ${KDE4_KDEUI_LIBS}) +target_link_libraries(ktutorial_editor_view + ktutorial_editor_commands + ktutorial_editor_data + ${KDE4_KDEUI_LIBS} +) Added: trunk/ktutorial/ktutorial-editor/src/view/CommandWidget.cpp =================================================================== --- trunk/ktutorial/ktutorial-editor/src/view/CommandWidget.cpp (rev 0) +++ trunk/ktutorial/ktutorial-editor/src/view/CommandWidget.cpp 2010-03-29 00:36:12 UTC (rev 205) @@ -0,0 +1,68 @@ +/*************************************************************************** + * 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 "CommandWidget.h" + +#include <QUndoStack> + +//public: + +CommandWidget::CommandWidget(QWidget* parent): EditionWidget(parent), + mParentUndoCommand(0), + mUndoStack(0) { +} + +void CommandWidget::saveChanges() { + QUndoCommand* parent = mParentUndoCommand; + if (!parent) { + parent = new QUndoCommand(); + } + + QList<QUndoCommand*> commands = createSaveCommands(parent); + + if (!mParentUndoCommand && commands.count() > 1) { + parent->setText(windowTitle()); + } else if (!mParentUndoCommand && commands.count() == 1) { + parent->setText(parent->child(0)->text()); + } + + if (mUndoStack && (commands.count() > 0 || mParentUndoCommand)){ + mUndoStack->push(parent); + return; + } + + if (mUndoStack) { + delete parent; + return; + } + + if (mParentUndoCommand) { + return; + } + + parent->redo(); + delete parent; +} + +void CommandWidget::setParentUndoCommand(QUndoCommand* parentUndoCommand) { + mParentUndoCommand = parentUndoCommand; +} + +void CommandWidget::setUndoStack(QUndoStack* undoStack) { + mUndoStack = undoStack; +} Property changes on: trunk/ktutorial/ktutorial-editor/src/view/CommandWidget.cpp ___________________________________________________________________ Added: svn:eol-style + native Added: trunk/ktutorial/ktutorial-editor/src/view/CommandWidget.h =================================================================== --- trunk/ktutorial/ktutorial-editor/src/view/CommandWidget.h (rev 0) +++ trunk/ktutorial/ktutorial-editor/src/view/CommandWidget.h 2010-03-29 00:36:12 UTC (rev 205) @@ -0,0 +1,122 @@ +/*************************************************************************** + * 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 COMMANDWIDGET_H +#define COMMANDWIDGET_H + +#include "EditionWidget.h" + +class QUndoCommand; +class QUndoStack; + +/** + * Base abstract class for command widgets. + * Command widgets are edition widgets that use undoable commands to save the + * data, for example, to set the name of a tutorial. + * + * To be done or undone by the user, the command must be added to a stack of + * commands. The stack that the commands will be added to can be set using + * setUndoStack(QUndoStack*) method. When the stack is set, the commands that + * are executed to save the data are added to the stack, which effectively + * causes them to be executed. + * + * However, the CommandWidget does not add the commands directly to the stack. + * Each command can have a parent command. When this happens, the child commands + * are done when their parent is done, and are undone when their parent is + * undone. It makes easier to compose several small commands to be executed as + * one bigger command. + * + * All the commands created in the widget have the same parent command, which is + * the one added directly to the stack. If no parent command was set, a new one + * is created automatically. If it has several children, its name will be the + * window title of the widget. If it has only one child, its name will be the + * name of its child. + * + * Note that if there is a stack, but no parent command and no child commands + * (for example, because there were no changes to save), the automatically + * created parent command is not added to the stack. However, if a parent + * command was explicitly set it is added to the stack even if no children were + * added to it. + * + * If no stack is set but there is a parent command, the commands will be added + * to the parent without executing them. + * + * If no stack and no parent are set, the commands will be executed when the + * changes are saved, but they will be deleted afterwards. + * + * Subclasses must implement createSaveCommands(QUndoCommand*) method. It has + * to return the list of the commands to execute to save the changes. + * + * @see QUndoCommand + */ +class CommandWidget: public EditionWidget { +Q_OBJECT +public: + + /** + * Creates a new CommandWidget with the given parent widget. + * + * @param parent The parent widget. + */ + CommandWidget(QWidget* parent = 0); + + /** + * Saves the changes to the object being edited. + */ + virtual void saveChanges(); + + /** + * Sets the parent command. + * + * @param parentUndoCommand The parent command. + */ + void setParentUndoCommand(QUndoCommand* parentUndoCommand); + + /** + * Sets the undo stack to add the commands to. + * + * @param undoStack The undo stack. + */ + void setUndoStack(QUndoStack* undoStack); + +protected: + + /** + * Creates the commands needed to save the changes. + * Subclasses must implement this method. + * + * @param parent The parent of all the created commands. + * @return A list with the commands. + */ + virtual QList<QUndoCommand*> createSaveCommands(QUndoCommand* parent) = 0; + +private: + + /** + * The explicitly set parent command. + */ + QUndoCommand* mParentUndoCommand; + + /** + * The undo stack to add the commands to. + */ + QUndoStack* mUndoStack; + +}; + +#endif Property changes on: trunk/ktutorial/ktutorial-editor/src/view/CommandWidget.h ___________________________________________________________________ Added: svn:eol-style + native Modified: trunk/ktutorial/ktutorial-editor/src/view/LicenseWidget.cpp =================================================================== --- trunk/ktutorial/ktutorial-editor/src/view/LicenseWidget.cpp 2010-03-28 07:46:36 UTC (rev 204) +++ trunk/ktutorial/ktutorial-editor/src/view/LicenseWidget.cpp 2010-03-29 00:36:12 UTC (rev 205) @@ -19,12 +19,13 @@ #include "LicenseWidget.h" #include "ui_LicenseWidget.h" +#include "../commands/TutorialCommands.h" #include "../data/Tutorial.h" //public: LicenseWidget::LicenseWidget(Tutorial* tutorial, QWidget* parent): - EditionWidget(parent), + CommandWidget(parent), mTutorial(tutorial) { ui = new Ui::LicenseWidget(); ui->setupUi(this); @@ -36,9 +37,16 @@ delete ui; } -void LicenseWidget::saveChanges() { +//protected: + +QList<QUndoCommand*> LicenseWidget::createSaveCommands(QUndoCommand* parent) { + QList<QUndoCommand*> commands; + TutorialCommands tutorialCommands(mTutorial); + QString licenseText = ui->licenseTextEdit->toPlainText(); if (mTutorial->licenseText() != licenseText) { - mTutorial->setLicenseText(licenseText); + commands.append(tutorialCommands.setLicenseText(licenseText, parent)); } + + return commands; } Modified: trunk/ktutorial/ktutorial-editor/src/view/LicenseWidget.h =================================================================== --- trunk/ktutorial/ktutorial-editor/src/view/LicenseWidget.h 2010-03-28 07:46:36 UTC (rev 204) +++ trunk/ktutorial/ktutorial-editor/src/view/LicenseWidget.h 2010-03-29 00:36:12 UTC (rev 205) @@ -19,7 +19,7 @@ #ifndef LICENSEWIDGET_H #define LICENSEWIDGET_H -#include "EditionWidget.h" +#include "CommandWidget.h" class Tutorial; @@ -28,9 +28,9 @@ } /** - * Edition widget for the license of a tutorial. + * Command widget for the license of a tutorial. */ -class LicenseWidget: public EditionWidget { +class LicenseWidget: public CommandWidget { Q_OBJECT public: @@ -47,10 +47,15 @@ */ virtual ~LicenseWidget(); +protected: + /** - * Saves the license in the tutorial. + * Commands to save the license of the tutorial. + * + * @param parent The parent command. + * @return A list with the commands. */ - virtual void saveChanges(); + virtual QList<QUndoCommand*> createSaveCommands(QUndoCommand* parent); private: Modified: trunk/ktutorial/ktutorial-editor/src/view/ReactionWidget.cpp =================================================================== --- trunk/ktutorial/ktutorial-editor/src/view/ReactionWidget.cpp 2010-03-28 07:46:36 UTC (rev 204) +++ trunk/ktutorial/ktutorial-editor/src/view/ReactionWidget.cpp 2010-03-29 00:36:12 UTC (rev 205) @@ -20,13 +20,14 @@ #include "ui_ReactionWidget.h" #include "WaitForWidget.h" +#include "../commands/ReactionCommands.h" #include "../data/Reaction.h" #include "../data/WaitFor.h" //public: ReactionWidget::ReactionWidget(Reaction* reaction, QWidget* parent): - EditionWidget(parent), + CommandWidget(parent), mReaction(reaction), mWaitForClone(0) { @@ -72,51 +73,64 @@ delete ui; } -void ReactionWidget::saveChanges() { - if (mReaction->optionName() != ui->triggerOptionLineEdit->text()) { - mReaction->setOptionName(ui->triggerOptionLineEdit->text()); +//protected: + +QList<QUndoCommand*> ReactionWidget::createSaveCommands(QUndoCommand... [truncated message content] |
From: <dan...@us...> - 2010-03-29 03:59:47
|
Revision: 207 http://ktutorial.svn.sourceforge.net/ktutorial/?rev=207&view=rev Author: danxuliu Date: 2010-03-29 03:59:41 +0000 (Mon, 29 Mar 2010) Log Message: ----------- Ensure that no unnecessary commands are created to set a WaitFor Modified Paths: -------------- trunk/ktutorial/ktutorial-editor/src/view/ReactionWidget.cpp trunk/ktutorial/ktutorial-editor/tests/unit/view/ReactionWidgetTest.cpp Modified: trunk/ktutorial/ktutorial-editor/src/view/ReactionWidget.cpp =================================================================== --- trunk/ktutorial/ktutorial-editor/src/view/ReactionWidget.cpp 2010-03-29 03:15:38 UTC (rev 206) +++ trunk/ktutorial/ktutorial-editor/src/view/ReactionWidget.cpp 2010-03-29 03:59:41 UTC (rev 207) @@ -86,8 +86,10 @@ commands.append(reactionCommands.setOptionName(optionName, parent)); } - if (!mReaction->waitFor() || !mWaitForWidget->waitFor() || - *mReaction->waitFor() != *mWaitForWidget->waitFor()) { + if ((!mReaction->waitFor() && mWaitForWidget->waitFor()) || + (mReaction->waitFor() && !mWaitForWidget->waitFor()) || + (mReaction->waitFor() && mWaitForWidget->waitFor() && + *mReaction->waitFor() != *mWaitForWidget->waitFor())) { commands.append(reactionCommands.setWaitFor(mWaitForWidget->waitFor(), parent)); Modified: trunk/ktutorial/ktutorial-editor/tests/unit/view/ReactionWidgetTest.cpp =================================================================== --- trunk/ktutorial/ktutorial-editor/tests/unit/view/ReactionWidgetTest.cpp 2010-03-29 03:15:38 UTC (rev 206) +++ trunk/ktutorial/ktutorial-editor/tests/unit/view/ReactionWidgetTest.cpp 2010-03-29 03:59:41 UTC (rev 207) @@ -22,6 +22,7 @@ #include <QRadioButton> #include <QTreeView> +#include <QUndoStack> #include <KComboBox> #include <KDialog> @@ -48,7 +49,10 @@ void testSelectResponseTypeCustomCode(); void testSaveChanges(); - void testSaveChangesWithNoWaitFor(); + void testSaveChangesAddRootWaitFor(); + void testSaveChangesRemoveRootWaitFor(); + void testSaveChangesNoOldWaitForAndNoNewWaitFor(); + void testSaveChangesEqualWaitFor(); private: @@ -63,6 +67,7 @@ void addWaitForSignal(ReactionWidget* widget); void addWaitForSignalToRootWaitFor(ReactionWidget* widget); + void removeRootWaitFor(ReactionWidget* widget); }; @@ -180,21 +185,61 @@ QCOMPARE(reaction.customCode(), QString("The custom code")); } -void ReactionWidgetTest::testSaveChangesWithNoWaitFor() { +void ReactionWidgetTest::testSaveChangesAddRootWaitFor() { Reaction reaction; reaction.setTriggerType(Reaction::ConditionMet); ReactionWidget widget(&reaction); + addWaitForSignal(&widget); widget.saveChanges(); + QVERIFY(reaction.waitFor() != 0); + QVERIFY(qobject_cast<WaitForSignal*>(reaction.waitFor())); +} + +void ReactionWidgetTest::testSaveChangesRemoveRootWaitFor() { + Reaction reaction; + reaction.setTriggerType(Reaction::ConditionMet); + reaction.setWaitFor(new WaitForSignal()); + + ReactionWidget widget(&reaction); + + removeRootWaitFor(&widget); + widget.saveChanges(); + QCOMPARE(reaction.waitFor(), (WaitFor*)0); +} +void ReactionWidgetTest::testSaveChangesNoOldWaitForAndNoNewWaitFor() { + Reaction reaction; + + ReactionWidget widget(&reaction); + + QUndoStack undoStack; + widget.setUndoStack(&undoStack); + + widget.saveChanges(); + + QCOMPARE(undoStack.count(), 0); + QCOMPARE(reaction.waitFor(), (WaitFor*)0); +} + +void ReactionWidgetTest::testSaveChangesEqualWaitFor() { + Reaction reaction; + WaitForSignal* waitFor = new WaitForSignal(); + reaction.setWaitFor(waitFor); + + ReactionWidget widget(&reaction); + + QUndoStack undoStack; + widget.setUndoStack(&undoStack); + addWaitForSignal(&widget); widget.saveChanges(); - QVERIFY(reaction.waitFor() != 0); - QVERIFY(qobject_cast<WaitForSignal*>(reaction.waitFor())); + QCOMPARE(undoStack.count(), 0); + QCOMPARE(reaction.waitFor(), waitFor); } /////////////////////////////////// Helpers //////////////////////////////////// @@ -286,6 +331,14 @@ addWaitForSignal(widget); } +void ReactionWidgetTest::removeRootWaitFor(ReactionWidget* widget) { + QTreeView* tree = widget->findChild<QTreeView*>("waitForTreeView"); + QModelIndex index = tree->model()->index(0, 0); + tree->selectionModel()->select(index, QItemSelectionModel::SelectCurrent); + + widget->findChild<KPushButton*>("removeButton")->click(); +} + QTEST_MAIN(ReactionWidgetTest) #include "ReactionWidgetTest.moc" This was sent by the SourceForge.net collaborative development platform, the world's largest Open Source development site. |