ktutorial-commits Mailing List for KTutorial (Page 4)
Status: Alpha
Brought to you by:
danxuliu
You can subscribe to this list here.
2010 |
Jan
(1) |
Feb
(36) |
Mar
(117) |
Apr
(11) |
May
(8) |
Jun
(1) |
Jul
|
Aug
(2) |
Sep
(21) |
Oct
(16) |
Nov
|
Dec
|
---|---|---|---|---|---|---|---|---|---|---|---|---|
2011 |
Jan
(1) |
Feb
|
Mar
(6) |
Apr
(6) |
May
(15) |
Jun
(15) |
Jul
(6) |
Aug
|
Sep
(1) |
Oct
(4) |
Nov
|
Dec
|
2012 |
Jan
|
Feb
|
Mar
|
Apr
|
May
|
Jun
(10) |
Jul
(4) |
Aug
(29) |
Sep
(4) |
Oct
|
Nov
|
Dec
(2) |
From: <dan...@us...> - 2011-05-28 04:00:22
|
Revision: 315 http://ktutorial.svn.sourceforge.net/ktutorial/?rev=315&view=rev Author: danxuliu Date: 2011-05-28 04:00:15 +0000 (Sat, 28 May 2011) Log Message: ----------- Provide completion in the step id line edits. StepDataWidget proposes the unused ids from all the reactions (except for the reactions of the own step), and ReactionWidget proposes the ids of all the steps (except for the step that the reaction belongs to). Modified Paths: -------------- trunk/ktutorial/ktutorial-editor/src/EditActions.cpp trunk/ktutorial/ktutorial-editor/src/view/ReactionWidget.cpp trunk/ktutorial/ktutorial-editor/src/view/ReactionWidget.h trunk/ktutorial/ktutorial-editor/src/view/StepDataWidget.cpp trunk/ktutorial/ktutorial-editor/src/view/StepDataWidget.h trunk/ktutorial/ktutorial-editor/tests/unit/view/ReactionWidgetTest.cpp trunk/ktutorial/ktutorial-editor/tests/unit/view/StepDataWidgetTest.cpp Modified: trunk/ktutorial/ktutorial-editor/src/EditActions.cpp =================================================================== --- trunk/ktutorial/ktutorial-editor/src/EditActions.cpp 2011-05-25 03:00:55 UTC (rev 314) +++ trunk/ktutorial/ktutorial-editor/src/EditActions.cpp 2011-05-28 04:00:15 UTC (rev 315) @@ -1,5 +1,5 @@ /*************************************************************************** - * Copyright (C) 2010 by Daniel Calviño Sánchez * + * Copyright (C) 2010-2011 by Daniel Calviño Sánchez * * dan...@gm... * * * * This program is free software; you can redistribute it and/or modify * @@ -264,7 +264,8 @@ parentCommand->setText(i18nc("@action", "Add step")); TutorialCommands(mTutorialEditor->tutorial()).addStep(step, parentCommand); - CommandWidget* widget = new StepDataWidget(step); + StepDataWidget* widget = new StepDataWidget(step); + widget->enableStepIdCompletion(mTutorialEditor->tutorial()); widget->setParentUndoCommand(parentCommand); if (showEditionDialog(widget) == QDialog::Rejected) { delete parentCommand; @@ -274,7 +275,9 @@ void EditActions::setStepData() { Q_ASSERT(mCurrentStep); - showEditionDialog(new StepDataWidget(mCurrentStep)); + StepDataWidget* widget = new StepDataWidget(mCurrentStep); + widget->enableStepIdCompletion(mTutorialEditor->tutorial()); + showEditionDialog(widget); } void EditActions::setStepSetup() { @@ -303,7 +306,8 @@ parentCommand->setText(i18nc("@action", "Add reaction")); StepCommands(mCurrentStep).addReaction(reaction, parentCommand); - CommandWidget* widget = new ReactionWidget(reaction); + ReactionWidget* widget = new ReactionWidget(reaction); + widget->enableStepIdCompletion(mTutorialEditor->tutorial(), mCurrentStep); widget->setParentUndoCommand(parentCommand); if (showEditionDialog(widget) == QDialog::Rejected) { delete parentCommand; @@ -313,7 +317,9 @@ void EditActions::setReactionData() { Q_ASSERT(mCurrentReaction); - showEditionDialog(new ReactionWidget(mCurrentReaction)); + ReactionWidget* widget = new ReactionWidget(mCurrentReaction); + widget->enableStepIdCompletion(mTutorialEditor->tutorial()); + showEditionDialog(widget); } void EditActions::removeReaction() { Modified: trunk/ktutorial/ktutorial-editor/src/view/ReactionWidget.cpp =================================================================== --- trunk/ktutorial/ktutorial-editor/src/view/ReactionWidget.cpp 2011-05-25 03:00:55 UTC (rev 314) +++ trunk/ktutorial/ktutorial-editor/src/view/ReactionWidget.cpp 2011-05-28 04:00:15 UTC (rev 315) @@ -1,5 +1,5 @@ /*************************************************************************** - * Copyright (C) 2010 by Daniel Calviño Sánchez * + * Copyright (C) 2010-2011 by Daniel Calviño Sánchez * * dan...@gm... * * * * This program is free software; you can redistribute it and/or modify * @@ -22,6 +22,8 @@ #include "WaitForWidget.h" #include "../commands/ReactionCommands.h" #include "../data/Reaction.h" +#include "../data/Step.h" +#include "../data/Tutorial.h" #include "../data/WaitFor.h" //public: @@ -75,6 +77,20 @@ delete ui; } +void ReactionWidget::enableStepIdCompletion(const Tutorial* tutorial, + const Step* ownStep /*= 0*/) { + QStringList stepIds; + + foreach (Step* step, tutorial->steps()) { + if (step != ownStep && !step->reactions().contains(mReaction) && + !step->id().isEmpty()) { + stepIds.append(step->id()); + } + } + + ui->responseStepLineEdit->completionObject()->setItems(stepIds); +} + //protected: QList<QUndoCommand*> ReactionWidget::createSaveCommands(QUndoCommand* parent) { Modified: trunk/ktutorial/ktutorial-editor/src/view/ReactionWidget.h =================================================================== --- trunk/ktutorial/ktutorial-editor/src/view/ReactionWidget.h 2011-05-25 03:00:55 UTC (rev 314) +++ trunk/ktutorial/ktutorial-editor/src/view/ReactionWidget.h 2011-05-28 04:00:15 UTC (rev 315) @@ -1,5 +1,5 @@ /*************************************************************************** - * Copyright (C) 2010 by Daniel Calviño Sánchez * + * Copyright (C) 2010-2011 by Daniel Calviño Sánchez * * dan...@gm... * * * * This program is free software; you can redistribute it and/or modify * @@ -24,6 +24,8 @@ #include "CommandWidget.h" #include "../data/Reaction.h" +class Step; +class Tutorial; class WaitFor; class WaitForWidget; @@ -51,6 +53,17 @@ */ virtual ~ReactionWidget(); + /** + * Enables the text completion for the id of the next step. + * The proposed ids are the ids of every step, except for the one that the + * reaction belongs to or is going to be added to. + * + * @param tutorial The tutorial to get the step ids from. + * @param ownStep The step that the reaction is going to be added to. + */ + void enableStepIdCompletion(const Tutorial* tutorial, + const Step* ownStep = 0); + protected: /** Modified: trunk/ktutorial/ktutorial-editor/src/view/StepDataWidget.cpp =================================================================== --- trunk/ktutorial/ktutorial-editor/src/view/StepDataWidget.cpp 2011-05-25 03:00:55 UTC (rev 314) +++ trunk/ktutorial/ktutorial-editor/src/view/StepDataWidget.cpp 2011-05-28 04:00:15 UTC (rev 315) @@ -24,7 +24,9 @@ #include "ui_StepDataWidget.h" #include "SemanticMarkupEdition.h" #include "../commands/StepCommands.h" +#include "../data/Reaction.h" #include "../data/Step.h" +#include "../data/Tutorial.h" //public: @@ -53,6 +55,37 @@ delete ui; } +void StepDataWidget::enableStepIdCompletion(const Tutorial* tutorial) { + QStringList usedStepIds; + QStringList nextStepIds; + + foreach (Step* step, tutorial->steps()) { + if (!step->id().isEmpty()) { + usedStepIds.append(step->id()); + } + + if (step == mStep) { + continue; + } + + foreach (Reaction* reaction, step->reactions()) { + if (!reaction->nextStepId().isEmpty()) { + nextStepIds.append(reaction->nextStepId()); + } + } + } + + QStringList unusedStepIds; + + foreach (QString nextStepId, nextStepIds) { + if (!usedStepIds.contains(nextStepId)) { + unusedStepIds.append(nextStepId); + } + } + + ui->idLineEdit->completionObject()->setItems(unusedStepIds); +} + //protected: QList<QUndoCommand*> StepDataWidget::createSaveCommands(QUndoCommand* parent) { Modified: trunk/ktutorial/ktutorial-editor/src/view/StepDataWidget.h =================================================================== --- trunk/ktutorial/ktutorial-editor/src/view/StepDataWidget.h 2011-05-25 03:00:55 UTC (rev 314) +++ trunk/ktutorial/ktutorial-editor/src/view/StepDataWidget.h 2011-05-28 04:00:15 UTC (rev 315) @@ -1,5 +1,5 @@ /*************************************************************************** - * Copyright (C) 2010 by Daniel Calviño Sánchez * + * Copyright (C) 2010-2011 by Daniel Calviño Sánchez * * dan...@gm... * * * * This program is free software; you can redistribute it and/or modify * @@ -22,6 +22,7 @@ #include "CommandWidget.h" class Step; +class Tutorial; namespace Ui { class StepDataWidget; @@ -47,6 +48,16 @@ */ virtual ~StepDataWidget(); + /** + * Enables the text completion for the id of the step. + * The proposed ids are the unused ids from all the reactions, except for + * those that belong to the step of this StepDataWidget. + * An id is unused if it is not the id of any step added in the tutorial. + * + * @param tutorial The tutorial to get the step ids from. + */ + void enableStepIdCompletion(const Tutorial* tutorial); + protected: /** Modified: trunk/ktutorial/ktutorial-editor/tests/unit/view/ReactionWidgetTest.cpp =================================================================== --- trunk/ktutorial/ktutorial-editor/tests/unit/view/ReactionWidgetTest.cpp 2011-05-25 03:00:55 UTC (rev 314) +++ trunk/ktutorial/ktutorial-editor/tests/unit/view/ReactionWidgetTest.cpp 2011-05-28 04:00:15 UTC (rev 315) @@ -1,5 +1,5 @@ /*************************************************************************** - * Copyright (C) 2010 by Daniel Calviño Sánchez * + * Copyright (C) 2010-2011 by Daniel Calviño Sánchez * * dan...@gm... * * * * This program is free software; you can redistribute it and/or modify * @@ -31,9 +31,11 @@ #include <KTextEdit> #include "WaitForWidget.h" +#include "../data/Reaction.h" +#include "../data/Step.h" +#include "../data/Tutorial.h" #include "../data/WaitForComposed.h" #include "../data/WaitForSignal.h" -#include "../data/Reaction.h" class ReactionWidgetTest: public QObject { Q_OBJECT @@ -43,6 +45,8 @@ void testConstructor(); void testConstructorWithRichText(); + void testEnableStepIdCompletion(); + void testSelectTriggerTypeOption(); void testSelectTriggerTypeCondition(); @@ -132,6 +136,48 @@ QString("<p>The custom code</p>")); } +void ReactionWidgetTest::testEnableStepIdCompletion() { + Reaction* reaction = new Reaction(); + + ReactionWidget widget(reaction); + + Tutorial tutorial; + + Step* emptyIdStep = new Step(); + emptyIdStep->setId(""); + tutorial.addStep(emptyIdStep); + + Step* firstStep = new Step(); + firstStep->setId("First step"); + tutorial.addStep(firstStep); + + Step* secondStep = new Step(); + secondStep->setId("Second step"); + tutorial.addStep(secondStep); + + Step* thirdStep = new Step(); + thirdStep->setId("Third step"); + tutorial.addStep(thirdStep); + + widget.enableStepIdCompletion(&tutorial, firstStep); + + QStringList completionItems = + responseStepLineEdit(&widget)->completionObject()->items(); + QCOMPARE(completionItems.count(), 2); + QVERIFY(completionItems.contains("Second step")); + QVERIFY(completionItems.contains("Third step")); + + secondStep->addReaction(reaction); + + widget.enableStepIdCompletion(&tutorial); + + completionItems = + responseStepLineEdit(&widget)->completionObject()->items(); + QCOMPARE(completionItems.count(), 2); + QVERIFY(completionItems.contains("First step")); + QVERIFY(completionItems.contains("Third step")); +} + void ReactionWidgetTest::testSelectTriggerTypeOption() { Reaction reaction; reaction.setTriggerType(Reaction::ConditionMet); Modified: trunk/ktutorial/ktutorial-editor/tests/unit/view/StepDataWidgetTest.cpp =================================================================== --- trunk/ktutorial/ktutorial-editor/tests/unit/view/StepDataWidgetTest.cpp 2011-05-25 03:00:55 UTC (rev 314) +++ trunk/ktutorial/ktutorial-editor/tests/unit/view/StepDataWidgetTest.cpp 2011-05-28 04:00:15 UTC (rev 315) @@ -1,5 +1,5 @@ /*************************************************************************** - * Copyright (C) 2010 by Daniel Calviño Sánchez * + * Copyright (C) 2010-2011 by Daniel Calviño Sánchez * * dan...@gm... * * * * This program is free software; you can redistribute it and/or modify * @@ -23,7 +23,9 @@ #include <KLineEdit> #include <KTextEdit> +#include "../data/Reaction.h" #include "../data/Step.h" +#include "../data/Tutorial.h" class StepDataWidgetTest: public QObject { Q_OBJECT @@ -33,6 +35,8 @@ void testConstructor(); void testConstructorWithRichText(); + void testEnableStepIdCompletion(); + void testSaveChanges(); private: @@ -68,6 +72,63 @@ QCOMPARE(textTextEdit(widget)->toPlainText(), QString("<p>The text</p>")); } +void StepDataWidgetTest::testEnableStepIdCompletion() { + Step* step = new Step; + + StepDataWidget widget(step); + + Tutorial tutorial; + tutorial.addStep(step); + + Reaction* stepFirstReaction = new Reaction(); + stepFirstReaction->setNextStepId("Unused id in the step of the widget"); + step->addReaction(stepFirstReaction); + + Step* emptyStep = new Step(); + emptyStep->setId(""); + tutorial.addStep(emptyStep); + + Step* firstStep = new Step(); + firstStep->setId("First step"); + tutorial.addStep(firstStep); + + Reaction* firstStepFirstReaction = new Reaction(); + firstStepFirstReaction->setNextStepId("Second step"); + firstStep->addReaction(firstStepFirstReaction); + + Reaction* firstStepSecondReaction = new Reaction(); + firstStepSecondReaction->setNextStepId("Unused id"); + firstStep->addReaction(firstStepSecondReaction); + + Reaction* firstStepThirdReaction = new Reaction(); + firstStepThirdReaction->setNextStepId("Duplicated unused id"); + firstStep->addReaction(firstStepThirdReaction); + + Reaction* firstStepEmptyReaction = new Reaction(); + firstStep->addReaction(firstStepEmptyReaction); + + Step* secondStep = new Step(); + secondStep->setId("Second step"); + tutorial.addStep(secondStep); + + Reaction* secondStepFirstReaction = new Reaction(); + secondStepFirstReaction->setNextStepId("Duplicated unused id"); + secondStep->addReaction(secondStepFirstReaction); + + Reaction* secondStepSecondReaction = new Reaction(); + secondStepSecondReaction->setNextStepId("Another unused id"); + secondStep->addReaction(secondStepSecondReaction); + + widget.enableStepIdCompletion(&tutorial); + + QStringList completionItems = + idLineEdit(&widget)->completionObject()->items(); + QCOMPARE(completionItems.count(), 3); + QVERIFY(completionItems.contains("Unused id")); + QVERIFY(completionItems.contains("Duplicated unused id")); + QVERIFY(completionItems.contains("Another unused id")); +} + void StepDataWidgetTest::testSaveChanges() { Step step; step.setId("The id"); This was sent by the SourceForge.net collaborative development platform, the world's largest Open Source development site. |
From: <dan...@us...> - 2011-05-25 03:01:01
|
Revision: 314 http://ktutorial.svn.sourceforge.net/ktutorial/?rev=314&view=rev Author: danxuliu Date: 2011-05-25 03:00:55 +0000 (Wed, 25 May 2011) Log Message: ----------- Fix memory leak. Modified Paths: -------------- trunk/ktutorial/ktutorial-editor/src/view/RemoteObjectNameWidget.cpp Modified: trunk/ktutorial/ktutorial-editor/src/view/RemoteObjectNameWidget.cpp =================================================================== --- trunk/ktutorial/ktutorial-editor/src/view/RemoteObjectNameWidget.cpp 2011-05-24 21:36:42 UTC (rev 313) +++ trunk/ktutorial/ktutorial-editor/src/view/RemoteObjectNameWidget.cpp 2011-05-25 03:00:55 UTC (rev 314) @@ -124,6 +124,7 @@ new RemoteObjectNameCompletion(mRemoteObjectNameRegister); completion->setOrder(KCompletion::Sorted); ui->objectNameLineEdit->setCompletionObject(completion); + ui->objectNameLineEdit->setAutoDeleteCompletionObject(true); foreach (const QString& name, mRemoteObjectNameRegister->names()) { completion->addItem(name); This was sent by the SourceForge.net collaborative development platform, the world's largest Open Source development site. |
From: <dan...@us...> - 2011-05-24 21:36:49
|
Revision: 313 http://ktutorial.svn.sourceforge.net/ktutorial/?rev=313&view=rev Author: danxuliu Date: 2011-05-24 21:36:42 +0000 (Tue, 24 May 2011) Log Message: ----------- Set the buddy for object name labels. Modified Paths: -------------- trunk/ktutorial/ktutorial-editor/src/view/RemoteObjectNameWidget.cpp trunk/ktutorial/ktutorial-editor/src/view/WaitForEventWidget.cpp trunk/ktutorial/ktutorial-editor/src/view/WaitForEventWidget.ui trunk/ktutorial/ktutorial-editor/src/view/WaitForPropertyWidget.cpp trunk/ktutorial/ktutorial-editor/src/view/WaitForPropertyWidget.ui trunk/ktutorial/ktutorial-editor/src/view/WaitForSignalWidget.cpp trunk/ktutorial/ktutorial-editor/src/view/WaitForSignalWidget.ui trunk/ktutorial/ktutorial-editor/src/view/WaitForWindowWidget.cpp trunk/ktutorial/ktutorial-editor/src/view/WaitForWindowWidget.ui trunk/ktutorial/ktutorial-editor/tests/unit/view/RemoteObjectNameWidgetTest.cpp Modified: trunk/ktutorial/ktutorial-editor/src/view/RemoteObjectNameWidget.cpp =================================================================== --- trunk/ktutorial/ktutorial-editor/src/view/RemoteObjectNameWidget.cpp 2011-05-24 16:01:19 UTC (rev 312) +++ trunk/ktutorial/ktutorial-editor/src/view/RemoteObjectNameWidget.cpp 2011-05-24 21:36:42 UTC (rev 313) @@ -111,6 +111,9 @@ ui = new Ui::RemoteObjectNameWidget(); ui->setupUi(this); + setFocusPolicy(Qt::StrongFocus); + setFocusProxy(ui->objectNameLineEdit); + connect(ui->objectNameLineEdit, SIGNAL(textChanged(QString)), this, SLOT(handleNameChanged(QString))); Modified: trunk/ktutorial/ktutorial-editor/src/view/WaitForEventWidget.cpp =================================================================== --- trunk/ktutorial/ktutorial-editor/src/view/WaitForEventWidget.cpp 2011-05-24 16:01:19 UTC (rev 312) +++ trunk/ktutorial/ktutorial-editor/src/view/WaitForEventWidget.cpp 2011-05-24 21:36:42 UTC (rev 313) @@ -1,5 +1,5 @@ /*************************************************************************** - * Copyright (C) 2010 by Daniel Calviño Sánchez * + * Copyright (C) 2010-2011 by Daniel Calviño Sánchez * * dan...@gm... * * * * This program is free software; you can redistribute it and/or modify * @@ -50,6 +50,7 @@ delete ui->receiverNameLineEdit; ui->valueVerticalLayout->insertWidget(0, mRemoteObjectNameWidget); + ui->receiverNameLabel->setBuddy(mRemoteObjectNameWidget); mRemoteObjectNameWidget->setName(waitForEvent->receiverName()); #else Modified: trunk/ktutorial/ktutorial-editor/src/view/WaitForEventWidget.ui =================================================================== --- trunk/ktutorial/ktutorial-editor/src/view/WaitForEventWidget.ui 2011-05-24 16:01:19 UTC (rev 312) +++ trunk/ktutorial/ktutorial-editor/src/view/WaitForEventWidget.ui 2011-05-24 21:36:42 UTC (rev 313) @@ -33,6 +33,9 @@ <property name="alignment"> <set>Qt::AlignRight|Qt::AlignTrailing|Qt::AlignVCenter</set> </property> + <property name="buddy"> + <cstring>receiverNameLineEdit</cstring> + </property> </widget> </item> <item> Modified: trunk/ktutorial/ktutorial-editor/src/view/WaitForPropertyWidget.cpp =================================================================== --- trunk/ktutorial/ktutorial-editor/src/view/WaitForPropertyWidget.cpp 2011-05-24 16:01:19 UTC (rev 312) +++ trunk/ktutorial/ktutorial-editor/src/view/WaitForPropertyWidget.cpp 2011-05-24 21:36:42 UTC (rev 313) @@ -51,6 +51,7 @@ delete ui->objectNameLineEdit; ui->valueVerticalLayout->insertWidget(0, mRemoteObjectNameWidget); + ui->objectNameLabel->setBuddy(mRemoteObjectNameWidget); connect(mRemoteObjectNameWidget, SIGNAL(remoteObjectChosen(RemoteObject*)), this, SLOT(setChosenRemoteObject(RemoteObject*))); Modified: trunk/ktutorial/ktutorial-editor/src/view/WaitForPropertyWidget.ui =================================================================== --- trunk/ktutorial/ktutorial-editor/src/view/WaitForPropertyWidget.ui 2011-05-24 16:01:19 UTC (rev 312) +++ trunk/ktutorial/ktutorial-editor/src/view/WaitForPropertyWidget.ui 2011-05-24 21:36:42 UTC (rev 313) @@ -33,6 +33,9 @@ <property name="alignment"> <set>Qt::AlignRight|Qt::AlignTrailing|Qt::AlignVCenter</set> </property> + <property name="buddy"> + <cstring>objectNameLineEdit</cstring> + </property> </widget> </item> <item> Modified: trunk/ktutorial/ktutorial-editor/src/view/WaitForSignalWidget.cpp =================================================================== --- trunk/ktutorial/ktutorial-editor/src/view/WaitForSignalWidget.cpp 2011-05-24 16:01:19 UTC (rev 312) +++ trunk/ktutorial/ktutorial-editor/src/view/WaitForSignalWidget.cpp 2011-05-24 21:36:42 UTC (rev 313) @@ -1,5 +1,5 @@ /*************************************************************************** - * Copyright (C) 2010 by Daniel Calviño Sánchez * + * Copyright (C) 2010-2011 by Daniel Calviño Sánchez * * dan...@gm... * * * * This program is free software; you can redistribute it and/or modify * @@ -53,6 +53,7 @@ delete ui->emitterNameLineEdit; ui->valueVerticalLayout->insertWidget(0, mRemoteObjectNameWidget); + ui->emitterNameLabel->setBuddy(mRemoteObjectNameWidget); connect(mRemoteObjectNameWidget, SIGNAL(remoteObjectChosen(RemoteObject*)), this, SLOT(setChosenRemoteObject(RemoteObject*))); Modified: trunk/ktutorial/ktutorial-editor/src/view/WaitForSignalWidget.ui =================================================================== --- trunk/ktutorial/ktutorial-editor/src/view/WaitForSignalWidget.ui 2011-05-24 16:01:19 UTC (rev 312) +++ trunk/ktutorial/ktutorial-editor/src/view/WaitForSignalWidget.ui 2011-05-24 21:36:42 UTC (rev 313) @@ -33,6 +33,9 @@ <property name="alignment"> <set>Qt::AlignRight|Qt::AlignTrailing|Qt::AlignVCenter</set> </property> + <property name="buddy"> + <cstring>emitterNameLineEdit</cstring> + </property> </widget> </item> <item> Modified: trunk/ktutorial/ktutorial-editor/src/view/WaitForWindowWidget.cpp =================================================================== --- trunk/ktutorial/ktutorial-editor/src/view/WaitForWindowWidget.cpp 2011-05-24 16:01:19 UTC (rev 312) +++ trunk/ktutorial/ktutorial-editor/src/view/WaitForWindowWidget.cpp 2011-05-24 21:36:42 UTC (rev 313) @@ -1,5 +1,5 @@ /*************************************************************************** - * Copyright (C) 2010 by Daniel Calviño Sánchez * + * Copyright (C) 2010-2011 by Daniel Calviño Sánchez * * dan...@gm... * * * * This program is free software; you can redistribute it and/or modify * @@ -42,6 +42,7 @@ mRemoteObjectNameWidget = new RemoteObjectNameWidget(this); ui->valueVerticalLayout->insertWidget(0, mRemoteObjectNameWidget); + ui->windowObjectNameLabel->setBuddy(mRemoteObjectNameWidget); mRemoteObjectNameWidget->setName(waitForWindow->windowObjectName()); #else Modified: trunk/ktutorial/ktutorial-editor/src/view/WaitForWindowWidget.ui =================================================================== --- trunk/ktutorial/ktutorial-editor/src/view/WaitForWindowWidget.ui 2011-05-24 16:01:19 UTC (rev 312) +++ trunk/ktutorial/ktutorial-editor/src/view/WaitForWindowWidget.ui 2011-05-24 21:36:42 UTC (rev 313) @@ -33,6 +33,9 @@ <property name="alignment"> <set>Qt::AlignRight|Qt::AlignTrailing|Qt::AlignVCenter</set> </property> + <property name="buddy"> + <cstring>windowObjectNameLineEdit</cstring> + </property> </widget> </item> </layout> Modified: trunk/ktutorial/ktutorial-editor/tests/unit/view/RemoteObjectNameWidgetTest.cpp =================================================================== --- trunk/ktutorial/ktutorial-editor/tests/unit/view/RemoteObjectNameWidgetTest.cpp 2011-05-24 16:01:19 UTC (rev 312) +++ trunk/ktutorial/ktutorial-editor/tests/unit/view/RemoteObjectNameWidgetTest.cpp 2011-05-24 21:36:42 UTC (rev 313) @@ -25,6 +25,7 @@ #undef private #undef protected +#include <QLabel> #include <QtDBus/QtDBus> #include <KCompletionBox> @@ -65,6 +66,10 @@ void testAddingOrRemovingRemoteObjects(); + void testSetFocus(); + + void testWidgetAsBuddyOfLabel(); + private: QString mPath; @@ -338,6 +343,56 @@ "burdensome so the test must be done manually", SkipAll); } +void RemoteObjectNameWidgetTest::testSetFocus() { + QWidget parent; + QLineEdit* otherLineEdit = new QLineEdit(&parent); + + RemoteObjectNameWidget* widget = new RemoteObjectNameWidget(&parent); + + //Focus is not set in hidden widgets until they are shown + parent.show(); + + //Give the parent widget time to be shown + QTest::qWait(500); + + otherLineEdit->setFocus(); + + QVERIFY(!widget->hasFocus()); + QVERIFY(!objectNameLineEdit(widget)->hasFocus()); + + widget->setFocus(); + + QVERIFY(widget->hasFocus()); + QVERIFY(objectNameLineEdit(widget)->hasFocus()); +} + +void RemoteObjectNameWidgetTest::testWidgetAsBuddyOfLabel() { + QWidget parent; + QLineEdit* otherLineEdit = new QLineEdit(&parent); + + RemoteObjectNameWidget* widget = new RemoteObjectNameWidget(&parent); + + QLabel* widgetLabel = new QLabel(&parent); + widgetLabel->setText("&Widget label:"); + widgetLabel->setBuddy(widget); + + //Focus is not set in hidden widgets until they are shown + parent.show(); + + //Give the parent widget time to be shown + QTest::qWait(500); + + otherLineEdit->setFocus(); + + QVERIFY(!widget->hasFocus()); + QVERIFY(!objectNameLineEdit(widget)->hasFocus()); + + QTest::keyClick(&parent, Qt::Key_W, Qt::AltModifier); + + QVERIFY(widget->hasFocus()); + QVERIFY(objectNameLineEdit(widget)->hasFocus()); +} + /////////////////////////////////// Helpers //////////////////////////////////// KLineEdit* RemoteObjectNameWidgetTest::objectNameLineEdit( This was sent by the SourceForge.net collaborative development platform, the world's largest Open Source development site. |
From: <dan...@us...> - 2011-05-24 16:01:25
|
Revision: 312 http://ktutorial.svn.sourceforge.net/ktutorial/?rev=312&view=rev Author: danxuliu Date: 2011-05-24 16:01:19 +0000 (Tue, 24 May 2011) Log Message: ----------- Remove unnecessary forward declarations. Modified Paths: -------------- trunk/ktutorial/ktutorial-editor/src/serialization/TutorialReader.h Modified: trunk/ktutorial/ktutorial-editor/src/serialization/TutorialReader.h =================================================================== --- trunk/ktutorial/ktutorial-editor/src/serialization/TutorialReader.h 2011-05-24 14:48:23 UTC (rev 311) +++ trunk/ktutorial/ktutorial-editor/src/serialization/TutorialReader.h 2011-05-24 16:01:19 UTC (rev 312) @@ -28,13 +28,6 @@ class Step; class Tutorial; class WaitFor; -class WaitForComposed; -class WaitForEvent; -class WaitForNot; -class WaitForProperty; -class WaitForSignal; -class WaitForStepActivation; -class WaitForWindow; /** * Deserializer for tutorials stored in XML. This was sent by the SourceForge.net collaborative development platform, the world's largest Open Source development site. |
From: <dan...@us...> - 2011-05-24 14:48:30
|
Revision: 311 http://ktutorial.svn.sourceforge.net/ktutorial/?rev=311&view=rev Author: danxuliu Date: 2011-05-24 14:48:23 +0000 (Tue, 24 May 2011) Log Message: ----------- Add support for WaitForStepActivation to wait for its step to be activated. Modified Paths: -------------- trunk/ktutorial/ktutorial-editor/src/data/CMakeLists.txt trunk/ktutorial/ktutorial-editor/src/serialization/JavascriptExporter.cpp trunk/ktutorial/ktutorial-editor/src/serialization/JavascriptExporter.h trunk/ktutorial/ktutorial-editor/src/serialization/TutorialReader.cpp trunk/ktutorial/ktutorial-editor/src/serialization/TutorialReader.h trunk/ktutorial/ktutorial-editor/src/serialization/TutorialWriter.cpp trunk/ktutorial/ktutorial-editor/src/serialization/TutorialWriter.h 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/src/view/WaitForWidget.h trunk/ktutorial/ktutorial-editor/tests/unit/data/CMakeLists.txt trunk/ktutorial/ktutorial-editor/tests/unit/serialization/JavascriptExporterTest.cpp trunk/ktutorial/ktutorial-editor/tests/unit/serialization/TutorialReaderTest.cpp trunk/ktutorial/ktutorial-editor/tests/unit/serialization/TutorialWriterTest.cpp 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/data/WaitForStepActivation.cpp trunk/ktutorial/ktutorial-editor/src/data/WaitForStepActivation.h trunk/ktutorial/ktutorial-editor/src/view/WaitForStepActivationTreeItem.cpp trunk/ktutorial/ktutorial-editor/src/view/WaitForStepActivationTreeItem.h trunk/ktutorial/ktutorial-editor/tests/unit/data/WaitForStepActivationTest.cpp trunk/ktutorial/ktutorial-editor/tests/unit/view/WaitForStepActivationTreeItemTest.cpp Modified: trunk/ktutorial/ktutorial-editor/src/data/CMakeLists.txt =================================================================== --- trunk/ktutorial/ktutorial-editor/src/data/CMakeLists.txt 2011-05-24 14:41:54 UTC (rev 310) +++ trunk/ktutorial/ktutorial-editor/src/data/CMakeLists.txt 2011-05-24 14:48:23 UTC (rev 311) @@ -8,6 +8,7 @@ WaitForNot.cpp WaitForProperty.cpp WaitForSignal.cpp + WaitForStepActivation.cpp WaitForWindow.cpp ) Added: trunk/ktutorial/ktutorial-editor/src/data/WaitForStepActivation.cpp =================================================================== --- trunk/ktutorial/ktutorial-editor/src/data/WaitForStepActivation.cpp (rev 0) +++ trunk/ktutorial/ktutorial-editor/src/data/WaitForStepActivation.cpp 2011-05-24 14:48:23 UTC (rev 311) @@ -0,0 +1,36 @@ +/*************************************************************************** + * Copyright (C) 2011 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 "WaitForStepActivation.h" + +//public: + +WaitForStepActivation::WaitForStepActivation(QObject* parent): WaitFor(parent) { +} + +WaitFor* WaitForStepActivation::clone() const { + return new WaitForStepActivation(); +} + +bool WaitForStepActivation::equals(const WaitFor& waitFor) const { + if (!qobject_cast<const WaitForStepActivation*>(&waitFor)) { + return false; + } + + return true; +} Property changes on: trunk/ktutorial/ktutorial-editor/src/data/WaitForStepActivation.cpp ___________________________________________________________________ Added: svn:eol-style + native Added: trunk/ktutorial/ktutorial-editor/src/data/WaitForStepActivation.h =================================================================== --- trunk/ktutorial/ktutorial-editor/src/data/WaitForStepActivation.h (rev 0) +++ trunk/ktutorial/ktutorial-editor/src/data/WaitForStepActivation.h 2011-05-24 14:48:23 UTC (rev 311) @@ -0,0 +1,51 @@ +/*************************************************************************** + * Copyright (C) 2011 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 WAITFORSTEPACTIVATION_H +#define WAITFORSTEPACTIVATION_H + +#include "WaitFor.h" + +/** + * Container for conditions that wait for their step to be activated data. + * It stores the data used in KTutorial WaitForStepActivation, 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::WaitForStepActivation object. + * + * However, it contains no attributes as WaitForStepActivation only makes sense + * to be used with the step and tutorial that contains it, and those are set + * when the tutorial is exported without needing a explicit attribute. + */ +class WaitForStepActivation: public WaitFor { +Q_OBJECT +public: + + /** + * Creates a new WaitForStepActivation. + * + * @param parent The parent QObject. + */ + WaitForStepActivation(QObject* parent = 0); + + virtual WaitFor* clone() const; + virtual bool equals(const WaitFor& waitFor) const; + +}; + +#endif Property changes on: trunk/ktutorial/ktutorial-editor/src/data/WaitForStepActivation.h ___________________________________________________________________ Added: svn:eol-style + native Modified: trunk/ktutorial/ktutorial-editor/src/serialization/JavascriptExporter.cpp =================================================================== --- trunk/ktutorial/ktutorial-editor/src/serialization/JavascriptExporter.cpp 2011-05-24 14:41:54 UTC (rev 310) +++ trunk/ktutorial/ktutorial-editor/src/serialization/JavascriptExporter.cpp 2011-05-24 14:48:23 UTC (rev 311) @@ -31,6 +31,7 @@ #include "../data/WaitForNot.h" #include "../data/WaitForProperty.h" #include "../data/WaitForSignal.h" +#include "../data/WaitForStepActivation.h" #include "../data/WaitForWindow.h" //public: @@ -277,6 +278,9 @@ if (qobject_cast<const WaitForSignal*>(waitFor)) { return writeWaitFor(static_cast<const WaitForSignal*>(waitFor)); } + if (qobject_cast<const WaitForStepActivation*>(waitFor)) { + return writeWaitFor(static_cast<const WaitForStepActivation*>(waitFor)); + } if (qobject_cast<const WaitForWindow*>(waitFor)) { return writeWaitFor(static_cast<const WaitForWindow*>(waitFor)); } @@ -408,6 +412,19 @@ return variable; } +QString JavascriptExporter::writeWaitFor( + const WaitForStepActivation* waitForStepActivation) { + Q_UNUSED(waitForStepActivation); + + QString variable = addVariable("waitForStepActivation"); + + out() << variable + << " = ktutorial.newWaitFor(\"WaitForStepActivation\");\n"; + out() << variable << ".setStep(tutorial, step);\n"; + + return variable; +} + QString JavascriptExporter::writeWaitFor(const WaitForWindow* waitForWindow) { if (waitForWindow->windowObjectName().isEmpty()) { out() << "//Error: WaitForWindow without window object name!\n"; Modified: trunk/ktutorial/ktutorial-editor/src/serialization/JavascriptExporter.h =================================================================== --- trunk/ktutorial/ktutorial-editor/src/serialization/JavascriptExporter.h 2011-05-24 14:41:54 UTC (rev 310) +++ trunk/ktutorial/ktutorial-editor/src/serialization/JavascriptExporter.h 2011-05-24 14:48:23 UTC (rev 311) @@ -32,6 +32,7 @@ class WaitForNot; class WaitForProperty; class WaitForSignal; +class WaitForStepActivation; class WaitForWindow; /** @@ -230,6 +231,14 @@ QString writeWaitFor(const WaitForSignal* waitForSignal); /** + * Writes the code to create and set a WaitForStepActivation. + * + * @param waitForStepActivation The WaitForStepActivation. + * @return The name of the variable that holds the WaitFor. + */ + QString writeWaitFor(const WaitForStepActivation* waitForStepActivation); + + /** * Writes the code to create and set a WaitForWindow. * If the window object name isn't set, an error message is written instead, * and an empty string returned. Modified: trunk/ktutorial/ktutorial-editor/src/serialization/TutorialReader.cpp =================================================================== --- trunk/ktutorial/ktutorial-editor/src/serialization/TutorialReader.cpp 2011-05-24 14:41:54 UTC (rev 310) +++ trunk/ktutorial/ktutorial-editor/src/serialization/TutorialReader.cpp 2011-05-24 14:48:23 UTC (rev 311) @@ -30,6 +30,7 @@ #include "../data/WaitForNot.h" #include "../data/WaitForProperty.h" #include "../data/WaitForSignal.h" +#include "../data/WaitForStepActivation.h" #include "../data/WaitForWindow.h" //public: @@ -172,6 +173,9 @@ if (element.tagName() == "waitForSignal") { return readWaitForSignal(element); } + if (element.tagName() == "waitForStepActivation") { + return readWaitForStepActivation(element); + } if (element.tagName() == "waitForWindow") { return readWaitForWindow(element); } @@ -262,6 +266,12 @@ return waitForSignal; } +WaitFor* TutorialReader::readWaitForStepActivation(const QDomElement& element) { + Q_UNUSED(element); + + return new WaitForStepActivation(); +} + WaitFor* TutorialReader::readWaitForWindow(const QDomElement& element) { WaitForWindow* waitForWindow = new WaitForWindow(); @@ -279,6 +289,7 @@ element.tagName() != "waitForNot" && element.tagName() != "waitForProperty" && element.tagName() != "waitForSignal" && + element.tagName() != "waitForStepActivation" && element.tagName() != "waitForWindow") { return false; } Modified: trunk/ktutorial/ktutorial-editor/src/serialization/TutorialReader.h =================================================================== --- trunk/ktutorial/ktutorial-editor/src/serialization/TutorialReader.h 2011-05-24 14:41:54 UTC (rev 310) +++ trunk/ktutorial/ktutorial-editor/src/serialization/TutorialReader.h 2011-05-24 14:48:23 UTC (rev 311) @@ -33,6 +33,7 @@ class WaitForNot; class WaitForProperty; class WaitForSignal; +class WaitForStepActivation; class WaitForWindow; /** @@ -145,6 +146,15 @@ WaitFor* readWaitForSignal(const QDomElement& element); /** + * Reads a new WaitForStepActivation from the "waitForStepActivation" XML + * element. + * + * @param element The element to read the WaitForStepActivation from. + * @return The new WaitForStepActivation. + */ + WaitFor* readWaitForStepActivation(const QDomElement& element); + + /** * Reads a new WaitForWindow from the "waitForWindow" XML element. * * @param element The element to read the WaitForWindow from. Modified: trunk/ktutorial/ktutorial-editor/src/serialization/TutorialWriter.cpp =================================================================== --- trunk/ktutorial/ktutorial-editor/src/serialization/TutorialWriter.cpp 2011-05-24 14:41:54 UTC (rev 310) +++ trunk/ktutorial/ktutorial-editor/src/serialization/TutorialWriter.cpp 2011-05-24 14:48:23 UTC (rev 311) @@ -26,6 +26,7 @@ #include "../data/WaitForNot.h" #include "../data/WaitForProperty.h" #include "../data/WaitForSignal.h" +#include "../data/WaitForStepActivation.h" #include "../data/WaitForWindow.h" //public: @@ -158,6 +159,10 @@ write(static_cast<const WaitForSignal*>(waitFor)); return; } + if (qobject_cast<const WaitForStepActivation*>(waitFor)) { + write(static_cast<const WaitForStepActivation*>(waitFor)); + return; + } if (qobject_cast<const WaitForWindow*>(waitFor)) { write(static_cast<const WaitForWindow*>(waitFor)); return; @@ -230,6 +235,10 @@ } } +void TutorialWriter::write(const WaitForStepActivation* waitForStepActivation) { + mXmlWriter->writeEmptyElement("waitForStepActivation"); +} + void TutorialWriter::write(const WaitForWindow* waitForWindow) { mXmlWriter->writeEmptyElement("waitForWindow"); Modified: trunk/ktutorial/ktutorial-editor/src/serialization/TutorialWriter.h =================================================================== --- trunk/ktutorial/ktutorial-editor/src/serialization/TutorialWriter.h 2011-05-24 14:41:54 UTC (rev 310) +++ trunk/ktutorial/ktutorial-editor/src/serialization/TutorialWriter.h 2011-05-24 14:48:23 UTC (rev 311) @@ -30,6 +30,7 @@ class WaitForNot; class WaitForProperty; class WaitForSignal; +class WaitForStepActivation; class WaitForWindow; /** @@ -131,6 +132,14 @@ void write(const WaitForSignal* waitForSignal); /** + * Writes the XML serialization of the given WaitForStepActivation. + * + * @param waitForStepActivation The WaitForStepActivation to get its XML + * serialization. + */ + void write(const WaitForStepActivation* WaitForStepActivation); + + /** * Writes the XML serialization of the given WaitForWindow. * * @param waitForWindow The WaitForWindow to get its XML serialization. Modified: trunk/ktutorial/ktutorial-editor/src/view/CMakeLists.txt =================================================================== --- trunk/ktutorial/ktutorial-editor/src/view/CMakeLists.txt 2011-05-24 14:41:54 UTC (rev 310) +++ trunk/ktutorial/ktutorial-editor/src/view/CMakeLists.txt 2011-05-24 14:48:23 UTC (rev 311) @@ -31,6 +31,7 @@ WaitForPropertyWidget.cpp WaitForSignalTreeItem.cpp WaitForSignalWidget.cpp + WaitForStepActivationTreeItem.cpp WaitForTreeItem.cpp WaitForWidget.cpp WaitForWindowTreeItem.cpp Modified: trunk/ktutorial/ktutorial-editor/src/view/NewWaitForWidget.cpp =================================================================== --- trunk/ktutorial/ktutorial-editor/src/view/NewWaitForWidget.cpp 2011-05-24 14:41:54 UTC (rev 310) +++ trunk/ktutorial/ktutorial-editor/src/view/NewWaitForWidget.cpp 2011-05-24 14:48:23 UTC (rev 311) @@ -24,6 +24,7 @@ #include "../data/WaitForNot.h" #include "../data/WaitForProperty.h" #include "../data/WaitForSignal.h" +#include "../data/WaitForStepActivation.h" #include "../data/WaitForWindow.h" //public: @@ -58,6 +59,8 @@ return new WaitForWindow(); } else if (index == 6) { return new WaitForProperty(); + } else if (index == 7) { + return new WaitForStepActivation(); } return 0; Modified: trunk/ktutorial/ktutorial-editor/src/view/NewWaitForWidget.ui =================================================================== --- trunk/ktutorial/ktutorial-editor/src/view/NewWaitForWidget.ui 2011-05-24 14:41:54 UTC (rev 310) +++ trunk/ktutorial/ktutorial-editor/src/view/NewWaitForWidget.ui 2011-05-24 14:48:23 UTC (rev 311) @@ -76,6 +76,11 @@ <string comment="@item:inlistbox">The specified property has certain value</string> </property> </item> + <item> + <property name="text"> + <string comment="@item:inlistbox">The step is activated</string> + </property> + </item> </widget> </item> </layout> Added: trunk/ktutorial/ktutorial-editor/src/view/WaitForStepActivationTreeItem.cpp =================================================================== --- trunk/ktutorial/ktutorial-editor/src/view/WaitForStepActivationTreeItem.cpp (rev 0) +++ trunk/ktutorial/ktutorial-editor/src/view/WaitForStepActivationTreeItem.cpp 2011-05-24 14:48:23 UTC (rev 311) @@ -0,0 +1,35 @@ +/*************************************************************************** + * Copyright (C) 2011 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 "WaitForStepActivationTreeItem.h" + +#include <KLocalizedString> + +#include "../data/WaitForStepActivation.h" + +//public: + +WaitForStepActivationTreeItem::WaitForStepActivationTreeItem( + WaitForStepActivation* waitForStepActivation, + TreeItem* parent): + WaitForTreeItem(waitForStepActivation, parent) { +} + +QString WaitForStepActivationTreeItem::text() const { + return i18nc("@item", "When the step is activated"); +} Property changes on: trunk/ktutorial/ktutorial-editor/src/view/WaitForStepActivationTreeItem.cpp ___________________________________________________________________ Added: svn:eol-style + native Added: trunk/ktutorial/ktutorial-editor/src/view/WaitForStepActivationTreeItem.h =================================================================== --- trunk/ktutorial/ktutorial-editor/src/view/WaitForStepActivationTreeItem.h (rev 0) +++ trunk/ktutorial/ktutorial-editor/src/view/WaitForStepActivationTreeItem.h 2011-05-24 14:48:23 UTC (rev 311) @@ -0,0 +1,55 @@ +/*************************************************************************** + * Copyright (C) 2011 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 WAITFORSTEPACTIVATIONTREEITEM_H +#define WAITFORSTEPACTIVATIONTREEITEM_H + +#include "WaitForTreeItem.h" + +class WaitForStepActivation; + +/** + * A TreeItem that represents a WaitForStepActivation. + * The tree representation of a WaitForStepActivation is a plain text: + * When the step is activated + */ +class WaitForStepActivationTreeItem: public WaitForTreeItem { +Q_OBJECT +public: + + /** + * Creates a new WaitForStepActivationTreeItem for the given + * WaitForStepActivation and with the given parent. + * + * @param waitForStepActivation The WaitForStepActivation to represent. + * @param parent The parent TreeItem. + */ + explicit WaitForStepActivationTreeItem( + WaitForStepActivation* waitForStepActivation, + TreeItem* parent = 0); + + /** + * Returns the description of the WaitForStepActivation. + * + * @return The text for this TreeItem. + */ + virtual QString text() const; + +}; + +#endif Property changes on: trunk/ktutorial/ktutorial-editor/src/view/WaitForStepActivationTreeItem.h ___________________________________________________________________ Added: svn:eol-style + native Modified: trunk/ktutorial/ktutorial-editor/src/view/WaitForTreeItem.cpp =================================================================== --- trunk/ktutorial/ktutorial-editor/src/view/WaitForTreeItem.cpp 2011-05-24 14:41:54 UTC (rev 310) +++ trunk/ktutorial/ktutorial-editor/src/view/WaitForTreeItem.cpp 2011-05-24 14:48:23 UTC (rev 311) @@ -22,12 +22,14 @@ #include "WaitForNotTreeItem.h" #include "WaitForPropertyTreeItem.h" #include "WaitForSignalTreeItem.h" +#include "WaitForStepActivationTreeItem.h" #include "WaitForWindowTreeItem.h" #include "../data/WaitForComposed.h" #include "../data/WaitForEvent.h" #include "../data/WaitForNot.h" #include "../data/WaitForProperty.h" #include "../data/WaitForSignal.h" +#include "../data/WaitForStepActivation.h" #include "../data/WaitForWindow.h" //public: @@ -59,6 +61,11 @@ parent); } + if (qobject_cast<WaitForStepActivation*>(waitFor)) { + return new WaitForStepActivationTreeItem( + static_cast<WaitForStepActivation*>(waitFor), parent); + } + if (qobject_cast<WaitForWindow*>(waitFor)) { return new WaitForWindowTreeItem(static_cast<WaitForWindow*>(waitFor), parent); Modified: trunk/ktutorial/ktutorial-editor/src/view/WaitForWidget.cpp =================================================================== --- trunk/ktutorial/ktutorial-editor/src/view/WaitForWidget.cpp 2011-05-24 14:41:54 UTC (rev 310) +++ trunk/ktutorial/ktutorial-editor/src/view/WaitForWidget.cpp 2011-05-24 14:48:23 UTC (rev 311) @@ -34,6 +34,7 @@ #include "../data/WaitForNot.h" #include "../data/WaitForProperty.h" #include "../data/WaitForSignal.h" +#include "../data/WaitForStepActivation.h" #include "../data/WaitForWindow.h" //public: @@ -150,6 +151,14 @@ return; } + if (qobject_cast<WaitForStepActivation*>(selectedWaitFor)) { + ui->addButton->setEnabled(false); + ui->editButton->setEnabled(false); + ui->removeButton->setEnabled(true); + + return; + } + if (qobject_cast<WaitForWindow*>(selectedWaitFor)) { ui->addButton->setEnabled(false); ui->editButton->setEnabled(true); Modified: trunk/ktutorial/ktutorial-editor/src/view/WaitForWidget.h =================================================================== --- trunk/ktutorial/ktutorial-editor/src/view/WaitForWidget.h 2011-05-24 14:41:54 UTC (rev 310) +++ trunk/ktutorial/ktutorial-editor/src/view/WaitForWidget.h 2011-05-24 14:48:23 UTC (rev 311) @@ -1,5 +1,5 @@ /*************************************************************************** - * Copyright (C) 2010 by Daniel Calviño Sánchez * + * Copyright (C) 2010-2011 by Daniel Calviño Sánchez * * dan...@gm... * * * * This program is free software; you can redistribute it and/or modify * @@ -38,7 +38,7 @@ * as a child of a composed WaitFor (selecting the one that will be its parent). * * A WaitFor can be edited if it is a plain condition, that is, it is not - * composed from other WaitFors. + * composed from other WaitFors, and it is not a WaitForStepActivation. * * Finally, any WaitFor can be removed. * Modified: trunk/ktutorial/ktutorial-editor/tests/unit/data/CMakeLists.txt =================================================================== --- trunk/ktutorial/ktutorial-editor/tests/unit/data/CMakeLists.txt 2011-05-24 14:41:54 UTC (rev 310) +++ trunk/ktutorial/ktutorial-editor/tests/unit/data/CMakeLists.txt 2011-05-24 14:48:23 UTC (rev 311) @@ -21,6 +21,7 @@ WaitForNot WaitForProperty WaitForSignal + WaitForStepActivation WaitForWindow ) @@ -40,5 +41,6 @@ WaitForNot WaitForProperty WaitForSignal + WaitForStepActivation WaitForWindow ) Added: trunk/ktutorial/ktutorial-editor/tests/unit/data/WaitForStepActivationTest.cpp =================================================================== --- trunk/ktutorial/ktutorial-editor/tests/unit/data/WaitForStepActivationTest.cpp (rev 0) +++ trunk/ktutorial/ktutorial-editor/tests/unit/data/WaitForStepActivationTest.cpp 2011-05-24 14:48:23 UTC (rev 311) @@ -0,0 +1,91 @@ +/*************************************************************************** + * Copyright (C) 2011 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 "WaitForStepActivation.h" + +class WaitForStepActivationTest: public QObject { +Q_OBJECT + +private slots: + + void testConstructor(); + + void testClone(); + + void testEquals(); + +}; + +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 WaitForStepActivationTest::testConstructor() { + QObject parent; + WaitForStepActivation* waitForStepActivation = + new WaitForStepActivation(&parent); + + QCOMPARE(waitForStepActivation->parent(), &parent); +} + +void WaitForStepActivationTest::testClone() { + WaitForStepActivation waitForStepActivation; + + WaitForStepActivation* cloned = static_cast<WaitForStepActivation*> + (waitForStepActivation.clone()); + + QVERIFY(cloned); + QVERIFY(cloned != &waitForStepActivation); + delete cloned; +} + +void WaitForStepActivationTest::testEquals() { + WaitForStepActivation waitForStepActivation1; + WaitForStepActivation waitForStepActivation2; + + QCOMPARE(waitForStepActivation1 == waitForStepActivation2, true); + QCOMPARE(waitForStepActivation2 == waitForStepActivation1, true); + + StubWaitFor stubWaitFor; + + QCOMPARE(waitForStepActivation1 == stubWaitFor, false); +} + +QTEST_MAIN(WaitForStepActivationTest) + +#include "WaitForStepActivationTest.moc" Property changes on: trunk/ktutorial/ktutorial-editor/tests/unit/data/WaitForStepActivationTest.cpp ___________________________________________________________________ Added: svn:eol-style + native Modified: trunk/ktutorial/ktutorial-editor/tests/unit/serialization/JavascriptExporterTest.cpp =================================================================== --- trunk/ktutorial/ktutorial-editor/tests/unit/serialization/JavascriptExporterTest.cpp 2011-05-24 14:41:54 UTC (rev 310) +++ trunk/ktutorial/ktutorial-editor/tests/unit/serialization/JavascriptExporterTest.cpp 2011-05-24 14:48:23 UTC (rev 311) @@ -28,6 +28,7 @@ #include "../data/WaitForNot.h" #include "../data/WaitForProperty.h" #include "../data/WaitForSignal.h" +#include "../data/WaitForStepActivation.h" #include "../data/WaitForWindow.h" #define TUTORIAL_EMPTY_INFORMATION_CODE \ @@ -96,6 +97,7 @@ void testWaitForSignal(); void testWaitForSignalWithEscapeSequences(); void testWaitForSignalWithoutEmitterNameOrSignalName(); + void testWaitForStepActivation(); void testWaitForWindow(); void testWaitForWindowWithEscapeSequences(); void testWaitForWindowWithoutWindowObjectName(); @@ -1410,6 +1412,38 @@ QCOMPARE(exportedTutorial, expected); } +void JavascriptExporterTest::testWaitForStepActivation() { + Tutorial tutorial; + Step* step = new Step(); + step->setId("The id"); + tutorial.addStep(step); + + WaitForStepActivation* waitForStepActivation = new WaitForStepActivation(); + + Reaction* reaction = new Reaction(); + reaction->setTriggerType(Reaction::ConditionMet); + reaction->setWaitFor(waitForStepActivation); + 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" +" waitForStepActivation = ktutorial.newWaitFor(\"WaitForStepActivation\");\n" +" waitForStepActivation.setStep(tutorial, step);\n" +" step.addWaitFor(waitForStepActivation, \"Another step\");\n" +"}\n" +CONNECT_STEP_SETUP +STEP_WITH_ID_THE_ID_AND_EMPTY_TEXT_END_CODE; + + QCOMPARE(exportedTutorial, expected); +} + void JavascriptExporterTest::testWaitForWindow() { Tutorial tutorial; Step* step = new Step(); Modified: trunk/ktutorial/ktutorial-editor/tests/unit/serialization/TutorialReaderTest.cpp =================================================================== --- trunk/ktutorial/ktutorial-editor/tests/unit/serialization/TutorialReaderTest.cpp 2011-05-24 14:41:54 UTC (rev 310) +++ trunk/ktutorial/ktutorial-editor/tests/unit/serialization/TutorialReaderTest.cpp 2011-05-24 14:48:23 UTC (rev 311) @@ -30,6 +30,7 @@ #include "../data/WaitForNot.h" #include "../data/WaitForProperty.h" #include "../data/WaitForSignal.h" +#include "../data/WaitForStepActivation.h" #include "../data/WaitForWindow.h" #define HEADER_XML \ @@ -92,6 +93,7 @@ void testWaitForPropertyEmpty(); void testWaitForSignal(); void testWaitForSignalEmpty(); + void testWaitForStepActivation(); void testWaitForWindow(); void testWaitForWindowEmpty(); void testWaitForComposed(); @@ -441,6 +443,21 @@ assertWaitForSignal(waitFor, "", ""); } +void TutorialReaderTest::testWaitForStepActivation() { + QString data = +WAITFOR_PARENT_START +" <waitForStepActivation/>\n" +WAITFOR_PARENT_END; + + TutorialReader reader; + QScopedPointer<Tutorial> tutorial(reader.readTutorial(data)); + WaitFor* waitFor = tutorial->steps()[0]->reactions()[0]->waitFor(); + + WaitForStepActivation* waitForStepActivation = + qobject_cast<WaitForStepActivation*>(waitFor); + QVERIFY(waitForStepActivation); +} + void TutorialReaderTest::testWaitForWindow() { QString data = WAITFOR_PARENT_START Modified: trunk/ktutorial/ktutorial-editor/tests/unit/serialization/TutorialWriterTest.cpp =================================================================== --- trunk/ktutorial/ktutorial-editor/tests/unit/serialization/TutorialWriterTest.cpp 2011-05-24 14:41:54 UTC (rev 310) +++ trunk/ktutorial/ktutorial-editor/tests/unit/serialization/TutorialWriterTest.cpp 2011-05-24 14:48:23 UTC (rev 311) @@ -28,6 +28,7 @@ #include "../data/WaitForNot.h" #include "../data/WaitForProperty.h" #include "../data/WaitForSignal.h" +#include "../data/WaitForStepActivation.h" #include "../data/WaitForWindow.h" #define HEADER_XML \ @@ -90,6 +91,7 @@ void testWaitForPropertyEmpty(); void testWaitForSignal(); void testWaitForSignalEmpty(); + void testWaitForStepActivation(); void testWaitForWindow(); void testWaitForWindowEmpty(); void testWaitForComposed(); @@ -499,6 +501,30 @@ QCOMPARE(savedTutorial, expected); } +void TutorialWriterTest::testWaitForStepActivation() { + Tutorial tutorial; + Step* step = new Step(); + tutorial.addStep(step); + + WaitForStepActivation* waitForStepActivation = new WaitForStepActivation(); + + Reaction* reaction = new Reaction(); + reaction->setTriggerType(Reaction::ConditionMet); + reaction->setWaitFor(waitForStepActivation); + reaction->setResponseType(Reaction::NextStep); + step->addReaction(reaction); + + TutorialWriter saver; + QString savedTutorial = saver.writeTutorial(&tutorial); + + QString expected = +WAITFOR_PARENT_START +" <waitForStepActivation/>\n" +WAITFOR_PARENT_END; + + QCOMPARE(savedTutorial, expected); +} + void TutorialWriterTest::testWaitForWindow() { Tutorial tutorial; Step* step = new Step(); Modified: trunk/ktutorial/ktutorial-editor/tests/unit/view/CMakeLists.txt =================================================================== --- trunk/ktutorial/ktutorial-editor/tests/unit/view/CMakeLists.txt 2011-05-24 14:41:54 UTC (rev 310) +++ trunk/ktutorial/ktutorial-editor/tests/unit/view/CMakeLists.txt 2011-05-24 14:48:23 UTC (rev 311) @@ -48,6 +48,7 @@ WaitForPropertyWidget WaitForSignalTreeItem WaitForSignalWidget + WaitForStepActivationTreeItem WaitForTreeItem WaitForWidget WaitForWindowTreeItem @@ -106,6 +107,7 @@ WaitForPropertyWidget WaitForSignalTreeItem WaitForSignalWidget + WaitForStepActivationTreeItem WaitForTreeItem WaitForWidget WaitForWindowTreeItem Modified: trunk/ktutorial/ktutorial-editor/tests/unit/view/NewWaitForWidgetTest.cpp =================================================================== --- trunk/ktutorial/ktutorial-editor/tests/unit/view/NewWaitForWidgetTest.cpp 2011-05-24 14:41:54 UTC (rev 310) +++ trunk/ktutorial/ktutorial-editor/tests/unit/view/NewWaitForWidgetTest.cpp 2011-05-24 14:48:23 UTC (rev 311) @@ -27,6 +27,7 @@ #include "../data/WaitForNot.h" #include "../data/WaitForProperty.h" #include "../data/WaitForSignal.h" +#include "../data/WaitForStepActivation.h" #include "../data/WaitForWindow.h" class NewWaitForWidgetTest: public QObject { @@ -43,6 +44,7 @@ void testWaitForWhenEventConditionIsSelected(); void testWaitForWhenWindowConditionIsSelected(); void testWaitForWhenPropertyConditionIsSelected(); + void testWaitForWhenStepActivationConditionIsSelected(); private: @@ -129,6 +131,17 @@ delete waitFor; } +void NewWaitForWidgetTest::testWaitForWhenStepActivationConditionIsSelected() { + NewWaitForWidget widget; + + selectOption(&widget, 7); + + WaitForStepActivation* waitFor = + qobject_cast<WaitForStepActivation*>(widget.waitFor()); + QVERIFY(waitFor); + delete waitFor; +} + /////////////////////////////////// Helpers //////////////////////////////////// void NewWaitForWidgetTest::selectOption(NewWaitForWidget* widget, Added: trunk/ktutorial/ktutorial-editor/tests/unit/view/WaitForStepActivationTreeItemTest.cpp =================================================================== --- trunk/ktutorial/ktutorial-editor/tests/unit/view/WaitForStepActivationTreeItemTest.cpp (rev 0) +++ trunk/ktutorial/ktutorial-editor/tests/unit/view/WaitForStepActivationTreeItemTest.cpp 2011-05-24 14:48:23 UTC (rev 311) @@ -0,0 +1,56 @@ +/*************************************************************************** + * Copyright (C) 2011 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 "WaitForStepActivationTreeItem.h" + +#include <KLocalizedString> + +#include "../data/WaitForStepActivation.h" + +class WaitForStepActivationTreeItemTest: public QObject { +Q_OBJECT + +private slots: + + void testConstructor(); + +}; + +class StubTreeItem: public TreeItem { +public: + virtual QString text() const { + return ""; + } +}; + +void WaitForStepActivationTreeItemTest::testConstructor() { + WaitForStepActivation waitForStepActivation; + + StubTreeItem parent; + WaitForStepActivationTreeItem item(&waitForStepActivation, &parent); + + QCOMPARE(item.parent(), &parent); + QCOMPARE(item.waitFor(), &waitForStepActivation); + QCOMPARE(item.text(), i18nc("@item", "When the step is activated")); +} + +QTEST_MAIN(WaitForStepActivationTreeItemTest) + +#include "WaitForStepActivationTreeItemTest.moc" Property changes on: trunk/ktutorial/ktutorial-editor/tests/unit/view/WaitForStepActivationTreeItemTest.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 2011-05-24 14:41:54 UTC (rev 310) +++ trunk/ktutorial/ktutorial-editor/tests/unit/view/WaitForTreeItemTest.cpp 2011-05-24 14:48:23 UTC (rev 311) @@ -25,6 +25,7 @@ #include "WaitForNotTreeItem.h" #include "WaitForPropertyTreeItem.h" #include "WaitForSignalTreeItem.h" +#include "WaitForStepActivationTreeItem.h" #include "WaitForWindowTreeItem.h" #include "../data/WaitFor.h" #include "../data/WaitForComposed.h" @@ -32,6 +33,7 @@ #include "../data/WaitForNot.h" #include "../data/WaitForProperty.h" #include "../data/WaitForSignal.h" +#include "../data/WaitForStepActivation.h" #include "../data/WaitForWindow.h" class WaitForTreeItemTest: public QObject { @@ -46,6 +48,7 @@ void testTreeItemForWaitForNot(); void testTreeItemForWaitForProperty(); void testTreeItemForWaitForSignal(); + void testTreeItemForWaitForStepActivation(); void testTreeItemForWaitForWindow(); }; @@ -164,6 +167,20 @@ delete item; } +void WaitForTreeItemTest::testTreeItemForWaitForStepActivation() { + WaitForStepActivation waitFor; + StubTreeItem parent; + + WaitForTreeItem* item = WaitForTreeItem::treeItemForWaitFor(&waitFor, + &parent); + + QVERIFY(qobject_cast<WaitForStepActivationTreeItem*>(item)); + QCOMPARE(item->parent(), &parent); + QCOMPARE(item->waitFor(), &waitFor); + + delete item; +} + void WaitForTreeItemTest::testTreeItemForWaitForWindow() { WaitForWindow waitFor; StubTreeItem parent; Modified: trunk/ktutorial/ktutorial-editor/tests/unit/view/WaitForWidgetTest.cpp =================================================================== --- trunk/ktutorial/ktutorial-editor/tests/unit/view/WaitForWidgetTest.cpp 2011-05-24 14:41:54 UTC (rev 310) +++ trunk/ktutorial/ktutorial-editor/tests/unit/view/WaitForWidgetTest.cpp 2011-05-24 14:48:23 UTC (rev 311) @@ -32,6 +32,7 @@ #include "../data/WaitForNot.h" #include "../data/WaitForProperty.h" #include "../data/WaitForSignal.h" +#include "../data/WaitForStepActivation.h" #include "../data/WaitForWindow.h" class WaitForWidgetTest: public QObject { @@ -61,6 +62,7 @@ void testSelectWaitForEvent(); void testSelectWaitForProperty(); void testSelectWaitForSignal(); + void testSelectWaitForStepActivation(); void testSelectWaitForWindow(); void testClearSelection(); @@ -86,6 +88,7 @@ WaitForEvent* mWaitFor2_1; WaitForWindow* mWaitFor2_2; WaitForProperty* mWaitFor2_3; + WaitForStepActivation* mWaitFor2_4; WaitForNot* mWaitFor3; WaitForSignal* mWaitFor3_1; WaitForNot* mWaitFor4; @@ -134,6 +137,9 @@ mWaitFor2_3->setValue("value"); mWaitFor2->addWaitFor(mWaitFor2_3); + mWaitFor2_4 = new WaitForStepActivation(); + mWaitFor2->addWaitFor(mWaitFor2_4); + mWaitFor3 = new WaitForNot(); mWaitFor->addWaitFor(mWaitFor3); @@ -213,6 +219,12 @@ assertButtonEnabled(false, true, true); } +void WaitForWidgetTest::testSelectWaitForStepActivation() { + selectItem(getIndex(3, getIndex(1, getIndex(0)))); + + assertButtonEnabled(false, false, true); +} + void WaitForWidgetTest::testSelectWaitForWindow() { selectItem(getIndex(1, getIndex(1, getIndex(0)))); @@ -267,12 +279,13 @@ QCOMPARE(mWaitFor->waitFors()[2], mWaitFor3); QCOMPARE(mWaitFor->waitFors()[3], mWaitFor4); QVERIFY(qobject_cast<WaitForSignal*>(mWaitFor->waitFors()[4])); - QCOMPARE(mWaitFor2->waitFors().count(), 4); + QCOMPARE(mWaitFor2->waitFors().count(), 5); QCOMPARE(mWaitFor2->waitFors()[0], mWaitFor2_1); QCOMPARE(mWaitFor2->waitFors()[1], mWaitFor2_2); QCOMPARE(mWaitFor2->waitFors()[2], mWaitFor2_3); - QVERIFY(qobject_cast<WaitForSignal*>(mWaitFor2->waitFors()[3])); - QVERIFY(mWaitFor->waitFors()[4] != mWaitFor2->waitFors()[3]); + QCOMPARE(mWaitFor2->waitFors()[3], mWaitFor2_4); + QVERIFY(qobject_cast<WaitForSignal*>(mWaitFor2->waitFors()[4])); + QVERIFY(mWaitFor->waitFors()[4] != mWaitFor2->waitFors()[4]); } void WaitForWidgetTest::testAddWaitForToWaitForNot() { This was sent by the SourceForge.net collaborative development platform, the world's largest Open Source development site. |
From: <dan...@us...> - 2011-05-24 14:42:01
|
Revision: 310 http://ktutorial.svn.sourceforge.net/ktutorial/?rev=310&view=rev Author: danxuliu Date: 2011-05-24 14:41:54 +0000 (Tue, 24 May 2011) Log Message: ----------- Add WaitForStepActivation class to wait for its step to be activated. Modified Paths: -------------- trunk/ktutorial/ktutorial-library/src/CMakeLists.txt trunk/ktutorial/ktutorial-library/src/scripting/ScriptingModule.cpp trunk/ktutorial/ktutorial-library/tests/CMakeLists.txt trunk/ktutorial/ktutorial-library/tests/scripting/ScriptingModuleTest.cpp trunk/ktutorial/ktutorial-library/tests/scripting/ScriptingTest.cpp Added Paths: ----------- trunk/ktutorial/ktutorial-library/src/WaitForStepActivation.cpp trunk/ktutorial/ktutorial-library/src/WaitForStepActivation.h trunk/ktutorial/ktutorial-library/tests/WaitForStepActivationTest.cpp Modified: trunk/ktutorial/ktutorial-library/src/CMakeLists.txt =================================================================== --- trunk/ktutorial/ktutorial-library/src/CMakeLists.txt 2011-05-24 14:33:07 UTC (rev 309) +++ trunk/ktutorial/ktutorial-library/src/CMakeLists.txt 2011-05-24 14:41:54 UTC (rev 310) @@ -30,6 +30,7 @@ WaitForOr.cpp WaitForProperty.cpp WaitForSignal.cpp + WaitForStepActivation.cpp WaitForWindow.cpp ) @@ -61,6 +62,7 @@ WaitForOr.h WaitForProperty.h WaitForSignal.h + WaitForStepActivation.h WaitForWindow.h ) Added: trunk/ktutorial/ktutorial-library/src/WaitForStepActivation.cpp =================================================================== --- trunk/ktutorial/ktutorial-library/src/WaitForStepActivation.cpp (rev 0) +++ trunk/ktutorial/ktutorial-library/src/WaitForStepActivation.cpp 2011-05-24 14:41:54 UTC (rev 310) @@ -0,0 +1,70 @@ +/*************************************************************************** + * Copyright (C) 2011 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 "WaitForStepActivation.h" + +#include <QEvent> + +#include <KDebug> + +#include "Tutorial.h" + +//public: + +WaitForStepActivation::WaitForStepActivation(): WaitFor(), + mDuringStepActivation(false) { +} + +WaitForStepActivation::WaitForStepActivation(const Tutorial* tutorial, + const Step* step): WaitFor(), + mDuringStepActivation(false) { + setStep(tutorial, step); +} + +void WaitForStepActivation::setStep(const Tutorial* tutorial, + const Step* step) { + if (!tutorial) { + kWarning() << "The tutorial that contains the step to wait for its" + << "activation is null!"; + return; + } + + if (!step) { + kWarning() << "The step to wait for its activation is null!"; + return; + } + + connect(tutorial, SIGNAL(stepActivated(Step*)), + this, SLOT(checkStepActivatedToEndTheWait(Step*))); +} + +bool WaitForStepActivation::conditionMet() const { + return mDuringStepActivation; +} + +//private slots: + +void WaitForStepActivation::checkStepActivatedToEndTheWait(Step* step) { + if (!isActive()) { + return; + } + + mDuringStepActivation = true; + emit waitEnded(this); + mDuringStepActivation = false; +} Property changes on: trunk/ktutorial/ktutorial-library/src/WaitForStepActivation.cpp ___________________________________________________________________ Added: svn:eol-style + native Added: trunk/ktutorial/ktutorial-library/src/WaitForStepActivation.h =================================================================== --- trunk/ktutorial/ktutorial-library/src/WaitForStepActivation.h (rev 0) +++ trunk/ktutorial/ktutorial-library/src/WaitForStepActivation.h 2011-05-24 14:41:54 UTC (rev 310) @@ -0,0 +1,119 @@ +/*************************************************************************** + * Copyright (C) 2011 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 WAITFORSTEPACTIVATION_H +#define WAITFORSTEPACTIVATION_H + +#include "ktutorial_export.h" + +#include "WaitFor.h" + +class Step; +class Tutorial; + +/** + * Waits for the activation of a step. + * When the step is activated, the wait ends. + * + * The purpose of WaitForStepActivations is to be combined with one or more + * WaitForProperties using a WaitForAnd. If the properties have the expected + * value when the step is activated, the associated slot is executed or the next + * step is requested (depending on the Step::addWaitFor() method used). It can + * be used to set "preconditions" for a step, and change to another step if + * some things that should have been done before that step were not done yet. + * + * Note that the condition is met only while the step is being activated. Once + * the step is active, the condition is no longer met (until the next time that + * the step is being activated again). Due to this, it only makes sense to use + * WaitForStepActivation with the same step that the WaitForStepActivation is + * going to be added to (if used to wait for the activation of another step, the + * WaitForStepActivation will always be inactive when that step is being + * activated). + * + * Despite waiting for the step activation, WaitForStepActivation can be safely + * created and added to a step in its setup, and several WaitForStepActivation + * can be added to the same step without problems. + * + * @see WaitForAnd + * @see WaitForProperty + */ +class KTUTORIAL_EXPORT WaitForStepActivation: public WaitFor { +Q_OBJECT +public: + + /** + * Creates a new WaitForStepActivation. + * This constructor is needed to dynamically create WaitForStepActivation + * objects in scripts using ScriptingModule::newWaitFor(const QString&). + * Method setStep(const Tutorial*, const Step*) must be called to finish + * setting up the object. For C++ tutorials, use + * WaitForStepActivation(const Tutorial*, const Step*) constructor instead + * of this one. + */ + Q_INVOKABLE WaitForStepActivation(); + + /** + * Creates a new WaitForStepActivation. + * + * @param tutorial The tutorial that contains the step. + * @param step The step to wait for its activation. + */ + WaitForStepActivation(const Tutorial* tutorial, const Step* step); + + /** + * Sets the step to wait for its activation. + * This method can be invoked from a script. + * + * In fact, you should only invoke this method from a script, and only once, + * to set up the object. For C++ tutorials, use + * WaitForStepActivation(const Tutorial*, const Step*) constructor when + * creating this WaitForStepActivation. + * + * @param tutorial The tutorial that contains the step. + * @param step The step to wait for its activation. + */ + Q_INVOKABLE void setStep(const Tutorial* tutorial, const Step* step); + + /** + * Returns true if the step is being activated. + * Note that true is only returned during the step activation, but not once + * it is already active. + * + * @return True if the step is being activated, false otherwise. + */ + virtual bool conditionMet() const; + +private: + + /** + * Whether the step is being activated or not. + */ + bool mDuringStepActivation; + +private slots: + + /** + * When the step is activated, this method notifies that the wait for the + * activation ended. + * The wait is only ended if this WaitForStepActivation is active. + */ + void checkStepActivatedToEndTheWait(Step* step); + +}; + +#endif Property changes on: trunk/ktutorial/ktutorial-library/src/WaitForStepActivation.h ___________________________________________________________________ Added: svn:eol-style + native Modified: trunk/ktutorial/ktutorial-library/src/scripting/ScriptingModule.cpp =================================================================== --- trunk/ktutorial/ktutorial-library/src/scripting/ScriptingModule.cpp 2011-05-24 14:33:07 UTC (rev 309) +++ trunk/ktutorial/ktutorial-library/src/scripting/ScriptingModule.cpp 2011-05-24 14:41:54 UTC (rev 310) @@ -29,6 +29,7 @@ #include "../WaitForOr.h" #include "../WaitForProperty.h" #include "../WaitForSignal.h" +#include "../WaitForStepActivation.h" #include "../WaitForWindow.h" namespace scripting { @@ -42,6 +43,8 @@ sSelf->registerWaitForMetaObject(WaitForOr::staticMetaObject); sSelf->registerWaitForMetaObject(WaitForProperty::staticMetaObject); sSelf->registerWaitForMetaObject(WaitForSignal::staticMetaObject); + sSelf->registerWaitForMetaObject( + WaitForStepActivation::staticMetaObject); sSelf->registerWaitForMetaObject(WaitForWindow::staticMetaObject); } Modified: trunk/ktutorial/ktutorial-library/tests/CMakeLists.txt =================================================================== --- trunk/ktutorial/ktutorial-library/tests/CMakeLists.txt 2011-05-24 14:33:07 UTC (rev 309) +++ trunk/ktutorial/ktutorial-library/tests/CMakeLists.txt 2011-05-24 14:41:54 UTC (rev 310) @@ -40,6 +40,7 @@ WaitForOr WaitForProperty WaitForSignal + WaitForStepActivation WaitForWindow ) @@ -64,5 +65,6 @@ WaitForOr WaitForProperty WaitForSignal + WaitForStepActivation WaitForWindow ) Added: trunk/ktutorial/ktutorial-library/tests/WaitForStepActivationTest.cpp =================================================================== --- trunk/ktutorial/ktutorial-library/tests/WaitForStepActivationTest.cpp (rev 0) +++ trunk/ktutorial/ktutorial-library/tests/WaitForStepActivationTest.cpp 2011-05-24 14:41:54 UTC (rev 310) @@ -0,0 +1,179 @@ +/*************************************************************************** + * Copyright (C) 2011 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 "WaitForStepActivation.h" + +#include "Step.h" +#include "Tutorial.h" + +class WaitForStepActivationTest: public QObject { +Q_OBJECT + +public slots: + + void assertConditionMet(WaitFor* waitForToAssertItsCondition) { + QVERIFY(waitForToAssertItsCondition); + QVERIFY(waitForToAssertItsCondition->conditionMet()); + } + +private slots: + + void testConstructor(); + void testConstructorWithNullTutorial(); + void testConstructorWithNullStep(); + void testConstructorDefault(); + void testConstructorDefaultWithNullTutorial(); + void testConstructorDefaultWithNullStep(); + + void testStepActivation(); + void testStepActivationWhenWaitForIsInactive(); + +}; + +class InspectedTutorial: public Tutorial { +public: + + int mstepActivatedConnectionCount; + + InspectedTutorial(TutorialInformation* tutorialInformation): + Tutorial(tutorialInformation), + mstepActivatedConnectionCount(0) { + } + +protected: + + void connectNotify(const char* signal) { + if (QLatin1String(signal) == SIGNAL(stepActivated(Step*))) { + mstepActivatedConnectionCount++; + } + } + +}; + +void WaitForStepActivationTest::testConstructor() { + InspectedTutorial tutorial(0); + Step step("stepName"); + WaitForStepActivation waitForStepActivation(&tutorial, &step); + + QVERIFY(!waitForStepActivation.isActive()); + QVERIFY(!waitForStepActivation.conditionMet()); + QCOMPARE(tutorial.mstepActivatedConnectionCount, 1); +} + +void WaitForStepActivationTest::testConstructorWithNullTutorial() { + Step step("stepName"); + WaitForStepActivation waitForStepActivation(0, &step); + + QVERIFY(!waitForStepActivation.isActive()); + QVERIFY(!waitForStepActivation.conditionMet()); +} + +void WaitForStepActivationTest::testConstructorWithNullStep() { + InspectedTutorial tutorial(0); + WaitForStepActivation waitForStepActivation(&tutorial, 0); + + QVERIFY(!waitForStepActivation.isActive()); + QVERIFY(!waitForStepActivation.conditionMet()); + QCOMPARE(tutorial.mstepActivatedConnectionCount, 0); +} + +void WaitForStepActivationTest::testConstructorDefault() { + InspectedTutorial tutorial(0); + Step step("stepName"); + WaitForStepActivation waitForStepActivation; + waitForStepActivation.setStep(&tutorial, &step); + + QVERIFY(!waitForStepActivation.isActive()); + QVERIFY(!waitForStepActivation.conditionMet()); + QCOMPARE(tutorial.mstepActivatedConnectionCount, 1); +} + +void WaitForStepActivationTest::testConstructorDefaultWithNullTutorial() { + Step step("stepName"); + WaitForStepActivation waitForStepActivation; + waitForStepActivation.setStep(0, &step); + + QVERIFY(!waitForStepActivation.isActive()); + QVERIFY(!waitForStepActivation.conditionMet()); +} + +void WaitForStepActivationTest::testConstructorDefaultWithNullStep() { + InspectedTutorial tutorial(0); + WaitForStepActivation waitForStepActivation; + waitForStepActivation.setStep(&tutorial, 0); + + QVERIFY(!waitForStepActivation.isActive()); + QVERIFY(!waitForStepActivation.conditionMet()); + QCOMPARE(tutorial.mstepActivatedConnectionCount, 0); +} + +//WaitFor* must be declared as a metatype to be used in qvariant_cast +Q_DECLARE_METATYPE(WaitFor*); + +void WaitForStepActivationTest::testStepActivation() { + InspectedTutorial tutorial(0); + Step* startStep = new Step("start"); + tutorial.addStep(startStep); + + WaitForStepActivation* waitForStepActivation = + new WaitForStepActivation(&tutorial, startStep); + waitForStepActivation->setActive(true); + + QVERIFY(!waitForStepActivation->conditionMet()); + + //WaitFor* must be registered in order to be used with QSignalSpy + int waitForStarType = qRegisterMetaType<WaitFor*>("WaitFor*"); + QSignalSpy waitEndedSpy(waitForStepActivation, SIGNAL(waitEnded(WaitFor*))); + + connect(waitForStepActivation, SIGNAL(waitEnded(WaitFor*)), + this, SLOT(assertConditionMet(WaitFor*))); + + tutorial.start(); + + QVERIFY(!waitForStepActivation->conditionMet()); + QCOMPARE(waitEndedSpy.count(), 1); + QVariant argument = waitEndedSpy.at(0).at(0); + QCOMPARE(argument.userType(), waitForStarType); + QCOMPARE(qvariant_cast<WaitFor*>(argument), waitForStepActivation); +} + +//Should not happen, as WaitForStepActivation is meant to be used only with the +//step that contains the WaitFor... but just in case ;) +void WaitForStepActivationTest::testStepActivationWhenWaitForIsInactive() { + InspectedTutorial tutorial(0); + Step* startStep = new Step("start"); + tutorial.addStep(startStep); + + WaitForStepActivation* waitForStepActivation = + new WaitForStepActivation(&tutorial, startStep); + + //WaitFor* must be registered in order to be used with QSignalSpy + qRegisterMetaType<WaitFor*>("WaitFor*"); + QSignalSpy waitEndedSpy(waitForStepActivation, SIGNAL(waitEnded(WaitFor*))); + + tutorial.start(); + + QVERIFY(!waitForStepActivation->conditionMet()); + QCOMPARE(waitEndedSpy.count(), 0); +} + +QTEST_MAIN(WaitForStepActivationTest) + +#include "WaitForStepActivationTest.moc" Property changes on: trunk/ktutorial/ktutorial-library/tests/WaitForStepActivationTest.cpp ___________________________________________________________________ Added: svn:eol-style + native Modified: trunk/ktutorial/ktutorial-library/tests/scripting/ScriptingModuleTest.cpp =================================================================== --- trunk/ktutorial/ktutorial-library/tests/scripting/ScriptingModuleTest.cpp 2011-05-24 14:33:07 UTC (rev 309) +++ trunk/ktutorial/ktutorial-library/tests/scripting/ScriptingModuleTest.cpp 2011-05-24 14:41:54 UTC (rev 310) @@ -35,6 +35,7 @@ #include "../WaitForOr.h" #include "../WaitForProperty.h" #include "../WaitForSignal.h" +#include "../WaitForStepActivation.h" #include "../WaitForWindow.h" class MockWaitForDefaultNamespace: public WaitFor { @@ -178,6 +179,11 @@ type = metaObject(scriptingModule, "WaitForSignal"); QCOMPARE(type.className(), WaitForSignal::staticMetaObject.className()); + QVERIFY(containsMetaObject(scriptingModule, "WaitForStepActivation")); + type = metaObject(scriptingModule, "WaitForStepActivation"); + QCOMPARE(type.className(), + WaitForStepActivation::staticMetaObject.className()); + QVERIFY(containsMetaObject(scriptingModule, "WaitForWindow")); type = metaObject(scriptingModule, "WaitForWindow"); QCOMPARE(type.className(), WaitForWindow::staticMetaObject.className()); Modified: trunk/ktutorial/ktutorial-library/tests/scripting/ScriptingTest.cpp =================================================================== --- trunk/ktutorial/ktutorial-library/tests/scripting/ScriptingTest.cpp 2011-05-24 14:33:07 UTC (rev 309) +++ trunk/ktutorial/ktutorial-library/tests/scripting/ScriptingTest.cpp 2011-05-24 14:41:54 UTC (rev 310) @@ -328,6 +328,8 @@ out << "tutorial.addStep(thirdStep);\n"; out << "fourthStep = ktutorial.newStep(\"fourth\");\n"; out << "tutorial.addStep(fourthStep);\n"; + out << "fifthStep = ktutorial.newStep(\"fifth\");\n"; + out << "tutorial.addStep(fifthStep);\n"; out << "endStep = ktutorial.newStep(\"end\");\n"; out << "endStep.setText(\"The tutorial has ended.\");\n"; out << "tutorial.addStep(endStep);\n"; @@ -371,8 +373,27 @@ out << "waitForIntProperty.setProperty(testObject, \"intProperty\", \ \"42\");\n"; - out << "fourthStep.addWaitFor(waitForIntProperty, \"end\");\n"; + out << "fourthStep.addWaitFor(waitForIntProperty, \"fifth\");\n"; + out << "function fifthStepSetup(step) {\n"; + out << " waitForStepActivation = ktutorial.newWaitFor(\ +\"WaitForStepActivation\");\n"; + out << " waitForStepActivation.setStep(tutorial, step);\n"; + + out << " waitForIntProperty = ktutorial.newWaitFor(\ +\"WaitForProperty\");\n"; + out << " waitForIntProperty.setProperty(testObject, \"intProperty\", \ +\"42\");\n"; + + out << " waitForAnd = ktutorial.newWaitFor(\"WaitForAnd\");\n"; + out << " waitForAnd.add(waitForStepActivation);\n"; + out << " waitForAnd.add(waitForIntProperty);\n"; + out << " step.addWaitFor(waitForAnd, \"end\");\n"; + out << "}\n"; + + out << "connect(fifthStep, \"setup(QObject*)\",\n" + << " this, \"fifthStepSetup(QObject*)\");\n"; + out.flush(); ScriptedTutorial scriptedTutorial(mTemporaryFile->fileName()); @@ -422,6 +443,8 @@ mIntProperty = 42; emit intPropertyChanged(); + //Fifth step changes to end step when activated + QCOMPARE(scriptedTutorial.mCurrentStep->id(), QString("end")); QCOMPARE(scriptedTutorial.mCurrentStep->text(), QString("The tutorial has ended.")); This was sent by the SourceForge.net collaborative development platform, the world's largest Open Source development site. |
From: <dan...@us...> - 2011-05-24 14:33:14
|
Revision: 309 http://ktutorial.svn.sourceforge.net/ktutorial/?rev=309&view=rev Author: danxuliu Date: 2011-05-24 14:33:07 +0000 (Tue, 24 May 2011) Log Message: ----------- Change WaitForPropertyTreeItem text from "When the property (...) changes to the value (...)" to "When the property (...) has the value (...)". Modified Paths: -------------- trunk/ktutorial/ktutorial-editor/src/view/WaitForPropertyTreeItem.cpp trunk/ktutorial/ktutorial-editor/src/view/WaitForPropertyTreeItem.h trunk/ktutorial/ktutorial-editor/tests/unit/view/WaitForPropertyTreeItemTest.cpp Modified: trunk/ktutorial/ktutorial-editor/src/view/WaitForPropertyTreeItem.cpp =================================================================== --- trunk/ktutorial/ktutorial-editor/src/view/WaitForPropertyTreeItem.cpp 2011-05-16 22:44:36 UTC (rev 308) +++ trunk/ktutorial/ktutorial-editor/src/view/WaitForPropertyTreeItem.cpp 2011-05-24 14:33:07 UTC (rev 309) @@ -58,8 +58,8 @@ value = mValue; } - return i18nc("@item", "When the property %1 in the object %2 changes to " - "the value %3", propertyName, objectName, value); + return i18nc("@item", "When the property %1 in the object %2 has the value " + "%3", propertyName, objectName, value); } //private: Modified: trunk/ktutorial/ktutorial-editor/src/view/WaitForPropertyTreeItem.h =================================================================== --- trunk/ktutorial/ktutorial-editor/src/view/WaitForPropertyTreeItem.h 2011-05-16 22:44:36 UTC (rev 308) +++ trunk/ktutorial/ktutorial-editor/src/view/WaitForPropertyTreeItem.h 2011-05-24 14:33:07 UTC (rev 309) @@ -26,8 +26,8 @@ /** * A TreeItem that represents a WaitForProperty. * The tree representation of a WaitForProperty is a plain text: - * When the property "property name" in the object "object name" changes to the - * value value + * When the property "property name" in the object "object name" has the value + * value * * If the property, the object name or the value aren't set yet, a placeholder * is put instead. Property placeholder is "(property not set)", the object name Modified: trunk/ktutorial/ktutorial-editor/tests/unit/view/WaitForPropertyTreeItemTest.cpp =================================================================== --- trunk/ktutorial/ktutorial-editor/tests/unit/view/WaitForPropertyTreeItemTest.cpp 2011-05-16 22:44:36 UTC (rev 308) +++ trunk/ktutorial/ktutorial-editor/tests/unit/view/WaitForPropertyTreeItemTest.cpp 2011-05-24 14:33:07 UTC (rev 309) @@ -74,8 +74,7 @@ QCOMPARE(item.waitFor(), &waitForProperty); QCOMPARE(item.text(), i18nc("@item", "When the property (property not set) " "in the object (object name not set) " - "changes to the value (value not " - "set)")); + "has the value (value not set)")); } void WaitForPropertyTreeItemTest::testConstructorFull() { @@ -90,8 +89,8 @@ QCOMPARE(item.parent(), &parent); QCOMPARE(item.waitFor(), &waitForProperty); QCOMPARE(item.text(), i18nc("@item", "When the property \"propertyName\" " - "in the object \"objectName\" changes " - "to the value theValue")); + "in the object \"objectName\" has the " + "value theValue")); } void WaitForPropertyTreeItemTest::testWaitForPropertySetObjectName() { @@ -101,8 +100,8 @@ WaitForPropertyTreeItem item(&waitForProperty); QCOMPARE(item.text(), i18nc("@item", "When the property (property not set) " - "in the object \"objectName\" changes " - "to the value (value not set)")); + "in the object \"objectName\" has the " + "value (value not set)")); } void WaitForPropertyTreeItemTest::testWaitForPropertySetObjectNameChange() { @@ -117,8 +116,7 @@ QCOMPARE(item.text(), i18nc("@item", "When the property (property not set) " "in the object \"objectNameChanged\" " - "changes to the value (value not " - "set)")); + "has the value (value not set)")); QCOMPARE(dataChangedSpy.count(), 1); assertDataChanged(dataChangedSpy, 0, &item); } @@ -131,8 +129,7 @@ QCOMPARE(item.text(), i18nc("@item", "When the property \"propertyName\" " "in the object (object name not set) " - "changes to the value (value not " - "set)")); + "has the value (value not set)")); } void WaitForPropertyTreeItemTest::testWaitForPropertySetPropertyNameChange() { @@ -147,8 +144,8 @@ QCOMPARE(item.text(), i18nc("@item", "When the property " "\"propertyNameChanged\" in the " - "object (object name not set) changes " - "to the value (value not set)")); + "object (object name not set) has the " + "value (value not set)")); QCOMPARE(dataChangedSpy.count(), 1); assertDataChanged(dataChangedSpy, 0, &item); } @@ -161,7 +158,7 @@ QCOMPARE(item.text(), i18nc("@item", "When the property (property not set) " "in the object (object name not set) " - "changes to the value theValue")); + "has the value theValue")); } void WaitForPropertyTreeItemTest::testWaitForPropertySetValueChange() { @@ -176,8 +173,7 @@ QCOMPARE(item.text(), i18nc("@item", "When the property (property not set) " "in the object (object name not set) " - "changes to the value " - "\"theValueChanged\"")); + "has the value \"theValueChanged\"")); QCOMPARE(dataChangedSpy.count(), 1); assertDataChanged(dataChangedSpy, 0, &item); } This was sent by the SourceForge.net collaborative development platform, the world's largest Open Source development site. |
From: <dan...@us...> - 2011-05-16 22:44:42
|
Revision: 308 http://ktutorial.svn.sourceforge.net/ktutorial/?rev=308&view=rev Author: danxuliu Date: 2011-05-16 22:44:36 +0000 (Mon, 16 May 2011) Log Message: ----------- Provide completion in the property line edit in WaitForPropertyWidget with the properties of the chosen RemoteObject. Modified Paths: -------------- trunk/ktutorial/ktutorial-editor/src/targetapplication/RemoteClass.cpp trunk/ktutorial/ktutorial-editor/src/targetapplication/RemoteClass.h trunk/ktutorial/ktutorial-editor/src/view/WaitForPropertyWidget.cpp trunk/ktutorial/ktutorial-editor/src/view/WaitForPropertyWidget.h trunk/ktutorial/ktutorial-editor/tests/unit/targetapplication/RemoteClassStubs.h trunk/ktutorial/ktutorial-editor/tests/unit/targetapplication/RemoteClassTest.cpp trunk/ktutorial/ktutorial-editor/tests/unit/view/WaitForPropertyWidgetTest.cpp Modified: trunk/ktutorial/ktutorial-editor/src/targetapplication/RemoteClass.cpp =================================================================== --- trunk/ktutorial/ktutorial-editor/src/targetapplication/RemoteClass.cpp 2011-05-16 22:42:33 UTC (rev 307) +++ trunk/ktutorial/ktutorial-editor/src/targetapplication/RemoteClass.cpp 2011-05-16 22:44:36 UTC (rev 308) @@ -1,5 +1,5 @@ /*************************************************************************** - * Copyright (C) 2010 by Daniel Calviño Sánchez * + * Copyright (C) 2010-2011 by Daniel Calviño Sánchez * * dan...@gm... * * * * This program is free software; you can redistribute it and/or modify * @@ -50,6 +50,15 @@ return mMapper->remoteClass(reply.value()); } +QStringList RemoteClass::propertyList() throw (DBusException) { + QDBusReply<QStringList> reply = call("propertyList", mClassName); + if (!reply.isValid()) { + throw DBusException(reply.error().message()); + } + + return reply.value(); +} + QStringList RemoteClass::signalList() throw (DBusException) { QDBusReply<QStringList> reply = call("signalList", mClassName); if (!reply.isValid()) { Modified: trunk/ktutorial/ktutorial-editor/src/targetapplication/RemoteClass.h =================================================================== --- trunk/ktutorial/ktutorial-editor/src/targetapplication/RemoteClass.h 2011-05-16 22:42:33 UTC (rev 307) +++ trunk/ktutorial/ktutorial-editor/src/targetapplication/RemoteClass.h 2011-05-16 22:44:36 UTC (rev 308) @@ -1,5 +1,5 @@ /*************************************************************************** - * Copyright (C) 2010 by Daniel Calviño Sánchez * + * Copyright (C) 2010-2011 by Daniel Calviño Sánchez * * dan...@gm... * * * * This program is free software; you can redistribute it and/or modify * @@ -73,6 +73,16 @@ RemoteClass* superClass() throw (DBusException); /** + * Returns a list with the properties defined in the remote class. + * The list only includes the properties from the class itself, but not its + * super classes. + * + * @return The properties. + * @throws DBusException If a DBus error happens. + */ + QStringList propertyList() throw (DBusException); + + /** * Returns a list with the signals defined in the remote class. * The list only includes the signals from the class itself, but not its * super classes. Modified: trunk/ktutorial/ktutorial-editor/src/view/WaitForPropertyWidget.cpp =================================================================== --- trunk/ktutorial/ktutorial-editor/src/view/WaitForPropertyWidget.cpp 2011-05-16 22:42:33 UTC (rev 307) +++ trunk/ktutorial/ktutorial-editor/src/view/WaitForPropertyWidget.cpp 2011-05-16 22:44:36 UTC (rev 308) @@ -22,7 +22,11 @@ #include "../data/WaitForProperty.h" #ifdef QT_QTDBUS_FOUND +#include <KDebug> + #include "RemoteObjectNameWidget.h" +#include "../targetapplication/RemoteClass.h" +#include "../targetapplication/RemoteObject.h" #endif //public: @@ -48,6 +52,9 @@ ui->valueVerticalLayout->insertWidget(0, mRemoteObjectNameWidget); + connect(mRemoteObjectNameWidget, SIGNAL(remoteObjectChosen(RemoteObject*)), + this, SLOT(setChosenRemoteObject(RemoteObject*))); + mRemoteObjectNameWidget->setName(waitForProperty->objectName()); #else ui->objectNameLineEdit->setText(waitForProperty->objectName()); @@ -82,3 +89,41 @@ mWaitForProperty->setValue(value); } } + +//private: + +#ifdef QT_QTDBUS_FOUND +void WaitForPropertyWidget::setPropertyCompletion(RemoteClass* remoteClass) +throw (DBusException) { + KCompletion* completion = ui->propertyNameLineEdit->completionObject(); + completion->clear(); + completion->setOrder(KCompletion::Sorted); + + while (remoteClass) { + foreach (const QString& property, remoteClass->propertyList()) { + completion->addItem(property); + } + + remoteClass = remoteClass->superClass(); + } +} +#endif + +//private slots: + +#ifdef QT_QTDBUS_FOUND +void WaitForPropertyWidget::setChosenRemoteObject(RemoteObject* remoteObject) { + if (!remoteObject) { + setPropertyCompletion(0); + return; + } + + try { + setPropertyCompletion(remoteObject->remoteClass()); + } catch (DBusException e) { + kWarning() << "The property completion could not be set, there was a " + << "problem getting the class of the remote object (" + << e.message() << ")."; + } +} +#endif Modified: trunk/ktutorial/ktutorial-editor/src/view/WaitForPropertyWidget.h =================================================================== --- trunk/ktutorial/ktutorial-editor/src/view/WaitForPropertyWidget.h 2011-05-16 22:42:33 UTC (rev 307) +++ trunk/ktutorial/ktutorial-editor/src/view/WaitForPropertyWidget.h 2011-05-16 22:44:36 UTC (rev 308) @@ -22,6 +22,10 @@ #include "EditionWidget.h" #ifdef QT_QTDBUS_FOUND +#include "../targetapplication/DBusException.h" + +class RemoteClass; +class RemoteObject; class RemoteObjectNameWidget; #endif @@ -75,8 +79,28 @@ * The widget to get the name of a remote object. */ RemoteObjectNameWidget* mRemoteObjectNameWidget; + + /** + * Sets the completion of the property line edit to the properties contained + * in the given remote class and its super classes. + * + * @param remoteClass The class to get its property list. + */ + void setPropertyCompletion(RemoteClass* remoteClass) throw (DBusException); #endif +private slots: + +#ifdef QT_QTDBUS_FOUND + /** + * Sets the completion for the property names based in the chosen remote + * object. + * + * @param remoteObject The chosen RemoteObject. + */ + void setChosenRemoteObject(RemoteObject* remoteObject); +#endif + }; #endif Modified: trunk/ktutorial/ktutorial-editor/tests/unit/targetapplication/RemoteClassStubs.h =================================================================== --- trunk/ktutorial/ktutorial-editor/tests/unit/targetapplication/RemoteClassStubs.h 2011-05-16 22:42:33 UTC (rev 307) +++ trunk/ktutorial/ktutorial-editor/tests/unit/targetapplication/RemoteClassStubs.h 2011-05-16 22:44:36 UTC (rev 308) @@ -59,6 +59,15 @@ return ""; } + QStringList propertyList(const QString& className) { + QStringList propertyList; + for (int i=0; i<3; ++i) { + propertyList.append(className + "Property" + QString::number(i)); + } + + return propertyList; + } + QStringList signalList(const QString& className) { QStringList signalList; for (int i=0; i<3; ++i) { Modified: trunk/ktutorial/ktutorial-editor/tests/unit/targetapplication/RemoteClassTest.cpp =================================================================== --- trunk/ktutorial/ktutorial-editor/tests/unit/targetapplication/RemoteClassTest.cpp 2011-05-16 22:42:33 UTC (rev 307) +++ trunk/ktutorial/ktutorial-editor/tests/unit/targetapplication/RemoteClassTest.cpp 2011-05-16 22:44:36 UTC (rev 308) @@ -1,5 +1,5 @@ /*************************************************************************** - * Copyright (C) 2010 by Daniel Calviño Sánchez * + * Copyright (C) 2010-2011 by Daniel Calviño Sánchez * * dan...@gm... * * * * This program is free software; you can redistribute it and/or modify * @@ -49,6 +49,9 @@ void testSuperClass(); void testSuperClassWhenRemoteClassIsNotAvailable(); + void testPropertyList(); + void testPropertyListWhenRemoteClassIsNotAvailable(); + void testSignalList(); void testSignalListWhenRemoteClassIsNotAvailable(); @@ -100,6 +103,24 @@ EXPECT_EXCEPTION(remoteClass.superClass(), DBusException); } +void RemoteClassTest::testPropertyList() { + RemoteClass remoteClass(mService, mMapper, "Class"); + + QStringList propertyList = remoteClass.propertyList(); + QCOMPARE(propertyList.count(), 3); + QCOMPARE(propertyList[0], QString("ClassProperty0")); + QCOMPARE(propertyList[1], QString("ClassProperty1")); + QCOMPARE(propertyList[2], QString("ClassProperty2")); +} + +void RemoteClassTest::testPropertyListWhenRemoteClassIsNotAvailable() { + RemoteClass remoteClass(mService, mMapper, "Class"); + + QDBusConnection::sessionBus().unregisterObject("/ktutorial/ObjectRegister"); + + EXPECT_EXCEPTION(remoteClass.propertyList(), DBusException); +} + void RemoteClassTest::testSignalList() { RemoteClass remoteClass(mService, mMapper, "Class"); Modified: trunk/ktutorial/ktutorial-editor/tests/unit/view/WaitForPropertyWidgetTest.cpp =================================================================== --- trunk/ktutorial/ktutorial-editor/tests/unit/view/WaitForPropertyWidgetTest.cpp 2011-05-16 22:42:33 UTC (rev 307) +++ trunk/ktutorial/ktutorial-editor/tests/unit/view/WaitForPropertyWidgetTest.cpp 2011-05-16 22:44:36 UTC (rev 308) @@ -24,23 +24,57 @@ #include "../data/WaitForProperty.h" +#ifdef QT_QTDBUS_FOUND +#define protected public +#define private public +#include "../targetapplication/TargetApplication.h" +#undef private +#undef protected +#endif + class WaitForPropertyWidgetTest: public QObject { Q_OBJECT private slots: + void init(); + void cleanup(); + void testConstructor(); void testSaveChanges(); + void testPropertyNameCompletion(); + private: + QString mTargetApplicationStubPath; + KLineEdit* objectNameLineEdit(WaitForPropertyWidget* widget) const; KLineEdit* propertyNameLineEdit(WaitForPropertyWidget* widget) const; KLineEdit* valueLineEdit(WaitForPropertyWidget* widget) const; }; +void WaitForPropertyWidgetTest::init() { +#ifdef QT_QTDBUS_FOUND + mTargetApplicationStubPath = QApplication::applicationDirPath() + + "/../targetapplication/TargetApplicationStub"; + + //Avoid signals from previous tests to be delivered to the next ones + //setting a new TargetApplication + delete TargetApplication::sSelf; + TargetApplication::sSelf = new TargetApplication(); +#endif +} + +void WaitForPropertyWidgetTest::cleanup() { +#ifdef QT_QTDBUS_FOUND + delete TargetApplication::sSelf; + TargetApplication::sSelf = 0; +#endif +} + void WaitForPropertyWidgetTest::testConstructor() { WaitForProperty waitFor; waitFor.setObjectName("The object name"); @@ -76,6 +110,35 @@ QCOMPARE(waitFor.value(), QString("The new value")); } +void WaitForPropertyWidgetTest::testPropertyNameCompletion() { +#ifdef QT_QTDBUS_FOUND + TargetApplication::self()->setTargetApplicationFilePath( + mTargetApplicationStubPath); + TargetApplication::self()->start(); + + //Give the target application time to start + QTest::qWait(1000); + + WaitForProperty waitFor; + WaitForPropertyWidget widget(&waitFor); + + objectNameLineEdit(&widget)->setText("The object name 830"); + + KCompletion* completion = propertyNameLineEdit(&widget)->completionObject(); + QStringList items = completion->items(); + QCOMPARE(items.count(), 6); + QCOMPARE(items[0], QString("ChildQWidgetProperty0")); + QCOMPARE(items[1], QString("ChildQWidgetProperty1")); + QCOMPARE(items[2], QString("ChildQWidgetProperty2")); + QCOMPARE(items[3], QString("QWidgetProperty0")); + QCOMPARE(items[4], QString("QWidgetProperty1")); + QCOMPARE(items[5], QString("QWidgetProperty2")); +#else + QSKIP("Property name completion is only available when KTutorial editor is " + "compiled with DBus support", SkipAll); +#endif +} + /////////////////////////////////// Helpers //////////////////////////////////// KLineEdit* WaitForPropertyWidgetTest::objectNameLineEdit( This was sent by the SourceForge.net collaborative development platform, the world's largest Open Source development site. |
From: <dan...@us...> - 2011-05-16 22:42:39
|
Revision: 307 http://ktutorial.svn.sourceforge.net/ktutorial/?rev=307&view=rev Author: danxuliu Date: 2011-05-16 22:42:33 +0000 (Mon, 16 May 2011) Log Message: ----------- Provide the names of the properties of a class in the editor support module. Modified Paths: -------------- trunk/ktutorial/ktutorial-library/src/editorsupport/ClassRegisterAdaptor.cpp trunk/ktutorial/ktutorial-library/src/editorsupport/ClassRegisterAdaptor.h trunk/ktutorial/ktutorial-library/tests/editorsupport/ClassRegisterAdaptorTest.cpp Modified: trunk/ktutorial/ktutorial-library/src/editorsupport/ClassRegisterAdaptor.cpp =================================================================== --- trunk/ktutorial/ktutorial-library/src/editorsupport/ClassRegisterAdaptor.cpp 2011-05-16 16:46:51 UTC (rev 306) +++ trunk/ktutorial/ktutorial-library/src/editorsupport/ClassRegisterAdaptor.cpp 2011-05-16 22:42:33 UTC (rev 307) @@ -1,5 +1,5 @@ /*************************************************************************** - * Copyright (C) 2010 by Daniel Calviño Sánchez * + * Copyright (C) 2010-2011 by Daniel Calviño Sánchez * * dan...@gm... * * * * This program is free software; you can redistribute it and/or modify * @@ -46,6 +46,24 @@ return metaObject->superClass()->className(); } +QStringList ClassRegisterAdaptor::propertyList(const QString& className) const { + const QMetaObject* metaObject = + mObjectRegister->metaObjectForClassName(className); + if (!metaObject) { + return QStringList(); + } + + QStringList propertyList; + for (int i=0; i<metaObject->propertyCount(); ++i) { + QMetaProperty property = metaObject->property(i); + if (isPropertyDefinedInClass(property, metaObject)) { + propertyList.append(property.name()); + } + } + + return propertyList; +} + QStringList ClassRegisterAdaptor::signalList(const QString& className) const { const QMetaObject* metaObject = mObjectRegister->metaObjectForClassName(className); @@ -66,6 +84,19 @@ //private: +bool ClassRegisterAdaptor::isPropertyDefinedInClass( + const QMetaProperty& metaProperty, + const QMetaObject* metaObject) const { + const QMetaObject* superClass = metaObject; + while ((superClass = superClass->superClass())) { + if (superClass->indexOfProperty(metaProperty.name()) != -1) { + return false; + } + } + + return true; +} + bool ClassRegisterAdaptor::isSignalDefinedInClass(const QMetaMethod& metaMethod, const QMetaObject* metaObject) const { if (metaMethod.methodType() != QMetaMethod::Signal) { Modified: trunk/ktutorial/ktutorial-library/src/editorsupport/ClassRegisterAdaptor.h =================================================================== --- trunk/ktutorial/ktutorial-library/src/editorsupport/ClassRegisterAdaptor.h 2011-05-16 16:46:51 UTC (rev 306) +++ trunk/ktutorial/ktutorial-library/src/editorsupport/ClassRegisterAdaptor.h 2011-05-16 22:42:33 UTC (rev 307) @@ -1,5 +1,5 @@ /*************************************************************************** - * Copyright (C) 2010 by Daniel Calviño Sánchez * + * Copyright (C) 2010-2011 by Daniel Calviño Sánchez * * dan...@gm... * * * * This program is free software; you can redistribute it and/or modify * @@ -59,6 +59,18 @@ QString superClass(const QString& className) const; /** + * Returns the properties of the class with the given name. + * If the class is not registered, an empty list is returned. + * + * Only the properties defined in the given class are included in the list. + * Properties from parent classes must be got using the parent class name. + * + * @param className The name of the class. + * @return The list of properties. + */ + QStringList propertyList(const QString& className) const; + + /** * Returns the signals of the class with the given name. * If the class is not registered, an empty list is returned. * @@ -78,6 +90,20 @@ ObjectRegister* mObjectRegister; /** + * Checks whether the given meta property is a property defined in the given + * meta object. + * If the property is inherited in the given meta object instead of defined + * in it, false is also returned. + * + * @param metaProperty The meta property to check. + * @param metaObject The meta object to check the meta property with. + * @return True if the meta property is a property defined in the meta + * object, false otherwise. + */ + bool isPropertyDefinedInClass(const QMetaProperty& metaProperty, + const QMetaObject* metaObject) const; + + /** * Checks whether the given meta method is a signal defined in the given * meta object. * If the signal is inherited in the given meta object instead of defined in Modified: trunk/ktutorial/ktutorial-library/tests/editorsupport/ClassRegisterAdaptorTest.cpp =================================================================== --- trunk/ktutorial/ktutorial-library/tests/editorsupport/ClassRegisterAdaptorTest.cpp 2011-05-16 16:46:51 UTC (rev 306) +++ trunk/ktutorial/ktutorial-library/tests/editorsupport/ClassRegisterAdaptorTest.cpp 2011-05-16 22:42:33 UTC (rev 307) @@ -1,5 +1,5 @@ /*************************************************************************** - * Copyright (C) 2010 by Daniel Calviño Sánchez * + * Copyright (C) 2010-2011 by Daniel Calviño Sánchez * * dan...@gm... * * * * This program is free software; you can redistribute it and/or modify * @@ -26,6 +26,20 @@ class ClassRegisterAdaptorTest: public QObject { Q_OBJECT +Q_PROPERTY(QString dummyProperty READ dummyProperty) +Q_PROPERTY(QString dummyPropertyWithNotifySignal + READ dummyPropertyWithNotifySignal NOTIFY dummySignal) + +public: + + QString dummyProperty() const { + return mDummyProperty; + } + + QString dummyPropertyWithNotifySignal() const { + return mDummyPropertyWithNotifySignal; + } + Q_SIGNALS: void dummySignal(); @@ -38,9 +52,17 @@ void testSuperClass(); void testSuperClassWithUnknownClassName(); + void testPropertyList(); + void testPropertyListWithUnknownClassName(); + void testSignalList(); void testSignalListWithUnknownClassName(); +private: + + QString mDummyProperty; + QString mDummyPropertyWithNotifySignal; + }; void ClassRegisterAdaptorTest::testConstructor() { @@ -68,6 +90,27 @@ QCOMPARE(adaptor->superClass("UnknownClassName"), QString("")); } +void ClassRegisterAdaptorTest::testPropertyList() { + ObjectRegister objectRegister; + ClassRegisterAdaptor* adaptor = new ClassRegisterAdaptor(&objectRegister); + + objectRegister.idForObject(this); + + QStringList propertyList = + adaptor->propertyList("editorsupport::ClassRegisterAdaptorTest"); + QCOMPARE(propertyList.count(), 2); + QCOMPARE(propertyList[0], QString("dummyProperty")); + QCOMPARE(propertyList[1], QString("dummyPropertyWithNotifySignal")); +} + +void ClassRegisterAdaptorTest::testPropertyListWithUnknownClassName() { + ObjectRegister objectRegister; + ClassRegisterAdaptor* adaptor = new ClassRegisterAdaptor(&objectRegister); + + QStringList propertyList = adaptor->propertyList("UnknownClassName"); + QCOMPARE(propertyList.count(), 0); +} + void ClassRegisterAdaptorTest::testSignalList() { ObjectRegister objectRegister; ClassRegisterAdaptor* adaptor = new ClassRegisterAdaptor(&objectRegister); This was sent by the SourceForge.net collaborative development platform, the world's largest Open Source development site. |
From: <dan...@us...> - 2011-05-16 16:47:00
|
Revision: 306 http://ktutorial.svn.sourceforge.net/ktutorial/?rev=306&view=rev Author: danxuliu Date: 2011-05-16 16:46:51 +0000 (Mon, 16 May 2011) Log Message: ----------- Add support for WaitForProperty to wait for a property to change its value to the expected one. Modified Paths: -------------- trunk/ktutorial/ktutorial-editor/src/data/CMakeLists.txt trunk/ktutorial/ktutorial-editor/src/serialization/JavascriptExporter.cpp trunk/ktutorial/ktutorial-editor/src/serialization/JavascriptExporter.h trunk/ktutorial/ktutorial-editor/src/serialization/Tutorial.xsd trunk/ktutorial/ktutorial-editor/src/serialization/TutorialReader.cpp trunk/ktutorial/ktutorial-editor/src/serialization/TutorialReader.h trunk/ktutorial/ktutorial-editor/src/serialization/TutorialWriter.cpp trunk/ktutorial/ktutorial-editor/src/serialization/TutorialWriter.h 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/data/CMakeLists.txt trunk/ktutorial/ktutorial-editor/tests/unit/serialization/JavascriptExporterTest.cpp trunk/ktutorial/ktutorial-editor/tests/unit/serialization/TutorialReaderTest.cpp trunk/ktutorial/ktutorial-editor/tests/unit/serialization/TutorialWriterTest.cpp 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/data/WaitForProperty.cpp trunk/ktutorial/ktutorial-editor/src/data/WaitForProperty.h trunk/ktutorial/ktutorial-editor/src/view/WaitForPropertyTreeItem.cpp trunk/ktutorial/ktutorial-editor/src/view/WaitForPropertyTreeItem.h trunk/ktutorial/ktutorial-editor/src/view/WaitForPropertyWidget.cpp trunk/ktutorial/ktutorial-editor/src/view/WaitForPropertyWidget.h trunk/ktutorial/ktutorial-editor/src/view/WaitForPropertyWidget.ui trunk/ktutorial/ktutorial-editor/tests/unit/data/WaitForPropertyTest.cpp trunk/ktutorial/ktutorial-editor/tests/unit/view/WaitForPropertyTreeItemTest.cpp trunk/ktutorial/ktutorial-editor/tests/unit/view/WaitForPropertyWidgetTest.cpp Modified: trunk/ktutorial/ktutorial-editor/src/data/CMakeLists.txt =================================================================== --- trunk/ktutorial/ktutorial-editor/src/data/CMakeLists.txt 2011-05-16 16:39:27 UTC (rev 305) +++ trunk/ktutorial/ktutorial-editor/src/data/CMakeLists.txt 2011-05-16 16:46:51 UTC (rev 306) @@ -6,6 +6,7 @@ WaitForComposed.cpp WaitForEvent.cpp WaitForNot.cpp + WaitForProperty.cpp WaitForSignal.cpp WaitForWindow.cpp ) Added: trunk/ktutorial/ktutorial-editor/src/data/WaitForProperty.cpp =================================================================== --- trunk/ktutorial/ktutorial-editor/src/data/WaitForProperty.cpp (rev 0) +++ trunk/ktutorial/ktutorial-editor/src/data/WaitForProperty.cpp 2011-05-16 16:46:51 UTC (rev 306) @@ -0,0 +1,85 @@ +/*************************************************************************** + * Copyright (C) 2011 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 "WaitForProperty.h" + +//public: + +WaitForProperty::WaitForProperty(QObject* parent): WaitFor(parent) { +} + +WaitFor* WaitForProperty::clone() const { + WaitForProperty* cloned = new WaitForProperty(); + cloned->setObjectName(mObjectName); + cloned->setPropertyName(mPropertyName); + cloned->setValue(mValue); + + return cloned; +} + +bool WaitForProperty::equals(const WaitFor& waitFor) const { + if (!qobject_cast<const WaitForProperty*>(&waitFor)) { + return false; + } + + const WaitForProperty* waitForProperty = + static_cast<const WaitForProperty*>(&waitFor); + if (waitForProperty->objectName() != mObjectName) { + return false; + } + + if (waitForProperty->propertyName() != mPropertyName) { + return false; + } + + if (waitForProperty->value() != mValue) { + return false; + } + + return true; +} + +QString WaitForProperty::objectName() const { + return mObjectName; +} + +void WaitForProperty::setObjectName(const QString& objectName) { + mObjectName = objectName; + + emit dataChanged(this); +} + +QString WaitForProperty::propertyName() const { + return mPropertyName; +} + +void WaitForProperty::setPropertyName(const QString& propertyName) { + mPropertyName = propertyName; + + emit dataChanged(this); +} + +QString WaitForProperty::value() const { + return mValue; +} + +void WaitForProperty::setValue(const QString& value) { + mValue = value; + + emit dataChanged(this); +} Property changes on: trunk/ktutorial/ktutorial-editor/src/data/WaitForProperty.cpp ___________________________________________________________________ Added: svn:eol-style + native Added: trunk/ktutorial/ktutorial-editor/src/data/WaitForProperty.h =================================================================== --- trunk/ktutorial/ktutorial-editor/src/data/WaitForProperty.h (rev 0) +++ trunk/ktutorial/ktutorial-editor/src/data/WaitForProperty.h 2011-05-16 16:46:51 UTC (rev 306) @@ -0,0 +1,64 @@ +/*************************************************************************** + * Copyright (C) 2011 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 WAITFORPROPERTY_H +#define WAITFORPROPERTY_H + +#include "WaitFor.h" + +/** + * Container for conditions that wait for a property to have some value data. + * It stores the data used in KTutorial WaitForProperty, 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::WaitForProperty + * object. + * + * When any attribute is modified, dataChanged(WaitFor*) signal is emitted. + */ +class WaitForProperty: public WaitFor { +Q_OBJECT +public: + + /** + * Creates a new WaitForProperty. + * + * @param parent The parent QObject. + */ + WaitForProperty(QObject* parent = 0); + + virtual WaitFor* clone() const; + virtual bool equals(const WaitFor& waitFor) const; + + QString objectName() const; + void setObjectName(const QString& objectName); + + QString propertyName() const; + void setPropertyName(const QString& propertyName); + + QString value() const; + void setValue(const QString& value); + +private: + + QString mObjectName; + QString mPropertyName; + QString mValue; + +}; + +#endif Property changes on: trunk/ktutorial/ktutorial-editor/src/data/WaitForProperty.h ___________________________________________________________________ Added: svn:eol-style + native Modified: trunk/ktutorial/ktutorial-editor/src/serialization/JavascriptExporter.cpp =================================================================== --- trunk/ktutorial/ktutorial-editor/src/serialization/JavascriptExporter.cpp 2011-05-16 16:39:27 UTC (rev 305) +++ trunk/ktutorial/ktutorial-editor/src/serialization/JavascriptExporter.cpp 2011-05-16 16:46:51 UTC (rev 306) @@ -1,5 +1,5 @@ /*************************************************************************** - * Copyright (C) 2010 by Daniel Calviño Sánchez * + * Copyright (C) 2010-2011 by Daniel Calviño Sánchez * * dan...@gm... * * * * This program is free software; you can redistribute it and/or modify * @@ -29,6 +29,7 @@ #include "../data/WaitForComposed.h" #include "../data/WaitForEvent.h" #include "../data/WaitForNot.h" +#include "../data/WaitForProperty.h" #include "../data/WaitForSignal.h" #include "../data/WaitForWindow.h" @@ -270,6 +271,9 @@ if (qobject_cast<const WaitForNot*>(waitFor)) { return writeWaitFor(static_cast<const WaitForNot*>(waitFor)); } + if (qobject_cast<const WaitForProperty*>(waitFor)) { + return writeWaitFor(static_cast<const WaitForProperty*>(waitFor)); + } if (qobject_cast<const WaitForSignal*>(waitFor)) { return writeWaitFor(static_cast<const WaitForSignal*>(waitFor)); } @@ -347,6 +351,38 @@ return variable; } +QString JavascriptExporter::writeWaitFor( + const WaitForProperty* waitForProperty) { + if (waitForProperty->objectName().isEmpty()) { + out() << "//Error: WaitForProperty without object name!\n"; + return ""; + } + + if (waitForProperty->propertyName().isEmpty()) { + out() << "//Error: WaitForProperty without property name!\n"; + return ""; + } + + if (waitForProperty->value().isEmpty()) { + out() << "//Error: WaitForProperty without value!\n"; + return ""; + } + + QString propertyName = waitForProperty->propertyName(); + propertyName.remove(QRegExp("\\(.*")); + QString variable = "waitFor" + toUpperCamelCase(propertyName) + + "In" + toUpperCamelCase(waitForProperty->objectName()); + variable = addVariable(variable); + + out() << variable << " = ktutorial.newWaitFor(\"WaitForProperty\");\n"; + out() << variable << ".setProperty(ktutorial.findObject(\"" + << escape(waitForProperty->objectName()) << "\"), \"" + << escape(waitForProperty->propertyName()) << "\", " + << waitForProperty->value() << ");\n"; + + return variable; +} + QString JavascriptExporter::writeWaitFor(const WaitForSignal* waitForSignal) { if (waitForSignal->emitterName().isEmpty()) { out() << "//Error: WaitForSignal without emitter name!\n"; Modified: trunk/ktutorial/ktutorial-editor/src/serialization/JavascriptExporter.h =================================================================== --- trunk/ktutorial/ktutorial-editor/src/serialization/JavascriptExporter.h 2011-05-16 16:39:27 UTC (rev 305) +++ trunk/ktutorial/ktutorial-editor/src/serialization/JavascriptExporter.h 2011-05-16 16:46:51 UTC (rev 306) @@ -1,5 +1,5 @@ /*************************************************************************** - * Copyright (C) 2010 by Daniel Calviño Sánchez * + * Copyright (C) 2010-2011 by Daniel Calviño Sánchez * * dan...@gm... * * * * This program is free software; you can redistribute it and/or modify * @@ -30,6 +30,7 @@ class WaitForComposed; class WaitForEvent; class WaitForNot; +class WaitForProperty; class WaitForSignal; class WaitForWindow; @@ -207,6 +208,18 @@ QString writeWaitFor(const WaitForNot* waitForNot); /** + * Writes the code to create and set a WaitForProperty. + * If the object name, the property name or the value aren't set, an error + * message is written instead, and an empty string returned. + * + * The value is written as is. It is neither escaped nor wrapped in quotes. + * + * @param waitForProperty The WaitForProperty. + * @return The name of the variable that holds the WaitFor. + */ + QString writeWaitFor(const WaitForProperty* waitForProperty); + + /** * 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. Modified: trunk/ktutorial/ktutorial-editor/src/serialization/Tutorial.xsd =================================================================== --- trunk/ktutorial/ktutorial-editor/src/serialization/Tutorial.xsd 2011-05-16 16:39:27 UTC (rev 305) +++ trunk/ktutorial/ktutorial-editor/src/serialization/Tutorial.xsd 2011-05-16 16:46:51 UTC (rev 306) @@ -44,6 +44,7 @@ <xsd:element name="waitForComposed" type="WaitForComposedType"/> <xsd:element name="waitForEvent" type="WaitForEventType"/> <xsd:element name="waitForNot" type="WaitForNotType"/> + <xsd:element name="waitForProperty" type="WaitForPropertyType"/> <xsd:element name="waitForSignal" type="WaitForSignalType"/> <xsd:element name="waitForWindow" type="WaitForWindowType"/> </xsd:choice> @@ -92,6 +93,12 @@ </xsd:sequence> </xsd:complexType> + <xsd:complexType name="WaitForPropertyType"> + <xsd:attribute name="objectName" type="xsd:string" use="optional"/> + <xsd:attribute name="propertyName" type="xsd:string" use="optional"/> + <xsd:attribute name="value" type="xsd:string" use="optional"/> + </xsd:complexType> + <xsd:complexType name="WaitForSignalType"> <xsd:attribute name="emitterName" type="xsd:string" use="optional"/> <xsd:attribute name="signalName" type="xsd:string" use="optional"/> Modified: trunk/ktutorial/ktutorial-editor/src/serialization/TutorialReader.cpp =================================================================== --- trunk/ktutorial/ktutorial-editor/src/serialization/TutorialReader.cpp 2011-05-16 16:39:27 UTC (rev 305) +++ trunk/ktutorial/ktutorial-editor/src/serialization/TutorialReader.cpp 2011-05-16 16:46:51 UTC (rev 306) @@ -1,5 +1,5 @@ /*************************************************************************** - * Copyright (C) 2010 by Daniel Calviño Sánchez * + * Copyright (C) 2010-2011 by Daniel Calviño Sánchez * * dan...@gm... * * * * This program is free software; you can redistribute it and/or modify * @@ -28,6 +28,7 @@ #include "../data/WaitForComposed.h" #include "../data/WaitForEvent.h" #include "../data/WaitForNot.h" +#include "../data/WaitForProperty.h" #include "../data/WaitForSignal.h" #include "../data/WaitForWindow.h" @@ -165,6 +166,9 @@ if (element.tagName() == "waitForNot") { return readWaitForNot(element); } + if (element.tagName() == "waitForProperty") { + return readWaitForProperty(element); + } if (element.tagName() == "waitForSignal") { return readWaitForSignal(element); } @@ -229,6 +233,22 @@ return waitForNot; } +WaitFor* TutorialReader::readWaitForProperty(const QDomElement& element) { + WaitForProperty* waitForProperty = new WaitForProperty(); + + if (element.hasAttribute("objectName")) { + waitForProperty->setObjectName(element.attribute("objectName")); + } + if (element.hasAttribute("propertyName")) { + waitForProperty->setPropertyName(element.attribute("propertyName")); + } + if (element.hasAttribute("value")) { + waitForProperty->setValue(element.attribute("value")); + } + + return waitForProperty; +} + WaitFor* TutorialReader::readWaitForSignal(const QDomElement& element) { WaitForSignal* waitForSignal = new WaitForSignal(); @@ -257,6 +277,7 @@ if (element.tagName() != "waitForComposed" && element.tagName() != "waitForEvent" && element.tagName() != "waitForNot" && + element.tagName() != "waitForProperty" && element.tagName() != "waitForSignal" && element.tagName() != "waitForWindow") { return false; Modified: trunk/ktutorial/ktutorial-editor/src/serialization/TutorialReader.h =================================================================== --- trunk/ktutorial/ktutorial-editor/src/serialization/TutorialReader.h 2011-05-16 16:39:27 UTC (rev 305) +++ trunk/ktutorial/ktutorial-editor/src/serialization/TutorialReader.h 2011-05-16 16:46:51 UTC (rev 306) @@ -1,5 +1,5 @@ /*************************************************************************** - * Copyright (C) 2010 by Daniel Calviño Sánchez * + * Copyright (C) 2010-2011 by Daniel Calviño Sánchez * * dan...@gm... * * * * This program is free software; you can redistribute it and/or modify * @@ -31,6 +31,7 @@ class WaitForComposed; class WaitForEvent; class WaitForNot; +class WaitForProperty; class WaitForSignal; class WaitForWindow; @@ -128,6 +129,14 @@ WaitFor* readWaitForNot(const QDomElement& element); /** + * Reads a new WaitForProperty from the "waitForProperty" XML element. + * + * @param element The element to read the WaitForProperty from. + * @return The new WaitForProperty. + */ + WaitFor* readWaitForProperty(const QDomElement& element); + + /** * Reads a new WaitForSignal from the "waitForSignal" XML element. * * @param element The element to read the WaitForSignal from. Modified: trunk/ktutorial/ktutorial-editor/src/serialization/TutorialWriter.cpp =================================================================== --- trunk/ktutorial/ktutorial-editor/src/serialization/TutorialWriter.cpp 2011-05-16 16:39:27 UTC (rev 305) +++ trunk/ktutorial/ktutorial-editor/src/serialization/TutorialWriter.cpp 2011-05-16 16:46:51 UTC (rev 306) @@ -1,5 +1,5 @@ /*************************************************************************** - * Copyright (C) 2010 by Daniel Calviño Sánchez * + * Copyright (C) 2010-2011 by Daniel Calviño Sánchez * * dan...@gm... * * * * This program is free software; you can redistribute it and/or modify * @@ -24,6 +24,7 @@ #include "../data/WaitForComposed.h" #include "../data/WaitForEvent.h" #include "../data/WaitForNot.h" +#include "../data/WaitForProperty.h" #include "../data/WaitForSignal.h" #include "../data/WaitForWindow.h" @@ -149,6 +150,10 @@ write(static_cast<const WaitForNot*>(waitFor)); return; } + if (qobject_cast<const WaitForProperty*>(waitFor)) { + write(static_cast<const WaitForProperty*>(waitFor)); + return; + } if (qobject_cast<const WaitForSignal*>(waitFor)) { write(static_cast<const WaitForSignal*>(waitFor)); return; @@ -199,6 +204,21 @@ mXmlWriter->writeEndElement(); } +void TutorialWriter::write(const WaitForProperty* waitForProperty) { + mXmlWriter->writeEmptyElement("waitForProperty"); + + if (!waitForProperty->objectName().isEmpty()) { + mXmlWriter->writeAttribute("objectName", waitForProperty->objectName()); + } + if (!waitForProperty->propertyName().isEmpty()) { + mXmlWriter->writeAttribute("propertyName", + waitForProperty->propertyName()); + } + if (!waitForProperty->value().isEmpty()) { + mXmlWriter->writeAttribute("value", waitForProperty->value()); + } +} + void TutorialWriter::write(const WaitForSignal* waitForSignal) { mXmlWriter->writeEmptyElement("waitForSignal"); Modified: trunk/ktutorial/ktutorial-editor/src/serialization/TutorialWriter.h =================================================================== --- trunk/ktutorial/ktutorial-editor/src/serialization/TutorialWriter.h 2011-05-16 16:39:27 UTC (rev 305) +++ trunk/ktutorial/ktutorial-editor/src/serialization/TutorialWriter.h 2011-05-16 16:46:51 UTC (rev 306) @@ -1,5 +1,5 @@ /*************************************************************************** - * Copyright (C) 2010 by Daniel Calviño Sánchez * + * Copyright (C) 2010-2011 by Daniel Calviño Sánchez * * dan...@gm... * * * * This program is free software; you can redistribute it and/or modify * @@ -28,6 +28,7 @@ class WaitForComposed; class WaitForEvent; class WaitForNot; +class WaitForProperty; class WaitForSignal; class WaitForWindow; @@ -116,6 +117,13 @@ void write(const WaitForNot* waitForNot); /** + * Writes the XML serialization of the given WaitForProperty. + * + * @param waitForProperty The WaitForProperty to get its XML serialization. + */ + void write(const WaitForProperty* waitForProperty); + + /** * Writes the XML serialization of the given WaitForSignal. * * @param waitForSignal The WaitForSignal to get its XML serialization. Modified: trunk/ktutorial/ktutorial-editor/src/view/CMakeLists.txt =================================================================== --- trunk/ktutorial/ktutorial-editor/src/view/CMakeLists.txt 2011-05-16 16:39:27 UTC (rev 305) +++ trunk/ktutorial/ktutorial-editor/src/view/CMakeLists.txt 2011-05-16 16:46:51 UTC (rev 306) @@ -27,6 +27,8 @@ WaitForEventTreeItem.cpp WaitForEventWidget.cpp WaitForNotTreeItem.cpp + WaitForPropertyTreeItem.cpp + WaitForPropertyWidget.cpp WaitForSignalTreeItem.cpp WaitForSignalWidget.cpp WaitForTreeItem.cpp @@ -60,6 +62,7 @@ StepDataWidget.ui TutorialInformationWidget.ui WaitForEventWidget.ui + WaitForPropertyWidget.ui WaitForSignalWidget.ui WaitForWidget.ui WaitForWindowWidget.ui Modified: trunk/ktutorial/ktutorial-editor/src/view/NewWaitForWidget.cpp =================================================================== --- trunk/ktutorial/ktutorial-editor/src/view/NewWaitForWidget.cpp 2011-05-16 16:39:27 UTC (rev 305) +++ trunk/ktutorial/ktutorial-editor/src/view/NewWaitForWidget.cpp 2011-05-16 16:46:51 UTC (rev 306) @@ -1,5 +1,5 @@ /*************************************************************************** - * Copyright (C) 2010 by Daniel Calviño Sánchez * + * Copyright (C) 2010-2011 by Daniel Calviño Sánchez * * dan...@gm... * * * * This program is free software; you can redistribute it and/or modify * @@ -22,6 +22,7 @@ #include "../data/WaitForComposed.h" #include "../data/WaitForEvent.h" #include "../data/WaitForNot.h" +#include "../data/WaitForProperty.h" #include "../data/WaitForSignal.h" #include "../data/WaitForWindow.h" @@ -55,6 +56,8 @@ return new WaitForEvent(); } else if (index == 5) { return new WaitForWindow(); + } else if (index == 6) { + return new WaitForProperty(); } return 0; Modified: trunk/ktutorial/ktutorial-editor/src/view/NewWaitForWidget.ui =================================================================== --- trunk/ktutorial/ktutorial-editor/src/view/NewWaitForWidget.ui 2011-05-16 16:39:27 UTC (rev 305) +++ trunk/ktutorial/ktutorial-editor/src/view/NewWaitForWidget.ui 2011-05-16 16:46:51 UTC (rev 306) @@ -71,6 +71,11 @@ <string comment="@item:inlistbox">The specified window is shown</string> </property> </item> + <item> + <property name="text"> + <string comment="@item:inlistbox">The specified property has certain value</string> + </property> + </item> </widget> </item> </layout> Added: trunk/ktutorial/ktutorial-editor/src/view/WaitForPropertyTreeItem.cpp =================================================================== --- trunk/ktutorial/ktutorial-editor/src/view/WaitForPropertyTreeItem.cpp (rev 0) +++ trunk/ktutorial/ktutorial-editor/src/view/WaitForPropertyTreeItem.cpp 2011-05-16 16:46:51 UTC (rev 306) @@ -0,0 +1,74 @@ +/*************************************************************************** + * Copyright (C) 2011 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 "WaitForPropertyTreeItem.h" + +#include <KLocalizedString> + +#include "../data/WaitForProperty.h" + +//public: + +WaitForPropertyTreeItem::WaitForPropertyTreeItem( + WaitForProperty* waitForProperty, + TreeItem* parent): + WaitForTreeItem(waitForProperty, parent) { + mObjectName = waitForProperty->objectName(); + mPropertyName = waitForProperty->propertyName(); + mValue = waitForProperty->value(); + + connect(waitForProperty, SIGNAL(dataChanged(WaitFor*)), + this, SLOT(update(WaitFor*))); +} + +QString WaitForPropertyTreeItem::text() const { + QString objectName; + if (mObjectName.isEmpty()) { + objectName = i18nc("@item", "(object name not set)"); + } else { + objectName = "\"" + mObjectName + "\""; + } + + QString propertyName; + if (mPropertyName.isEmpty()) { + propertyName = i18nc("@item", "(property not set)"); + } else { + propertyName = "\"" + mPropertyName + "\""; + } + + QString value; + if (mValue.isEmpty()) { + value = i18nc("@item", "(value not set)"); + } else { + value = mValue; + } + + return i18nc("@item", "When the property %1 in the object %2 changes to " + "the value %3", propertyName, objectName, value); +} + +//private: + +void WaitForPropertyTreeItem::update(WaitFor* waitFor) { + WaitForProperty* waitForProperty = static_cast<WaitForProperty*>(waitFor); + mObjectName = waitForProperty->objectName(); + mPropertyName = waitForProperty->propertyName(); + mValue = waitForProperty->value(); + + emit dataChanged(this); +} Property changes on: trunk/ktutorial/ktutorial-editor/src/view/WaitForPropertyTreeItem.cpp ___________________________________________________________________ Added: svn:eol-style + native Added: trunk/ktutorial/ktutorial-editor/src/view/WaitForPropertyTreeItem.h =================================================================== --- trunk/ktutorial/ktutorial-editor/src/view/WaitForPropertyTreeItem.h (rev 0) +++ trunk/ktutorial/ktutorial-editor/src/view/WaitForPropertyTreeItem.h 2011-05-16 16:46:51 UTC (rev 306) @@ -0,0 +1,90 @@ +/*************************************************************************** + * Copyright (C) 2011 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 WAITFORPROPERTYTREEITEM_H +#define WAITFORPROPERTYTREEITEM_H + +#include "WaitForTreeItem.h" + +class WaitForProperty; + +/** + * A TreeItem that represents a WaitForProperty. + * The tree representation of a WaitForProperty is a plain text: + * When the property "property name" in the object "object name" changes to the + * value value + * + * If the property, the object name or the value aren't set yet, a placeholder + * is put instead. Property placeholder is "(property not set)", the object name + * placeholder is "(object name not set)" , and the value placeholder is "(value + * not set)" (without quotes, but with parenthesis). + * + * Whenever the WaitForProperty data changes, the WaitForPropertyTreeItem text + * is updated as needed. + */ +class WaitForPropertyTreeItem: public WaitForTreeItem { +Q_OBJECT +public: + + /** + * Creates a new WaitForPropertyTreeItem for the given WaitForProperty and + * with the given parent. + * + * @param waitForProperty The WaitForProperty to represent. + * @param parent The parent TreeItem. + */ + explicit WaitForPropertyTreeItem(WaitForProperty* waitForProperty, + TreeItem* parent = 0); + + /** + * Returns the description of the WaitForProperty. + * + * @return The text for this TreeItem. + */ + virtual QString text() const; + +private: + + /** + * The object name of the WaitForProperty. + */ + QString mObjectName; + + /** + * The property name of the WaitForProperty. + */ + QString mPropertyName; + + /** + * The value of the WaitForProperty. + */ + QString mValue; + +private Q_SLOTS: + + /** + * Updates this WaitForPropertyTreeItem when the data of its WaitForProperty + * changed. + * + * @param waitFor The WaitForProperty. + */ + void update(WaitFor* waitFor); + +}; + +#endif Property changes on: trunk/ktutorial/ktutorial-editor/src/view/WaitForPropertyTreeItem.h ___________________________________________________________________ Added: svn:eol-style + native Added: trunk/ktutorial/ktutorial-editor/src/view/WaitForPropertyWidget.cpp =================================================================== --- trunk/ktutorial/ktutorial-editor/src/view/WaitForPropertyWidget.cpp (rev 0) +++ trunk/ktutorial/ktutorial-editor/src/view/WaitForPropertyWidget.cpp 2011-05-16 16:46:51 UTC (rev 306) @@ -0,0 +1,84 @@ +/*************************************************************************** + * Copyright (C) 2011 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 "WaitForPropertyWidget.h" + +#include "ui_WaitForPropertyWidget.h" +#include "../data/WaitForProperty.h" + +#ifdef QT_QTDBUS_FOUND +#include "RemoteObjectNameWidget.h" +#endif + +//public: + +WaitForPropertyWidget::WaitForPropertyWidget(WaitForProperty* waitForProperty, + QWidget* parent): + EditionWidget(parent), + mWaitForProperty(waitForProperty) { + + ui = new Ui::WaitForPropertyWidget(); +#ifdef QT_QTDBUS_FOUND + //Hack: RemoteObjectNameWidget is created before the other widgets to be + //the first widget in the tab order. I feel dumb, but I tried using + //setTabOrder and got nothing... + mRemoteObjectNameWidget = new RemoteObjectNameWidget(this); +#endif + ui->setupUi(this); + +#ifdef QT_QTDBUS_FOUND + //Replace ui->objectNameLineEdit with mRemoteObjectNameWidget + ui->valueVerticalLayout->removeWidget(ui->objectNameLineEdit); + delete ui->objectNameLineEdit; + + ui->valueVerticalLayout->insertWidget(0, mRemoteObjectNameWidget); + + mRemoteObjectNameWidget->setName(waitForProperty->objectName()); +#else + ui->objectNameLineEdit->setText(waitForProperty->objectName()); +#endif + + ui->propertyNameLineEdit->setText(waitForProperty->propertyName()); + + ui->valueLineEdit->setText(waitForProperty->value()); +} + +WaitForPropertyWidget::~WaitForPropertyWidget() { + delete ui; +} + +void WaitForPropertyWidget::saveChanges() { +#ifdef QT_QTDBUS_FOUND + QString objectName = mRemoteObjectNameWidget->name(); +#else + QString objectName = ui->objectNameLineEdit->text(); +#endif + if (mWaitForProperty->objectName() != objectName) { + mWaitForProperty->setObjectName(objectName); + } + + QString propertyName = ui->propertyNameLineEdit->text(); + if (mWaitForProperty->propertyName() != propertyName) { + mWaitForProperty->setPropertyName(propertyName); + } + + QString value = ui->valueLineEdit->text(); + if (mWaitForProperty->value() != value) { + mWaitForProperty->setValue(value); + } +} Property changes on: trunk/ktutorial/ktutorial-editor/src/view/WaitForPropertyWidget.cpp ___________________________________________________________________ Added: svn:eol-style + native Added: trunk/ktutorial/ktutorial-editor/src/view/WaitForPropertyWidget.h =================================================================== --- trunk/ktutorial/ktutorial-editor/src/view/WaitForPropertyWidget.h (rev 0) +++ trunk/ktutorial/ktutorial-editor/src/view/WaitForPropertyWidget.h 2011-05-16 16:46:51 UTC (rev 306) @@ -0,0 +1,82 @@ +/*************************************************************************** + * Copyright (C) 2011 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 WAITFORPROPERTYWIDGET_H +#define WAITFORPROPERTYWIDGET_H + +#include "EditionWidget.h" + +#ifdef QT_QTDBUS_FOUND +class RemoteObjectNameWidget; +#endif + +class WaitForProperty; + +namespace Ui { +class WaitForPropertyWidget; +} + +/** + * Edition widget for the condition to wait for a property. + */ +class WaitForPropertyWidget: public EditionWidget { +Q_OBJECT +public: + + /** + * Creates a new WaitForPropertyWidget for the given WaitForProperty. + * + * @param waitForProperty The WaitForProperty to set its data. + * @param parent The parent QWidget. + */ + explicit WaitForPropertyWidget(WaitForProperty* waitForProperty, + QWidget* parent = 0); + + /** + * Destroys this widget. + */ + virtual ~WaitForPropertyWidget(); + + /** + * Saves the object name, the property name and the value in the + * WaitForProperty. + */ + virtual void saveChanges(); + +private: + + /** + * The WaitForProperty to edit. + */ + WaitForProperty* mWaitForProperty; + + /** + * The Ui Designer generated class. + */ + Ui::WaitForPropertyWidget* ui; + +#ifdef QT_QTDBUS_FOUND + /** + * The widget to get the name of a remote object. + */ + RemoteObjectNameWidget* mRemoteObjectNameWidget; +#endif + +}; + +#endif Property changes on: trunk/ktutorial/ktutorial-editor/src/view/WaitForPropertyWidget.h ___________________________________________________________________ Added: svn:eol-style + native Added: trunk/ktutorial/ktutorial-editor/src/view/WaitForPropertyWidget.ui =================================================================== --- trunk/ktutorial/ktutorial-editor/src/view/WaitForPropertyWidget.ui (rev 0) +++ trunk/ktutorial/ktutorial-editor/src/view/WaitForPropertyWidget.ui 2011-05-16 16:46:51 UTC (rev 306) @@ -0,0 +1,123 @@ +<?xml version="1.0" encoding="UTF-8"?> +<ui version="4.0"> + <class>WaitForPropertyWidget</class> + <widget class="QWidget" name="WaitForPropertyWidget"> + <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 property to wait for</string> + </property> + <property name="whatsThis"> + <string comment="@info:whatsthis"><para>Set the object name, the property name and the value to wait for.</para></string> + </property> + <layout class="QVBoxLayout" name="WaitForPropertyVerticalLayout"> + <item> + <widget class="QGroupBox" name="waitForPropertyGroupBox"> + <property name="title"> + <string comment="@title:group">Wait for property</string> + </property> + <layout class="QHBoxLayout" name="waitForPropertyGroupBoxHorizontalLayout"> + <item> + <layout class="QVBoxLayout" name="labelVerticalLayout"> + <item> + <widget class="QLabel" name="objectNameLabel"> + <property name="text"> + <string comment="@label:textbox">Object name:</string> + </property> + <property name="alignment"> + <set>Qt::AlignRight|Qt::AlignTrailing|Qt::AlignVCenter</set> + </property> + </widget> + </item> + <item> + <widget class="QLabel" name="propertyNameLabel"> + <property name="text"> + <string comment="@label:textbox">Property name:</string> + </property> + <property name="alignment"> + <set>Qt::AlignRight|Qt::AlignTrailing|Qt::AlignVCenter</set> + </property> + <property name="buddy"> + <cstring>propertyNameLineEdit</cstring> + </property> + </widget> + </item> + <item> + <widget class="QLabel" name="valueLabel"> + <property name="text"> + <string comment="@label:textbox">Value:</string> + </property> + <property name="alignment"> + <set>Qt::AlignRight|Qt::AlignTrailing|Qt::AlignVCenter</set> + </property> + <property name="buddy"> + <cstring>valueLineEdit</cstring> + </property> + </widget> + </item> + </layout> + </item> + <item> + <layout class="QVBoxLayout" name="valueVerticalLayout"> + <item> + <widget class="KLineEdit" name="objectNameLineEdit"> + <property name="whatsThis"> + <string comment="@info:whatsthis"><para>The name of the QObject that contains the property.</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="propertyNameLineEdit"> + <property name="whatsThis"> + <string comment="@info:whatsthis"><para>The name of the property.</para> +<para>Not every property can be used to wait until its value changes to the expected one. Only properties that have a notify signal can be used with that purpose.</para> +<para>Properties that do not have a notify signal can still be used to enrich other conditions (for example, waiting for a signal to be emitted but only changing to the next step if, in addition, some property has some value), but they can not be used alone as single conditions in a reaction.</para></string> + </property> + </widget> + </item> + <item> + <widget class="KLineEdit" name="valueLineEdit"> + <property name="whatsThis"> + <string comment="@info:whatsthis"><para>The expected value of the property.</para> +<para>The value is copied as is to the script. That means that it has to be written with the syntax of the script language that the tutorial is going to be exported to. For example, if the tutorial is going to be exported to Javascript and the value to wait for is a text, the value has to be written as <em>"The expected text"</em> (wrapped in quotes).</para> +<para>The value can even contain a programming expression in the script language. For example, something like <em>t.i18nc("@item:inlistbox", "Certain item text")</em> would be used to wait for the localized text of an item in a combo box.</para></string> + </property> + </widget> + </item> + </layout> + </item> + </layout> + </widget> + </item> + <item> + <spacer name="waitForPropertyWidgetSpacer"> + <property name="orientation"> + <enum>Qt::Vertical</enum> + </property> + <property name="sizeHint" stdset="0"> + <size> + <width>20</width> + <height>20</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 2011-05-16 16:39:27 UTC (rev 305) +++ trunk/ktutorial/ktutorial-editor/src/view/WaitForTreeItem.cpp 2011-05-16 16:46:51 UTC (rev 306) @@ -1,5 +1,5 @@ /*************************************************************************** - * Copyright (C) 2010 by Daniel Calviño Sánchez * + * Copyright (C) 2010-2011 by Daniel Calviño Sánchez * * dan...@gm... * * * * This program is free software; you can redistribute it and/or modify * @@ -20,11 +20,13 @@ #include "WaitForComposedTreeItem.h" #include "WaitForEventTreeItem.h" #include "WaitForNotTreeItem.h" +#include "WaitForPropertyTreeItem.h" #include "WaitForSignalTreeItem.h" #include "WaitForWindowTreeItem.h" #include "../data/WaitForComposed.h" #include "../data/WaitForEvent.h" #include "../data/WaitForNot.h" +#include "../data/WaitForProperty.h" #include "../data/WaitForSignal.h" #include "../data/WaitForWindow.h" @@ -47,6 +49,11 @@ parent); } + if (qobject_cast<WaitForProperty*>(waitFor)) { + return new WaitForPropertyTreeItem( + static_cast<WaitForProperty*>(waitFor), parent); + } + if (qobject_cast<WaitForSignal*>(waitFor)) { return new WaitForSignalTreeItem(static_cast<WaitForSignal*>(waitFor), parent); Modified: trunk/ktutorial/ktutorial-editor/src/view/WaitForWidget.cpp =================================================================== --- trunk/ktutorial/ktutorial-editor/src/view/WaitForWidget.cpp 2011-05-16 16:39:27 UTC (rev 305) +++ trunk/ktutorial/ktutorial-editor/src/view/WaitForWidget.cpp 2011-05-16 16:46:51 UTC (rev 306) @@ -1,5 +1,5 @@ /*************************************************************************** - * Copyright (C) 2010 by Daniel Calviño Sánchez * + * Copyright (C) 2010-2011 by Daniel Calviño Sánchez * * dan...@gm... * * * * This program is free software; you can redistribute it and/or modify * @@ -25,12 +25,14 @@ #include "TextTreeItem.h" #include "TreeModel.h" #include "WaitForEventWidget.h" +#include "WaitForPropertyWidget.h" #include "WaitForSignalWidget.h" #include "WaitForWindowWidget.h" #include "WaitForTreeItem.h" #include "../data/WaitForComposed.h" #include "../data/WaitForEvent.h" #include "../data/WaitForNot.h" +#include "../data/WaitForProperty.h" #include "../data/WaitForSignal.h" #include "../data/WaitForWindow.h" @@ -132,6 +134,14 @@ return; } + if (qobject_cast<WaitForProperty*>(selectedWaitFor)) { + ui->addButton->setEnabled(false); + ui->editButton->setEnabled(true); + ui->removeButton->setEnabled(true); + + return; + } + if (qobject_cast<WaitForSignal*>(selectedWaitFor)) { ui->addButton->setEnabled(false); ui->editButton->setEnabled(true); @@ -228,6 +238,12 @@ editionWidget = new WaitForEventWidget(waitForEvent, this); } + if (qobject_cast<WaitForProperty*>(mCurrentWaitFor)) { + WaitForProperty* waitForProperty = + static_cast<WaitForProperty*>(mCurrentWaitFor); + editionWidget = new WaitForPropertyWidget(waitForProperty, this); + } + if (qobject_cast<WaitForSignal*>(mCurrentWaitFor)) { WaitForSignal* waitForSignal = static_cast<WaitForSignal*>(mCurrentWaitFor); Modified: trunk/ktutorial/ktutorial-editor/tests/unit/data/CMakeLists.txt =================================================================== --- trunk/ktutorial/ktutorial-editor/tests/unit/data/CMakeLists.txt 2011-05-16 16:39:27 UTC (rev 305) +++ trunk/ktutorial/ktutorial-editor/tests/unit/data/CMakeLists.txt 2011-05-16 16:46:51 UTC (rev 306) @@ -19,6 +19,7 @@ WaitForComposed WaitForEvent WaitForNot + WaitForProperty WaitForSignal WaitForWindow ) @@ -37,6 +38,7 @@ WaitForComposed WaitForEvent WaitForNot + WaitForProperty WaitForSignal WaitForWindow ) Added: trunk/ktutorial/ktutorial-editor/tests/unit/data/WaitForPropertyTest.cpp =================================================================== --- trunk/ktutorial/ktutorial-editor/tests/unit/data/WaitForPropertyTest.cpp (rev 0) +++ trunk/ktutorial/ktutorial-editor/tests/unit/data/WaitForPropertyTest.cpp 2011-05-16 16:46:51 UTC (rev 306) @@ -0,0 +1,175 @@ +/*************************************************************************** + * Copyright (C) 2011 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 "WaitForProperty.h" + +class WaitForPropertyTest: public QObject { +Q_OBJECT + +private slots: + + void initTestCase(); + + void testConstructor(); + + void testClone(); + + void testEquals(); + + void testSetObjectName(); + + void testSetPropertyName(); + + void testSetValue(); + +private: + + int mWaitForStarType; + + void assertWaitForProperty(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 WaitForPropertyTest::initTestCase() { + //WaitFor* must be registered in order to be used with QSignalSpy + mWaitForStarType = qRegisterMetaType<WaitFor*>("WaitFor*"); +} + +void WaitForPropertyTest::testConstructor() { + QObject parent; + WaitForProperty* waitForProperty = new WaitForProperty(&parent); + + QCOMPARE(waitForProperty->parent(), &parent); +} + +void WaitForPropertyTest::testClone() { + WaitForProperty waitForProperty; + waitForProperty.setObjectName("The object name"); + waitForProperty.setPropertyName("The property name"); + waitForProperty.setValue("The value"); + + WaitForProperty* cloned = + static_cast<WaitForProperty*>(waitForProperty.clone()); + + QVERIFY(cloned != &waitForProperty); + QCOMPARE(cloned->objectName(), waitForProperty.objectName()); + QCOMPARE(cloned->propertyName(), waitForProperty.propertyName()); + QCOMPARE(cloned->value(), waitForProperty.value()); + delete cloned; +} + +void WaitForPropertyTest::testEquals() { + WaitForProperty waitForProperty1; + waitForProperty1.setObjectName("The object name"); + waitForProperty1.setPropertyName("The property name"); + waitForProperty1.setValue("The value"); + WaitForProperty waitForProperty2; + + QCOMPARE(waitForProperty1 == waitForProperty2, false); + QCOMPARE(waitForProperty2 == waitForProperty1, false); + + waitForProperty2.setObjectName("The object name"); + waitForProperty2.setPropertyName("The property name"); + waitForProperty2.setValue("The value"); + + QCOMPARE(waitForProperty1 == waitForProperty2, true); + QCOMPARE(waitForProperty2 == waitForProperty1, true); + + StubWaitFor stubWaitFor; + + QCOMPARE(waitForProperty1 == stubWaitFor, false); +} + +void WaitForPropertyTest::testSetObjectName() { + WaitForProperty waitForProperty; + + QSignalSpy dataChangedSpy(&waitForProperty, SIGNAL(dataChanged(WaitFor*))); + + waitForProperty.setObjectName("The object name"); + + QCOMPARE(waitForProperty.objectName(), QString("The object name")); + QCOMPARE(dataChangedSpy.count(), 1); + assertWaitForProperty(dataChangedSpy, 0, &waitForProperty); +} + +void WaitForPropertyTest::testSetPropertyName() { + WaitForProperty waitForProperty; + + QSignalSpy dataChangedSpy(&waitForProperty, SIGNAL(dataChanged(WaitFor*))); + + waitForProperty.setPropertyName("The property name"); + + QCOMPARE(waitForProperty.propertyName(), QString("The property name")); + QCOMPARE(dataChangedSpy.count(), 1); + assertWaitForProperty(dataChangedSpy, 0, &waitForProperty); +} + +void WaitForPropertyTest::testSetValue() { + WaitForProperty waitForProperty; + + QSignalSpy dataChangedSpy(&waitForProperty, SIGNAL(dataChanged(WaitFor*))); + + waitForProperty.setValue("The value"); + + QCOMPARE(waitForProperty.value(), QString("The value")); + QCOMPARE(dataChangedSpy.count(), 1); + assertWaitForProperty(dataChangedSpy, 0, &waitForProperty); +} + +//WaitFor* must be declared as a metatype to be used in qvariant_cast +Q_DECLARE_METATYPE(WaitFor*); + +/////////////////////////////////// Helpers //////////////////////////////////// + +void WaitForPropertyTest::assertWaitForProperty(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(WaitForPropertyTest) + +#include "WaitForPropertyTest.moc" Property changes on: trunk/ktutorial/ktutorial-editor/tests/unit/data/WaitForPropertyTest.cpp ___________________________________________________________________ Added: svn:eol-style + native Modified: trunk/ktutorial/ktutorial-editor/tests/unit/serialization/JavascriptExporterTest.cpp =================================================================== --- trunk/ktutorial/ktutorial-editor/tests/unit/serialization/JavascriptExporterTest.cpp 2011-05-16 16:39:27 UTC (rev 305) +++ trunk/ktutorial/ktutorial-editor/tests/unit/serialization/JavascriptExporterTest.cpp 2011-05-16 16:46:51 UTC (rev 306) @@ -1,5 +1,5 @@ /*************************************************************************** - * Copyright (C) 2010 by Daniel Calviño Sánchez * + * Copyright (C) 2010-2011 by Daniel Calviño Sánchez * * dan...@gm... * * * * This program is free software; you can redistribute it and/or modify * @@ -26,6 +26,7 @@ #include "../data/WaitForComposed.h" #include "../data/WaitForEvent.h" #include "../data/WaitForNot.h" +#include "../data/WaitForProperty.h" #include "../data/WaitForSignal.h" #include "../data/WaitForWindow.h" @@ -89,6 +90,9 @@ void testWaitForEvent(); void testWaitForEventWithEscapeSequences(); void testWaitForEventWithoutReceiverNameOrEventName(); + void testWaitForProperty(); + void testWaitForPropertyWithEscapeSequences(); + void testWaitForPropertyWithoutObjectNameOrPropertyNameOrValue(); void testWaitForSignal(); void testWaitForSignalWithEscapeSequences(); void testWaitForSignalWithoutEmitterNameOrSignalName(); @@ -1148,6 +1152,144 @@ QCOMPARE(exportedTutorial, expected); } +void JavascriptExporterTest::testWaitForProperty() { + Tutorial tutorial; + Step* step = new Step(); + step->setId("The id"); + tutorial.addStep(step); + + WaitForProperty* waitForProperty = new WaitForProperty(); + waitForProperty->setObjectName("The object name"); + waitForProperty->setPropertyName("thePropertyName"); + waitForProperty->setValue("TheValue"); + + Reaction* reaction = new Reaction(); + reaction->setTriggerType(Reaction::ConditionMet); + reaction->setWaitFor(waitForProperty); + 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" +" waitForThePropertyNameInTheObjectName = \ +ktutorial.newWaitFor(\"WaitForProperty\");\n" +" waitForThePropertyNameInTheObjectName.setProperty(\ +ktutorial.findObject(\"The object name\"), \"thePropertyName\", TheValue);\n" +" step.addWaitFor(waitForThePropertyNameInTheObjectName, \ +\"Another step\");\n" +"}\n" +CONNECT_STEP_SETUP +STEP_WITH_ID_THE_ID_AND_EMPTY_TEXT_END_CODE; + + QCOMPARE(exportedTutorial, expected); +} + +void JavascriptExporterTest::testWaitForPropertyWithEscapeSequences() { + Tutorial tutorial; + Step* step = new Step(); + step->setId("The id"); + tutorial.addStep(step); + + WaitForProperty* waitForProper... [truncated message content] |
From: <dan...@us...> - 2011-05-16 16:39:34
|
Revision: 305 http://ktutorial.svn.sourceforge.net/ktutorial/?rev=305&view=rev Author: danxuliu Date: 2011-05-16 16:39:27 +0000 (Mon, 16 May 2011) Log Message: ----------- Add WaitForProperty class to wait for a property to change its value to the expected one. Modified Paths: -------------- trunk/ktutorial/ktutorial-library/src/CMakeLists.txt trunk/ktutorial/ktutorial-library/src/scripting/ScriptingModule.cpp trunk/ktutorial/ktutorial-library/tests/CMakeLists.txt trunk/ktutorial/ktutorial-library/tests/scripting/ScriptingModuleTest.cpp trunk/ktutorial/ktutorial-library/tests/scripting/ScriptingTest.cpp Added Paths: ----------- trunk/ktutorial/ktutorial-library/src/WaitForProperty.cpp trunk/ktutorial/ktutorial-library/src/WaitForProperty.h trunk/ktutorial/ktutorial-library/tests/WaitForPropertyTest.cpp Modified: trunk/ktutorial/ktutorial-library/src/CMakeLists.txt =================================================================== --- trunk/ktutorial/ktutorial-library/src/CMakeLists.txt 2011-05-08 15:16:11 UTC (rev 304) +++ trunk/ktutorial/ktutorial-library/src/CMakeLists.txt 2011-05-16 16:39:27 UTC (rev 305) @@ -28,6 +28,7 @@ WaitForEvent.cpp WaitForNot.cpp WaitForOr.cpp + WaitForProperty.cpp WaitForSignal.cpp WaitForWindow.cpp ) @@ -58,6 +59,7 @@ WaitForEvent.h WaitForNot.h WaitForOr.h + WaitForProperty.h WaitForSignal.h WaitForWindow.h ) Added: trunk/ktutorial/ktutorial-library/src/WaitForProperty.cpp =================================================================== --- trunk/ktutorial/ktutorial-library/src/WaitForProperty.cpp (rev 0) +++ trunk/ktutorial/ktutorial-library/src/WaitForProperty.cpp 2011-05-16 16:39:27 UTC (rev 305) @@ -0,0 +1,94 @@ +/*************************************************************************** + * Copyright (C) 2011 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 "WaitForProperty.h" + +#include <QMetaProperty> + +#include <KDebug> + +//public: + +WaitForProperty::WaitForProperty(): WaitFor() { +} + +WaitForProperty::WaitForProperty(QObject* object, const QString& propertyName, + const QVariant& value): WaitFor() { + setProperty(object, propertyName, value); +} + +void WaitForProperty::setProperty(QObject* object, const QString& propertyName, + const QVariant& value) { + mObject = object; + mPropertyName = propertyName; + mValue = value; + + if (!mObject) { + kWarning() << "The object that contains the property" << mPropertyName + << "to wait for is null!"; + return; + } + + const QMetaObject* metaObject = mObject->metaObject(); + int propertyIndex = metaObject->indexOfProperty(mPropertyName.toUtf8()); + + if (propertyIndex == -1) { + kWarning() << "The class" << metaObject->className() << "does not" + << "contain a property named" << mPropertyName << "!"; + return; + } + + QMetaProperty metaProperty = metaObject->property(propertyIndex); + + if (!metaProperty.hasNotifySignal()) { + kWarning() << "The property" << mPropertyName << "in the class" + << metaObject->className() << "does not have a notification" + << "signal!"; + return; + } + + const char* notifySignalSignature = metaProperty.notifySignal().signature(); + QString notifySignal = QString("2%1").arg(notifySignalSignature); + + connect(object, notifySignal.toUtf8(), + this, SLOT(checkPropertyValueToEndTheWait())); +} + +bool WaitForProperty::conditionMet() const { + if (!mObject) { + return false; + } + + if (mObject->property(mPropertyName.toUtf8()) != mValue) { + return false; + } + + return true; +} + +//private slots: + +void WaitForProperty::checkPropertyValueToEndTheWait() { + if (!isActive()) { + return; + } + + if (conditionMet()) { + emit waitEnded(this); + } +} Property changes on: trunk/ktutorial/ktutorial-library/src/WaitForProperty.cpp ___________________________________________________________________ Added: svn:eol-style + native Added: trunk/ktutorial/ktutorial-library/src/WaitForProperty.h =================================================================== --- trunk/ktutorial/ktutorial-library/src/WaitForProperty.h (rev 0) +++ trunk/ktutorial/ktutorial-library/src/WaitForProperty.h 2011-05-16 16:39:27 UTC (rev 305) @@ -0,0 +1,145 @@ +/*************************************************************************** + * Copyright (C) 2011 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 WAITFORPROPERTY_H +#define WAITFORPROPERTY_H + +#include <QVariant> + +#include "ktutorial_export.h" + +#include "WaitFor.h" + +/** + * Waits for a property to have a specific value. + * When the property changes its value to the specified one and the + * WaitForProperty is active, the wait ends. + * + * Note that the condition can be met even if the wait did not end. The + * condition is met if the property has the expected value. However, the wait + * ends only when the property changes to the expected value while the WaitFor + * is active. That is, in an active WaitFor, the condition would be met even if + * the expected value was set in the property when the WaitFor was inactive, but + * the wait would not end until the expected value was set again in the property + * after the WaitFor was activated. + * + * Not every property can be used to wait for its value to change. Only + * properties that have a notify signal can be used with that purpose. + * + * WaitForProperty with properties that do not have a notify signal can still be + * used to enrich other WaitFors (for example, a WaitForAnd containing a + * WaitForSignal and a WaitForProperty: waiting for a signal to be emitted but + * only changing to the next step if, in addition, some property has some + * value), but they can not be used alone as single WaitFors (for example, + * waiting just for the property "visible" of some widget to have some value + * would never end). + * + * Using a WaitForProperty just to perform further checks when other WaitFor + * ends its waiting should be done only with properties that do not have a + * notify signal. For example, if a WaitForAnd contains a WaitForSignal and a + * WaitForProperty, and the WaitForProperty uses a property with a notify + * signal, it may happen that the property changes to the expected value after + * the signal was emitted. If that happens, the WaitForProperty would end its + * waiting, and so the WaitForAnd as the WaitForSignal had already ended its + * waiting too. It may not be the desired behavior if the WaitForProperty was + * there to be checked only when the WaitForSignal ended. In that case, instead + * of using a WaitForProperty, the proper way to do it is executing a custom + * slot when the WaitForSignal ends its waiting, and checking the value of the + * property in a "if" construction in that slot. + */ +class KTUTORIAL_EXPORT WaitForProperty: public WaitFor { +Q_OBJECT +public: + + /** + * Creates a new WaitForProperty. + * This constructor is needed to dynamically create WaitForProperty objects + * in scripts using ScriptingModule::newWaitFor(const QString&). Method + * setProperty(QObject*, const QString&, const QVariant&) must be called to + * finish setting up the object. For C++ tutorials, use + * WaitForProperty(QObject*, const QString&, const QVariant&) constructor + * instead of this one. + */ + Q_INVOKABLE WaitForProperty(); + + /** + * Creates a new WaitForProperty. + * + * @param object The object that contains the property. + * @param propertyName The name of the property. + * @param value The value of the property to wait for. + */ + WaitForProperty(QObject* object, const QString& propertyName, + const QVariant& value); + + /** + * Sets the property to wait for. + * This method can be invoked from a script. + * + * In fact, you should only invoke this method from a script, and only once, + * to set up the object. For C++ tutorials, use + * WaitForProperty(QObject*, const QString&, const QVariant&) constructor + * when creating this WaitForProperty. + * + * @param object The object that contains the property. + * @param propertyName The name of the property. + * @param value The value of the property to wait for. + */ + Q_INVOKABLE void setProperty(QObject* sender, const QString& propertyName, + const QVariant& value); + + /** + * Returns true if the property has the expected value, false otherwise. + * Note that it will return true even if the property got the expected value + * when this WaitForProperty was inactive. That is, as long as the property + * has the expected value, it will return true, no matter when that value + * was set. + * + * @return True if the property has the expected value, false otherwise. + */ + virtual bool conditionMet() const; + +private: + + /** + * The object that contains the property. + */ + QObject* mObject; + + /** + * The name of the property. + */ + QString mPropertyName; + + /** + * The value of the property to wait for. + */ + QVariant mValue; + +private slots: + + /** + * When the property value changes to the expected one, this method notifies + * that the wait for the property ended. + * The wait is only ended if this WaitForProperty is active. + */ + void checkPropertyValueToEndTheWait(); + +}; + +#endif Property changes on: trunk/ktutorial/ktutorial-library/src/WaitForProperty.h ___________________________________________________________________ Added: svn:eol-style + native Modified: trunk/ktutorial/ktutorial-library/src/scripting/ScriptingModule.cpp =================================================================== --- trunk/ktutorial/ktutorial-library/src/scripting/ScriptingModule.cpp 2011-05-08 15:16:11 UTC (rev 304) +++ trunk/ktutorial/ktutorial-library/src/scripting/ScriptingModule.cpp 2011-05-16 16:39:27 UTC (rev 305) @@ -1,5 +1,5 @@ /*************************************************************************** - * Copyright (C) 2009-2010 by Daniel Calviño Sánchez * + * Copyright (C) 2009-2011 by Daniel Calviño Sánchez * * dan...@gm... * * * * This program is free software; you can redistribute it and/or modify * @@ -27,6 +27,7 @@ #include "../WaitForEvent.h" #include "../WaitForNot.h" #include "../WaitForOr.h" +#include "../WaitForProperty.h" #include "../WaitForSignal.h" #include "../WaitForWindow.h" @@ -39,6 +40,7 @@ sSelf->registerWaitForMetaObject(WaitForEvent::staticMetaObject); sSelf->registerWaitForMetaObject(WaitForNot::staticMetaObject); sSelf->registerWaitForMetaObject(WaitForOr::staticMetaObject); + sSelf->registerWaitForMetaObject(WaitForProperty::staticMetaObject); sSelf->registerWaitForMetaObject(WaitForSignal::staticMetaObject); sSelf->registerWaitForMetaObject(WaitForWindow::staticMetaObject); } Modified: trunk/ktutorial/ktutorial-library/tests/CMakeLists.txt =================================================================== --- trunk/ktutorial/ktutorial-library/tests/CMakeLists.txt 2011-05-08 15:16:11 UTC (rev 304) +++ trunk/ktutorial/ktutorial-library/tests/CMakeLists.txt 2011-05-16 16:39:27 UTC (rev 305) @@ -38,6 +38,7 @@ WaitForEvent WaitForNot WaitForOr + WaitForProperty WaitForSignal WaitForWindow ) @@ -61,6 +62,7 @@ WaitForEvent WaitForNot WaitForOr + WaitForProperty WaitForSignal WaitForWindow ) Added: trunk/ktutorial/ktutorial-library/tests/WaitForPropertyTest.cpp =================================================================== --- trunk/ktutorial/ktutorial-library/tests/WaitForPropertyTest.cpp (rev 0) +++ trunk/ktutorial/ktutorial-library/tests/WaitForPropertyTest.cpp 2011-05-16 16:39:27 UTC (rev 305) @@ -0,0 +1,273 @@ +/*************************************************************************** + * Copyright (C) 2011 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> + +#define protected public +#define private public +#include "WaitForProperty.h" +#undef private +#undef protected + +class WaitForPropertyTest: public QObject { +Q_OBJECT +Q_PROPERTY(QString stringProperty READ stringProperty + NOTIFY stringPropertyChanged) +Q_PROPERTY(int intProperty READ intProperty) + +public: + + QString stringProperty() const { + return mStringProperty; + } + + int intProperty() const { + return mIntProperty; + } + +signals: + + void stringPropertyChanged(); + +protected: + + void connectNotify(const char* signal) { + if (QLatin1String(signal) == SIGNAL(stringPropertyChanged())) { + mStringPropertyChangedConnectionCount++; + } + } + +private: + + QString mStringProperty; + int mStringPropertyChangedConnectionCount; + + int mIntProperty; + +private slots: + + void init() { + mStringProperty = ""; + mStringPropertyChangedConnectionCount = 0; + + mIntProperty = 0; + } + + void testConstructor(); + void testConstructorWithPropertyWithoutNotifySignal(); + void testConstructorWithNullObject(); + void testConstructorWithUnknownPropertyName(); + void testConstructorDefault(); + void testConstructorDefaultWithPropertyWithoutNotifySignal(); + void testConstructorDefaultWithNullObject(); + void testConstructorDefaultWithUnknownPropertyName(); + + void testConditionMet(); + void testConditionMetWhenStepWasNotActive(); + void testConditionMetWithPropertyWithoutNotifySignal(); + void testConditionMetWithValueTypeDifferentFromPropertyType(); + + void testPropertyChangeToExpectedValue(); + void testPropertyChangeToExpectedValueWhenNotActive(); + +}; + +void WaitForPropertyTest::testConstructor() { + WaitForProperty waitForProperty(this, "stringProperty", "Expected value"); + + QVERIFY(!waitForProperty.isActive()); + QVERIFY(!waitForProperty.conditionMet()); + QCOMPARE(mStringPropertyChangedConnectionCount, 1); +} + +void WaitForPropertyTest::testConstructorWithPropertyWithoutNotifySignal() { + WaitForProperty waitForProperty(this, "intProperty", 42); + + QVERIFY(!waitForProperty.isActive()); + QVERIFY(!waitForProperty.conditionMet()); +} + +void WaitForPropertyTest::testConstructorWithNullObject() { + WaitForProperty waitForProperty(0, "stringProperty", "Expected value"); + + QVERIFY(!waitForProperty.isActive()); + QVERIFY(!waitForProperty.conditionMet()); +} + +void WaitForPropertyTest::testConstructorWithUnknownPropertyName() { + WaitForProperty waitForProperty(this, "unknownProperty", "Expected value"); + + QVERIFY(!waitForProperty.isActive()); + QVERIFY(!waitForProperty.conditionMet()); +} + +void WaitForPropertyTest::testConstructorDefault() { + WaitForProperty waitForProperty; + waitForProperty.setProperty(this, "stringProperty", "Expected value"); + + QVERIFY(!waitForProperty.isActive()); + QVERIFY(!waitForProperty.conditionMet()); + QCOMPARE(mStringPropertyChangedConnectionCount, 1); +} + +void WaitForPropertyTest:: + testConstructorDefaultWithPropertyWithoutNotifySignal() { + WaitForProperty waitForProperty; + waitForProperty.setProperty(this, "intProperty", 42); + + QVERIFY(!waitForProperty.isActive()); + QVERIFY(!waitForProperty.conditionMet()); +} + +void WaitForPropertyTest::testConstructorDefaultWithNullObject() { + WaitForProperty waitForProperty; + waitForProperty.setProperty(0, "stringProperty", "Expected value"); + + QVERIFY(!waitForProperty.isActive()); + QVERIFY(!waitForProperty.conditionMet()); +} + +void WaitForPropertyTest::testConstructorDefaultWithUnknownPropertyName() { + WaitForProperty waitForProperty; + waitForProperty.setProperty(this, "unknownProperty", "Expected value"); + + QVERIFY(!waitForProperty.isActive()); + QVERIFY(!waitForProperty.conditionMet()); +} + +void WaitForPropertyTest::testConditionMet() { + WaitForProperty waitForProperty(this, "stringProperty", "Expected value"); + + waitForProperty.setActive(true); + + QVERIFY(!waitForProperty.conditionMet()); + + mStringProperty = "Another value"; + emit stringPropertyChanged(); + + QVERIFY(!waitForProperty.conditionMet()); + + mStringProperty = "Expected value"; + emit stringPropertyChanged(); + + QVERIFY(waitForProperty.conditionMet()); +} + +void WaitForPropertyTest::testConditionMetWhenStepWasNotActive() { + WaitForProperty waitForProperty(this, "stringProperty", "Expected value"); + + mStringProperty = "Another value"; + emit stringPropertyChanged(); + + waitForProperty.setActive(true); + + QVERIFY(!waitForProperty.conditionMet()); + + waitForProperty.setActive(false); + + mStringProperty = "Expected value"; + emit stringPropertyChanged(); + + waitForProperty.setActive(true); + + QVERIFY(waitForProperty.conditionMet()); +} + +void WaitForPropertyTest::testConditionMetWithPropertyWithoutNotifySignal() { + WaitForProperty waitForProperty(this, "intProperty", 42); + + waitForProperty.setActive(true); + + QVERIFY(!waitForProperty.conditionMet()); + + mIntProperty = 4; + + QVERIFY(!waitForProperty.conditionMet()); + + mIntProperty = 42; + + QVERIFY(waitForProperty.conditionMet()); +} + +void WaitForPropertyTest:: + testConditionMetWithValueTypeDifferentFromPropertyType() { + WaitForProperty waitForProperty(this, "intProperty", "42"); + + waitForProperty.setActive(true); + + QVERIFY(!waitForProperty.conditionMet()); + + mIntProperty = 4; + + QVERIFY(!waitForProperty.conditionMet()); + + mIntProperty = 42; + + QVERIFY(waitForProperty.conditionMet()); +} + +//WaitFor* must be declared as a metatype to be used in qvariant_cast +Q_DECLARE_METATYPE(WaitFor*); + +void WaitForPropertyTest::testPropertyChangeToExpectedValue() { + WaitForProperty waitForProperty(this, "stringProperty", "Expected value"); + waitForProperty.setActive(true); + + //WaitFor* must be registered in order to be used with QSignalSpy + int waitForStarType = qRegisterMetaType<WaitFor*>("WaitFor*"); + QSignalSpy waitEndedSpy(&waitForProperty, SIGNAL(waitEnded(WaitFor*))); + + mStringProperty = "Another value"; + emit stringPropertyChanged(); + + QVERIFY(!waitForProperty.conditionMet()); + QCOMPARE(waitEndedSpy.count(), 0); + + mStringProperty = "Expected value"; + emit stringPropertyChanged(); + + QVERIFY(waitForProperty.conditionMet()); + QCOMPARE(waitEndedSpy.count(), 1); + QVariant argument = waitEndedSpy.at(0).at(0); + QCOMPARE(argument.userType(), waitForStarType); + QCOMPARE(qvariant_cast<WaitFor*>(argument), &waitForProperty); +} + +void WaitForPropertyTest::testPropertyChangeToExpectedValueWhenNotActive() { + WaitForProperty waitForProperty(this, "stringProperty", "Expected value"); + waitForProperty.setActive(false); + + qRegisterMetaType<WaitFor*>("WaitFor*"); + QSignalSpy waitEndedSpy(&waitForProperty, SIGNAL(waitEnded(WaitFor*))); + + mStringProperty = "Another value"; + emit stringPropertyChanged(); + + QVERIFY(!waitForProperty.conditionMet()); + QCOMPARE(waitEndedSpy.count(), 0); + + mStringProperty = "Expected value"; + emit stringPropertyChanged(); + + QVERIFY(waitForProperty.conditionMet()); + QCOMPARE(waitEndedSpy.count(), 0); +} + +QTEST_MAIN(WaitForPropertyTest) + +#include "WaitForPropertyTest.moc" Property changes on: trunk/ktutorial/ktutorial-library/tests/WaitForPropertyTest.cpp ___________________________________________________________________ Added: svn:eol-style + native Modified: trunk/ktutorial/ktutorial-library/tests/scripting/ScriptingModuleTest.cpp =================================================================== --- trunk/ktutorial/ktutorial-library/tests/scripting/ScriptingModuleTest.cpp 2011-05-08 15:16:11 UTC (rev 304) +++ trunk/ktutorial/ktutorial-library/tests/scripting/ScriptingModuleTest.cpp 2011-05-16 16:39:27 UTC (rev 305) @@ -1,5 +1,5 @@ /*************************************************************************** - * Copyright (C) 2009-2010 by Daniel Calviño Sánchez * + * Copyright (C) 2009-2011 by Daniel Calviño Sánchez * * dan...@gm... * * * * This program is free software; you can redistribute it and/or modify * @@ -33,6 +33,7 @@ #include "../WaitForEvent.h" #include "../WaitForNot.h" #include "../WaitForOr.h" +#include "../WaitForProperty.h" #include "../WaitForSignal.h" #include "../WaitForWindow.h" @@ -169,6 +170,10 @@ type = metaObject(scriptingModule, "WaitForOr"); QCOMPARE(type.className(), WaitForOr::staticMetaObject.className()); + QVERIFY(containsMetaObject(scriptingModule, "WaitForProperty")); + type = metaObject(scriptingModule, "WaitForProperty"); + QCOMPARE(type.className(), WaitForProperty::staticMetaObject.className()); + QVERIFY(containsMetaObject(scriptingModule, "WaitForSignal")); type = metaObject(scriptingModule, "WaitForSignal"); QCOMPARE(type.className(), WaitForSignal::staticMetaObject.className()); Modified: trunk/ktutorial/ktutorial-library/tests/scripting/ScriptingTest.cpp =================================================================== --- trunk/ktutorial/ktutorial-library/tests/scripting/ScriptingTest.cpp 2011-05-08 15:16:11 UTC (rev 304) +++ trunk/ktutorial/ktutorial-library/tests/scripting/ScriptingTest.cpp 2011-05-16 16:39:27 UTC (rev 305) @@ -1,5 +1,5 @@ /*************************************************************************** - * Copyright (C) 2009-2010 by Daniel Calviño Sánchez * + * Copyright (C) 2009-2011 by Daniel Calviño Sánchez * * dan...@gm... * * * * This program is free software; you can redistribute it and/or modify * @@ -42,6 +42,13 @@ //tutorials work as expected class ScriptingTest: public QObject { Q_OBJECT +Q_PROPERTY(int intProperty READ intProperty NOTIFY intPropertyChanged) +public: + + int intProperty() const { + return mIntProperty; + } + public slots: bool booleanValue() { @@ -62,6 +69,8 @@ void otherDummySignal(); void anotherDummySignal(); + void intPropertyChanged(); + private slots: void initTestCase(); @@ -83,6 +92,8 @@ bool mBooleanValue; + int mIntProperty; + int mDummySlotCallCount; KTemporaryFile* mTemporaryFile; @@ -98,6 +109,7 @@ void ScriptingTest::init() { mBooleanValue = false; + mIntProperty = 0; mDummySlotCallCount = 0; mTemporaryFile = new KTemporaryFile(); @@ -314,6 +326,8 @@ out << "tutorial.addStep(secondStep);\n"; out << "thirdStep = ktutorial.newStep(\"third\");\n"; out << "tutorial.addStep(thirdStep);\n"; + out << "fourthStep = ktutorial.newStep(\"fourth\");\n"; + out << "tutorial.addStep(fourthStep);\n"; out << "endStep = ktutorial.newStep(\"end\");\n"; out << "endStep.setText(\"The tutorial has ended.\");\n"; out << "tutorial.addStep(endStep);\n"; @@ -351,8 +365,14 @@ out << "waitForChildAddedEvent = ktutorial.newWaitFor(\"WaitForEvent\");\n"; out << "waitForChildAddedEvent.setEvent(testObject, \"ChildAdded\");\n"; - out << "thirdStep.addWaitFor(waitForChildAddedEvent, \"end\");\n"; + out << "thirdStep.addWaitFor(waitForChildAddedEvent, \"fourth\");\n"; + out << "waitForIntProperty = ktutorial.newWaitFor(\"WaitForProperty\");\n"; + out << "waitForIntProperty.setProperty(testObject, \"intProperty\", \ +\"42\");\n"; + + out << "fourthStep.addWaitFor(waitForIntProperty, \"end\");\n"; + out.flush(); ScriptedTutorial scriptedTutorial(mTemporaryFile->fileName()); @@ -397,6 +417,11 @@ QObject* childObject = new QObject(); childObject->setParent(this); + QCOMPARE(scriptedTutorial.mCurrentStep->id(), QString("fourth")); + + mIntProperty = 42; + emit intPropertyChanged(); + QCOMPARE(scriptedTutorial.mCurrentStep->id(), QString("end")); QCOMPARE(scriptedTutorial.mCurrentStep->text(), QString("The tutorial has ended.")); This was sent by the SourceForge.net collaborative development platform, the world's largest Open Source development site. |
From: <dan...@us...> - 2011-05-08 15:16:18
|
Revision: 304 http://ktutorial.svn.sourceforge.net/ktutorial/?rev=304&view=rev Author: danxuliu Date: 2011-05-08 15:16:11 +0000 (Sun, 08 May 2011) Log Message: ----------- Modify the internal behavior of Tutorial when changing to the next step. Until now, when nextStep(Step*) was called it just changed to the next step, which could cause recursive changes and wrong results when called from the setup method of a Step. Now, the steps to change to are queued and the changes are done one after the other. Modified Paths: -------------- trunk/ktutorial/ktutorial-library/src/Tutorial.cpp trunk/ktutorial/ktutorial-library/src/Tutorial.h trunk/ktutorial/ktutorial-library/tests/TutorialTest.cpp Modified: trunk/ktutorial/ktutorial-library/src/Tutorial.cpp =================================================================== --- trunk/ktutorial/ktutorial-library/src/Tutorial.cpp 2011-05-06 12:49:50 UTC (rev 303) +++ trunk/ktutorial/ktutorial-library/src/Tutorial.cpp 2011-05-08 15:16:11 UTC (rev 304) @@ -1,5 +1,5 @@ /*************************************************************************** - * Copyright (C) 2008-2010 by Daniel Calviño Sánchez * + * Copyright (C) 2008-2011 by Daniel Calviño Sánchez * * dan...@gm... * * * * This program is free software; you can redistribute it and/or modify * @@ -65,6 +65,38 @@ } void Tutorial::nextStep(Step* step) { + mQueuedSteps.append(step); + + if (mQueuedSteps.count() > 1) { + //Nested call to nextStep(Step*) (that is, something called by + //nextStep(Step*) caused the method to be called again before its + //previous execution ended). Once that previous call continues its + //execution it will change to the next queued step. + return; + } + + while (mQueuedSteps.count() > 0) { + changeToStep(mQueuedSteps[0]); + mQueuedSteps.removeFirst(); + } +} + +//public slots: + +void Tutorial::finish() { + if (mCurrentStep != 0) { + mCurrentStep->setActive(false); + mCurrentStep = 0; + } + + tearDown(); + + emit finished(this); +} + +//private: + +void Tutorial::changeToStep(Step* step) { if (mSteps.key(step).isEmpty()) { kError() << "Activate step " << step->id() << " which doesn't belong to tutorial " @@ -84,16 +116,3 @@ emit stepActivated(step); } - -//public slots: - -void Tutorial::finish() { - if (mCurrentStep != 0) { - mCurrentStep->setActive(false); - mCurrentStep = 0; - } - - tearDown(); - - emit finished(this); -} Modified: trunk/ktutorial/ktutorial-library/src/Tutorial.h =================================================================== --- trunk/ktutorial/ktutorial-library/src/Tutorial.h 2011-05-06 12:49:50 UTC (rev 303) +++ trunk/ktutorial/ktutorial-library/src/Tutorial.h 2011-05-08 15:16:11 UTC (rev 304) @@ -1,5 +1,5 @@ /*************************************************************************** - * Copyright (C) 2008-2010 by Daniel Calviño Sánchez * + * Copyright (C) 2008-2011 by Daniel Calviño Sánchez * * dan...@gm... * * * * This program is free software; you can redistribute it and/or modify * @@ -208,6 +208,20 @@ */ Step* mCurrentStep; + /** + * The steps to change to that were not activated yet. + */ + QList<Step*> mQueuedSteps; + + /** + * Activates the given step. + * When calling nextStep(Step*), the tutorial queues the steps to change to. + * The real activation of the step is done by this method. + * + * @param step The Step to activate. + */ + void changeToStep(Step* step); + }; #endif Modified: trunk/ktutorial/ktutorial-library/tests/TutorialTest.cpp =================================================================== --- trunk/ktutorial/ktutorial-library/tests/TutorialTest.cpp 2011-05-06 12:49:50 UTC (rev 303) +++ trunk/ktutorial/ktutorial-library/tests/TutorialTest.cpp 2011-05-08 15:16:11 UTC (rev 304) @@ -1,5 +1,5 @@ /*************************************************************************** - * Copyright (C) 2009-2010 by Daniel Calviño Sánchez * + * Copyright (C) 2009-2011 by Daniel Calviño Sánchez * * dan...@gm... * * * * This program is free software; you can redistribute it and/or modify * @@ -55,6 +55,8 @@ void testNextStepStep(); void testNextStepStepWithInvalidStep(); + void testNextStepFromStepSetup(); + void testFinish(); }; @@ -71,6 +73,46 @@ }; +class StepToSetNextStepInSetup: public Step { +public: + + Tutorial* mTutorial; + Step* mNextStep; + bool mDuringSetup; + + StepToSetNextStepInSetup(const QString& id): Step(id), + mTutorial(0), + mNextStep(0), + mDuringSetup(false) { + } + +protected: + + void setup() { + mDuringSetup = true; + mTutorial->nextStep(mNextStep); + mDuringSetup = false; + } + +}; + +class StepToAssertNoRecursiveStepActivation: public Step { +public: + + StepToSetNextStepInSetup* mPreviousStep; + + StepToAssertNoRecursiveStepActivation(const QString& id): Step(id), + mPreviousStep(0) { + } + +protected: + + void setup() { + QVERIFY(!mPreviousStep->mDuringSetup); + } + +}; + class MockTutorial: public Tutorial { public: @@ -408,6 +450,54 @@ QVERIFY(step1->isActive()); } +//Ensure that if some step calls Tutorial::nextStep from its setup (that is, +//when the step is being activated), the next step is not activated until the +//activation of the previous one ended (that is, steps are not activated +//recursively, but sequentially). +void TutorialTest::testNextStepFromStepSetup() { + Tutorial tutorial(new TutorialInformation("pearlOrientation")); + + Step* stepStart = new Step("start"); + tutorial.addStep(stepStart); + + StepToSetNextStepInSetup* step1 = new StepToSetNextStepInSetup("record"); + tutorial.addStep(step1); + + StepToAssertNoRecursiveStepActivation* step2 = + new StepToAssertNoRecursiveStepActivation("roll"); + tutorial.addStep(step2); + + step1->mTutorial = &tutorial; + step1->mNextStep = step2; + step2->mPreviousStep = step1; + + tutorial.addStep(new Step("send")); + + tutorial.start(); + + //Step* must be registered in order to be used with QSignalSpy + int stepStarType = qRegisterMetaType<Step*>("Step*"); + QSignalSpy stepActivatedSpy(&tutorial, SIGNAL(stepActivated(Step*))); + + //Ensure that the step is already active when the signal is emitted + connect(&tutorial, SIGNAL(stepActivated(Step*)), + this, SLOT(assertStepActive(Step*))); + + tutorial.nextStep(step1); + + QCOMPARE(stepActivatedSpy.count(), 2); + QVariant argument = stepActivatedSpy.at(0).at(0); + QCOMPARE(argument.userType(), stepStarType); + QCOMPARE(qvariant_cast<Step*>(argument), step1); + argument = stepActivatedSpy.at(1).at(0); + QCOMPARE(argument.userType(), stepStarType); + QCOMPARE(qvariant_cast<Step*>(argument), step2); + QCOMPARE(tutorial.mCurrentStep, step2); + QVERIFY(!stepStart->isActive()); + QVERIFY(!step1->isActive()); + QVERIFY(step2->isActive()); +} + void TutorialTest::testFinish() { MockTutorial tutorial(new TutorialInformation("pearlOrientation")); This was sent by the SourceForge.net collaborative development platform, the world's largest Open Source development site. |
From: <dan...@us...> - 2011-05-06 12:49:57
|
Revision: 303 http://ktutorial.svn.sourceforge.net/ktutorial/?rev=303&view=rev Author: danxuliu Date: 2011-05-06 12:49:50 +0000 (Fri, 06 May 2011) Log Message: ----------- Set the event name completion as sorted and not case sensitive. Modified Paths: -------------- trunk/ktutorial/ktutorial-editor/src/view/WaitForEventWidget.cpp trunk/ktutorial/ktutorial-editor/tests/unit/view/WaitForEventWidgetTest.cpp Modified: trunk/ktutorial/ktutorial-editor/src/view/WaitForEventWidget.cpp =================================================================== --- trunk/ktutorial/ktutorial-editor/src/view/WaitForEventWidget.cpp 2011-05-06 12:44:36 UTC (rev 302) +++ trunk/ktutorial/ktutorial-editor/src/view/WaitForEventWidget.cpp 2011-05-06 12:49:50 UTC (rev 303) @@ -58,6 +58,8 @@ ui->eventNameLineEdit->setText(waitForEvent->eventName()); + ui->eventNameLineEdit->completionObject()->setOrder(KCompletion::Sorted); + ui->eventNameLineEdit->completionObject()->setIgnoreCase(true); addItemsToEventNameCompletion(); } Modified: trunk/ktutorial/ktutorial-editor/tests/unit/view/WaitForEventWidgetTest.cpp =================================================================== --- trunk/ktutorial/ktutorial-editor/tests/unit/view/WaitForEventWidgetTest.cpp 2011-05-06 12:44:36 UTC (rev 302) +++ trunk/ktutorial/ktutorial-editor/tests/unit/view/WaitForEventWidgetTest.cpp 2011-05-06 12:49:50 UTC (rev 303) @@ -77,8 +77,9 @@ WaitForEventWidget widget(&waitFor); KCompletion* completion = eventNameLineEdit(&widget)->completionObject(); - QCOMPARE(completion->allMatches("Dest").count(), 1); - QCOMPARE(completion->allMatches("Dest")[0], QString("Destroy")); + QCOMPARE(completion->order(), KCompletion::Sorted); + QCOMPARE(completion->allMatches("dest").count(), 1); + QCOMPARE(completion->allMatches("dest")[0], QString("Destroy")); } /////////////////////////////////// Helpers //////////////////////////////////// This was sent by the SourceForge.net collaborative development platform, the world's largest Open Source development site. |
From: <dan...@us...> - 2011-05-06 12:44:42
|
Revision: 302 http://ktutorial.svn.sourceforge.net/ktutorial/?rev=302&view=rev Author: danxuliu Date: 2011-05-06 12:44:36 +0000 (Fri, 06 May 2011) Log Message: ----------- Fix not providing information of a class if it is the class of a widget that was registered while it was being constructed. By the way, I forgot to say it in the commit 300, and now it doesn't really do much sense, but I can't resist... "THIS... IS... KTUTORIAL!!!" :P Modified Paths: -------------- trunk/ktutorial/ktutorial-library/src/editorsupport/ObjectRegister.cpp trunk/ktutorial/ktutorial-library/src/editorsupport/ObjectRegister.h trunk/ktutorial/ktutorial-library/src/editorsupport/ObjectRegisterAdaptor.cpp trunk/ktutorial/ktutorial-library/tests/editorsupport/EditorSupportTest.cpp Modified: trunk/ktutorial/ktutorial-library/src/editorsupport/ObjectRegister.cpp =================================================================== --- trunk/ktutorial/ktutorial-library/src/editorsupport/ObjectRegister.cpp 2011-05-05 14:39:15 UTC (rev 301) +++ trunk/ktutorial/ktutorial-library/src/editorsupport/ObjectRegister.cpp 2011-05-06 12:44:36 UTC (rev 302) @@ -1,5 +1,5 @@ /*************************************************************************** - * Copyright (C) 2010 by Daniel Calviño Sánchez * + * Copyright (C) 2010-2011 by Daniel Calviño Sánchez * * dan...@gm... * * * * This program is free software; you can redistribute it and/or modify * @@ -58,8 +58,6 @@ mRegisteredMetaObjects.clear(); } -//private: - void ObjectRegister::registerMetaObject(const QMetaObject* metaObject) { if (mRegisteredMetaObjects.contains(metaObject->className())) { return; Modified: trunk/ktutorial/ktutorial-library/src/editorsupport/ObjectRegister.h =================================================================== --- trunk/ktutorial/ktutorial-library/src/editorsupport/ObjectRegister.h 2011-05-05 14:39:15 UTC (rev 301) +++ trunk/ktutorial/ktutorial-library/src/editorsupport/ObjectRegister.h 2011-05-06 12:44:36 UTC (rev 302) @@ -1,5 +1,5 @@ /*************************************************************************** - * Copyright (C) 2010 by Daniel Calviño Sánchez * + * Copyright (C) 2010-2011 by Daniel Calviño Sánchez * * dan...@gm... * * * * This program is free software; you can redistribute it and/or modify * @@ -78,6 +78,13 @@ */ void clear(); + /** + * Registers a meta object and the meta objects of all its super classes. + * + * @param metaObject The meta object to register. + */ + void registerMetaObject(const QMetaObject* metaObject); + private: /** @@ -100,13 +107,6 @@ */ QHash<QString, const QMetaObject*> mRegisteredMetaObjects; - /** - * Registers a meta object and the meta objects of all its super classes. - * - * @param metaObject The meta object to register. - */ - void registerMetaObject(const QMetaObject* metaObject); - private Q_SLOTS: /** Modified: trunk/ktutorial/ktutorial-library/src/editorsupport/ObjectRegisterAdaptor.cpp =================================================================== --- trunk/ktutorial/ktutorial-library/src/editorsupport/ObjectRegisterAdaptor.cpp 2011-05-05 14:39:15 UTC (rev 301) +++ trunk/ktutorial/ktutorial-library/src/editorsupport/ObjectRegisterAdaptor.cpp 2011-05-06 12:44:36 UTC (rev 302) @@ -1,5 +1,5 @@ /*************************************************************************** - * Copyright (C) 2010 by Daniel Calviño Sánchez * + * Copyright (C) 2010-2011 by Daniel Calviño Sánchez * * dan...@gm... * * * * This program is free software; you can redistribute it and/or modify * @@ -45,6 +45,16 @@ return ""; } + //Ensure that the meta object is registered. If a widget is registered while + //it is being constructed (if the event spy is enabled, it will register the + //object when it sets its parent, as it sends a ParentChanged event) its + //real class will not be registered, only QWidget, as at that moment the + //object will not be fully constructed and the pointer to the meta object + //will not be set to the real class yet. + //This does not seem to happen with plain objects; only widgets send that + //ParentChanged event in their constructor. + mObjectRegister->registerMetaObject(object->metaObject()); + return object->metaObject()->className(); } Modified: trunk/ktutorial/ktutorial-library/tests/editorsupport/EditorSupportTest.cpp =================================================================== --- trunk/ktutorial/ktutorial-library/tests/editorsupport/EditorSupportTest.cpp 2011-05-05 14:39:15 UTC (rev 301) +++ trunk/ktutorial/ktutorial-library/tests/editorsupport/EditorSupportTest.cpp 2011-05-06 12:44:36 UTC (rev 302) @@ -1,5 +1,5 @@ /*************************************************************************** - * Copyright (C) 2010 by Daniel Calviño Sánchez * + * Copyright (C) 2010-2011 by Daniel Calviño Sánchez * * dan...@gm... * * * * This program is free software; you can redistribute it and/or modify * @@ -42,6 +42,20 @@ //Tutorial* must be declared as a metatype to be used in qvariant_cast Q_DECLARE_METATYPE(Tutorial*); +class SubClassWidget: public QWidget { +Q_OBJECT +public: + SubClassWidget(QWidget* parent = 0): QWidget(parent) { + } +}; + +class SubSubClassWidget: public SubClassWidget { +Q_OBJECT +public: + SubSubClassWidget(QWidget* parent = 0): SubClassWidget(parent) { + } +}; + namespace editorsupport { class EditorSupportTest: public QObject { @@ -75,6 +89,8 @@ void testTestScriptedTutorial(); void testTestScriptedTutorialWithInvalidTutorial(); + void testObjectRegisterWhenEventSpyNotifiesEventBeforeEndingConstructor(); + private: QStringList mEventTypes; @@ -293,8 +309,52 @@ QCOMPARE(startedSpy.count(), 0); } +//Not really a unit test, but sort of an integration test for a strange bug. +void EditorSupportTest:: + testObjectRegisterWhenEventSpyNotifiesEventBeforeEndingConstructor() { + QDBusConnection bus = QDBusConnection::sessionBus(); + QVERIFY(bus.isConnected()); + + EditorSupport editorSupport; + QWidget mainWidget; + + editorSupport.setup(&mainWidget); + editorSupport.enableEventSpy(); + + SubSubClassWidget* childWidget = new SubSubClassWidget(&mainWidget); + + QCOMPARE(childWidget->metaObject()->className(), + "SubSubClassWidget"); + QCOMPARE(childWidget->metaObject()->superClass()->className(), + "SubClassWidget"); + QCOMPARE(childWidget->metaObject()->superClass()->superClass()->className(), + "QWidget"); + + //childWidget gets registered by a ParentChange event. However, that event + //is sent by QWidget constructor itself. The object is not fully + //constructed, so SubClassWidget and SubSubClassWidget are not registered. + ObjectRegister* objectRegister = editorSupport.mObjectRegister; + QCOMPARE(objectRegister->objectForId(1), &mainWidget); + QCOMPARE(objectRegister->objectForId(2), childWidget); + QVERIFY(objectRegister->metaObjectForClassName("QWidget")); + QVERIFY(!objectRegister->metaObjectForClassName("SubClassWidget")); + QVERIFY(!objectRegister->metaObjectForClassName("SubSubClassWidget")); + + //From the outside (the caller DBus client), the only way to get an object + //class is asking the ObjectRegister adaptor about it. So if a class is + //registered after its name was returned by the ObjectRegister adaptor, when + //the client asks for information about that class the register will be able + //to provide it. + ObjectRegisterAdaptor* objectRegisterAdaptor = + objectRegister->findChild<ObjectRegisterAdaptor*>(); + + QCOMPARE(objectRegisterAdaptor->className(2), QString("SubSubClassWidget")); + QVERIFY(objectRegister->metaObjectForClassName("SubClassWidget")); + QVERIFY(objectRegister->metaObjectForClassName("SubSubClassWidget")); } +} + QTEST_MAIN(editorsupport::EditorSupportTest) #include "EditorSupportTest.moc" This was sent by the SourceForge.net collaborative development platform, the world's largest Open Source development site. |
From: <dan...@us...> - 2011-05-05 14:39:24
|
Revision: 301 http://ktutorial.svn.sourceforge.net/ktutorial/?rev=301&view=rev Author: danxuliu Date: 2011-05-05 14:39:15 +0000 (Thu, 05 May 2011) Log Message: ----------- Add a basic helper to edit KUIT semantic markup in the text of a step. Modified Paths: -------------- trunk/ktutorial/ktutorial-editor/src/view/CMakeLists.txt trunk/ktutorial/ktutorial-editor/src/view/StepDataWidget.cpp trunk/ktutorial/ktutorial-editor/tests/unit/view/CMakeLists.txt Added Paths: ----------- trunk/ktutorial/ktutorial-editor/src/view/SemanticMarkupEdition.cpp trunk/ktutorial/ktutorial-editor/src/view/SemanticMarkupEdition.h trunk/ktutorial/ktutorial-editor/src/view/SemanticMarkupLinkWidget.cpp trunk/ktutorial/ktutorial-editor/src/view/SemanticMarkupLinkWidget.h trunk/ktutorial/ktutorial-editor/src/view/SemanticMarkupLinkWidget.ui trunk/ktutorial/ktutorial-editor/src/view/SemanticMarkupParser.cpp trunk/ktutorial/ktutorial-editor/src/view/SemanticMarkupParser.h trunk/ktutorial/ktutorial-editor/tests/unit/view/SemanticMarkupEditionTest.cpp trunk/ktutorial/ktutorial-editor/tests/unit/view/SemanticMarkupLinkWidgetTest.cpp trunk/ktutorial/ktutorial-editor/tests/unit/view/SemanticMarkupParserTest.cpp Modified: trunk/ktutorial/ktutorial-editor/src/view/CMakeLists.txt =================================================================== --- trunk/ktutorial/ktutorial-editor/src/view/CMakeLists.txt 2011-04-30 17:31:13 UTC (rev 300) +++ trunk/ktutorial/ktutorial-editor/src/view/CMakeLists.txt 2011-05-05 14:39:15 UTC (rev 301) @@ -9,6 +9,9 @@ NewWaitForWidget.cpp ReactionTreeItem.cpp ReactionWidget.cpp + SemanticMarkupEdition.cpp + SemanticMarkupLinkWidget.cpp + SemanticMarkupParser.cpp StepCustomCodeWidget.cpp StepDataWidget.cpp StepTreeItem.cpp @@ -53,6 +56,7 @@ NewWaitForWidget.ui ReactionWidget.ui RemoteObjectNameWidget.ui + SemanticMarkupLinkWidget.ui StepDataWidget.ui TutorialInformationWidget.ui WaitForEventWidget.ui Added: trunk/ktutorial/ktutorial-editor/src/view/SemanticMarkupEdition.cpp =================================================================== --- trunk/ktutorial/ktutorial-editor/src/view/SemanticMarkupEdition.cpp (rev 0) +++ trunk/ktutorial/ktutorial-editor/src/view/SemanticMarkupEdition.cpp 2011-05-05 14:39:15 UTC (rev 301) @@ -0,0 +1,418 @@ +/*************************************************************************** + * Copyright (C) 2011 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 "SemanticMarkupEdition.h" + +#include <QRegExp> +#include <QTextEdit> + +#include <KAction> +#include <KActionCollection> +#include <KDialog> +#include <KLocalizedString> +#include <KPushButton> + +#include "DialogRunner.h" +#include "SemanticMarkupLinkWidget.h" +#include "SemanticMarkupParser.h" + +//public: + +SemanticMarkupEdition::SemanticMarkupEdition(QTextEdit* textEdit): + QObject(textEdit), + mTextEdit(textEdit) { + Q_ASSERT(textEdit); + + connect(mTextEdit, SIGNAL(cursorPositionChanged()), + this, SLOT(updateActionStates())); + //TODO Needed to update the action states when the user deletes a character; + //look how to do that without updating twice in any other text change. + connect(mTextEdit, SIGNAL(textChanged()), + this, SLOT(updateActionStates())); +} + +void SemanticMarkupEdition::createActions(KActionCollection* actionCollection) { + Q_ASSERT(actionCollection); + + mEmphasisAction = new KAction("emphasis", actionCollection); + mEmphasisAction->setCheckable(true); + mEmphasisAction->setToolTip(i18nc("@info:tooltip", "Emphasized text")); + mEmphasisAction->setWhatsThis(i18nc("@info:whatsthis", + "Phrase tag to emphasize a word or phrase in the text.<nl/>" + "Example: <emphasis>emphasized text</emphasis>")); + actionCollection->addAction("kuit-edition-phrase-emphasis", + mEmphasisAction); + connect(mEmphasisAction, SIGNAL(triggered()), this, SLOT(emphasis())); + mActions.append(mEmphasisAction); + + mEmphasisStrongAction = new KAction("emphasis (strong)", actionCollection); + mEmphasisStrongAction->setCheckable(true); + mEmphasisStrongAction->setToolTip(i18nc("@info:tooltip", + "Strongly emphasized text")); + mEmphasisStrongAction->setWhatsThis(i18nc("@info:whatsthis", + "Phrase tag to strongly emphasize a word or phrase in the text.<nl/>" + "Example: <emphasis strong=\"1\">strongly emphasized text</emphasis>")); + actionCollection->addAction("kuit-edition-phrase-emphasis-strong", + mEmphasisStrongAction); + connect(mEmphasisStrongAction, SIGNAL(triggered()), + this, SLOT(emphasisStrong())); + mActions.append(mEmphasisStrongAction); + + mFilenameAction = new KAction("filename", actionCollection); + mFilenameAction->setCheckable(true); + mFilenameAction->setToolTip(i18nc("@info:tooltip", "Filename or path")); + mFilenameAction->setWhatsThis(i18nc("@info:whatsthis", + "Phrase tag for file or folder name or path.<nl/>" + "The path separators will be transformed into what is native to the " + "platform.<nl/>" + "Example: <filename>/home/user/Music/song.ogg</filename>")); + actionCollection->addAction("kuit-edition-phrase-filename", + mFilenameAction); + connect(mFilenameAction, SIGNAL(triggered()), this, SLOT(filename())); + mActions.append(mFilenameAction); + + mInterfaceAction = new KAction("interface", actionCollection); + mInterfaceAction->setCheckable(true); + mInterfaceAction->setToolTip(i18nc("@info:tooltip", + "GUI interface element")); + mInterfaceAction->setWhatsThis(i18nc("@info:whatsthis", + "Phrase tag for paths to GUI interface elements.<nl/>" + "If there is more than one element in the path, use \"|\" to delimit " + "elements, which will be converted into canonical delimiter.<nl/>" + "Example: <interface>File|Open</interface>")); + actionCollection->addAction("kuit-edition-phrase-interface", + mInterfaceAction); + connect(mInterfaceAction, SIGNAL(triggered()), this, SLOT(interface())); + mActions.append(mInterfaceAction); + + mLinkAction = new KAction("link", actionCollection); + mLinkAction->setCheckable(true); + mLinkAction->setToolTip(i18nc("@info:tooltip", "Link to URL or widget")); + mLinkAction->setWhatsThis(i18nc("@info:whatsthis", + "Phrase tag to link to a URL-addressable resource.<nl/>" + "Widgets in the target application interface can be linked using " + "<emphasis>widget:theObjectNameOfTheWidget</emphasis><nl/>" + "Example: <link url=\"http://www.kde.org\">a link</link>")); + actionCollection->addAction("kuit-edition-phrase-link", mLinkAction); + connect(mLinkAction, SIGNAL(triggered()), this, SLOT(link())); + mActions.append(mLinkAction); + + mNlAction = new KAction("nl", actionCollection); + mNlAction->setToolTip(i18nc("@info:tooltip", "Line break")); + mNlAction->setWhatsThis(i18nc("@info:whatsthis", + "Phrase tag for line breaks.<nl/>" + "Example: line<nl/>break")); + actionCollection->addAction("kuit-edition-phrase-nl", mNlAction); + connect(mNlAction, SIGNAL(triggered()), this, SLOT(nl())); + mActions.append(mNlAction); + + mShortcutAction = new KAction("shortcut", actionCollection); + mShortcutAction->setCheckable(true); + mShortcutAction->setToolTip(i18nc("@info:tooltip", + "Combination of keys to press")); + mShortcutAction->setWhatsThis(i18nc("@info:whatsthis", + "Phrase tag for combinations of keys to press.<nl/>" + "Separate the keys by \"+\" or \"-\", and the shortcut will be " + "converted into canonical form.<nl/>" + "Example: <shortcut>Ctrl+N</shortcut>")); + actionCollection->addAction("kuit-edition-phrase-shortcut", + mShortcutAction); + connect(mShortcutAction, SIGNAL(triggered()), this, SLOT(shortcut())); + mActions.append(mShortcutAction); + + mParaAction = new KAction("para", actionCollection); + mParaAction->setCheckable(true); + mParaAction->setToolTip(i18nc("@info:tooltip", "Paragraph")); + mParaAction->setWhatsThis(i18nc("@info:whatsthis", + "<para>Structure tag for text paragraphs.<nl/>" + "Example: one paragraph</para><para>Other paragraph</para>")); + actionCollection->addAction("kuit-edition-structure-para", mParaAction); + connect(mParaAction, SIGNAL(triggered()), this, SLOT(para())); + mActions.append(mParaAction); + + mListAction = new KAction("list", actionCollection); + mListAction->setCheckable(true); + mListAction->setToolTip(i18nc("@info:tooltip", "List of items")); + mListAction->setWhatsThis(i18nc("@info:whatsthis", + "<para>Structure tag for lists of items.<nl/>" + "Can contain only <item> as subtags. List is considered an " + "element of the paragraph, so the <list> must be found inside " + "<para>.<nl/>" + "Example: <list>" + " <item>One item</item>" + " <item>Other item</item>" + " </list></para>")); + actionCollection->addAction("kuit-edition-structure-list", mListAction); + connect(mListAction, SIGNAL(triggered()), this, SLOT(list())); + mActions.append(mListAction); + + mItemAction = new KAction("item", actionCollection); + mItemAction->setCheckable(true); + mItemAction->setToolTip(i18nc("@info:tooltip", "List items")); + mItemAction->setWhatsThis(i18nc("@info:whatsthis", + "<para>Structure tag for list items.<nl/>" + "Example: <list>" + " <item>One item</item>" + " <item>Other item</item>" + " </list></para>")); + actionCollection->addAction("kuit-edition-structure-item", mItemAction); + connect(mItemAction, SIGNAL(triggered()), this, SLOT(item())); + mActions.append(mItemAction); + + updateActionStates(); +} + +//private: + +QAction* SemanticMarkupEdition::actionForElement(const StartTag& startTag) + const { + QAction* action = 0; + + QRegExp emphasisStrongRegExp("strong=\"yes|true|1\""); + if (startTag.mName == "emphasis" && + startTag.mAttributes.indexOf(emphasisStrongRegExp) < 0) { + action = mEmphasisAction; + } else if (startTag.mName == "emphasis" && + startTag.mAttributes.indexOf(emphasisStrongRegExp) >= 0) { + action = mEmphasisStrongAction; + } else if (startTag.mName == "filename") { + action = mFilenameAction; + } else if (startTag.mName == "interface") { + action = mInterfaceAction; + } else if (startTag.mName == "link") { + action = mLinkAction; + } else if (startTag.mName == "nl") { + action = mNlAction; + } else if (startTag.mName == "shortcut") { + action = mShortcutAction; + } else if (startTag.mName == "para") { + action = mParaAction; + } else if (startTag.mName == "list") { + action = mListAction; + } else if (startTag.mName == "item") { + action = mItemAction; + } + + return action; +} + +void SemanticMarkupEdition::writeSimpleTagFor(const QAction* action) { + if (action->isChecked()) { + mTextEdit->insertPlainText('<' + action->text() + '>'); + } else { + mTextEdit->insertPlainText("</" + action->text() + '>'); + } +} + +QDialog* SemanticMarkupEdition::newLinkDialog(const QString& url) const { + KDialog* dialog = new KDialog(mTextEdit); + dialog->setModal(true); + + dialog->setButtons(KDialog::Ok | KDialog::Cancel); + + dialog->button(KDialog::Ok)->setObjectName("okButton"); + dialog->button(KDialog::Cancel)->setObjectName("cancelButton"); + + SemanticMarkupLinkWidget* linkWidget = new SemanticMarkupLinkWidget(dialog); + linkWidget->setUrl(url); + dialog->setMainWidget(linkWidget); + dialog->setWindowTitle(linkWidget->windowTitle()); + + return dialog; +} + +//private slots: + +void SemanticMarkupEdition::updateActionStates() { + Q_ASSERT(!mActions.isEmpty()); + + foreach (QAction* action, mActions) { + action->setEnabled(true); + action->setChecked(false); + } + + mLinkElementClosed = false; + + SemanticMarkupParser parser; + parser.setCursorIndex(mTextEdit->textCursor().position()); + parser.parse(mTextEdit->toPlainText()); + + if (parser.isCursorInsideTag()) { + foreach (QAction* action, mActions) { + action->setEnabled(false); + } + + return; + } + + QList<StartTag> openElementsAtCursor = parser.openElementsAtCursor(); + if (openElementsAtCursor.isEmpty()) { + mListAction->setEnabled(false); + mItemAction->setEnabled(false); + + return; + } + + QList<QAction*> phraseActions; + phraseActions << mEmphasisAction << mEmphasisStrongAction << mFilenameAction + << mInterfaceAction << mLinkAction << mNlAction + << mShortcutAction; + + foreach (const StartTag& startTag, openElementsAtCursor) { + QAction* action = actionForElement(startTag); + if (!action) { + continue; + } + + action->setChecked(true); + + bool elementClosed = parser.isElementClosed(startTag); + if (elementClosed && action != mLinkAction) { + action->setEnabled(false); + } else if (elementClosed && action == mLinkAction) { + action->setEnabled(true); + mLinkElementClosed = true; + } + + if (phraseActions.contains(action)) { + foreach (QAction* actionToDisable, mActions) { + if (actionToDisable != action) { + actionToDisable->setEnabled(false); + } + } + } else if (action == mParaAction) { + if (!mListAction->isChecked()) { + mItemAction->setEnabled(false); + } + } else if (action == mListAction) { + mParaAction->setEnabled(false); + if (!mItemAction->isChecked()) { + foreach (QAction* phraseAction, phraseActions) { + phraseAction->setEnabled(false); + } + } + } else if (action == mItemAction) { + mParaAction->setEnabled(false); + mListAction->setEnabled(false); + } + } +} + +void SemanticMarkupEdition::emphasis() { + writeSimpleTagFor(mEmphasisAction); +} + +void SemanticMarkupEdition::emphasisStrong() { + if (mEmphasisStrongAction->isChecked()) { + mTextEdit->insertPlainText("<emphasis strong=\"yes\">"); + } else { + mTextEdit->insertPlainText("</emphasis>"); + } +} + +void SemanticMarkupEdition::filename() { + writeSimpleTagFor(mFilenameAction); +} + +void SemanticMarkupEdition::interface() { + writeSimpleTagFor(mInterfaceAction); +} + +void SemanticMarkupEdition::link() { + if (!mLinkAction->isChecked() && !mLinkElementClosed) { + mTextEdit->insertPlainText("</link>"); + return; + } + + if (!mLinkElementClosed) { + QScopedPointer<QDialog> dialog(newLinkDialog("")); + if (DialogRunner(dialog.data()).exec() == QDialog::Rejected) { + mLinkAction->setChecked(false); + return; + } + + QString newUrl = dialog->findChild<SemanticMarkupLinkWidget*>()->url(); + mTextEdit->insertPlainText(QString("<link url=\"%1\">").arg(newUrl)); + + return; + } + + mLinkAction->setChecked(true); + + QString text = mTextEdit->toPlainText(); + int cursorIndex = mTextEdit->textCursor().position(); + QRegExp linkRegExp("<\\s*link\\s*(\\w+=\"[^\"]*\")*\\s*>"); + int linkElementIndex = text.lastIndexOf(linkRegExp, cursorIndex); + + QString linkText = linkRegExp.capturedTexts().at(0); + QRegExp urlRegExp(" url=\"([^\"]*)\""); + int urlAttributeIndex = linkText.indexOf(urlRegExp); + + if (urlAttributeIndex == -1) { + urlAttributeIndex = QString("<link").length(); + } + + int absoluteUrlAttributeIndex = linkElementIndex + urlAttributeIndex; + QString oldUrlAttribute = urlRegExp.capturedTexts().at(0); + QString oldUrl = urlRegExp.capturedTexts().at(1); + + QScopedPointer<QDialog> dialog(newLinkDialog(oldUrl)); + if (DialogRunner(dialog.data()).exec() == QDialog::Rejected) { + return; + } + + QString newUrl = dialog->findChild<SemanticMarkupLinkWidget*>()->url(); + + QTextCursor cursor = mTextEdit->textCursor(); + cursor.setPosition(absoluteUrlAttributeIndex); + cursor.movePosition(QTextCursor::NextCharacter, QTextCursor::KeepAnchor, + oldUrlAttribute.length()); + cursor.insertText(QString(" url=\"%1\"").arg(newUrl)); +} + +void SemanticMarkupEdition::nl() { + mTextEdit->insertPlainText("<nl/>\n"); +} + +void SemanticMarkupEdition::shortcut() { + writeSimpleTagFor(mShortcutAction); +} + +void SemanticMarkupEdition::para() { + if (mParaAction->isChecked()) { + mTextEdit->insertPlainText("<para>"); + } else { + mTextEdit->insertPlainText("</para>\n\n"); + } +} + +void SemanticMarkupEdition::list() { + if (mListAction->isChecked()) { + mTextEdit->insertPlainText("<list>\n"); + } else { + mTextEdit->insertPlainText("</list>\n"); + } +} + +void SemanticMarkupEdition::item() { + if (mItemAction->isChecked()) { + mTextEdit->insertPlainText("<item>"); + } else { + mTextEdit->insertPlainText("</item>\n"); + } +} Property changes on: trunk/ktutorial/ktutorial-editor/src/view/SemanticMarkupEdition.cpp ___________________________________________________________________ Added: svn:eol-style + native Added: trunk/ktutorial/ktutorial-editor/src/view/SemanticMarkupEdition.h =================================================================== --- trunk/ktutorial/ktutorial-editor/src/view/SemanticMarkupEdition.h (rev 0) +++ trunk/ktutorial/ktutorial-editor/src/view/SemanticMarkupEdition.h 2011-05-05 14:39:15 UTC (rev 301) @@ -0,0 +1,248 @@ +/*************************************************************************** + * Copyright (C) 2011 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 SEMANTICMARKUPEDITION_H +#define SEMANTICMARKUPEDITION_H + +#include <QObject> + +class QAction; +class QDialog; +class QTextEdit; + +class KActionCollection; + +class StartTag; + +/** + * Helper to edit KUIT semantic markup in a QTextEdit widget. + * SemanticMarkupEdition provides several actions that ease the edition of the + * most common KUIT semantic markup tags. The actions are added to a + * KActionCollection using createActions(KActionCollection*). + * + * Triggering an action will write its associated start tag in the current + * position of the text edit cursor. Triggering the action again will write its + * associated end tag. When a tag needs extra information from the user to be + * written (for example, the URL of a link element), a dialog will be shown. + * Also, triggering the action when the cursor is between two paired start and + * end tags will show the dialog and update the attribute. + * + * The action states will be updated based on the cursor of the QTextEdit. + * Depending on its position or the current selection some actions may be + * disabled or checked. + * + * When the cursor is inside any tag all the actions will be disabled. If it is + * between two paired start and end tags they will also be disabled (except the + * ones that show a dialog), although the action for that tag (and its paired + * parent elements) will be checked. If the cursor is after a start tag, the + * action for that tag will be enabled and checked (and triggering it will write + * the end tag). + * + * The actions may also be disabled when their element can not be written at the + * current position of the cursor. For example, the list action will be disabled + * unless the cursor is after a para tag. It will be disabled too if after the + * para tag there is a phrase element tag, as list elements can be child only of + * para elements. + * + * Only the cursor position is used to update the state of the actions. + * Selections are not taken into account. + */ +class SemanticMarkupEdition: public QObject { +Q_OBJECT +public: + + /** + * Creates a new SemanticMarkupEdition. + * The QTextEdit will also act as parent of the SemanticMarkupEdition. + * + * @param textEdit The QTextEdit used for the edition of the text. + */ + SemanticMarkupEdition(QTextEdit* textEdit); + + /** + * Creates the actions for markup edition and adds them to the given + * collection. + * The collection is made parent of the actions. + * + * @param actionCollection The collection to add the actions to. + */ + void createActions(KActionCollection* actionCollection); + +private: + + /** + * All the edition actions. + */ + QList<QAction*> mActions; + + /** + * Action for "emphasis" phrase tag. + */ + QAction* mEmphasisAction; + + /** + * Action for "emphasis" phrase tag with "strong" attribute. + */ + QAction* mEmphasisStrongAction; + + /** + * Action for "filename" phrase tag. + */ + QAction* mFilenameAction; + + /** + * Action for "interface" phrase tag. + */ + QAction* mInterfaceAction; + + /** + * Action for "link" phrase tag. + */ + QAction* mLinkAction; + + /** + * Action for "nl" phrase tag. + */ + QAction* mNlAction; + + /** + * Action for "shortcut" phrase tag. + */ + QAction* mShortcutAction; + + /** + * Action for "para" structure tag. + */ + QAction* mParaAction; + + /** + * Action for "list" structure tag. + */ + QAction* mListAction; + + /** + * Action for "item" structure tag. + */ + QAction* mItemAction; + + /** + * The QTextEdit used for the edition of the text. + */ + QTextEdit* mTextEdit; + + /** + * Whether the cursor is between two paired start and end link elements or + * not. + */ + bool mLinkElementClosed; + + /** + * Returns the action that represents the given start tag. + * + * @param startTag The start tag to get its action. + * @return The action for the tag. + */ + QAction* actionForElement(const StartTag& startTag) const; + + /** + * Writes a simple tag for the given action. + * If the action is checked, a start tag for the element of the action is + * inserted in the text edit. If the action is not checked, an end tag is + * inserted. + * + * @param action The action to write its tag. + */ + void writeSimpleTagFor(const QAction* action); + + /** + * Creates a new dialog for link elements. + * The dialog contains a SemanticMarkupLinkWidget and two dialog buttons: Ok + * and Cancel. + * + * @param url The URL to show in the link widget of the dialog. + * @return The new dialog. + */ + QDialog* newLinkDialog(const QString& url) const; + +private Q_SLOTS: + + /** + * Updates the state of the edition actions based on the cursor position. + */ + void updateActionStates(); + + /** + * Behavior for "emphasis" phrase tag edition. + */ + void emphasis(); + + /** + * Behavior for "emphasis" phrase tag with "strong" attribute edition. + */ + void emphasisStrong(); + + /** + * Behavior for "filename" phrase tag edition. + */ + void filename(); + + /** + * Behavior for "interface" phrase tag edition. + */ + void interface(); + + /** + * Behavior for "link" phrase tag edition. + * Unlike other tags, to write the start link" element the user has to + * provide some information. A dialog is shown to the user to set the URL of + * the link. + * + * Moreover, the URL can be modified even on a closed "link" element. The + * "link" action can be triggered even on a closed element, and when the + * action is triggered, the dialog is shown to modify the URL. + */ + void link(); + + /** + * Behavior for "nl" phrase tag edition. + */ + void nl(); + + /** + * Behavior for "shortcut" phrase tag edition. + */ + void shortcut(); + + /** + * Behavior for "para" structure tag edition. + */ + void para(); + + /** + * Behavior for "list" structure tag edition. + */ + void list(); + + /** + * Behavior for "item" structure tag edition. + */ + void item(); + +}; + +#endif Property changes on: trunk/ktutorial/ktutorial-editor/src/view/SemanticMarkupEdition.h ___________________________________________________________________ Added: svn:eol-style + native Added: trunk/ktutorial/ktutorial-editor/src/view/SemanticMarkupLinkWidget.cpp =================================================================== --- trunk/ktutorial/ktutorial-editor/src/view/SemanticMarkupLinkWidget.cpp (rev 0) +++ trunk/ktutorial/ktutorial-editor/src/view/SemanticMarkupLinkWidget.cpp 2011-05-05 14:39:15 UTC (rev 301) @@ -0,0 +1,93 @@ +/*************************************************************************** + * Copyright (C) 2011 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 "SemanticMarkupLinkWidget.h" + +#include "ui_SemanticMarkupLinkWidget.h" + +#ifdef QT_QTDBUS_FOUND +#include "RemoteObjectNameWidget.h" +#endif + +//public: + +SemanticMarkupLinkWidget::SemanticMarkupLinkWidget(QWidget* parent): + QWidget(parent) { + + ui = new Ui::SemanticMarkupLinkWidget(); + ui->setupUi(this); + +#ifdef QT_QTDBUS_FOUND + mRemoteObjectNameWidget = new RemoteObjectNameWidget(this); + + //Replace ui->widgetLinkLineEdit with mRemoteObjectNameWidget + ui->valueVerticalLayout->removeWidget(ui->widgetLinkLineEdit); + delete ui->widgetLinkLineEdit; + + ui->valueVerticalLayout->insertWidget(1, mRemoteObjectNameWidget); +#endif + + ui->genericLinkRadioButton->setChecked(true); + + connect(ui->genericLinkRadioButton, SIGNAL(toggled(bool)), + ui->genericLinkLineEdit, SLOT(setEnabled(bool))); + +#ifdef QT_QTDBUS_FOUND + mRemoteObjectNameWidget->setEnabled(false); + + connect(ui->widgetLinkRadioButton, SIGNAL(toggled(bool)), + mRemoteObjectNameWidget, SLOT(setEnabled(bool))); +#else + ui->widgetLinkLineEdit->setEnabled(false); + + connect(ui->widgetLinkRadioButton, SIGNAL(toggled(bool)), + ui->widgetLinkLineEdit, SLOT(setEnabled(bool))); +#endif +} + +SemanticMarkupLinkWidget::~SemanticMarkupLinkWidget() { + delete ui; +} + +QString SemanticMarkupLinkWidget::url() const { + if (ui->genericLinkRadioButton->isChecked()) { + return ui->genericLinkLineEdit->text(); + } + +#ifdef QT_QTDBUS_FOUND + return "widget:" + mRemoteObjectNameWidget->name(); +#else + return "widget:" + ui->widgetLinkLineEdit->text(); +#endif +} + +void SemanticMarkupLinkWidget::setUrl(const QString& url) { + if (!url.startsWith(QLatin1String("widget:"))) { + ui->genericLinkRadioButton->setChecked(true); + ui->genericLinkLineEdit->setText(url); + return; + } + + ui->widgetLinkRadioButton->setChecked(true); + QString widgetName = url.mid(QString("widget:").length()); +#ifdef QT_QTDBUS_FOUND + mRemoteObjectNameWidget->setName(widgetName); +#else + ui->widgetLinkLineEdit->setText(widgetName); +#endif +} Property changes on: trunk/ktutorial/ktutorial-editor/src/view/SemanticMarkupLinkWidget.cpp ___________________________________________________________________ Added: svn:eol-style + native Added: trunk/ktutorial/ktutorial-editor/src/view/SemanticMarkupLinkWidget.h =================================================================== --- trunk/ktutorial/ktutorial-editor/src/view/SemanticMarkupLinkWidget.h (rev 0) +++ trunk/ktutorial/ktutorial-editor/src/view/SemanticMarkupLinkWidget.h 2011-05-05 14:39:15 UTC (rev 301) @@ -0,0 +1,96 @@ +/*************************************************************************** + * Copyright (C) 2011 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 SEMANTICMARKUPLINKWIDGET_H +#define SEMANTICMARKUPLINKWIDGET_H + +#include <QWidget> + +#ifdef QT_QTDBUS_FOUND +class RemoteObjectNameWidget; +#endif + +namespace Ui { +class SemanticMarkupLinkWidget; +} + +/** + * Helper widget for the semantic markup edition to input the URL of a link. + * The widget contains a line edit where any URL can be written. However, it + * also offers support for a specific type of URLs: widget URLs. There are two + * radio buttons to select between a generic URL and a widget URL. + * + * Widget URLs represent a widget in the target application. When DBus module is + * enabled, the widget to link to can be selected using a RemoteObjectChooser. + * + * When the URL is got, the URL returned depends on the current type of URL + * selected. Widget URLs also contain the "widget:" protocol. When the URL is + * set, the line edit filled and radio button checked depend on the type of URL + * set. + */ +class SemanticMarkupLinkWidget: public QWidget { +Q_OBJECT +public: + + /** + * Creates a new SemanticMarkupLinkWidget. + * + * @param parent The parent QWidget. + */ + explicit SemanticMarkupLinkWidget(QWidget* parent = 0); + + /** + * Destroys this widget. + */ + virtual ~SemanticMarkupLinkWidget(); + + /** + * Returns the URL. + * If the URL is a widget URL, the returned URL contains the "widget:" + * protocol. + * + * @return The URL. + */ + QString url() const; + + /** + * Sets the URL. + * If the URL is a widget URL, the "widget:" protocol is not shown in its + * line edit. + * + * @param url The URL to set. + */ + void setUrl(const QString& url); + +private: + + /** + * The Ui Designer generated class. + */ + Ui::SemanticMarkupLinkWidget* ui; + +#ifdef QT_QTDBUS_FOUND + /** + * The widget to get the name of a remote object. + */ + RemoteObjectNameWidget* mRemoteObjectNameWidget; +#endif + +}; + +#endif Property changes on: trunk/ktutorial/ktutorial-editor/src/view/SemanticMarkupLinkWidget.h ___________________________________________________________________ Added: svn:eol-style + native Added: trunk/ktutorial/ktutorial-editor/src/view/SemanticMarkupLinkWidget.ui =================================================================== --- trunk/ktutorial/ktutorial-editor/src/view/SemanticMarkupLinkWidget.ui (rev 0) +++ trunk/ktutorial/ktutorial-editor/src/view/SemanticMarkupLinkWidget.ui 2011-05-05 14:39:15 UTC (rev 301) @@ -0,0 +1,91 @@ +<?xml version="1.0" encoding="UTF-8"?> +<ui version="4.0"> + <class>SemanticMarkupLinkWidget</class> + <widget class="QWidget" name="SemanticMarkupLinkWidget"> + <property name="geometry"> + <rect> + <x>0</x> + <y>0</y> + <width>400</width> + <height>300</height> + </rect> + </property> + <property name="sizePolicy"> + <sizepolicy hsizetype="Preferred" vsizetype="Preferred"> + <horstretch>0</horstretch> + <verstretch>0</verstretch> + </sizepolicy> + </property> + <property name="windowTitle"> + <string comment="@title">URL for <emphasis>link</emphasis> element</string> + </property> + <property name="whatsThis"> + <string comment="@info:whatsthis"><para>Set the <emphasis>url</emphasis> attribute for the <emphasis>link</emphasis> semantic element.</para> + +<para>Any URL can be set in the <interface>Generic</interface> field. For example, the URL of a webpage or the URL to link to a widget.</para> + +<para>However, to link to a widget it is better to just write the object name of the desired widget in the <interface>Widget</interface> field. Moreover, that field provides also text completion for the names and a dialog to choose the widget from a running target application.</para> + +<para>These advanced features, though, are not available in every system; if <application>KTutorial editor</application> was not built with <application>QtDBus</application> support only a plain text line will be shown. Again, only the name has to be written in the text line for the widget; <emphasis>widget:</emphasis> is automatically added to the URL when the dialog is accepted.</para></string> + </property> + <layout class="QVBoxLayout" name="SemanticMarkupLinkWidgetLayout"> + <item> + <layout class="QHBoxLayout" name="semanticMarkupLinkWidgetHorizontalLayout"> + <item> + <layout class="QVBoxLayout" name="radioButtonVerticalLayout"> + <item> + <widget class="QRadioButton" name="genericLinkRadioButton"> + <property name="text"> + <string comment="@option:radio Generic link URL">Generic</string> + </property> + </widget> + </item> + <item> + <widget class="QRadioButton" name="widgetLinkRadioButton"> + <property name="text"> + <string comment="@option:radio Widget link URL">Widget</string> + </property> + </widget> + </item> + </layout> + </item> + <item> + <layout class="QVBoxLayout" name="valueVerticalLayout"> + <item> + <widget class="KLineEdit" name="genericLinkLineEdit"/> + </item> + <item> + <widget class="KLineEdit" name="widgetLinkLineEdit"/> + </item> + </layout> + </item> + </layout> + </item> + <item> + <spacer name="semanticMarkupLinkWidgetSpacer"> + <property name="orientation"> + <enum>Qt::Vertical</enum> + </property> + <property name="sizeType"> + <enum>QSizePolicy::MinimumExpanding</enum> + </property> + <property name="sizeHint" stdset="0"> + <size> + <width>20</width> + <height>0</height> + </size> + </property> + </spacer> + </item> + </layout> + </widget> + <customwidgets> + <customwidget> + <class>KLineEdit</class> + <extends>QLineEdit</extends> + <header>klineedit.h</header> + </customwidget> + </customwidgets> + <resources/> + <connections/> +</ui> Added: trunk/ktutorial/ktutorial-editor/src/view/SemanticMarkupParser.cpp =================================================================== --- trunk/ktutorial/ktutorial-editor/src/view/SemanticMarkupParser.cpp (rev 0) +++ trunk/ktutorial/ktutorial-editor/src/view/SemanticMarkupParser.cpp 2011-05-05 14:39:15 UTC (rev 301) @@ -0,0 +1,137 @@ +/*************************************************************************** + * Copyright (C) 2011 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 "SemanticMarkupParser.h" + +#include <QRegExp> +#include <QStringList> + +//public: + +SemanticMarkupParser::SemanticMarkupParser(): + mCursorIndex(-1), + mCursorInsideTag(false) { +} + +void SemanticMarkupParser::setCursorIndex(int cursorIndex) { + mCursorIndex = cursorIndex; +} + +void SemanticMarkupParser::parse(const QString& text) { + mCursorInsideTag = false; + mOpenElements.clear(); + mOpenElementsAtCursor.clear(); + mNotClosedChildElements.clear(); + + QRegExp startTagRegExp("<\\s*(\\w+)\\s*((\\w+=\"[^\"]*\"\\s*)*)>"); + QRegExp endTagRegExp("</\\s*(\\w+)\\s*>"); + QRegExp emptyTagRegExp("<\\s*(\\w+)\\s*((\\w+=\"[^\"]*\"\\s*)*)/>"); + QRegExp tagRegExp(startTagRegExp.pattern() + '|' + + endTagRegExp.pattern() + '|' + + emptyTagRegExp.pattern()); + + bool parsingReachedCursor = false; + + int parsingIndex = tagRegExp.indexIn(text); + while (parsingIndex >= 0) { + QString tag = tagRegExp.capturedTexts().at(0); + + if (mCursorIndex > parsingIndex && + mCursorIndex < parsingIndex + tagRegExp.matchedLength()) { + mCursorInsideTag = true; + mOpenElementsAtCursor.clear(); + return; + } + + if (!parsingReachedCursor && parsingIndex >= mCursorIndex) { + parsingReachedCursor = true; + mOpenElementsAtCursor = mOpenElements; + } + + if (startTagRegExp.exactMatch(tag)) { + StartTag startTag; + startTag.mName = startTagRegExp.capturedTexts().at(1); + startTag.mAttributes = startTagRegExp.capturedTexts().at(2); + startTag.mIndex = parsingIndex; + mOpenElements.insert(0, startTag); + } else if (endTagRegExp.exactMatch(tag)) { + QString endTagName = endTagRegExp.capturedTexts().at(1); + + int endElementIndex = indexOf(mOpenElements, endTagName); + if (endElementIndex >= 0) { + int index = 0; + while (index < endElementIndex) { + mNotClosedChildElements.append(mOpenElements.first()); + mOpenElements.removeFirst(); + index++; + } + mOpenElements.removeFirst(); + } + } + + parsingIndex = parsingIndex + tagRegExp.matchedLength(); + parsingIndex = tagRegExp.indexIn(text, parsingIndex); + } + + if (!parsingReachedCursor) { + mOpenElementsAtCursor = mOpenElements; + } +} + +bool SemanticMarkupParser::isElementClosed(const StartTag& startTag) const { + if (indexOf(mOpenElements, startTag) > -1 || + indexOf(mNotClosedChildElements, startTag) > -1) { + return false; + } + + return true; +} + +bool SemanticMarkupParser::isCursorInsideTag() const { + return mCursorInsideTag; +} + +QList<StartTag> SemanticMarkupParser::openElementsAtCursor() const { + return mOpenElementsAtCursor; +} + +//private: + +int SemanticMarkupParser::indexOf(const QList<StartTag>& startTags, + const QString& tagName) const { + for (int i=0; i<startTags.count(); ++i) { + if (startTags[i].mName == tagName) { + return i; + } + } + + return -1; +} + +int SemanticMarkupParser::indexOf(const QList<StartTag>& startTags, + const StartTag& startTag) const { + for (int i=0; i<startTags.count(); ++i) { + if (startTags[i].mName == startTag.mName && + startTags[i].mAttributes == startTag.mAttributes && + startTags[i].mIndex == startTag.mIndex) { + return i; + } + } + + return -1; +} Property changes on: trunk/ktutorial/ktutorial-editor/src/view/SemanticMarkupParser.cpp ___________________________________________________________________ Added: svn:eol-style + native Added: trunk/ktutorial/ktutorial-editor/src/view/SemanticMarkupParser.h =================================================================== --- trunk/ktutorial/ktutorial-editor/src/view/SemanticMarkupParser.h (rev 0) +++ trunk/ktutorial/ktutorial-editor/src/view/SemanticMarkupParser.h 2011-05-05 14:39:15 UTC (rev 301) @@ -0,0 +1,182 @@ +/*************************************************************************** + * Copyright (C) 2011 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 SEMANTICMARKUPPARSER_H +#define SEMANTICMARKUPPARSER_H + +#include <QList> +#include <QString> + +/** + * Structure to store the data of a XML start tag. + */ +struct StartTag { + + /** + * The tag name. + */ + QString mName; + + /** + * The attributes, if any. + */ + QString mAttributes; + + /** + * The index of the tag in the text (the position of the '<' character). + */ + int mIndex; + + /** + * Creates a new StartTag. + */ + StartTag(): + mName(""), + mAttributes(""), + mIndex(-1) { + } + +}; + +/** + * Simple parser for texts containing KUIT semantic markup. + * The parser is meant to provide SemanticMarkupEdition with information about + * the markup in the text. Thus, it is designed just for that purpose; it is not + * a general purpose parser. + * + * The parser supports XML where not all the elements have been closed. For + * example, it can parse a text with just a start tag, or a text where there + * is an unpaired start tag inside a valid element (one with paired start and + * end tags). + * + * The parser stores which elements have been opened, and when it reaches an end + * tag it regardes as closed the newest element that matches the end tag. For + * example, in <a><a><b></a></b>, when </a> + * is reached the second "a" element is regarded as closed. The </b> will + * be ignored, as the "b" element is no longer taken into account since its + * parent element was closed. Note, however, that the "b" element is not closed, + * and isElementClosed(StartTag) with that "b" element would return false. + * Passing the first "a" element would also return false; true would be returned + * only for the second "a" element. + * + * Before parsing a text, the cursor index has to be set using + * setCursorIndex(int). Then the text can be parsed using parse(QString). + * + * Once parsed, the SemanticMarkupParser object provides information about the + * parsed text regarding the cursor position. To update the information provided + * the text must be parsed again; that is, even if the only change is in the + * cursor index, parse(QString) has to be called again. + */ +class SemanticMarkupParser { +public: + + /** + * Creates a new SemanticMarkupParser. + */ + SemanticMarkupParser(); + + /** + * Sets the index of the cursor. + * + * @param cursorIndex The index to set. + */ + void setCursorIndex(int cursorIndex); + + /** + * Parses the given text, updating the state of this parser. + * + * @param text The text to parse. + */ + void parse(const QString& text); + + /** + * Returns whether the cursor is inside a tag or not. + * + * @return True if the cursor is inside a tag, false otherwise. + */ + bool isCursorInsideTag() const; + + /** + * Returns whether the given start tag was closed or not. + * + * @param startTag The tag to check. + * @return True if the start tag was closed, false otherwise. + */ + bool isElementClosed(const StartTag& startTag) const; + + /** + * Returns a list with all the start tags that were open at the cursor + * position. + * The order of the tags goes from the deepest one to the more general one. + * That is, for <a><b>, the first tag is "b" and the second one + * is "a". + * + * @return The start tags open at the cursor. + */ + QList<StartTag> openElementsAtCursor() const; + +private: + + /** + * The position of the cursor in the text. + */ + int mCursorIndex; + + /** + * Whether the cursor was inside a tag or not in the last parsed text. + */ + bool mCursorInsideTag; + + /** + * A list with all the open elements at the end of the last parsed text. + */ + QList<StartTag> mOpenElements; + + /** + * A list with all the open elements at the cursor of the last parsed text. + */ + QList<StartTag> mOpenElementsAtCursor; + + /** + * A list with all the elements that were not closed but some ancestor + * element was at the end of the last parsed text. + */ + QList<StartTag> mNotClosedChildElements; + + /** + * The position in the given list of a tag with the given name. + * + * @param startTags The list to check. + * @param tagName The name of the tag to find. + * @return The position of the tag name, or -1 if it is not found. + */ + int indexOf(const QList<StartTag>& startTags, const QString& tagName) const; + + /** + * The position in the given list of the given tag. + * + * @param startTags The list to check. + * @param startTag The tag to find. + * @return The position of the tag, or -1 if it is not found. + */ + int indexOf(const QList<StartTag>& startTags, + const StartTag& startTag) const; + +}; + +#endif Property changes on: trunk/ktutorial/ktutorial-editor/src/view/SemanticMarkupParser.h ___________________________________________________________________ Added: svn:eol-style + native Modified: trunk/ktutorial/ktutorial-editor/src/view/StepDataWidget.cpp =================================================================== --- trunk/ktutorial/ktutorial-editor/src/view/StepDataWidget.cpp 2011-04-30 17:31:13 UTC (rev 300) +++ trunk/ktutorial/ktutorial-editor/src/view/StepDataWidget.cpp 2011-05-05 14:39:15 UTC (rev 301) @@ -1,5 +1,5 @@ /*************************************************************************** - * Copyright (C) 2010 by Daniel Calviño Sánchez * + * Copyright (C) 2010-2011 by Daniel Calviño Sánchez * * dan...@gm... * * * * This program is free software; you can redistribute it and/or modify * @@ -18,7 +18,11 @@ #include "StepDataWidget.h" +#include <KActionCollection> +#include <KToolBar> + #include "ui_StepDataWidget.h" +#include "SemanticMarkupEdition.h" #include "../commands/StepCommands.h" #include "../data/Step.h" @@ -30,6 +34,17 @@ ui = new Ui::StepDataWidget(); ui->setupUi(this); + KToolBar* toolBar = new KToolBar(this); + int textEditIndex = ui->textLayout->indexOf(ui->textTextEdit); + ui->textLayout->insertWidget(textEditIndex, toolBar); + + KActionCollection* editionActions = new KActionCollection(this); + editionActions->addAssociatedWidget(toolBar); + + SemanticMarkupEdition* semanticMarkupEdition = + new SemanticMarkupEdition(ui->textTextEdit); + semanticMarkupEdition->createActions(editionActions); + ui->idLineEdit->setText(step->id()); ui->textTextEdit->setPlainText(step->text()); } Modified: trunk/ktutorial/ktutorial-editor/tests/unit/view/CMakeLists.txt =================================================================== --- trunk/ktutorial/ktutorial-editor/tests/unit/view/CMakeLists.txt 2011-04-30 17:31:13 UTC (rev 300) +++ trunk/ktutorial/ktutorial-editor/tests/unit/view/CMakeLists.txt 2011-05-05 14:39:15 UTC (rev 301) @@ -26,6 +26,9 @@ NewWaitForWidget ReactionTreeItem ReactionWidget + SemanticMarkupEdition + SemanticMarkupLinkWidget + SemanticMarkupParser StepCustomCodeWidget StepDataWidget StepTreeItem @@ -79,6 +82,9 @@ NewWaitForWidget ReactionTreeItem ReactionWidget + SemanticMarkupEdition + SemanticMarkupLinkWidget + SemanticMarkupParser StepCustomCodeWidget StepDataWidget StepTreeItem Added: trunk/ktutorial/ktutorial-editor/tests/unit/view/SemanticMarkupEditionTest.cpp =================================================================== --- trunk/ktutorial/ktutorial-editor/tests/unit/view/SemanticMarkupEditionTest.cpp (rev 0) +++ trunk/ktutorial/ktutorial-editor/tests/unit/view/SemanticMarkupEditionTest.cpp 2011-05-05 14:39:15 UTC (rev 301) @@ -0,0 +1,842 @@ +/*************************************************************************** + * Copyright (C) 2011 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 "SemanticMarkupEdition.h" + +#include <QAction> +#include <QTextEdit> + +#include <KActionCollection> +#include <KPushButton> + +#include "SemanticMarkupLinkWidget.h" + +class SemanticMarkupEditionTest: public QObject { +Q_OBJECT + +private slots: + + void init(); + void cleanup(); + + void testConstructor(); + + void testCreateActions(); + + void testEmphasis(); + void testEmphasisStrong(); + void testFilename(); + void testInterface(); + void testLink(); + void testLinkUpdate(); + void testLinkUpdateWithoutUrlAttribute(); + void testNl(); + void testShortcut(); + void testPara(); + void testList(); + void testItem(); + + void testCursorInStartTag(); + void testCursorInEndTag(); + void testCursorInEmptyElementTag(); + + void testCursorBetweenPhraseTags(); + void testCursorBetweenLinkTags(); + void testCursorBetweenLinkTagsWithChildElement(); + void testCursorBetweenParaTags(); + void testCursorBetweenParaTagsWithPhraseTagNotClosed(); + void testCursorBetweenListTags(); + void testCursorBetweenListTagsWithItemTagNotClosed(); + void testCursorBetweenItemTags(); + void testCursorBetweenItemTagsWithPhraseTagNotClosed(); + + void testCursorBetweenEndAndStartTags(); + void testCursorBetweenUnpairedTags(); + void testCursorBetweenUnpairedTagsClosedLater(); + void testCursorBetweenTwoStartTags(); + void testCursorBetweenTwoEndTags(); + + void testChangeTextWithoutChangingCursorPosition(); + +private: + + SemanticMarkupEdition* mSemanticMarkupEdition; + KActionCollection* mActionCollection; + QTextEdit* mTextEdit; + + QAction* mEmphasisAction; + QAction* mEmphasisStrongAction; + QAction* mFilenameAction; + QAction* mInterfaceAction; + QAction* mLinkAction; + QAction* mNlAction; + QAction* mShortcutAction; + QAction* mParaAction; + QAction* mListAction; + QAction* mItemAction; + + void queueAssertLinkUrl(const QString& url, int timeToWait); + void queueSetLinkUrl(const QString& url, int timeToWait); + void queueCancelSetLinkUrl(const QString& url, int timeToWait); + + void moveCursorTo(int position) const; + + void assertOnlyEnabled(const QList<QAction*>& enabledActions) const; + void assertOnlyDisabled(const QList<QAction*>& disabledActions) const; + void assertOnlyChecked(const QList<QAction*>& checkedActions) const; + + void assertTextStartTriggerTextEndTriggerText(QAction* action, + const QString& tagName) const; + +}; + +void SemanticMarkupEditionTest::init() { + mTextEdit = new QTextEdit(); + mSemanticMarkupEdition = new SemanticMarkupEdition(mTextEdit); + mActionCollection = new KActionCollection(this); + + mSemanticMarkupEdition->createActions(mActionCollection); + + mEmphasisAction = mActionCollection->action("kuit-edition-phrase-emphasis"); + mEmphasisStrongAction = + mActionCollection->action("kuit-edition-phrase-emphasis-strong"); + mFilenameAction = mActionCollection->action("kuit-edition-phrase-filename"); + mInterfaceAction = + mActionCollection->action("kuit-edition-phrase-interface"); + mLinkAction = mActionCollection->action("kuit-edition-phrase-link"); + mNlAction = mActionCollection->action("kuit-edition-phrase-nl"); + mShortcutAction = mActionCollection->action("kuit-edition-phrase-shortcut"); + mParaAction = mActionCollection->action("kuit-edition-structure-para"); + mListAction = mActionCollection->action("kuit-edition-structure-list"); + mItemAction = mActionCollection->action("kuit-edition-structure-item"); +} + +void SemanticMarkupEditionTest::cleanup() { + delete mActionCollection; + delete mTextEdit; +} + +void SemanticMarkupEditionTest::testConstructor() { + QTextEdit textEdit; + SemanticMarkupEdition* semanticMarkupEdition = + new SemanticMarkupEdition(&textEdit); + + QCOMPARE(semanticMarkupEdition->parent(), &textEdit); +} + +void SemanticMarkupEditionTest::testCreateActions() { + QTextEdit textEdit; + SemanticMarkupEdition* semanticMarkupEdition = + new SemanticMarkupEdition(&textEdit); + KActionCollection actionCollection(this); + + semanticMarkupEdition->createActions(&actionCollection); + + QCOMPARE(actionCollection.count(), 10); + QVERIFY(actionCollection.action("kuit-edition-phrase-emphasis")); + QVERIFY(actionCollectio... [truncated message content] |
From: <dan...@us...> - 2011-04-30 17:31:19
|
Revision: 300 http://ktutorial.svn.sourceforge.net/ktutorial/?rev=300&view=rev Author: danxuliu Date: 2011-04-30 17:31:13 +0000 (Sat, 30 Apr 2011) Log Message: ----------- Fix Krazy2 issues (doublequote, spelling and strings). Modified Paths: -------------- trunk/ktutorial/ktutorial-editor/src/view/RemoteObjectNameRegister.cpp trunk/ktutorial/ktutorial-editor/src/view/RemoteObjectNameRegister.h Modified: trunk/ktutorial/ktutorial-editor/src/view/RemoteObjectNameRegister.cpp =================================================================== --- trunk/ktutorial/ktutorial-editor/src/view/RemoteObjectNameRegister.cpp 2011-04-30 16:53:54 UTC (rev 299) +++ trunk/ktutorial/ktutorial-editor/src/view/RemoteObjectNameRegister.cpp 2011-04-30 17:31:13 UTC (rev 300) @@ -66,7 +66,7 @@ for (int i=1; i<reversedFullPath.size(); ++i) { if (ancestorNotInPaths(reversedFullPath[i], reversedPathsToHomonyms)) { - return reversedFullPath[i] + "/" + reversedFullPath[0]; + return reversedFullPath[i] + '/' + reversedFullPath[0]; } } @@ -155,7 +155,7 @@ RemoteObject* parent = remoteObject; while (parent) { QString name = parent->name(); - if (!name.isEmpty() && !name.startsWith("qt_")) { + if (!name.isEmpty() && !name.startsWith(QLatin1String("qt_"))) { reversedPath.append(name); } parent = mRemoteObjectForParent.key(parent); Modified: trunk/ktutorial/ktutorial-editor/src/view/RemoteObjectNameRegister.h =================================================================== --- trunk/ktutorial/ktutorial-editor/src/view/RemoteObjectNameRegister.h 2011-04-30 16:53:54 UTC (rev 299) +++ trunk/ktutorial/ktutorial-editor/src/view/RemoteObjectNameRegister.h 2011-04-30 17:31:13 UTC (rev 300) @@ -30,7 +30,7 @@ * Provides information related to the names of the remote objects in the target * application. * RemoteObjectNameRegister can be used to know the names of all the remote - * objects accesible by KTutorial in the target application, and it also + * objects accessible by KTutorial in the target application, and it also * notifies the names of the remote objects added or removed in the target * application through the signals nameAdded(QString) and nameRemoved(QString). * This was sent by the SourceForge.net collaborative development platform, the world's largest Open Source development site. |
From: <dan...@us...> - 2011-04-30 16:54:00
|
Revision: 299 http://ktutorial.svn.sourceforge.net/ktutorial/?rev=299&view=rev Author: danxuliu Date: 2011-04-30 16:53:54 +0000 (Sat, 30 Apr 2011) Log Message: ----------- Fix missing memory tests. Modified Paths: -------------- trunk/ktutorial/ktutorial-editor/tests/unit/view/CMakeLists.txt Modified: trunk/ktutorial/ktutorial-editor/tests/unit/view/CMakeLists.txt =================================================================== --- trunk/ktutorial/ktutorial-editor/tests/unit/view/CMakeLists.txt 2011-04-15 16:29:27 UTC (rev 298) +++ trunk/ktutorial/ktutorial-editor/tests/unit/view/CMakeLists.txt 2011-04-30 16:53:54 UTC (rev 299) @@ -106,6 +106,8 @@ mem_tests( RemoteObjectChooser RemoteObjectChooserFilterModel + RemoteObjectNameRegister + RemoteObjectNameWidget RemoteObjectTreeItem RemoteObjectTreeItemUpdater RemoteObjectTreeSelectionManager This was sent by the SourceForge.net collaborative development platform, the world's largest Open Source development site. |
From: <dan...@us...> - 2011-04-15 16:29:34
|
Revision: 298 http://ktutorial.svn.sourceforge.net/ktutorial/?rev=298&view=rev Author: danxuliu Date: 2011-04-15 16:29:27 +0000 (Fri, 15 Apr 2011) Log Message: ----------- Fix always exporting step text as rich text, even when there were no rich text or semantic markup tags. 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 2011-04-08 15:14:19 UTC (rev 297) +++ trunk/ktutorial/ktutorial-editor/src/serialization/JavascriptExporter.cpp 2011-04-15 16:29:27 UTC (rev 298) @@ -19,7 +19,9 @@ #include "JavascriptExporter.h" #include <QRegExp> +#include <QSet> #include <QStringList> +#include <QTextDocument> #include "../data/Reaction.h" #include "../data/Step.h" @@ -137,9 +139,13 @@ if (step->text().isEmpty()) { out() << "//Error: Step without text!\n"; - } else { + } else if (Qt::mightBeRichText(step->text()) || + mightContainSemanticMarkup(step->text())) { out() << stepVariable << ".setText(t.i18nc(\"@info\", \"" << escape(step->text()) << "\"));\n"; + } else { + out() << stepVariable << ".setText(t.i18nc(\"@info/plain\", \"" + << escape(step->text()) << "\"));\n"; } mOut << '\n'; @@ -485,3 +491,26 @@ return upperCamelCase; } + +bool JavascriptExporter::mightContainSemanticMarkup(const QString& text) const { + QSet<QString> semanticMarkupTags; + semanticMarkupTags << "application" << "bcode" << "command" << "email" + << "emphasis" << "envar" << "filename" << "icode" + << "interface" << "link" << "message" << "nl" + << "numid" << "placeholder" << "resource" << "shortcut"; + semanticMarkupTags << "para" << "title" << "subtitle" << "list" << "item"; + semanticMarkupTags << "note" << "warning"; + + QRegExp tagRegExp(QString::fromLatin1("<\\s*(\\w+)[^>]*>")); + + int index = text.indexOf(tagRegExp); + while (index >= 0) { + QString tagName = tagRegExp.capturedTexts().at(1).toLower(); + if (semanticMarkupTags.contains(tagName)) { + return true; + } + index = text.indexOf(tagRegExp, index + tagRegExp.matchedLength()); + } + + return false; +} Modified: trunk/ktutorial/ktutorial-editor/src/serialization/JavascriptExporter.h =================================================================== --- trunk/ktutorial/ktutorial-editor/src/serialization/JavascriptExporter.h 2011-04-08 15:14:19 UTC (rev 297) +++ trunk/ktutorial/ktutorial-editor/src/serialization/JavascriptExporter.h 2011-04-15 16:29:27 UTC (rev 298) @@ -130,7 +130,9 @@ /** * 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. + * If the step id or name aren't set, an error message is written instead. + * When the text seems to contain rich text or semantic markup, it is + * formatted as rich text. Otherwise, it is formatted as plain text. * * @param step The step to write its code. */ @@ -312,6 +314,18 @@ */ QString toUpperCamelCase(QString text) const; + /** + * Returns true if the string text is likely to contain semantic markup. + * It just checks whether there is something that looks like a KUIT tag in + * the text. Although the result may be correct for common cases, there is + * no guarantee. + * + * @param text The string to check. + * @return True if the string text is likely to contain semantic markup, + * false otherwise. + */ + bool mightContainSemanticMarkup(const QString& text) const; + }; #endif Modified: trunk/ktutorial/ktutorial-editor/tests/unit/serialization/JavascriptExporterTest.cpp =================================================================== --- trunk/ktutorial/ktutorial-editor/tests/unit/serialization/JavascriptExporterTest.cpp 2011-04-08 15:14:19 UTC (rev 297) +++ trunk/ktutorial/ktutorial-editor/tests/unit/serialization/JavascriptExporterTest.cpp 2011-04-15 16:29:27 UTC (rev 298) @@ -65,6 +65,8 @@ void testStep(); void testStepWithEscapeSequences(); + void testStepWithRichText(); + void testStepWithSemanticMarkup(); void testStepSetupCode(); void testStepSetupCodeWithReactions(); void testStepTearDownCode(); @@ -239,7 +241,7 @@ TUTORIAL_EMPTY_INFORMATION_CODE "//Step The id1\n" "theId1Step = ktutorial.newStep(\"The id1\");\n" -"theId1Step.setText(t.i18nc(\"@info\", \"The text1\"));\n" +"theId1Step.setText(t.i18nc(\"@info/plain\", \"The text1\"));\n" "\n" "function theId1StepSetup(step) {\n" " waitForTheSignalNameByTheEmitterName = \ @@ -262,7 +264,7 @@ "\n" "//Step The id2\n" "theId2Step = ktutorial.newStep(\"The id2\");\n" -"theId2Step.setText(t.i18nc(\"@info\", \"The text2\"));\n" +"theId2Step.setText(t.i18nc(\"@info/plain\", \"The text2\"));\n" "\n" "function theId2StepSetup(step) {\n" " waitForTheSignalNameByTheEmitterName = \ @@ -301,7 +303,7 @@ TUTORIAL_EMPTY_INFORMATION_CODE "//Step The id\n" "theIdStep = ktutorial.newStep(\"The id\");\n" -"theIdStep.setText(t.i18nc(\"@info\", \"The text\"));\n" +"theIdStep.setText(t.i18nc(\"@info/plain\", \"The text\"));\n" "\n" "tutorial.addStep(theIdStep);\n" "\n"; @@ -323,7 +325,7 @@ TUTORIAL_EMPTY_INFORMATION_CODE "//Step The \"id\"\n" "theIdStep = ktutorial.newStep(\"The \\\"id\\\"\");\n" -"theIdStep.setText(t.i18nc(\"@info\", \ +"theIdStep.setText(t.i18nc(\"@info/plain\", \ \"The\\ttext\\nwith \\\"escape\\\" sequences\"));\n" "\n" "tutorial.addStep(theIdStep);\n" @@ -332,6 +334,51 @@ QCOMPARE(exportedTutorial, expected); } +void JavascriptExporterTest::testStepWithRichText() { + Tutorial tutorial; + Step* step = new Step(); + step->setId("The id"); + step->setText("The <i>rich</i> 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 <i>rich</i> text\"));\n" +"\n" +"tutorial.addStep(theIdStep);\n" +"\n"; + + QCOMPARE(exportedTutorial, expected); +} + +void JavascriptExporterTest::testStepWithSemanticMarkup() { + Tutorial tutorial; + Step* step = new Step(); + step->setId("The id"); + step->setText("The text with <emphasis>semantic markup</emphasis>"); + 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 with <emphasis>semantic markup</emphasis>\"));\n" +"\n" +"tutorial.addStep(theIdStep);\n" +"\n"; + + QCOMPARE(exportedTutorial, expected); +} + void JavascriptExporterTest::testStepSetupCode() { 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...> - 2011-04-08 15:14:25
|
Revision: 297 http://ktutorial.svn.sourceforge.net/ktutorial/?rev=297&view=rev Author: danxuliu Date: 2011-04-08 15:14:19 +0000 (Fri, 08 Apr 2011) Log Message: ----------- When a duplicated name is matched in the text completion, the name in the match list is now replaced by the unique names of the remote objects it represents. Modified Paths: -------------- trunk/ktutorial/ktutorial-editor/src/view/RemoteObjectNameRegister.cpp trunk/ktutorial/ktutorial-editor/src/view/RemoteObjectNameRegister.h trunk/ktutorial/ktutorial-editor/src/view/RemoteObjectNameWidget.cpp trunk/ktutorial/ktutorial-editor/src/view/RemoteObjectNameWidget.h trunk/ktutorial/ktutorial-editor/tests/unit/view/RemoteObjectNameRegisterTest.cpp trunk/ktutorial/ktutorial-editor/tests/unit/view/RemoteObjectNameWidgetTest.cpp Modified: trunk/ktutorial/ktutorial-editor/src/view/RemoteObjectNameRegister.cpp =================================================================== --- trunk/ktutorial/ktutorial-editor/src/view/RemoteObjectNameRegister.cpp 2011-04-05 02:11:06 UTC (rev 296) +++ trunk/ktutorial/ktutorial-editor/src/view/RemoteObjectNameRegister.cpp 2011-04-08 15:14:19 UTC (rev 297) @@ -84,6 +84,24 @@ return reversedPathAsName(reversedUniquePath); } +QStringList RemoteObjectNameRegister::uniqueNames(const QString& name) const +throw (DBusException) { + Q_ASSERT(mRemoteObjectForName.values(name).count() > 0); + + QStringList uniqueNames; + + if (mRemoteObjectForName.values(name).count() <= 1) { + uniqueNames.append(name); + return uniqueNames; + } + + foreach (RemoteObject* remoteObject, mRemoteObjectForName.values(name)) { + uniqueNames.append(uniqueName(remoteObject)); + } + + return uniqueNames; +} + RemoteObject* RemoteObjectNameRegister::findRemoteObject(const QString& name) const { return findRemoteObject(name, 0); Modified: trunk/ktutorial/ktutorial-editor/src/view/RemoteObjectNameRegister.h =================================================================== --- trunk/ktutorial/ktutorial-editor/src/view/RemoteObjectNameRegister.h 2011-04-05 02:11:06 UTC (rev 296) +++ trunk/ktutorial/ktutorial-editor/src/view/RemoteObjectNameRegister.h 2011-04-08 15:14:19 UTC (rev 297) @@ -38,7 +38,10 @@ * case, the names of one or more ancestors are required to differentiate * between those remote objects. The compound name that identifies a remote * object can be got using uniqueName(RemoteObject*). Also, given a name, the - * remote object that it represents can be got using findObject(QString). + * remote object that it represents can be got using findObject(QString). An + * unqualified name (without any ancestor names, just the name of the remote + * object itself) can be used to get the unique names of all the remote objects + * represented by that unqualified name. * * Note that a name and the remote object it represents depends on the state of * the target application. For example, if there is a dialog named @@ -94,6 +97,17 @@ QString uniqueName(RemoteObject* remoteObject) const throw (DBusException); /** + * Returns the unique names of the remote objects that have the given name. + * The given name can not contain any ancestor names, and it must be a + * registered name. + * + * @param name The name of the remote objects to get their unique names. + * @return The unique names of the remote objects that have the given name. + * @throws DBusException If a DBus error happens. + */ + QStringList uniqueNames(const QString& name) const throw (DBusException); + + /** * Returns the remote object with the given name, if any. * When the name of the desired remote object is not unique the name of some * ancestor must be included. Ancestor names are separated using a "/". That Modified: trunk/ktutorial/ktutorial-editor/src/view/RemoteObjectNameWidget.cpp =================================================================== --- trunk/ktutorial/ktutorial-editor/src/view/RemoteObjectNameWidget.cpp 2011-04-05 02:11:06 UTC (rev 296) +++ trunk/ktutorial/ktutorial-editor/src/view/RemoteObjectNameWidget.cpp 2011-04-08 15:14:19 UTC (rev 297) @@ -19,12 +19,88 @@ #include "RemoteObjectNameWidget.h" #include "ui_RemoteObjectNameWidget.h" +#include <KDebug> #include <KMessageBox> #include "RemoteObjectChooser.h" #include "RemoteObjectNameRegister.h" #include "../targetapplication/TargetApplication.h" +/** + * Completion for remote object names. + * The items added for completion should be the unqualified remote object names, + * that is, just the name of the remote objects, without any ancestor. When a + * match is found, and it represents more than one remote object, the match is + * replaced by the unique names of its remote objects. + */ +class RemoteObjectNameCompletion: public KCompletion { +public: + + /** + * Creates a new RemoteObjectNameCompletion. + * + * @param nameRegister The register to query about the remote object names. + */ + RemoteObjectNameCompletion(RemoteObjectNameRegister* nameRegister): + KCompletion() { + mNameRegister = nameRegister; + } + +protected: + + /** + * Default parent implementation. + * It is implemented just to avoid a compilation warning that complains that + * the method in the parent class is hidden by + * postProcessMatches(QStringList*). + * + * @param matches The matches to process. + */ + virtual void postProcessMatches(KCompletionMatches* matches) const { + KCompletion::postProcessMatches(matches); + } + + /** + * Processes the matches to provide unique names. + * When a match is a name that represents several remote objects that match + * is replaced by all the unique names of the remote objects it represents. + * + * @param matches The matches to process. + */ + virtual void postProcessMatches(QStringList* matches) const { + QMutableListIterator<QString> it(*matches); + while (it.hasNext()) { + QStringList uniqueNames; + + try { + uniqueNames = mNameRegister->uniqueNames(it.next()); + } catch (DBusException e) { + kWarning() << "The unique names for the remote objects named " + << it.value() << "could not be added to the " + << "completion matches (" << e.message() << ")"; + } + + if (uniqueNames.count() > 1) { + it.remove(); + + qSort(uniqueNames); + + foreach (const QString& uniqueName, uniqueNames) { + it.insert(uniqueName); + } + } + } + } + +private: + + /** + * The RemoteObjectNameRegister to query about the remote object names. + */ + RemoteObjectNameRegister* mNameRegister; + +}; + //public: RemoteObjectNameWidget::RemoteObjectNameWidget(QWidget* parent): @@ -41,8 +117,10 @@ connect(ui->objectNamePushButton, SIGNAL(clicked(bool)), this, SLOT(showRemoteObjectChooser())); - KCompletion* completion = ui->objectNameLineEdit->completionObject(); + KCompletion* completion = + new RemoteObjectNameCompletion(mRemoteObjectNameRegister); completion->setOrder(KCompletion::Sorted); + ui->objectNameLineEdit->setCompletionObject(completion); foreach (const QString& name, mRemoteObjectNameRegister->names()) { completion->addItem(name); Modified: trunk/ktutorial/ktutorial-editor/src/view/RemoteObjectNameWidget.h =================================================================== --- trunk/ktutorial/ktutorial-editor/src/view/RemoteObjectNameWidget.h 2011-04-05 02:11:06 UTC (rev 296) +++ trunk/ktutorial/ktutorial-editor/src/view/RemoteObjectNameWidget.h 2011-04-08 15:14:19 UTC (rev 297) @@ -37,6 +37,8 @@ * The line edit provides text completion for the names of the remote objects * in the target application. If there is no target application running, no * completion is provided. As soon as it starts, the completion is enabled. + * When the completion matches contain a name that represents several remote + * objects that match is replaced by the unique name of each remote object. * * When a name is set in the line edit the signal * remoteObjectChosen(RemoteObject*) is emitted. Modified: trunk/ktutorial/ktutorial-editor/tests/unit/view/RemoteObjectNameRegisterTest.cpp =================================================================== --- trunk/ktutorial/ktutorial-editor/tests/unit/view/RemoteObjectNameRegisterTest.cpp 2011-04-05 02:11:06 UTC (rev 296) +++ trunk/ktutorial/ktutorial-editor/tests/unit/view/RemoteObjectNameRegisterTest.cpp 2011-04-08 15:14:19 UTC (rev 297) @@ -58,6 +58,9 @@ void testUniqueNameWhenUniqueUnionOfGrandparentAndParent(); void testUniqueNameWhenEmptyName(); + void testUniqueNames(); + void testUniqueNamesWithSingleRemoteObject(); + private: QString mPath; @@ -358,6 +361,42 @@ QCOMPARE(remoteObjectNameRegister.uniqueName(remoteObject), QString("")); } +void RemoteObjectNameRegisterTest::testUniqueNames() { + TargetApplication::self()->setTargetApplicationFilePath(mPath); + TargetApplication::self()->start(); + + //Give the target application time to start + QTest::qWait(1000); + + RemoteObjectNameRegister remoteObjectNameRegister; + + QStringList uniqueNames = + remoteObjectNameRegister.uniqueNames("Duplicated object"); + + QCOMPARE(uniqueNames.count(), 4); + QVERIFY(uniqueNames.contains("The object name 50/Duplicated object")); + QVERIFY(uniqueNames.contains("Duplicated grandparent/Duplicated parent/" + "Duplicated object")); + QVERIFY(uniqueNames.contains("The object name 7/Duplicated object")); + QVERIFY(uniqueNames.contains("The object name 8/Duplicated object")); +} + +void RemoteObjectNameRegisterTest::testUniqueNamesWithSingleRemoteObject() { + TargetApplication::self()->setTargetApplicationFilePath(mPath); + TargetApplication::self()->start(); + + //Give the target application time to start + QTest::qWait(1000); + + RemoteObjectNameRegister remoteObjectNameRegister; + + QStringList uniqueNames = + remoteObjectNameRegister.uniqueNames("The object name 423"); + + QCOMPARE(uniqueNames.count(), 1); + QVERIFY(uniqueNames.contains("The object name 423")); +} + /////////////////////////////////// Helpers //////////////////////////////////// void RemoteObjectNameRegisterTest::assertNames(const QStringList& names) const { Modified: trunk/ktutorial/ktutorial-editor/tests/unit/view/RemoteObjectNameWidgetTest.cpp =================================================================== --- trunk/ktutorial/ktutorial-editor/tests/unit/view/RemoteObjectNameWidgetTest.cpp 2011-04-05 02:11:06 UTC (rev 296) +++ trunk/ktutorial/ktutorial-editor/tests/unit/view/RemoteObjectNameWidgetTest.cpp 2011-04-08 15:14:19 UTC (rev 297) @@ -17,6 +17,7 @@ ***************************************************************************/ #include <QtTest> +#include <QtTest/QTestKeyClicksEvent> #define protected public #define private public @@ -26,6 +27,7 @@ #include <QtDBus/QtDBus> +#include <KCompletionBox> #include <KLineEdit> #include <KProcess> @@ -56,6 +58,8 @@ void testSetChosenRemoteObject(); void testSetChosenRemoteObjectWithNameNotUnique(); + void testDuplicatedNameCompletion(); + void testTargetApplicationStartedAfterWidget(); void testTargetApplicationStopped(); @@ -238,6 +242,34 @@ assertRemoteObjectSignal(remoteObjectChosenSpy, 2, remoteObject); } +void RemoteObjectNameWidgetTest::testDuplicatedNameCompletion() { + TargetApplication::self()->setTargetApplicationFilePath(mPath); + TargetApplication::self()->start(); + + //Give the target application time to start + QTest::qWait(1000); + + RemoteObjectNameWidget widget; + KLineEdit* lineEdit = objectNameLineEdit(&widget); + lineEdit->setText("Duplicated "); + + QTest::keyClick(lineEdit, Qt::Key_O, Qt::NoModifier, 500); + + KCompletionBox* completionBox = lineEdit->completionBox(); + QStringList completionItems = completionBox->items(); + + QCOMPARE(completionItems.count(), 4); + QCOMPARE(completionItems[0], + QString("Duplicated grandparent/Duplicated parent/" + "Duplicated object")); + QCOMPARE(completionItems[1], + QString("The object name 50/Duplicated object")); + QCOMPARE(completionItems[2], + QString("The object name 7/Duplicated object")); + QCOMPARE(completionItems[3], + QString("The object name 8/Duplicated object")); +} + void RemoteObjectNameWidgetTest::testTargetApplicationStartedAfterWidget() { RemoteObjectNameWidget widget; QSignalSpy remoteObjectChosenSpy(&widget, This was sent by the SourceForge.net collaborative development platform, the world's largest Open Source development site. |
From: <dan...@us...> - 2011-04-05 02:11:14
|
Revision: 296 http://ktutorial.svn.sourceforge.net/ktutorial/?rev=296&view=rev Author: danxuliu Date: 2011-04-05 02:11:06 +0000 (Tue, 05 Apr 2011) Log Message: ----------- Add support for object paths instead of just object names in RemoteObjectNameWidget. Now, when choosing an object, the ancestor names are included if necessary to differentiate between several remote objects with the same name. Modified Paths: -------------- trunk/ktutorial/ktutorial-editor/src/view/CMakeLists.txt trunk/ktutorial/ktutorial-editor/src/view/RemoteObjectNameWidget.cpp trunk/ktutorial/ktutorial-editor/src/view/RemoteObjectNameWidget.h trunk/ktutorial/ktutorial-editor/tests/unit/view/CMakeLists.txt trunk/ktutorial/ktutorial-editor/tests/unit/view/RemoteObjectNameWidgetTest.cpp Added Paths: ----------- trunk/ktutorial/ktutorial-editor/src/view/RemoteObjectNameRegister.cpp trunk/ktutorial/ktutorial-editor/src/view/RemoteObjectNameRegister.h trunk/ktutorial/ktutorial-editor/tests/unit/view/RemoteObjectNameRegisterTest.cpp Modified: trunk/ktutorial/ktutorial-editor/src/view/CMakeLists.txt =================================================================== --- trunk/ktutorial/ktutorial-editor/src/view/CMakeLists.txt 2011-04-05 02:00:36 UTC (rev 295) +++ trunk/ktutorial/ktutorial-editor/src/view/CMakeLists.txt 2011-04-05 02:11:06 UTC (rev 296) @@ -38,6 +38,7 @@ ${ktutorial_editor_view_SRCS} RemoteObjectChooser.cpp RemoteObjectChooserFilterModel.cpp + RemoteObjectNameRegister.cpp RemoteObjectNameWidget.cpp RemoteObjectTreeItem.cpp RemoteObjectTreeItemUpdater.cpp Added: trunk/ktutorial/ktutorial-editor/src/view/RemoteObjectNameRegister.cpp =================================================================== --- trunk/ktutorial/ktutorial-editor/src/view/RemoteObjectNameRegister.cpp (rev 0) +++ trunk/ktutorial/ktutorial-editor/src/view/RemoteObjectNameRegister.cpp 2011-04-05 02:11:06 UTC (rev 296) @@ -0,0 +1,322 @@ +/*************************************************************************** + * Copyright (C) 2011 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 "RemoteObjectNameRegister.h" + +#include <KDebug> + +#include "../targetapplication/RemoteEditorSupport.h" +#include "../targetapplication/RemoteEventSpy.h" +#include "../targetapplication/RemoteObject.h" +#include "../targetapplication/TargetApplication.h" + +//public: + +RemoteObjectNameRegister::RemoteObjectNameRegister(QObject* parent /*= 0*/): + QObject(parent) { + if (TargetApplication::self()->remoteEditorSupport()) { + registerRemoteObjects(); + } + + connect(TargetApplication::self(), SIGNAL(started()), + this, SLOT(registerRemoteObjects())); + connect(TargetApplication::self(), SIGNAL(finished()), + this, SLOT(deregisterRemoteObjects())); +} + +RemoteObjectNameRegister::~RemoteObjectNameRegister() { + if (TargetApplication::self()->remoteEditorSupport()) { + TargetApplication::self()->remoteEditorSupport()->disableEventSpy(); + } +} + +QStringList RemoteObjectNameRegister::names() const { + return mRemoteObjectForName.keys(); +} + +QString RemoteObjectNameRegister::uniqueName(RemoteObject* remoteObject) const +throw (DBusException) { + QString name = remoteObject->name(); + if (name.isEmpty()) { + return ""; + } + + QList<QStringList> reversedPathsToHomonyms = + reversedPathsToHomonymsOf(remoteObject); + if (reversedPathsToHomonyms.count() == 0) { + return name; + } + + QStringList reversedFullPath = reversedPathTo(remoteObject); + + for (int i=1; i<reversedFullPath.size(); ++i) { + if (ancestorNotInPaths(reversedFullPath[i], reversedPathsToHomonyms)) { + return reversedFullPath[i] + "/" + reversedFullPath[0]; + } + } + + QStringList reversedUniquePath; + reversedUniquePath.append(reversedFullPath[0]); + + for (int i=1; i<reversedFullPath.size(); ++i) { + reversedUniquePath.append(reversedFullPath[i]); + + if (isUniquePath(reversedUniquePath, reversedPathsToHomonyms)) { + return reversedPathAsName(reversedUniquePath); + } + } + + return reversedPathAsName(reversedUniquePath); +} + +RemoteObject* RemoteObjectNameRegister::findRemoteObject(const QString& name) + const { + return findRemoteObject(name, 0); +} + +//private: + +void RemoteObjectNameRegister::registerRemoteObject(RemoteObject* remoteObject, + RemoteObject* parent) +throw (DBusException) { + Q_ASSERT(remoteObject); + + mRemoteObjectForParent.insert(parent, remoteObject); + + QString name = remoteObject->name(); + if (!name.isEmpty()) { + emit nameAdded(name); + + mRemoteObjectForName.insert(name, remoteObject); + } + + foreach (RemoteObject* child, remoteObject->children()) { + registerRemoteObject(child, remoteObject); + } +} + +void RemoteObjectNameRegister::deregisterRemoteObject( + RemoteObject* remoteObject, + RemoteObject* parent) +throw (DBusException) { + Q_ASSERT(remoteObject); + + //The remote object is no longer accessible, so name() can't be called + QString name = mRemoteObjectForName.key(remoteObject); + + emit nameRemoved(name); + + mRemoteObjectForName.remove(name, remoteObject); + mRemoteObjectForParent.remove(parent, remoteObject); + + foreach (RemoteObject* child, remoteObject->children()) { + deregisterRemoteObject(child, remoteObject); + } +} + +QStringList RemoteObjectNameRegister::reversedPathTo( + RemoteObject* remoteObject) const +throw (DBusException) { + QStringList reversedPath; + + RemoteObject* parent = remoteObject; + while (parent) { + QString name = parent->name(); + if (!name.isEmpty() && !name.startsWith("qt_")) { + reversedPath.append(name); + } + parent = mRemoteObjectForParent.key(parent); + } + + return reversedPath; +} + +QList<QStringList> RemoteObjectNameRegister::reversedPathsToHomonymsOf( + RemoteObject* remoteObject) const +throw (DBusException) { + QList<QStringList> reversedPaths; + + QList<RemoteObject*> homonymRemoteObjects = + mRemoteObjectForName.values(remoteObject->name()); + homonymRemoteObjects.removeOne(remoteObject); + + foreach (RemoteObject* homonymRemoteObject, homonymRemoteObjects) { + reversedPaths.append(reversedPathTo(homonymRemoteObject)); + } + + return reversedPaths; +} + +bool RemoteObjectNameRegister::ancestorNotInPaths(const QString& ancestor, + const QList<QStringList>& reversedPaths) const { + foreach (const QStringList& reversedPath, reversedPaths) { + if (reversedPath.contains(ancestor)) { + return false; + } + } + + return true; +} + +bool RemoteObjectNameRegister::isUniquePath( + const QStringList& reversedPathToCheck, + const QList<QStringList>& reversedPaths) const { + for (int i=0; i<reversedPaths.size(); ++i) { + if (!isUniquePath(reversedPathToCheck, reversedPaths[i])) { + return false; + } + } + + return true; +} + +bool RemoteObjectNameRegister::isUniquePath( + const QStringList& reversedPathToCheck, + const QStringList& reversedPath) const { + int commonAncestorIndex = -1; + for (int i=reversedPathToCheck.size()-1; i>0; --i) { + commonAncestorIndex = reversedPath.lastIndexOf(reversedPathToCheck[i], + commonAncestorIndex); + if (commonAncestorIndex == -1) { + return true; + } + } + + return false; +} + +QString RemoteObjectNameRegister::reversedPathAsName( + const QStringList& reversedPath) const { + QString name = reversedPath[0]; + for (int i=1; i<reversedPath.size(); ++i) { + name = reversedPath[i] + '/' + name; + } + + return name; +} + +RemoteObject* RemoteObjectNameRegister::findRemoteObject(const QString& name, + RemoteObject* ancestor) const { + if (name.indexOf('/') == -1) { + QList<RemoteObject*> remoteObjects = mRemoteObjectForName.values(name); + foreach (RemoteObject* remoteObject, remoteObjects) { + if (isDescendantOf(remoteObject, ancestor)) { + return remoteObject; + } + } + + return 0; + } + + QRegExp slashPattern("/+"); + QString ancestorName = name.left(name.indexOf(slashPattern)); + QString descendantName = name.mid(ancestorName.length() + + slashPattern.matchedLength()); + + QList<RemoteObject*> namedAncestors = + mRemoteObjectForName.values(ancestorName); + + foreach (RemoteObject* namedAncestor, namedAncestors) { + if (isDescendantOf(namedAncestor, ancestor)) { + RemoteObject* remoteObject = findRemoteObject(descendantName, + namedAncestor); + if (remoteObject) { + return remoteObject; + } + } + } + + return 0; +} + +bool RemoteObjectNameRegister::isDescendantOf(RemoteObject* remoteObject, + RemoteObject* ancestor) const { + if (!ancestor) { + return true; + } + + QList<RemoteObject*> children = mRemoteObjectForParent.values(ancestor); + foreach (RemoteObject* child, children) { + if (child == remoteObject || isDescendantOf(remoteObject, child)) { + return true; + } + } + + return false; +} + +//private slots: + +void RemoteObjectNameRegister::registerRemoteObjects() { + try { + registerRemoteObject(TargetApplication::self()-> + remoteEditorSupport()->mainWindow(), 0); + } catch (DBusException e) { + kWarning() << "The remote objects could not be registered to provide " + << "name completion (" << e.message() << ")."; + } + + try { + RemoteEventSpy* remoteEventSpy = + TargetApplication::self()->remoteEditorSupport()->enableEventSpy(); + connect(remoteEventSpy, SIGNAL(eventReceived(RemoteObject*,QString)), + this, SLOT(updateRemoteObjects(RemoteObject*,QString))); + } catch (DBusException e) { + kWarning() << "The remote event spy could not be connected to provide " + << "name completion updates (" << e.message() << ")."; + } +} + +void RemoteObjectNameRegister::deregisterRemoteObjects() { + mRemoteObjectForName.clear(); + mRemoteObjectForParent.clear(); +} + +void RemoteObjectNameRegister::updateRemoteObjects(RemoteObject* remoteObject, + const QString& eventType) { + if (eventType != "ChildAdded" && eventType != "ChildRemoved") { + return; + } + + try { + QList<RemoteObject*> children = remoteObject->children(); + + QList<RemoteObject*> knownChildren = + mRemoteObjectForParent.values(remoteObject); + + if (eventType == "ChildAdded") { + foreach (RemoteObject* child, children) { + if (!knownChildren.contains(child)) { + registerRemoteObject(child, remoteObject); + } + } + } + + if (eventType == "ChildRemoved") { + foreach (RemoteObject* child, knownChildren) { + if (!children.contains(child)) { + deregisterRemoteObject(child, remoteObject); + } + } + } + } catch (DBusException e) { + kWarning() << "There was a problem querying the remote objects, the " + << "name completion could not be updated (" + << e.message() << ")."; + } +} Property changes on: trunk/ktutorial/ktutorial-editor/src/view/RemoteObjectNameRegister.cpp ___________________________________________________________________ Added: svn:eol-style + native Added: trunk/ktutorial/ktutorial-editor/src/view/RemoteObjectNameRegister.h =================================================================== --- trunk/ktutorial/ktutorial-editor/src/view/RemoteObjectNameRegister.h (rev 0) +++ trunk/ktutorial/ktutorial-editor/src/view/RemoteObjectNameRegister.h 2011-04-05 02:11:06 UTC (rev 296) @@ -0,0 +1,302 @@ +/*************************************************************************** + * Copyright (C) 2011 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 REMOTEOBJECTNAMEREGISTER_H +#define REMOTEOBJECTNAMEREGISTER_H + +#include <QMultiHash> +#include <QObject> + +#include "../targetapplication/DBusException.h" + +class RemoteObject; + +/** + * Provides information related to the names of the remote objects in the target + * application. + * RemoteObjectNameRegister can be used to know the names of all the remote + * objects accesible by KTutorial in the target application, and it also + * notifies the names of the remote objects added or removed in the target + * application through the signals nameAdded(QString) and nameRemoved(QString). + * + * However, sometimes two or more remote objects may have the same name. In that + * case, the names of one or more ancestors are required to differentiate + * between those remote objects. The compound name that identifies a remote + * object can be got using uniqueName(RemoteObject*). Also, given a name, the + * remote object that it represents can be got using findObject(QString). + * + * Note that a name and the remote object it represents depends on the state of + * the target application. For example, if there is a dialog named + * "Configuration dialog" with a button named "Ok button", its unique name could + * be just "Ok button". However, if another dialog named "File information + * dialog" were opened while the "Configuration dialog" was still opened, and + * "File information dialog" had a also button called "Ok button", now the + * unique name of the first button would be "Configuration dialog/Ok button". In + * this situation, "Ok button" would not represent a specific remote object. + */ +class RemoteObjectNameRegister: public QObject { +Q_OBJECT +public: + + /** + * Creates a new RemoteObjectNameRegister. + * + * @param parent The parent QObject. + */ + explicit RemoteObjectNameRegister(QObject* parent = 0); + + /** + * Destroys this RemoteObjectNameRegister. + * If necessary, disables the EventSpy used to update the remote object + * names. + */ + virtual ~RemoteObjectNameRegister(); + + /** + * Returns a list with all the names. + * + * @return A list with all the names. + */ + QStringList names() const; + + /** + * Returns a unique name for the given remote object. + * When the remote object name is unique by itself, its name is returned. + * When there are other remote objects with the same name as the given one, + * but it has an ancestor with a unique name, the returned name includes + * both names. The ancestor with a unique name used is the nearest one to + * the remote object (parent preferred to grandparent, grandparent preferred + * to great-grandparent and so on). + * When there are other remote objects with the same name as the given one, + * and no ancestor has a unique name, the returned name includes as many + * ancestor names as necessary to create a name unique to the given remote + * object. + * + * @param remoteObject The remote object to get its unique name. + * @return A unique name for the given remote object. + * @throws DBusException If a DBus error happens. + */ + QString uniqueName(RemoteObject* remoteObject) const throw (DBusException); + + /** + * Returns the remote object with the given name, if any. + * When the name of the desired remote object is not unique the name of some + * ancestor must be included. Ancestor names are separated using a "/". That + * is, "Ancestor name/The remote object with a repeated name". As many + * ancestor names as desired can be included, not just one. + * The name of the ancestors does not need to be unique either; what has to + * be unique is the full path to the remote object to find. For example, + * "Ancestor name not unique/The remote object to find" is valid if, among + * all the remote objects called "Ancestor name not unique", there is only + * one that has a descendant called "The remote object to find". + * + * @param name The name of the remote object to find. + * @return The remote object with the specified name, or a null pointer if + * there is none. + */ + RemoteObject* findRemoteObject(const QString& name) const; + +Q_SIGNALS: + + /** + * Emitted when the name of a remote object is added to the register. + * + * @param name The name added. + */ + void nameAdded(const QString& name); + + /** + * Emitted when the name of a remote object is removed from the register. + * + * @param name The name removed. + */ + void nameRemoved(const QString& name); + +private: + + /** + * The RemoteObjects with a name indexed by their name. + */ + QMultiHash<QString, RemoteObject*> mRemoteObjectForName; + + /** + * The known RemoteObjects (with and without name) indexed by their parent. + */ + QMultiHash<RemoteObject*, RemoteObject*> mRemoteObjectForParent; + + /** + * Registers the given RemoteObject and all its children. + * The objects are only registered if they have a name. + * + * @param remoteObject The RemoteObject to register. + * @param parent The parent of the RemoteObject to register. + * @throws DBusException If a DBus error happens. + */ + void registerRemoteObject(RemoteObject* remoteObject, RemoteObject* parent) + throw (DBusException); + + /** + * Deregisters the given RemoteObject and all its children. + * + * @param remoteObject The RemoteObject to deregister. + * @param parent The parent of the RemoteObject to deregister. + * @throws DBusException If a DBus error happens. + */ + void deregisterRemoteObject(RemoteObject* remoteObject, + RemoteObject* parent) + throw (DBusException); + + /** + * Returns the reversed path to the given remote object. + * The path contains the name of the remote object itself and all its named + * ancestors. The order of the items is reversed from the natural path, that + * is, the first item in the returned path is the remote object name, the + * second item is the name of its parent, the third is the name of its + * grandparent... + * Empty names and Qt default names (like "qt_scrollarea_viewport") are not + * included in the path. + * + * @param remoteObject The remote object to get its path. + * @return The reversed path to the given remote object. + * @throws DBusException If a DBus error happens. + */ + QStringList reversedPathTo(RemoteObject* remoteObject) const + throw (DBusException); + + /** + * Returns the reversed paths to the remote objects with the same name as + * the given one. + * + * @param remoteObject The remote object to get the paths to its homonyms. + * @return The reversed paths to the homonyms of the given remote object. + * @throws DBusException If a DBus error happens. + * @see reversedPathTo(RemoteObject*) + */ + QList<QStringList> reversedPathsToHomonymsOf(RemoteObject* remoteObject) + const + throw (DBusException); + + /** + * Checks if the ancestor is unique, that is, if the paths do not contain + * the given ancestor. + * + * @param ancestor The ancestor to check. + * @param reversedPaths The list with the paths to check. + * @return True if the paths do not contain the given ancestor, false + * otherwise. + */ + bool ancestorNotInPaths(const QString& ancestor, + const QList<QStringList>& reversedPaths) const; + + /** + * Checks if the path represents a remote object that is unique regarding + * the reference paths. + * + * @param reversedPathToCheck The path to check. + * @param reversedPaths The other paths to check against. + * @return True if the path is unique, false otherwise. + * @see isUniquePath(const QStringList&, const QStringList&) + */ + bool isUniquePath(const QStringList& reversedPathToCheck, + const QList<QStringList>& reversedPaths) const; + + /** + * Checks if the path represents a remote object that is unique regarding + * the reference path. + * Note that the argument order matters. The path to check can be unique + * regarding the reference path and, at the same time, the reference path + * can be used to find the same remote object as the path to check. Take, + * for example, "Common ancestor/Another ancestor/Duplicated object name" as + * the path to check and "Common ancestor/Duplicated object name" as the + * reference path. The reference path may represent a remote object named + * "Duplicated object name" that is child of the remote object named + * "Common ancestor", but when using that path to find the object it + * represents it would represent both that object and the one represented by + * the path to check (as ANY remote object named "Duplicated object name" + * that is descendant of the remote object named "Common ancestor" would + * match). The path to check, on the other hand, would represent only its + * own object thanks to its extra ancestor. + * + * @param reversedPathToCheck The path to check. + * @param reversedPath The reference path to check against. + * @return True if the path is unique, false otherwise. + */ + bool isUniquePath(const QStringList& reversedPathToCheck, + const QStringList& reversedPath) const; + + /** + * Returns the name equivalent to the given reversed path. + * The name contains all the items in the path separated by "/". The order + * of the items in the name is their natural order, that is, the last item + * is the first one, the penultimate is the second one... + * + * @param path The reversed path to get its equivalent name. + * @return The name equivalent to the given reversed path. + */ + QString reversedPathAsName(const QStringList& reversedPath) const; + + /** + * Returns the remote object with the given name, if any. + * The name can contain also the ancestor names, separated by "/". The + * first object that matches the whole path is returned (note that ancestor + * are not necessarily direct parents). + * + * @param name The name of the remote object to find. + * @param ancestor The ancestor to look the remote object in. + * @return The remote object with the specified name, or a null pointer if + * there is none. + */ + RemoteObject* findRemoteObject(const QString& name, RemoteObject* ancestor) + const; + + /** + * Returns true if remoteObject is descendant of ancestor, false otherwise. + * When ancestor is null, it always returns true. + * + * @param remoteObject The remote object to check. + * @param ancestor The ancestor to check. + * @return True if remoteObject is descendant of ancestor, false otherwise. + */ + bool isDescendantOf(RemoteObject* remoteObject, + RemoteObject* ancestor) const; + +private Q_SLOTS: + + /** + * Registers all the remote objects. + */ + void registerRemoteObjects(); + + /** + * Deregisters all the remote objects. + */ + void deregisterRemoteObjects(); + + /** + * Updates the registered remote objects if they received a ChildAdded or + * ChildRemoved event. + * + * @param remoteObject The RemoteObject that received the event. + * @param eventType The type of the event received. + */ + void updateRemoteObjects(RemoteObject* remoteObject, + const QString& eventType); + +}; + +#endif Property changes on: trunk/ktutorial/ktutorial-editor/src/view/RemoteObjectNameRegister.h ___________________________________________________________________ Added: svn:eol-style + native Modified: trunk/ktutorial/ktutorial-editor/src/view/RemoteObjectNameWidget.cpp =================================================================== --- trunk/ktutorial/ktutorial-editor/src/view/RemoteObjectNameWidget.cpp 2011-04-05 02:00:36 UTC (rev 295) +++ trunk/ktutorial/ktutorial-editor/src/view/RemoteObjectNameWidget.cpp 2011-04-05 02:11:06 UTC (rev 296) @@ -19,13 +19,10 @@ #include "RemoteObjectNameWidget.h" #include "ui_RemoteObjectNameWidget.h" -#include <KDebug> #include <KMessageBox> #include "RemoteObjectChooser.h" -#include "../targetapplication/RemoteEditorSupport.h" -#include "../targetapplication/RemoteEventSpy.h" -#include "../targetapplication/RemoteObject.h" +#include "RemoteObjectNameRegister.h" #include "../targetapplication/TargetApplication.h" //public: @@ -33,31 +30,33 @@ RemoteObjectNameWidget::RemoteObjectNameWidget(QWidget* parent): QWidget(parent) { + mRemoteObjectNameRegister = new RemoteObjectNameRegister(this); + ui = new Ui::RemoteObjectNameWidget(); ui->setupUi(this); - ui->objectNameLineEdit->completionObject()->setOrder(KCompletion::Sorted); connect(ui->objectNameLineEdit, SIGNAL(textChanged(QString)), this, SLOT(handleNameChanged(QString))); connect(ui->objectNamePushButton, SIGNAL(clicked(bool)), this, SLOT(showRemoteObjectChooser())); - if (TargetApplication::self()->remoteEditorSupport()) { - registerRemoteObjects(); + KCompletion* completion = ui->objectNameLineEdit->completionObject(); + completion->setOrder(KCompletion::Sorted); + + foreach (const QString& name, mRemoteObjectNameRegister->names()) { + completion->addItem(name); } - connect(TargetApplication::self(), SIGNAL(started()), - this, SLOT(registerRemoteObjects())); + connect(mRemoteObjectNameRegister, SIGNAL(nameAdded(QString)), + completion, SLOT(addItem(QString))); + connect(mRemoteObjectNameRegister, SIGNAL(nameRemoved(QString)), + completion, SLOT(removeItem(QString))); connect(TargetApplication::self(), SIGNAL(finished()), - this, SLOT(deregisterRemoteObjects())); + completion, SLOT(clear())); } RemoteObjectNameWidget::~RemoteObjectNameWidget() { - if (TargetApplication::self()->remoteEditorSupport()) { - TargetApplication::self()->remoteEditorSupport()->disableEventSpy(); - } - delete ui; } @@ -69,46 +68,6 @@ ui->objectNameLineEdit->setText(name); } -//private: - -void RemoteObjectNameWidget::registerRemoteObject(RemoteObject* remoteObject, - RemoteObject* parent) -throw (DBusException) { - Q_ASSERT(remoteObject); - - mRemoteObjectForParent.insert(parent, remoteObject); - - if (!remoteObject->name().isEmpty()) { - KCompletion* completion = ui->objectNameLineEdit->completionObject(); - completion->addItem(remoteObject->name()); - - mRemoteObjectForName.insert(remoteObject->name(), remoteObject); - } - - foreach (RemoteObject* child, remoteObject->children()) { - registerRemoteObject(child, remoteObject); - } -} - -void RemoteObjectNameWidget::deregisterRemoteObject(RemoteObject* remoteObject, - RemoteObject* parent) -throw (DBusException) { - Q_ASSERT(remoteObject); - - //The remote object is no longer accessible, so name() can't be called - QString name = mRemoteObjectForName.key(remoteObject); - - KCompletion* completion = ui->objectNameLineEdit->completionObject(); - completion->removeItem(name); - - mRemoteObjectForName.remove(name); - mRemoteObjectForParent.remove(parent, remoteObject); - - foreach (RemoteObject* child, remoteObject->children()) { - deregisterRemoteObject(child, remoteObject); - } -} - //private slots: void RemoteObjectNameWidget::showRemoteObjectChooser() { @@ -121,7 +80,8 @@ void RemoteObjectNameWidget::setChosenRemoteObject(RemoteObject* remoteObject) { try { - ui->objectNameLineEdit->setText(remoteObject->name()); + ui->objectNameLineEdit->setText( + mRemoteObjectNameRegister->uniqueName(remoteObject)); } catch (DBusException e) { QString text = i18nc("@label", "The object name can not be set, there " "was a problem getting the name from the target application: %1", e.message()); @@ -131,66 +91,6 @@ } } -void RemoteObjectNameWidget::registerRemoteObjects() { - try { - registerRemoteObject(TargetApplication::self()-> - remoteEditorSupport()->mainWindow(), 0); - } catch (DBusException e) { - kWarning() << "The remote objects could not be registered to provide " - << "name completion (" << e.message() << ")."; - } - - try { - RemoteEventSpy* remoteEventSpy = - TargetApplication::self()->remoteEditorSupport()->enableEventSpy(); - connect(remoteEventSpy, SIGNAL(eventReceived(RemoteObject*,QString)), - this, SLOT(updateRemoteObjects(RemoteObject*,QString))); - } catch (DBusException e) { - kWarning() << "The remote event spy could not be connected to provide " - << "name completion updates (" << e.message() << ")."; - } -} - -void RemoteObjectNameWidget::deregisterRemoteObjects() { - ui->objectNameLineEdit->completionObject()->clear(); - mRemoteObjectForName.clear(); - mRemoteObjectForParent.clear(); -} - -void RemoteObjectNameWidget::updateRemoteObjects(RemoteObject* remoteObject, - const QString& eventType) { - if (eventType != "ChildAdded" && eventType != "ChildRemoved") { - return; - } - - try { - QList<RemoteObject*> children = remoteObject->children(); - - QList<RemoteObject*> knownChildren = - mRemoteObjectForParent.values(remoteObject); - - if (eventType == "ChildAdded") { - foreach (RemoteObject* child, children) { - if (!knownChildren.contains(child)) { - registerRemoteObject(child, remoteObject); - } - } - } - - if (eventType == "ChildRemoved") { - foreach (RemoteObject* child, knownChildren) { - if (!children.contains(child)) { - deregisterRemoteObject(child, remoteObject); - } - } - } - } catch (DBusException e) { - kWarning() << "There was a problem querying the remote objects, the " - << "name completion could not be updated (" - << e.message() << ")."; - } -} - void RemoteObjectNameWidget::handleNameChanged(const QString& name) { - emit remoteObjectChosen(mRemoteObjectForName.value(name)); + emit remoteObjectChosen(mRemoteObjectNameRegister->findRemoteObject(name)); } Modified: trunk/ktutorial/ktutorial-editor/src/view/RemoteObjectNameWidget.h =================================================================== --- trunk/ktutorial/ktutorial-editor/src/view/RemoteObjectNameWidget.h 2011-04-05 02:00:36 UTC (rev 295) +++ trunk/ktutorial/ktutorial-editor/src/view/RemoteObjectNameWidget.h 2011-04-05 02:11:06 UTC (rev 296) @@ -19,12 +19,10 @@ #ifndef REMOTEOBJECTNAMEWIDGET_H #define REMOTEOBJECTNAMEWIDGET_H -#include <QHash> #include <QWidget> -#include "../targetapplication/DBusException.h" - class RemoteObject; +class RemoteObjectNameRegister; namespace Ui { class RemoteObjectNameWidget; @@ -89,43 +87,16 @@ private: /** - * The RemoteObjects with a name indexed by their name. + * The register that provides the names of the remote objects and finds them + * based on their name. */ - QHash<QString, RemoteObject*> mRemoteObjectForName; + RemoteObjectNameRegister* mRemoteObjectNameRegister; /** - * The known RemoteObjects (with and without name) indexed by their parent. - */ - QMultiHash<RemoteObject*, RemoteObject*> mRemoteObjectForParent; - - /** * The Ui Designer generated class. */ Ui::RemoteObjectNameWidget* ui; - /** - * Registers the given RemoteObject and all its children. - * The objects are only registered if they have a name. In that case, it is - * added to the completion of the name line edit. - * - * @param remoteObject The RemoteObject to register. - * @param parent The parent of the RemoteObject to register. - * @throws DBusException If a DBus error happens. - */ - void registerRemoteObject(RemoteObject* remoteObject, RemoteObject* parent) - throw (DBusException); - - /** - * Deregisters the given RemoteObject and all its children. - * - * @param remoteObject The RemoteObject to deregister. - * @param parent The parent of the RemoteObject to deregister. - * @throws DBusException If a DBus error happens. - */ - void deregisterRemoteObject(RemoteObject* remoteObject, - RemoteObject* parent) - throw (DBusException); - private Q_SLOTS: /** @@ -141,28 +112,6 @@ void setChosenRemoteObject(RemoteObject* remoteObject); /** - * Registers the remote objects and add their names to the line edit - * completion object. - */ - void registerRemoteObjects(); - - /** - * Deregisters the remote objects and removes their names from the line edit - * completion object. - */ - void deregisterRemoteObjects(); - - /** - * Updates the registered remote objects if they received a ChildAdded or - * ChildRemoved event. - * - * @param remoteObject The RemoteObject that received the event. - * @param eventType The type of the event received. - */ - void updateRemoteObjects(RemoteObject* remoteObject, - const QString& eventType); - - /** * Emits remoteObjectChosen(RemoteObject*) with the remote object with the * given name. * Modified: trunk/ktutorial/ktutorial-editor/tests/unit/view/CMakeLists.txt =================================================================== --- trunk/ktutorial/ktutorial-editor/tests/unit/view/CMakeLists.txt 2011-04-05 02:00:36 UTC (rev 295) +++ trunk/ktutorial/ktutorial-editor/tests/unit/view/CMakeLists.txt 2011-04-05 02:11:06 UTC (rev 296) @@ -55,6 +55,7 @@ unit_tests( RemoteObjectChooser RemoteObjectChooserFilterModel + RemoteObjectNameRegister RemoteObjectNameWidget RemoteObjectTreeItem RemoteObjectTreeItemUpdater Added: trunk/ktutorial/ktutorial-editor/tests/unit/view/RemoteObjectNameRegisterTest.cpp =================================================================== --- trunk/ktutorial/ktutorial-editor/tests/unit/view/RemoteObjectNameRegisterTest.cpp (rev 0) +++ trunk/ktutorial/ktutorial-editor/tests/unit/view/RemoteObjectNameRegisterTest.cpp 2011-04-05 02:11:06 UTC (rev 296) @@ -0,0 +1,380 @@ +/*************************************************************************** + * Copyright (C) 2011 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 "RemoteObjectNameRegister.h" + +#include <KProcess> + +#include "../targetapplication/RemoteEditorSupport.h" +#include "../targetapplication/RemoteObject.h" +#define protected public +#define private public +#include "../targetapplication/TargetApplication.h" +#undef private +#undef protected + +class RemoteObjectNameRegisterTest: public QObject { +Q_OBJECT + +private slots: + + void init(); + void cleanup(); + + void testConstructor(); + + void testTargetApplicationStartedAfterRegister(); + void testTargetApplicationStopped(); + + void testAddingOrRemovingRemoteObjects(); + + void testFindRemoteObject(); + void testFindRemoteObjectWithParentName(); + void testFindRemoteObjectWithGrandparentName(); + void testFindRemoteObjectWithParentAndGrandparentNames(); + void testFindRemoteObjectWithUnknownName(); + + void testUniqueName(); + void testUniqueNameWhenUniqueParent(); + void testUniqueNameWhenUniqueGrandparentAndEmptyParent(); + void testUniqueNameWhenUniqueGrandparentAndDuplicatedParent(); + void testUniqueNameWhenUniqueUnionOfGrandparentAndParent(); + void testUniqueNameWhenEmptyName(); + +private: + + QString mPath; + + void assertNames(const QStringList& names) const; + +}; + +void RemoteObjectNameRegisterTest::init() { + mPath = QApplication::applicationDirPath() + + "/../targetapplication/TargetApplicationStub"; + + //Avoid signals from previews tests to be delivered to the next ones + //setting a new TargetApplication + delete TargetApplication::sSelf; + TargetApplication::sSelf = new TargetApplication(); +} + +void RemoteObjectNameRegisterTest::cleanup() { + delete TargetApplication::sSelf; + TargetApplication::sSelf = 0; +} + +void RemoteObjectNameRegisterTest::testConstructor() { + TargetApplication::self()->setTargetApplicationFilePath(mPath); + TargetApplication::self()->start(); + + //Give the target application time to start + QTest::qWait(1000); + + RemoteObjectNameRegister remoteObjectNameRegister; + + assertNames(remoteObjectNameRegister.names()); +} + +void RemoteObjectNameRegisterTest::testTargetApplicationStartedAfterRegister() { + RemoteObjectNameRegister remoteObjectNameRegister; + QSignalSpy nameAddedSpy(&remoteObjectNameRegister, + SIGNAL(nameAdded(QString))); + QSignalSpy nameRemovedSpy(&remoteObjectNameRegister, + SIGNAL(nameRemoved(QString))); + + TargetApplication::self()->setTargetApplicationFilePath(mPath); + TargetApplication::self()->start(); + + //Give the target application time to start + QTest::qWait(1000); + + assertNames(remoteObjectNameRegister.names()); + QCOMPARE(nameAddedSpy.count(), 82); + QCOMPARE(nameAddedSpy.at(0).at(0).toString(), + QString("The object name 42")); + QCOMPARE(nameAddedSpy.at(1).at(0).toString(), + QString("The object name 420")); + QCOMPARE(nameAddedSpy.at(5).at(0).toString(), + QString("Duplicated grandparent")); + QCOMPARE(nameAddedSpy.at(6).at(0).toString(), + QString("The object name 50")); + QCOMPARE(nameAddedSpy.at(7).at(0).toString(), + QString("Duplicated object")); + QCOMPARE(nameAddedSpy.at(11).at(0).toString(), + QString("The object name 51")); + QCOMPARE(nameAddedSpy.at(26).at(0).toString(), + QString("Duplicated grandparent")); + QCOMPARE(nameAddedSpy.at(27).at(0).toString(), + QString("Duplicated parent")); + QCOMPARE(nameAddedSpy.at(28).at(0).toString(), + QString("Duplicated object")); + QCOMPARE(nameAddedSpy.at(68).at(0).toString(), + QString("The object name 8")); + QCOMPARE(nameAddedSpy.at(69).at(0).toString(), + QString("Duplicated object")); + QCOMPARE(nameAddedSpy.at(70).at(0).toString(), + QString("The object name 801")); + QCOMPARE(nameAddedSpy.at(71).at(0).toString(), + QString("The object name 803")); + QCOMPARE(nameRemovedSpy.count(), 0); +} + +void RemoteObjectNameRegisterTest::testTargetApplicationStopped() { + TargetApplication::self()->setTargetApplicationFilePath(mPath); + TargetApplication::self()->start(); + + //Give the target application time to start + QTest::qWait(1000); + + RemoteObjectNameRegister remoteObjectNameRegister; + + QSignalSpy nameAddedSpy(&remoteObjectNameRegister, + SIGNAL(nameAdded(QString))); + QSignalSpy nameRemovedSpy(&remoteObjectNameRegister, + SIGNAL(nameAdded(QString))); + + TargetApplication::self()->mProcess->kill(); + + //Give the target application time to stop + QTest::qWait(1000); + + QVERIFY(remoteObjectNameRegister.names().isEmpty()); + QCOMPARE(nameAddedSpy.count(), 0); + QCOMPARE(nameRemovedSpy.count(), 0); +} + +void RemoteObjectNameRegisterTest::testAddingOrRemovingRemoteObjects() { + QSKIP("Unfortunately, testing if the signals are emitted when an object is " + "added or removed in the target application is too burdensome so the " + "test must be done manually", SkipAll); +} + +void RemoteObjectNameRegisterTest::testFindRemoteObject() { + TargetApplication::self()->setTargetApplicationFilePath(mPath); + TargetApplication::self()->start(); + + //Give the target application time to start + QTest::qWait(1000); + + RemoteObjectNameRegister remoteObjectNameRegister; + + RemoteObject* mainWindow = + TargetApplication::self()->remoteEditorSupport()->mainWindow(); + + QCOMPARE(remoteObjectNameRegister.findRemoteObject("The object name 423"), + mainWindow->children()[3]); +} + +void RemoteObjectNameRegisterTest::testFindRemoteObjectWithParentName() { + TargetApplication::self()->setTargetApplicationFilePath(mPath); + TargetApplication::self()->start(); + + //Give the target application time to start + QTest::qWait(1000); + + RemoteObjectNameRegister remoteObjectNameRegister; + + RemoteObject* mainWindow = + TargetApplication::self()->remoteEditorSupport()->mainWindow(); + + QCOMPARE(remoteObjectNameRegister.findRemoteObject( + "The object name 50/Duplicated object"), + mainWindow->children()[4]->children()[0]->children()[0]); +} + +void RemoteObjectNameRegisterTest::testFindRemoteObjectWithGrandparentName() { + TargetApplication::self()->setTargetApplicationFilePath(mPath); + TargetApplication::self()->start(); + + //Give the target application time to start + QTest::qWait(1000); + + RemoteObjectNameRegister remoteObjectNameRegister; + + RemoteObject* mainWindow = + TargetApplication::self()->remoteEditorSupport()->mainWindow(); + + QCOMPARE(remoteObjectNameRegister.findRemoteObject( + "The object name 7/Duplicated object"), + mainWindow->children()[6]->children()[0]->children()[0]); +} + +void RemoteObjectNameRegisterTest:: + testFindRemoteObjectWithParentAndGrandparentNames() { + TargetApplication::self()->setTargetApplicationFilePath(mPath); + TargetApplication::self()->start(); + + //Give the target application time to start + QTest::qWait(1000); + + RemoteObjectNameRegister remoteObjectNameRegister; + + RemoteObject* mainWindow = + TargetApplication::self()->remoteEditorSupport()->mainWindow(); + + QCOMPARE(remoteObjectNameRegister.findRemoteObject( + "Duplicated grandparent/Duplicated parent/Duplicated object"), + mainWindow->children()[5]->children()[0]->children()[0]); +} + +void RemoteObjectNameRegisterTest::testFindRemoteObjectWithUnknownName() { + TargetApplication::self()->setTargetApplicationFilePath(mPath); + TargetApplication::self()->start(); + + //Give the target application time to start + QTest::qWait(1000); + + RemoteObjectNameRegister remoteObjectNameRegister; + + QCOMPARE(remoteObjectNameRegister.findRemoteObject("The object name 108"), + (RemoteObject*)0); +} + +void RemoteObjectNameRegisterTest::testUniqueName() { + TargetApplication::self()->setTargetApplicationFilePath(mPath); + TargetApplication::self()->start(); + + //Give the target application time to start + QTest::qWait(1000); + + RemoteObjectNameRegister remoteObjectNameRegister; + + RemoteObject* mainWindow = + TargetApplication::self()->remoteEditorSupport()->mainWindow(); + RemoteObject* remoteObject = + mainWindow->children()[4]->children()[0]->children()[1]; + + QCOMPARE(remoteObjectNameRegister.uniqueName(remoteObject), + QString("The object name 501")); +} + +void RemoteObjectNameRegisterTest::testUniqueNameWhenUniqueParent() { + TargetApplication::self()->setTargetApplicationFilePath(mPath); + TargetApplication::self()->start(); + + //Give the target application time to start + QTest::qWait(1000); + + RemoteObjectNameRegister remoteObjectNameRegister; + + RemoteObject* mainWindow = + TargetApplication::self()->remoteEditorSupport()->mainWindow(); + RemoteObject* remoteObject = + mainWindow->children()[4]->children()[0]->children()[0]; + + QCOMPARE(remoteObjectNameRegister.uniqueName(remoteObject), + QString("The object name 50/Duplicated object")); +} + +void RemoteObjectNameRegisterTest:: + testUniqueNameWhenUniqueGrandparentAndEmptyParent() { + TargetApplication::self()->setTargetApplicationFilePath(mPath); + TargetApplication::self()->start(); + + //Give the target application time to start + QTest::qWait(1000); + + RemoteObjectNameRegister remoteObjectNameRegister; + + RemoteObject* mainWindow = + TargetApplication::self()->remoteEditorSupport()->mainWindow(); + RemoteObject* remoteObject = + mainWindow->children()[7]->children()[0]->children()[0]; + + QCOMPARE(remoteObjectNameRegister.uniqueName(remoteObject), + QString("The object name 8/Duplicated object")); +} + +void RemoteObjectNameRegisterTest:: + testUniqueNameWhenUniqueGrandparentAndDuplicatedParent() { + TargetApplication::self()->setTargetApplicationFilePath(mPath); + TargetApplication::self()->start(); + + //Give the target application time to start + QTest::qWait(1000); + + RemoteObjectNameRegister remoteObjectNameRegister; + + RemoteObject* mainWindow = + TargetApplication::self()->remoteEditorSupport()->mainWindow(); + RemoteObject* remoteObject = + mainWindow->children()[6]->children()[0]->children()[0]; + + QCOMPARE(remoteObjectNameRegister.uniqueName(remoteObject), + QString("The object name 7/Duplicated object")); +} + +void RemoteObjectNameRegisterTest:: + testUniqueNameWhenUniqueUnionOfGrandparentAndParent() { + TargetApplication::self()->setTargetApplicationFilePath(mPath); + TargetApplication::self()->start(); + + //Give the target application time to start + QTest::qWait(1000); + + RemoteObjectNameRegister remoteObjectNameRegister; + + RemoteObject* mainWindow = + TargetApplication::self()->remoteEditorSupport()->mainWindow(); + RemoteObject* remoteObject = + mainWindow->children()[5]->children()[0]->children()[0]; + + QCOMPARE(remoteObjectNameRegister.uniqueName(remoteObject), + QString("Duplicated grandparent/Duplicated parent/" + "Duplicated object")); +} + +void RemoteObjectNameRegisterTest::testUniqueNameWhenEmptyName() { + TargetApplication::self()->setTargetApplicationFilePath(mPath); + TargetApplication::self()->start(); + + //Give the target application time to start + QTest::qWait(1000); + + RemoteObjectNameRegister remoteObjectNameRegister; + + RemoteObject* mainWindow = + TargetApplication::self()->remoteEditorSupport()->mainWindow(); + RemoteObject* remoteObject = mainWindow->children()[7]->children()[0]; + + QCOMPARE(remoteObjectNameRegister.uniqueName(remoteObject), QString("")); +} + +/////////////////////////////////// Helpers //////////////////////////////////// + +void RemoteObjectNameRegisterTest::assertNames(const QStringList& names) const { + QCOMPARE(names.count(), 82); + QVERIFY(names.contains("The object name 42")); + QVERIFY(names.contains("The object name 420")); + QVERIFY(names.contains("The object name 421")); + QVERIFY(names.contains("The object name 422")); + QVERIFY(names.contains("The object name 423")); + QVERIFY(names.contains("The object name 7")); + QVERIFY(names.contains("The object name 62")); + QVERIFY(names.contains("The object name 833")); + QVERIFY(names.contains("Duplicated object")); + QVERIFY(names.contains("Duplicated parent")); + QVERIFY(names.contains("Duplicated grandparent")); +} + +QTEST_MAIN(RemoteObjectNameRegisterTest) + +#include "RemoteObjectNameRegisterTest.moc" Property changes on: trunk/ktutorial/ktutorial-editor/tests/unit/view/RemoteObjectNameRegisterTest.cpp ___________________________________________________________________ Added: svn:eol-style + native Modified: trunk/ktutorial/ktutorial-editor/tests/unit/view/RemoteObjectNameWidgetTest.cpp =================================================================== --- trunk/ktutorial/ktutorial-editor/tests/unit/view/RemoteObjectNameWidgetTest.cpp 2011-04-05 02:00:36 UTC (rev 295) +++ trunk/ktutorial/ktutorial-editor/tests/unit/view/RemoteObjectNameWidgetTest.cpp 2011-04-05 02:11:06 UTC (rev 296) @@ -18,7 +18,11 @@ #include <QtTest> +#define protected public +#define private public #include "RemoteObjectNameWidget.h" +#undef private +#undef protected #include <QtDBus/QtDBus> @@ -46,8 +50,12 @@ void testConstructor(); void testSetName(); + void testSetNameWithPath(); void testSetNameWithUnknownRemoteObjectName(); + void testSetChosenRemoteObject(); + void testSetChosenRemoteObjectWithNameNotUnique(); + void testTargetApplicationStartedAfterWidget(); void testTargetApplicationStopped(); @@ -129,6 +137,28 @@ mainWindow->children()[3]); } +void RemoteObjectNameWidgetTest::testSetNameWithPath() { + TargetApplication::self()->setTargetApplicationFilePath(mPath); + TargetApplication::self()->start(); + + //Give the target application time to start + QTest::qWait(1000); + + RemoteObjectNameWidget widget; + QSignalSpy remoteObjectChosenSpy(&widget, + SIGNAL(remoteObjectChosen(RemoteObject*))); + + widget.setName("The object name 7/Duplicated object"); + + RemoteObject* mainWindow = + TargetApplication::self()->remoteEditorSupport()->mainWindow(); + + QCOMPARE(widget.name(), QString("The object name 7/Duplicated object")); + QCOMPARE(remoteObjectChosenSpy.count(), 1); + assertRemoteObjectSignal(remoteObjectChosenSpy, 0, + mainWindow->children()[6]->children()[0]->children()[0]); +} + void RemoteObjectNameWidgetTest::testSetNameWithUnknownRemoteObjectName() { TargetApplication::self()->setTargetApplicationFilePath(mPath); TargetApplication::self()->start(); @@ -147,6 +177,67 @@ assertRemoteObjectSignal(remoteObjectChosenSpy, 0, 0); } +void RemoteObjectNameWidgetTest::testSetChosenRemoteObject() { + TargetApplication::self()->setTargetApplicationFilePath(mPath); + TargetApplication::self()->start(); + + //Give the target application time to start + QTest::qWait(1000); + + RemoteObjectNameWidget widget; + QSignalSpy remoteObjectChosenSpy(&widget, + SIGNAL(remoteObjectChosen(RemoteObject*))); + + RemoteObject* mainWindow = + TargetApplication::self()->remoteEditorSupport()->mainWindow(); + RemoteObject* remoteObject = + mainWindow->children()[4]->children()[0]->children()[1]; + + widget.setChosenRemoteObject(remoteObject); + + QCOMPARE(widget.name(), QString("The object name 501")); + QCOMPARE(remoteObjectChosenSpy.count(), 1); + assertRemoteObjectSignal(remoteObjectChosenSpy, 0, remoteObject); +} + +void RemoteObjectNameWidgetTest::testSetChosenRemoteObjectWithNameNotUnique() { + TargetApplication::self()->setTargetApplicationFilePath(mPath); + TargetApplication::self()->start(); + + //Give the target application time to start + QTest::qWait(1000); + + RemoteObjectNameWidget widget; + QSignalSpy remoteObjectChosenSpy(&widget, + SIGNAL(remoteObjectChosen(RemoteObject*))); + + RemoteObject* mainWindow = + TargetApplication::self()->remoteEditorSupport()->mainWindow(); + + RemoteObject* remoteObject = + mainWindow->children()[4]->children()[0]->children()[0]; + widget.setChosenRemoteObject(remoteObject); + + QCOMPARE(widget.name(), QString("The object name 50/Duplicated object")); + QCOMPARE(remoteObjectChosenSpy.count(), 1); + assertRemoteObjectSignal(remoteObjectChosenSpy, 0, remoteObject); + + remoteObject = mainWindow->children()[5]->children()[0]->children()[0]; + widget.setChosenRemoteObject(remoteObject); + + QCOMPARE(widget.name(), QString("Duplicated grandparent/Duplicated parent/" + "Duplicated object")); + QCOMPARE(remoteObjectChosenSpy.count(), 2); + assertRemoteObjectSignal(remoteObjectChosenSpy, 1, remoteObject); + + remoteObject = mainWindow->children()[6]->children()[0]->children()[0]; + widget.setChosenRemoteObject(remoteObject); + + QCOMPARE(widget.name(), QString("The object name 7/Duplicated object")); + QCOMPARE(remoteObjectChosenSpy.count(), 3); + assertRemoteObjectSignal(remoteObjectChosenSpy, 2, remoteObject); +} + void RemoteObjectNameWidgetTest::testTargetApplicationStartedAfterWidget() { RemoteObjectNameWidget widget; QSignalSpy remoteObjectChosenSpy(&widget, This was sent by the SourceForge.net collaborative development platform, the world's largest Open Source development site. |
From: <dan...@us...> - 2011-04-05 02:00:42
|
Revision: 295 http://ktutorial.svn.sourceforge.net/ktutorial/?rev=295&view=rev Author: danxuliu Date: 2011-04-05 02:00:36 +0000 (Tue, 05 Apr 2011) Log Message: ----------- Fix typo in documentation. Modified Paths: -------------- trunk/ktutorial/ktutorial-editor/tests/unit/targetapplication/RemoteClassStubs.h Modified: trunk/ktutorial/ktutorial-editor/tests/unit/targetapplication/RemoteClassStubs.h =================================================================== --- trunk/ktutorial/ktutorial-editor/tests/unit/targetapplication/RemoteClassStubs.h 2011-03-27 16:07:21 UTC (rev 294) +++ trunk/ktutorial/ktutorial-editor/tests/unit/targetapplication/RemoteClassStubs.h 2011-04-05 02:00:36 UTC (rev 295) @@ -96,13 +96,12 @@ * | |-800: "Duplicated object" * | |-801: "The object name 801" * | |-802: "" - * | |... + * | |-803: "The object name 803" * |-81: "" (QWidgetChildChild) * | |-810: "" * | |-811: "" * | |-812: "" * | |-813: "" - * |... * |-82: "The object name 82" (ChildChildQWidget) * | |-820: "The object name 820" * | |... This was sent by the SourceForge.net collaborative development platform, the world's largest Open Source development site. |
From: <dan...@us...> - 2011-03-27 16:07:29
|
Revision: 294 http://ktutorial.svn.sourceforge.net/ktutorial/?rev=294&view=rev Author: danxuliu Date: 2011-03-27 16:07:21 +0000 (Sun, 27 Mar 2011) Log Message: ----------- -Add filters for named objects and widgets in the RemoteObjectChooser dialog. -Update RemoteObject and RemoteObjectNameWidget tests due to changes in RemoteClassStubs. Modified Paths: -------------- trunk/ktutorial/ktutorial-editor/src/view/CMakeLists.txt trunk/ktutorial/ktutorial-editor/src/view/RemoteObjectChooser.cpp trunk/ktutorial/ktutorial-editor/src/view/RemoteObjectChooser.h trunk/ktutorial/ktutorial-editor/src/view/RemoteObjectChooser.ui trunk/ktutorial/ktutorial-editor/src/view/RemoteObjectTreeSelectionManager.cpp trunk/ktutorial/ktutorial-editor/src/view/RemoteObjectTreeSelectionManager.h trunk/ktutorial/ktutorial-editor/tests/unit/targetapplication/RemoteClassStubs.h trunk/ktutorial/ktutorial-editor/tests/unit/targetapplication/RemoteObjectTest.cpp trunk/ktutorial/ktutorial-editor/tests/unit/view/CMakeLists.txt trunk/ktutorial/ktutorial-editor/tests/unit/view/RemoteObjectChooserTest.cpp trunk/ktutorial/ktutorial-editor/tests/unit/view/RemoteObjectNameWidgetTest.cpp trunk/ktutorial/ktutorial-editor/tests/unit/view/RemoteObjectTreeSelectionManagerTest.cpp Added Paths: ----------- trunk/ktutorial/ktutorial-editor/src/view/RemoteObjectChooserFilterModel.cpp trunk/ktutorial/ktutorial-editor/src/view/RemoteObjectChooserFilterModel.h trunk/ktutorial/ktutorial-editor/tests/unit/view/RemoteObjectChooserFilterModelTest.cpp Modified: trunk/ktutorial/ktutorial-editor/src/view/CMakeLists.txt =================================================================== --- trunk/ktutorial/ktutorial-editor/src/view/CMakeLists.txt 2011-03-09 16:38:59 UTC (rev 293) +++ trunk/ktutorial/ktutorial-editor/src/view/CMakeLists.txt 2011-03-27 16:07:21 UTC (rev 294) @@ -37,6 +37,7 @@ set(ktutorial_editor_view_SRCS ${ktutorial_editor_view_SRCS} RemoteObjectChooser.cpp + RemoteObjectChooserFilterModel.cpp RemoteObjectNameWidget.cpp RemoteObjectTreeItem.cpp RemoteObjectTreeItemUpdater.cpp Modified: trunk/ktutorial/ktutorial-editor/src/view/RemoteObjectChooser.cpp =================================================================== --- trunk/ktutorial/ktutorial-editor/src/view/RemoteObjectChooser.cpp 2011-03-09 16:38:59 UTC (rev 293) +++ trunk/ktutorial/ktutorial-editor/src/view/RemoteObjectChooser.cpp 2011-03-27 16:07:21 UTC (rev 294) @@ -1,5 +1,5 @@ /*************************************************************************** - * Copyright (C) 2010 by Daniel Calviño Sánchez * + * Copyright (C) 2010-2011 by Daniel Calviño Sánchez * * dan...@gm... * * * * This program is free software; you can redistribute it and/or modify * @@ -25,6 +25,7 @@ #include <KDialogButtonBox> #include <KMessageBox> +#include "RemoteObjectChooserFilterModel.h" #include "RemoteObjectTreeItem.h" #include "RemoteObjectTreeItemUpdater.h" #include "RemoteObjectTreeSelectionManager.h" @@ -165,8 +166,17 @@ RemoteObject* mainWindow = remoteEditorSupport->mainWindow(); RemoteObjectTreeItem* rootItem = new RemoteObjectTreeItem(mainWindow); TreeModel* treeModel = new TreeModel(rootItem, this); - ui->remoteObjectsTreeView->setModel(treeModel); + RemoteObjectChooserFilterModel* filterModel = + new RemoteObjectChooserFilterModel(this); + filterModel->setSourceModel(treeModel); + ui->remoteObjectsTreeView->setModel(filterModel); + + connect(ui->showOnlyNamedObjectsCheckBox, SIGNAL(toggled(bool)), + filterModel, SLOT(setNamedObjectFilterEnabled(bool))); + connect(ui->showOnlyWidgetsCheckBox, SIGNAL(toggled(bool)), + filterModel, SLOT(setWidgetFilterEnabled(bool))); + RemoteObjectTreeItemUpdater* updater = new RemoteObjectTreeItemUpdater(this); rootItem->setUpdater(updater); Modified: trunk/ktutorial/ktutorial-editor/src/view/RemoteObjectChooser.h =================================================================== --- trunk/ktutorial/ktutorial-editor/src/view/RemoteObjectChooser.h 2011-03-09 16:38:59 UTC (rev 293) +++ trunk/ktutorial/ktutorial-editor/src/view/RemoteObjectChooser.h 2011-03-27 16:07:21 UTC (rev 294) @@ -1,5 +1,5 @@ /*************************************************************************** - * Copyright (C) 2010 by Daniel Calviño Sánchez * + * Copyright (C) 2010-2011 by Daniel Calviño Sánchez * * dan...@gm... * * * * This program is free software; you can redistribute it and/or modify * @@ -45,6 +45,11 @@ * When the user selects a remote object in the list and that object represents * a widget, the widget is highlighted in the target application. * + * The list shows all the available remote objects in the target application. + * Some of them may not be useful at all (for example, those without name), so + * the user can select some filters to narrow the remote objects shown in the + * list hiding those that do not pass the filters. + * * The window contains an "Ok" and a "Cancel" button, like the ones found in * dialogs. A window is used instead of a dialog to be shown in the task bar (as * after hidding the rest of KTutorial editor windows no entry would be shown if Modified: trunk/ktutorial/ktutorial-editor/src/view/RemoteObjectChooser.ui =================================================================== --- trunk/ktutorial/ktutorial-editor/src/view/RemoteObjectChooser.ui 2011-03-09 16:38:59 UTC (rev 293) +++ trunk/ktutorial/ktutorial-editor/src/view/RemoteObjectChooser.ui 2011-03-27 16:07:21 UTC (rev 294) @@ -7,7 +7,7 @@ <x>0</x> <y>0</y> <width>400</width> - <height>300</height> + <height>400</height> </rect> </property> <property name="windowTitle"> @@ -20,6 +20,34 @@ </property> <layout class="QVBoxLayout" name="remoteObjectChooserVerticalLayout"> <item> + <widget class="QGroupBox" name="filtersGroupBox"> + <property name="whatsThis"> + <string comment="@info:whatsthis"><p>Filters the objects shown in the list.</p> + +<p>Note, however, that if an object has to be shown in the list its parent object is also shown even if it should have been filtered.</p></string> + </property> + <property name="title"> + <string comment="@title:group">Filters</string> + </property> + <layout class="QVBoxLayout" name="verticalLayout"> + <item> + <widget class="QCheckBox" name="showOnlyNamedObjectsCheckBox"> + <property name="text"> + <string comment="@option:check">Show only named objects</string> + </property> + </widget> + </item> + <item> + <widget class="QCheckBox" name="showOnlyWidgetsCheckBox"> + <property name="text"> + <string comment="@option:check">Show only widgets</string> + </property> + </widget> + </item> + </layout> + </widget> + </item> + <item> <widget class="AutoExpandableTreeView" name="remoteObjectsTreeView"/> </item> <item> Added: trunk/ktutorial/ktutorial-editor/src/view/RemoteObjectChooserFilterModel.cpp =================================================================== --- trunk/ktutorial/ktutorial-editor/src/view/RemoteObjectChooserFilterModel.cpp (rev 0) +++ trunk/ktutorial/ktutorial-editor/src/view/RemoteObjectChooserFilterModel.cpp 2011-03-27 16:07:21 UTC (rev 294) @@ -0,0 +1,120 @@ +/*************************************************************************** + * Copyright (C) 2011 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 "RemoteObjectChooserFilterModel.h" + +#include <QQueue> + +#include "RemoteObjectTreeItem.h" +#include "../targetapplication/RemoteClass.h" +#include "../targetapplication/RemoteObject.h" + +//public: + +RemoteObjectChooserFilterModel::RemoteObjectChooserFilterModel( + QObject* parent /* = 0*/): + QSortFilterProxyModel(parent), + mNamedObjectFilterEnabled(false), + mWidgetFilterEnabled(false) { +} + +//public slots: + +void RemoteObjectChooserFilterModel::setNamedObjectFilterEnabled( + bool namedObjectFilterEnabled) { + mNamedObjectFilterEnabled = namedObjectFilterEnabled; + invalidateFilter(); +} + +void RemoteObjectChooserFilterModel::setWidgetFilterEnabled( + bool widgetFilterEnabled) { + mWidgetFilterEnabled = widgetFilterEnabled; + invalidateFilter(); +} + +//protected: + +bool RemoteObjectChooserFilterModel::filterAcceptsRow(int sourceRow, + const QModelIndex &sourceParent) const { + QModelIndex index = sourceModel()->index(sourceRow, 0, sourceParent); + RemoteObjectTreeItem* item = static_cast<RemoteObjectTreeItem*>( + index.internalPointer()); + RemoteObject* remoteObject = item->remoteObject(); + Q_ASSERT(remoteObject); + + //Breadth-first traversal. No "scientific" reason to use it instead of + //depth-first, just the "feeling" that it will find widgets and named + //objects sooner than a depth-first approach. + QQueue<RemoteObject*> objects; + objects.append(remoteObject); + + while (!objects.isEmpty()) { + remoteObject = objects.dequeue(); + + try { + if (filterNamedObject(remoteObject) && filterWidget(remoteObject)) { + return true; + } + + objects.append(remoteObject->children()); + } catch (DBusException) { + return true; + } + } + + return false; +} + +//private: + +bool RemoteObjectChooserFilterModel::filterNamedObject( + RemoteObject* remoteObject) const +throw (DBusException) { + if (!mNamedObjectFilterEnabled || !remoteObject->name().isEmpty()) { + return true; + } + + return false; +} + +bool RemoteObjectChooserFilterModel::filterWidget( + RemoteObject* remoteObject) const +throw (DBusException) { + if (!mWidgetFilterEnabled || isWidget(remoteObject->remoteClass())) { + return true; + } + + return false; +} + +bool RemoteObjectChooserFilterModel::isWidget(RemoteClass* remoteClass) const +throw (DBusException) { + if (!remoteClass) { + return false; + } + + if (remoteClass->className() == "QWidget") { + return true; + } + + if (isWidget(remoteClass->superClass())) { + return true; + } + + return false; +} Property changes on: trunk/ktutorial/ktutorial-editor/src/view/RemoteObjectChooserFilterModel.cpp ___________________________________________________________________ Added: svn:eol-style + native Added: trunk/ktutorial/ktutorial-editor/src/view/RemoteObjectChooserFilterModel.h =================================================================== --- trunk/ktutorial/ktutorial-editor/src/view/RemoteObjectChooserFilterModel.h (rev 0) +++ trunk/ktutorial/ktutorial-editor/src/view/RemoteObjectChooserFilterModel.h 2011-03-27 16:07:21 UTC (rev 294) @@ -0,0 +1,141 @@ +/*************************************************************************** + * Copyright (C) 2011 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 REMOTEOBJECTCHOOSERFILTERMODEL_H +#define REMOTEOBJECTCHOOSERFILTERMODEL_H + +#include <QSortFilterProxyModel> + +#include "../targetapplication/DBusException.h" + +class RemoteClass; +class RemoteObject; + +/** + * Proxy model to filter RemoteObjecTreeItem tree models. + * When applied on a TreeModel composed by RemoteObjectTreeItems it hides those + * items that do not pass the enabled filters. Note that the TreeModel must + * contain only RemoteObjectTreeItems; no other TreeItem types can appear in the + * source model. + * + * There are two available filters: named objects and widgets. Both filters + * check the RemoteObjects referenced by the RemoteObjectTreeItems. The first + * checks if it has a name, and the second checks if it is a widget. + * + * The filters can be enabled and disabled using + * setNamedObjectFilterEnabled(bool) and setWidgetFilterEnabled(bool). When both + * filters are disabled every item in the model is shown. + * + * When there are filters enabled, an item may be shown even if it does not pass + * them if any of its descendants does. + */ +class RemoteObjectChooserFilterModel: public QSortFilterProxyModel { +Q_OBJECT +public: + + /** + * Creates a new RemoteObjectChooserFilterModel. + * + * @param parent The parent object. + */ + RemoteObjectChooserFilterModel(QObject* parent = 0); + +public Q_SLOTS: + + /** + * Enables or disables the named object filter. + * + * @param namedObjectFilterEnabled If the filter has to be enabled or + * disabled. + */ + void setNamedObjectFilterEnabled(bool namedObjectFilterEnabled); + + /** + * Enables or disables the widget filter. + * + * @param widgetFilterEnabled If the filter has to be enabled or disabled. + */ + void setWidgetFilterEnabled(bool widgetFilterEnabled); + +protected: + + /** + * Returns true if the item indicated by the given sourceRow and + * sourceParent should be included in the model, false otherwise. + * An item is included if the item, or any of its children, passes the + * enabled filters. If no filter is enabled, every item is included in the + * model. + * Also, if there was a problem querying the remote objects the item is also + * included in the model. + * + * @param sourceRow The row of the index in the source model. + * @param sourceParent The parent of the index in the source model. + * @return True if the item passes the filter, false otherwise. + */ + virtual bool filterAcceptsRow(int sourceRow, + const QModelIndex &sourceParent) const; + +private: + + /** + * Whether the named object filter is enabled or not. + */ + bool mNamedObjectFilterEnabled; + + /** + * Whether the widget filter is enabled or not. + */ + bool mWidgetFilterEnabled; + + /** + * Checks if the given remote object passes the name object filter. + * The remote object passes the filter if the filter is not enabled, or if + * the filter is enabled and the remote object has a name. + * + * @param remoteObject The remote object to check. + * @return True if the remote object passes the named object filter, false + * otherwise. + * @throws DBusException If a DBus error happens. + */ + bool filterNamedObject(RemoteObject* remoteObject) const + throw (DBusException); + + /** + * Checks if the given remote object passes the widget filter. + * The remote object passes the filter if the filter is not enabled, or if + * the filter is enabled and the remote object is a widget. + * + * @param remoteObject The remote object to check. + * @return True if the remote object passes the widget filter, false + * otherwise. + * @throws DBusException If a DBus error happens. + */ + bool filterWidget(RemoteObject* remoteObject) const throw (DBusException); + + /** + * Returns true if the remote class is a widget, false otherwise. + * + * @param remoteClass The remote class to check. + * @return True if the remote class is a widget, false otherwise. + * @throws DBusException If a DBus error happens. + */ + bool isWidget(RemoteClass* remoteClass) const throw (DBusException); + +}; + +#endif Property changes on: trunk/ktutorial/ktutorial-editor/src/view/RemoteObjectChooserFilterModel.h ___________________________________________________________________ Added: svn:eol-style + native Modified: trunk/ktutorial/ktutorial-editor/src/view/RemoteObjectTreeSelectionManager.cpp =================================================================== --- trunk/ktutorial/ktutorial-editor/src/view/RemoteObjectTreeSelectionManager.cpp 2011-03-09 16:38:59 UTC (rev 293) +++ trunk/ktutorial/ktutorial-editor/src/view/RemoteObjectTreeSelectionManager.cpp 2011-03-27 16:07:21 UTC (rev 294) @@ -1,5 +1,5 @@ /*************************************************************************** - * Copyright (C) 2010 by Daniel Calviño Sánchez * + * Copyright (C) 2010-2011 by Daniel Calviño Sánchez * * dan...@gm... * * * * This program is free software; you can redistribute it and/or modify * @@ -18,6 +18,8 @@ #include "RemoteObjectTreeSelectionManager.h" +#include <QAbstractProxyModel> + #include "RemoteObjectTreeItem.h" //public: @@ -65,6 +67,17 @@ return getRemoteObjectForTreeItem(item->parent()); } +QModelIndex RemoteObjectTreeSelectionManager::getTreeModelIndex( + const QModelIndex& index) const { + const QAbstractProxyModel* proxyModel = + qobject_cast<const QAbstractProxyModel*>(index.model()); + if (proxyModel) { + return proxyModel->mapToSource(index); + } + + return index; +} + //private slots: void RemoteObjectTreeSelectionManager::handleSelectionChanged( @@ -81,6 +94,7 @@ Q_ASSERT(selected.at(0).indexes().count() == 1); QModelIndex index = selected.at(0).indexes().at(0); + index = getTreeModelIndex(index); selectedItem = static_cast<TreeItem*>(index.internalPointer()); } @@ -88,6 +102,7 @@ Q_ASSERT(deselected.at(0).indexes().count() == 1); QModelIndex index = deselected.at(0).indexes().at(0); + index = getTreeModelIndex(index); deselectedItem = static_cast<TreeItem*>(index.internalPointer()); } Modified: trunk/ktutorial/ktutorial-editor/src/view/RemoteObjectTreeSelectionManager.h =================================================================== --- trunk/ktutorial/ktutorial-editor/src/view/RemoteObjectTreeSelectionManager.h 2011-03-09 16:38:59 UTC (rev 293) +++ trunk/ktutorial/ktutorial-editor/src/view/RemoteObjectTreeSelectionManager.h 2011-03-27 16:07:21 UTC (rev 294) @@ -1,5 +1,5 @@ /*************************************************************************** - * Copyright (C) 2010 by Daniel Calviño Sánchez * + * Copyright (C) 2010-2011 by Daniel Calviño Sánchez * * dan...@gm... * * * * This program is free software; you can redistribute it and/or modify * @@ -26,9 +26,9 @@ class TreeItem; /** - * Watches the QItemSelectionModel of a TreeModel composed by - * RemoteObjectTreeItems for changes in the selection. - * When an item is selected in the TreeModel, + * Watches the QItemSelectionModel of a TreeModel (or a proxy to a TreeModel) + * composed by RemoteObjectTreeItems for changes in the selection. + * When an item is selected in the TreeModel (or its proxy), * remoteObjectSelected(RemoteObject*) signal is emitted with the RemoteObject * represented by the selected item. * @@ -82,6 +82,16 @@ */ RemoteObject* getRemoteObjectForTreeItem(TreeItem* item); + /** + * Ensures that the index comes from a tree model and not from a proxy + * model. + * + * @param index The index to "clean". + * @return The index mapped to the given one in the source model, or the + * given index if it already comes from a source model. + */ + QModelIndex getTreeModelIndex(const QModelIndex& index) const; + private Q_SLOTS: /** Modified: trunk/ktutorial/ktutorial-editor/tests/unit/targetapplication/RemoteClassStubs.h =================================================================== --- trunk/ktutorial/ktutorial-editor/tests/unit/targetapplication/RemoteClassStubs.h 2011-03-09 16:38:59 UTC (rev 293) +++ trunk/ktutorial/ktutorial-editor/tests/unit/targetapplication/RemoteClassStubs.h 2011-03-27 16:07:21 UTC (rev 294) @@ -1,5 +1,5 @@ /*************************************************************************** - * Copyright (C) 2010 by Daniel Calviño Sánchez * + * Copyright (C) 2010-2011 by Daniel Calviño Sánchez * * dan...@gm... * * * * This program is free software; you can redistribute it and/or modify * @@ -69,6 +69,47 @@ } }; +/** + * ... + * |-42: "The object name 42" + * |-420: "The object name 420" + * |-421: "The object name 421" + * |-422: "The object name 422" + * |-423: "The object name 423" + * |-5: "Duplicated grandparent" + * | |-50: "The object name 50" + * | | |-500: "Duplicated object" + * | | |... + * | |... + * |-6: "Duplicated grandparent" + * | |-60: "Duplicated parent" + * | | |-600: "Duplicated object" + * | | |... + * | |... + * |-7: "The object name 7" + * | |-70: "Duplicated parent" + * | | |-700: "Duplicated object" + * | | |... + * | |... + * |-8: "The object name 8" + * |-80: "" (The class name 80) + * | |-800: "Duplicated object" + * | |-801: "The object name 801" + * | |-802: "" + * | |... + * |-81: "" (QWidgetChildChild) + * | |-810: "" + * | |-811: "" + * | |-812: "" + * | |-813: "" + * |... + * |-82: "The object name 82" (ChildChildQWidget) + * | |-820: "The object name 820" + * | |... + * |-83: "The object name 83" (The class name 83) + * |-830: "The object name 830" (ChildQWidget) + * |... + */ class StubObjectRegisterAdaptor: public QDBusAbstractAdaptor { Q_OBJECT Q_CLASSINFO("D-Bus Interface", "org.kde.ktutorial.ObjectRegister") @@ -79,8 +120,26 @@ public slots: + QString objectName(int objectId) { + if (objectId == 500 || objectId == 600 || objectId == 700 || + objectId == 800) { + return "Duplicated object"; + } - QString objectName(int objectId) { + if (objectId == 60 || objectId == 70) { + return "Duplicated parent"; + } + + if (objectId == 5 || objectId == 6) { + return "Duplicated grandparent"; + } + + if (objectId == 80 || objectId == 81 || objectId == 802 || + objectId == 810 || objectId == 811 || objectId == 812 || + objectId == 813) { + return ""; + } + if (objectId > 1000) { return ""; } @@ -89,6 +148,14 @@ } QString className(int objectId) { + if (objectId == 81 || objectId == 82) { + return "ChildChildQWidget"; + } + + if (objectId == 830) { + return "ChildQWidget"; + } + if (objectId > 1000) { return ""; } @@ -97,7 +164,7 @@ } QList<int> childObjectIds(int objectId) { - if (objectId > 42) { + if (objectId > 99) { return QList<int>(); } @@ -105,6 +172,14 @@ for (int i=0; i<4; i++) { ids.append(objectId * 10 + i); } + + if (objectId == 42) { + ids.append(5); + ids.append(6); + ids.append(7); + ids.append(8); + } + return ids; } }; Modified: trunk/ktutorial/ktutorial-editor/tests/unit/targetapplication/RemoteObjectTest.cpp =================================================================== --- trunk/ktutorial/ktutorial-editor/tests/unit/targetapplication/RemoteObjectTest.cpp 2011-03-09 16:38:59 UTC (rev 293) +++ trunk/ktutorial/ktutorial-editor/tests/unit/targetapplication/RemoteObjectTest.cpp 2011-03-27 16:07:21 UTC (rev 294) @@ -1,5 +1,5 @@ /*************************************************************************** - * Copyright (C) 2010 by Daniel Calviño Sánchez * + * Copyright (C) 2010-2011 by Daniel Calviño Sánchez * * dan...@gm... * * * * This program is free software; you can redistribute it and/or modify * @@ -122,11 +122,15 @@ RemoteObject remoteObject(mService, mMapper, 42); QList<RemoteObject*> children = remoteObject.children(); - QCOMPARE(children.count(), 4); + QCOMPARE(children.count(), 8); QCOMPARE(children[0]->objectId(), 420); QCOMPARE(children[1]->objectId(), 421); QCOMPARE(children[2]->objectId(), 422); QCOMPARE(children[3]->objectId(), 423); + QCOMPARE(children[4]->objectId(), 5); + QCOMPARE(children[5]->objectId(), 6); + QCOMPARE(children[6]->objectId(), 7); + QCOMPARE(children[7]->objectId(), 8); } void RemoteObjectTest::testChildrenWhenRemoteObjectIsNotAvailable() { Modified: trunk/ktutorial/ktutorial-editor/tests/unit/view/CMakeLists.txt =================================================================== --- trunk/ktutorial/ktutorial-editor/tests/unit/view/CMakeLists.txt 2011-03-09 16:38:59 UTC (rev 293) +++ trunk/ktutorial/ktutorial-editor/tests/unit/view/CMakeLists.txt 2011-03-27 16:07:21 UTC (rev 294) @@ -54,6 +54,7 @@ unit_tests( RemoteObjectChooser + RemoteObjectChooserFilterModel RemoteObjectNameWidget RemoteObjectTreeItem RemoteObjectTreeItemUpdater @@ -103,6 +104,7 @@ if (QT_QTDBUS_FOUND) mem_tests( RemoteObjectChooser + RemoteObjectChooserFilterModel RemoteObjectTreeItem RemoteObjectTreeItemUpdater RemoteObjectTreeSelectionManager Added: trunk/ktutorial/ktutorial-editor/tests/unit/view/RemoteObjectChooserFilterModelTest.cpp =================================================================== --- trunk/ktutorial/ktutorial-editor/tests/unit/view/RemoteObjectChooserFilterModelTest.cpp (rev 0) +++ trunk/ktutorial/ktutorial-editor/tests/unit/view/RemoteObjectChooserFilterModelTest.cpp 2011-03-27 16:07:21 UTC (rev 294) @@ -0,0 +1,338 @@ +/*************************************************************************** + * Copyright (C) 2011 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 "RemoteObjectChooserFilterModel.h" + +#include "RemoteObjectTreeItem.h" +#include "TreeModel.h" +#include "../targetapplication/RemoteClassStubs.h" +#include "../targetapplication/RemoteObject.h" +#include "../targetapplication/RemoteObjectMapper.h" + +class RemoteObjectChooserFilterModelTest: public QObject { +Q_OBJECT + +private slots: + + void init(); + void cleanup(); + + void testNamedObjectFilter(); + void testNamedObjectFilterWhenRemoteObjectsAreNotAvailable(); + + void testWidgetFilter(); + void testWidgetFilterWhenRemoteObjectsAreNotAvailable(); + + void testNamedObjectAndWidgetFilters(); + +private: + + StubObjectRegister* mObjectRegister; + RemoteObjectMapper* mMapper; + + TreeModel* mTreeModel; + + RemoteObjectChooserFilterModel* mFilterModel; + + QModelIndex mappedFromSource(int row, int column, const QModelIndex& parent) const; + +}; + +void RemoteObjectChooserFilterModelTest::init() { + QVERIFY(QDBusConnection::sessionBus().isConnected()); + + mObjectRegister = new StubObjectRegister(); + QDBusConnection::sessionBus().registerObject("/ktutorial/ObjectRegister", + mObjectRegister, QDBusConnection::ExportAdaptors); + + QString service = QDBusConnection::sessionBus().baseService(); + mMapper = new RemoteObjectMapper(service); + + RemoteObject* mainWindow = mMapper->remoteObject(42); + RemoteObjectTreeItem* rootItem = new RemoteObjectTreeItem(mainWindow); + mTreeModel = new TreeModel(rootItem, this); + + mFilterModel = new RemoteObjectChooserFilterModel(this); + mFilterModel->setSourceModel(mTreeModel); +} + +void RemoteObjectChooserFilterModelTest::cleanup() { + delete mFilterModel; + + delete mTreeModel; + + delete mMapper; + + QDBusConnection::sessionBus().unregisterObject("/ktutorial/ObjectRegister"); + delete mObjectRegister; +} + +void RemoteObjectChooserFilterModelTest::testNamedObjectFilter() { + mFilterModel->setNamedObjectFilterEnabled(true); + + QModelIndex baseIndex = mFilterModel->index(7, 0); + QModelIndex sourceBaseIndex = mTreeModel->index(7, 0); + + QCOMPARE(mFilterModel->rowCount(baseIndex), 3); + QCOMPARE(mappedFromSource(0, 0, sourceBaseIndex), + mFilterModel->index(0, 0, baseIndex)); + QCOMPARE(mappedFromSource(1, 0, sourceBaseIndex), + QModelIndex()); + QCOMPARE(mappedFromSource(2, 0, sourceBaseIndex), + mFilterModel->index(1, 0, baseIndex)); + QCOMPARE(mappedFromSource(3, 0, sourceBaseIndex), + mFilterModel->index(2, 0, baseIndex)); + + QModelIndex childBaseIndex = mFilterModel->index(0, 0, baseIndex); + QModelIndex childSourceBaseIndex = mTreeModel->index(0, 0, sourceBaseIndex); + + QCOMPARE(mFilterModel->rowCount(childBaseIndex), 3); + QCOMPARE(mappedFromSource(0, 0, childSourceBaseIndex), + mFilterModel->index(0, 0, childBaseIndex)); + QCOMPARE(mappedFromSource(1, 0, childSourceBaseIndex), + mFilterModel->index(1, 0, childBaseIndex)); + QCOMPARE(mappedFromSource(2, 0, childSourceBaseIndex), + QModelIndex()); + QCOMPARE(mappedFromSource(3, 0, childSourceBaseIndex), + mFilterModel->index(2, 0, childBaseIndex)); + + childBaseIndex = mFilterModel->index(1, 0, baseIndex); + + QCOMPARE(mFilterModel->rowCount(childBaseIndex), 4); + + childBaseIndex = mFilterModel->index(2, 0, baseIndex); + + QCOMPARE(mFilterModel->rowCount(childBaseIndex), 4); + + mFilterModel->setNamedObjectFilterEnabled(false); + + baseIndex = mFilterModel->index(7, 0); + sourceBaseIndex = mTreeModel->index(7, 0); + + QCOMPARE(mFilterModel->rowCount(baseIndex), 4); + QCOMPARE(mappedFromSource(0, 0, sourceBaseIndex), + mFilterModel->index(0, 0, baseIndex)); + QCOMPARE(mappedFromSource(1, 0, sourceBaseIndex), + mFilterModel->index(1, 0, baseIndex)); + QCOMPARE(mappedFromSource(2, 0, sourceBaseIndex), + mFilterModel->index(2, 0, baseIndex)); + QCOMPARE(mappedFromSource(3, 0, sourceBaseIndex), + mFilterModel->index(3, 0, baseIndex)); + + childBaseIndex = mFilterModel->index(0, 0, baseIndex); + childSourceBaseIndex = mTreeModel->index(0, 0, sourceBaseIndex); + + QCOMPARE(mFilterModel->rowCount(childBaseIndex), 4); + QCOMPARE(mappedFromSource(0, 0, childSourceBaseIndex), + mFilterModel->index(0, 0, childBaseIndex)); + QCOMPARE(mappedFromSource(1, 0, childSourceBaseIndex), + mFilterModel->index(1, 0, childBaseIndex)); + QCOMPARE(mappedFromSource(2, 0, childSourceBaseIndex), + mFilterModel->index(2, 0, childBaseIndex)); + QCOMPARE(mappedFromSource(3, 0, childSourceBaseIndex), + mFilterModel->index(3, 0, childBaseIndex)); + + childBaseIndex = mFilterModel->index(1, 0, baseIndex); + + QCOMPARE(mFilterModel->rowCount(childBaseIndex), 4); + + childBaseIndex = mFilterModel->index(2, 0, baseIndex); + + QCOMPARE(mFilterModel->rowCount(childBaseIndex), 4); + + childBaseIndex = mFilterModel->index(3, 0, baseIndex); + + QCOMPARE(mFilterModel->rowCount(childBaseIndex), 4); +} + +void RemoteObjectChooserFilterModelTest:: + testNamedObjectFilterWhenRemoteObjectsAreNotAvailable() { + QDBusConnection::sessionBus().unregisterObject("/ktutorial/ObjectRegister"); + + mFilterModel->setNamedObjectFilterEnabled(true); + + QModelIndex baseIndex = mFilterModel->index(7, 0); + + QCOMPARE(mFilterModel->rowCount(baseIndex), 4); + + mFilterModel->setNamedObjectFilterEnabled(false); + + QCOMPARE(mFilterModel->rowCount(baseIndex), 4); +} + +void RemoteObjectChooserFilterModelTest::testWidgetFilter() { + mFilterModel->setWidgetFilterEnabled(true); + + QModelIndex baseIndex = mFilterModel->index(0, 0); + QModelIndex sourceBaseIndex = mTreeModel->index(7, 0); + + QCOMPARE(mFilterModel->rowCount(baseIndex), 3); + QCOMPARE(mappedFromSource(0, 0, sourceBaseIndex), + QModelIndex()); + QCOMPARE(mappedFromSource(1, 0, sourceBaseIndex), + mFilterModel->index(0, 0, baseIndex)); + QCOMPARE(mappedFromSource(2, 0, sourceBaseIndex), + mFilterModel->index(1, 0, baseIndex)); + QCOMPARE(mappedFromSource(3, 0, sourceBaseIndex), + mFilterModel->index(2, 0, baseIndex)); + + QModelIndex childBaseIndex = mFilterModel->index(0, 0, baseIndex); + + QCOMPARE(mFilterModel->rowCount(childBaseIndex), 0); + + childBaseIndex = mFilterModel->index(1, 0, baseIndex); + + QCOMPARE(mFilterModel->rowCount(childBaseIndex), 0); + + childBaseIndex = mFilterModel->index(2, 0, baseIndex); + QModelIndex childSourceBaseIndex = mTreeModel->index(3, 0, sourceBaseIndex); + + QCOMPARE(mFilterModel->rowCount(childBaseIndex), 1); + QCOMPARE(mappedFromSource(0, 0, childSourceBaseIndex), + mFilterModel->index(0, 0, childBaseIndex)); + + mFilterModel->setWidgetFilterEnabled(false); + + baseIndex = mFilterModel->index(7, 0); + sourceBaseIndex = mTreeModel->index(7, 0); + + QCOMPARE(mFilterModel->rowCount(baseIndex), 4); + QCOMPARE(mappedFromSource(0, 0, sourceBaseIndex), + mFilterModel->index(0, 0, baseIndex)); + QCOMPARE(mappedFromSource(1, 0, sourceBaseIndex), + mFilterModel->index(1, 0, baseIndex)); + QCOMPARE(mappedFromSource(2, 0, sourceBaseIndex), + mFilterModel->index(2, 0, baseIndex)); + QCOMPARE(mappedFromSource(3, 0, sourceBaseIndex), + mFilterModel->index(3, 0, baseIndex)); + + childBaseIndex = mFilterModel->index(0, 0, baseIndex); + + QCOMPARE(mFilterModel->rowCount(childBaseIndex), 4); + + childBaseIndex = mFilterModel->index(1, 0, baseIndex); + + QCOMPARE(mFilterModel->rowCount(childBaseIndex), 4); + + childBaseIndex = mFilterModel->index(2, 0, baseIndex); + + QCOMPARE(mFilterModel->rowCount(childBaseIndex), 4); + + childBaseIndex = mFilterModel->index(3, 0, baseIndex); + childSourceBaseIndex = mTreeModel->index(3, 0, sourceBaseIndex); + + QCOMPARE(mFilterModel->rowCount(childBaseIndex), 4); + QCOMPARE(mappedFromSource(0, 0, childSourceBaseIndex), + mFilterModel->index(0, 0, childBaseIndex)); + QCOMPARE(mappedFromSource(1, 0, childSourceBaseIndex), + mFilterModel->index(1, 0, childBaseIndex)); + QCOMPARE(mappedFromSource(2, 0, childSourceBaseIndex), + mFilterModel->index(2, 0, childBaseIndex)); + QCOMPARE(mappedFromSource(3, 0, childSourceBaseIndex), + mFilterModel->index(3, 0, childBaseIndex)); +} + +void RemoteObjectChooserFilterModelTest:: + testWidgetFilterWhenRemoteObjectsAreNotAvailable() { + QDBusConnection::sessionBus().unregisterObject("/ktutorial/ObjectRegister"); + + mFilterModel->setWidgetFilterEnabled(true); + + QModelIndex baseIndex = mFilterModel->index(7, 0); + + QCOMPARE(mFilterModel->rowCount(baseIndex), 4); + + mFilterModel->setWidgetFilterEnabled(false); + + QCOMPARE(mFilterModel->rowCount(baseIndex), 4); +} + +void RemoteObjectChooserFilterModelTest::testNamedObjectAndWidgetFilters() { + mFilterModel->setNamedObjectFilterEnabled(true); + mFilterModel->setWidgetFilterEnabled(true); + + QModelIndex baseIndex = mFilterModel->index(0, 0); + QModelIndex sourceBaseIndex = mTreeModel->index(7, 0); + + QCOMPARE(mFilterModel->rowCount(baseIndex), 2); + QCOMPARE(mappedFromSource(0, 0, sourceBaseIndex), + QModelIndex()); + QCOMPARE(mappedFromSource(1, 0, sourceBaseIndex), + QModelIndex()); + QCOMPARE(mappedFromSource(2, 0, sourceBaseIndex), + mFilterModel->index(0, 0, baseIndex)); + QCOMPARE(mappedFromSource(3, 0, sourceBaseIndex), + mFilterModel->index(1, 0, baseIndex)); + + QModelIndex childBaseIndex = mFilterModel->index(0, 0, baseIndex); + + QCOMPARE(mFilterModel->rowCount(childBaseIndex), 0); + + childBaseIndex = mFilterModel->index(1, 0, baseIndex); + QModelIndex childSourceBaseIndex = mTreeModel->index(3, 0, sourceBaseIndex); + + QCOMPARE(mFilterModel->rowCount(childBaseIndex), 1); + QCOMPARE(mappedFromSource(0, 0, childSourceBaseIndex), + mFilterModel->index(0, 0, childBaseIndex)); + + mFilterModel->setNamedObjectFilterEnabled(false); + mFilterModel->setWidgetFilterEnabled(false); + + baseIndex = mFilterModel->index(7, 0); + sourceBaseIndex = mTreeModel->index(7, 0); + + QCOMPARE(mFilterModel->rowCount(baseIndex), 4); + QCOMPARE(mappedFromSource(0, 0, sourceBaseIndex), + mFilterModel->index(0, 0, baseIndex)); + QCOMPARE(mappedFromSource(1, 0, sourceBaseIndex), + mFilterModel->index(1, 0, baseIndex)); + QCOMPARE(mappedFromSource(2, 0, sourceBaseIndex), + mFilterModel->index(2, 0, baseIndex)); + QCOMPARE(mappedFromSource(3, 0, sourceBaseIndex), + mFilterModel->index(3, 0, baseIndex)); + + childBaseIndex = mFilterModel->index(0, 0, baseIndex); + + QCOMPARE(mFilterModel->rowCount(childBaseIndex), 4); + + childBaseIndex = mFilterModel->index(1, 0, baseIndex); + + QCOMPARE(mFilterModel->rowCount(childBaseIndex), 4); + + childBaseIndex = mFilterModel->index(2, 0, baseIndex); + + QCOMPARE(mFilterModel->rowCount(childBaseIndex), 4); + + childBaseIndex = mFilterModel->index(3, 0, baseIndex); + + QCOMPARE(mFilterModel->rowCount(childBaseIndex), 4); +} + +/////////////////////////////////// Helpers //////////////////////////////////// + +QModelIndex RemoteObjectChooserFilterModelTest::mappedFromSource(int row, + int column, const QModelIndex& parent) const { + return mFilterModel->mapFromSource(mTreeModel->index(row, column, parent)); +} + +QTEST_MAIN(RemoteObjectChooserFilterModelTest) + +#include "../targetapplication/moc_RemoteClassStubs.cxx" +#include "RemoteObjectChooserFilterModelTest.moc" Property changes on: trunk/ktutorial/ktutorial-editor/tests/unit/view/RemoteObjectChooserFilterModelTest.cpp ___________________________________________________________________ Added: svn:eol-style + native Modified: trunk/ktutorial/ktutorial-editor/tests/unit/view/RemoteObjectChooserTest.cpp =================================================================== --- trunk/ktutorial/ktutorial-editor/tests/unit/view/RemoteObjectChooserTest.cpp 2011-03-09 16:38:59 UTC (rev 293) +++ trunk/ktutorial/ktutorial-editor/tests/unit/view/RemoteObjectChooserTest.cpp 2011-03-27 16:07:21 UTC (rev 294) @@ -1,5 +1,5 @@ /*************************************************************************** - * Copyright (C) 2010 by Daniel Calviño Sánchez * + * Copyright (C) 2010-2011 by Daniel Calviño Sánchez * * dan...@gm... * * * * This program is free software; you can redistribute it and/or modify * @@ -64,6 +64,10 @@ //Closing with ALT+F4 can't be tested, as it depends on the window manager //rather than the widget + void testShowOnlyNamedObjects(); + void testShowOnlyWidgets(); + void testShowOnlyNamedWidgets(); + void testSelectRemoteObject(); void testOkButton(); @@ -78,6 +82,9 @@ void killTargetApplication(int timeToWait); + QCheckBox* showOnlyNamedObjectsCheckBox(RemoteObjectChooser* widget) const; + QCheckBox* showOnlyWidgetsCheckBox(RemoteObjectChooser* widget) const; + QTreeView* remoteObjectsTreeView(RemoteObjectChooser* widget) const; QPushButton* okButton(RemoteObjectChooser* widget) const; @@ -315,6 +322,98 @@ QVERIFY(dialog->isVisible()); } +void RemoteObjectChooserTest::testShowOnlyNamedObjects() { + TargetApplication::self()->setTargetApplicationFilePath(mPath); + + QWidget window(0, Qt::Window); + //Queue closing the information message box + closeInformationMessageBox(1000); + RemoteObjectChooser* chooser = new RemoteObjectChooser(&window); + chooser->show(); + + //Give the target application time to start + QTest::qWait(1000); + + QVERIFY(remoteObjectsTreeView(chooser)->model()); + + QModelIndex index = remoteObjectsTreeView(chooser)->model()->index(7, 0); + QCOMPARE(remoteObjectsTreeView(chooser)->model()->rowCount(index), 4); + + showOnlyNamedObjectsCheckBox(chooser)->click(); + + QCOMPARE(remoteObjectsTreeView(chooser)->model()->rowCount(index), 3); + + showOnlyNamedObjectsCheckBox(chooser)->click(); + + QCOMPARE(remoteObjectsTreeView(chooser)->model()->rowCount(index), 4); +} + +void RemoteObjectChooserTest::testShowOnlyWidgets() { + TargetApplication::self()->setTargetApplicationFilePath(mPath); + + QWidget window(0, Qt::Window); + //Queue closing the information message box + closeInformationMessageBox(1000); + RemoteObjectChooser* chooser = new RemoteObjectChooser(&window); + chooser->show(); + + //Give the target application time to start + QTest::qWait(1000); + + QVERIFY(remoteObjectsTreeView(chooser)->model()); + + QModelIndex index = remoteObjectsTreeView(chooser)->model()->index(7, 0); + QCOMPARE(remoteObjectsTreeView(chooser)->model()->rowCount(index), 4); + + showOnlyWidgetsCheckBox(chooser)->click(); + + //The index changes because the other base items were hidden + index = remoteObjectsTreeView(chooser)->model()->index(0, 0); + QCOMPARE(remoteObjectsTreeView(chooser)->model()->rowCount(index), 3); + + showOnlyWidgetsCheckBox(chooser)->click(); + + index = remoteObjectsTreeView(chooser)->model()->index(7, 0); + QCOMPARE(remoteObjectsTreeView(chooser)->model()->rowCount(index), 4); +} + +void RemoteObjectChooserTest::testShowOnlyNamedWidgets() { + TargetApplication::self()->setTargetApplicationFilePath(mPath); + + QWidget window(0, Qt::Window); + //Queue closing the information message box + closeInformationMessageBox(1000); + RemoteObjectChooser* chooser = new RemoteObjectChooser(&window); + chooser->show(); + + //Give the target application time to start + QTest::qWait(1000); + + QVERIFY(remoteObjectsTreeView(chooser)->model()); + + QModelIndex index = remoteObjectsTreeView(chooser)->model()->index(7, 0); + QCOMPARE(remoteObjectsTreeView(chooser)->model()->rowCount(index), 4); + + showOnlyWidgetsCheckBox(chooser)->click(); + + //The index changes because the other base items were hidden + index = remoteObjectsTreeView(chooser)->model()->index(0, 0); + QCOMPARE(remoteObjectsTreeView(chooser)->model()->rowCount(index), 3); + + showOnlyNamedObjectsCheckBox(chooser)->click(); + + QCOMPARE(remoteObjectsTreeView(chooser)->model()->rowCount(index), 2); + + showOnlyWidgetsCheckBox(chooser)->click(); + + index = remoteObjectsTreeView(chooser)->model()->index(7, 0); + QCOMPARE(remoteObjectsTreeView(chooser)->model()->rowCount(index), 3); + + showOnlyNamedObjectsCheckBox(chooser)->click(); + + QCOMPARE(remoteObjectsTreeView(chooser)->model()->rowCount(index), 4); +} + void RemoteObjectChooserTest::testSelectRemoteObject() { TargetApplication::self()->setTargetApplicationFilePath(mPath); @@ -516,6 +615,16 @@ QTimer::singleShot(timeToWait, helper, SLOT(killTargetApplication())); } +QCheckBox* RemoteObjectChooserTest::showOnlyNamedObjectsCheckBox( + RemoteObjectChooser* widget) const { + return widget->findChild<QCheckBox*>("showOnlyNamedObjectsCheckBox"); +} + +QCheckBox* RemoteObjectChooserTest::showOnlyWidgetsCheckBox( + RemoteObjectChooser* widget) const { + return widget->findChild<QCheckBox*>("showOnlyWidgetsCheckBox"); +} + QTreeView* RemoteObjectChooserTest::remoteObjectsTreeView( RemoteObjectChooser* widget) const { return widget->findChild<QTreeView*>("remoteObjectsTreeView"); Modified: trunk/ktutorial/ktutorial-editor/tests/unit/view/RemoteObjectNameWidgetTest.cpp =================================================================== --- trunk/ktutorial/ktutorial-editor/tests/unit/view/RemoteObjectNameWidgetTest.cpp 2011-03-09 16:38:59 UTC (rev 293) +++ trunk/ktutorial/ktutorial-editor/tests/unit/view/RemoteObjectNameWidgetTest.cpp 2011-03-27 16:07:21 UTC (rev 294) @@ -1,5 +1,5 @@ /*************************************************************************** - * Copyright (C) 2010 by Daniel Calviño Sánchez * + * Copyright (C) 2010-2011 by Daniel Calviño Sánchez * * dan...@gm... * * * * This program is free software; you can redistribute it and/or modify * @@ -67,6 +67,8 @@ void assertRemoteObjectSignal(const QSignalSpy& spy, int index, const RemoteObject* remoteObject) const; + void assertCompletionItems(const QStringList& items) const; + }; void RemoteObjectNameWidgetTest::initTestCase() { @@ -102,12 +104,7 @@ QCOMPARE(widget->parentWidget(), &parent); QCOMPARE(widget->name(), QString("")); QStringList items = objectNameLineEdit(widget)->completionObject()->items(); - QCOMPARE(items.count(), 5); - QVERIFY(items.contains("The object name 42")); - QVERIFY(items.contains("The object name 420")); - QVERIFY(items.contains("The object name 421")); - QVERIFY(items.contains("The object name 422")); - QVERIFY(items.contains("The object name 423")); + assertCompletionItems(items); } void RemoteObjectNameWidgetTest::testSetName() { @@ -172,12 +169,7 @@ QTest::qWait(1000); items = objectNameLineEdit(&widget)->completionObject()->items(); - QCOMPARE(items.count(), 5); - QVERIFY(items.contains("The object name 42")); - QVERIFY(items.contains("The object name 420")); - QVERIFY(items.contains("The object name 421")); - QVERIFY(items.contains("The object name 422")); - QVERIFY(items.contains("The object name 423")); + assertCompletionItems(items); widget.setName("The object name 423"); @@ -240,6 +232,22 @@ QCOMPARE(qvariant_cast<RemoteObject*>(argument), remoteObject); } +void RemoteObjectNameWidgetTest::assertCompletionItems( + const QStringList& items) const { + QCOMPARE(items.count(), 77); + QVERIFY(items.contains("The object name 42")); + QVERIFY(items.contains("The object name 420")); + QVERIFY(items.contains("The object name 421")); + QVERIFY(items.contains("The object name 422")); + QVERIFY(items.contains("The object name 423")); + QVERIFY(items.contains("The object name 7")); + QVERIFY(items.contains("The object name 62")); + QVERIFY(items.contains("The object name 833")); + QVERIFY(items.contains("Duplicated object")); + QVERIFY(items.contains("Duplicated parent")); + QVERIFY(items.contains("Duplicated grandparent")); +} + QTEST_MAIN(RemoteObjectNameWidgetTest) #include "RemoteObjectNameWidgetTest.moc" Modified: trunk/ktutorial/ktutorial-editor/tests/unit/view/RemoteObjectTreeSelectionManagerTest.cpp =================================================================== --- trunk/ktutorial/ktutorial-editor/tests/unit/view/RemoteObjectTreeSelectionManagerTest.cpp 2011-03-09 16:38:59 UTC (rev 293) +++ trunk/ktutorial/ktutorial-editor/tests/unit/view/RemoteObjectTreeSelectionManagerTest.cpp 2011-03-27 16:07:21 UTC (rev 294) @@ -1,5 +1,5 @@ /*************************************************************************** - * Copyright (C) 2010 by Daniel Calviño Sánchez * + * Copyright (C) 2010-2011 by Daniel Calviño Sánchez * * dan...@gm... * * * * This program is free software; you can redistribute it and/or modify * @@ -20,6 +20,8 @@ #include "RemoteObjectTreeSelectionManager.h" +#include <QSortFilterProxyModel> + #include "RemoteObjectTreeItem.h" #include "TreeModel.h" #include "../targetapplication/RemoteObject.h" @@ -40,6 +42,8 @@ void testSelectRemoteObjectClearingTheSelection(); void testSelectRemoteObjectChangingBetweenRemoteObjects(); + void testSelectInProxyModel(); + private: int mRemoteObjectStarType; @@ -215,6 +219,32 @@ assertRemoteObjectSignal(mRemoteObjectSelectedSpy, 2, mRemoteObject3); } +void RemoteObjectTreeSelectionManagerTest::testSelectInProxyModel() { + QSortFilterProxyModel proxyModel; + proxyModel.setSourceModel(mTreeModel); + + QItemSelectionModel selectionModel(&proxyModel); + RemoteObjectTreeSelectionManager selectionManager(&selectionModel); + + QSignalSpy remoteObjectSelectedSpy(&selectionManager, + SIGNAL(remoteObjectSelected(RemoteObject*))); + + QModelIndex remoteObject1Index = proxyModel.index(0, 0); + selectionModel.select(remoteObject1Index, + QItemSelectionModel::SelectCurrent); + + QCOMPARE(remoteObjectSelectedSpy.count(), 1); + assertRemoteObjectSignal(&remoteObjectSelectedSpy, 0, mRemoteObject1); + + QModelIndex remoteObject1_2Index = + proxyModel.index(1, 0, remoteObject1Index); + selectionModel.select(remoteObject1_2Index, + QItemSelectionModel::SelectCurrent); + + QCOMPARE(remoteObjectSelectedSpy.count(), 2); + assertRemoteObjectSignal(&remoteObjectSelectedSpy, 1, mRemoteObject1_2); +} + /////////////////////////////////// Helpers //////////////////////////////////// void RemoteObjectTreeSelectionManagerTest::select(const QModelIndex& index) { This was sent by the SourceForge.net collaborative development platform, the world's largest Open Source development site. |
From: <dan...@us...> - 2011-03-09 16:39:06
|
Revision: 293 http://ktutorial.svn.sourceforge.net/ktutorial/?rev=293&view=rev Author: danxuliu Date: 2011-03-09 16:38:59 +0000 (Wed, 09 Mar 2011) Log Message: ----------- Fix documentation. Modified Paths: -------------- trunk/ktutorial/ktutorial-library/src/KTutorial.h Modified: trunk/ktutorial/ktutorial-library/src/KTutorial.h =================================================================== --- trunk/ktutorial/ktutorial-library/src/KTutorial.h 2011-03-08 14:31:36 UTC (rev 292) +++ trunk/ktutorial/ktutorial-library/src/KTutorial.h 2011-03-09 16:38:59 UTC (rev 293) @@ -178,13 +178,13 @@ /** * Returns the object with the specified name that is descendant of the - * given parent, if any. + * given ancestor, if any. * The name of the object can contain ancestor names separated by "/". The - * first object that matches the whole path is returned (note that ancestor + * first object that matches the whole path is returned (note that ancestors * are not necessarily direct parents). * * @param name The name of the object to find. - * @param parent The parent to look the object in. + * @param ancestor The ancestor to look the object in. * @return The object with the specified name, or null if there is none. */ template <typename T> This was sent by the SourceForge.net collaborative development platform, the world's largest Open Source development site. |
From: <dan...@us...> - 2011-03-08 14:31:42
|
Revision: 292 http://ktutorial.svn.sourceforge.net/ktutorial/?rev=292&view=rev Author: danxuliu Date: 2011-03-08 14:31:36 +0000 (Tue, 08 Mar 2011) Log Message: ----------- Fix default return value. Modified Paths: -------------- trunk/ktutorial/ktutorial-library/src/KTutorial.h Modified: trunk/ktutorial/ktutorial-library/src/KTutorial.h =================================================================== --- trunk/ktutorial/ktutorial-library/src/KTutorial.h 2011-03-08 04:54:47 UTC (rev 291) +++ trunk/ktutorial/ktutorial-library/src/KTutorial.h 2011-03-08 14:31:36 UTC (rev 292) @@ -211,7 +211,7 @@ } } - return 0; + return T(); } private slots: This was sent by the SourceForge.net collaborative development platform, the world's largest Open Source development site. |
From: <dan...@us...> - 2011-03-08 04:54:54
|
Revision: 291 http://ktutorial.svn.sourceforge.net/ktutorial/?rev=291&view=rev Author: danxuliu Date: 2011-03-08 04:54:47 +0000 (Tue, 08 Mar 2011) Log Message: ----------- Register also unnamed remote objects to avoid trying to register them again when a child is added to their parent. Modified Paths: -------------- trunk/ktutorial/ktutorial-editor/src/view/RemoteObjectNameWidget.cpp trunk/ktutorial/ktutorial-editor/src/view/RemoteObjectNameWidget.h Modified: trunk/ktutorial/ktutorial-editor/src/view/RemoteObjectNameWidget.cpp =================================================================== --- trunk/ktutorial/ktutorial-editor/src/view/RemoteObjectNameWidget.cpp 2011-03-08 02:59:37 UTC (rev 290) +++ trunk/ktutorial/ktutorial-editor/src/view/RemoteObjectNameWidget.cpp 2011-03-08 04:54:47 UTC (rev 291) @@ -1,5 +1,5 @@ /*************************************************************************** - * Copyright (C) 2010 by Daniel Calviño Sánchez * + * Copyright (C) 2010-2011 by Daniel Calviño Sánchez * * dan...@gm... * * * * This program is free software; you can redistribute it and/or modify * @@ -76,12 +76,13 @@ throw (DBusException) { Q_ASSERT(remoteObject); + mRemoteObjectForParent.insert(parent, remoteObject); + if (!remoteObject->name().isEmpty()) { KCompletion* completion = ui->objectNameLineEdit->completionObject(); completion->addItem(remoteObject->name()); mRemoteObjectForName.insert(remoteObject->name(), remoteObject); - mRemoteObjectForParent.insert(parent, remoteObject); } foreach (RemoteObject* child, remoteObject->children()) { Modified: trunk/ktutorial/ktutorial-editor/src/view/RemoteObjectNameWidget.h =================================================================== --- trunk/ktutorial/ktutorial-editor/src/view/RemoteObjectNameWidget.h 2011-03-08 02:59:37 UTC (rev 290) +++ trunk/ktutorial/ktutorial-editor/src/view/RemoteObjectNameWidget.h 2011-03-08 04:54:47 UTC (rev 291) @@ -1,5 +1,5 @@ /*************************************************************************** - * Copyright (C) 2010 by Daniel Calviño Sánchez * + * Copyright (C) 2010-2011 by Daniel Calviño Sánchez * * dan...@gm... * * * * This program is free software; you can redistribute it and/or modify * @@ -94,7 +94,7 @@ QHash<QString, RemoteObject*> mRemoteObjectForName; /** - * The known RemoteObjects with a name indexed by their parent + * The known RemoteObjects (with and without name) indexed by their parent. */ QMultiHash<RemoteObject*, RemoteObject*> mRemoteObjectForParent; This was sent by the SourceForge.net collaborative development platform, the world's largest Open Source development site. |