ktutorial-commits Mailing List for KTutorial (Page 6)
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...> - 2010-09-27 16:17:16
|
Revision: 263 http://ktutorial.svn.sourceforge.net/ktutorial/?rev=263&view=rev Author: danxuliu Date: 2010-09-27 16:17:07 +0000 (Mon, 27 Sep 2010) Log Message: ----------- Fix loading rich text markup as rich text instead of as plain text in the KTextEdits: in some places like code edition widgets rich text makes no sense, and in places like step description it must be loaded as plain text to be properly edited and saved (as there is no WYSIWYG edition yet). Modified Paths: -------------- trunk/ktutorial/ktutorial-editor/src/view/LicenseWidget.cpp trunk/ktutorial/ktutorial-editor/src/view/ReactionWidget.cpp trunk/ktutorial/ktutorial-editor/src/view/StepCustomCodeWidget.cpp trunk/ktutorial/ktutorial-editor/src/view/StepDataWidget.cpp trunk/ktutorial/ktutorial-editor/src/view/TutorialCustomCodeWidget.cpp trunk/ktutorial/ktutorial-editor/src/view/TutorialInformationWidget.cpp trunk/ktutorial/ktutorial-editor/tests/unit/view/LicenseWidgetTest.cpp trunk/ktutorial/ktutorial-editor/tests/unit/view/ReactionWidgetTest.cpp trunk/ktutorial/ktutorial-editor/tests/unit/view/StepCustomCodeWidgetTest.cpp trunk/ktutorial/ktutorial-editor/tests/unit/view/StepDataWidgetTest.cpp trunk/ktutorial/ktutorial-editor/tests/unit/view/TutorialCustomCodeWidgetTest.cpp trunk/ktutorial/ktutorial-editor/tests/unit/view/TutorialInformationWidgetTest.cpp Modified: trunk/ktutorial/ktutorial-editor/src/view/LicenseWidget.cpp =================================================================== --- trunk/ktutorial/ktutorial-editor/src/view/LicenseWidget.cpp 2010-09-26 21:07:06 UTC (rev 262) +++ trunk/ktutorial/ktutorial-editor/src/view/LicenseWidget.cpp 2010-09-27 16:17:07 UTC (rev 263) @@ -30,7 +30,7 @@ ui = new Ui::LicenseWidget(); ui->setupUi(this); - ui->licenseTextEdit->setText(tutorial->licenseText()); + ui->licenseTextEdit->setPlainText(tutorial->licenseText()); } LicenseWidget::~LicenseWidget() { Modified: trunk/ktutorial/ktutorial-editor/src/view/ReactionWidget.cpp =================================================================== --- trunk/ktutorial/ktutorial-editor/src/view/ReactionWidget.cpp 2010-09-26 21:07:06 UTC (rev 262) +++ trunk/ktutorial/ktutorial-editor/src/view/ReactionWidget.cpp 2010-09-27 16:17:07 UTC (rev 263) @@ -66,7 +66,7 @@ } ui->triggerOptionLineEdit->setText(reaction->optionName()); - ui->responseCodeTextEdit->setText(reaction->customCode()); + ui->responseCodeTextEdit->setPlainText(reaction->customCode()); ui->responseStepLineEdit->setText(reaction->nextStepId()); } Modified: trunk/ktutorial/ktutorial-editor/src/view/StepCustomCodeWidget.cpp =================================================================== --- trunk/ktutorial/ktutorial-editor/src/view/StepCustomCodeWidget.cpp 2010-09-26 21:07:06 UTC (rev 262) +++ trunk/ktutorial/ktutorial-editor/src/view/StepCustomCodeWidget.cpp 2010-09-27 16:17:07 UTC (rev 263) @@ -36,7 +36,7 @@ ui->setupUi(this); if (type == Setup) { - ui->customCodeTextEdit->setText(step->customSetupCode()); + ui->customCodeTextEdit->setPlainText(step->customSetupCode()); ui->customCodeGroupBox->setTitle(i18nc("@title", "Step setup code")); setWindowTitle(i18nc("@title", "Set the step setup code")); setWhatsThis(i18nc("@info:whatsthis", "<para>Set the code to be " @@ -46,7 +46,7 @@ "must be written in the same programming language the tutorial will be " "exported to.</para>")); } else { - ui->customCodeTextEdit->setText(step->customTearDownCode()); + ui->customCodeTextEdit->setPlainText(step->customTearDownCode()); ui->customCodeGroupBox->setTitle(i18nc("@title", "Step tear down code")); setWindowTitle(i18nc("@title", "Set the step tear down code")); Modified: trunk/ktutorial/ktutorial-editor/src/view/StepDataWidget.cpp =================================================================== --- trunk/ktutorial/ktutorial-editor/src/view/StepDataWidget.cpp 2010-09-26 21:07:06 UTC (rev 262) +++ trunk/ktutorial/ktutorial-editor/src/view/StepDataWidget.cpp 2010-09-27 16:17:07 UTC (rev 263) @@ -31,7 +31,7 @@ ui->setupUi(this); ui->idLineEdit->setText(step->id()); - ui->textTextEdit->setText(step->text()); + ui->textTextEdit->setPlainText(step->text()); } StepDataWidget::~StepDataWidget() { Modified: trunk/ktutorial/ktutorial-editor/src/view/TutorialCustomCodeWidget.cpp =================================================================== --- trunk/ktutorial/ktutorial-editor/src/view/TutorialCustomCodeWidget.cpp 2010-09-26 21:07:06 UTC (rev 262) +++ trunk/ktutorial/ktutorial-editor/src/view/TutorialCustomCodeWidget.cpp 2010-09-27 16:17:07 UTC (rev 263) @@ -36,7 +36,7 @@ ui->setupUi(this); if (type == Setup) { - ui->customCodeTextEdit->setText(tutorial->customSetupCode()); + ui->customCodeTextEdit->setPlainText(tutorial->customSetupCode()); ui->customCodeGroupBox->setTitle(i18nc("@title", "Tutorial setup code")); setWindowTitle(i18nc("@title", "Set the tutorial setup code")); @@ -47,7 +47,7 @@ "must be written in the same programming language the tutorial will be " "exported to.</para>")); } else { - ui->customCodeTextEdit->setText(tutorial->customTearDownCode()); + ui->customCodeTextEdit->setPlainText(tutorial->customTearDownCode()); ui->customCodeGroupBox->setTitle(i18nc("@title", "Tutorial tear down code")); setWindowTitle(i18nc("@title", "Set the tutorial tear down code")); Modified: trunk/ktutorial/ktutorial-editor/src/view/TutorialInformationWidget.cpp =================================================================== --- trunk/ktutorial/ktutorial-editor/src/view/TutorialInformationWidget.cpp 2010-09-26 21:07:06 UTC (rev 262) +++ trunk/ktutorial/ktutorial-editor/src/view/TutorialInformationWidget.cpp 2010-09-27 16:17:07 UTC (rev 263) @@ -32,7 +32,7 @@ ui->setupUi(this); ui->nameLineEdit->setText(tutorial->name()); - ui->descriptionTextEdit->setText(tutorial->description()); + ui->descriptionTextEdit->setPlainText(tutorial->description()); } TutorialInformationWidget::~TutorialInformationWidget() { Modified: trunk/ktutorial/ktutorial-editor/tests/unit/view/LicenseWidgetTest.cpp =================================================================== --- trunk/ktutorial/ktutorial-editor/tests/unit/view/LicenseWidgetTest.cpp 2010-09-26 21:07:06 UTC (rev 262) +++ trunk/ktutorial/ktutorial-editor/tests/unit/view/LicenseWidgetTest.cpp 2010-09-27 16:17:07 UTC (rev 263) @@ -31,6 +31,7 @@ private slots: void testConstructor(); + void testConstructorWithRichText(); void testSaveChanges(); @@ -51,6 +52,18 @@ QCOMPARE(licenseTextEdit(widget)->toPlainText(), QString("The license")); } +void LicenseWidgetTest::testConstructorWithRichText() { + Tutorial tutorial; + tutorial.setLicenseText("<p>The license</p>"); + + QWidget parent; + LicenseWidget* widget = new LicenseWidget(&tutorial, &parent); + + QCOMPARE(widget->parentWidget(), &parent); + QCOMPARE(licenseTextEdit(widget)->toPlainText(), + QString("<p>The license</p>")); +} + void LicenseWidgetTest::testSaveChanges() { Tutorial tutorial; tutorial.setLicenseText("The license"); Modified: trunk/ktutorial/ktutorial-editor/tests/unit/view/ReactionWidgetTest.cpp =================================================================== --- trunk/ktutorial/ktutorial-editor/tests/unit/view/ReactionWidgetTest.cpp 2010-09-26 21:07:06 UTC (rev 262) +++ trunk/ktutorial/ktutorial-editor/tests/unit/view/ReactionWidgetTest.cpp 2010-09-27 16:17:07 UTC (rev 263) @@ -41,6 +41,7 @@ private slots: void testConstructor(); + void testConstructorWithRichText(); void testSelectTriggerTypeOption(); void testSelectTriggerTypeCondition(); @@ -101,6 +102,36 @@ QString("The custom code")); } +void ReactionWidgetTest::testConstructorWithRichText() { + WaitFor* waitFor = new WaitForSignal(); + Reaction reaction; + reaction.setTriggerType(Reaction::ConditionMet); + reaction.setWaitFor(waitFor); + reaction.setOptionName("The option name"); + reaction.setResponseType(Reaction::CustomCode); + reaction.setCustomCode("<p>The custom code</p>"); + reaction.setNextStepId("The step id"); + + QWidget parent; + ReactionWidget* widget = new ReactionWidget(&reaction, &parent); + + QCOMPARE(widget->parentWidget(), &parent); + QVERIFY(!triggerOptionRadioButton(widget)->isChecked()); + QVERIFY(!triggerOptionLineEdit(widget)->isEnabled()); + QCOMPARE(triggerOptionLineEdit(widget)->text(), QString("The option name")); + QVERIFY(triggerConditionRadioButton(widget)->isChecked()); + QVERIFY(triggerConditionWidget(widget)->isEnabled()); + QVERIFY(triggerConditionWidget(widget)->waitFor() != waitFor); + QVERIFY(*triggerConditionWidget(widget)->waitFor() == *waitFor); + QVERIFY(!responseStepRadioButton(widget)->isChecked()); + QVERIFY(!responseStepLineEdit(widget)->isEnabled()); + QCOMPARE(responseStepLineEdit(widget)->text(), QString("The step id")); + QVERIFY(responseCodeRadioButton(widget)->isChecked()); + QVERIFY(responseCodeTextEdit(widget)->isEnabled()); + QCOMPARE(responseCodeTextEdit(widget)->toPlainText(), + QString("<p>The custom code</p>")); +} + void ReactionWidgetTest::testSelectTriggerTypeOption() { Reaction reaction; reaction.setTriggerType(Reaction::ConditionMet); Modified: trunk/ktutorial/ktutorial-editor/tests/unit/view/StepCustomCodeWidgetTest.cpp =================================================================== --- trunk/ktutorial/ktutorial-editor/tests/unit/view/StepCustomCodeWidgetTest.cpp 2010-09-26 21:07:06 UTC (rev 262) +++ trunk/ktutorial/ktutorial-editor/tests/unit/view/StepCustomCodeWidgetTest.cpp 2010-09-27 16:17:07 UTC (rev 263) @@ -31,7 +31,9 @@ private slots: void testConstructorSetup(); + void testConstructorSetupWithRichText(); void testConstructorTearDown(); + void testConstructorTearDownWithRichText(); void testSaveChangesSetup(); void testSaveChangesTearDown(); @@ -57,6 +59,21 @@ QString("The setup code")); } +void StepCustomCodeWidgetTest::testConstructorSetupWithRichText() { + Step step; + step.setCustomSetupCode("<p>The setup code</p>"); + + QWidget parent; + StepCustomCodeWidget* widget = + new StepCustomCodeWidget(&step, + StepCustomCodeWidget::Setup, + &parent); + + QCOMPARE(widget->parentWidget(), &parent); + QCOMPARE(customCodeTextEdit(widget)->toPlainText(), + QString("<p>The setup code</p>")); +} + void StepCustomCodeWidgetTest::testConstructorTearDown() { Step step; step.setCustomTearDownCode("The tear down code"); @@ -72,6 +89,21 @@ QString("The tear down code")); } +void StepCustomCodeWidgetTest::testConstructorTearDownWithRichText() { + Step step; + step.setCustomTearDownCode("<p>The tear down code</p>"); + + QWidget parent; + StepCustomCodeWidget* widget = + new StepCustomCodeWidget(&step, + StepCustomCodeWidget::TearDown, + &parent); + + QCOMPARE(widget->parentWidget(), &parent); + QCOMPARE(customCodeTextEdit(widget)->toPlainText(), + QString("<p>The tear down code</p>")); +} + void StepCustomCodeWidgetTest::testSaveChangesSetup() { Step step; step.setCustomSetupCode("The setup code"); Modified: trunk/ktutorial/ktutorial-editor/tests/unit/view/StepDataWidgetTest.cpp =================================================================== --- trunk/ktutorial/ktutorial-editor/tests/unit/view/StepDataWidgetTest.cpp 2010-09-26 21:07:06 UTC (rev 262) +++ trunk/ktutorial/ktutorial-editor/tests/unit/view/StepDataWidgetTest.cpp 2010-09-27 16:17:07 UTC (rev 263) @@ -31,6 +31,7 @@ private slots: void testConstructor(); + void testConstructorWithRichText(); void testSaveChanges(); @@ -54,6 +55,19 @@ QCOMPARE(textTextEdit(widget)->toPlainText(), QString("The text")); } +void StepDataWidgetTest::testConstructorWithRichText() { + Step step; + step.setId("The id"); + step.setText("<p>The text</p>"); + + QWidget parent; + StepDataWidget* widget = new StepDataWidget(&step, &parent); + + QCOMPARE(widget->parentWidget(), &parent); + QCOMPARE(idLineEdit(widget)->text(), QString("The id")); + QCOMPARE(textTextEdit(widget)->toPlainText(), QString("<p>The text</p>")); +} + void StepDataWidgetTest::testSaveChanges() { Step step; step.setId("The id"); Modified: trunk/ktutorial/ktutorial-editor/tests/unit/view/TutorialCustomCodeWidgetTest.cpp =================================================================== --- trunk/ktutorial/ktutorial-editor/tests/unit/view/TutorialCustomCodeWidgetTest.cpp 2010-09-26 21:07:06 UTC (rev 262) +++ trunk/ktutorial/ktutorial-editor/tests/unit/view/TutorialCustomCodeWidgetTest.cpp 2010-09-27 16:17:07 UTC (rev 263) @@ -31,7 +31,9 @@ private slots: void testConstructorSetup(); + void testConstructorSetupWithRichText(); void testConstructorTearDown(); + void testConstructorTearDownWithRichText(); void testSaveChangesSetup(); void testSaveChangesTearDown(); @@ -57,6 +59,21 @@ QString("The setup code")); } +void TutorialCustomCodeWidgetTest::testConstructorSetupWithRichText() { + Tutorial tutorial; + tutorial.setCustomSetupCode("<p>The setup code</p>"); + + QWidget parent; + TutorialCustomCodeWidget* widget = + new TutorialCustomCodeWidget(&tutorial, + TutorialCustomCodeWidget::Setup, + &parent); + + QCOMPARE(widget->parentWidget(), &parent); + QCOMPARE(customCodeTextEdit(widget)->toPlainText(), + QString("<p>The setup code</p>")); +} + void TutorialCustomCodeWidgetTest::testConstructorTearDown() { Tutorial tutorial; tutorial.setCustomTearDownCode("The tear down code"); @@ -72,6 +89,21 @@ QString("The tear down code")); } +void TutorialCustomCodeWidgetTest::testConstructorTearDownWithRichText() { + Tutorial tutorial; + tutorial.setCustomTearDownCode("<p>The tear down code</p>"); + + QWidget parent; + TutorialCustomCodeWidget* widget = + new TutorialCustomCodeWidget(&tutorial, + TutorialCustomCodeWidget::TearDown, + &parent); + + QCOMPARE(widget->parentWidget(), &parent); + QCOMPARE(customCodeTextEdit(widget)->toPlainText(), + QString("<p>The tear down code</p>")); +} + void TutorialCustomCodeWidgetTest::testSaveChangesSetup() { Tutorial tutorial; tutorial.setCustomSetupCode("The setup code"); Modified: trunk/ktutorial/ktutorial-editor/tests/unit/view/TutorialInformationWidgetTest.cpp =================================================================== --- trunk/ktutorial/ktutorial-editor/tests/unit/view/TutorialInformationWidgetTest.cpp 2010-09-26 21:07:06 UTC (rev 262) +++ trunk/ktutorial/ktutorial-editor/tests/unit/view/TutorialInformationWidgetTest.cpp 2010-09-27 16:17:07 UTC (rev 263) @@ -31,6 +31,7 @@ private slots: void testConstructor(); + void testConstructorWithRichText(); void testSaveChanges(); @@ -56,6 +57,21 @@ QString("The description")); } +void TutorialInformationWidgetTest::testConstructorWithRichText() { + Tutorial tutorial; + tutorial.setName("The name"); + tutorial.setDescription("<p>The description</p>"); + + QWidget parent; + TutorialInformationWidget* widget = new TutorialInformationWidget(&tutorial, + &parent); + + QCOMPARE(widget->parentWidget(), &parent); + QCOMPARE(nameLineEdit(widget)->text(), QString("The name")); + QCOMPARE(descriptionTextEdit(widget)->toPlainText(), + QString("<p>The description</p>")); +} + void TutorialInformationWidgetTest::testSaveChanges() { Tutorial tutorial; tutorial.setName("The name"); This was sent by the SourceForge.net collaborative development platform, the world's largest Open Source development site. |
From: <dan...@us...> - 2010-09-26 21:07:12
|
Revision: 262 http://ktutorial.svn.sourceforge.net/ktutorial/?rev=262&view=rev Author: danxuliu Date: 2010-09-26 21:07:06 +0000 (Sun, 26 Sep 2010) Log Message: ----------- Set object name for Ok and Cancel buttons in EditionDialog. Modified Paths: -------------- trunk/ktutorial/ktutorial-editor/src/view/EditionDialog.cpp Modified: trunk/ktutorial/ktutorial-editor/src/view/EditionDialog.cpp =================================================================== --- trunk/ktutorial/ktutorial-editor/src/view/EditionDialog.cpp 2010-09-26 21:00:50 UTC (rev 261) +++ trunk/ktutorial/ktutorial-editor/src/view/EditionDialog.cpp 2010-09-26 21:07:06 UTC (rev 262) @@ -19,6 +19,7 @@ #include "EditionDialog.h" #include <KLocalizedString> +#include <KPushButton> #include "EditionWidget.h" @@ -36,6 +37,9 @@ setModal(true); setButtons(KDialog::Ok | KDialog::Cancel); + + button(KDialog::Ok)->setObjectName("okButton"); + button(KDialog::Cancel)->setObjectName("cancelButton"); } //protected slots: This was sent by the SourceForge.net collaborative development platform, the world's largest Open Source development site. |
From: <dan...@us...> - 2010-09-26 21:00:56
|
Revision: 261 http://ktutorial.svn.sourceforge.net/ktutorial/?rev=261&view=rev Author: danxuliu Date: 2010-09-26 21:00:50 +0000 (Sun, 26 Sep 2010) Log Message: ----------- Set a different object name for each EditionDialog based on the CommandWidget it contains. Modified Paths: -------------- trunk/ktutorial/ktutorial-editor/src/EditActions.cpp trunk/ktutorial/ktutorial-editor/src/view/WaitForWidget.cpp trunk/ktutorial/ktutorial-editor/tests/unit/view/WaitForWidgetTest.cpp Modified: trunk/ktutorial/ktutorial-editor/src/EditActions.cpp =================================================================== --- trunk/ktutorial/ktutorial-editor/src/EditActions.cpp 2010-09-26 18:49:53 UTC (rev 260) +++ trunk/ktutorial/ktutorial-editor/src/EditActions.cpp 2010-09-26 21:00:50 UTC (rev 261) @@ -228,8 +228,11 @@ int EditActions::showEditionDialog(CommandWidget* commandWidget) { commandWidget->setUndoStack(mUndoStack); + QString dialogName = commandWidget->objectName(); + dialogName.replace("Widget", "Dialog"); + EditionDialog* dialog = new EditionDialog(commandWidget, mTutorialEditor); - dialog->setObjectName("editionDialog"); + dialog->setObjectName(dialogName); return DialogRunner(dialog).exec(); } Modified: trunk/ktutorial/ktutorial-editor/src/view/WaitForWidget.cpp =================================================================== --- trunk/ktutorial/ktutorial-editor/src/view/WaitForWidget.cpp 2010-09-26 18:49:53 UTC (rev 260) +++ trunk/ktutorial/ktutorial-editor/src/view/WaitForWidget.cpp 2010-09-26 21:00:50 UTC (rev 261) @@ -240,8 +240,11 @@ Q_ASSERT(editionWidget); + QString dialogName = "edit" + editionWidget->objectName(); + dialogName.replace("Widget", "Dialog"); + EditionDialog* dialog = new EditionDialog(editionWidget, this); - dialog->setObjectName("editionDialog"); + dialog->setObjectName(dialogName); DialogRunner(dialog).exec(); } Modified: trunk/ktutorial/ktutorial-editor/tests/unit/view/WaitForWidgetTest.cpp =================================================================== --- trunk/ktutorial/ktutorial-editor/tests/unit/view/WaitForWidgetTest.cpp 2010-09-26 18:49:53 UTC (rev 260) +++ trunk/ktutorial/ktutorial-editor/tests/unit/view/WaitForWidgetTest.cpp 2010-09-26 21:00:50 UTC (rev 261) @@ -405,7 +405,8 @@ QVERIFY(eventNameLineEdit); eventNameLineEdit->setText("The new event name"); - EditionDialog* dialog = mWidget->findChild<EditionDialog*>("editionDialog"); + EditionDialog* dialog = + mWidget->findChild<EditionDialog*>("editWaitForEventDialog"); QVERIFY(dialog); dialog->button(KDialog::Ok)->click(); } @@ -425,7 +426,8 @@ QVERIFY(signalNameLineEdit); signalNameLineEdit->setText("The new signal name"); - EditionDialog* dialog = mWidget->findChild<EditionDialog*>("editionDialog"); + EditionDialog* dialog = + mWidget->findChild<EditionDialog*>("editWaitForSignalDialog"); QVERIFY(dialog); dialog->button(KDialog::Ok)->click(); } @@ -440,7 +442,8 @@ QVERIFY(windowObjectNameLineEdit); windowObjectNameLineEdit->setText("The new window object name"); - EditionDialog* dialog = mWidget->findChild<EditionDialog*>("editionDialog"); + EditionDialog* dialog = + mWidget->findChild<EditionDialog*>("editWaitForWindowDialog"); QVERIFY(dialog); dialog->button(KDialog::Ok)->click(); } This was sent by the SourceForge.net collaborative development platform, the world's largest Open Source development site. |
From: <dan...@us...> - 2010-09-26 18:49:59
|
Revision: 260 http://ktutorial.svn.sourceforge.net/ktutorial/?rev=260&view=rev Author: danxuliu Date: 2010-09-26 18:49:53 +0000 (Sun, 26 Sep 2010) Log Message: ----------- Fix clone() tests in WaitForEvent and WaitForSignal, as the asserts were worthless if the attributes of the object to clone had the default value. Modified Paths: -------------- trunk/ktutorial/ktutorial-editor/tests/unit/data/WaitForEventTest.cpp trunk/ktutorial/ktutorial-editor/tests/unit/data/WaitForSignalTest.cpp Modified: trunk/ktutorial/ktutorial-editor/tests/unit/data/WaitForEventTest.cpp =================================================================== --- trunk/ktutorial/ktutorial-editor/tests/unit/data/WaitForEventTest.cpp 2010-09-26 18:27:32 UTC (rev 259) +++ trunk/ktutorial/ktutorial-editor/tests/unit/data/WaitForEventTest.cpp 2010-09-26 18:49:53 UTC (rev 260) @@ -82,6 +82,8 @@ void WaitForEventTest::testClone() { WaitForEvent waitForEvent; + waitForEvent.setReceiverName("The receiver name"); + waitForEvent.setEventName("The event name"); WaitForEvent* cloned = static_cast<WaitForEvent*>(waitForEvent.clone()); Modified: trunk/ktutorial/ktutorial-editor/tests/unit/data/WaitForSignalTest.cpp =================================================================== --- trunk/ktutorial/ktutorial-editor/tests/unit/data/WaitForSignalTest.cpp 2010-09-26 18:27:32 UTC (rev 259) +++ trunk/ktutorial/ktutorial-editor/tests/unit/data/WaitForSignalTest.cpp 2010-09-26 18:49:53 UTC (rev 260) @@ -82,6 +82,8 @@ void WaitForSignalTest::testClone() { WaitForSignal waitForSignal; + waitForSignal.setEmitterName("The emitter name"); + waitForSignal.setSignalName("The signal name"); WaitForSignal* cloned = static_cast<WaitForSignal*>(waitForSignal.clone()); This was sent by the SourceForge.net collaborative development platform, the world's largest Open Source development site. |
From: <dan...@us...> - 2010-09-26 18:27:38
|
Revision: 259 http://ktutorial.svn.sourceforge.net/ktutorial/?rev=259&view=rev Author: danxuliu Date: 2010-09-26 18:27:32 +0000 (Sun, 26 Sep 2010) Log Message: ----------- Minor API documentation fix. Modified Paths: -------------- trunk/ktutorial/ktutorial-editor/src/serialization/TutorialWriter.h Modified: trunk/ktutorial/ktutorial-editor/src/serialization/TutorialWriter.h =================================================================== --- trunk/ktutorial/ktutorial-editor/src/serialization/TutorialWriter.h 2010-09-26 17:49:55 UTC (rev 258) +++ trunk/ktutorial/ktutorial-editor/src/serialization/TutorialWriter.h 2010-09-26 18:27:32 UTC (rev 259) @@ -116,7 +116,7 @@ void write(const WaitForNot* waitForNot); /** - * Writes the XML serialization of the given WaitForComposed. + * Writes the XML serialization of the given WaitForSignal. * * @param waitForSignal The WaitForSignal to get its XML serialization. */ This was sent by the SourceForge.net collaborative development platform, the world's largest Open Source development site. |
From: <dan...@us...> - 2010-09-26 17:50:03
|
Revision: 258 http://ktutorial.svn.sourceforge.net/ktutorial/?rev=258&view=rev Author: danxuliu Date: 2010-09-26 17:49:55 +0000 (Sun, 26 Sep 2010) Log Message: ----------- Add support for WaitForWindow to wait for a specific window to be shown. 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/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/WaitForWindow.cpp trunk/ktutorial/ktutorial-editor/src/data/WaitForWindow.h trunk/ktutorial/ktutorial-editor/src/view/WaitForWindowTreeItem.cpp trunk/ktutorial/ktutorial-editor/src/view/WaitForWindowTreeItem.h trunk/ktutorial/ktutorial-editor/src/view/WaitForWindowWidget.cpp trunk/ktutorial/ktutorial-editor/src/view/WaitForWindowWidget.h trunk/ktutorial/ktutorial-editor/src/view/WaitForWindowWidget.ui trunk/ktutorial/ktutorial-editor/tests/unit/data/WaitForWindowTest.cpp trunk/ktutorial/ktutorial-editor/tests/unit/view/WaitForWindowTreeItemTest.cpp trunk/ktutorial/ktutorial-editor/tests/unit/view/WaitForWindowWidgetTest.cpp Modified: trunk/ktutorial/ktutorial-editor/src/data/CMakeLists.txt =================================================================== --- trunk/ktutorial/ktutorial-editor/src/data/CMakeLists.txt 2010-09-25 20:16:03 UTC (rev 257) +++ trunk/ktutorial/ktutorial-editor/src/data/CMakeLists.txt 2010-09-26 17:49:55 UTC (rev 258) @@ -7,6 +7,7 @@ WaitForEvent.cpp WaitForNot.cpp WaitForSignal.cpp + WaitForWindow.cpp ) kde4_add_library(ktutorial_editor_data ${ktutorial_editor_data_SRCS}) Added: trunk/ktutorial/ktutorial-editor/src/data/WaitForWindow.cpp =================================================================== --- trunk/ktutorial/ktutorial-editor/src/data/WaitForWindow.cpp (rev 0) +++ trunk/ktutorial/ktutorial-editor/src/data/WaitForWindow.cpp 2010-09-26 17:49:55 UTC (rev 258) @@ -0,0 +1,55 @@ +/*************************************************************************** + * Copyright (C) 2010 by Daniel Calviño Sánchez * + * dan...@gm... * + * * + * This program is free software; you can redistribute it and/or modify * + * it under the terms of the GNU General Public License as published by * + * the Free Software Foundation; either version 3 of the License, or * + * (at your option) any later version. * + * * + * This program is distributed in the hope that it will be useful, * + * but WITHOUT ANY WARRANTY; without even the implied warranty of * + * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the * + * GNU General Public License for more details. * + * * + * You should have received a copy of the GNU General Public License * + * along with this program; If not, see <http://www.gnu.org/licenses/>. * + ***************************************************************************/ + +#include "WaitForWindow.h" + +//public: + +WaitForWindow::WaitForWindow(QObject* parent): WaitFor(parent) { +} + +WaitFor* WaitForWindow::clone() const { + WaitForWindow* cloned = new WaitForWindow(); + cloned->setWindowObjectName(mWindowObjectName); + + return cloned; +} + +bool WaitForWindow::equals(const WaitFor& waitFor) const { + if (!qobject_cast<const WaitForWindow*>(&waitFor)) { + return false; + } + + const WaitForWindow* waitForWindow = + static_cast<const WaitForWindow*>(&waitFor); + if (waitForWindow->windowObjectName() != mWindowObjectName) { + return false; + } + + return true; +} + +QString WaitForWindow::windowObjectName() const { + return mWindowObjectName; +} + +void WaitForWindow::setWindowObjectName(const QString& windowObjectName) { + mWindowObjectName = windowObjectName; + + emit dataChanged(this); +} Property changes on: trunk/ktutorial/ktutorial-editor/src/data/WaitForWindow.cpp ___________________________________________________________________ Added: svn:eol-style + native Added: trunk/ktutorial/ktutorial-editor/src/data/WaitForWindow.h =================================================================== --- trunk/ktutorial/ktutorial-editor/src/data/WaitForWindow.h (rev 0) +++ trunk/ktutorial/ktutorial-editor/src/data/WaitForWindow.h 2010-09-26 17:49:55 UTC (rev 258) @@ -0,0 +1,56 @@ +/*************************************************************************** + * Copyright (C) 2010 by Daniel Calviño Sánchez * + * dan...@gm... * + * * + * This program is free software; you can redistribute it and/or modify * + * it under the terms of the GNU General Public License as published by * + * the Free Software Foundation; either version 3 of the License, or * + * (at your option) any later version. * + * * + * This program is distributed in the hope that it will be useful, * + * but WITHOUT ANY WARRANTY; without even the implied warranty of * + * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the * + * GNU General Public License for more details. * + * * + * You should have received a copy of the GNU General Public License * + * along with this program; If not, see <http://www.gnu.org/licenses/>. * + ***************************************************************************/ + +#ifndef WAITFORWINDOW_H +#define WAITFORWINDOW_H + +#include "WaitFor.h" + +/** + * Container for conditions that wait for a window to be shown data. + * It stores the data used in KTutorial WaitForWindow, 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::WaitForWindow + * object. + * + * When any attribute is modified, dataChanged(WaitFor*) signal is emitted. + */ +class WaitForWindow: public WaitFor { +Q_OBJECT +public: + + /** + * Creates a new WaitForWindow. + * + * @param parent The parent QObject. + */ + WaitForWindow(QObject* parent = 0); + + virtual WaitFor* clone() const; + virtual bool equals(const WaitFor& waitFor) const; + + QString windowObjectName() const; + void setWindowObjectName(const QString& windowObjectName); + +private: + + QString mWindowObjectName; + +}; + +#endif Property changes on: trunk/ktutorial/ktutorial-editor/src/data/WaitForWindow.h ___________________________________________________________________ Added: svn:eol-style + native Modified: trunk/ktutorial/ktutorial-editor/src/serialization/JavascriptExporter.cpp =================================================================== --- trunk/ktutorial/ktutorial-editor/src/serialization/JavascriptExporter.cpp 2010-09-25 20:16:03 UTC (rev 257) +++ trunk/ktutorial/ktutorial-editor/src/serialization/JavascriptExporter.cpp 2010-09-26 17:49:55 UTC (rev 258) @@ -28,6 +28,7 @@ #include "../data/WaitForEvent.h" #include "../data/WaitForNot.h" #include "../data/WaitForSignal.h" +#include "../data/WaitForWindow.h" //public: @@ -266,6 +267,9 @@ if (qobject_cast<const WaitForSignal*>(waitFor)) { return writeWaitFor(static_cast<const WaitForSignal*>(waitFor)); } + if (qobject_cast<const WaitForWindow*>(waitFor)) { + return writeWaitFor(static_cast<const WaitForWindow*>(waitFor)); + } return ""; } @@ -362,6 +366,24 @@ return variable; } +QString JavascriptExporter::writeWaitFor(const WaitForWindow* waitForWindow) { + if (waitForWindow->windowObjectName().isEmpty()) { + out() << "//Error: WaitForWindow without window object name!\n"; + return ""; + } + + QString variable = "waitFor" + + toUpperCamelCase(waitForWindow->windowObjectName()) + + "ToBeShown"; + variable = addVariable(variable); + + out() << variable << " = ktutorial.newWaitFor(\"WaitForWindow\");\n"; + out() << variable << ".setWindowObjectName(\"" + << escape(waitForWindow->windowObjectName()) << "\");\n"; + + return variable; +} + QTextStream& JavascriptExporter::out() { mOut << indentation(); return mOut; Modified: trunk/ktutorial/ktutorial-editor/src/serialization/JavascriptExporter.h =================================================================== --- trunk/ktutorial/ktutorial-editor/src/serialization/JavascriptExporter.h 2010-09-25 20:16:03 UTC (rev 257) +++ trunk/ktutorial/ktutorial-editor/src/serialization/JavascriptExporter.h 2010-09-26 17:49:55 UTC (rev 258) @@ -31,6 +31,7 @@ class WaitForEvent; class WaitForNot; class WaitForSignal; +class WaitForWindow; /** * Exporter of tutorials to Javascript code. @@ -214,6 +215,16 @@ QString writeWaitFor(const WaitForSignal* waitForSignal); /** + * 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. + * + * @param waitForWindow The WaitForWindow. + * @return The name of the variable that holds the WaitFor. + */ + QString writeWaitFor(const WaitForWindow* waitForWindow); + + /** * Returns the output stream after adding the identation text. * It is used as a shortcut to "mOut << indentation()". Use it to output any * line that has no previous indentation. Modified: trunk/ktutorial/ktutorial-editor/src/serialization/TutorialReader.cpp =================================================================== --- trunk/ktutorial/ktutorial-editor/src/serialization/TutorialReader.cpp 2010-09-25 20:16:03 UTC (rev 257) +++ trunk/ktutorial/ktutorial-editor/src/serialization/TutorialReader.cpp 2010-09-26 17:49:55 UTC (rev 258) @@ -29,6 +29,7 @@ #include "../data/WaitForEvent.h" #include "../data/WaitForNot.h" #include "../data/WaitForSignal.h" +#include "../data/WaitForWindow.h" //public: @@ -167,6 +168,9 @@ if (element.tagName() == "waitForSignal") { return readWaitForSignal(element); } + if (element.tagName() == "waitForWindow") { + return readWaitForWindow(element); + } Q_ASSERT(false); return 0; @@ -238,11 +242,23 @@ return waitForSignal; } +WaitFor* TutorialReader::readWaitForWindow(const QDomElement& element) { + WaitForWindow* waitForWindow = new WaitForWindow(); + + if (element.hasAttribute("windowObjectName")) { + waitForWindow->setWindowObjectName( + element.attribute("windowObjectName")); + } + + return waitForWindow; +} + bool TutorialReader::isWaitForElement(const QDomElement& element) { if (element.tagName() != "waitForComposed" && element.tagName() != "waitForEvent" && element.tagName() != "waitForNot" && - element.tagName() != "waitForSignal") { + 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 2010-09-25 20:16:03 UTC (rev 257) +++ trunk/ktutorial/ktutorial-editor/src/serialization/TutorialReader.h 2010-09-26 17:49:55 UTC (rev 258) @@ -32,6 +32,7 @@ class WaitForEvent; class WaitForNot; class WaitForSignal; +class WaitForWindow; /** * Deserializer for tutorials stored in XML. @@ -135,6 +136,14 @@ WaitFor* readWaitForSignal(const QDomElement& element); /** + * Reads a new WaitForWindow from the "waitForWindow" XML element. + * + * @param element The element to read the WaitForWindow from. + * @return The new WaitForWindow. + */ + WaitFor* readWaitForWindow(const QDomElement& element); + + /** * Returns whether the given element is one of the WaitFor elements or not. * * @param element The element to check. Modified: trunk/ktutorial/ktutorial-editor/src/serialization/TutorialWriter.cpp =================================================================== --- trunk/ktutorial/ktutorial-editor/src/serialization/TutorialWriter.cpp 2010-09-25 20:16:03 UTC (rev 257) +++ trunk/ktutorial/ktutorial-editor/src/serialization/TutorialWriter.cpp 2010-09-26 17:49:55 UTC (rev 258) @@ -25,6 +25,7 @@ #include "../data/WaitForEvent.h" #include "../data/WaitForNot.h" #include "../data/WaitForSignal.h" +#include "../data/WaitForWindow.h" //public: @@ -152,6 +153,10 @@ write(static_cast<const WaitForSignal*>(waitFor)); return; } + if (qobject_cast<const WaitForWindow*>(waitFor)) { + write(static_cast<const WaitForWindow*>(waitFor)); + return; + } } void TutorialWriter::write(const WaitForComposed* waitForComposed) { @@ -204,3 +209,12 @@ mXmlWriter->writeAttribute("signalName", waitForSignal->signalName()); } } + +void TutorialWriter::write(const WaitForWindow* waitForWindow) { + mXmlWriter->writeEmptyElement("waitForWindow"); + + if (!waitForWindow->windowObjectName().isEmpty()) { + mXmlWriter->writeAttribute("windowObjectName", + waitForWindow->windowObjectName()); + } +} Modified: trunk/ktutorial/ktutorial-editor/src/serialization/TutorialWriter.h =================================================================== --- trunk/ktutorial/ktutorial-editor/src/serialization/TutorialWriter.h 2010-09-25 20:16:03 UTC (rev 257) +++ trunk/ktutorial/ktutorial-editor/src/serialization/TutorialWriter.h 2010-09-26 17:49:55 UTC (rev 258) @@ -29,6 +29,7 @@ class WaitForEvent; class WaitForNot; class WaitForSignal; +class WaitForWindow; /** * Serializes a Tutorial in XML. @@ -121,6 +122,13 @@ */ void write(const WaitForSignal* waitForSignal); + /** + * Writes the XML serialization of the given WaitForWindow. + * + * @param waitForWindow The WaitForWindow to get its XML serialization. + */ + void write(const WaitForWindow* waitForWindow); + }; #endif Modified: trunk/ktutorial/ktutorial-editor/src/view/CMakeLists.txt =================================================================== --- trunk/ktutorial/ktutorial-editor/src/view/CMakeLists.txt 2010-09-25 20:16:03 UTC (rev 257) +++ trunk/ktutorial/ktutorial-editor/src/view/CMakeLists.txt 2010-09-26 17:49:55 UTC (rev 258) @@ -28,6 +28,8 @@ WaitForSignalWidget.cpp WaitForTreeItem.cpp WaitForWidget.cpp + WaitForWindowTreeItem.cpp + WaitForWindowWidget.cpp ) if (QT_QTDBUS_FOUND) @@ -54,6 +56,7 @@ WaitForEventWidget.ui WaitForSignalWidget.ui WaitForWidget.ui + WaitForWindowWidget.ui ) if (QT_QTDBUS_FOUND) Modified: trunk/ktutorial/ktutorial-editor/src/view/NewWaitForWidget.cpp =================================================================== --- trunk/ktutorial/ktutorial-editor/src/view/NewWaitForWidget.cpp 2010-09-25 20:16:03 UTC (rev 257) +++ trunk/ktutorial/ktutorial-editor/src/view/NewWaitForWidget.cpp 2010-09-26 17:49:55 UTC (rev 258) @@ -23,6 +23,7 @@ #include "../data/WaitForEvent.h" #include "../data/WaitForNot.h" #include "../data/WaitForSignal.h" +#include "../data/WaitForWindow.h" //public: @@ -52,6 +53,8 @@ return new WaitForSignal(); } else if (index == 4) { return new WaitForEvent(); + } else if (index == 5) { + return new WaitForWindow(); } return 0; Modified: trunk/ktutorial/ktutorial-editor/src/view/NewWaitForWidget.ui =================================================================== --- trunk/ktutorial/ktutorial-editor/src/view/NewWaitForWidget.ui 2010-09-25 20:16:03 UTC (rev 257) +++ trunk/ktutorial/ktutorial-editor/src/view/NewWaitForWidget.ui 2010-09-26 17:49:55 UTC (rev 258) @@ -66,6 +66,11 @@ <string comment="@item:inlistbox">The specified event is received</string> </property> </item> + <item> + <property name="text"> + <string comment="@item:inlistbox">The specified window is shown</string> + </property> + </item> </widget> </item> </layout> Modified: trunk/ktutorial/ktutorial-editor/src/view/WaitForTreeItem.cpp =================================================================== --- trunk/ktutorial/ktutorial-editor/src/view/WaitForTreeItem.cpp 2010-09-25 20:16:03 UTC (rev 257) +++ trunk/ktutorial/ktutorial-editor/src/view/WaitForTreeItem.cpp 2010-09-26 17:49:55 UTC (rev 258) @@ -21,10 +21,12 @@ #include "WaitForEventTreeItem.h" #include "WaitForNotTreeItem.h" #include "WaitForSignalTreeItem.h" +#include "WaitForWindowTreeItem.h" #include "../data/WaitForComposed.h" #include "../data/WaitForEvent.h" #include "../data/WaitForNot.h" #include "../data/WaitForSignal.h" +#include "../data/WaitForWindow.h" //public: @@ -50,6 +52,11 @@ parent); } + if (qobject_cast<WaitForWindow*>(waitFor)) { + return new WaitForWindowTreeItem(static_cast<WaitForWindow*>(waitFor), + parent); + } + Q_ASSERT(false); return 0; } Modified: trunk/ktutorial/ktutorial-editor/src/view/WaitForWidget.cpp =================================================================== --- trunk/ktutorial/ktutorial-editor/src/view/WaitForWidget.cpp 2010-09-25 20:16:03 UTC (rev 257) +++ trunk/ktutorial/ktutorial-editor/src/view/WaitForWidget.cpp 2010-09-26 17:49:55 UTC (rev 258) @@ -26,11 +26,13 @@ #include "TreeModel.h" #include "WaitForEventWidget.h" #include "WaitForSignalWidget.h" +#include "WaitForWindowWidget.h" #include "WaitForTreeItem.h" #include "../data/WaitForComposed.h" #include "../data/WaitForEvent.h" #include "../data/WaitForNot.h" #include "../data/WaitForSignal.h" +#include "../data/WaitForWindow.h" //public: @@ -137,6 +139,14 @@ return; } + + if (qobject_cast<WaitForWindow*>(selectedWaitFor)) { + ui->addButton->setEnabled(false); + ui->editButton->setEnabled(true); + ui->removeButton->setEnabled(true); + + return; + } } //private slots: @@ -222,6 +232,12 @@ editionWidget = new WaitForSignalWidget(waitForSignal, this); } + if (qobject_cast<WaitForWindow*>(mCurrentWaitFor)) { + WaitForWindow* waitForWindow = + static_cast<WaitForWindow*>(mCurrentWaitFor); + editionWidget = new WaitForWindowWidget(waitForWindow, this); + } + Q_ASSERT(editionWidget); EditionDialog* dialog = new EditionDialog(editionWidget, this); Added: trunk/ktutorial/ktutorial-editor/src/view/WaitForWindowTreeItem.cpp =================================================================== --- trunk/ktutorial/ktutorial-editor/src/view/WaitForWindowTreeItem.cpp (rev 0) +++ trunk/ktutorial/ktutorial-editor/src/view/WaitForWindowTreeItem.cpp 2010-09-26 17:49:55 UTC (rev 258) @@ -0,0 +1,54 @@ +/*************************************************************************** + * Copyright (C) 2010 by Daniel Calviño Sánchez * + * dan...@gm... * + * * + * This program is free software; you can redistribute it and/or modify * + * it under the terms of the GNU General Public License as published by * + * the Free Software Foundation; either version 3 of the License, or * + * (at your option) any later version. * + * * + * This program is distributed in the hope that it will be useful, * + * but WITHOUT ANY WARRANTY; without even the implied warranty of * + * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the * + * GNU General Public License for more details. * + * * + * You should have received a copy of the GNU General Public License * + * along with this program; If not, see <http://www.gnu.org/licenses/>. * + ***************************************************************************/ + +#include "WaitForWindowTreeItem.h" + +#include <KLocalizedString> + +#include "../data/WaitForWindow.h" + +//public: + +WaitForWindowTreeItem::WaitForWindowTreeItem(WaitForWindow* waitForWindow, + TreeItem* parent): + WaitForTreeItem(waitForWindow, parent) { + mWindowObjectName = waitForWindow->windowObjectName(); + + connect(waitForWindow, SIGNAL(dataChanged(WaitFor*)), + this, SLOT(update(WaitFor*))); +} + +QString WaitForWindowTreeItem::text() const { + QString windowObjectName; + if (mWindowObjectName.isEmpty()) { + windowObjectName = i18nc("@item", "(object name not set)"); + } else { + windowObjectName = "\"" + mWindowObjectName + "\""; + } + + return i18nc("@item", "When the window %1 is shown", windowObjectName); +} + +//private: + +void WaitForWindowTreeItem::update(WaitFor* waitFor) { + WaitForWindow* waitForWindow = static_cast<WaitForWindow*>(waitFor); + mWindowObjectName = waitForWindow->windowObjectName(); + + emit dataChanged(this); +} Property changes on: trunk/ktutorial/ktutorial-editor/src/view/WaitForWindowTreeItem.cpp ___________________________________________________________________ Added: svn:eol-style + native Added: trunk/ktutorial/ktutorial-editor/src/view/WaitForWindowTreeItem.h =================================================================== --- trunk/ktutorial/ktutorial-editor/src/view/WaitForWindowTreeItem.h (rev 0) +++ trunk/ktutorial/ktutorial-editor/src/view/WaitForWindowTreeItem.h 2010-09-26 17:49:55 UTC (rev 258) @@ -0,0 +1,78 @@ +/*************************************************************************** + * Copyright (C) 2010 by Daniel Calviño Sánchez * + * dan...@gm... * + * * + * This program is free software; you can redistribute it and/or modify * + * it under the terms of the GNU General Public License as published by * + * the Free Software Foundation; either version 3 of the License, or * + * (at your option) any later version. * + * * + * This program is distributed in the hope that it will be useful, * + * but WITHOUT ANY WARRANTY; without even the implied warranty of * + * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the * + * GNU General Public License for more details. * + * * + * You should have received a copy of the GNU General Public License * + * along with this program; If not, see <http://www.gnu.org/licenses/>. * + ***************************************************************************/ + +#ifndef WAITFORWINDOWTREEITEM_H +#define WAITFORWINDOWTREEITEM_H + +#include "WaitForTreeItem.h" + +class WaitForWindow; + +/** + * A TreeItem that represents a WaitForWindow. + * The tree representation of a WaitForWindow is a plain text: + * When the window "object name" is shown + * + * If the window object name isn't set yet, a placeholder is put instead. The + * object name placeholder is "(object name not set)" (without quotes, but with + * parenthesis). + * + * Whenever the WaitForWindow data changes, the WaitForWindowTreeItem text is + * updated as needed. + */ +class WaitForWindowTreeItem: public WaitForTreeItem { +Q_OBJECT +public: + + /** + * Creates a new WaitForWindowTreeItem for the given WaitForWindow and with + * the given parent. + * + * @param waitForWindow The WaitForWindow to represent. + * @param parent The parent TreeItem. + */ + explicit WaitForWindowTreeItem(WaitForWindow* waitForWindow, + TreeItem* parent = 0); + + /** + * Returns the description of the WaitForWindow. + * + * @return The text for this TreeItem. + */ + virtual QString text() const; + +private: + + /** + * The window object name of the WaitForWindow. + */ + QString mWindowObjectName; + +private Q_SLOTS: + + /** + * Updates this WaitForWindowTreeItem when the data of its WaitForWindow + * changed. + * + * @param waitFor The WaitForWindow. + */ + void update(WaitFor* waitFor); + +}; + +#endif Property changes on: trunk/ktutorial/ktutorial-editor/src/view/WaitForWindowTreeItem.h ___________________________________________________________________ Added: svn:eol-style + native Added: trunk/ktutorial/ktutorial-editor/src/view/WaitForWindowWidget.cpp =================================================================== --- trunk/ktutorial/ktutorial-editor/src/view/WaitForWindowWidget.cpp (rev 0) +++ trunk/ktutorial/ktutorial-editor/src/view/WaitForWindowWidget.cpp 2010-09-26 17:49:55 UTC (rev 258) @@ -0,0 +1,65 @@ +/*************************************************************************** + * Copyright (C) 2010 by Daniel Calviño Sánchez * + * dan...@gm... * + * * + * This program is free software; you can redistribute it and/or modify * + * it under the terms of the GNU General Public License as published by * + * the Free Software Foundation; either version 3 of the License, or * + * (at your option) any later version. * + * * + * This program is distributed in the hope that it will be useful, * + * but WITHOUT ANY WARRANTY; without even the implied warranty of * + * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the * + * GNU General Public License for more details. * + * * + * You should have received a copy of the GNU General Public License * + * along with this program; If not, see <http://www.gnu.org/licenses/>. * + ***************************************************************************/ + +#include "WaitForWindowWidget.h" + +#include "ui_WaitForWindowWidget.h" +#include "../data/WaitForWindow.h" + +#ifdef QT_QTDBUS_FOUND +#include "RemoteObjectNameWidget.h" +#endif + +//public: + +WaitForWindowWidget::WaitForWindowWidget(WaitForWindow* waitForWindow, + QWidget* parent): + EditionWidget(parent), + mWaitForWindow(waitForWindow) { + + ui = new Ui::WaitForWindowWidget(); + ui->setupUi(this); + +#ifdef QT_QTDBUS_FOUND + //Replace ui->windowObjectNameLineEdit with mRemoteObjectNameWidget + ui->valueVerticalLayout->removeWidget(ui->windowObjectNameLineEdit); + delete ui->windowObjectNameLineEdit; + + mRemoteObjectNameWidget = new RemoteObjectNameWidget(this); + ui->valueVerticalLayout->insertWidget(0, mRemoteObjectNameWidget); + + mRemoteObjectNameWidget->setName(waitForWindow->windowObjectName()); +#else + ui->windowObjectNameLineEdit->setText(waitForWindow->windowObjectName()); +#endif +} + +WaitForWindowWidget::~WaitForWindowWidget() { + delete ui; +} + +void WaitForWindowWidget::saveChanges() { +#ifdef QT_QTDBUS_FOUND + QString windowObjectName = mRemoteObjectNameWidget->name(); +#else + QString windowObjectName = ui->windowObjectNameLineEdit->text(); +#endif + if (mWaitForWindow->windowObjectName() != windowObjectName) { + mWaitForWindow->setWindowObjectName(windowObjectName); + } +} Property changes on: trunk/ktutorial/ktutorial-editor/src/view/WaitForWindowWidget.cpp ___________________________________________________________________ Added: svn:eol-style + native Added: trunk/ktutorial/ktutorial-editor/src/view/WaitForWindowWidget.h =================================================================== --- trunk/ktutorial/ktutorial-editor/src/view/WaitForWindowWidget.h (rev 0) +++ trunk/ktutorial/ktutorial-editor/src/view/WaitForWindowWidget.h 2010-09-26 17:49:55 UTC (rev 258) @@ -0,0 +1,81 @@ +/*************************************************************************** + * Copyright (C) 2010 by Daniel Calviño Sánchez * + * dan...@gm... * + * * + * This program is free software; you can redistribute it and/or modify * + * it under the terms of the GNU General Public License as published by * + * the Free Software Foundation; either version 3 of the License, or * + * (at your option) any later version. * + * * + * This program is distributed in the hope that it will be useful, * + * but WITHOUT ANY WARRANTY; without even the implied warranty of * + * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the * + * GNU General Public License for more details. * + * * + * You should have received a copy of the GNU General Public License * + * along with this program; If not, see <http://www.gnu.org/licenses/>. * + ***************************************************************************/ + +#ifndef WAITFORWINDOWWIDGET_H +#define WAITFORWINDOWWIDGET_H + +#include "EditionWidget.h" + +#ifdef QT_QTDBUS_FOUND +class RemoteObjectNameWidget; +#endif + +class WaitForWindow; + +namespace Ui { +class WaitForWindowWidget; +} + +/** + * Edition widget for the condition to wait for a window to be shown. + */ +class WaitForWindowWidget: public EditionWidget { +Q_OBJECT +public: + + /** + * Creates a new WaitForWindowWidget for the given WaitForWindow. + * + * @param waitForWindow The WaitForWindow to set its data. + * @param parent The parent QWidget. + */ + explicit WaitForWindowWidget(WaitForWindow* waitForWindow, + QWidget* parent = 0); + + /** + * Destroys this widget. + */ + virtual ~WaitForWindowWidget(); + + /** + * Saves the window object name in the WaitForWindow. + */ + virtual void saveChanges(); + +private: + + /** + * The WaitForWindow to edit. + */ + WaitForWindow* mWaitForWindow; + + /** + * The Ui Designer generated class. + */ + Ui::WaitForWindowWidget* 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/WaitForWindowWidget.h ___________________________________________________________________ Added: svn:eol-style + native Added: trunk/ktutorial/ktutorial-editor/src/view/WaitForWindowWidget.ui =================================================================== --- trunk/ktutorial/ktutorial-editor/src/view/WaitForWindowWidget.ui (rev 0) +++ trunk/ktutorial/ktutorial-editor/src/view/WaitForWindowWidget.ui 2010-09-26 17:49:55 UTC (rev 258) @@ -0,0 +1,80 @@ +<?xml version="1.0" encoding="UTF-8"?> +<ui version="4.0"> + <class>WaitForWindowWidget</class> + <widget class="QWidget" name="WaitForWindowWidget"> + <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 window to wait for</string> + </property> + <property name="whatsThis"> + <string comment="@info:whatsthis"><para>Set the object name of the window to wait for.</para></string> + </property> + <layout class="QVBoxLayout" name="WaitForWindowVerticalLayout"> + <item> + <widget class="QGroupBox" name="waitForWindowGroupBox"> + <property name="title"> + <string comment="@title:group">Wait for window</string> + </property> + <layout class="QHBoxLayout" name="waitForWindowGroupBoxHorizontalLayout"> + <item> + <layout class="QVBoxLayout" name="labelVerticalLayout"> + <item> + <widget class="QLabel" name="windowObjectNameLabel"> + <property name="text"> + <string comment="@label:textbox">Window name:</string> + </property> + <property name="alignment"> + <set>Qt::AlignRight|Qt::AlignTrailing|Qt::AlignVCenter</set> + </property> + </widget> + </item> + </layout> + </item> + <item> + <layout class="QVBoxLayout" name="valueVerticalLayout"> + <item> + <widget class="KLineEdit" name="windowObjectNameLineEdit"> + <property name="whatsThis"> + <string comment="@info:whatsthis"><para>The name of the window to be shown.</para> +<para>Note that the name is not the title of the window or its class name, but the string returned by its objectName() method.</para> +<para>Also note that it can wait either for windows or for dialogs, not just for windows.</para></string> + </property> + </widget> + </item> + </layout> + </item> + </layout> + </widget> + </item> + <item> + <spacer name="waitForWindowWidgetSpacer"> + <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/tests/unit/data/CMakeLists.txt =================================================================== --- trunk/ktutorial/ktutorial-editor/tests/unit/data/CMakeLists.txt 2010-09-25 20:16:03 UTC (rev 257) +++ trunk/ktutorial/ktutorial-editor/tests/unit/data/CMakeLists.txt 2010-09-26 17:49:55 UTC (rev 258) @@ -20,6 +20,7 @@ WaitForEvent WaitForNot WaitForSignal + WaitForWindow ) MACRO(MEM_TESTS) @@ -37,4 +38,5 @@ WaitForEvent WaitForNot WaitForSignal + WaitForWindow ) Added: trunk/ktutorial/ktutorial-editor/tests/unit/data/WaitForWindowTest.cpp =================================================================== --- trunk/ktutorial/ktutorial-editor/tests/unit/data/WaitForWindowTest.cpp (rev 0) +++ trunk/ktutorial/ktutorial-editor/tests/unit/data/WaitForWindowTest.cpp 2010-09-26 17:49:55 UTC (rev 258) @@ -0,0 +1,139 @@ +/*************************************************************************** + * Copyright (C) 2010 by Daniel Calviño Sánchez * + * dan...@gm... * + * * + * This program is free software; you can redistribute it and/or modify * + * it under the terms of the GNU General Public License as published by * + * the Free Software Foundation; either version 3 of the License, or * + * (at your option) any later version. * + * * + * This program is distributed in the hope that it will be useful, * + * but WITHOUT ANY WARRANTY; without even the implied warranty of * + * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the * + * GNU General Public License for more details. * + * * + * You should have received a copy of the GNU General Public License * + * along with this program; If not, see <http://www.gnu.org/licenses/>. * + ***************************************************************************/ + +#include <QtTest> + +#include "WaitForWindow.h" + +class WaitForWindowTest: public QObject { +Q_OBJECT + +private slots: + + void initTestCase(); + + void testConstructor(); + + void testClone(); + + void testEquals(); + + void testSetWindowObjectName(); + +private: + + int mWaitForStarType; + + void assertWaitForWindow(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 WaitForWindowTest::initTestCase() { + //WaitFor* must be registered in order to be used with QSignalSpy + mWaitForStarType = qRegisterMetaType<WaitFor*>("WaitFor*"); +} + +void WaitForWindowTest::testConstructor() { + QObject parent; + WaitForWindow* waitForWindow = new WaitForWindow(&parent); + + QCOMPARE(waitForWindow->parent(), &parent); +} + +void WaitForWindowTest::testClone() { + WaitForWindow waitForWindow; + waitForWindow.setWindowObjectName("The window object name"); + + WaitForWindow* cloned = static_cast<WaitForWindow*>(waitForWindow.clone()); + + QVERIFY(cloned != &waitForWindow); + QCOMPARE(cloned->windowObjectName(), waitForWindow.windowObjectName()); + delete cloned; +} + +void WaitForWindowTest::testEquals() { + WaitForWindow waitForWindow1; + waitForWindow1.setWindowObjectName("The window object name"); + WaitForWindow waitForWindow2; + + QCOMPARE(waitForWindow1 == waitForWindow2, false); + QCOMPARE(waitForWindow2 == waitForWindow1, false); + + waitForWindow2.setWindowObjectName("The window object name"); + + QCOMPARE(waitForWindow1 == waitForWindow2, true); + QCOMPARE(waitForWindow2 == waitForWindow1, true); + + StubWaitFor stubWaitFor; + + QCOMPARE(waitForWindow1 == stubWaitFor, false); +} + +void WaitForWindowTest::testSetWindowObjectName() { + WaitForWindow waitForWindow; + + QSignalSpy dataChangedSpy(&waitForWindow, SIGNAL(dataChanged(WaitFor*))); + + waitForWindow.setWindowObjectName("The window object name"); + + QCOMPARE(waitForWindow.windowObjectName(), + QString("The window object name")); + QCOMPARE(dataChangedSpy.count(), 1); + assertWaitForWindow(dataChangedSpy, 0, &waitForWindow); +} + +//WaitFor* must be declared as a metatype to be used in qvariant_cast +Q_DECLARE_METATYPE(WaitFor*); + +/////////////////////////////////// Helpers //////////////////////////////////// + +void WaitForWindowTest::assertWaitForWindow(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(WaitForWindowTest) + +#include "WaitForWindowTest.moc" Property changes on: trunk/ktutorial/ktutorial-editor/tests/unit/data/WaitForWindowTest.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 2010-09-25 20:16:03 UTC (rev 257) +++ trunk/ktutorial/ktutorial-editor/tests/unit/serialization/JavascriptExporterTest.cpp 2010-09-26 17:49:55 UTC (rev 258) @@ -27,6 +27,7 @@ #include "../data/WaitForEvent.h" #include "../data/WaitForNot.h" #include "../data/WaitForSignal.h" +#include "../data/WaitForWindow.h" #define TUTORIAL_EMPTY_INFORMATION_CODE \ "t = Kross.module(\"kdetranslation\");\n"\ @@ -89,6 +90,9 @@ void testWaitForSignal(); void testWaitForSignalWithEscapeSequences(); void testWaitForSignalWithoutEmitterNameOrSignalName(); + void testWaitForWindow(); + void testWaitForWindowWithEscapeSequences(); + void testWaitForWindowWithoutWindowObjectName(); void testWaitForComposed(); void testWaitForComposedWithInvalidChildWaitFor(); void testWaitForNot(); @@ -1217,6 +1221,106 @@ QCOMPARE(exportedTutorial, expected); } +void JavascriptExporterTest::testWaitForWindow() { + Tutorial tutorial; + Step* step = new Step(); + step->setId("The id"); + tutorial.addStep(step); + + WaitForWindow* waitForWindow = new WaitForWindow(); + waitForWindow->setWindowObjectName("The window object name"); + + Reaction* reaction = new Reaction(); + reaction->setTriggerType(Reaction::ConditionMet); + reaction->setWaitFor(waitForWindow); + 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" +" waitForTheWindowObjectNameToBeShown = \ +ktutorial.newWaitFor(\"WaitForWindow\");\n" +" waitForTheWindowObjectNameToBeShown.setWindowObjectName(\ +\"The window object name\");\n" +" step.addWaitFor(waitForTheWindowObjectNameToBeShown, \"Another step\");\n" +"}\n" +CONNECT_STEP_SETUP +STEP_WITH_ID_THE_ID_AND_EMPTY_TEXT_END_CODE; + + QCOMPARE(exportedTutorial, expected); +} + +void JavascriptExporterTest::testWaitForWindowWithEscapeSequences() { + Tutorial tutorial; + Step* step = new Step(); + step->setId("The id"); + tutorial.addStep(step); + + WaitForWindow* waitForWindow = new WaitForWindow(); + waitForWindow->setWindowObjectName("The \"window\" object name"); + + Reaction* reaction = new Reaction(); + reaction->setTriggerType(Reaction::ConditionMet); + reaction->setWaitFor(waitForWindow); + 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" +" waitForTheWindowObjectNameToBeShown = \ +ktutorial.newWaitFor(\"WaitForWindow\");\n" +" waitForTheWindowObjectNameToBeShown.setWindowObjectName(\ +\"The \\\"window\\\" object name\");\n" +" step.addWaitFor(waitForTheWindowObjectNameToBeShown, \"Another step\");\n" +"}\n" +CONNECT_STEP_SETUP +STEP_WITH_ID_THE_ID_AND_EMPTY_TEXT_END_CODE; + + QCOMPARE(exportedTutorial, expected); +} + +void JavascriptExporterTest::testWaitForWindowWithoutWindowObjectName() { + Tutorial tutorial; + Step* step = new Step(); + step->setId("The id"); + tutorial.addStep(step); + + WaitForWindow* waitForWindow = new WaitForWindow(); + + Reaction* reaction = new Reaction(); + reaction->setTriggerType(Reaction::ConditionMet); + reaction->setWaitFor(waitForWindow); + reaction->setResponseType(Reaction::NextStep); + reaction->setNextStepId("Another step"); + step->addReaction(reaction); + + JavascriptExporter exporter; + QString exportedTutorial = exporter.exportTutorial(&tutorial); + + QString expected = +TUTORIAL_EMPTY_INFORMATION_CODE +STEP_WITH_ID_THE_ID_AND_EMPTY_TEXT_START_CODE +"function theIdStepSetup(step) {\n" +" //Error: WaitForWindow without window object name!\n" +"}\n" +CONNECT_STEP_SETUP +STEP_WITH_ID_THE_ID_AND_EMPTY_TEXT_END_CODE; + + QCOMPARE(exportedTutorial, expected); +} + void JavascriptExporterTest::testWaitForComposed() { 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 2010-09-25 20:16:03 UTC (rev 257) +++ trunk/ktutorial/ktutorial-editor/tests/unit/serialization/TutorialReaderTest.cpp 2010-09-26 17:49:55 UTC (rev 258) @@ -29,6 +29,7 @@ #include "../data/WaitForEvent.h" #include "../data/WaitForNot.h" #include "../data/WaitForSignal.h" +#include "../data/WaitForWindow.h" #define HEADER_XML \ "<?xml version=\"1.0\" encoding=\"utf-8\"?>\n" @@ -88,6 +89,8 @@ void testWaitForEventEmpty(); void testWaitForSignal(); void testWaitForSignalEmpty(); + void testWaitForWindow(); + void testWaitForWindowEmpty(); void testWaitForComposed(); void testWaitForComposedEmpty(); void testWaitForNot(); @@ -399,6 +402,38 @@ assertWaitForSignal(waitFor, "", ""); } +void TutorialReaderTest::testWaitForWindow() { + QString data = +WAITFOR_PARENT_START +" <waitForWindow windowObjectName=\"The "window" object \ +name\"/>\n" +WAITFOR_PARENT_END; + + TutorialReader reader; + QScopedPointer<Tutorial> tutorial(reader.readTutorial(data)); + WaitFor* waitFor = tutorial->steps()[0]->reactions()[0]->waitFor(); + + WaitForWindow* waitForWindow = qobject_cast<WaitForWindow*>(waitFor); + QVERIFY(waitForWindow); + QCOMPARE(waitForWindow->windowObjectName(), + QString("The \"window\" object name")); +} + +void TutorialReaderTest::testWaitForWindowEmpty() { + QString data = +WAITFOR_PARENT_START +" <waitForWindow/>\n" +WAITFOR_PARENT_END; + + TutorialReader reader; + QScopedPointer<Tutorial> tutorial(reader.readTutorial(data)); + WaitFor* waitFor = tutorial->steps()[0]->reactions()[0]->waitFor(); + + WaitForWindow* waitForWindow = qobject_cast<WaitForWindow*>(waitFor); + QVERIFY(waitForWindow); + QCOMPARE(waitForWindow->windowObjectName(), QString("")); +} + void TutorialReaderTest::testWaitForComposed() { QString data = WAITFOR_PARENT_START Modified: trunk/ktutorial/ktutorial-editor/tests/unit/serialization/TutorialWriterTest.cpp =================================================================== --- trunk/ktutorial/ktutorial-editor/tests/unit/serialization/TutorialWriterTest.cpp 2010-09-25 20:16:03 UTC (rev 257) +++ trunk/ktutorial/ktutorial-editor/tests/unit/serialization/TutorialWriterTest.cpp 2010-09-26 17:49:55 UTC (rev 258) @@ -27,6 +27,7 @@ #include "../data/WaitForEvent.h" #include "../data/WaitForNot.h" #include "../data/WaitForSignal.h" +#include "../data/WaitForWindow.h" #define HEADER_XML \ "<?xml version=\"1.0\" encoding=\"utf-8\"?>\n" @@ -86,6 +87,8 @@ void testWaitForEventEmpty(); void testWaitForSignal(); void testWaitForSignalEmpty(); + void testWaitForWindow(); + void testWaitForWindowEmpty(); void testWaitForComposed(); void testWaitForComposedEmpty(); void testWaitForNot(); @@ -440,6 +443,56 @@ QCOMPARE(savedTutorial, expected); } +void TutorialWriterTest::testWaitForWindow() { + Tutorial tutorial; + Step* step = new Step(); + tutorial.addStep(step); + + WaitForWindow* waitForWindow = new WaitForWindow(); + waitForWindow->setWindowObjectName("The \"window\" object name"); + + Reaction* reaction = new Reaction(); + reaction->setTriggerType(Reaction::ConditionMet); + reaction->setWaitFor(waitForWindow); + reaction->setResponseType(Reaction::NextStep); + step->addReaction(reaction); + + TutorialWriter saver; + QString savedTutorial = saver.writeTutorial(&tutorial); + + QString expected = +WAITFOR_PARENT_START +" <waitForWindow windowObjectName=\"The "window" object \ +name\"/>\n" +WAITFOR_PARENT_END; + + QCOMPARE(savedTutorial, expected); +} + +void TutorialWriterTest::testWaitForWindowEmpty() { + Tutorial tutorial; + Step* step = new Step(); + tutorial.addStep(step); + + WaitForWindow* waitForWindow = new WaitForWindow(); + + Reaction* reaction = new Reaction(); + reaction->setTriggerType(Reaction::ConditionMet); + reaction->setWaitFor(waitForWindow); + reaction->setResponseType(Reaction::NextStep); + step->addReaction(reaction); + + TutorialWriter saver; + QString savedTutorial = saver.writeTutorial(&tutorial); + + QString expected = +WAITFOR_PARENT_START +" <waitForWindow/>\n" +WAITFOR_PARENT_END; + + QCOMPARE(savedTutorial, expected); +} + void TutorialWriterTest::testWaitForComposed() { 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 2010-09-25 20:16:03 UTC (rev 257) +++ trunk/ktutorial/ktutorial-editor/tests/unit/view/CMakeLists.txt 2010-09-26 17:49:55 UTC (rev 258) @@ -45,6 +45,8 @@ WaitForSignalWidget WaitForTreeItem WaitForWidget + WaitForWindowTreeItem + WaitForWindowWidget ) if (QT_QTDBUS_FOUND) @@ -94,6 +96,8 @@ WaitForSignalWidget WaitForTreeItem WaitForWidget + WaitForWindowTreeItem + WaitForWindowWidget ) if (QT_QTDBUS_FOUND) Modified: trunk/ktutorial/ktutorial-editor/tests/unit/view/NewWaitForWidgetTest.cpp =================================================================== --- trunk/ktutorial/ktutorial-editor/tests/unit/view/NewWaitForWidgetTest.cpp 2010-09-25 20:16:03 UTC (rev 257) +++ trunk/ktutorial/ktutorial-editor/tests/unit/view/NewWaitForWidgetTest.cpp 2010-09-26 17:49:55 UTC (rev 258) @@ -26,6 +26,7 @@ #include "../data/WaitForEvent.h" #include "../data/WaitForNot.h" #include "../data/WaitForSignal.h" +#include "../data/WaitForWindow.h" class NewWaitForWidgetTest: public QObject { Q_OBJECT @@ -39,6 +40,7 @@ void testWaitForWhenNotConditionIsSelected(); void testWaitForWhenSignalConditionIsSelected(); void testWaitForWhenEventConditionIsSelected(); + void testWaitForWhenWindowConditionIsSelected(); private: @@ -105,6 +107,16 @@ delete waitFor; } +void NewWaitForWidgetTest::testWaitForWhenWindowConditionIsSelected() { + NewWaitForWidget widget; + + selectOption(&widget, 5); + + WaitForWindow* waitFor = qobject_cast<WaitForWindow*>(widget.waitFor()); + QVERIFY(waitFor); + delete waitFor; +} + /////////////////////////////////// Helpers //////////////////////////////////// void NewWaitForWidgetTest::selectOption(NewWaitForWidget* widget, Modified: trunk/ktutorial/ktutorial-editor/tests/unit/view/WaitForTreeItemTest.cpp =================================================================== --- trunk/ktutorial/ktutorial-editor/tests/unit/view/WaitForTreeItemTest.cpp 2010-09-25 20:16:03 UTC (rev 257) +++ trunk/ktutorial/ktutorial-editor/tests/unit/view/WaitForTreeItemTest.cpp 2010-09-26 17:49:55 UTC (rev 258) @@ -24,11 +24,13 @@ #include "WaitForEventTreeItem.h" #include "WaitForNotTreeItem.h" #include "WaitForSignalTreeItem.h" +#include "WaitForWindowTreeItem.h" #include "../data/WaitFor.h" #include "../data/WaitForComposed.h" #include "../data/WaitForEvent.h" #include "../data/WaitForNot.h" #include "../data/WaitForSignal.h" +#include "../data/WaitForWindow.h" class WaitForTreeItemTest: public QObject { Q_OBJECT @@ -41,6 +43,7 @@ void testTreeItemForWaitForEvent(); void testTreeItemForWaitForNot(); void testTreeItemForWaitForSignal(); + void testTreeItemForWaitForWindow(); }; @@ -144,6 +147,20 @@ delete item; } +void WaitForTreeItemTest::testTreeItemForWaitForWindow() { + WaitForWindow waitFor; + StubTreeItem parent; + + WaitForTreeItem* item = WaitForTreeItem::treeItemForWaitFor(&waitFor, + &parent); + + QVERIFY(qobject_cast<WaitForWindowTreeItem*>(item)); + QCOMPARE(item->parent(), &parent); + QCOMPARE(item->waitFor(), &waitFor); + + delete item; +} + QTEST_MAIN(WaitForTreeItemTest) #include "WaitForTreeItemTest.moc" Modified: trunk/ktutorial/ktutorial-editor/tests/unit/view/WaitForWidgetTest.cpp =================================================================== --- trunk/ktutorial/ktutorial-editor/tests/unit/view/WaitForWidgetTest.cpp 2010-09-25 20:16:03 UTC (rev 257) +++ trunk/ktutorial/ktutorial-editor/tests/unit/view/WaitForWidgetTest.cpp 2010-09-26 17:49:55 UTC (rev 258) @@ -31,6 +31,7 @@ #include "../data/WaitForEvent.h" #include "../data/WaitForNot.h" #include "../data/WaitForSignal.h" +#include "../data/WaitForWindow.h" class WaitForWidgetTest: public QObject { Q_OBJECT @@ -41,6 +42,7 @@ void setEventData() const; void setSignalData() const; + void setWindowData() const; private slots: @@ -56,6 +58,7 @@ void testSelectWaitForNotEmpty(); void testSelectWaitForEvent(); void testSelectWaitForSignal(); + void testSelectWaitForWindow(); void testClearSelection(); void testAddWaitForWhenEmpty(); @@ -65,6 +68,7 @@ void testEditWaitForEvent(); void testEditWaitForSignal(); + void testEditWaitForWindow(); void testRemoveWaitForFromRoot(); void testRemoveWaitForFromWaitForComposed(); @@ -76,6 +80,7 @@ WaitForSignal* mWaitFor1; WaitForComposed* mWaitFor2; WaitForEvent* mWaitFor2_1; + WaitForWindow* mWaitFor2_2; WaitForNot* mWaitFor3; WaitForSignal* mWaitFor3_1; WaitForNot* mWaitFor4; @@ -114,6 +119,10 @@ mWaitFor2_1->setEventName("event"); mWaitFor2->addWaitFor(mWaitFor2_1); + mWaitFor2_2 = new WaitForWindow(); + mWaitFor2_2->setWindowObjectName("windowObject"); + mWaitFor2->addWaitFor(mWaitFor2_2); + mWaitFor3 = new WaitForNot(); mWaitFor->addWaitFor(mWaitFor3); @@ -187,6 +196,12 @@ assertButtonEnabled(false, true, true); } +void WaitForWidgetTest::testSelectWaitForWindow() { + selectItem(getIndex(1, getIndex(1, getIndex(0)))); + + assertButtonEnabled(false, true, true); +} + void WaitForWidgetTest::testClearSelection() { selectItem(getIndex(0)); selectItem(QModelIndex()); @@ -235,10 +250,11 @@ QCOMPARE(mWaitFor->waitFors()[2], mWaitFor3); QCOMPARE(mWaitFor->waitFors()[3], mWaitFor4); QVERIFY(qobject_cast<WaitForSignal*>(mWaitFor->waitFors()[4])); - QCOMPARE(mWaitFor2->waitFors().count(), 2); + QCOMPARE(mWaitFor2->waitFors().count(), 3); QCOMPARE(mWaitFor2->waitFors()[0], mWaitFor2_1); - QVERIFY(qobject_cast<WaitForSignal*>(mWaitFor2->waitFors()[1])); - QVERIFY(mWaitFor->waitFors()[4] != mWaitFor2->waitFors()[1]); + QCOMPARE(mWaitFor2->waitFors()[1], mWaitFor2_2); + QVERIFY(qobject_cast<WaitForSignal*>(mWaitFor2->waitFors()[2])); + QVERIFY(mWaitFor->waitFors()[4] != mWaitFor2->waitFors()[2]); } void WaitForWidgetTest::testAddWaitForToWaitForNot() { @@ -307,6 +323,20 @@ QCOMPARE(mWaitFor1->signalName(), QString("The new signal name")); } +void WaitForWidgetTest::testEditWaitForWindow() { + selectItem(getIndex(1, getIndex(1, getIndex(0)))); + + //The dialog is modal, so it won't return to the test code until it is + //closed. Thus, the commands to execute on the dialog must be "queued", + //as calling setWindowData after the button click won't work. + QTimer::singleShot(500, this, SLOT(setWindowData())); + + button("editButton")->click(); + + QCOMPARE(mWaitFor2_2->windowObjectName(), + QString("The new window object name")); +} + void WaitForWidgetTest::testRemoveWaitForFromRoot() { delete mWidget; WaitForSignal* waitForSignal = new WaitForSignal(); @@ -400,6 +430,21 @@ dialog->button(KDialog::Ok)->click(); } +void WaitForWidgetTest::setWindowData() const { + KLineEdit* windowObjectNameLineEdit = +#ifdef QT_QTDBUS_FOUND + mWidget->findChild<KLineEdit*>("objectNameLineEdit"); +#else + mWidget->findChild<KLineEdit*>("windowObjectNameLineEdit"); +#endif + QVERIFY(windowObjectNameLineEdit); + windowObjectNameLineEdit->setText("The new window object name"); + + EditionDialog* dialog = mWidget->findChild<EditionDialog*>("editionDialog"); + QVERIFY(dialog); + dialog->button(KDialog::Ok)->click(); +} + QModelIndex WaitForWidgetTest::getIndex(int row, const QModelIndex& parent) const { QTreeView* tree = mWidget->findChild<QTreeView*>("waitForTreeView"); Added: trunk/ktutorial/ktutorial-editor/tests/unit/view/WaitForWindowTreeItemTest.cpp =================================================================== --- trunk/ktutorial/ktutorial-editor/tests/unit/view/WaitForWindowTreeItemTest.cpp (rev 0) +++ trunk/ktutorial/ktutorial-editor/tests/unit/view/WaitForWindowTreeItemTest.cpp 2010-09-26 17:49:55 UTC (rev 258) @@ -0,0 +1,130 @@ +/*************************************************************************** + * Copyright (C) 2010 by Daniel Calviño Sánchez * + * dan...@gm... * + * * + * This program is free software; you can redistribute it and/or modify * + * it under the terms of the GNU General Public License as published by * + * the Free Software Foundation; either version 3 of the License, or * + * (at your option) any later version. * + * * + * This program is distributed in the hope that it will be useful, * + * but WITHOUT ANY WARRANTY... [truncated message content] |
From: <dan...@us...> - 2010-09-25 20:16:10
|
Revision: 257 http://ktutorial.svn.sourceforge.net/ktutorial/?rev=257&view=rev Author: danxuliu Date: 2010-09-25 20:16:03 +0000 (Sat, 25 Sep 2010) Log Message: ----------- Add WaitForWindow to wait for a specific window (identified by its object name) to be shown. 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 Added Paths: ----------- trunk/ktutorial/ktutorial-library/src/WaitForWindow.cpp trunk/ktutorial/ktutorial-library/src/WaitForWindow.h trunk/ktutorial/ktutorial-library/tests/WaitForWindowTest.cpp Modified: trunk/ktutorial/ktutorial-library/src/CMakeLists.txt =================================================================== --- trunk/ktutorial/ktutorial-library/src/CMakeLists.txt 2010-09-25 14:39:08 UTC (rev 256) +++ trunk/ktutorial/ktutorial-library/src/CMakeLists.txt 2010-09-25 20:16:03 UTC (rev 257) @@ -29,6 +29,7 @@ WaitForNot.cpp WaitForOr.cpp WaitForSignal.cpp + WaitForWindow.cpp ) kde4_add_library(ktutorial SHARED ${ktutorial_LIB_SRCS}) @@ -58,6 +59,7 @@ WaitForNot.h WaitForOr.h WaitForSignal.h + WaitForWindow.h ) # Hack to make headers available to other ktutorial modules (like Added: trunk/ktutorial/ktutorial-library/src/WaitForWindow.cpp =================================================================== --- trunk/ktutorial/ktutorial-library/src/WaitForWindow.cpp (rev 0) +++ trunk/ktutorial/ktutorial-library/src/WaitForWindow.cpp 2010-09-25 20:16:03 UTC (rev 257) @@ -0,0 +1,78 @@ +/*************************************************************************** + * Copyright (C) 2010 by Daniel Calviño Sánchez * + * dan...@gm... * + * * + * This program is free software; you can redistribute it and/or modify * + * it under the terms of the GNU General Public License as published by * + * the Free Software Foundation; either version 3 of the License, or * + * (at your option) any later version. * + * * + * This program is distributed in the hope that it will be useful, * + * but WITHOUT ANY WARRANTY; without even the implied warranty of * + * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the * + * GNU General Public License for more details. * + * * + * You should have received a copy of the GNU General Public License * + * along with this program; If not, see <http://www.gnu.org/licenses/>. * + ***************************************************************************/ + +#include "WaitForWindow.h" +#include "KTutorial.h" +#include "common/WindowVisibilitySpy.h" + +using common::WindowVisibilitySpy; + +//public: + +WaitForWindow::WaitForWindow(): WaitFor(), + mConditionMet(false) { + + WindowVisibilitySpy* spy = new WindowVisibilitySpy(this); + spy->addWidgetToSpy(KTutorial::self()->parentWidget()); + connect(spy, SIGNAL(windowShown(QWidget*)), + this, SLOT(checkWindowShown(QWidget*))); +} + +WaitForWindow::WaitForWindow(const QString& objectName): WaitFor(), + mConditionMet(false) { + + WindowVisibilitySpy* spy = new WindowVisibilitySpy(this); + spy->addWidgetToSpy(KTutorial::self()->parentWidget()); + connect(spy, SIGNAL(windowShown(QWidget*)), + this, SLOT(checkWindowShown(QWidget*))); + + setWindowObjectName(objectName); +} + +void WaitForWindow::setWindowObjectName(const QString& objectName) { + mWindowObjectName = objectName; +} + +bool WaitForWindow::conditionMet() const { + return mConditionMet; +} + +void WaitForWindow::setActive(bool active) { + WaitFor::setActive(active); + + if (active) { + mConditionMet = false; + } +} + +//private slots: + +void WaitForWindow::checkWindowShown(QWidget* window) { + if (!isActive()) { + return; + } + + if (window->objectName() != mWindowObjectName) { + return; + } + + mConditionMet = true; + emit waitEnded(this); +} + +#include "WaitForWindow.moc" Property changes on: trunk/ktutorial/ktutorial-library/src/WaitForWindow.cpp ___________________________________________________________________ Added: svn:eol-style + native Added: trunk/ktutorial/ktutorial-library/src/WaitForWindow.h =================================================================== --- trunk/ktutorial/ktutorial-library/src/WaitForWindow.h (rev 0) +++ trunk/ktutorial/ktutorial-library/src/WaitForWindow.h 2010-09-25 20:16:03 UTC (rev 257) @@ -0,0 +1,120 @@ +/*************************************************************************** + * Copyright (C) 2010 by Daniel Calviño Sánchez * + * dan...@gm... * + * * + * This program is free software; you can redistribute it and/or modify * + * it under the terms of the GNU General Public License as published by * + * the Free Software Foundation; either version 3 of the License, or * + * (at your option) any later version. * + * * + * This program is distributed in the hope that it will be useful, * + * but WITHOUT ANY WARRANTY; without even the implied warranty of * + * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the * + * GNU General Public License for more details. * + * * + * You should have received a copy of the GNU General Public License * + * along with this program; If not, see <http://www.gnu.org/licenses/>. * + ***************************************************************************/ + +#ifndef WAITFORWINDOW_H +#define WAITFORWINDOW_H + +#include "ktutorial_export.h" + +#include "WaitFor.h" + +/** + * Waits for a specific window to be shown. + * When the window with the expected object name is shown and the WaitForEvent + * is active, the wait ends. + * + * Note that if the window is shown while the WaitFor isn't active, it won't + * be registered and the condition won't be met. In order to met the condition, + * the window must be shown while the WaitForEvent is active. + * + * The term "window" is used here in a general sense: WaitForWindow can wait + * either for true windows or for dialogs. In fact, WaitForWindow must be used + * whenever there is a modal dialog; waiting for the user to click a button that + * causes a modal dialog to appear will not work, as the modal dialog will + * halt further processing of the clicked() signal until it is closed (if the + * modal dialog was created in a slot connected to the clicked() signal, which + * is very likely). + */ +class KTUTORIAL_EXPORT WaitForWindow: public WaitFor { +Q_OBJECT +public: + + /** + * Creates a new WaitForWindow. + * This constructor is needed to dynamically create WaitForWindow objects in + * scripts using ScriptingModule::newWaitFor(const QString&). Method + * setWindowObjectName(const QString&) must be called to finish setting up + * the object. For C++ tutorials, use WaitForWindow(const QString&) + * constructor instead of this one. + */ + Q_INVOKABLE WaitForWindow(); + + /** + * Creates a new WaitForWindow. + * Note that the name is the object name, not the window title. + * + * @param windowObjectName The object name of the window to wait for. + */ + WaitForWindow(const QString& windowObjectName); + + /** + * Sets the object name of the window to wait for. + * Note that the name is the object name, not the window title. + * 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 + * WaitForWindow(const QString&) constructor when creating this + * WaitForWindow. + * + * @param windowObjectName The object name of the window to wait for. + */ + Q_INVOKABLE void setWindowObjectName(const QString& windowObjectName); + + /** + * Returns true if the window was shown while active, false otherwise. + * + * @return True if the window was shown while active, false otherwise. + */ + virtual bool conditionMet() const; + + /** + * Sets this WaitForWindow active or inactive. + * Activating it resets its condition. + * + * @param active True to set it active, false otherwise. + */ + virtual void setActive(bool active); + +private: + + /** + * Whether the window with the expected object name was shown when active or + * not. + */ + bool mConditionMet; + + /** + * The object name of the window to wait for. + */ + QString mWindowObjectName; + +private Q_SLOTS: + + /** + * Checks whether the window that has been shown is the expected one. + * If the WaitFor is active and the object name of the window is the + * expected one, the condition is met and the wait ended. + * + * @param window A window that has been shown. + */ + void checkWindowShown(QWidget* window); + +}; + +#endif Property changes on: trunk/ktutorial/ktutorial-library/src/WaitForWindow.h ___________________________________________________________________ Added: svn:eol-style + native Modified: trunk/ktutorial/ktutorial-library/src/scripting/ScriptingModule.cpp =================================================================== --- trunk/ktutorial/ktutorial-library/src/scripting/ScriptingModule.cpp 2010-09-25 14:39:08 UTC (rev 256) +++ trunk/ktutorial/ktutorial-library/src/scripting/ScriptingModule.cpp 2010-09-25 20:16:03 UTC (rev 257) @@ -28,6 +28,7 @@ #include "../WaitForNot.h" #include "../WaitForOr.h" #include "../WaitForSignal.h" +#include "../WaitForWindow.h" namespace scripting { @@ -39,6 +40,7 @@ sSelf->registerWaitForMetaObject(WaitForNot::staticMetaObject); sSelf->registerWaitForMetaObject(WaitForOr::staticMetaObject); sSelf->registerWaitForMetaObject(WaitForSignal::staticMetaObject); + sSelf->registerWaitForMetaObject(WaitForWindow::staticMetaObject); } return sSelf; Modified: trunk/ktutorial/ktutorial-library/tests/CMakeLists.txt =================================================================== --- trunk/ktutorial/ktutorial-library/tests/CMakeLists.txt 2010-09-25 14:39:08 UTC (rev 256) +++ trunk/ktutorial/ktutorial-library/tests/CMakeLists.txt 2010-09-25 20:16:03 UTC (rev 257) @@ -12,6 +12,11 @@ include_directories(${CMAKE_CURRENT_BINARY_DIR} ${ktutorial-library_SOURCE_DIR}/src ${KDE4_INCLUDES}) +# Since Qt 4.6.0, this definition is needed for GUI testing. +# It is backwards compatible with previous Qt versions, unlike the alternative +# which is to add #include <QTestGui> in the test files. +add_definitions(-DQT_GUI_LIB) + MACRO(UNIT_TESTS) FOREACH(_className ${ARGN}) set(_testName ${_className}Test) @@ -33,6 +38,7 @@ WaitForNot WaitForOr WaitForSignal + WaitForWindow ) MACRO(MEM_TESTS) @@ -54,4 +60,5 @@ WaitForNot WaitForOr WaitForSignal + WaitForWindow ) Added: trunk/ktutorial/ktutorial-library/tests/WaitForWindowTest.cpp =================================================================== --- trunk/ktutorial/ktutorial-library/tests/WaitForWindowTest.cpp (rev 0) +++ trunk/ktutorial/ktutorial-library/tests/WaitForWindowTest.cpp 2010-09-25 20:16:03 UTC (rev 257) @@ -0,0 +1,252 @@ +/*************************************************************************** + * Copyright (C) 2010 by Daniel Calviño Sánchez * + * dan...@gm... * + * * + * This program is free software; you can redistribute it and/or modify * + * it under the terms of the GNU General Public License as published by * + * the Free Software Foundation; either version 3 of the License, or * + * (at your option) any later version. * + * * + * This program is distributed in the hope that it will be useful, * + * but WITHOUT ANY WARRANTY; without even the implied warranty of * + * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the * + * GNU General Public License for more details. * + * * + * You should have received a copy of the GNU General Public License * + * along with this program; If not, see <http://www.gnu.org/licenses/>. * + ***************************************************************************/ + +#include <QtTest> + +#include <QDialog> + +#include <KXmlGuiWindow> + +#define protected public +#define private public +#include "WaitForWindow.h" +#undef private +#undef protected + +#include "KTutorial.h" + +class WaitForWindowTest: public QObject { +Q_OBJECT +private slots: + + void initTestCase(); + + void testConstructor(); + void testConstructorDefault(); + + void testSetActive(); + + void testWaitEnded(); + void testWaitEndedByModalDialog(); + void testWaitEndedWithDefaultConstructor(); + void testWaitEndedNotActive(); + +private: + + KXmlGuiWindow* mMainWindow; + + void queueAssertConditionMet(WaitForWindow* waitForWindow, + QSignalSpy* waitEndedSpy, + int timeToWait); + +}; + +void WaitForWindowTest::initTestCase() { + mMainWindow = new KXmlGuiWindow(); + KTutorial::self()->setup(mMainWindow); +} + +void WaitForWindowTest::testConstructor() { + WaitForWindow waitForWindow("theName"); + + QVERIFY(!waitForWindow.isActive()); + QVERIFY(!waitForWindow.conditionMet()); +} + +void WaitForWindowTest::testConstructorDefault() { + WaitForWindow waitForWindow; + waitForWindow.setWindowObjectName("theName"); + + QVERIFY(!waitForWindow.isActive()); + QVERIFY(!waitForWindow.conditionMet()); +} + +void WaitForWindowTest::testSetActive() { + WaitForWindow waitForWindow("theName"); + waitForWindow.mConditionMet = true; + + waitForWindow.setActive(true); + + QVERIFY(waitForWindow.isActive()); + QVERIFY(!waitForWindow.conditionMet()); +} + +//WaitFor* must be declared as a metatype to be used in qvariant_cast +Q_DECLARE_METATYPE(WaitFor*); + +void WaitForWindowTest::testWaitEnded() { + WaitForWindow waitForWindow("theName"); + waitForWindow.setActive(true); + + //WaitFor* must be registered in order to be used with QSignalSpy + int waitForStarType = qRegisterMetaType<WaitFor*>("WaitFor*"); + QSignalSpy waitEndedSpy(&waitForWindow, SIGNAL(waitEnded(WaitFor*))); + + QWidget* otherWindow = new QWidget(mMainWindow); + otherWindow->setObjectName("otherName"); + otherWindow->setWindowFlags(Qt::Window); + otherWindow->show(); + + otherWindow->deleteLater(); + + QVERIFY(!waitForWindow.conditionMet()); + QCOMPARE(waitEndedSpy.count(), 0); + + QWidget* window = new QWidget(mMainWindow); + window->setObjectName("theName"); + window->setWindowFlags(Qt::Window); + window->show(); + + window->deleteLater(); + + QVERIFY(waitForWindow.conditionMet()); + QCOMPARE(waitEndedSpy.count(), 1); + QVariant argument = waitEndedSpy.at(0).at(0); + QCOMPARE(argument.userType(), waitForStarType); + QCOMPARE(qvariant_cast<WaitFor*>(argument), &waitForWindow); +} + +void WaitForWindowTest::testWaitEndedByModalDialog() { + WaitForWindow waitForWindow("theName"); + waitForWindow.setActive(true); + + //WaitFor* must be registered in order to be used with QSignalSpy + int waitForStarType = qRegisterMetaType<WaitFor*>("WaitFor*"); + QSignalSpy waitEndedSpy(&waitForWindow, SIGNAL(waitEnded(WaitFor*))); + + QDialog* modalDialog = new QDialog(mMainWindow); + modalDialog->setObjectName("theName"); + + QTimer timerAccept; + timerAccept.setSingleShot(true); + timerAccept.setInterval(1500); + connect(&timerAccept, SIGNAL(timeout()), modalDialog, SLOT(accept())); + + //Check that the condition was met before closing the modal dialog to ensure + //that the processing of events or signals is not halted due to being modal. + queueAssertConditionMet(&waitForWindow, &waitEndedSpy, 500); + + timerAccept.start(); + modalDialog->exec(); + + modalDialog->deleteLater(); + + QVERIFY(waitForWindow.conditionMet()); + QCOMPARE(waitEndedSpy.count(), 1); + QVariant argument = waitEndedSpy.at(0).at(0); + QCOMPARE(argument.userType(), waitForStarType); + QCOMPARE(qvariant_cast<WaitFor*>(argument), &waitForWindow); +} + +void WaitForWindowTest::testWaitEndedWithDefaultConstructor() { + WaitForWindow waitForWindow; + waitForWindow.setWindowObjectName("theName"); + waitForWindow.setActive(true); + + //WaitFor* must be registered in order to be used with QSignalSpy + int waitForStarType = qRegisterMetaType<WaitFor*>("WaitFor*"); + QSignalSpy waitEndedSpy(&waitForWindow, SIGNAL(waitEnded(WaitFor*))); + + QWidget* otherWindow = new QWidget(mMainWindow); + otherWindow->setObjectName("otherName"); + otherWindow->setWindowFlags(Qt::Window); + otherWindow->show(); + + otherWindow->deleteLater(); + + QVERIFY(!waitForWindow.conditionMet()); + QCOMPARE(waitEndedSpy.count(), 0); + + QWidget* window = new QWidget(mMainWindow); + window->setObjectName("theName"); + window->setWindowFlags(Qt::Window); + window->show(); + + window->deleteLater(); + + QVERIFY(waitForWindow.conditionMet()); + QCOMPARE(waitEndedSpy.count(), 1); + QVariant argument = waitEndedSpy.at(0).at(0); + QCOMPARE(argument.userType(), waitForStarType); + QCOMPARE(qvariant_cast<WaitFor*>(argument), &waitForWindow); +} + +void WaitForWindowTest::testWaitEndedNotActive() { + WaitForWindow waitForWindow("theName"); + + qRegisterMetaType<WaitFor*>("WaitFor*"); + QSignalSpy waitEndedSpy(&waitForWindow, SIGNAL(waitEnded(WaitFor*))); + + QWidget* window = new QWidget(mMainWindow); + window->setObjectName("theName"); + window->setWindowFlags(Qt::Window); + window->show(); + + window->deleteLater(); + + QVERIFY(!waitForWindow.conditionMet()); + QCOMPARE(waitEndedSpy.count(), 0); +} + +/////////////////////////////////// Helpers //////////////////////////////////// + +//Modal dialogs don't return to the test code until they are closed. Thus, the +//actions or asserts to be performed while a modal dialog is being shown (like +//checking if a wait for condition was met) must be "queued". +class QueuedActionsHelper: public QObject { +Q_OBJECT +public: + + QueuedActionsHelper(QObject* object = 0): QObject(object) { + } + + void setWaitForWindow(WaitForWindow* waitForWindow) { + mWaitForWindow = waitForWindow; + } + + void setWaitEndedSpy(QSignalSpy* waitEndedSpy) { + mWaitEndedSpy = waitEndedSpy; + } + +public slots: + + void assertConditionMet() { + QVERIFY(mWaitForWindow->conditionMet()); + QCOMPARE(mWaitEndedSpy->count(), 1); + } + +private: + + WaitForWindow* mWaitForWindow; + QSignalSpy* mWaitEndedSpy; + +}; + +void WaitForWindowTest::queueAssertConditionMet(WaitForWindow* waitForWindow, + QSignalSpy* waitEndedSpy, + int timeToWait) { + QueuedActionsHelper* helper = new QueuedActionsHelper(); + helper->setWaitForWindow(waitForWindow); + helper->setWaitEndedSpy(waitEndedSpy); + QTimer::singleShot(timeToWait, helper, SLOT(assertConditionMet())); + QTimer::singleShot(timeToWait, helper, SLOT(deleteLater())); +} + +QTEST_MAIN(WaitForWindowTest) + +#include "WaitForWindowTest.moc" Property changes on: trunk/ktutorial/ktutorial-library/tests/WaitForWindowTest.cpp ___________________________________________________________________ Added: svn:eol-style + native Modified: trunk/ktutorial/ktutorial-library/tests/scripting/ScriptingModuleTest.cpp =================================================================== --- trunk/ktutorial/ktutorial-library/tests/scripting/ScriptingModuleTest.cpp 2010-09-25 14:39:08 UTC (rev 256) +++ trunk/ktutorial/ktutorial-library/tests/scripting/ScriptingModuleTest.cpp 2010-09-25 20:16:03 UTC (rev 257) @@ -34,6 +34,7 @@ #include "../WaitForNot.h" #include "../WaitForOr.h" #include "../WaitForSignal.h" +#include "../WaitForWindow.h" class MockWaitForDefaultNamespace: public WaitFor { Q_OBJECT @@ -171,6 +172,10 @@ QVERIFY(containsMetaObject(scriptingModule, "WaitForSignal")); type = metaObject(scriptingModule, "WaitForSignal"); QCOMPARE(type.className(), WaitForSignal::staticMetaObject.className()); + + QVERIFY(containsMetaObject(scriptingModule, "WaitForWindow")); + type = metaObject(scriptingModule, "WaitForWindow"); + QCOMPARE(type.className(), WaitForWindow::staticMetaObject.className()); } void ScriptingModuleTest::testRegisterWaitForMetaObject() { This was sent by the SourceForge.net collaborative development platform, the world's largest Open Source development site. |
From: <dan...@us...> - 2010-09-25 14:39:15
|
Revision: 256 http://ktutorial.svn.sourceforge.net/ktutorial/?rev=256&view=rev Author: danxuliu Date: 2010-09-25 14:39:08 +0000 (Sat, 25 Sep 2010) Log Message: ----------- Fix emitting Tutorial::stepActivated(Step*) before really activating the step, which lead to options created in the step setup to not to be shown in the StepWidget (as they weren't created yet when StepWidget::setStep(Step*) was called). Modified Paths: -------------- trunk/ktutorial/ktutorial-library/src/Tutorial.cpp trunk/ktutorial/ktutorial-library/tests/TutorialTest.cpp Modified: trunk/ktutorial/ktutorial-library/src/Tutorial.cpp =================================================================== --- trunk/ktutorial/ktutorial-library/src/Tutorial.cpp 2010-09-25 03:40:16 UTC (rev 255) +++ trunk/ktutorial/ktutorial-library/src/Tutorial.cpp 2010-09-25 14:39:08 UTC (rev 256) @@ -79,10 +79,10 @@ //TODO remove kDebug() << "Next step: " << step->id() << endl; - emit stepActivated(step); - mCurrentStep = step; mCurrentStep->setActive(true); + + emit stepActivated(step); } //public slots: Modified: trunk/ktutorial/ktutorial-library/tests/TutorialTest.cpp =================================================================== --- trunk/ktutorial/ktutorial-library/tests/TutorialTest.cpp 2010-09-25 03:40:16 UTC (rev 255) +++ trunk/ktutorial/ktutorial-library/tests/TutorialTest.cpp 2010-09-25 14:39:08 UTC (rev 256) @@ -30,7 +30,12 @@ class TutorialTest: public QObject { Q_OBJECT +public slots: + void assertStepActive(Step* step) { + QVERIFY(step->isActive()); + } + private slots: void testConstructor(); @@ -267,6 +272,10 @@ 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("record"); QCOMPARE(stepActivatedSpy.count(), 1); @@ -296,6 +305,10 @@ 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*))); + stepStart->emitNextStepRequested("record"); QCOMPARE(stepActivatedSpy.count(), 1); @@ -352,6 +365,10 @@ 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(), 1); This was sent by the SourceForge.net collaborative development platform, the world's largest Open Source development site. |
From: <dan...@us...> - 2010-09-25 03:40:22
|
Revision: 255 http://ktutorial.svn.sourceforge.net/ktutorial/?rev=255&view=rev Author: danxuliu Date: 2010-09-25 03:40:16 +0000 (Sat, 25 Sep 2010) Log Message: ----------- Use KTutorial library in KTutorial editor to be able to provide tutorials for the editor itself. Modified Paths: -------------- trunk/ktutorial/ktutorial-editor/src/CMakeLists.txt trunk/ktutorial/ktutorial-editor/src/KTutorialEditor.cpp trunk/ktutorial/ktutorial-editor/src/ktutorial-editorui.rc Modified: trunk/ktutorial/ktutorial-editor/src/CMakeLists.txt =================================================================== --- trunk/ktutorial/ktutorial-editor/src/CMakeLists.txt 2010-09-25 03:33:38 UTC (rev 254) +++ trunk/ktutorial/ktutorial-editor/src/CMakeLists.txt 2010-09-25 03:40:16 UTC (rev 255) @@ -10,6 +10,22 @@ add_subdirectory(util) add_subdirectory(view) +# When KTutorial is built, the library isn't installed yet when the editor is +# built. In that case, use the headers and libraries in the build directory +# of the library. +if(ktutorial-library_BINARY_DIR) + set(KTUTORIAL_FOUND TRUE) + include_directories(${ktutorial-library_BINARY_DIR}/includes) + set(KTUTORIAL_LIBRARIES ktutorial) +endif(ktutorial-library_BINARY_DIR) + +# If ktutorial-test-app is built in standalone mode, look for an installed +# KTutorial library. +if(NOT KTUTORIAL_FOUND) + find_package(KTutorial REQUIRED) + include_directories(${KTUTORIAL_INCLUDE_DIRS}) +endif(NOT KTUTORIAL_FOUND) + if (QT_QTDBUS_FOUND) add_definitions(-DQT_QTDBUS_FOUND) add_subdirectory(targetapplication) @@ -39,6 +55,7 @@ ktutorial_editor_serialization ktutorial_editor_util ktutorial_editor_view + ${KTUTORIAL_LIBRARIES} ) if (QT_QTDBUS_FOUND) Modified: trunk/ktutorial/ktutorial-editor/src/KTutorialEditor.cpp =================================================================== --- trunk/ktutorial/ktutorial-editor/src/KTutorialEditor.cpp 2010-09-25 03:33:38 UTC (rev 254) +++ trunk/ktutorial/ktutorial-editor/src/KTutorialEditor.cpp 2010-09-25 03:40:16 UTC (rev 255) @@ -26,6 +26,8 @@ #include <KConfigGroup> #include <KLocalizedString> +#include <ktutorial/KTutorial.h> + #include "EditActions.h" #include "FileActions.h" #include "data/Tutorial.h" @@ -64,6 +66,8 @@ mFileActions->newTutorial(); + KTutorial::self()->setup(this); + setupGUI(); } Modified: trunk/ktutorial/ktutorial-editor/src/ktutorial-editorui.rc =================================================================== --- trunk/ktutorial/ktutorial-editor/src/ktutorial-editorui.rc 2010-09-25 03:33:38 UTC (rev 254) +++ trunk/ktutorial/ktutorial-editor/src/ktutorial-editorui.rc 2010-09-25 03:40:16 UTC (rev 255) @@ -38,6 +38,9 @@ <Action name="showEditReactionDock"/> </Menu> </Menu> + <Menu name="help"> + <DefineGroup name="ktutorial"/> + </Menu> </MenuBar> <ToolBar name="mainToolBar"> <Text context="@title:menu">Main Toolbar</Text> This was sent by the SourceForge.net collaborative development platform, the world's largest Open Source development site. |
From: <dan...@us...> - 2010-09-25 03:33:45
|
Revision: 254 http://ktutorial.svn.sourceforge.net/ktutorial/?rev=254&view=rev Author: danxuliu Date: 2010-09-25 03:33:38 +0000 (Sat, 25 Sep 2010) Log Message: ----------- Add support to test in the target application the tutorial being designed in the editor. Modified Paths: -------------- trunk/ktutorial/ktutorial-editor/src/CMakeLists.txt trunk/ktutorial/ktutorial-editor/src/EditActions.cpp trunk/ktutorial/ktutorial-editor/src/EditActions.h trunk/ktutorial/ktutorial-editor/src/ktutorial-editorui.rc trunk/ktutorial/ktutorial-editor/src/targetapplication/RemoteEditorSupport.cpp trunk/ktutorial/ktutorial-editor/src/targetapplication/RemoteEditorSupport.h trunk/ktutorial/ktutorial-editor/tests/unit/targetapplication/RemoteClassStubs.h trunk/ktutorial/ktutorial-editor/tests/unit/targetapplication/RemoteEditorSupportTest.cpp Added Paths: ----------- trunk/ktutorial/ktutorial-editor/src/TutorialTester.cpp trunk/ktutorial/ktutorial-editor/src/TutorialTester.h Modified: trunk/ktutorial/ktutorial-editor/src/CMakeLists.txt =================================================================== --- trunk/ktutorial/ktutorial-editor/src/CMakeLists.txt 2010-09-25 03:01:55 UTC (rev 253) +++ trunk/ktutorial/ktutorial-editor/src/CMakeLists.txt 2010-09-25 03:33:38 UTC (rev 254) @@ -21,6 +21,13 @@ KTutorialEditor.cpp ) +if (QT_QTDBUS_FOUND) + set(ktutorial_editor_SRCS + ${ktutorial_editor_SRCS} + TutorialTester.cpp + ) +endif (QT_QTDBUS_FOUND) + # Instead of compiling the executable directly from the sources, the sources are # compiled to a static library that is linked (and, being static, also embedded) # in the editor executable. Modified: trunk/ktutorial/ktutorial-editor/src/EditActions.cpp =================================================================== --- trunk/ktutorial/ktutorial-editor/src/EditActions.cpp 2010-09-25 03:01:55 UTC (rev 253) +++ trunk/ktutorial/ktutorial-editor/src/EditActions.cpp 2010-09-25 03:33:38 UTC (rev 254) @@ -37,6 +37,10 @@ #include "view/TutorialCustomCodeWidget.h" #include "view/TutorialInformationWidget.h" +#ifdef QT_QTDBUS_FOUND +#include "TutorialTester.h" +#endif + //public: EditActions::EditActions(KTutorialEditor* tutorialEditor): @@ -207,6 +211,18 @@ action->setEnabled(false); actionCollection->addAction("removeReaction", action); connect(action, SIGNAL(triggered(bool)), this, SLOT(removeReaction())); + +#ifdef QT_QTDBUS_FOUND + action = new KAction(this); + action->setText(i18nc("@action", "Test tutorial")); + action->setStatusTip(i18nc("@info:status", "Starts the tutorial in the " +"target application.")); + action->setIcon(KIcon("document-preview")); + action->setEnabled(true); + actionCollection->addAction("testTutorial", action); + connect(action, SIGNAL(triggered(bool)), + new TutorialTester(mTutorialEditor), SLOT(testTutorial())); +#endif } int EditActions::showEditionDialog(CommandWidget* commandWidget) { Modified: trunk/ktutorial/ktutorial-editor/src/EditActions.h =================================================================== --- trunk/ktutorial/ktutorial-editor/src/EditActions.h 2010-09-25 03:01:55 UTC (rev 253) +++ trunk/ktutorial/ktutorial-editor/src/EditActions.h 2010-09-25 03:33:38 UTC (rev 254) @@ -30,7 +30,8 @@ /** * Edition related actions. * EditActions provide the actions to edit a tutorial (set the setup code, add a - * step...), and also actions to undo and redo the edition. + * step...), actions to undo and redo the edition, and also an action to test + * the current tutorial in the target application. * * KTutorialEditor notifies EditActions when a step or reaction is selected, so * it can know which step or reaction have to be edited. EditActions provides Added: trunk/ktutorial/ktutorial-editor/src/TutorialTester.cpp =================================================================== --- trunk/ktutorial/ktutorial-editor/src/TutorialTester.cpp (rev 0) +++ trunk/ktutorial/ktutorial-editor/src/TutorialTester.cpp 2010-09-25 03:33:38 UTC (rev 254) @@ -0,0 +1,92 @@ +/*************************************************************************** + * Copyright (C) 2010 by Daniel Calviño Sánchez * + * dan...@gm... * + * * + * This program is free software; you can redistribute it and/or modify * + * it under the terms of the GNU General Public License as published by * + * the Free Software Foundation; either version 3 of the License, or * + * (at your option) any later version. * + * * + * This program is distributed in the hope that it will be useful, * + * but WITHOUT ANY WARRANTY; without even the implied warranty of * + * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the * + * GNU General Public License for more details. * + * * + * You should have received a copy of the GNU General Public License * + * along with this program; If not, see <http://www.gnu.org/licenses/>. * + ***************************************************************************/ + +#include "TutorialTester.h" + +#include <KLocalizedString> +#include <KMessageBox> +#include <KTemporaryFile> + +#include "KTutorialEditor.h" +#include "serialization/Serialization.h" +#include "targetapplication/RemoteEditorSupport.h" +#include "targetapplication/TargetApplication.h" +#include "view/TargetApplicationView.h" + +//public: + +TutorialTester::TutorialTester(KTutorialEditor* tutorialEditor): + QObject(tutorialEditor), + mTutorialEditor(tutorialEditor) { + + mTargetApplicationView = + new TargetApplicationView(TargetApplication::self(), mTutorialEditor); +} + +//public slots: + +void TutorialTester::testTutorial() { + if (TargetApplication::self()->remoteEditorSupport()) { + sendTutorialToTargetApplication(); + } else { + connect(TargetApplication::self(), SIGNAL(started()), + this, SLOT(sendTutorialToTargetApplication())); + + mTargetApplicationView->start(); + } +} + +//private slots: + +void TutorialTester::sendTutorialToTargetApplication() { + disconnect(TargetApplication::self(), SIGNAL(started()), + this, SLOT(sendTutorialToTargetApplication())); + + //As this TutorialTester is set as parent of the KTemporaryFile object, the + //file will be automatically removed when this TutorialTester is destroyed + KTemporaryFile* temporaryFile = new KTemporaryFile(); + temporaryFile->setAutoRemove(true); + temporaryFile->setParent(this); + temporaryFile->setSuffix(".js"); + temporaryFile->open(); + + const Tutorial* tutorial = mTutorialEditor->tutorial(); + try { + Serialization(mTutorialEditor). + exportTutorial(tutorial, "*.js", temporaryFile->fileName()); + } catch (IOException e) { + QString text = i18nc("@label", "There was a problem when trying to " +"save the tutorial to a temporary file (to be used by the target application " +"to test the tutorial):<nl/>%1", e.message()); + QString caption = i18nc("@title:window", "Tutorial could not be saved"); + KMessageBox::error(mTutorialEditor, text, caption); + delete temporaryFile; + return; + } + + try { + TargetApplication::self()->remoteEditorSupport()->testScriptedTutorial( + temporaryFile->fileName()); + } catch (DBusException e) { + QString text = i18nc("@label", "There was a problem when trying to " +"tell the target application to start the tutorial:<nl/>%1", e.message()); + QString caption = i18nc("@title:window", "Tutorial could not be " +"started"); + KMessageBox::error(mTutorialEditor, text, caption); + } +} Property changes on: trunk/ktutorial/ktutorial-editor/src/TutorialTester.cpp ___________________________________________________________________ Added: svn:eol-style + native Added: trunk/ktutorial/ktutorial-editor/src/TutorialTester.h =================================================================== --- trunk/ktutorial/ktutorial-editor/src/TutorialTester.h (rev 0) +++ trunk/ktutorial/ktutorial-editor/src/TutorialTester.h 2010-09-25 03:33:38 UTC (rev 254) @@ -0,0 +1,73 @@ +/*************************************************************************** + * Copyright (C) 2010 by Daniel Calviño Sánchez * + * dan...@gm... * + * * + * This program is free software; you can redistribute it and/or modify * + * it under the terms of the GNU General Public License as published by * + * the Free Software Foundation; either version 3 of the License, or * + * (at your option) any later version. * + * * + * This program is distributed in the hope that it will be useful, * + * but WITHOUT ANY WARRANTY; without even the implied warranty of * + * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the * + * GNU General Public License for more details. * + * * + * You should have received a copy of the GNU General Public License * + * along with this program; If not, see <http://www.gnu.org/licenses/>. * + ***************************************************************************/ + +#ifndef TUTORIALTESTER_H +#define TUTORIALTESTER_H + +#include <QObject> + +class KTutorialEditor; +class TargetApplicationView; + +/** + * Utility class to test a tutorial in the target application, starting it if + * necessary. + */ +class TutorialTester: public QObject { +Q_OBJECT +public: + + /** + * Creates a new TutorialTester with the given KTutorialEditor. + * + * @param tutorialEditor The parent KTutorialEditor. + */ + explicit TutorialTester(KTutorialEditor* tutorialEditor); + +public Q_SLOTS: + + /** + * Tests the current tutorial in the target application. + * The tutorial is saved to a temporary file that will be removed when the + * editor is closed. + */ + void testTutorial(); + +private: + + /** + * The KTutorialEditor to work with. + */ + KTutorialEditor* mTutorialEditor; + + /** + * The TargetApplicationView used to start the target application. + */ + TargetApplicationView* mTargetApplicationView; + +private Q_SLOTS: + + /** + * Exports the current tutorial to a temporary Javascript file and sends the + * file name to the target application to test the tutorial. + */ + void sendTutorialToTargetApplication(); + +}; + +#endif Property changes on: trunk/ktutorial/ktutorial-editor/src/TutorialTester.h ___________________________________________________________________ Added: svn:eol-style + native Modified: trunk/ktutorial/ktutorial-editor/src/ktutorial-editorui.rc =================================================================== --- trunk/ktutorial/ktutorial-editor/src/ktutorial-editorui.rc 2010-09-25 03:01:55 UTC (rev 253) +++ trunk/ktutorial/ktutorial-editor/src/ktutorial-editorui.rc 2010-09-25 03:33:38 UTC (rev 254) @@ -27,6 +27,8 @@ <Action name="setReactionData"/> <Action name="removeReaction"/> </Menu> + <Separator/> + <Action name="testTutorial"/> </Menu> <Menu name="view"> <Menu name="panels"> @@ -40,5 +42,7 @@ <ToolBar name="mainToolBar"> <Text context="@title:menu">Main Toolbar</Text> <Action name="exportTutorial"/> + <Separator/> + <Action name="testTutorial"/> </ToolBar> </gui> Modified: trunk/ktutorial/ktutorial-editor/src/targetapplication/RemoteEditorSupport.cpp =================================================================== --- trunk/ktutorial/ktutorial-editor/src/targetapplication/RemoteEditorSupport.cpp 2010-09-25 03:01:55 UTC (rev 253) +++ trunk/ktutorial/ktutorial-editor/src/targetapplication/RemoteEditorSupport.cpp 2010-09-25 03:33:38 UTC (rev 254) @@ -99,3 +99,11 @@ delete mRemoteEventSpy; mRemoteEventSpy = 0; } + +void RemoteEditorSupport::testScriptedTutorial(const QString& filename) + throw (DBusException) { + QDBusReply<void> reply = call("testScriptedTutorial", filename); + if (!reply.isValid()) { + throw DBusException(reply.error().message()); + } +} Modified: trunk/ktutorial/ktutorial-editor/src/targetapplication/RemoteEditorSupport.h =================================================================== --- trunk/ktutorial/ktutorial-editor/src/targetapplication/RemoteEditorSupport.h 2010-09-25 03:01:55 UTC (rev 253) +++ trunk/ktutorial/ktutorial-editor/src/targetapplication/RemoteEditorSupport.h 2010-09-25 03:33:38 UTC (rev 254) @@ -114,6 +114,14 @@ */ void disableEventSpy() throw (DBusException); + /** + * Tests the scripted tutorial stored in the file with the given name. + * The target application just starts the tutorial and shows it to the user. + * + * @param filename The name of the file that contains the tutorial to test. + */ + void testScriptedTutorial(const QString& filename) throw (DBusException); + private: /** Modified: trunk/ktutorial/ktutorial-editor/tests/unit/targetapplication/RemoteClassStubs.h =================================================================== --- trunk/ktutorial/ktutorial-editor/tests/unit/targetapplication/RemoteClassStubs.h 2010-09-25 03:01:55 UTC (rev 253) +++ trunk/ktutorial/ktutorial-editor/tests/unit/targetapplication/RemoteClassStubs.h 2010-09-25 03:33:38 UTC (rev 254) @@ -132,6 +132,7 @@ QList<int> mStopHighlightingRemoteWidgetIds; int mEnableEventSpyCount; int mDisableEventSpyCount; + QList<QString> mTestScriptedTutorialFilenames; StubEditorSupport(QObject* parent = 0): QObject(parent), mEventSpy(0), @@ -171,6 +172,10 @@ QDBusConnection::sessionBus().unregisterObject("/ktutorial/EventSpy"); } + void testScriptedTutorial(const QString& filename) { + mTestScriptedTutorialFilenames.append(filename); + } + }; #endif Modified: trunk/ktutorial/ktutorial-editor/tests/unit/targetapplication/RemoteEditorSupportTest.cpp =================================================================== --- trunk/ktutorial/ktutorial-editor/tests/unit/targetapplication/RemoteEditorSupportTest.cpp 2010-09-25 03:01:55 UTC (rev 253) +++ trunk/ktutorial/ktutorial-editor/tests/unit/targetapplication/RemoteEditorSupportTest.cpp 2010-09-25 03:33:38 UTC (rev 254) @@ -65,6 +65,9 @@ void testDisableEventSpyTwice(); void testDisableEventSpyWhenRemoteEditorSupportIsNotAvailable(); + void testTestScriptedTutorial(); + void testTestScriptedTutorialWhenRemoteEditorSupportIsNotAvailable(); + private: StubEditorSupport* mEditorSupport; @@ -328,6 +331,30 @@ EXPECT_EXCEPTION(remoteEditorSupport.disableEventSpy(), DBusException); } +void RemoteEditorSupportTest::testTestScriptedTutorial() { + RemoteObjectMapper mapper(QDBusConnection::sessionBus().baseService()); + RemoteEditorSupport remoteEditorSupport( + QDBusConnection::sessionBus().baseService(), &mapper); + + remoteEditorSupport.testScriptedTutorial("/some/file"); + + QCOMPARE(mEditorSupport->mTestScriptedTutorialFilenames.count(), 1); + QCOMPARE(mEditorSupport->mTestScriptedTutorialFilenames[0], + QString("/some/file")); +} + +void RemoteEditorSupportTest:: + testTestScriptedTutorialWhenRemoteEditorSupportIsNotAvailable() { + RemoteObjectMapper mapper(QDBusConnection::sessionBus().baseService()); + RemoteEditorSupport remoteEditorSupport( + QDBusConnection::sessionBus().baseService(), &mapper); + + QDBusConnection::sessionBus().unregisterObject("/ktutorial"); + + EXPECT_EXCEPTION(remoteEditorSupport.testScriptedTutorial("/some/file"), + DBusException); +} + QTEST_MAIN(RemoteEditorSupportTest) #include "RemoteEditorSupportTest.moc" This was sent by the SourceForge.net collaborative development platform, the world's largest Open Source development site. |
From: <dan...@us...> - 2010-09-25 03:02:02
|
Revision: 253 http://ktutorial.svn.sourceforge.net/ktutorial/?rev=253&view=rev Author: danxuliu Date: 2010-09-25 03:01:55 +0000 (Sat, 25 Sep 2010) Log Message: ----------- Add the ability to test a scripted tutorial through the KTutorial editor support module. Modified Paths: -------------- trunk/ktutorial/ktutorial-library/src/KTutorial.cpp trunk/ktutorial/ktutorial-library/src/Tutorial.cpp trunk/ktutorial/ktutorial-library/src/Tutorial.h trunk/ktutorial/ktutorial-library/src/TutorialManager.cpp trunk/ktutorial/ktutorial-library/src/editorsupport/CMakeLists.txt trunk/ktutorial/ktutorial-library/src/editorsupport/EditorSupport.cpp trunk/ktutorial/ktutorial-library/src/editorsupport/EditorSupport.h trunk/ktutorial/ktutorial-library/src/editorsupport/EditorSupportAdaptor.cpp trunk/ktutorial/ktutorial-library/src/editorsupport/EditorSupportAdaptor.h trunk/ktutorial/ktutorial-library/tests/TutorialManagerTest.cpp trunk/ktutorial/ktutorial-library/tests/TutorialTest.cpp trunk/ktutorial/ktutorial-library/tests/editorsupport/CMakeLists.txt trunk/ktutorial/ktutorial-library/tests/editorsupport/EditorSupportAdaptorTest.cpp trunk/ktutorial/ktutorial-library/tests/editorsupport/EditorSupportTest.cpp trunk/ktutorial/ktutorial-library/tests/view/TutorialManagerDialogTest.cpp Modified: trunk/ktutorial/ktutorial-library/src/KTutorial.cpp =================================================================== --- trunk/ktutorial/ktutorial-library/src/KTutorial.cpp 2010-09-24 17:30:22 UTC (rev 252) +++ trunk/ktutorial/ktutorial-library/src/KTutorial.cpp 2010-09-25 03:01:55 UTC (rev 253) @@ -84,7 +84,11 @@ ScriptManager().loadTutorials(mTutorialmanager); #ifdef QT_QTDBUS_FOUND - (new editorsupport::EditorSupport(this))->setup(window); + editorsupport::EditorSupport* editorSupport = + new editorsupport::EditorSupport(this); + editorSupport->setup(window); + connect(editorSupport, SIGNAL(started(Tutorial*)), + this, SLOT(showStepWidget(Tutorial*))); #endif } Modified: trunk/ktutorial/ktutorial-library/src/Tutorial.cpp =================================================================== --- trunk/ktutorial/ktutorial-library/src/Tutorial.cpp 2010-09-24 17:30:22 UTC (rev 252) +++ trunk/ktutorial/ktutorial-library/src/Tutorial.cpp 2010-09-25 03:01:55 UTC (rev 253) @@ -95,5 +95,5 @@ tearDown(); - emit finished(); + emit finished(this); } Modified: trunk/ktutorial/ktutorial-library/src/Tutorial.h =================================================================== --- trunk/ktutorial/ktutorial-library/src/Tutorial.h 2010-09-24 17:30:22 UTC (rev 252) +++ trunk/ktutorial/ktutorial-library/src/Tutorial.h 2010-09-25 03:01:55 UTC (rev 253) @@ -158,8 +158,10 @@ * This signal is emitted when this Tutorial finishes. * Don't connect nor emit this signal yourself. It is connected * automatically by KTutorial. + * + * @param tutorial This tutorial. */ - void finished(); + void finished(Tutorial* tutorial); /** * This signal is emitted when a Step is activated. Modified: trunk/ktutorial/ktutorial-library/src/TutorialManager.cpp =================================================================== --- trunk/ktutorial/ktutorial-library/src/TutorialManager.cpp 2010-09-24 17:30:22 UTC (rev 252) +++ trunk/ktutorial/ktutorial-library/src/TutorialManager.cpp 2010-09-25 03:01:55 UTC (rev 253) @@ -53,7 +53,7 @@ kDebug() << "Started: " << id; Tutorial* tutorial = mTutorials.value(mTutorialInformations.value(id)); - connect(tutorial, SIGNAL(finished()), this, SLOT(finish())); + connect(tutorial, SIGNAL(finished(Tutorial*)), this, SLOT(finish())); emit started(tutorial); Modified: trunk/ktutorial/ktutorial-library/src/editorsupport/CMakeLists.txt =================================================================== --- trunk/ktutorial/ktutorial-library/src/editorsupport/CMakeLists.txt 2010-09-24 17:30:22 UTC (rev 252) +++ trunk/ktutorial/ktutorial-library/src/editorsupport/CMakeLists.txt 2010-09-25 03:01:55 UTC (rev 253) @@ -14,6 +14,7 @@ target_link_libraries(ktutorial_editorsupport ktutorial_extendedinformation + ktutorial_scripting ${QT_QTDBUS_LIBRARY} ${KDE4_KDECORE_LIBS} ) Modified: trunk/ktutorial/ktutorial-library/src/editorsupport/EditorSupport.cpp =================================================================== --- trunk/ktutorial/ktutorial-library/src/editorsupport/EditorSupport.cpp 2010-09-24 17:30:22 UTC (rev 252) +++ trunk/ktutorial/ktutorial-library/src/editorsupport/EditorSupport.cpp 2010-09-25 03:01:55 UTC (rev 253) @@ -29,8 +29,10 @@ #include "ObjectRegister.h" #include "ObjectRegisterAdaptor.h" #include "../extendedinformation/WidgetHighlighterManager.h" +#include "../scripting/ScriptedTutorial.h" using extendedinformation::WidgetHighlighterManager; +using scripting::ScriptedTutorial; namespace editorsupport { @@ -101,4 +103,29 @@ mEventSpy = 0; } +void EditorSupport::testScriptedTutorial(const QString& filename) { + ScriptedTutorial* scriptedTutorial = new ScriptedTutorial(filename); + + if (!scriptedTutorial->isValid()) { + kWarning() << "Cannot test the scripted tutorial stored in " + << filename << ": the script is invalid"; + delete scriptedTutorial; + return; + } + + connect(scriptedTutorial, SIGNAL(finished(Tutorial*)), + this, SLOT(deleteFinishedTestTutorial(Tutorial*))); + + emit started(scriptedTutorial); + + scriptedTutorial->start(); } + +//private: + +void EditorSupport::deleteFinishedTestTutorial(Tutorial* tutorial) { + tutorial->deleteLater(); +} + + +} Modified: trunk/ktutorial/ktutorial-library/src/editorsupport/EditorSupport.h =================================================================== --- trunk/ktutorial/ktutorial-library/src/editorsupport/EditorSupport.h 2010-09-24 17:30:22 UTC (rev 252) +++ trunk/ktutorial/ktutorial-library/src/editorsupport/EditorSupport.h 2010-09-25 03:01:55 UTC (rev 253) @@ -21,6 +21,8 @@ #include <QObject> +class Tutorial; + namespace editorsupport { class EventSpy; class EventSupportAdaptor; @@ -40,7 +42,8 @@ * The main object sets up the D-Bus objects and provides a way to enable and * disable the EventSpy (as notifying all the events sent by an application * through D-Bus is very costly, the EventSpy should be enabled only when - * needed), and highlight and stop the highlighting of widgets. + * needed), highlight and stop the highlighting of widgets, and test a scripted + * tutorial (starting the tutorial stored in the given filename). * * The object register assigns an id to QObjects to be identified by the remote * KTutorial editor. Using that id, KTutorial editor can request further @@ -116,6 +119,22 @@ */ void disableEventSpy(); + /** + * Starts the scripted tutorial stored in the given filename. + * + * @param filename The name of the file to read the scripted tutorial from. + */ + void testScriptedTutorial(const QString& filename); + +Q_SIGNALS: + + /** + * This signals is emitted when the given tutorial is about to be started. + * + * @param tutorial The tutorial that is going to be started. + */ + void started(Tutorial* tutorial); + private: /** @@ -133,6 +152,15 @@ */ QObject* mWindow; +private Q_SLOTS: + + /** + * Deletes the test tutorial when it is finished. + * + * @param tutorial The tutorial to delete. + */ + void deleteFinishedTestTutorial(Tutorial* tutorial); + }; } Modified: trunk/ktutorial/ktutorial-library/src/editorsupport/EditorSupportAdaptor.cpp =================================================================== --- trunk/ktutorial/ktutorial-library/src/editorsupport/EditorSupportAdaptor.cpp 2010-09-24 17:30:22 UTC (rev 252) +++ trunk/ktutorial/ktutorial-library/src/editorsupport/EditorSupportAdaptor.cpp 2010-09-25 03:01:55 UTC (rev 253) @@ -57,4 +57,8 @@ mEditorSupport->disableEventSpy(); } +void EditorSupportAdaptor::testScriptedTutorial(const QString& filename) { + mEditorSupport->testScriptedTutorial(filename); } + +} Modified: trunk/ktutorial/ktutorial-library/src/editorsupport/EditorSupportAdaptor.h =================================================================== --- trunk/ktutorial/ktutorial-library/src/editorsupport/EditorSupportAdaptor.h 2010-09-24 17:30:22 UTC (rev 252) +++ trunk/ktutorial/ktutorial-library/src/editorsupport/EditorSupportAdaptor.h 2010-09-25 03:01:55 UTC (rev 253) @@ -87,6 +87,13 @@ */ void disableEventSpy(); + /** + * Starts the scripted tutorial stored in the given filename. + * + * @param filename The name of the file to read the scripted tutorial from. + */ + void testScriptedTutorial(const QString& filename); + private: /** Modified: trunk/ktutorial/ktutorial-library/tests/TutorialManagerTest.cpp =================================================================== --- trunk/ktutorial/ktutorial-library/tests/TutorialManagerTest.cpp 2010-09-24 17:30:22 UTC (rev 252) +++ trunk/ktutorial/ktutorial-library/tests/TutorialManagerTest.cpp 2010-09-25 03:01:55 UTC (rev 253) @@ -62,7 +62,7 @@ } void emitFinished() { - emit finished(); + emit finished(this); } }; Modified: trunk/ktutorial/ktutorial-library/tests/TutorialTest.cpp =================================================================== --- trunk/ktutorial/ktutorial-library/tests/TutorialTest.cpp 2010-09-24 17:30:22 UTC (rev 252) +++ trunk/ktutorial/ktutorial-library/tests/TutorialTest.cpp 2010-09-25 03:01:55 UTC (rev 253) @@ -188,6 +188,9 @@ //Step* must be declared as a metatype to be used in qvariant_cast Q_DECLARE_METATYPE(Step*); +//Tutorial* must be declared as a metatype to be used in qvariant_cast +Q_DECLARE_METATYPE(Tutorial*); + void TutorialTest::testStart() { MockTutorial tutorial(new TutorialInformation("pearlOrientation")); @@ -202,7 +205,9 @@ int stepStarType = qRegisterMetaType<Step*>("Step*"); QSignalSpy stepActivatedSpy(&tutorial, SIGNAL(stepActivated(Step*))); - QSignalSpy finishedSpy(&tutorial, SIGNAL(finished())); + //Tutorial* must be registered in order to be used with QSignalSpy + qRegisterMetaType<Tutorial*>("Tutorial*"); + QSignalSpy finishedSpy(&tutorial, SIGNAL(finished(Tutorial*))); tutorial.start(); @@ -228,7 +233,9 @@ qRegisterMetaType<Step*>("Step*"); QSignalSpy stepActivatedSpy(&tutorial, SIGNAL(stepActivated(Step*))); - QSignalSpy finishedSpy(&tutorial, SIGNAL(finished())); + //Tutorial* must be registered in order to be used with QSignalSpy + int tutorialStarType = qRegisterMetaType<Tutorial*>("Tutorial*"); + QSignalSpy finishedSpy(&tutorial, SIGNAL(finished(Tutorial*))); tutorial.start(); @@ -236,6 +243,9 @@ QCOMPARE(stepActivatedSpy.count(), 0); QCOMPARE(tutorial.mCurrentStep, (Step*)0); QCOMPARE(finishedSpy.count(), 1); + QVariant argument = finishedSpy.at(0).at(0); + QCOMPARE(argument.userType(), tutorialStarType); + QCOMPARE(qvariant_cast<Tutorial*>(argument), &tutorial); QCOMPARE(tutorial.mTearDownCount, 1); } @@ -387,7 +397,9 @@ Step* stepStart = new Step("start"); tutorial.addStep(stepStart); - QSignalSpy finishedSpy(&tutorial, SIGNAL(finished())); + //Tutorial* must be registered in order to be used with QSignalSpy + int tutorialStarType = qRegisterMetaType<Tutorial*>("Tutorial*"); + QSignalSpy finishedSpy(&tutorial, SIGNAL(finished(Tutorial*))); tutorial.start(); tutorial.finish(); @@ -395,6 +407,9 @@ QCOMPARE(tutorial.mCurrentStep, (Step*)0); QVERIFY(!stepStart->isActive()); QCOMPARE(finishedSpy.count(), 1); + QVariant argument = finishedSpy.at(0).at(0); + QCOMPARE(argument.userType(), tutorialStarType); + QCOMPARE(qvariant_cast<Tutorial*>(argument), &tutorial); QCOMPARE(tutorial.mTearDownCount, 1); } Modified: trunk/ktutorial/ktutorial-library/tests/editorsupport/CMakeLists.txt =================================================================== --- trunk/ktutorial/ktutorial-library/tests/editorsupport/CMakeLists.txt 2010-09-24 17:30:22 UTC (rev 252) +++ trunk/ktutorial/ktutorial-library/tests/editorsupport/CMakeLists.txt 2010-09-25 03:01:55 UTC (rev 253) @@ -12,7 +12,7 @@ FOREACH(_className ${ARGN}) set(_testName ${_className}Test) kde4_add_unit_test(${_testName} TESTNAME ktutorial-${_testName} ${_testName}.cpp) - target_link_libraries(${_testName} ktutorial_editorsupport ${QT_QTTEST_LIBRARY}) + target_link_libraries(${_testName} ktutorial_editorsupport ktutorial ${QT_QTTEST_LIBRARY}) ENDFOREACH(_className) ENDMACRO(UNIT_TESTS) Modified: trunk/ktutorial/ktutorial-library/tests/editorsupport/EditorSupportAdaptorTest.cpp =================================================================== --- trunk/ktutorial/ktutorial-library/tests/editorsupport/EditorSupportAdaptorTest.cpp 2010-09-24 17:30:22 UTC (rev 252) +++ trunk/ktutorial/ktutorial-library/tests/editorsupport/EditorSupportAdaptorTest.cpp 2010-09-25 03:01:55 UTC (rev 253) @@ -21,6 +21,8 @@ #include <QWidget> #include <QtDBus/QtDBus> +#include <KTemporaryFile> + #include "EditorSupportAdaptor.h" #include "EditorSupport.h" @@ -51,6 +53,8 @@ void testDisableEventSpy(); + void testTestScriptedTutorial(); + }; void EditorSupportAdaptorTest::testConstructor() { @@ -132,8 +136,30 @@ QVERIFY(!bus.objectRegisteredAt("/ktutorial/EventSpy")); } +void EditorSupportAdaptorTest::testTestScriptedTutorial() { + KTemporaryFile temporaryFile; + temporaryFile.setSuffix(".js"); + temporaryFile.open(); + + QTextStream out(&temporaryFile); + out << "tutorial.tutorialInformationAsObject().setName(\ +\"Test tutorial\");\n"; + out.flush(); + + EditorSupport editorSupport; + EditorSupportAdaptor* adaptor = new EditorSupportAdaptor(&editorSupport); + + //Tutorial* must be registered in order to be used with QSignalSpy + int tutorialStarType = qRegisterMetaType<Tutorial*>("Tutorial*"); + QSignalSpy startedSpy(&editorSupport, SIGNAL(started(Tutorial*))); + + adaptor->testScriptedTutorial(temporaryFile.fileName()); + + QCOMPARE(startedSpy.count(), 1); } +} + QTEST_MAIN(editorsupport::EditorSupportAdaptorTest) #include "EditorSupportAdaptorTest.moc" Modified: trunk/ktutorial/ktutorial-library/tests/editorsupport/EditorSupportTest.cpp =================================================================== --- trunk/ktutorial/ktutorial-library/tests/editorsupport/EditorSupportTest.cpp 2010-09-24 17:30:22 UTC (rev 252) +++ trunk/ktutorial/ktutorial-library/tests/editorsupport/EditorSupportTest.cpp 2010-09-25 03:01:55 UTC (rev 253) @@ -21,6 +21,8 @@ #include <QApplication> #include <QtDBus/QtDBus> +#include <KTemporaryFile> + #define protected public #define private public #include "EditorSupport.h" @@ -31,10 +33,15 @@ #include "EventSpy.h" #include "ObjectRegister.h" #include "ObjectRegisterAdaptor.h" +#include "../Tutorial.h" +#include "../TutorialInformation.h" #include "../extendedinformation/WidgetHighlighter.h" using extendedinformation::WidgetHighlighter; +//Tutorial* must be declared as a metatype to be used in qvariant_cast +Q_DECLARE_METATYPE(Tutorial*); + namespace editorsupport { class EditorSupportTest: public QObject { @@ -65,6 +72,9 @@ void testDisableEventSpy(); + void testTestScriptedTutorial(); + void testTestScriptedTutorialWithInvalidTutorial(); + private: QStringList mEventTypes; @@ -212,8 +222,79 @@ QCOMPARE(mEventTypes.count(), 0); } +void EditorSupportTest::testTestScriptedTutorial() { + KTemporaryFile temporaryFile; + temporaryFile.setSuffix(".js"); + temporaryFile.open(); + + QTextStream out(&temporaryFile); + out << "tutorial.tutorialInformationAsObject().setName(\ +\"Test tutorial\");\n"; + out << "tutorial.addStep(ktutorial.newStep(\"start\"))"; + out.flush(); + + EditorSupport editorSupport; + + //Tutorial* must be registered in order to be used with QSignalSpy + int tutorialStarType = qRegisterMetaType<Tutorial*>("Tutorial*"); + QSignalSpy startedSpy(&editorSupport, SIGNAL(started(Tutorial*))); + + editorSupport.testScriptedTutorial(temporaryFile.fileName()); + + QCOMPARE(startedSpy.count(), 1); + QVariant argument = startedSpy.at(0).at(0); + QCOMPARE(argument.userType(), tutorialStarType); + + Tutorial* tutorial = qvariant_cast<Tutorial*>(argument); + QVERIFY(tutorial->tutorialInformation()); + QCOMPARE(tutorial->tutorialInformation()->id(), + temporaryFile.fileName()); + QCOMPARE(tutorial->tutorialInformation()->name(), QString("Test tutorial")); + + //Ensuring that the tutorial was really started is too cumbersome + + QSignalSpy destroyedSpy(tutorial, SIGNAL(destroyed())); + + //Process deleteLater() + QCoreApplication::sendPostedEvents(tutorial, QEvent::DeferredDelete); + + //Ensure that the tutorial is not deleted before explicitly calling finish + //(for example, if the test tutorial written in the text stream does not + //have a start step) + QCOMPARE(destroyedSpy.count(), 0); + + tutorial->finish(); + + //Process deleteLater() + QCoreApplication::sendPostedEvents(tutorial, QEvent::DeferredDelete); + + QCOMPARE(destroyedSpy.count(), 1); } +void EditorSupportTest::testTestScriptedTutorialWithInvalidTutorial() { + KTemporaryFile temporaryFile; + temporaryFile.setSuffix(".js"); + temporaryFile.open(); + + QTextStream out(&temporaryFile); + out << "tutorial.tutorialInformationAsObject().setName(\ +\"Test tutorial\");\n"; + out << "Just a bunch of text to make the script invalid\n"; + out.flush(); + + EditorSupport editorSupport; + + //Tutorial* must be registered in order to be used with QSignalSpy + qRegisterMetaType<Tutorial*>("Tutorial*"); + QSignalSpy startedSpy(&editorSupport, SIGNAL(started(Tutorial*))); + + editorSupport.testScriptedTutorial(temporaryFile.fileName()); + + QCOMPARE(startedSpy.count(), 0); +} + +} + QTEST_MAIN(editorsupport::EditorSupportTest) #include "EditorSupportTest.moc" Modified: trunk/ktutorial/ktutorial-library/tests/view/TutorialManagerDialogTest.cpp =================================================================== --- trunk/ktutorial/ktutorial-library/tests/view/TutorialManagerDialogTest.cpp 2010-09-24 17:30:22 UTC (rev 252) +++ trunk/ktutorial/ktutorial-library/tests/view/TutorialManagerDialogTest.cpp 2010-09-25 03:01:55 UTC (rev 253) @@ -89,7 +89,7 @@ } void emitFinished() { - emit finished(); + emit finished(this); } }; This was sent by the SourceForge.net collaborative development platform, the world's largest Open Source development site. |
From: <dan...@us...> - 2010-09-24 17:30:35
|
Revision: 252 http://ktutorial.svn.sourceforge.net/ktutorial/?rev=252&view=rev Author: danxuliu Date: 2010-09-24 17:30:22 +0000 (Fri, 24 Sep 2010) Log Message: ----------- -Fix not restoring the normal cursor shape when the target application was closed before the editor was able to decide whether it supported KTutorial or not. -Fix showing the error message several times if the target application was successfully started several times and then failed to start. Modified Paths: -------------- trunk/ktutorial/ktutorial-editor/src/view/TargetApplicationView.cpp trunk/ktutorial/ktutorial-editor/src/view/TargetApplicationView.h Modified: trunk/ktutorial/ktutorial-editor/src/view/TargetApplicationView.cpp =================================================================== --- trunk/ktutorial/ktutorial-editor/src/view/TargetApplicationView.cpp 2010-09-21 16:24:13 UTC (rev 251) +++ trunk/ktutorial/ktutorial-editor/src/view/TargetApplicationView.cpp 2010-09-24 17:30:22 UTC (rev 252) @@ -51,13 +51,8 @@ mTargetApplication->setTargetApplicationFilePath(path); } - connect(mTargetApplication, SIGNAL(started()), - this, SLOT(restoreCursor())); - connect(mTargetApplication, SIGNAL(startFailed(TargetApplication::Error)), - this, SLOT(showErrorMessage(TargetApplication::Error))); + startExpectingTheTargetApplicationToStart(); - QApplication::setOverrideCursor(QCursor(Qt::BusyCursor)); - mTargetApplication->start(); } @@ -84,10 +79,28 @@ return executable; } +void TargetApplicationView::startExpectingTheTargetApplicationToStart() { + //Only knowing if the TargetApplication failed to start is relevant in order + //to show the error message. However, once started the signal must be + //disconnected to avoid showing several error messages (for example, if the + //target application fails after being started several times by this view). + //finished() is also connected, as if the target application is closed + //before it could be checked whether it supports KTutorial or not, only + //finished() signal is emitted. + connect(mTargetApplication, SIGNAL(started()), + this, SLOT(stopExpectingTheTargetApplicationToStart())); + connect(mTargetApplication, SIGNAL(startFailed(TargetApplication::Error)), + this, SLOT(showErrorMessage(TargetApplication::Error))); + connect(mTargetApplication, SIGNAL(finished()), + this, SLOT(stopExpectingTheTargetApplicationToStart())); + + QApplication::setOverrideCursor(QCursor(Qt::BusyCursor)); +} + //private slots: void TargetApplicationView::showErrorMessage(TargetApplication::Error error) { - restoreCursor(); + stopExpectingTheTargetApplicationToStart(); QString caption = i18nc("@title:window", "Problem starting the target \ application"); @@ -111,6 +124,13 @@ mTargetApplication->setTargetApplicationFilePath(""); } -void TargetApplicationView::restoreCursor() { +void TargetApplicationView::stopExpectingTheTargetApplicationToStart() { + disconnect(mTargetApplication, SIGNAL(started()), + this, SLOT(stopExpectingTheTargetApplicationToStart())); + disconnect(mTargetApplication, SIGNAL(startFailed(TargetApplication::Error)), + this, SLOT(showErrorMessage(TargetApplication::Error))); + disconnect(mTargetApplication, SIGNAL(finished()), + this, SLOT(stopExpectingTheTargetApplicationToStart())); + QApplication::restoreOverrideCursor(); } Modified: trunk/ktutorial/ktutorial-editor/src/view/TargetApplicationView.h =================================================================== --- trunk/ktutorial/ktutorial-editor/src/view/TargetApplicationView.h 2010-09-21 16:24:13 UTC (rev 251) +++ trunk/ktutorial/ktutorial-editor/src/view/TargetApplicationView.h 2010-09-24 17:30:22 UTC (rev 252) @@ -42,7 +42,7 @@ QWidget* parent = 0); /** - * Convenienve method to start the target application. + * Convenience method to start the target application. * It asks for the executable to be executed if the target application does * not have one set yet. When the application is started, the cursor is set * to the busy shape until the target application has started or failed to @@ -70,6 +70,12 @@ */ QString askApplicationFilePath(); + /** + * Connects to the TargetApplication signals and sets the cursor to the busy + * shape. + */ + void startExpectingTheTargetApplicationToStart(); + private Q_SLOTS: /** @@ -81,9 +87,10 @@ void showErrorMessage(TargetApplication::Error error); /** - * Restores the cursor to the normal shape. + * Disconnects from the TargetApplication signals and restores the normal + * cursor. */ - void restoreCursor(); + void stopExpectingTheTargetApplicationToStart(); }; This was sent by the SourceForge.net collaborative development platform, the world's largest Open Source development site. |
From: <dan...@us...> - 2010-09-21 16:24:20
|
Revision: 251 http://ktutorial.svn.sourceforge.net/ktutorial/?rev=251&view=rev Author: danxuliu Date: 2010-09-21 16:24:13 +0000 (Tue, 21 Sep 2010) Log Message: ----------- Fix handbook localization: the "English" entity in the base Docbook files must be changed to the language of the localization. If this is not done, the common KDE entities will be replaced with their English value instead of their localized value. Modified Paths: -------------- trunk/ktutorial/ktutorial-editor/doc/CMakeLists.txt Added Paths: ----------- trunk/ktutorial/ktutorial-editor/doc/es/language Modified: trunk/ktutorial/ktutorial-editor/doc/CMakeLists.txt =================================================================== --- trunk/ktutorial/ktutorial-editor/doc/CMakeLists.txt 2010-09-20 19:30:21 UTC (rev 250) +++ trunk/ktutorial/ktutorial-editor/doc/CMakeLists.txt 2010-09-21 16:24:13 UTC (rev 251) @@ -9,6 +9,15 @@ ------") else(NOT PO2XML_EXECUTABLE) + find_program(SED_EXECUTABLE sed) + + if(NOT SED_EXECUTABLE) + message( +"------ + NOTE: sed not found. Common KDE text in handbooks will *not* be translated +------") + endif(NOT SED_EXECUTABLE) + file(GLOB_RECURSE PO_FILES ktutorial-editor-handbook.po) file(GLOB DOCBOOK_FILES en/*.docbook) @@ -23,24 +32,45 @@ # directory foreach(docbookFile ${DOCBOOK_FILES}) get_filename_component(docbookFileName ${docbookFile} NAME) - set(translatedDocbookFile ${CMAKE_CURRENT_SOURCE_DIR}/${lang}/${docbookFileName}) + set(langDirectory ${CMAKE_CURRENT_SOURCE_DIR}/${lang}) + set(translatedDocbookFile ${langDirectory}/${docbookFileName}) list(APPEND allTranslatedDocbookFiles ${translatedDocbookFile}) set(po2XmlCommand ${PO2XML_EXECUTABLE} ${docbookFile} ${poFile}) - add_custom_command(OUTPUT ${translatedDocbookFile} - COMMAND ${po2XmlCommand} > ${translatedDocbookFile} - DEPENDS ${docbookFile} ${poFile}) + # kde4_create_handbook gets a list of the docbook files that had to + # be copied when the handbook is installed. The custom commands + # below create the translation for each file in order to be found by + # the kde4_create_handbook macro. Also, the translations will be + # updated as needed by the build system if the docbook or the po + # file were modified. + # Note, however, that the translations are created/updated under the + # source directory, not the build directory, as there is where + # kde4_create_handbook expects them. + if(NOT SED_EXECUTABLE) + add_custom_command(OUTPUT ${translatedDocbookFile} + COMMAND ${po2XmlCommand} > ${translatedDocbookFile} + DEPENDS ${docbookFile} ${poFile}) + else(NOT SED_EXECUTABLE) - # kde4_create_handbook gets a list of the docbook files that had to - # be copied when the handbook is installed. It creates, when the - # configuration previous to the build is made, the translation for - # each file in order to be found by the macro. - # It does not interfere with the normmal behavior of the build - # system. The translations will be updated as needed when the - # docbook or the po file are modified. - execute_process(COMMAND ${po2XmlCommand} - OUTPUT_FILE ${translatedDocbookFile}) + # sed is used to set the entity containing the name of the + # language to its appropriate value in each translated + # index.docbook file. + # If this is not done, the rest of the entities appear in + # English instead of in the language of the translation. + # The name of the language is read from the language file in + # each localization directory. + file(READ ${langDirectory}/language langName) + set(sedCommand ${SED_EXECUTABLE} + "-e \"s/<!ENTITY % English/<!ENTITY % ${langName}/\"" + -i ${translatedDocbookFile} + ) + + add_custom_command(OUTPUT ${translatedDocbookFile} + COMMAND ${po2XmlCommand} > ${translatedDocbookFile} + COMMAND ${sedCommand} + DEPENDS ${docbookFile} ${poFile}) + endif(NOT SED_EXECUTABLE) endforeach(docbookFile ${DOCBOOK_FILES}) endforeach(poFile ${PO_FILES}) Added: trunk/ktutorial/ktutorial-editor/doc/es/language =================================================================== --- trunk/ktutorial/ktutorial-editor/doc/es/language (rev 0) +++ trunk/ktutorial/ktutorial-editor/doc/es/language 2010-09-21 16:24:13 UTC (rev 251) @@ -0,0 +1 @@ +Spanish \ No newline at end of file This was sent by the SourceForge.net collaborative development platform, the world's largest Open Source development site. |
From: <dan...@us...> - 2010-09-20 19:30:27
|
Revision: 250 http://ktutorial.svn.sourceforge.net/ktutorial/?rev=250&view=rev Author: danxuliu Date: 2010-09-20 19:30:21 +0000 (Mon, 20 Sep 2010) Log Message: ----------- Fix crash when an application not supporting KTutorial was closed before TargetApplication realized that the application did not support KTutorial. Modified Paths: -------------- trunk/ktutorial/ktutorial-editor/src/targetapplication/TargetApplication.cpp trunk/ktutorial/ktutorial-editor/src/targetapplication/TargetApplication.h trunk/ktutorial/ktutorial-editor/tests/unit/targetapplication/TargetApplicationTest.cpp Modified: trunk/ktutorial/ktutorial-editor/src/targetapplication/TargetApplication.cpp =================================================================== --- trunk/ktutorial/ktutorial-editor/src/targetapplication/TargetApplication.cpp 2010-09-19 16:40:33 UTC (rev 249) +++ trunk/ktutorial/ktutorial-editor/src/targetapplication/TargetApplication.cpp 2010-09-20 19:30:21 UTC (rev 250) @@ -162,6 +162,12 @@ } void TargetApplication::handleTargetApplicationDoesNotSupportKTutorial() { + //The target application not using KTutorial may have been closed by the + //user before the timeout expired and this slot was called + if (!mProcess) { + return; + } + mProcess->kill(); emit startFailed(InvalidApplication); Modified: trunk/ktutorial/ktutorial-editor/src/targetapplication/TargetApplication.h =================================================================== --- trunk/ktutorial/ktutorial-editor/src/targetapplication/TargetApplication.h 2010-09-19 16:40:33 UTC (rev 249) +++ trunk/ktutorial/ktutorial-editor/src/targetapplication/TargetApplication.h 2010-09-20 19:30:21 UTC (rev 250) @@ -46,6 +46,10 @@ * other problem happened (for example, if the target application does not * support KTutorial), startFailed(Error) signal is emitted instead. * + * Note that started() and startFailed(Error) signals may not be emitted if the + * target application is closed too soon to realize that it was successfully + * started or that it does not support KTutorial. + * * Once the target application has been started, remoteEditorSupport * returns a RemoteEditorSupport connected to the remote * "org.kde.ktutorial.EditorSupport" interface exposed by the target Modified: trunk/ktutorial/ktutorial-editor/tests/unit/targetapplication/TargetApplicationTest.cpp =================================================================== --- trunk/ktutorial/ktutorial-editor/tests/unit/targetapplication/TargetApplicationTest.cpp 2010-09-19 16:40:33 UTC (rev 249) +++ trunk/ktutorial/ktutorial-editor/tests/unit/targetapplication/TargetApplicationTest.cpp 2010-09-20 19:30:21 UTC (rev 250) @@ -68,6 +68,8 @@ void testStartApplicationNotUsingKTutorial(); void testApplicationStopped(); + void testApplicationStoppedBeforeBeingSuccessfullyStarted(); + void testApplicationNotUsingKTutorialStoppedBeforeCheckTimeout(); private: @@ -383,6 +385,71 @@ QVERIFY(!targetApplication.remoteEditorSupport()); } +void TargetApplicationTest:: + testApplicationStoppedBeforeBeingSuccessfullyStarted() { + TargetApplication targetApplication; + targetApplication.setTargetApplicationFilePath(mTargetApplicationStubPath); + + QSignalSpy startedSpy(&targetApplication, SIGNAL(started())); + //TargetApplication::Error must be registered in order to be used with + //QSignalSpy + qRegisterMetaType<TargetApplication::Error>("TargetApplication::Error"); + QSignalSpy startFailedSpy(&targetApplication, + SIGNAL(startFailed(TargetApplication::Error))); + SignalWait finishedWait(&targetApplication, SIGNAL(finished())); + + targetApplication.start(); + + //Give the application some time to start before killing it, but not enough + //time to start successfully + QTest::qWait(5); + + targetApplication.mProcess->kill(); + + QVERIFY(finishedWait.waitForCount(1, 1000)); + QVERIFY(!targetApplication.remoteEditorSupport()); + + //Keep waiting until the timeout expires to ensure that no other signal is + //emitted or the process is tried to be killed again + QTest::qWait(3000); + + QCOMPARE(startedSpy.count(), 0); + QCOMPARE(startFailedSpy.count(), 0); +} + +void TargetApplicationTest:: + testApplicationNotUsingKTutorialStoppedBeforeCheckTimeout() { + TargetApplication targetApplication; + targetApplication.setTargetApplicationFilePath( + QApplication::applicationDirPath() + "/DummyApplication"); + + QSignalSpy startedSpy(&targetApplication, SIGNAL(started())); + //TargetApplication::Error must be registered in order to be used with + //QSignalSpy + qRegisterMetaType<TargetApplication::Error>("TargetApplication::Error"); + QSignalSpy startFailedSpy(&targetApplication, + SIGNAL(startFailed(TargetApplication::Error))); + SignalWait finishedWait(&targetApplication, SIGNAL(finished())); + + targetApplication.start(); + + //Give the application some time to start before killing it, but not enough + //time to realize that it does not use KTutorial + QTest::qWait(1000); + + targetApplication.mProcess->kill(); + + QVERIFY(finishedWait.waitForCount(1, 1000)); + QVERIFY(!targetApplication.remoteEditorSupport()); + + //Keep waiting until the timeout expires to ensure that no other signal is + //emitted or the process is tried to be killed again + QTest::qWait(3000); + + QCOMPARE(startedSpy.count(), 0); + QCOMPARE(startFailedSpy.count(), 0); +} + QTEST_MAIN(TargetApplicationTest) #include "TargetApplicationTest.moc" This was sent by the SourceForge.net collaborative development platform, the world's largest Open Source development site. |
From: <dan...@us...> - 2010-09-19 16:40:41
|
Revision: 249 http://ktutorial.svn.sourceforge.net/ktutorial/?rev=249&view=rev Author: danxuliu Date: 2010-09-19 16:40:33 +0000 (Sun, 19 Sep 2010) Log Message: ----------- Fix StepWidget being blocked when a modal dialog is shown: now when a modal dialog is shown, the StepWidget is reparented to the modal dialog so it is no longer blocked, and when the modal dialog is closed, the StepWidget is reparented back to its previous parent. Modified Paths: -------------- trunk/ktutorial/ktutorial-library/src/CMakeLists.txt trunk/ktutorial/ktutorial-library/src/KTutorial.cpp trunk/ktutorial/ktutorial-library/src/view/CMakeLists.txt trunk/ktutorial/ktutorial-library/src/view/StepWidget.cpp trunk/ktutorial/ktutorial-library/src/view/StepWidget.h trunk/ktutorial/ktutorial-library/tests/CMakeLists.txt trunk/ktutorial/ktutorial-library/tests/view/CMakeLists.txt trunk/ktutorial/ktutorial-library/tests/view/StepWidgetTest.cpp Added Paths: ----------- trunk/ktutorial/ktutorial-library/src/common/ trunk/ktutorial/ktutorial-library/src/common/CMakeLists.txt trunk/ktutorial/ktutorial-library/src/common/WindowVisibilitySpy.cpp trunk/ktutorial/ktutorial-library/src/common/WindowVisibilitySpy.h trunk/ktutorial/ktutorial-library/src/view/WindowOnTopEnforcer.cpp trunk/ktutorial/ktutorial-library/src/view/WindowOnTopEnforcer.h trunk/ktutorial/ktutorial-library/tests/common/ trunk/ktutorial/ktutorial-library/tests/common/CMakeLists.txt trunk/ktutorial/ktutorial-library/tests/common/WindowVisibilitySpyTest.cpp trunk/ktutorial/ktutorial-library/tests/view/WindowOnTopEnforcerTest.cpp Modified: trunk/ktutorial/ktutorial-library/src/CMakeLists.txt =================================================================== --- trunk/ktutorial/ktutorial-library/src/CMakeLists.txt 2010-08-14 17:30:49 UTC (rev 248) +++ trunk/ktutorial/ktutorial-library/src/CMakeLists.txt 2010-09-19 16:40:33 UTC (rev 249) @@ -2,6 +2,7 @@ # In order to work, they must be compiled using -fPIC add_definitions("-fPIC") +add_subdirectory(common) add_subdirectory(extendedinformation) add_subdirectory(scripting) add_subdirectory(tutorials) Modified: trunk/ktutorial/ktutorial-library/src/KTutorial.cpp =================================================================== --- trunk/ktutorial/ktutorial-library/src/KTutorial.cpp 2010-08-14 17:30:49 UTC (rev 248) +++ trunk/ktutorial/ktutorial-library/src/KTutorial.cpp 2010-09-19 16:40:33 UTC (rev 249) @@ -105,6 +105,7 @@ QString tutorialName = tutorial->tutorialInformation()->name(); StepWidget* stepWidget = new StepWidget(tutorialName, mParent); + stepWidget->setMainApplicationWindow(mParent); stepWidget->setObjectName("ktutorial_StepWidget"); connect(tutorial, SIGNAL(stepActivated(Step*)), stepWidget, SLOT(setStep(Step*))); Added: trunk/ktutorial/ktutorial-library/src/common/CMakeLists.txt =================================================================== --- trunk/ktutorial/ktutorial-library/src/common/CMakeLists.txt (rev 0) +++ trunk/ktutorial/ktutorial-library/src/common/CMakeLists.txt 2010-09-19 16:40:33 UTC (rev 249) @@ -0,0 +1,9 @@ +include_directories(${CMAKE_CURRENT_BINARY_DIR} ${KDE4_INCLUDES}) + +set(ktutorial_common_SRCS + WindowVisibilitySpy.cpp +) + +kde4_add_library(ktutorial_common ${ktutorial_common_SRCS}) + +target_link_libraries(ktutorial_common ${KDE4_KDEUI_LIBS}) Property changes on: trunk/ktutorial/ktutorial-library/src/common/CMakeLists.txt ___________________________________________________________________ Added: svn:eol-style + native Added: trunk/ktutorial/ktutorial-library/src/common/WindowVisibilitySpy.cpp =================================================================== --- trunk/ktutorial/ktutorial-library/src/common/WindowVisibilitySpy.cpp (rev 0) +++ trunk/ktutorial/ktutorial-library/src/common/WindowVisibilitySpy.cpp 2010-09-19 16:40:33 UTC (rev 249) @@ -0,0 +1,72 @@ +/*************************************************************************** + * Copyright (C) 2010 by Daniel Calviño Sánchez * + * dan...@gm... * + * * + * This program is free software; you can redistribute it and/or modify * + * it under the terms of the GNU General Public License as published by * + * the Free Software Foundation; either version 3 of the License, or * + * (at your option) any later version. * + * * + * This program is distributed in the hope that it will be useful, * + * but WITHOUT ANY WARRANTY; without even the implied warranty of * + * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the * + * GNU General Public License for more details. * + * * + * You should have received a copy of the GNU General Public License * + * along with this program; If not, see <http://www.gnu.org/licenses/>. * + ***************************************************************************/ + +#include <QEvent> +#include <QWidget> + +#include "WindowVisibilitySpy.h" + +namespace common { + +//public: + +WindowVisibilitySpy::WindowVisibilitySpy(QObject* parent /*= 0*/): + QObject(parent) { +} + +void WindowVisibilitySpy::addWidgetToSpy(QWidget* widget) { + Q_ASSERT(widget); + + widget->installEventFilter(this); + + foreach (QObject* childObject, widget->children()) { + if (childObject->isWidgetType()) { + addWidgetToSpy(static_cast<QWidget*>(childObject)); + } + } +} + +//protected: + +bool WindowVisibilitySpy::eventFilter(QObject* object, QEvent* event) { + if (event->type() == QEvent::ChildAdded) { + QChildEvent* childEvent = static_cast<QChildEvent*>(event); + if (childEvent->child()->isWidgetType()) { + addWidgetToSpy(static_cast<QWidget*>(childEvent->child())); + } + return false; + } + + QWidget* widget = static_cast<QWidget*>(object); + + if (!(widget->windowFlags() & (Qt::Window | Qt::Dialog))) { + return false; + } + + if (event->type() == QEvent::Show) { + emit windowShown(widget); + } else if (event->type() == QEvent::Hide) { + emit windowHidden(widget); + } + + return false; +} + +} + +#include "WindowVisibilitySpy.moc" Property changes on: trunk/ktutorial/ktutorial-library/src/common/WindowVisibilitySpy.cpp ___________________________________________________________________ Added: svn:eol-style + native Added: trunk/ktutorial/ktutorial-library/src/common/WindowVisibilitySpy.h =================================================================== --- trunk/ktutorial/ktutorial-library/src/common/WindowVisibilitySpy.h (rev 0) +++ trunk/ktutorial/ktutorial-library/src/common/WindowVisibilitySpy.h 2010-09-19 16:40:33 UTC (rev 249) @@ -0,0 +1,89 @@ +/*************************************************************************** + * Copyright (C) 2010 by Daniel Calviño Sánchez * + * dan...@gm... * + * * + * This program is free software; you can redistribute it and/or modify * + * it under the terms of the GNU General Public License as published by * + * the Free Software Foundation; either version 3 of the License, or * + * (at your option) any later version. * + * * + * This program is distributed in the hope that it will be useful, * + * but WITHOUT ANY WARRANTY; without even the implied warranty of * + * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the * + * GNU General Public License for more details. * + * * + * You should have received a copy of the GNU General Public License * + * along with this program; If not, see <http://www.gnu.org/licenses/>. * + ***************************************************************************/ + +#ifndef COMMON_WINDOWVISIBILITYSPY_H +#define COMMON_WINDOWVISIBILITYSPY_H + +#include <QObject> + +namespace common { + +/** + * Spy to know when windows from a widget hierarchy are shown or hidden. + * WindowVisibilitySpy emitts windowShown(QWidget*) whenever any of the spied + * widgets or its child widgets (recursively) are shown as a window. The signal + * windowHidden(QWidget*) is emitted when any of them is hidden. The signals are + * emitted for windows but also for dialogs. + * + * Children added to a spied widget after it was added to the + * WindowVisibilitySpy are also automatically spied. + */ +class WindowVisibilitySpy: public QObject { +Q_OBJECT +public: + + /** + * Creates a new WindowVisibilitySpy with the given parent. + * + * @param parent The parent QObject. + */ + explicit WindowVisibilitySpy(QObject* parent = 0); + + /** + * Add widget and all its child widgets to spy. + * + * @param widget The widget to spy. + */ + void addWidgetToSpy(QWidget* widget); + +Q_SIGNALS: + + /** + * Emitted when any of the spied widgets or its children is shown as a + * window. + * + * @param window The widget shown. + */ + void windowShown(QWidget* window); + + /** + * Emitted when any of the spied widgets or its children is hidden (and it + * was a window). + * + * @param window The widget hidden. + */ + void windowHidden(QWidget* window); + +protected: + + /** + * Filters the events received in the spied widget hierarchies. + * A windowShown(QWidget*) is emitted when a window is shown, and a + * windowHidden(QWidget*) is emitted when a window is hidden. + * + * @param object The widget that received the event. + * @param event The event received. + * @return False, to let the events be handled as necessary. + */ + virtual bool eventFilter(QObject* object, QEvent* event); + +}; + +} + +#endif Property changes on: trunk/ktutorial/ktutorial-library/src/common/WindowVisibilitySpy.h ___________________________________________________________________ Added: svn:eol-style + native Modified: trunk/ktutorial/ktutorial-library/src/view/CMakeLists.txt =================================================================== --- trunk/ktutorial/ktutorial-library/src/view/CMakeLists.txt 2010-08-14 17:30:49 UTC (rev 248) +++ trunk/ktutorial/ktutorial-library/src/view/CMakeLists.txt 2010-09-19 16:40:33 UTC (rev 249) @@ -5,6 +5,7 @@ StepWidget.cpp TutorialListModel.cpp TutorialManagerDialog.cpp + WindowOnTopEnforcer.cpp ) kde4_add_ui_files(ktutorial_view_SRCS @@ -14,4 +15,8 @@ kde4_add_library(ktutorial_view ${ktutorial_view_SRCS}) -target_link_libraries(ktutorial_view ktutorial_extendedinformation ${KDE4_KDEUI_LIBS}) +target_link_libraries(ktutorial_view + ktutorial_common + ktutorial_extendedinformation + ${KDE4_KDEUI_LIBS} +) Modified: trunk/ktutorial/ktutorial-library/src/view/StepWidget.cpp =================================================================== --- trunk/ktutorial/ktutorial-library/src/view/StepWidget.cpp 2010-08-14 17:30:49 UTC (rev 248) +++ trunk/ktutorial/ktutorial-library/src/view/StepWidget.cpp 2010-09-19 16:40:33 UTC (rev 249) @@ -25,6 +25,7 @@ #include "StepWidget.h" #include "ui_StepWidget.h" +#include "WindowOnTopEnforcer.h" #include "../Option.h" #include "../Step.h" @@ -62,6 +63,11 @@ delete ui; } +void StepWidget::setMainApplicationWindow(QWidget* mainApplicationWindow) { + WindowOnTopEnforcer* windowOnTopEnforcer = new WindowOnTopEnforcer(this); + windowOnTopEnforcer->setBaseWindow(mainApplicationWindow); +} + //public slots: void StepWidget::setStep(Step* step) { Modified: trunk/ktutorial/ktutorial-library/src/view/StepWidget.h =================================================================== --- trunk/ktutorial/ktutorial-library/src/view/StepWidget.h 2010-08-14 17:30:49 UTC (rev 248) +++ trunk/ktutorial/ktutorial-library/src/view/StepWidget.h 2010-09-19 16:40:33 UTC (rev 249) @@ -69,6 +69,16 @@ */ virtual ~StepWidget(); + /** + * Sets the main application window to spy for child dialogs. + * When a modal dialog is shown, this StepWidget will be reparented to the + * dialog to avoid being blocked by it. The previous parent will be restored + * when the modal dialog is hidden. + * + * @param mainApplicationWindow The main application window. + */ + void setMainApplicationWindow(QWidget* mainApplicationWindow); + public slots: /** Added: trunk/ktutorial/ktutorial-library/src/view/WindowOnTopEnforcer.cpp =================================================================== --- trunk/ktutorial/ktutorial-library/src/view/WindowOnTopEnforcer.cpp (rev 0) +++ trunk/ktutorial/ktutorial-library/src/view/WindowOnTopEnforcer.cpp 2010-09-19 16:40:33 UTC (rev 249) @@ -0,0 +1,85 @@ +/*************************************************************************** + * Copyright (C) 2010 by Daniel Calviño Sánchez * + * dan...@gm... * + * * + * This program is free software; you can redistribute it and/or modify * + * it under the terms of the GNU General Public License as published by * + * the Free Software Foundation; either version 3 of the License, or * + * (at your option) any later version. * + * * + * This program is distributed in the hope that it will be useful, * + * but WITHOUT ANY WARRANTY; without even the implied warranty of * + * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the * + * GNU General Public License for more details. * + * * + * You should have received a copy of the GNU General Public License * + * along with this program; If not, see <http://www.gnu.org/licenses/>. * + ***************************************************************************/ + +#include <QWidget> + +#include "WindowOnTopEnforcer.h" +#include "../common/WindowVisibilitySpy.h" + +using common::WindowVisibilitySpy; + +namespace view { + +//public: + +WindowOnTopEnforcer::WindowOnTopEnforcer(QWidget* widget): QObject(widget), + mWidgetToKeepOnTop(widget) { + + Q_ASSERT(widget); + + mParentStack.push(mWidgetToKeepOnTop->parentWidget()); +} + +void WindowOnTopEnforcer::setBaseWindow(QWidget* baseWindow) { + Q_ASSERT(baseWindow); + + WindowVisibilitySpy* spy = new WindowVisibilitySpy(this); + spy->addWidgetToSpy(baseWindow); + connect(spy, SIGNAL(windowShown(QWidget*)), + this, SLOT(handleWindowShown(QWidget*))); + connect(spy, SIGNAL(windowHidden(QWidget*)), + this, SLOT(handleWindowHidden(QWidget*))); +} + +//private slots: + +void WindowOnTopEnforcer::handleWindowShown(QWidget* window) { + Q_ASSERT(window); + + if (!window->isModal()) { + return; + } + + mParentStack.push(window); + + //When a widget is reparented it is hidden and its window flags are cleared, + //so they must be restored and the widget shown again + Qt::WindowFlags flags = mWidgetToKeepOnTop->windowFlags(); + mWidgetToKeepOnTop->setParent(window); + mWidgetToKeepOnTop->setWindowFlags(flags); + mWidgetToKeepOnTop->show(); +} + +void WindowOnTopEnforcer::handleWindowHidden(QWidget* window) { + Q_ASSERT(window); + + if (!window->isModal()) { + return; + } + + mParentStack.pop(); + + //When a widget is reparented it is hidden and its window flags are cleared + //so they must be restored and the widget shown again + Qt::WindowFlags flags = mWidgetToKeepOnTop->windowFlags(); + mWidgetToKeepOnTop->setParent(mParentStack.top()); + mWidgetToKeepOnTop->setWindowFlags(flags); + mWidgetToKeepOnTop->show(); +} + +} Property changes on: trunk/ktutorial/ktutorial-library/src/view/WindowOnTopEnforcer.cpp ___________________________________________________________________ Added: svn:eol-style + native Added: trunk/ktutorial/ktutorial-library/src/view/WindowOnTopEnforcer.h =================================================================== --- trunk/ktutorial/ktutorial-library/src/view/WindowOnTopEnforcer.h (rev 0) +++ trunk/ktutorial/ktutorial-library/src/view/WindowOnTopEnforcer.h 2010-09-19 16:40:33 UTC (rev 249) @@ -0,0 +1,92 @@ +/*************************************************************************** + * Copyright (C) 2010 by Daniel Calviño Sánchez * + * dan...@gm... * + * * + * This program is free software; you can redistribute it and/or modify * + * it under the terms of the GNU General Public License as published by * + * the Free Software Foundation; either version 3 of the License, or * + * (at your option) any later version. * + * * + * This program is distributed in the hope that it will be useful, * + * but WITHOUT ANY WARRANTY; without even the implied warranty of * + * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the * + * GNU General Public License for more details. * + * * + * You should have received a copy of the GNU General Public License * + * along with this program; If not, see <http://www.gnu.org/licenses/>. * + ***************************************************************************/ + +#ifndef VIEW_WINDOWONTOPENFORCER_H +#define VIEW_WINDOWONTOPENFORCER_H + +#include <QObject> +#include <QStack> + +namespace common { +class WindowVisibilitySpy; +} + +namespace view { + +/** + * Utility class to avoid windows being blocked by modal dialogs. + * When a modal dialog is shown, the widget to keep on top is reparented to the + * shown dialog. When the modal dialog is hidden, the widget is reparented to + * its previous parent. + */ +class WindowOnTopEnforcer: public QObject { +Q_OBJECT +public: + + /** + * Creates a new WindowOnTopEnforcer with the widget to keep on top. + * The widget to keep on top is set as the parent of the + * WindowOnTopEnforcer. + * + * @param widget The widget to keep on top. + */ + explicit WindowOnTopEnforcer(QWidget* widget); + + /** + * Sets the base window to spy for its children dialogs. + * + * @param baseWindow The window to spy. + */ + void setBaseWindow(QWidget* baseWindow); + +private: + + /** + * The widget to keep on top. + */ + QWidget* mWidgetToKeepOnTop; + + /** + * A stack with the parents of the widget to keep on top. + * It is used to restore the previous parent when the latest one is hidden. + */ + QStack<QWidget*> mParentStack; + +private Q_SLOTS: + + /** + * Reparents the widget to keep on top to the window if it is a modal + * dialog. + * + * @param window The window that has been shown. + */ + void handleWindowShown(QWidget* window); + + /** + * Reparents the widget to keep on top to its previous parent if the hidden + * window is a modal dialog. + * + * @param window The window that has been hidden. + */ + void handleWindowHidden(QWidget* window); + +}; + +}; + +#endif Property changes on: trunk/ktutorial/ktutorial-library/src/view/WindowOnTopEnforcer.h ___________________________________________________________________ Added: svn:eol-style + native Modified: trunk/ktutorial/ktutorial-library/tests/CMakeLists.txt =================================================================== --- trunk/ktutorial/ktutorial-library/tests/CMakeLists.txt 2010-08-14 17:30:49 UTC (rev 248) +++ trunk/ktutorial/ktutorial-library/tests/CMakeLists.txt 2010-09-19 16:40:33 UTC (rev 249) @@ -1,3 +1,4 @@ +add_subdirectory(common) add_subdirectory(extendedinformation) add_subdirectory(scripting) add_subdirectory(view) Added: trunk/ktutorial/ktutorial-library/tests/common/CMakeLists.txt =================================================================== --- trunk/ktutorial/ktutorial-library/tests/common/CMakeLists.txt (rev 0) +++ trunk/ktutorial/ktutorial-library/tests/common/CMakeLists.txt 2010-09-19 16:40:33 UTC (rev 249) @@ -0,0 +1,31 @@ +# Used by kde4_add_unit_test to set the full path to test executables +set(EXECUTABLE_OUTPUT_PATH ${CMAKE_CURRENT_BINARY_DIR}) + +include_directories(${CMAKE_CURRENT_BINARY_DIR} ${ktutorial-library_SOURCE_DIR}/src/common ${KDE4_INCLUDES}) + +# Since Qt 4.6.0, this definition is needed for GUI testing. +# It is backwards compatible with previous Qt versions, unlike the alternative +# which is to add #include <QTestGui> in the test files. +add_definitions(-DQT_GUI_LIB) + +MACRO(UNIT_TESTS) + FOREACH(_className ${ARGN}) + set(_testName ${_className}Test) + kde4_add_unit_test(${_testName} TESTNAME ktutorial-${_testName} ${_testName}.cpp) + target_link_libraries(${_testName} ktutorial_common ${QT_QTTEST_LIBRARY}) + ENDFOREACH(_className) +ENDMACRO(UNIT_TESTS) + +unit_tests( + WindowVisibilitySpy +) + +MACRO(MEM_TESTS) + FOREACH(_testname ${ARGN}) + add_test(ktutorial-mem-${_testname} ${CMAKE_CURRENT_SOURCE_DIR}/../runMemcheck.py ${CMAKE_CURRENT_BINARY_DIR}/${_testname}Test ${CMAKE_CURRENT_BINARY_DIR}) + ENDFOREACH(_testname) +ENDMACRO(MEM_TESTS) + +mem_tests( + WindowVisibilitySpy +) Property changes on: trunk/ktutorial/ktutorial-library/tests/common/CMakeLists.txt ___________________________________________________________________ Added: svn:eol-style + native Added: trunk/ktutorial/ktutorial-library/tests/common/WindowVisibilitySpyTest.cpp =================================================================== --- trunk/ktutorial/ktutorial-library/tests/common/WindowVisibilitySpyTest.cpp (rev 0) +++ trunk/ktutorial/ktutorial-library/tests/common/WindowVisibilitySpyTest.cpp 2010-09-19 16:40:33 UTC (rev 249) @@ -0,0 +1,200 @@ +/*************************************************************************** + * Copyright (C) 2010 by Daniel Calviño Sánchez * + * dan...@gm... * + * * + * This program is free software; you can redistribute it and/or modify * + * it under the terms of the GNU General Public License as published by * + * the Free Software Foundation; either version 3 of the License, or * + * (at your option) any later version. * + * * + * This program is distributed in the hope that it will be useful, * + * but WITHOUT ANY WARRANTY; without even the implied warranty of * + * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the * + * GNU General Public License for more details. * + * * + * You should have received a copy of the GNU General Public License * + * along with this program; If not, see <http://www.gnu.org/licenses/>. * + ***************************************************************************/ + +#include <QtTest> + +#include <QWidget> + +#include "WindowVisibilitySpy.h" + +namespace common { + +class WindowVisibilitySpyTest: public QObject { +Q_OBJECT +private slots: + + void testConstructor(); + + void testShowWidgetAsWindow(); + void testHideWidgetAsWindow(); + void testDeleteWidgetShownAsWindow(); + void testShowWidgetAsWidget(); + void testHideWidgetAsWidget(); + void testDeleteWidgetShownAsWidget(); + + void testShowChildWidgetAddedBeforeSpy(); + void testShowChildWidgetAddedAfterSpy(); + +}; + +void WindowVisibilitySpyTest::testConstructor() { + QObject parent; + WindowVisibilitySpy* spy = new WindowVisibilitySpy(&parent); + + QCOMPARE(spy->parent(), &parent); +} + +void WindowVisibilitySpyTest::testShowWidgetAsWindow() { + QWidget widget; + widget.setWindowFlags(Qt::Window); + + WindowVisibilitySpy spy; + spy.addWidgetToSpy(&widget); + + QSignalSpy shownSpy(&spy, SIGNAL(windowShown(QWidget*))); + + widget.show(); + + QCOMPARE(shownSpy.count(), 1); + QVariant argument = shownSpy.at(0).at(0); + QCOMPARE(argument.userType(), (int)QMetaType::QWidgetStar); + QCOMPARE(qvariant_cast<QWidget*>(argument), &widget); +} + +void WindowVisibilitySpyTest::testHideWidgetAsWindow() { + QWidget widget; + widget.setWindowFlags(Qt::Window); + widget.show(); + + WindowVisibilitySpy spy; + spy.addWidgetToSpy(&widget); + + QSignalSpy hiddenSpy(&spy, SIGNAL(windowHidden(QWidget*))); + + widget.hide(); + + QCOMPARE(hiddenSpy.count(), 1); + QVariant argument = hiddenSpy.at(0).at(0); + QCOMPARE(argument.userType(), (int)QMetaType::QWidgetStar); + QCOMPARE(qvariant_cast<QWidget*>(argument), &widget); +} + +void WindowVisibilitySpyTest::testDeleteWidgetShownAsWindow() { + QWidget* widget = new QWidget(); + widget->setWindowFlags(Qt::Window); + widget->show(); + + WindowVisibilitySpy spy; + spy.addWidgetToSpy(widget); + + QSignalSpy hiddenSpy(&spy, SIGNAL(windowHidden(QWidget*))); + + delete widget; + + QCOMPARE(hiddenSpy.count(), 1); + QVariant argument = hiddenSpy.at(0).at(0); + QCOMPARE(argument.userType(), (int)QMetaType::QWidgetStar); + QCOMPARE(qvariant_cast<QWidget*>(argument), widget); +} + +void WindowVisibilitySpyTest::testShowWidgetAsWidget() { + QWidget window; + window.show(); + + QWidget* widget = new QWidget(&window); + + WindowVisibilitySpy spy; + spy.addWidgetToSpy(widget); + + QSignalSpy shownSpy(&spy, SIGNAL(windowShown(QWidget*))); + + widget->show(); + + QCOMPARE(shownSpy.count(), 0); +} + +void WindowVisibilitySpyTest::testHideWidgetAsWidget() { + QWidget window; + window.show(); + + QWidget* widget = new QWidget(&window); + widget->show(); + + WindowVisibilitySpy spy; + spy.addWidgetToSpy(widget); + + QSignalSpy hiddenSpy(&spy, SIGNAL(windowHidden(QWidget*))); + + widget->hide(); + + QCOMPARE(hiddenSpy.count(), 0); +} + +void WindowVisibilitySpyTest::testDeleteWidgetShownAsWidget() { + QWidget window; + window.show(); + + QWidget* widget = new QWidget(&window); + widget->show(); + + WindowVisibilitySpy spy; + spy.addWidgetToSpy(widget); + + QSignalSpy shownSpy(&spy, SIGNAL(windowShown(QWidget*))); + + delete widget; + + QCOMPARE(shownSpy.count(), 0); +} + +void WindowVisibilitySpyTest::testShowChildWidgetAddedBeforeSpy() { + QWidget window; + QWidget* childWidget = new QWidget(&window); + window.show(); + + QWidget* grandChildWindow = new QWidget(childWidget); + grandChildWindow->setWindowFlags(Qt::Window); + + WindowVisibilitySpy spy; + spy.addWidgetToSpy(&window); + + QSignalSpy shownSpy(&spy, SIGNAL(windowShown(QWidget*))); + + grandChildWindow->show(); + + QCOMPARE(shownSpy.count(), 1); + QVariant argument = shownSpy.at(0).at(0); + QCOMPARE(argument.userType(), (int)QMetaType::QWidgetStar); + QCOMPARE(qvariant_cast<QWidget*>(argument), grandChildWindow); +} + +void WindowVisibilitySpyTest::testShowChildWidgetAddedAfterSpy() { + QWidget window; + QWidget* childWidget = new QWidget(&window); + window.show(); + + WindowVisibilitySpy spy; + spy.addWidgetToSpy(&window); + + QSignalSpy shownSpy(&spy, SIGNAL(windowShown(QWidget*))); + + QWidget* grandChildWindow = new QWidget(childWidget); + grandChildWindow->setWindowFlags(Qt::Window); + grandChildWindow->show(); + + QCOMPARE(shownSpy.count(), 1); + QVariant argument = shownSpy.at(0).at(0); + QCOMPARE(argument.userType(), (int)QMetaType::QWidgetStar); + QCOMPARE(qvariant_cast<QWidget*>(argument), grandChildWindow); +} + +} + +QTEST_MAIN(common::WindowVisibilitySpyTest) + +#include "WindowVisibilitySpyTest.moc" Property changes on: trunk/ktutorial/ktutorial-library/tests/common/WindowVisibilitySpyTest.cpp ___________________________________________________________________ Added: svn:eol-style + native Modified: trunk/ktutorial/ktutorial-library/tests/view/CMakeLists.txt =================================================================== --- trunk/ktutorial/ktutorial-library/tests/view/CMakeLists.txt 2010-08-14 17:30:49 UTC (rev 248) +++ trunk/ktutorial/ktutorial-library/tests/view/CMakeLists.txt 2010-09-19 16:40:33 UTC (rev 249) @@ -21,6 +21,7 @@ StepWidget TutorialListModel TutorialManagerDialog + WindowOnTopEnforcer ) MACRO(MEM_TESTS) @@ -34,4 +35,5 @@ StepWidget TutorialListModel TutorialManagerDialog + WindowOnTopEnforcer ) Modified: trunk/ktutorial/ktutorial-library/tests/view/StepWidgetTest.cpp =================================================================== --- trunk/ktutorial/ktutorial-library/tests/view/StepWidgetTest.cpp 2010-08-14 17:30:49 UTC (rev 248) +++ trunk/ktutorial/ktutorial-library/tests/view/StepWidgetTest.cpp 2010-09-19 16:40:33 UTC (rev 249) @@ -72,6 +72,8 @@ //Closing with ALT+F4 can't be tested, as it depends on the window manager //rather than the widget + void moveAfterShowingModalDialogAndThenClose(); + private: int mDummySlotCallCount; @@ -80,6 +82,8 @@ StepTextWidget* textWidget(StepWidget* stepWidget); KPushButton* closeButton(StepWidget* stepWidget); + void queueAssertWidgetDragged(StepWidget* stepWidget, int timeToWait); + }; void StepWidgetTest::testConstructor() { @@ -311,6 +315,36 @@ QCOMPARE(destroyedSpy.count(), 1); } +void StepWidgetTest::moveAfterShowingModalDialogAndThenClose() { + QWidget* window = new QWidget(); + window->show(); + + StepWidget* stepWidget = new StepWidget("Test tutorial"); + stepWidget->setMainApplicationWindow(window); + stepWidget->show(); + + QDialog* modalDialog = new QDialog(window); + + QTimer timerAccept; + timerAccept.setSingleShot(true); + timerAccept.setInterval(2000); + connect(&timerAccept, SIGNAL(timeout()), modalDialog, SLOT(accept())); + + queueAssertWidgetDragged(stepWidget, 500); + + timerAccept.start(); + modalDialog->exec(); + + QSignalSpy destroyedSpy(stepWidget, SIGNAL(destroyed(QObject*))); + + QTest::mouseClick(closeButton(stepWidget), Qt::LeftButton, + Qt::NoModifier, QPoint(), 500); + //Give it time to die + QTest::qWait(500); + + QCOMPARE(destroyedSpy.count(), 1); +} + /////////////////////////////////// Helpers //////////////////////////////////// StepTextWidget* StepWidgetTest::textWidget(StepWidget* stepWidget) { @@ -321,8 +355,66 @@ return stepWidget->ui->closeButton; } +//Modal dialogs don't return to the test code until they are closed. Thus, the +//actions or asserts to be performed while a modal dialog is being shown (like +//checking the position of the widget) must be "queued". +class QueuedActionsHelper: public QObject { +Q_OBJECT +public: + + QueuedActionsHelper(QObject* object = 0): QObject(object) { + } + + void setStepWidget(StepWidget* stepWidget) { + mStepWidget = stepWidget; + } + +public slots: + + void assertWidgetDragged() { + QVERIFY(mStepWidget->isVisible()); + + QPoint previousPosition = mStepWidget->pos(); + + QPoint widgetCenter(mStepWidget->size().width()/2, + mStepWidget->size().height()/2); + + QTest::mouseMove(mStepWidget); + + //Use setMouseTracking and QCursor::setPos as a workaround. + //QTest::mouseMove, due to unknown reasons for me, doesn't make + //StepWidget to receive QMouseEvent for move. Neither QCursor::setPos + //does if tracking isn't enabled + mStepWidget->setMouseTracking(true); + QTest::mousePress(mStepWidget, Qt::LeftButton, + Qt::NoModifier, QPoint(), 500); + QCursor::setPos(previousPosition + widgetCenter + QPoint(42, 23)); + QTest::mouseRelease(mStepWidget, Qt::LeftButton, + Qt::NoModifier, QPoint(), 500); + mStepWidget->setMouseTracking(false); + + QVERIFY(previousPosition.x() + 41 <= mStepWidget->pos().x() && + previousPosition.x() + 43 >= mStepWidget->pos().x()); + QVERIFY(previousPosition.y() + 22 <= mStepWidget->pos().y() && + previousPosition.y() + 24 >= mStepWidget->pos().y()); + } + +private: + + StepWidget* mStepWidget; + +}; + +void StepWidgetTest::queueAssertWidgetDragged(StepWidget* stepWidget, + int timeToWait) { + QueuedActionsHelper* helper = new QueuedActionsHelper(); + helper->setStepWidget(stepWidget); + QTimer::singleShot(timeToWait, helper, SLOT(assertWidgetDragged())); + QTimer::singleShot(timeToWait + 1000, helper, SLOT(deleteLater())); } +} + QTEST_KDEMAIN(view::StepWidgetTest, GUI) #include "StepWidgetTest.moc" Added: trunk/ktutorial/ktutorial-library/tests/view/WindowOnTopEnforcerTest.cpp =================================================================== --- trunk/ktutorial/ktutorial-library/tests/view/WindowOnTopEnforcerTest.cpp (rev 0) +++ trunk/ktutorial/ktutorial-library/tests/view/WindowOnTopEnforcerTest.cpp 2010-09-19 16:40:33 UTC (rev 249) @@ -0,0 +1,419 @@ +/*************************************************************************** + * Copyright (C) 2010 by Daniel Calviño Sánchez * + * dan...@gm... * + * * + * This program is free software; you can redistribute it and/or modify * + * it under the terms of the GNU General Public License as published by * + * the Free Software Foundation; either version 3 of the License, or * + * (at your option) any later version. * + * * + * This program is distributed in the hope that it will be useful, * + * but WITHOUT ANY WARRANTY; without even the implied warranty of * + * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the * + * GNU General Public License for more details. * + * * + * You should have received a copy of the GNU General Public License * + * along with this program; If not, see <http://www.gnu.org/licenses/>. * + ***************************************************************************/ + +#include <QtTest> + +#include <QDialog> + +#include "WindowOnTopEnforcer.h" + +namespace view { + +class WindowOnTopEnforcerTest: public QObject { +Q_OBJECT + +private slots: + + void testConstructor(); + + void testBaseWindow(); + + void testChildWindow(); + + void testModalDialog(); + + void testNestedModalDialog(); + + void testSeveralModalDialogs(); + + void testNestedModalDialogOnChildWindow(); + +private: + + void queueAssertParent(QWidget* widget, QWidget* parent, int timeToWait); + void queueAssertIsVisibleWindow(QWidget* widget, int timeToWait); + +}; + +void WindowOnTopEnforcerTest::testConstructor() { + QWidget widget; + WindowOnTopEnforcer* enforcer = new WindowOnTopEnforcer(&widget); + + QCOMPARE(enforcer->parent(), &widget); +} + +void WindowOnTopEnforcerTest::testBaseWindow() { + QWidget* window = new QWidget(); + window->show(); + + QWidget* windowToKeepOnTop = new QWidget(window); + windowToKeepOnTop->setWindowFlags(Qt::Window); + windowToKeepOnTop->show(); + + WindowOnTopEnforcer* enforcer = new WindowOnTopEnforcer(windowToKeepOnTop); + enforcer->setBaseWindow(window); + + QSignalSpy destroyedSpy(windowToKeepOnTop, SIGNAL(destroyed(QObject*))); + + delete window; + + QCOMPARE(destroyedSpy.count(), 1); + QVariant argument = destroyedSpy.at(0).at(0); + QCOMPARE(argument.userType(), (int)QMetaType::QObjectStar); + QCOMPARE(qvariant_cast<QObject*>(argument), windowToKeepOnTop); +} + +void WindowOnTopEnforcerTest::testChildWindow() { + QWidget* window = new QWidget(); + window->show(); + + QWidget* windowToKeepOnTop = new QWidget(window); + windowToKeepOnTop->setWindowFlags(Qt::Window); + windowToKeepOnTop->show(); + + WindowOnTopEnforcer* enforcer = new WindowOnTopEnforcer(windowToKeepOnTop); + enforcer->setBaseWindow(window); + + QWidget* childWindow = new QWidget(window); + childWindow->setWindowFlags(Qt::Window); + childWindow->show(); + + QCOMPARE(windowToKeepOnTop->parentWidget(), window); + QVERIFY(windowToKeepOnTop->isVisible()); + QVERIFY(windowToKeepOnTop->windowFlags() & Qt::Window); + + delete childWindow; + + QCOMPARE(windowToKeepOnTop->parentWidget(), window); + QVERIFY(windowToKeepOnTop->isVisible()); + QVERIFY(windowToKeepOnTop->windowFlags() & Qt::Window); + + QSignalSpy destroyedSpy(windowToKeepOnTop, SIGNAL(destroyed(QObject*))); + + delete window; + + QCOMPARE(destroyedSpy.count(), 1); + QVariant argument = destroyedSpy.at(0).at(0); + QCOMPARE(argument.userType(), (int)QMetaType::QObjectStar); + QCOMPARE(qvariant_cast<QObject*>(argument), windowToKeepOnTop); +} + +void WindowOnTopEnforcerTest::testModalDialog() { + QWidget* window = new QWidget(); + window->show(); + + QWidget* windowToKeepOnTop = new QWidget(window); + windowToKeepOnTop->setWindowFlags(Qt::Window); + windowToKeepOnTop->show(); + + WindowOnTopEnforcer* enforcer = new WindowOnTopEnforcer(windowToKeepOnTop); + enforcer->setBaseWindow(window); + + QDialog* modalDialog = new QDialog(window); + + QTimer timerAccept; + timerAccept.setSingleShot(true); + timerAccept.setInterval(1000); + connect(&timerAccept, SIGNAL(timeout()), modalDialog, SLOT(accept())); + + queueAssertParent(windowToKeepOnTop, modalDialog, 500); + queueAssertIsVisibleWindow(windowToKeepOnTop, 500); + + timerAccept.start(); + modalDialog->exec(); + + QCOMPARE(windowToKeepOnTop->parentWidget(), window); + QVERIFY(windowToKeepOnTop->isVisible()); + QVERIFY(windowToKeepOnTop->windowFlags() & Qt::Window); + + QSignalSpy destroyedSpy(windowToKeepOnTop, SIGNAL(destroyed(QObject*))); + + delete window; + + QCOMPARE(destroyedSpy.count(), 1); + QVariant argument = destroyedSpy.at(0).at(0); + QCOMPARE(argument.userType(), (int)QMetaType::QObjectStar); + QCOMPARE(qvariant_cast<QObject*>(argument), windowToKeepOnTop); +} + +void WindowOnTopEnforcerTest::testNestedModalDialog() { + QWidget* window = new QWidget(); + window->show(); + + QWidget* windowToKeepOnTop = new QWidget(window); + windowToKeepOnTop->setWindowFlags(Qt::Window); + windowToKeepOnTop->show(); + + WindowOnTopEnforcer* enforcer = new WindowOnTopEnforcer(windowToKeepOnTop); + enforcer->setBaseWindow(window); + + QDialog* modalDialog = new QDialog(window); + QDialog* nestedModalDialog = new QDialog(modalDialog); + + QTimer timerAccept; + timerAccept.setSingleShot(true); + timerAccept.setInterval(2500); + connect(&timerAccept, SIGNAL(timeout()), modalDialog, SLOT(accept())); + + QTimer timerExecNested; + timerExecNested.setSingleShot(true); + timerExecNested.setInterval(500); + connect(&timerExecNested, SIGNAL(timeout()), + nestedModalDialog, SLOT(exec())); + + QTimer timerAcceptNested; + timerAcceptNested.setSingleShot(true); + timerAcceptNested.setInterval(1500); + connect(&timerAcceptNested, SIGNAL(timeout()), + nestedModalDialog, SLOT(accept())); + + queueAssertParent(windowToKeepOnTop, nestedModalDialog, 1000); + queueAssertIsVisibleWindow(windowToKeepOnTop, 1000); + queueAssertParent(windowToKeepOnTop, modalDialog, 2000); + queueAssertIsVisibleWindow(windowToKeepOnTop, 2000); + + timerAccept.start(); + timerExecNested.start(); + timerAcceptNested.start(); + modalDialog->exec(); + + QCOMPARE(windowToKeepOnTop->parentWidget(), window); + QVERIFY(windowToKeepOnTop->isVisible()); + QVERIFY(windowToKeepOnTop->windowFlags() & Qt::Window); + + QSignalSpy destroyedSpy(windowToKeepOnTop, SIGNAL(destroyed(QObject*))); + + delete window; + + QCOMPARE(destroyedSpy.count(), 1); + QVariant argument = destroyedSpy.at(0).at(0); + QCOMPARE(argument.userType(), (int)QMetaType::QObjectStar); + QCOMPARE(qvariant_cast<QObject*>(argument), windowToKeepOnTop); +} + +void WindowOnTopEnforcerTest::testSeveralModalDialogs() { + QWidget* window = new QWidget(); + window->show(); + + QWidget* windowToKeepOnTop = new QWidget(window); + windowToKeepOnTop->setWindowFlags(Qt::Window); + windowToKeepOnTop->show(); + + WindowOnTopEnforcer* enforcer = new WindowOnTopEnforcer(windowToKeepOnTop); + enforcer->setBaseWindow(window); + + QDialog* modalDialog = new QDialog(window); + QDialog* nestedModalDialog = new QDialog(modalDialog); + QDialog* nestedModalDialog2 = new QDialog(modalDialog); + + QTimer timerAccept; + timerAccept.setSingleShot(true); + timerAccept.setInterval(4500); + connect(&timerAccept, SIGNAL(timeout()), modalDialog, SLOT(accept())); + + QTimer timerExecNested; + timerExecNested.setSingleShot(true); + timerExecNested.setInterval(500); + connect(&timerExecNested, SIGNAL(timeout()), + nestedModalDialog, SLOT(exec())); + + QTimer timerAcceptNested; + timerAcceptNested.setSingleShot(true); + timerAcceptNested.setInterval(1500); + connect(&timerAcceptNested, SIGNAL(timeout()), + nestedModalDialog, SLOT(accept())); + + QTimer timerExecNested2; + timerExecNested2.setSingleShot(true); + timerExecNested2.setInterval(2500); + connect(&timerExecNested2, SIGNAL(timeout()), + nestedModalDialog2, SLOT(exec())); + + QTimer timerAcceptNested2; + timerAcceptNested2.setSingleShot(true); + timerAcceptNested2.setInterval(3500); + connect(&timerAcceptNested2, SIGNAL(timeout()), + nestedModalDialog2, SLOT(accept())); + + queueAssertParent(windowToKeepOnTop, nestedModalDialog, 1000); + queueAssertIsVisibleWindow(windowToKeepOnTop, 1000); + queueAssertParent(windowToKeepOnTop, modalDialog, 2000); + queueAssertIsVisibleWindow(windowToKeepOnTop, 2000); + queueAssertParent(windowToKeepOnTop, nestedModalDialog2, 3000); + queueAssertIsVisibleWindow(windowToKeepOnTop, 3000); + queueAssertParent(windowToKeepOnTop, modalDialog, 4000); + queueAssertIsVisibleWindow(windowToKeepOnTop, 4000); + + timerAccept.start(); + timerExecNested.start(); + timerAcceptNested.start(); + timerExecNested2.start(); + timerAcceptNested2.start(); + modalDialog->exec(); + + QCOMPARE(windowToKeepOnTop->parentWidget(), window); + QVERIFY(windowToKeepOnTop->isVisible()); + QVERIFY(windowToKeepOnTop->windowFlags() & Qt::Window); + + QDialog* modalDialog2 = new QDialog(window); + QDialog* nestedModalDialog3 = new QDialog(modalDialog); + + QTimer timerAccept2; + timerAccept2.setSingleShot(true); + timerAccept2.setInterval(2500); + connect(&timerAccept2, SIGNAL(timeout()), modalDialog2, SLOT(accept())); + + QTimer timerExecNested3; + timerExecNested3.setSingleShot(true); + timerExecNested3.setInterval(500); + connect(&timerExecNested3, SIGNAL(timeout()), + nestedModalDialog3, SLOT(exec())); + + QTimer timerAcceptNested3; + timerAcceptNested3.setSingleShot(true); + timerAcceptNested3.setInterval(1500); + connect(&timerAcceptNested3, SIGNAL(timeout()), + nestedModalDialog3, SLOT(accept())); + + queueAssertParent(windowToKeepOnTop, nestedModalDialog3, 1000); + queueAssertIsVisibleWindow(windowToKeepOnTop, 1000); + queueAssertParent(windowToKeepOnTop, modalDialog2, 2000); + queueAssertIsVisibleWindow(windowToKeepOnTop, 2000); + + timerAccept2.start(); + timerExecNested3.start(); + timerAcceptNested3.start(); + modalDialog2->exec(); + + QCOMPARE(windowToKeepOnTop->parentWidget(), window); + QVERIFY(windowToKeepOnTop->isVisible()); + QVERIFY(windowToKeepOnTop->windowFlags() & Qt::Window); + + QSignalSpy destroyedSpy(windowToKeepOnTop, SIGNAL(destroyed(QObject*))); + + delete window; + + QCOMPARE(destroyedSpy.count(), 1); + QVariant argument = destroyedSpy.at(0).at(0); + QCOMPARE(argument.userType(), (int)QMetaType::QObjectStar); + QCOMPARE(qvariant_cast<QObject*>(argument), windowToKeepOnTop); +} + +void WindowOnTopEnforcerTest::testNestedModalDialogOnChildWindow() { + QWidget* window = new QWidget(); + window->show(); + + QWidget* windowToKeepOnTop = new QWidget(window); + windowToKeepOnTop->setWindowFlags(Qt::Window); + windowToKeepOnTop->show(); + + WindowOnTopEnforcer* enforcer = new WindowOnTopEnforcer(windowToKeepOnTop); + enforcer->setBaseWindow(window); + + QWidget* childWindow = new QWidget(window); + childWindow->setWindowFlags(Qt::Window); + childWindow->show(); + + QDialog* nestedModalDialog = new QDialog(childWindow); + + QTimer timerAccept; + timerAccept.setSingleShot(true); + timerAccept.setInterval(1000); + connect(&timerAccept, SIGNAL(timeout()), nestedModalDialog, SLOT(accept())); + + queueAssertParent(windowToKeepOnTop, nestedModalDialog, 500); + queueAssertIsVisibleWindow(windowToKeepOnTop, 500); + + timerAccept.start(); + nestedModalDialog->exec(); + + QCOMPARE(windowToKeepOnTop->parentWidget(), window); + QVERIFY(windowToKeepOnTop->isVisible()); + QVERIFY(windowToKeepOnTop->windowFlags() & Qt::Window); + + QSignalSpy destroyedSpy(windowToKeepOnTop, SIGNAL(destroyed(QObject*))); + + delete window; + + QCOMPARE(destroyedSpy.count(), 1); + QVariant argument = destroyedSpy.at(0).at(0); + QCOMPARE(argument.userType(), (int)QMetaType::QObjectStar); + QCOMPARE(qvariant_cast<QObject*>(argument), windowToKeepOnTop); +} + +/////////////////////////////////// Helpers //////////////////////////////////// + +//The dialogs are modal, so they won't return to the test code until they are +//closed. Thus, the asserts to be performed while the dialogs are being shown +//(like checking the parent of a widget) must be "queued". +class QueuedActionsHelper: public QObject { +Q_OBJECT +public: + + QueuedActionsHelper(QObject* object = 0): QObject(object) { + } + + void setAssertWidget(QWidget* widget) { + mAssertWidget = widget; + } + + void setAssertParent(QWidget* parent) { + mAssertParent = parent; + } + +public slots: + + void assertParent() { + QCOMPARE(mAssertWidget->parentWidget(), mAssertParent); + } + + void assertIsVisibleWindow() { + QVERIFY(mAssertWidget->isVisible()); + QVERIFY(mAssertWidget->windowFlags() & Qt::Window); + } + +private: + + QWidget* mAssertWidget; + QWidget* mAssertParent; + +}; + +void WindowOnTopEnforcerTest::queueAssertParent(QWidget* widget, + QWidget* parent, + int timeToWait) { + QueuedActionsHelper* helper = new QueuedActionsHelper(); + helper->setAssertWidget(widget); + helper->setAssertParent(parent); + QTimer::singleShot(timeToWait, helper, SLOT(assertParent())); + QTimer::singleShot(timeToWait, helper, SLOT(deleteLater())); +} + +void WindowOnTopEnforcerTest::queueAssertIsVisibleWindow(QWidget* widget, + int timeToWait) { + QueuedActionsHelper* helper = new QueuedActionsHelper(); + helper->setAssertWidget(widget); + QTimer::singleShot(timeToWait, helper, SLOT(assertIsVisibleWindow())); + QTimer::singleShot(timeToWait, helper, SLOT(deleteLater())); +} + +} + +QTEST_MAIN(view::WindowOnTopEnforcerTest) + +#include "WidgetOnTopEnforcerTest.moc" Property changes on: trunk/ktutorial/ktutorial-library/tests/view/WindowOnTopEnforcerTest.cpp ___________________________________________________________________ Added: svn:eol-style + native This was sent by the SourceForge.net collaborative development platform, the world's largest Open Source development site. |
From: <dan...@us...> - 2010-08-14 17:30:56
|
Revision: 248 http://ktutorial.svn.sourceforge.net/ktutorial/?rev=248&view=rev Author: danxuliu Date: 2010-08-14 17:30:49 +0000 (Sat, 14 Aug 2010) Log Message: ----------- Show an information message box to tell the user that KTutorial editor windows will be hidden when the remote object is going to be chosen. Modified Paths: -------------- trunk/ktutorial/ktutorial-editor/src/targetapplication/TargetApplication.cpp trunk/ktutorial/ktutorial-editor/src/view/RemoteObjectChooser.cpp trunk/ktutorial/ktutorial-editor/src/view/RemoteObjectChooser.h trunk/ktutorial/ktutorial-editor/tests/unit/view/RemoteObjectChooserTest.cpp Modified: trunk/ktutorial/ktutorial-editor/src/targetapplication/TargetApplication.cpp =================================================================== --- trunk/ktutorial/ktutorial-editor/src/targetapplication/TargetApplication.cpp 2010-08-14 14:57:12 UTC (rev 247) +++ trunk/ktutorial/ktutorial-editor/src/targetapplication/TargetApplication.cpp 2010-08-14 17:30:49 UTC (rev 248) @@ -135,13 +135,20 @@ mServiceDiscoveryTimer.stop(); + //The bus must be disconnected before executing other code to ensure that + //no other services are handled, as when an application starts it can create + //more than one valid service: one like ":1.42" and another like + //"org.freedesktop.DBus". + //So this method could be called again before finishing its current + //execution if serviceRegistered(QSignal) is emitted, which could happen if + //other event loops are created (like in a message box). + disconnect(QDBusConnection::sessionBus().interface(), 0, this, 0); + mServiceName = service; mMapper = new RemoteObjectMapper(mServiceName); mRemoteEditorSupport = new RemoteEditorSupport(mServiceName, mMapper); emit started(); - - disconnect(QDBusConnection::sessionBus().interface(), 0, this, 0); } void TargetApplication::handleProcessError(QProcess::ProcessError error) { Modified: trunk/ktutorial/ktutorial-editor/src/view/RemoteObjectChooser.cpp =================================================================== --- trunk/ktutorial/ktutorial-editor/src/view/RemoteObjectChooser.cpp 2010-08-14 14:57:12 UTC (rev 247) +++ trunk/ktutorial/ktutorial-editor/src/view/RemoteObjectChooser.cpp 2010-08-14 17:30:49 UTC (rev 248) @@ -120,14 +120,41 @@ } } +void RemoteObjectChooser::warnAboutFinishedTargetApplicationBeforeClosing() { + QString text = i18nc("@label", "The target application has been closed, " +"but it must be running to be able to choose the objects."); + QString caption = i18nc("@title:window", "Target application closed"); + KMessageBox::sorry(this, text, caption); + + close(); +} + //private slots: void RemoteObjectChooser::handleTargetApplicationStarted() { - hideParentWindows(this); + QString text = i18nc("@label", "<para>The " +"<application>KTutorial editor</application> windows will be hidden and only " +"the list with the objects in the target application will be shown. It is made " +"to better view when a widget is highlighted in the target application.</para>" +"<para>The <application>KTutorial editor</application> windows will be shown " +"again once the selection list is closed.</para>"); + QString caption = i18nc("@title:window", "<application>KTutorial " +"editor</application> windows will be hidden"); + KMessageBox::information(this, text, caption, + "KTutorialEditorWindowsWillBeHidden"); RemoteEditorSupport* remoteEditorSupport = TargetApplication::self()->remoteEditorSupport(); + //The target application may have been closed while the message box was + //shown. + if (!remoteEditorSupport) { + warnAboutFinishedTargetApplicationBeforeClosing(); + return; + } + + hideParentWindows(this); + RemoteObject* mainWindow = remoteEditorSupport->mainWindow(); RemoteObjectTreeItem* rootItem = new RemoteObjectTreeItem(mainWindow); TreeModel* treeModel = new TreeModel(rootItem, this); @@ -167,12 +194,7 @@ return; } - QString text = i18nc("@label", "The target application has been closed, " -"but it must be running to be able to choose the objects."); - QString caption = i18nc("@title:window", "Target application closed"); - KMessageBox::sorry(this, text, caption); - - close(); + warnAboutFinishedTargetApplicationBeforeClosing(); } void RemoteObjectChooser::setCurrentRemoteObject(RemoteObject* remoteObject) { Modified: trunk/ktutorial/ktutorial-editor/src/view/RemoteObjectChooser.h =================================================================== --- trunk/ktutorial/ktutorial-editor/src/view/RemoteObjectChooser.h 2010-08-14 14:57:12 UTC (rev 247) +++ trunk/ktutorial/ktutorial-editor/src/view/RemoteObjectChooser.h 2010-08-14 17:30:49 UTC (rev 248) @@ -39,7 +39,8 @@ * When the target application is successfully started, the RemoteObjectChooser * hides all its parent dialogs and windows. Only the RemoteObjectChooser itself * is kept shown to avoid the rest of windows of KTutorial editor to get in the - * way of the user when he interacts with the target application. + * way of the user when he interacts with the target application. Before hiding + * the windows an information message is shown to the user explaining this. * * When the user selects a remote object in the list and that object represents * a widget, the widget is highlighted in the target application. @@ -132,11 +133,17 @@ */ void showParentWindows(QWidget* widget); + /** + * A warning is shown to the user explaining that the target application + * must be running and this RemoteObjectChooser is closed. + */ + void warnAboutFinishedTargetApplicationBeforeClosing(); + private Q_SLOTS: /** - * Hides the parent windows and dialogs and sets up the models for the tree - * view. + * Shows the information message about hiding the parent windows, hides the + * parent windows and dialogs, and sets up the models for the tree view. */ void handleTargetApplicationStarted(); Modified: trunk/ktutorial/ktutorial-editor/tests/unit/view/RemoteObjectChooserTest.cpp =================================================================== --- trunk/ktutorial/ktutorial-editor/tests/unit/view/RemoteObjectChooserTest.cpp 2010-08-14 14:57:12 UTC (rev 247) +++ trunk/ktutorial/ktutorial-editor/tests/unit/view/RemoteObjectChooserTest.cpp 2010-08-14 17:30:49 UTC (rev 248) @@ -58,6 +58,7 @@ void testTargetApplicationNotUsingKTutorial(); void testTargetApplicationStopped(); + void testTargetApplicationStoppedBeforeClosingInformationMessageBox(); void close(); //Closing with ALT+F4 can't be tested, as it depends on the window manager @@ -72,8 +73,11 @@ QString mPath; - void closeMessageBox(QWidget* widget, int timeToWait); + void closeInformationMessageBox(int timeToWait); + void closeSorryMessageBox(QWidget* widget, int timeToWait); + void killTargetApplication(int timeToWait); + QTreeView* remoteObjectsTreeView(RemoteObjectChooser* widget) const; QPushButton* okButton(RemoteObjectChooser* widget) const; @@ -120,6 +124,8 @@ QWidget* dialog = new QWidget(&window, Qt::Dialog); dialog->show(); + //Queue closing the information message box + closeInformationMessageBox(1000); RemoteObjectChooser* chooser = new RemoteObjectChooser(dialog); chooser->show(); @@ -147,6 +153,8 @@ QWidget* dialog = new QWidget(&window, Qt::Dialog); dialog->show(); + //Queue closing the information message box + closeInformationMessageBox(1000); RemoteObjectChooser* chooser = new RemoteObjectChooser(dialog); chooser->show(); @@ -170,8 +178,8 @@ QPointer<RemoteObjectChooser> chooser = new RemoteObjectChooser(dialog); chooser->show(); - //Queue closing the message box - closeMessageBox(chooser, 1000); + //Queue closing the sorry message box + closeSorryMessageBox(chooser, 1000); //Give the target application time to fail to start QTest::qWait(1000); @@ -197,8 +205,8 @@ QPointer<RemoteObjectChooser> chooser = new RemoteObjectChooser(dialog); chooser->show(); - //Queue closing the message box - closeMessageBox(chooser, 3500); + //Queue closing the sorry message box + closeSorryMessageBox(chooser, 3500); //Give the target application time to fail to start QTest::qWait(3500); @@ -219,14 +227,16 @@ QWidget* dialog = new QWidget(&window, Qt::Dialog); dialog->show(); + //Queue closing the information message box + closeInformationMessageBox(1000); QPointer<RemoteObjectChooser> chooser = new RemoteObjectChooser(dialog); chooser->show(); //Give the target application time to start QTest::qWait(1000); - //Queue closing the message box - closeMessageBox(chooser, 1000); + //Queue closing the sorry message box + closeSorryMessageBox(chooser, 1000); TargetApplication::self()->mProcess->kill(); @@ -241,6 +251,44 @@ QVERIFY(dialog->isVisible()); } +void RemoteObjectChooserTest:: +testTargetApplicationStoppedBeforeClosingInformationMessageBox() { + TargetApplication::self()->setTargetApplicationFilePath(mPath); + + QWidget window(0, Qt::Window); + window.show(); + QWidget* dialog = new QWidget(&window, Qt::Dialog); + dialog->show(); + + QPointer<RemoteObjectChooser> chooser = new RemoteObjectChooser(dialog); + chooser->show(); + + //All the queuing has to be done before the qWait, because the killing must + //be done once the information message is already shown, and the sorry + //message appears just after the information message is closed (and it may + //appear before the wait ends, so queuing it after the wait could not work). + + //Queue killing the target application + killTargetApplication(1000); + + //Queue closing the information message box + closeInformationMessageBox(2000); + + //Queue closing the sorry message box + closeSorryMessageBox(chooser, 3000); + + //Give the target application time to start and be killed, and to close the + //sorry message box + QTest::qWait(3000); + + //Process deleteLater() + QCoreApplication::sendPostedEvents(chooser, QEvent::DeferredDelete); + + QVERIFY(!chooser); + QVERIFY(window.isVisible()); + QVERIFY(dialog->isVisible()); +} + void RemoteObjectChooserTest::close() { TargetApplication::self()->setTargetApplicationFilePath(mPath); @@ -249,6 +297,8 @@ QWidget* dialog = new QWidget(&window, Qt::Dialog); dialog->show(); + //Queue closing the information message box + closeInformationMessageBox(1000); QPointer<RemoteObjectChooser> chooser = new RemoteObjectChooser(dialog); chooser->show(); @@ -269,6 +319,8 @@ TargetApplication::self()->setTargetApplicationFilePath(mPath); QWidget window(0, Qt::Window); + //Queue closing the information message box + closeInformationMessageBox(1000); RemoteObjectChooser* chooser = new RemoteObjectChooser(&window); chooser->show(); @@ -315,6 +367,8 @@ QWidget* dialog = new QWidget(&window, Qt::Dialog); dialog->show(); + //Queue closing the information message box + closeInformationMessageBox(1000); QPointer<RemoteObjectChooser> chooser = new RemoteObjectChooser(dialog); chooser->show(); @@ -358,6 +412,8 @@ QWidget* dialog = new QWidget(&window, Qt::Dialog); dialog->show(); + //Queue closing the information message box + closeInformationMessageBox(1000); QPointer<RemoteObjectChooser> chooser = new RemoteObjectChooser(dialog); chooser->show(); @@ -387,38 +443,78 @@ /////////////////////////////////// Helpers //////////////////////////////////// -class CloseMessageBoxHelper: public QObject { +//The message boxes are modal, so they won't return to the test code until they +//are closed. Thus, the actions to be performed while the message boxes are +//being shown (like closing the message boxes themselves) must be "queued". +class QueuedActionsHelper: public QObject { Q_OBJECT public: - CloseMessageBoxHelper(QWidget* widget): + QueuedActionsHelper(QWidget* widget = 0): QObject(widget), mWidget(widget) { } public slots: - void closeMessageBox() const { + void closeInformation() const { + //The information message box is created in the constructor itself of + //RemoteObjectChooser, so the RemoteObjectChooser can not be passed as + //an argument when this helper is created. It must be got when it is + //going to be destroyed. + QWidget* widget = findRemoteObjectChooser(); + QVERIFY(widget); + + KDialog* messageBox = widget->findChild<KDialog*>("information"); + QVERIFY(messageBox); + delete messageBox; + } + + void closeSorry() const { KDialog* messageBox = mWidget->findChild<KDialog*>("sorry"); QVERIFY(messageBox); delete messageBox; } + void killTargetApplication() const { + TargetApplication::self()->mProcess->kill(); + } + private: QWidget* mWidget; + QWidget* findRemoteObjectChooser() const { + foreach (QWidget* widget, QApplication::topLevelWidgets()) { + if (qobject_cast<RemoteObjectChooser*>(widget)) { + return widget; + } + } + + return 0; + } + }; -void RemoteObjectChooserTest::closeMessageBox(QWidget* widget, int timeToWait) { - CloseMessageBoxHelper* helper = new CloseMessageBoxHelper(widget); +void RemoteObjectChooserTest::closeInformationMessageBox(int timeToWait) { + QueuedActionsHelper* helper = new QueuedActionsHelper(); + QTimer::singleShot(timeToWait, helper, SLOT(closeInformation())); + QTimer::singleShot(timeToWait, helper, SLOT(deleteLater())); +} - //The message box is modal, so it won't return to the test code until it is - //closed. Thus, the commands to close the message box must be "queued", as - //deleting the message box after the qWait won't work. - QTimer::singleShot(timeToWait, helper, SLOT(closeMessageBox())); +void RemoteObjectChooserTest::closeSorryMessageBox(QWidget* widget, + int timeToWait) { + QueuedActionsHelper* helper = new QueuedActionsHelper(widget); + QTimer::singleShot(timeToWait, helper, SLOT(closeSorry())); + QTimer::singleShot(timeToWait, helper, SLOT(deleteLater())); } +void RemoteObjectChooserTest::killTargetApplication(int timeToWait) { + QueuedActionsHelper* helper = new QueuedActionsHelper(); + QTimer::singleShot(timeToWait, helper, SLOT(killTargetApplication())); + QTimer::singleShot(timeToWait, helper, SLOT(deleteLater())); +} + QTreeView* RemoteObjectChooserTest::remoteObjectsTreeView( RemoteObjectChooser* widget) const { return widget->findChild<QTreeView*>("remoteObjectsTreeView"); This was sent by the SourceForge.net collaborative development platform, the world's largest Open Source development site. |
From: <dan...@us...> - 2010-08-14 14:57:18
|
Revision: 247 http://ktutorial.svn.sourceforge.net/ktutorial/?rev=247&view=rev Author: danxuliu Date: 2010-08-14 14:57:12 +0000 (Sat, 14 Aug 2010) Log Message: ----------- Add missing What's this help. Modified Paths: -------------- trunk/ktutorial/ktutorial-editor/src/view/RemoteObjectNameWidget.ui Modified: trunk/ktutorial/ktutorial-editor/src/view/RemoteObjectNameWidget.ui =================================================================== --- trunk/ktutorial/ktutorial-editor/src/view/RemoteObjectNameWidget.ui 2010-06-13 18:25:22 UTC (rev 246) +++ trunk/ktutorial/ktutorial-editor/src/view/RemoteObjectNameWidget.ui 2010-08-14 14:57:12 UTC (rev 247) @@ -11,14 +11,23 @@ </rect> </property> <property name="windowTitle"> - <string>Form</string> + <string comment="@title">Choose the remote object name</string> </property> + <property name="whatsThis"> + <string comment="@info:whatsthis"><para>Choose the name of the remote object.</para> +<para>If the name is known, it can be directly written. Else, it can be choosen from all the objects currently available in the target application.</para></string> + </property> <layout class="QHBoxLayout" name="RemoteObjectNameWidgetHorizontalLayout"> <property name="margin"> <number>0</number> </property> <item> - <widget class="KLineEdit" name="objectNameLineEdit"/> + <widget class="KLineEdit" name="objectNameLineEdit"> + <property name="whatsThis"> + <string comment="@info:whatsthis"><para>The name of the QObject.</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="KPushButton" name="objectNamePushButton"> This was sent by the SourceForge.net collaborative development platform, the world's largest Open Source development site. |
From: <dan...@us...> - 2010-06-13 18:25:29
|
Revision: 246 http://ktutorial.svn.sourceforge.net/ktutorial/?rev=246&view=rev Author: danxuliu Date: 2010-06-13 18:25:22 +0000 (Sun, 13 Jun 2010) Log Message: ----------- Fix next step after "clearText" in "Using the tutorials" tutorial. Modified Paths: -------------- trunk/ktutorial/ktutorial-library/src/tutorials/UsingKTutorial.cpp Modified: trunk/ktutorial/ktutorial-library/src/tutorials/UsingKTutorial.cpp =================================================================== --- trunk/ktutorial/ktutorial-library/src/tutorials/UsingKTutorial.cpp 2010-05-22 21:30:54 UTC (rev 245) +++ trunk/ktutorial/ktutorial-library/src/tutorials/UsingKTutorial.cpp 2010-06-13 18:25:22 UTC (rev 246) @@ -310,7 +310,7 @@ findObject<QTextEdit*>("usingKTutorialTextEdit"); if (textEdit->toPlainText().isEmpty()) { - nextStep("highlightTextEdit"); + nextStep("textCleared"); } } This was sent by the SourceForge.net collaborative development platform, the world's largest Open Source development site. |
From: <dan...@us...> - 2010-05-22 21:31:01
|
Revision: 245 http://ktutorial.svn.sourceforge.net/ktutorial/?rev=245&view=rev Author: danxuliu Date: 2010-05-22 21:30:54 +0000 (Sat, 22 May 2010) Log Message: ----------- Rename "Set data..." actions to "Set step data..." and "Set reaction data..." so they can be distinguished in the "Configure Shortcuts" dialog. Modified Paths: -------------- trunk/ktutorial/ktutorial-editor/src/EditActions.cpp Modified: trunk/ktutorial/ktutorial-editor/src/EditActions.cpp =================================================================== --- trunk/ktutorial/ktutorial-editor/src/EditActions.cpp 2010-05-21 23:36:29 UTC (rev 244) +++ trunk/ktutorial/ktutorial-editor/src/EditActions.cpp 2010-05-22 21:30:54 UTC (rev 245) @@ -145,7 +145,7 @@ connect(action, SIGNAL(triggered(bool)), this, SLOT(addStep())); action = new KAction(this); - action->setText(i18nc("@action", "Set data...")); + action->setText(i18nc("@action", "Set step data...")); action->setStatusTip(i18nc("@info:status", "Set the name and text of the " "currently selected step.")); action->setIcon(KIcon("document-edit")); @@ -191,7 +191,7 @@ connect(action, SIGNAL(triggered(bool)), this, SLOT(addReaction())); action = new KAction(this); - action->setText(i18nc("@action", "Set data...")); + action->setText(i18nc("@action", "Set reaction data...")); action->setStatusTip(i18nc("@info:status", "Set the trigger and the " "response of the currently selected reaction.")); action->setIcon(KIcon("document-edit")); This was sent by the SourceForge.net collaborative development platform, the world's largest Open Source development site. |
From: <dan...@us...> - 2010-05-21 23:36:39
|
Revision: 244 http://ktutorial.svn.sourceforge.net/ktutorial/?rev=244&view=rev Author: danxuliu Date: 2010-05-21 23:36:29 +0000 (Fri, 21 May 2010) Log Message: ----------- Add RemoteObjectNameWidget to select the name of a remote object. It encapsulates the current KLineEdit and RemoteObjectChooser button in WaitForSignalWidget and WaitForEventWidget, also providing remote object name completion. Modified Paths: -------------- trunk/ktutorial/ktutorial-editor/src/targetapplication/RemoteEditorSupport.cpp trunk/ktutorial/ktutorial-editor/src/targetapplication/RemoteEditorSupport.h trunk/ktutorial/ktutorial-editor/src/view/CMakeLists.txt trunk/ktutorial/ktutorial-editor/src/view/WaitForEventWidget.cpp trunk/ktutorial/ktutorial-editor/src/view/WaitForEventWidget.h trunk/ktutorial/ktutorial-editor/src/view/WaitForEventWidget.ui trunk/ktutorial/ktutorial-editor/src/view/WaitForSignalWidget.cpp trunk/ktutorial/ktutorial-editor/src/view/WaitForSignalWidget.h trunk/ktutorial/ktutorial-editor/src/view/WaitForSignalWidget.ui trunk/ktutorial/ktutorial-editor/tests/unit/targetapplication/RemoteClassStubs.h trunk/ktutorial/ktutorial-editor/tests/unit/targetapplication/RemoteEditorSupportTest.cpp trunk/ktutorial/ktutorial-editor/tests/unit/view/CMakeLists.txt trunk/ktutorial/ktutorial-editor/tests/unit/view/WaitForEventWidgetTest.cpp trunk/ktutorial/ktutorial-editor/tests/unit/view/WaitForSignalWidgetTest.cpp trunk/ktutorial/ktutorial-editor/tests/unit/view/WaitForWidgetTest.cpp Added Paths: ----------- trunk/ktutorial/ktutorial-editor/src/view/RemoteObjectNameWidget.cpp trunk/ktutorial/ktutorial-editor/src/view/RemoteObjectNameWidget.h trunk/ktutorial/ktutorial-editor/src/view/RemoteObjectNameWidget.ui trunk/ktutorial/ktutorial-editor/tests/unit/view/RemoteObjectNameWidgetTest.cpp Modified: trunk/ktutorial/ktutorial-editor/src/targetapplication/RemoteEditorSupport.cpp =================================================================== --- trunk/ktutorial/ktutorial-editor/src/targetapplication/RemoteEditorSupport.cpp 2010-05-18 16:42:44 UTC (rev 243) +++ trunk/ktutorial/ktutorial-editor/src/targetapplication/RemoteEditorSupport.cpp 2010-05-21 23:36:29 UTC (rev 244) @@ -32,7 +32,8 @@ "org.kde.ktutorial.EditorSupport", QDBusConnection::sessionBus(), 0), mMapper(mapper), - mRemoteEventSpy(0) { + mRemoteEventSpy(0), + mNumberOfPendingEnableEventSpyCalls(0) { } RemoteEditorSupport::~RemoteEditorSupport() { @@ -66,6 +67,7 @@ RemoteEventSpy* RemoteEditorSupport::enableEventSpy() throw (DBusException) { if (mRemoteEventSpy) { + mNumberOfPendingEnableEventSpyCalls++; return mRemoteEventSpy; } @@ -75,6 +77,7 @@ } mRemoteEventSpy = new RemoteEventSpy(service(), mMapper); + mNumberOfPendingEnableEventSpyCalls = 1; return mRemoteEventSpy; } @@ -83,6 +86,11 @@ return; } + mNumberOfPendingEnableEventSpyCalls--; + if (mNumberOfPendingEnableEventSpyCalls > 0) { + return; + } + QDBusReply<void> reply = call("disableEventSpy"); if (!reply.isValid()) { throw DBusException(reply.error().message()); Modified: trunk/ktutorial/ktutorial-editor/src/targetapplication/RemoteEditorSupport.h =================================================================== --- trunk/ktutorial/ktutorial-editor/src/targetapplication/RemoteEditorSupport.h 2010-05-18 16:42:44 UTC (rev 243) +++ trunk/ktutorial/ktutorial-editor/src/targetapplication/RemoteEditorSupport.h 2010-05-21 23:36:29 UTC (rev 244) @@ -103,6 +103,12 @@ /** * Disables the EventSpy in the remote EditorSupport and destroys the proxy * for it. + * The EventSpy is not disabled until the same number of calls to the + * enableEventSpy() method are made to this method. It makes possible to + * share the same RemoteEventSpy between objects that know nothing one of + * each other: each object enable and disable the RemoteEventSpy as they + * need, but it is not actually disabled until it is disabled by the last + * object using it. * * @throws DBusException If a DBus error happens. */ @@ -120,6 +126,12 @@ */ RemoteEventSpy* mRemoteEventSpy; + /** + * The number of enableEventSpy calls that didn't get a disableEventSpy + * counterpart yet. + */ + int mNumberOfPendingEnableEventSpyCalls; + }; #endif Modified: trunk/ktutorial/ktutorial-editor/src/view/CMakeLists.txt =================================================================== --- trunk/ktutorial/ktutorial-editor/src/view/CMakeLists.txt 2010-05-18 16:42:44 UTC (rev 243) +++ trunk/ktutorial/ktutorial-editor/src/view/CMakeLists.txt 2010-05-21 23:36:29 UTC (rev 244) @@ -35,6 +35,7 @@ set(ktutorial_editor_view_SRCS ${ktutorial_editor_view_SRCS} RemoteObjectChooser.cpp + RemoteObjectNameWidget.cpp RemoteObjectTreeItem.cpp RemoteObjectTreeItemUpdater.cpp RemoteObjectTreeSelectionManager.cpp @@ -47,6 +48,7 @@ LicenseWidget.ui NewWaitForWidget.ui ReactionWidget.ui + RemoteObjectNameWidget.ui StepDataWidget.ui TutorialInformationWidget.ui WaitForEventWidget.ui Added: trunk/ktutorial/ktutorial-editor/src/view/RemoteObjectNameWidget.cpp =================================================================== --- trunk/ktutorial/ktutorial-editor/src/view/RemoteObjectNameWidget.cpp (rev 0) +++ trunk/ktutorial/ktutorial-editor/src/view/RemoteObjectNameWidget.cpp 2010-05-21 23:36:29 UTC (rev 244) @@ -0,0 +1,195 @@ +/*************************************************************************** + * Copyright (C) 2010 by Daniel Calviño Sánchez * + * dan...@gm... * + * * + * This program is free software; you can redistribute it and/or modify * + * it under the terms of the GNU General Public License as published by * + * the Free Software Foundation; either version 3 of the License, or * + * (at your option) any later version. * + * * + * This program is distributed in the hope that it will be useful, * + * but WITHOUT ANY WARRANTY; without even the implied warranty of * + * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the * + * GNU General Public License for more details. * + * * + * You should have received a copy of the GNU General Public License * + * along with this program; If not, see <http://www.gnu.org/licenses/>. * + ***************************************************************************/ + +#include "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 "../targetapplication/TargetApplication.h" + +//public: + +RemoteObjectNameWidget::RemoteObjectNameWidget(QWidget* parent): + QWidget(parent) { + + 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(); + } + + connect(TargetApplication::self(), SIGNAL(started()), + this, SLOT(registerRemoteObjects())); + connect(TargetApplication::self(), SIGNAL(finished()), + this, SLOT(deregisterRemoteObjects())); +} + +RemoteObjectNameWidget::~RemoteObjectNameWidget() { + if (TargetApplication::self()->remoteEditorSupport()) { + TargetApplication::self()->remoteEditorSupport()->disableEventSpy(); + } + + delete ui; +} + +QString RemoteObjectNameWidget::name() const { + return ui->objectNameLineEdit->text(); +} + +void RemoteObjectNameWidget::setName(const QString& name) { + ui->objectNameLineEdit->setText(name); +} + +//private: + +void RemoteObjectNameWidget::registerRemoteObject(RemoteObject* remoteObject, + RemoteObject* parent) +throw (DBusException) { + Q_ASSERT(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()) { + registerRemoteObject(child, remoteObject); + } +} + +void RemoteObjectNameWidget::deregisterRemoteObject(RemoteObject* remoteObject, + RemoteObject* parent) +throw (DBusException) { + Q_ASSERT(remoteObject); + + //The remote object is no longer accesible, 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() { + RemoteObjectChooser* chooser = new RemoteObjectChooser(this); + connect(chooser, SIGNAL(remoteObjectChosen(RemoteObject*)), + this, SLOT(setChosenRemoteObject(RemoteObject*))); + + chooser->show(); +} + +void RemoteObjectNameWidget::setChosenRemoteObject(RemoteObject* remoteObject) { + try { + ui->objectNameLineEdit->setText(remoteObject->name()); + } 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()); + QString title = i18nc("@title", "Can't communicate with the target " +"application"); + KMessageBox::sorry(this, text, title); + } +} + +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)); +} Property changes on: trunk/ktutorial/ktutorial-editor/src/view/RemoteObjectNameWidget.cpp ___________________________________________________________________ Added: svn:eol-style + native Added: trunk/ktutorial/ktutorial-editor/src/view/RemoteObjectNameWidget.h =================================================================== --- trunk/ktutorial/ktutorial-editor/src/view/RemoteObjectNameWidget.h (rev 0) +++ trunk/ktutorial/ktutorial-editor/src/view/RemoteObjectNameWidget.h 2010-05-21 23:36:29 UTC (rev 244) @@ -0,0 +1,175 @@ +/*************************************************************************** + * Copyright (C) 2010 by Daniel Calviño Sánchez * + * dan...@gm... * + * * + * This program is free software; you can redistribute it and/or modify * + * it under the terms of the GNU General Public License as published by * + * the Free Software Foundation; either version 3 of the License, or * + * (at your option) any later version. * + * * + * This program is distributed in the hope that it will be useful, * + * but WITHOUT ANY WARRANTY; without even the implied warranty of * + * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the * + * GNU General Public License for more details. * + * * + * You should have received a copy of the GNU General Public License * + * along with this program; If not, see <http://www.gnu.org/licenses/>. * + ***************************************************************************/ + +#ifndef REMOTEOBJECTNAMEWIDGET_H +#define REMOTEOBJECTNAMEWIDGET_H + +#include <QHash> +#include <QWidget> + +#include "../targetapplication/DBusException.h" + +class RemoteObject; + +namespace Ui { +class RemoteObjectNameWidget; +} + +/** + * Widget to choose the name of a RemoteObject. + * The widget is composed by a line edit and a button to show a + * RemoteObjectChooser. The name can be set directly in the line edit or with + * the aid of the RemoteObjectChooser. + * + * 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 a name is set in the line edit the signal + * remoteObjectChosen(RemoteObject*) is emitted. + */ +class RemoteObjectNameWidget: public QWidget { +Q_OBJECT +public: + + /** + * Creates a new RemoteObjectNameWidget. + * + * @param parent The parent QWidget. + */ + explicit RemoteObjectNameWidget(QWidget* parent = 0); + + /** + * Destroys this widget. + */ + virtual ~RemoteObjectNameWidget(); + + /** + * Returns the chosen remote object name. + * + * @return The chosen remote object name. + */ + QString name() const; + + /** + * Sets the chosen remote object name. + * + * @param name The chosen remote object name. + */ + void setName(const QString& name); + +Q_SIGNALS: + + /** + * Emitted when the name of a remote object is set. + * It does not matter how the name was set (using setName(QString), written + * by the user or chosen from the RemoteObjectChooser). + * If there is no remote object with the name set or the target application + * is not running, the parameter of this signal is a null pointer. + * + * @param remoteObject The RemoteObject with the name set. + */ + void remoteObjectChosen(RemoteObject* remoteObject); + +private: + + /** + * The RemoteObjects with a name indexed by their name. + */ + QHash<QString, RemoteObject*> mRemoteObjectForName; + + /** + * The known RemoteObjects with a 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: + + /** + * Creates and shows a new RemoteObjectChooser. + */ + void showRemoteObjectChooser(); + + /** + * Sets the object name based in the chosen remote object. + * + * @param remoteObject The chosen RemoteObject. + */ + 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. + * + * @param name The name set. + */ + void handleNameChanged(const QString& name); + +}; + +#endif Property changes on: trunk/ktutorial/ktutorial-editor/src/view/RemoteObjectNameWidget.h ___________________________________________________________________ Added: svn:eol-style + native Added: trunk/ktutorial/ktutorial-editor/src/view/RemoteObjectNameWidget.ui =================================================================== --- trunk/ktutorial/ktutorial-editor/src/view/RemoteObjectNameWidget.ui (rev 0) +++ trunk/ktutorial/ktutorial-editor/src/view/RemoteObjectNameWidget.ui 2010-05-21 23:36:29 UTC (rev 244) @@ -0,0 +1,55 @@ +<?xml version="1.0" encoding="UTF-8"?> +<ui version="4.0"> + <class>RemoteObjectNameWidget</class> + <widget class="QWidget" name="RemoteObjectNameWidget"> + <property name="geometry"> + <rect> + <x>0</x> + <y>0</y> + <width>400</width> + <height>300</height> + </rect> + </property> + <property name="windowTitle"> + <string>Form</string> + </property> + <layout class="QHBoxLayout" name="RemoteObjectNameWidgetHorizontalLayout"> + <property name="margin"> + <number>0</number> + </property> + <item> + <widget class="KLineEdit" name="objectNameLineEdit"/> + </item> + <item> + <widget class="KPushButton" name="objectNamePushButton"> + <property name="toolTip"> + <string comment="@info:tooltip">Choose the object name from a list with all the objects in the target application</string> + </property> + <property name="whatsThis"> + <string comment="@info:whatsthis"><p>Opens the list with all the objects in the target application to select the object from them.</p> +<p>The object list must be gotten from a running application. The first time that you try to choose the object name you will be asked for the target application of the tutorial. A new instance of the application will then be started to know the available objects.</p> +<p>The next time that you try to choose the object name the already running application will be used. If it is quitted, a new instance will be started again.</p> +<p>When the target application is started all the KTutorial editor windows, except the one with the list, will be hidden. When the list is closed, the windows will be shown again.</p></string> + </property> + <property name="text"> + <string comment="@action:button">Choose...</string> + </property> + </widget> + </item> + </layout> + </widget> + <customwidgets> + <customwidget> + <class>KPushButton</class> + <extends>QPushButton</extends> + <header>kpushbutton.h</header> + </customwidget> + <customwidget> + <class>KLineEdit</class> + <extends>QLineEdit</extends> + <header>klineedit.h</header> + </customwidget> + </customwidgets> + <resources/> + <connections/> +</ui> Modified: trunk/ktutorial/ktutorial-editor/src/view/WaitForEventWidget.cpp =================================================================== --- trunk/ktutorial/ktutorial-editor/src/view/WaitForEventWidget.cpp 2010-05-18 16:42:44 UTC (rev 243) +++ trunk/ktutorial/ktutorial-editor/src/view/WaitForEventWidget.cpp 2010-05-21 23:36:29 UTC (rev 244) @@ -24,9 +24,7 @@ #include "../data/WaitForEvent.h" #ifdef QT_QTDBUS_FOUND -#include <KMessageBox> - -#include "RemoteObjectChooser.h" +#include "RemoteObjectNameWidget.h" #include "../targetapplication/RemoteObject.h" #endif @@ -38,16 +36,26 @@ mWaitForEvent(waitForEvent) { ui = new Ui::WaitForEventWidget(); +#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 - connect(ui->receiverNamePushButton, SIGNAL(clicked(bool)), - this, SLOT(showRemoteObjectChooser())); + //Replace ui->receiverNameLineEdit with mRemoteObjectNameWidget + ui->valueVerticalLayout->removeWidget(ui->receiverNameLineEdit); + delete ui->receiverNameLineEdit; + + ui->valueVerticalLayout->insertWidget(0, mRemoteObjectNameWidget); + + mRemoteObjectNameWidget->setName(waitForEvent->receiverName()); #else - ui->receiverNamePushButton->hide(); + ui->receiverNameLineEdit->setText(waitForEvent->receiverName()); #endif - ui->receiverNameLineEdit->setText(waitForEvent->receiverName()); ui->eventNameLineEdit->setText(waitForEvent->eventName()); addItemsToEventNameCompletion(); @@ -58,7 +66,11 @@ } void WaitForEventWidget::saveChanges() { +#ifdef QT_QTDBUS_FOUND + QString receiverName = mRemoteObjectNameWidget->name(); +#else QString receiverName = ui->receiverNameLineEdit->text(); +#endif if (mWaitForEvent->receiverName() != receiverName) { mWaitForEvent->setReceiverName(receiverName); } @@ -80,28 +92,3 @@ completion->addItem(eventTypeEnumerator.key(i)); } } - -//private slots: - -#ifdef QT_QTDBUS_FOUND -void WaitForEventWidget::showRemoteObjectChooser() { - RemoteObjectChooser* chooser = new RemoteObjectChooser(this); - connect(chooser, SIGNAL(remoteObjectChosen(RemoteObject*)), - this, SLOT(setChosenRemoteObject(RemoteObject*))); - - chooser->show(); -} - -void WaitForEventWidget::setChosenRemoteObject(RemoteObject* remoteObject) { - try { - ui->receiverNameLineEdit->setText(remoteObject->name()); - } catch (DBusException e) { - QString text = i18nc("@label", "The receiver name can not be set, " -"there was a problem getting the name from the target application: %1", -e.message()); - QString title = i18nc("@title", "Can't communicate with the target " -"application"); - KMessageBox::sorry(this, text, title); - } -} -#endif Modified: trunk/ktutorial/ktutorial-editor/src/view/WaitForEventWidget.h =================================================================== --- trunk/ktutorial/ktutorial-editor/src/view/WaitForEventWidget.h 2010-05-18 16:42:44 UTC (rev 243) +++ trunk/ktutorial/ktutorial-editor/src/view/WaitForEventWidget.h 2010-05-21 23:36:29 UTC (rev 244) @@ -21,7 +21,11 @@ #include "EditionWidget.h" +#ifdef QT_QTDBUS_FOUND class RemoteObject; +class RemoteObjectNameWidget; +#endif + class WaitForEvent; namespace Ui { @@ -66,27 +70,18 @@ */ Ui::WaitForEventWidget* ui; - /** - * Adds all the event names to the completion object of the event name line - * edit. - */ - void addItemsToEventNameCompletion(); - -private Q_SLOTS: - #ifdef QT_QTDBUS_FOUND /** - * Creates and shows a new RemoteObjectChooser. + * The widget to get the name of a remote object. */ - void showRemoteObjectChooser(); + RemoteObjectNameWidget* mRemoteObjectNameWidget; +#endif /** - * Sets the receiver name based in the chosen remote object. - * - * @param remoteObject The chosen RemoteObject. + * Adds all the event names to the completion object of the event name line + * edit. */ - void setChosenRemoteObject(RemoteObject* remoteObject); -#endif + void addItemsToEventNameCompletion(); }; Modified: trunk/ktutorial/ktutorial-editor/src/view/WaitForEventWidget.ui =================================================================== --- trunk/ktutorial/ktutorial-editor/src/view/WaitForEventWidget.ui 2010-05-18 16:42:44 UTC (rev 243) +++ trunk/ktutorial/ktutorial-editor/src/view/WaitForEventWidget.ui 2010-05-21 23:36:29 UTC (rev 244) @@ -33,9 +33,6 @@ <property name="alignment"> <set>Qt::AlignRight|Qt::AlignTrailing|Qt::AlignVCenter</set> </property> - <property name="buddy"> - <cstring>receiverNameLineEdit</cstring> - </property> </widget> </item> <item> @@ -56,32 +53,12 @@ <item> <layout class="QVBoxLayout" name="valueVerticalLayout"> <item> - <layout class="QHBoxLayout" name="receiverNameValueHorizontalLayout"> - <item> - <widget class="KLineEdit" name="receiverNameLineEdit"> - <property name="whatsThis"> - <string comment="@info:whatsthis"><para>The name of the QObject that receives the event.</para> + <widget class="KLineEdit" name="receiverNameLineEdit"> + <property name="whatsThis"> + <string comment="@info:whatsthis"><para>The name of the QObject that receives the event.</para> <para>Note that the name is not the class of the object, but the string returned by its objectName() method.</para></string> - </property> - </widget> - </item> - <item> - <widget class="KPushButton" name="receiverNamePushButton"> - <property name="toolTip"> - <string comment="@info:tooltip">Choose the emitter name from a list with all the objects in the target application</string> - </property> - <property name="whatsThis"> - <string comment="@info:whatsthis"><p>Opens the list with all the objects in the target application to select the receiver from them.</p> -<p>The object list must be gotten from a running application. The first time that you try to choose the receiver name you will be asked for the target application of the tutorial. A new instance of the application will then be started to know the available objects.</p> -<p>The next time that you try to choose the receiver name the already running application will be used. If it is quitted, a new instance will be started again.</p> -<p>When the target application is started all the KTutorial editor windows, except the one with the list, will be hidden. When the list is closed, the windows will be shown again.</p></string> - </property> - <property name="text"> - <string comment="@action:button">Choose...</string> - </property> - </widget> - </item> - </layout> + </property> + </widget> </item> <item> <widget class="KLineEdit" name="eventNameLineEdit"> @@ -113,11 +90,6 @@ </widget> <customwidgets> <customwidget> - <class>KPushButton</class> - <extends>QPushButton</extends> - <header>kpushbutton.h</header> - </customwidget> - <customwidget> <class>KLineEdit</class> <extends>QLineEdit</extends> <header>klineedit.h</header> Modified: trunk/ktutorial/ktutorial-editor/src/view/WaitForSignalWidget.cpp =================================================================== --- trunk/ktutorial/ktutorial-editor/src/view/WaitForSignalWidget.cpp 2010-05-18 16:42:44 UTC (rev 243) +++ trunk/ktutorial/ktutorial-editor/src/view/WaitForSignalWidget.cpp 2010-05-21 23:36:29 UTC (rev 244) @@ -22,9 +22,9 @@ #include "../data/WaitForSignal.h" #ifdef QT_QTDBUS_FOUND -#include <KMessageBox> +#include <KDebug> -#include "RemoteObjectChooser.h" +#include "RemoteObjectNameWidget.h" #include "../targetapplication/RemoteClass.h" #include "../targetapplication/RemoteObject.h" #endif @@ -39,16 +39,29 @@ mWaitForSignal(waitForSignal) { ui = new Ui::WaitForSignalWidget(); +#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 - connect(ui->emitterNamePushButton, SIGNAL(clicked(bool)), - this, SLOT(showRemoteObjectChooser())); + //Replace ui->emitterNameLineEdit with mRemoteObjectNameWidget + ui->valueVerticalLayout->removeWidget(ui->emitterNameLineEdit); + delete ui->emitterNameLineEdit; + + ui->valueVerticalLayout->insertWidget(0, mRemoteObjectNameWidget); + + connect(mRemoteObjectNameWidget, SIGNAL(remoteObjectChosen(RemoteObject*)), + this, SLOT(setChosenRemoteObject(RemoteObject*))); + + mRemoteObjectNameWidget->setName(waitForSignal->emitterName()); #else - ui->emitterNamePushButton->hide(); + ui->emitterNameLineEdit->setText(waitForSignal->emitterName()); #endif - ui->emitterNameLineEdit->setText(waitForSignal->emitterName()); ui->signalNameLineEdit->setText(waitForSignal->signalName()); } @@ -57,7 +70,11 @@ } void WaitForSignalWidget::saveChanges() { +#ifdef QT_QTDBUS_FOUND + QString emitterName = mRemoteObjectNameWidget->name(); +#else QString emitterName = ui->emitterNameLineEdit->text(); +#endif if (mWaitForSignal->emitterName() != emitterName) { mWaitForSignal->setEmitterName(emitterName); } @@ -71,7 +88,8 @@ //private: #ifdef QT_QTDBUS_FOUND -void WaitForSignalWidget::setSignalCompletion(RemoteClass* remoteClass) { +void WaitForSignalWidget::setSignalCompletion(RemoteClass* remoteClass) +throw (DBusException) { KCompletion* completion = ui->signalNameLineEdit->completionObject(); completion->clear(); completion->setOrder(KCompletion::Sorted); @@ -89,24 +107,18 @@ //private slots: #ifdef QT_QTDBUS_FOUND -void WaitForSignalWidget::showRemoteObjectChooser() { - RemoteObjectChooser* chooser = new RemoteObjectChooser(this); - connect(chooser, SIGNAL(remoteObjectChosen(RemoteObject*)), - this, SLOT(setChosenRemoteObject(RemoteObject*))); +void WaitForSignalWidget::setChosenRemoteObject(RemoteObject* remoteObject) { + if (!remoteObject) { + setSignalCompletion(0); + return; + } - chooser->show(); -} - -void WaitForSignalWidget::setChosenRemoteObject(RemoteObject* remoteObject) { try { - ui->emitterNameLineEdit->setText(remoteObject->name()); setSignalCompletion(remoteObject->remoteClass()); } catch (DBusException e) { - QString text = i18nc("@label", "The emitter name can not be set, there " -"was a problem getting the name from the target application: %1", e.message()); - QString title = i18nc("@title", "Can't communicate with the target " -"application"); - KMessageBox::sorry(this, text, title); + kWarning() << "The signal 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/WaitForSignalWidget.h =================================================================== --- trunk/ktutorial/ktutorial-editor/src/view/WaitForSignalWidget.h 2010-05-18 16:42:44 UTC (rev 243) +++ trunk/ktutorial/ktutorial-editor/src/view/WaitForSignalWidget.h 2010-05-21 23:36:29 UTC (rev 244) @@ -21,8 +21,14 @@ #include "EditionWidget.h" +#ifdef QT_QTDBUS_FOUND +#include "../targetapplication/DBusException.h" + class RemoteClass; class RemoteObject; +class RemoteObjectNameWidget; +#endif + class WaitForSignal; namespace Ui { @@ -69,23 +75,23 @@ #ifdef QT_QTDBUS_FOUND /** + * The widget to get the name of a remote object. + */ + RemoteObjectNameWidget* mRemoteObjectNameWidget; + + /** * Sets the completion of the signal line edit to the signals emitted by the * given remote class and its super classes. * * @param remoteClass The class to get its signal list. */ - void setSignalCompletion(RemoteClass* remoteClass); + void setSignalCompletion(RemoteClass* remoteClass) throw (DBusException); #endif private Q_SLOTS: #ifdef QT_QTDBUS_FOUND /** - * Creates and shows a new RemoteObjectChooser. - */ - void showRemoteObjectChooser(); - - /** * Sets the emitter name based in the chosen remote object. * * @param remoteObject The chosen RemoteObject. Modified: trunk/ktutorial/ktutorial-editor/src/view/WaitForSignalWidget.ui =================================================================== --- trunk/ktutorial/ktutorial-editor/src/view/WaitForSignalWidget.ui 2010-05-18 16:42:44 UTC (rev 243) +++ trunk/ktutorial/ktutorial-editor/src/view/WaitForSignalWidget.ui 2010-05-21 23:36:29 UTC (rev 244) @@ -33,9 +33,6 @@ <property name="alignment"> <set>Qt::AlignRight|Qt::AlignTrailing|Qt::AlignVCenter</set> </property> - <property name="buddy"> - <cstring>emitterNameLineEdit</cstring> - </property> </widget> </item> <item> @@ -56,32 +53,12 @@ <item> <layout class="QVBoxLayout" name="valueVerticalLayout"> <item> - <layout class="QHBoxLayout" name="emitterNameValueHorizontalLayout"> - <item> - <widget class="KLineEdit" name="emitterNameLineEdit"> - <property name="whatsThis"> - <string comment="@info:whatsthis"><para>The name of the QObject that emits the signal.</para> + <widget class="KLineEdit" name="emitterNameLineEdit"> + <property name="whatsThis"> + <string comment="@info:whatsthis"><para>The name of the QObject that emits the signal.</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="KPushButton" name="emitterNamePushButton"> - <property name="toolTip"> - <string comment="@info:tooltip">Choose the emitter name from a list with all the objects in the target application</string> - </property> - <property name="whatsThis"> - <string comment="@info:whatsthis"><p>Opens the list with all the objects in the target application to select the emitter from them.</p> -<p>The object list must be gotten from a running application. The first time that you try to choose the emitter name you will be asked for the target application of the tutorial. A new instance of the application will then be started to know the available objects.</p> -<p>The next time that you try to choose the emitter name the already running application will be used. If it is quitted, a new instance will be started again.</p> -<p>When the target application is started all the KTutorial editor windows, except the one with the list, will be hidden. When the list is closed, the windows will be shown again.</p></string> - </property> - <property name="text"> - <string comment="@action:button">Choose...</string> - </property> - </widget> - </item> - </layout> + </property> + </widget> </item> <item> <widget class="KLineEdit" name="signalNameLineEdit"> @@ -113,11 +90,6 @@ </widget> <customwidgets> <customwidget> - <class>KPushButton</class> - <extends>QPushButton</extends> - <header>kpushbutton.h</header> - </customwidget> - <customwidget> <class>KLineEdit</class> <extends>QLineEdit</extends> <header>klineedit.h</header> Modified: trunk/ktutorial/ktutorial-editor/tests/unit/targetapplication/RemoteClassStubs.h =================================================================== --- trunk/ktutorial/ktutorial-editor/tests/unit/targetapplication/RemoteClassStubs.h 2010-05-18 16:42:44 UTC (rev 243) +++ trunk/ktutorial/ktutorial-editor/tests/unit/targetapplication/RemoteClassStubs.h 2010-05-21 23:36:29 UTC (rev 244) @@ -81,7 +81,7 @@ QString objectName(int objectId) { - if (objectId > 100) { + if (objectId > 1000) { return ""; } @@ -89,7 +89,7 @@ } QString className(int objectId) { - if (objectId > 100) { + if (objectId > 1000) { return ""; } Modified: trunk/ktutorial/ktutorial-editor/tests/unit/targetapplication/RemoteEditorSupportTest.cpp =================================================================== --- trunk/ktutorial/ktutorial-editor/tests/unit/targetapplication/RemoteEditorSupportTest.cpp 2010-05-18 16:42:44 UTC (rev 243) +++ trunk/ktutorial/ktutorial-editor/tests/unit/targetapplication/RemoteEditorSupportTest.cpp 2010-05-21 23:36:29 UTC (rev 244) @@ -61,6 +61,7 @@ void testEnableEventSpyWhenRemoteEditorSupportIsNotAvailable(); void testDisableEventSpy(); + void testDisableEventSpyAfterSeveralEnableEventSpyCalls(); void testDisableEventSpyTwice(); void testDisableEventSpyWhenRemoteEditorSupportIsNotAvailable(); @@ -267,6 +268,33 @@ QCOMPARE(eventReceivedSpy.count(), 0); } +void RemoteEditorSupportTest:: + testDisableEventSpyAfterSeveralEnableEventSpyCalls() { + RemoteObjectMapper mapper(QDBusConnection::sessionBus().baseService()); + RemoteEditorSupport remoteEditorSupport( + QDBusConnection::sessionBus().baseService(), &mapper); + + RemoteEventSpy* remoteEventSpy = remoteEditorSupport.enableEventSpy(); + remoteEditorSupport.enableEventSpy(); + remoteEditorSupport.enableEventSpy(); + + QVERIFY(remoteEventSpy); + + remoteEditorSupport.disableEventSpy(); + remoteEditorSupport.disableEventSpy(); + + QCOMPARE(mEditorSupport->mDisableEventSpyCount, 0); + + remoteEditorSupport.enableEventSpy(); + remoteEditorSupport.disableEventSpy(); + + QCOMPARE(mEditorSupport->mDisableEventSpyCount, 0); + + remoteEditorSupport.disableEventSpy(); + + QCOMPARE(mEditorSupport->mDisableEventSpyCount, 1); +} + void RemoteEditorSupportTest::testDisableEventSpyTwice() { RemoteObjectMapper mapper(QDBusConnection::sessionBus().baseService()); RemoteEditorSupport remoteEditorSupport( @@ -277,9 +305,14 @@ QVERIFY(remoteEventSpy); remoteEditorSupport.disableEventSpy(); + + QCOMPARE(mEditorSupport->mDisableEventSpyCount, 1); + remoteEditorSupport.disableEventSpy(); QCOMPARE(mEditorSupport->mDisableEventSpyCount, 1); + + QVERIFY(remoteEditorSupport.enableEventSpy()); } void RemoteEditorSupportTest:: Modified: trunk/ktutorial/ktutorial-editor/tests/unit/view/CMakeLists.txt =================================================================== --- trunk/ktutorial/ktutorial-editor/tests/unit/view/CMakeLists.txt 2010-05-18 16:42:44 UTC (rev 243) +++ trunk/ktutorial/ktutorial-editor/tests/unit/view/CMakeLists.txt 2010-05-21 23:36:29 UTC (rev 244) @@ -52,6 +52,7 @@ unit_tests( RemoteObjectChooser + RemoteObjectNameWidget RemoteObjectTreeItem RemoteObjectTreeItemUpdater RemoteObjectTreeSelectionManager Added: trunk/ktutorial/ktutorial-editor/tests/unit/view/RemoteObjectNameWidgetTest.cpp =================================================================== --- trunk/ktutorial/ktutorial-editor/tests/unit/view/RemoteObjectNameWidgetTest.cpp (rev 0) +++ trunk/ktutorial/ktutorial-editor/tests/unit/view/RemoteObjectNameWidgetTest.cpp 2010-05-21 23:36:29 UTC (rev 244) @@ -0,0 +1,245 @@ +/*************************************************************************** + * Copyright (C) 2010 by Daniel Calviño Sánchez * + * dan...@gm... * + * * + * This program is free software; you can redistribute it and/or modify * + * it under the terms of the GNU General Public License as published by * + * the Free Software Foundation; either version 3 of the License, or * + * (at your option) any later version. * + * * + * This program is distributed in the hope that it will be useful, * + * but WITHOUT ANY WARRANTY; without even the implied warranty of * + * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the * + * GNU General Public License for more details. * + * * + * You should have received a copy of the GNU General Public License * + * along with this program; If not, see <http://www.gnu.org/licenses/>. * + ***************************************************************************/ + +#include <QtTest> + +#include "RemoteObjectNameWidget.h" + +#include <QtDBus/QtDBus> + +#include <KLineEdit> +#include <KProcess> + +#include "../targetapplication/RemoteClassStubs.h" +#include "../targetapplication/RemoteEditorSupport.h" +#include "../targetapplication/RemoteObject.h" +#define protected public +#define private public +#include "../targetapplication/TargetApplication.h" +#undef private +#undef protected + +class RemoteObjectNameWidgetTest: public QObject { +Q_OBJECT + +private slots: + + void initTestCase(); + void init(); + void cleanup(); + + void testConstructor(); + + void testSetName(); + void testSetNameWithUnknownRemoteObjectName(); + + void testTargetApplicationStartedAfterWidget(); + void testTargetApplicationStopped(); + + void testAddingOrRemovingRemoteObjects(); + +private: + + QString mPath; + + int mRemoteObjectStarType; + + StubEditorSupport* mEditorSupport; + StubObjectRegister* mObjectRegister; + + KLineEdit* objectNameLineEdit(RemoteObjectNameWidget* widget) const; + + void assertRemoteObjectSignal(const QSignalSpy& spy, int index, + const RemoteObject* remoteObject) const; + +}; + +void RemoteObjectNameWidgetTest::initTestCase() { + //RemoteObject* must be registered in order to be used with QSignalSpy + mRemoteObjectStarType = qRegisterMetaType<RemoteObject*>("RemoteObject*"); +} + +void RemoteObjectNameWidgetTest::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 RemoteObjectNameWidgetTest::cleanup() { + delete TargetApplication::sSelf; + TargetApplication::sSelf = 0; +} + +void RemoteObjectNameWidgetTest::testConstructor() { + TargetApplication::self()->setTargetApplicationFilePath(mPath); + TargetApplication::self()->start(); + + //Give the target application time to start + QTest::qWait(1000); + + QWidget parent; + RemoteObjectNameWidget* widget = new RemoteObjectNameWidget(&parent); + + 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")); +} + +void RemoteObjectNameWidgetTest::testSetName() { + 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 423"); + + RemoteObject* mainWindow = + TargetApplication::self()->remoteEditorSupport()->mainWindow(); + + QCOMPARE(widget.name(), QString("The object name 423")); + QCOMPARE(remoteObjectChosenSpy.count(), 1); + assertRemoteObjectSignal(remoteObjectChosenSpy, 0, + mainWindow->children()[3]); +} + +void RemoteObjectNameWidgetTest::testSetNameWithUnknownRemoteObjectName() { + 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 108"); + + QCOMPARE(widget.name(), QString("The object name 108")); + QCOMPARE(remoteObjectChosenSpy.count(), 1); + assertRemoteObjectSignal(remoteObjectChosenSpy, 0, 0); +} + +void RemoteObjectNameWidgetTest::testTargetApplicationStartedAfterWidget() { + RemoteObjectNameWidget widget; + QSignalSpy remoteObjectChosenSpy(&widget, + SIGNAL(remoteObjectChosen(RemoteObject*))); + + QStringList items = objectNameLineEdit(&widget)->completionObject()-> + items(); + QCOMPARE(items.count(), 0); + + widget.setName("The object name 42"); + + QCOMPARE(widget.name(), QString("The object name 42")); + QCOMPARE(remoteObjectChosenSpy.count(), 1); + assertRemoteObjectSignal(remoteObjectChosenSpy, 0, 0); + + TargetApplication::self()->setTargetApplicationFilePath(mPath); + TargetApplication::self()->start(); + + //Give the target application time to start + 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")); + + widget.setName("The object name 423"); + + RemoteObject* mainWindow = + TargetApplication::self()->remoteEditorSupport()->mainWindow(); + + QCOMPARE(widget.name(), QString("The object name 423")); + QCOMPARE(remoteObjectChosenSpy.count(), 2); + assertRemoteObjectSignal(remoteObjectChosenSpy, 1, + mainWindow->children()[3]); +} + +void RemoteObjectNameWidgetTest::testTargetApplicationStopped() { + 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*))); + + TargetApplication::self()->mProcess->kill(); + + //Give the target application time to stop + QTest::qWait(1000); + + QStringList items = objectNameLineEdit(&widget)->completionObject()-> + items(); + QCOMPARE(items.count(), 0); + + widget.setName("The object name 42"); + + QCOMPARE(widget.name(), QString("The object name 42")); + QCOMPARE(remoteObjectChosenSpy.count(), 1); + assertRemoteObjectSignal(remoteObjectChosenSpy, 0, 0); +} + +void RemoteObjectNameWidgetTest::testAddingOrRemovingRemoteObjects() { + QSKIP("Unfortunately, testing if the completion list is updated when an " + "object is added or removed in the target application is too " + "burdensome so the test must be done manually", SkipAll); +} + +/////////////////////////////////// Helpers //////////////////////////////////// + +KLineEdit* RemoteObjectNameWidgetTest::objectNameLineEdit( + RemoteObjectNameWidget* widget) const { + return widget->findChild<KLineEdit*>("objectNameLineEdit"); +} + +//RemoteObject* must be declared as a metatype to be used in qvariant_cast +Q_DECLARE_METATYPE(RemoteObject*); + +void RemoteObjectNameWidgetTest::assertRemoteObjectSignal(const QSignalSpy& spy, + int index, const RemoteObject* remoteObject) const { + QVariant argument = spy.at(index).at(0); + QCOMPARE(argument.userType(), mRemoteObjectStarType); + QCOMPARE(qvariant_cast<RemoteObject*>(argument), remoteObject); +} + +QTEST_MAIN(RemoteObjectNameWidgetTest) + +#include "RemoteObjectNameWidgetTest.moc" Property changes on: trunk/ktutorial/ktutorial-editor/tests/unit/view/RemoteObjectNameWidgetTest.cpp ___________________________________________________________________ Added: svn:eol-style + native Modified: trunk/ktutorial/ktutorial-editor/tests/unit/view/WaitForEventWidgetTest.cpp =================================================================== --- trunk/ktutorial/ktutorial-editor/tests/unit/view/WaitForEventWidgetTest.cpp 2010-05-18 16:42:44 UTC (rev 243) +++ trunk/ktutorial/ktutorial-editor/tests/unit/view/WaitForEventWidgetTest.cpp 2010-05-21 23:36:29 UTC (rev 244) @@ -85,7 +85,11 @@ KLineEdit* WaitForEventWidgetTest::receiverNameLineEdit( WaitForEventWidget* widget) const { +#ifdef QT_QTDBUS_FOUND + return widget->findChild<KLineEdit*>("objectNameLineEdit"); +#else return widget->findChild<KLineEdit*>("receiverNameLineEdit"); +#endif } KLineEdit* WaitForEventWidgetTest::eventNameLineEdit( Modified: trunk/ktutorial/ktutorial-editor/tests/unit/view/WaitForSignalWidgetTest.cpp =================================================================== --- trunk/ktutorial/ktutorial-editor/tests/unit/view/WaitForSignalWidgetTest.cpp 2010-05-18 16:42:44 UTC (rev 243) +++ trunk/ktutorial/ktutorial-editor/tests/unit/view/WaitForSignalWidgetTest.cpp 2010-05-21 23:36:29 UTC (rev 244) @@ -72,7 +72,11 @@ KLineEdit* WaitForSignalWidgetTest::emitterNameLineEdit( WaitForSignalWidget* widget) const { +#ifdef QT_QTDBUS_FOUND + return widget->findChild<KLineEdit*>("objectNameLineEdit"); +#else return widget->findChild<KLineEdit*>("emitterNameLineEdit"); +#endif } KLineEdit* WaitForSignalWidgetTest::signalNameLineEdit( Modified: trunk/ktutorial/ktutorial-editor/tests/unit/view/WaitForWidgetTest.cpp =================================================================== --- trunk/ktutorial/ktutorial-editor/tests/unit/view/WaitForWidgetTest.cpp 2010-05-18 16:42:44 UTC (rev 243) +++ trunk/ktutorial/ktutorial-editor/tests/unit/view/WaitForWidgetTest.cpp 2010-05-21 23:36:29 UTC (rev 244) @@ -362,7 +362,11 @@ void WaitForWidgetTest::setEventData() const { KLineEdit* receiverNameLineEdit = +#ifdef QT_QTDBUS_FOUND + mWidget->findChild<KLineEdit*>("objectNameLineEdit"); +#else mWidget->findChild<KLineEdit*>("receiverNameLineEdit"); +#endif QVERIFY(receiverNameLineEdit); receiverNameLineEdit->setText("The new receiver name"); @@ -378,7 +382,11 @@ void WaitForWidgetTest::setSignalData() const { KLineEdit* emitterNameLineEdit = +#ifdef QT_QTDBUS_FOUND + mWidget->findChild<KLineEdit*>("objectNameLineEdit"); +#else mWidget->findChild<KLineEdit*>("emitterNameLineEdit"); +#endif QVERIFY(emitterNameLineEdit); emitterNameLineEdit->setText("The new emitter name"); This was sent by the SourceForge.net collaborative development platform, the world's largest Open Source development site. |
From: <dan...@us...> - 2010-05-18 16:42:51
|
Revision: 243 http://ktutorial.svn.sourceforge.net/ktutorial/?rev=243&view=rev Author: danxuliu Date: 2010-05-18 16:42:44 +0000 (Tue, 18 May 2010) Log Message: ----------- Use KOpenWithDialog instead of a generic KFileDialog to select the target application. Modified Paths: -------------- trunk/ktutorial/ktutorial-editor/src/view/TargetApplicationView.cpp Modified: trunk/ktutorial/ktutorial-editor/src/view/TargetApplicationView.cpp =================================================================== --- trunk/ktutorial/ktutorial-editor/src/view/TargetApplicationView.cpp 2010-05-18 15:42:15 UTC (rev 242) +++ trunk/ktutorial/ktutorial-editor/src/view/TargetApplicationView.cpp 2010-05-18 16:42:44 UTC (rev 243) @@ -21,10 +21,11 @@ #include <QApplication> #include <QScopedPointer> -#include <KFileDialog> -#include <KFileFilterCombo> #include <KLocalizedString> #include <KMessageBox> +#include <KOpenWithDialog> +#include <KShell> +#include <KStandardDirs> //public: @@ -63,18 +64,24 @@ //private: QString TargetApplicationView::askApplicationFilePath() { - QScopedPointer<KFileDialog> dialog(new KFileDialog(QString("/usr/bin"), "", - mParent)); + QScopedPointer<KOpenWithDialog> dialog(new KOpenWithDialog(mParent)); + dialog->hideNoCloseOnExit(); + dialog->hideRunInTerminal(); - dialog->setCaption(i18nc("@title", "Select Executable")); - dialog->setOperationMode(KFileDialog::Other); - dialog->setMode(KFile::File | KFile::ExistingOnly | KFile::LocalOnly); - if (dialog->exec() == QDialog::Rejected) { return ""; } - return dialog->selectedUrl().toLocalFile(); + //The executable returned by the services may contain arguments like "%U". + //We are interested only in the executable itself. + QString executable = KShell::splitArgs(dialog->text())[0]; + + //The executable may be just a name, not the absolute path to the executable + if (KUrl(executable).isRelative()) { + executable = KStandardDirs::findExe(executable); + } + + return executable; } //private slots: This was sent by the SourceForge.net collaborative development platform, the world's largest Open Source development site. |
From: <dan...@us...> - 2010-05-18 15:42:21
|
Revision: 242 http://ktutorial.svn.sourceforge.net/ktutorial/?rev=242&view=rev Author: danxuliu Date: 2010-05-18 15:42:15 +0000 (Tue, 18 May 2010) Log Message: ----------- Add widget highlighting information to the tutorial about how to use tutorials. Modified Paths: -------------- trunk/ktutorial/ktutorial-library/src/tutorials/UsingKTutorial.cpp Modified: trunk/ktutorial/ktutorial-library/src/tutorials/UsingKTutorial.cpp =================================================================== --- trunk/ktutorial/ktutorial-library/src/tutorials/UsingKTutorial.cpp 2010-05-18 15:39:17 UTC (rev 241) +++ trunk/ktutorial/ktutorial-library/src/tutorials/UsingKTutorial.cpp 2010-05-18 15:42:15 UTC (rev 242) @@ -29,6 +29,7 @@ #include "../TutorialInformation.h" #include "../WaitForEvent.h" #include "../WaitForSignal.h" +#include "../view/StepTextWidget.h" #include "../view/StepWidget.h" class WaitForLeftMouseButtonPressed: public WaitForEvent { @@ -77,12 +78,12 @@ }; -class CloseTextEditStep: public Step { +class HighlightTextEditStep: public Step { Q_OBJECT public: - CloseTextEditStep(): - Step("closeTextEdit") { + HighlightTextEditStep(): + Step("highlightTextEdit") { } virtual void setup() { @@ -222,21 +223,41 @@ addStep(clearTextStep); - //Step closeTextEdit - Step* closeTextEditStep = new CloseTextEditStep(); - closeTextEditStep->setText(i18nc("@info", + //Step textCleared + Step* textClearedStep = new Step("textCleared"); + textClearedStep->setText(i18nc("@info", "<para>Do you see? You are in a new step, but you didn't tell the tutorial to " "continue to the next step, and neither you had to select between several " "options. The tutorial advanced automatically when you erased the text as " "requested. This will be the most common way to advance from one step to " -"another.</para>" +"another.</para>")); + + textClearedStep->addOption(new Option(i18nc("@action", "Continue")), + "highlightTextEdit"); + + addStep(textClearedStep); + + //Step highlightTextEdit + //As changing to another step stops the highlighting in the currently + //highlighted widget, it is not possible to use one step to show how to + //highlight the widget and the next one to show how to stop highlighting it + Step* highlightTextEditStep = new HighlightTextEditStep(); + highlightTextEditStep->setText(i18nc("@info", +"<para>Sometimes, a tutorial may provide a link to a <emphasis>widget" +"</emphasis> (an element of the graphical user interface, like a button). For " +"example, <a href=\"widget:usingKTutorialTextEdit\">this is a link to the text " +"area</a>.</para>" +"<para>When you click on a link to a widget, the widget is highlighted to help " +"you to spot it. If you click again on it, the highlighting will be stopped. " +"In this example it is pretty clear what the text area refers to, but it can " +"be useful in tutorials for more complex applications.</para>" "<para>Ok, close the window with the text area to continue with the " "tutorial.</para>")); //WaitFor is added in step setup, as it uses an object that isn't available //when the tutorial is created - addStep(closeTextEditStep); + addStep(highlightTextEditStep); //Step moveWidgetPress Step* moveWidgetPressStep = new MoveWidgetPressStep(); @@ -289,7 +310,7 @@ findObject<QTextEdit*>("usingKTutorialTextEdit"); if (textEdit->toPlainText().isEmpty()) { - nextStep("closeTextEdit"); + nextStep("highlightTextEdit"); } } This was sent by the SourceForge.net collaborative development platform, the world's largest Open Source development site. |
From: <dan...@us...> - 2010-05-18 15:39:24
|
Revision: 241 http://ktutorial.svn.sourceforge.net/ktutorial/?rev=241&view=rev Author: danxuliu Date: 2010-05-18 15:39:17 +0000 (Tue, 18 May 2010) Log Message: ----------- Fix highlighting a parent widget of a currently highlighted widget. Modified Paths: -------------- trunk/ktutorial/ktutorial-library/src/extendedinformation/WidgetHighlighterManager.cpp trunk/ktutorial/ktutorial-library/src/extendedinformation/WidgetHighlighterManager.h trunk/ktutorial/ktutorial-library/tests/extendedinformation/WidgetHighlighterManagerTest.cpp Modified: trunk/ktutorial/ktutorial-library/src/extendedinformation/WidgetHighlighterManager.cpp =================================================================== --- trunk/ktutorial/ktutorial-library/src/extendedinformation/WidgetHighlighterManager.cpp 2010-05-18 15:37:12 UTC (rev 240) +++ trunk/ktutorial/ktutorial-library/src/extendedinformation/WidgetHighlighterManager.cpp 2010-05-18 15:39:17 UTC (rev 241) @@ -31,6 +31,11 @@ void WidgetHighlighterManager::highlight(QWidget* widget) { WidgetHighlighter* highlighter = widget->findChild<WidgetHighlighter*>(); + if (highlighter && !widget->children().contains(highlighter)) { + stopHighlighting(highlighter->parentWidget()); + highlighter = 0; + } + if (!highlighter) { highlighter = new WidgetHighlighter(widget); connect(highlighter, SIGNAL(stopped(extendedinformation::WidgetHighlighter*)), @@ -42,7 +47,7 @@ void WidgetHighlighterManager::stopHighlighting(QWidget* widget) { WidgetHighlighter* highlighter = widget->findChild<WidgetHighlighter*>(); - if (!highlighter) { + if (!highlighter || !widget->children().contains(highlighter)) { return; } Modified: trunk/ktutorial/ktutorial-library/src/extendedinformation/WidgetHighlighterManager.h =================================================================== --- trunk/ktutorial/ktutorial-library/src/extendedinformation/WidgetHighlighterManager.h 2010-05-18 15:37:12 UTC (rev 240) +++ trunk/ktutorial/ktutorial-library/src/extendedinformation/WidgetHighlighterManager.h 2010-05-18 15:39:17 UTC (rev 241) @@ -53,7 +53,9 @@ /** * Starts a WidgetHighlighter for the given widget. - * If the widget was already being highlighted nothing is done. + * If the widget was already being highlighted nothing is done. If a child + * widget was already being highlighted it is stopped, so only the parent + * highlighting is active. * * @param widget The widget to highlight. */ Modified: trunk/ktutorial/ktutorial-library/tests/extendedinformation/WidgetHighlighterManagerTest.cpp =================================================================== --- trunk/ktutorial/ktutorial-library/tests/extendedinformation/WidgetHighlighterManagerTest.cpp 2010-05-18 15:37:12 UTC (rev 240) +++ trunk/ktutorial/ktutorial-library/tests/extendedinformation/WidgetHighlighterManagerTest.cpp 2010-05-18 15:39:17 UTC (rev 241) @@ -37,9 +37,11 @@ void testHighlight(); void testHighlightWidgetAlreadyHighlighted(); + void testHighlightChildAlreadyHighlighted(); void testHighlightAfterStopHighlighting(); void testStopHighlighting(); + void testStopHighlightingWhenChildIsBeingHighlighted(); void testDeleteWidgetWhileHighlighting(); @@ -86,6 +88,23 @@ QCOMPARE(highlighterOf(&widget), highlighter); } +void WidgetHighlighterManagerTest::testHighlightChildAlreadyHighlighted() { + QWidget widget; + QWidget* child = new QWidget(&widget); + WidgetHighlighterManager* manager = WidgetHighlighterManager::self(); + + manager->highlight(child); + + WidgetHighlighter* childHighlighter = highlighterOf(child); + + manager->highlight(&widget); + + QCOMPARE(widget.findChildren<WidgetHighlighter*>().count(), 1); + QVERIFY(highlighterOf(&widget)); + QVERIFY(highlighterOf(&widget) != childHighlighter); + QVERIFY(!highlighterOf(child)); +} + void WidgetHighlighterManagerTest::testHighlightAfterStopHighlighting() { QWidget widget; WidgetHighlighterManager* manager = WidgetHighlighterManager::self(); @@ -126,6 +145,30 @@ QCOMPARE(widget.findChildren<WidgetHighlighter*>().count(), 0); } +void WidgetHighlighterManagerTest:: + testStopHighlightingWhenChildIsBeingHighlighted() { + QWidget widget; + QWidget* child = new QWidget(&widget); + WidgetHighlighterManager* manager = WidgetHighlighterManager::self(); + + manager->highlight(child); + + //Give it some time to update + QTest::qWait(100); + + manager->stopHighlighting(&widget); + + //Give it some time to update + QTest::qWait(200); + + //The highlighter should have not been stopped, as it was not highlighting + //the parent widget, but the child + QCOMPARE(widget.findChildren<WidgetHighlighter*>().count(), 1); + QVERIFY(highlighterOf(child)); + QVERIFY(highlighterOf(child)->mProgress > 0); + QVERIFY(highlighterOf(child)->mIncreasing); +} + void WidgetHighlighterManagerTest::testDeleteWidgetWhileHighlighting() { QWidget* widget = new QWidget(); WidgetHighlighterManager* manager = WidgetHighlighterManager::self(); This was sent by the SourceForge.net collaborative development platform, the world's largest Open Source development site. |
From: <dan...@us...> - 2010-05-18 15:37:19
|
Revision: 240 http://ktutorial.svn.sourceforge.net/ktutorial/?rev=240&view=rev Author: danxuliu Date: 2010-05-18 15:37:12 +0000 (Tue, 18 May 2010) Log Message: ----------- Change the way widgets are highlighted: use a semi-transparent child widget over the widget to be highlighted instead of changing its palette, as some widgets like QToolButtons don't paint a background, so changing its palette had no noticeable visual effect. Modified Paths: -------------- trunk/ktutorial/ktutorial-library/src/extendedinformation/WidgetHighlighter.cpp trunk/ktutorial/ktutorial-library/src/extendedinformation/WidgetHighlighter.h trunk/ktutorial/ktutorial-library/tests/extendedinformation/WidgetHighlighterManagerTest.cpp trunk/ktutorial/ktutorial-library/tests/extendedinformation/WidgetHighlighterTest.cpp Modified: trunk/ktutorial/ktutorial-library/src/extendedinformation/WidgetHighlighter.cpp =================================================================== --- trunk/ktutorial/ktutorial-library/src/extendedinformation/WidgetHighlighter.cpp 2010-05-18 15:29:49 UTC (rev 239) +++ trunk/ktutorial/ktutorial-library/src/extendedinformation/WidgetHighlighter.cpp 2010-05-18 15:37:12 UTC (rev 240) @@ -16,10 +16,9 @@ * along with this program; If not, see <http://www.gnu.org/licenses/>. * ***************************************************************************/ -#include <QWidget> +#include <QPainter> +#include <QPaintEvent> -#include <KColorUtils> - #include "WidgetHighlighter.h" namespace extendedinformation { @@ -27,12 +26,16 @@ //public: WidgetHighlighter::WidgetHighlighter(QWidget* targetWidget): - QObject(targetWidget), + QWidget(targetWidget), mTargetWidget(targetWidget) { Q_ASSERT(targetWidget); - mOriginalPalette = targetWidget->palette(); + setAttribute(Qt::WA_TransparentForMouseEvents); + setFocusPolicy(Qt::NoFocus); + resize(mTargetWidget->size()); + mTargetWidget->installEventFilter(this); + //TODO Use QPropertyAnimation instead? Increase Qt version requirement in //CMakeLists.txt to Qt 4.6 if done. mProgress = 0; @@ -44,11 +47,20 @@ mProgressForEachTick = interval / (qreal)duration; mTimer.setInterval(interval); - connect(&mTimer, SIGNAL(timeout()), this, SLOT(update())); + connect(&mTimer, SIGNAL(timeout()), this, SLOT(updateProgress())); + + show(); } -WidgetHighlighter::~WidgetHighlighter() { - mTargetWidget->setPalette(mOriginalPalette); +bool WidgetHighlighter::eventFilter(QObject* watched, QEvent* event) { + if (watched != mTargetWidget || event->type() != QEvent::Resize) { + return false; + } + + QResizeEvent* resizeEvent = static_cast<QResizeEvent*>(event); + resize(resizeEvent->size()); + + return false; } //public slots: @@ -70,35 +82,59 @@ } } -//private: +//protected: -void WidgetHighlighter::updateColorGroup(QPalette& palette, - QPalette::ColorGroup colorGroup) { - updateColorRole(palette, colorGroup, QPalette::Window, QPalette::Highlight); - updateColorRole(palette, colorGroup, QPalette::WindowText, - QPalette::HighlightedText); - updateColorRole(palette, colorGroup, QPalette::Base, QPalette::Highlight); - updateColorRole(palette, colorGroup, QPalette::Text, - QPalette::HighlightedText); - updateColorRole(palette, colorGroup, QPalette::Button, QPalette::Highlight); - updateColorRole(palette, colorGroup, QPalette::ButtonText, - QPalette::HighlightedText); -} +void WidgetHighlighter::paintEvent(QPaintEvent* event) { + //Painting the WidgetHighlighter over its parent widget with a + //semi-transpaernt color is the best I could get. However, it has some + //flaws. For example, a QMenu does not highlight its menu button. And some + //widgets may be hardly highlighted if their background color is almost the + //same as the highlight color (like QStatusBar in Oxygen style and default + //colors). + // + //Changing the parent widget palette does not work because some widgets + //(like tool buttons) don't paint a background, only paint the text and get + //its parent widget background. Forcing the painting of the background with + //some color role does not help, as it may look ugly in some styles that use + //a gradient for the background. Changing the palette has one benefit, + //though, as it also changes the palette from the children widgets, which + //means that a QMenu would highlight its menu button. + // + //Ideally, the highlighter should lighten its parent widget but when it is + //too bright (for example, the white background of a text edit). In that + //case, the parent widget should be darkened. To do this, however, the + //WidgetHighlighter must know how its parent widget is painted. + // + //Calling QPixmap::grabWidget from the WidgetHighlighter::paintEvent is not + //good, as it triggers a recursive paint event in its parent (provided the + //WidgetHighlighter paintEvent is guarded against a recursive call, else the + //application would directly hang). Calling it from the updateProgress and + //storing the QPixmap in memory would theoretically work, but it showed some + //strange artifacts. + // + //Setting a custom QGraphicsEffect does not seem like a good idea, as Qt can + //be compiled without them, and because, as far as I know, only one effect + //can be used on a widget at a time (as making a Composite design pattern + //with something like QComposedGraphicsEffect class is pretty easy and there + //is no such class, I presume that it is not a good idea to use several + //effects on the same widget, at least for now). + // + //Anyway, I do not know how to check whether a picture is light or dark + //quickly enough to be done in a realtime animation, so... a + //semi-transparent colored child widget is good enough until someone makes + //something better ;) -void WidgetHighlighter::updateColorRole(QPalette& palette, - QPalette::ColorGroup colorGroup, - QPalette::ColorRole base, - QPalette::ColorRole tint) { - qreal amount = 0.6 * mProgress; - QColor color = KColorUtils::tint(palette.color(colorGroup, base), - palette.color(colorGroup, tint), - amount); - palette.setColor(colorGroup, base, color); + QColor color = mTargetWidget->palette().color(QPalette::Highlight); + + QPainter painter(this); + painter.setOpacity(mProgress / 2.0f); + painter.fillRect(event->rect(), color); + painter.end(); } //private slots: -void WidgetHighlighter::update(){ +void WidgetHighlighter::updateProgress(){ if (mIncreasing) { mProgress += mProgressForEachTick; mProgress = qMin<qreal>(1, mProgress); @@ -109,13 +145,8 @@ mIncreasing = mProgress == 0; } - QPalette updatedPalette = mOriginalPalette; - updateColorGroup(updatedPalette, QPalette::Active); - updateColorGroup(updatedPalette, QPalette::Inactive); - updateColorGroup(updatedPalette, QPalette::Disabled); + update(); - mTargetWidget->setPalette(updatedPalette); - if (mStopping && mProgress == 0) { mTimer.stop(); emit stopped(this); Modified: trunk/ktutorial/ktutorial-library/src/extendedinformation/WidgetHighlighter.h =================================================================== --- trunk/ktutorial/ktutorial-library/src/extendedinformation/WidgetHighlighter.h 2010-05-18 15:29:49 UTC (rev 239) +++ trunk/ktutorial/ktutorial-library/src/extendedinformation/WidgetHighlighter.h 2010-05-18 15:37:12 UTC (rev 240) @@ -19,32 +19,35 @@ #ifndef WIDGETHIGHLIGHTER_H #define WIDGETHIGHLIGHTER_H -#include <QObject> -#include <QPalette> #include <QTimer> +#include <QWidget> namespace extendedinformation { /** * Utility class to highlight a widget. - * WidgetHighlighter executes an animation that modifies the color palette of - * some widget, changing its colors from normal to highlighted and back again. + * WidgetHighlighter executes an animation that tints its parent widget, + * changing its colors from normal to highlighted and back again. * * Once started, the animation goes on indefinitely until the stop slot is - * called. The colors of the palette are set back to the original colors - * animating the change from the current color of the widget to the normal one. + * called. The parent widget recovers its original appearance animating the + * change from the current color of the widget to the normal one. * If the highlighting is started again while the stop animation is running, the * highlighting animation is started again from the current color (that is, the * stop animation is cancelled and a new highlight animation is started from * that point). * + * To tint the widget, the WidgetHighlighter paints itself over the whole parent + * widget with a semi-transparent highlight color, so the parent widget can + * still be seen but tinted with the highlight color. + * * WidgetHighlighter should not be created directly. Instead, * WidgetHighlighterManager should be used, as it takes care of deleting the * highlighter when no longer needed. * * @see WidgetHighlighterManager */ -class WidgetHighlighter: public QObject { +class WidgetHighlighter: public QWidget { Q_OBJECT public: @@ -56,10 +59,14 @@ explicit WidgetHighlighter(QWidget* targetWidget); /** - * Destroys this WidgetHighlighter. - * It restores the original palette to the target widget. + * Resizes this WidgetHighlighter to the size of its parent widget when it + * receives a resize event. + * + * @param watched The filtered object that received an event. + * @param event The event received. + * @return False, to allow the event to be handled further. */ - virtual ~WidgetHighlighter(); + virtual bool eventFilter(QObject* watched, QEvent* event); public Q_SLOTS: @@ -89,6 +96,16 @@ */ void stopped(extendedinformation::WidgetHighlighter* widgetHighlighter); +protected: + + /** + * Fills the widget with a semi-transparent highlight color. + * The degree of opacity depends on the progress of the animation. + * + * @param event The paint event. + */ + virtual void paintEvent(QPaintEvent* event); + private: /** @@ -97,11 +114,6 @@ QWidget* mTargetWidget; /** - * The original palette used by the widget. - */ - QPalette mOriginalPalette; - - /** * Timer to update the colors. */ QTimer mTimer; @@ -127,33 +139,12 @@ */ bool mStopping; - /** - * Updates the color group of the given palette based on the current - * progress. - * - * @param palette The palette to update its colors. - * @param colorGroup The color group of the palette to update. - */ - void updateColorGroup(QPalette& palette, QPalette::ColorGroup colorGroup); - - /** - * Updates the color role "base" tinting it with the color role "tint". - * How much the base color role is tinted depends on the current progress. - * - * @param palette The palette to update its colors. - * @param colorGroup The color group of the palette to update. - * @param base The color role to update. - * @param tint The color role to tint the base color role with. - */ - void updateColorRole(QPalette& palette, QPalette::ColorGroup colorGroup, - QPalette::ColorRole from, QPalette::ColorRole to); - private Q_SLOTS: /** - * Updates the palette of the target widget based on the animation progress. + * Updates the animation progress. */ - void update(); + void updateProgress(); }; Modified: trunk/ktutorial/ktutorial-library/tests/extendedinformation/WidgetHighlighterManagerTest.cpp =================================================================== --- trunk/ktutorial/ktutorial-library/tests/extendedinformation/WidgetHighlighterManagerTest.cpp 2010-05-18 15:29:49 UTC (rev 239) +++ trunk/ktutorial/ktutorial-library/tests/extendedinformation/WidgetHighlighterManagerTest.cpp 2010-05-18 15:37:12 UTC (rev 240) @@ -21,7 +21,11 @@ #include <QWidget> #include "WidgetHighlighterManager.h" +#define protected public +#define private public #include "WidgetHighlighter.h" +#undef private +#undef protected namespace extendedinformation { @@ -39,6 +43,10 @@ void testDeleteWidgetWhileHighlighting(); +private: + + WidgetHighlighter* highlighterOf(const QWidget* widget) const; + }; void WidgetHighlighterManagerTest::testSelf() { @@ -52,7 +60,6 @@ void WidgetHighlighterManagerTest::testHighlight() { QWidget widget; - QPalette palette = widget.palette(); WidgetHighlighterManager* manager = WidgetHighlighterManager::self(); manager->highlight(&widget); @@ -61,8 +68,8 @@ QTest::qWait(100); QCOMPARE(widget.findChildren<WidgetHighlighter*>().count(), 1); - QVERIFY(widget.findChild<WidgetHighlighter*>()); - QVERIFY(widget.palette() != palette); + QVERIFY(highlighterOf(&widget)); + QVERIFY(highlighterOf(&widget)->mProgress > 0); } void WidgetHighlighterManagerTest::testHighlightWidgetAlreadyHighlighted() { @@ -71,12 +78,12 @@ manager->highlight(&widget); - WidgetHighlighter* highlighter = widget.findChild<WidgetHighlighter*>(); + WidgetHighlighter* highlighter = highlighterOf(&widget); manager->highlight(&widget); QCOMPARE(widget.findChildren<WidgetHighlighter*>().count(), 1); - QCOMPARE(widget.findChild<WidgetHighlighter*>(), highlighter); + QCOMPARE(highlighterOf(&widget), highlighter); } void WidgetHighlighterManagerTest::testHighlightAfterStopHighlighting() { @@ -85,28 +92,25 @@ manager->highlight(&widget); - QPointer<WidgetHighlighter> highlighter = - widget.findChild<WidgetHighlighter*>(); + QPointer<WidgetHighlighter> highlighter = highlighterOf(&widget); QVERIFY(highlighter); manager->stopHighlighting(&widget); QVERIFY(!highlighter); - QPalette palette = widget.palette(); manager->highlight(&widget); //Give it some time to update QTest::qWait(100); QCOMPARE(widget.findChildren<WidgetHighlighter*>().count(), 1); - QVERIFY(widget.findChild<WidgetHighlighter*>()); - QVERIFY(widget.palette() != palette); + QVERIFY(highlighterOf(&widget)); + QVERIFY(highlighterOf(&widget)->mProgress > 0); } void WidgetHighlighterManagerTest::testStopHighlighting() { QWidget widget; - QPalette palette = widget.palette(); WidgetHighlighterManager* manager = WidgetHighlighterManager::self(); manager->highlight(&widget); @@ -120,7 +124,6 @@ QTest::qWait(200); QCOMPARE(widget.findChildren<WidgetHighlighter*>().count(), 0); - QVERIFY(widget.palette() == palette); } void WidgetHighlighterManagerTest::testDeleteWidgetWhileHighlighting() { @@ -137,8 +140,20 @@ //No explicit check is made, if it does not crash everything is fine ;) } +WidgetHighlighter* WidgetHighlighterManagerTest::highlighterOf( + const QWidget* widget) const { + WidgetHighlighter* highlighter = widget->findChild<WidgetHighlighter*>(); + + //Ensure that it is a direct child + if (widget->children().contains(highlighter)) { + return highlighter; + } + + return 0; } +} + QTEST_MAIN(extendedinformation::WidgetHighlighterManagerTest) #include "WidgetHighlighterManagerTest.moc" Modified: trunk/ktutorial/ktutorial-library/tests/extendedinformation/WidgetHighlighterTest.cpp =================================================================== --- trunk/ktutorial/ktutorial-library/tests/extendedinformation/WidgetHighlighterTest.cpp 2010-05-18 15:29:49 UTC (rev 239) +++ trunk/ktutorial/ktutorial-library/tests/extendedinformation/WidgetHighlighterTest.cpp 2010-05-18 15:37:12 UTC (rev 240) @@ -39,47 +39,33 @@ void testConstructor(); - void testDestructor(); - void testStart(); void testStartAlreadyStarted(); void testStartWhileStopAnimationIsRunning(); - void testUpdate(); - void testUpdateWhenProgressIsAlmostOne(); - void testUpdateWhenProgressIsAlmostZero(); + void testUpdateProgress(); + void testUpdateProgressWhenProgressIsAlmostOne(); + void testUpdateProgressWhenProgressIsAlmostZero(); void testStop(); void testStopAfterStopAnimationEnded(); void testStopImmediatelyAfterStart(); + void testParentWidgetResized(); + }; void WidgetHighlighterTest::testConstructor() { QWidget widget; - widget.setPalette(Qt::blue); - QApplication::setPalette(Qt::green); WidgetHighlighter* highlighter = new WidgetHighlighter(&widget); QCOMPARE(highlighter->parent(), &widget); - QVERIFY(highlighter->mOriginalPalette != QApplication::palette()); - QVERIFY(highlighter->mOriginalPalette == widget.palette()); + QCOMPARE(highlighter->size(), widget.size()); + QCOMPARE(highlighter->mProgress, 0.0); } -void WidgetHighlighterTest::testDestructor() { - QWidget widget; - QPalette palette = widget.palette(); - WidgetHighlighter* highlighter = new WidgetHighlighter(&widget); - - widget.setPalette(QPalette(Qt::green)); - delete highlighter; - - QVERIFY(widget.palette() == palette); -} - void WidgetHighlighterTest::testStart() { QWidget widget; - QPalette palette = widget.palette(); WidgetHighlighter* highlighter = new WidgetHighlighter(&widget); highlighter->start(); @@ -87,12 +73,11 @@ //Give it some time to update QTest::qWait(100); - QVERIFY(widget.palette() != palette); + QVERIFY(highlighter->mProgress > 0); } void WidgetHighlighterTest::testStartAlreadyStarted() { QWidget widget; - QPalette palette = widget.palette(); WidgetHighlighter* highlighter = new WidgetHighlighter(&widget); highlighter->start(); @@ -105,12 +90,10 @@ //Ensure that progress is not reseted QCOMPARE(highlighter->mProgress, previousProgress); - QVERIFY(widget.palette() != palette); } void WidgetHighlighterTest::testStartWhileStopAnimationIsRunning() { QWidget widget; - QPalette palette = widget.palette(); WidgetHighlighter* highlighter = new WidgetHighlighter(&widget); highlighter->mProgress = 0.5; @@ -132,82 +115,59 @@ QVERIFY(highlighter->mProgress > 0.5); QVERIFY(highlighter->mIncreasing); QVERIFY(!highlighter->mStopping); - QVERIFY(widget.palette() != palette); } -void WidgetHighlighterTest::testUpdate() { +void WidgetHighlighterTest::testUpdateProgress() { QWidget widget; WidgetHighlighter* highlighter = new WidgetHighlighter(&widget); highlighter->mTimer.stop(); - QPalette palette = widget.palette(); int previousProgress = highlighter->mProgress; - highlighter->update(); + highlighter->updateProgress(); QCOMPARE(highlighter->mProgress, previousProgress + highlighter->mProgressForEachTick); - QVERIFY(widget.palette().color(QPalette::Window) != - palette.color(QPalette::Window)); - QVERIFY(widget.palette().color(QPalette::WindowText) != - palette.color(QPalette::WindowText)); - QVERIFY(widget.palette().color(QPalette::Base) != - palette.color(QPalette::Base)); - QVERIFY(widget.palette().color(QPalette::Text) != - palette.color(QPalette::Text)); - QVERIFY(widget.palette().color(QPalette::Button) != - palette.color(QPalette::Button)); - QVERIFY(widget.palette().color(QPalette::ButtonText) != - palette.color(QPalette::ButtonText)); } -void WidgetHighlighterTest::testUpdateWhenProgressIsAlmostOne() { +void WidgetHighlighterTest::testUpdateProgressWhenProgressIsAlmostOne() { QWidget widget; WidgetHighlighter* highlighter = new WidgetHighlighter(&widget); highlighter->mTimer.stop(); highlighter->mProgress = 0.995; highlighter->mIncreasing = true; - highlighter->update(); + highlighter->updateProgress(); - //Don't check palette changes here, as with such a small update it could - //have been left unchanged QCOMPARE(highlighter->mProgress, 1.0); QCOMPARE(highlighter->mIncreasing, false); - QPalette palette = widget.palette(); - highlighter->update(); + highlighter->updateProgress(); QCOMPARE(highlighter->mProgress, 1 - highlighter->mProgressForEachTick); QCOMPARE(highlighter->mIncreasing, false); - QVERIFY(widget.palette() != palette); } -void WidgetHighlighterTest::testUpdateWhenProgressIsAlmostZero() { +void WidgetHighlighterTest::testUpdateProgressWhenProgressIsAlmostZero() { QWidget widget; WidgetHighlighter* highlighter = new WidgetHighlighter(&widget); highlighter->mTimer.stop(); highlighter->mProgress = 0.005; highlighter->mIncreasing = false; - highlighter->update(); + highlighter->updateProgress(); - //Don't check palette changes here, as with such a small update it could - //have been left unchanged QCOMPARE(highlighter->mProgress, 0.0); QCOMPARE(highlighter->mIncreasing, true); - QPalette palette = widget.palette(); - highlighter->update(); + highlighter->updateProgress(); QCOMPARE(highlighter->mProgress, highlighter->mProgressForEachTick); QCOMPARE(highlighter->mIncreasing, true); - QVERIFY(widget.palette() != palette); } void WidgetHighlighterTest::testStop() { QWidget widget; - QPalette palette = widget.palette(); WidgetHighlighter* highlighter = new WidgetHighlighter(&widget); highlighter->mProgress = 0.5; @@ -225,12 +185,10 @@ QVERIFY(highlighter->mProgress < 0.5); QVERIFY(!highlighter->mIncreasing); QVERIFY(highlighter->mStopping); - QVERIFY(widget.palette() != palette); } void WidgetHighlighterTest::testStopAfterStopAnimationEnded() { QWidget widget; - QPalette palette = widget.palette(); WidgetHighlighter* highlighter = new WidgetHighlighter(&widget); highlighter->start(); @@ -252,7 +210,7 @@ QTest::qWait(200); QVERIFY(!highlighter->mTimer.isActive()); - QVERIFY(widget.palette() == palette); + QCOMPARE(highlighter->mProgress, 0.0); QCOMPARE(stoppedSpy.count(), 1); QVariant argument = stoppedSpy.at(0).at(0); QCOMPARE(argument.userType(), widgetHighlighterStarType); @@ -262,7 +220,6 @@ void WidgetHighlighterTest::testStopImmediatelyAfterStart() { QWidget widget; - QPalette palette = widget.palette(); WidgetHighlighter* highlighter = new WidgetHighlighter(&widget); highlighter->start(); @@ -278,7 +235,7 @@ highlighter->stop(); QVERIFY(!highlighter->mTimer.isActive()); - QVERIFY(widget.palette() == palette); + QCOMPARE(highlighter->mProgress, 0.0); QCOMPARE(stoppedSpy.count(), 1); QVariant argument = stoppedSpy.at(0).at(0); QCOMPARE(argument.userType(), widgetHighlighterStarType); @@ -286,8 +243,23 @@ highlighter); } +void WidgetHighlighterTest::testParentWidgetResized() { + QWidget widget; + WidgetHighlighter* highlighter = new WidgetHighlighter(&widget); + + //The widget must be visible to ensure that it receives the resize event + widget.show(); + + //Resize twice to prevent a false test if the first size was the current + //widget size + widget.resize(4, 4); + widget.resize(108, 108); + + QCOMPARE(highlighter->size(), widget.size()); } +} + QTEST_MAIN(extendedinformation::WidgetHighlighterTest) #include "WidgetHighlighterTest.moc" This was sent by the SourceForge.net collaborative development platform, the world's largest Open Source development site. |
From: <dan...@us...> - 2010-05-18 15:29:56
|
Revision: 239 http://ktutorial.svn.sourceforge.net/ktutorial/?rev=239&view=rev Author: danxuliu Date: 2010-05-18 15:29:49 +0000 (Tue, 18 May 2010) Log Message: ----------- Fix memory leak making TutorialKxmlGuiClient a subclass of QObject, so it is automatically destroyed when the KXmlGuiWindow is destroyed. Modified Paths: -------------- trunk/ktutorial/ktutorial-library/src/KTutorial.cpp Modified: trunk/ktutorial/ktutorial-library/src/KTutorial.cpp =================================================================== --- trunk/ktutorial/ktutorial-library/src/KTutorial.cpp 2010-05-11 03:38:55 UTC (rev 238) +++ trunk/ktutorial/ktutorial-library/src/KTutorial.cpp 2010-05-18 15:29:49 UTC (rev 239) @@ -40,9 +40,15 @@ //public: -class TutorialKXmlGuiClient: public KXMLGUIClient { +//It inherits from QObject to be automatically destroyed when the parent +//KXmlGuiWindow is destroyed. It uses the same strategy as +//KDEPrivate::ToolBarHandler. +//Usually I do not like multiple inheritance, but it comes very handy here :) +class TutorialKXmlGuiClient: public QObject, public KXMLGUIClient { +Q_OBJECT public: - TutorialKXmlGuiClient(KXMLGUIClient* parent): KXMLGUIClient(parent) { + TutorialKXmlGuiClient(KXmlGuiWindow* parent): + QObject(parent), KXMLGUIClient(parent) { setComponentData(KComponentData("ktutorial")); setXMLFile("ktutorialui.rc"); } @@ -112,3 +118,6 @@ void KTutorial::enableTutorialsAction() { mTutorialsAction->setEnabled(true); } + +#include "moc_KTutorial.cpp" +#include "KTutorial.moc" This was sent by the SourceForge.net collaborative development platform, the world's largest Open Source development site. |