Thread: [Ktutorial-commits] SF.net SVN: ktutorial:[253] trunk/ktutorial/ktutorial-library (Page 2)
Status: Alpha
Brought to you by:
danxuliu
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-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-30 15:38:30
|
Revision: 267 http://ktutorial.svn.sourceforge.net/ktutorial/?rev=267&view=rev Author: danxuliu Date: 2010-09-30 15:38:20 +0000 (Thu, 30 Sep 2010) Log Message: ----------- Fix waiting for a signal emitted by a null object. It didn't crash before, but now it doesn't even try to connect the signal and warns when this happens, like WaitForEvent does. Modified Paths: -------------- trunk/ktutorial/ktutorial-library/src/WaitForSignal.cpp trunk/ktutorial/ktutorial-library/tests/WaitForSignalTest.cpp Modified: trunk/ktutorial/ktutorial-library/src/WaitForSignal.cpp =================================================================== --- trunk/ktutorial/ktutorial-library/src/WaitForSignal.cpp 2010-09-30 15:35:32 UTC (rev 266) +++ trunk/ktutorial/ktutorial-library/src/WaitForSignal.cpp 2010-09-30 15:38:20 UTC (rev 267) @@ -1,5 +1,5 @@ /*************************************************************************** - * Copyright (C) 2008 by Daniel Calviño Sánchez * + * Copyright (C) 2008-2010 by Daniel Calviño Sánchez * * dan...@gm... * * * * This program is free software; you can redistribute it and/or modify * @@ -18,6 +18,8 @@ #include "WaitForSignal.h" +#include <KDebug> + //public: WaitForSignal::WaitForSignal(): WaitFor(), @@ -30,6 +32,11 @@ } void WaitForSignal::setSignal(QObject* sender, const QString& signal) { + if (!sender) { + kWarning() << "The object that emits the signal to wait for is null!"; + return; + } + QString signalName = signal; if (!signalName.startsWith('2')) { signalName = QString("2%1").arg(signal); Modified: trunk/ktutorial/ktutorial-library/tests/WaitForSignalTest.cpp =================================================================== --- trunk/ktutorial/ktutorial-library/tests/WaitForSignalTest.cpp 2010-09-30 15:35:32 UTC (rev 266) +++ trunk/ktutorial/ktutorial-library/tests/WaitForSignalTest.cpp 2010-09-30 15:38:20 UTC (rev 267) @@ -1,5 +1,5 @@ /*************************************************************************** - * Copyright (C) 2009 by Daniel Calviño Sánchez * + * Copyright (C) 2009-2010 by Daniel Calviño Sánchez * * dan...@gm... * * * * This program is free software; you can redistribute it and/or modify * @@ -51,8 +51,10 @@ void testConstructor(); void testConstructorWithoutSignalMacro(); + void testConstructorWithNullObject(); void testConstructorDefault(); void testConstructorDefaultWithoutSignalMacro(); + void testConstructorDefaultWithNullObject(); void testSetActive(); @@ -77,6 +79,13 @@ QCOMPARE(mDummySignalConnectionCount, 1); } +void WaitForSignalTest::testConstructorWithNullObject() { + WaitForSignal waitForSignal(0, SIGNAL(dummySignal())); + + QVERIFY(!waitForSignal.isActive()); + QVERIFY(!waitForSignal.conditionMet()); +} + void WaitForSignalTest::testConstructorDefault() { WaitForSignal waitForSignal; waitForSignal.setSignal(this, SIGNAL(dummySignal())); @@ -95,6 +104,14 @@ QCOMPARE(mDummySignalConnectionCount, 1); } +void WaitForSignalTest::testConstructorDefaultWithNullObject() { + WaitForSignal waitForSignal; + waitForSignal.setSignal(0, SIGNAL(dummySignal())); + + QVERIFY(!waitForSignal.isActive()); + QVERIFY(!waitForSignal.conditionMet()); +} + void WaitForSignalTest::testSetActive() { WaitForSignal waitForSignal(this, SIGNAL(dummySignal())); waitForSignal.mConditionMet = true; This was sent by the SourceForge.net collaborative development platform, the world's largest Open Source development site. |
From: <dan...@us...> - 2011-03-08 02:59:44
|
Revision: 290 http://ktutorial.svn.sourceforge.net/ktutorial/?rev=290&view=rev Author: danxuliu Date: 2011-03-08 02:59:37 +0000 (Tue, 08 Mar 2011) Log Message: ----------- Add support for object paths instead of just object names in KTutorial::findObject(QString). Now the ancestor names can be included when finding an object to differentiate between several objects with the same name. Modified Paths: -------------- trunk/ktutorial/ktutorial-library/src/KTutorial.h trunk/ktutorial/ktutorial-library/tests/CMakeLists.txt Added Paths: ----------- trunk/ktutorial/ktutorial-library/tests/KTutorialTest.cpp Modified: trunk/ktutorial/ktutorial-library/src/KTutorial.h =================================================================== --- trunk/ktutorial/ktutorial-library/src/KTutorial.h 2011-03-08 02:47:15 UTC (rev 289) +++ trunk/ktutorial/ktutorial-library/src/KTutorial.h 2011-03-08 02:59:37 UTC (rev 290) @@ -1,5 +1,5 @@ /*************************************************************************** - * Copyright (C) 2008-2010 by Daniel Calviño Sánchez * + * Copyright (C) 2008-2011 by Daniel Calviño Sánchez * * dan...@gm... * * * * This program is free software; you can redistribute it and/or modify * @@ -123,6 +123,15 @@ * Returns the object with the specified name, if any. * Objects are searched in the children of the main window of the * application. + * When the name of the desired object is not unique the name of some + * ancestor must be included. Ancestor names are separated using a "/". That + * is, "Ancestor name/The object with a repeated name". As many ancestor + * names as desired can be included, not just one. + * The name of the ancestors does not need to be unique either; what has to + * be unique is the full path to the object to find. For example, "Ancestor + * name not unique/The object to find" is valid if, among all the objects + * called "Ancestor name not unique", there is only one that has a + * descendant called "The object to find". * * @param name The name of the object to find. * @return The object with the specified name, or null if there is none. @@ -131,7 +140,7 @@ */ template <typename T> T findObject(const QString& name) const { - return mParent->findChild<T>(name); + return findObject<T>(name, mParent); } private: @@ -167,6 +176,44 @@ mParent = 0; } + /** + * Returns the object with the specified name that is descendant of the + * given parent, if any. + * The name of the object can contain ancestor names separated by "/". The + * first object that matches the whole path is returned (note that ancestor + * are not necessarily direct parents). + * + * @param name The name of the object to find. + * @param parent The parent to look the object in. + * @return The object with the specified name, or null if there is none. + */ + template <typename T> + T findObject(const QString& name, const QObject* ancestor) const { + if (name.isEmpty() || ancestor == 0) { + return T(); + } + + if (name.indexOf('/') == -1) { + return ancestor->findChild<T>(name); + } + + QRegExp slashPattern("/+"); + QString ancestorName = name.left(name.indexOf(slashPattern)); + QString descendantName = name.mid(ancestorName.length() + + slashPattern.matchedLength()); + + QList<QObject*> namedAncestors = + ancestor->findChildren<QObject*>(ancestorName); + foreach (QObject* namedAncestor, namedAncestors) { + T object = findObject<T>(descendantName, namedAncestor); + if (object) { + return object; + } + } + + return 0; + } + private slots: /** Modified: trunk/ktutorial/ktutorial-library/tests/CMakeLists.txt =================================================================== --- trunk/ktutorial/ktutorial-library/tests/CMakeLists.txt 2011-03-08 02:47:15 UTC (rev 289) +++ trunk/ktutorial/ktutorial-library/tests/CMakeLists.txt 2011-03-08 02:59:37 UTC (rev 290) @@ -26,6 +26,7 @@ ENDMACRO(UNIT_TESTS) unit_tests( + KTutorial Option Step Tutorial @@ -48,6 +49,7 @@ ENDMACRO(MEM_TESTS) mem_tests( + KTutorial Option Step Tutorial Added: trunk/ktutorial/ktutorial-library/tests/KTutorialTest.cpp =================================================================== --- trunk/ktutorial/ktutorial-library/tests/KTutorialTest.cpp (rev 0) +++ trunk/ktutorial/ktutorial-library/tests/KTutorialTest.cpp 2011-03-08 02:59:37 UTC (rev 290) @@ -0,0 +1,185 @@ +/*************************************************************************** + * Copyright (C) 2011 by Daniel Calviño Sánchez * + * dan...@gm... * + * * + * This program is free software; you can redistribute it and/or modify * + * it under the terms of the GNU General Public License as published by * + * the Free Software Foundation; either version 3 of the License, or * + * (at your option) any later version. * + * * + * This program is distributed in the hope that it will be useful, * + * but WITHOUT ANY WARRANTY; without even the implied warranty of * + * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the * + * GNU General Public License for more details. * + * * + * You should have received a copy of the GNU General Public License * + * along with this program; If not, see <http://www.gnu.org/licenses/>. * + ***************************************************************************/ + +#include <QtTest> + +#include <QAction> + +#include "KTutorial.h" + +class KTutorialTest: public QObject { +Q_OBJECT + +private slots: + + void initTestCase(); + void cleanupTestCase(); + + void testFindObjectSingleName(); + void testFindObjectSingleNameUnknown(); + void testFindObjectComplexNameDirectChild(); + void testFindObjectComplexNameNestedChild(); + void testFindObjectComplexNameAncestorNameNotUnique(); + void testFindObjectComplexNameUnknownParent(); + void testFindObjectEmptyName(); + void testFindObjectSingleSlash(); + void testFindObjectSlashEndedName(); + void testFindObjectSeveralSlashes(); + +private: + + KXmlGuiWindow* mMainWindow; + QObject* mObject1_1_1; + QAction* mAction1_1_2; + QObject* mObject1_2_1; + QObject* mObject2_1_1; + QObject* mObject2_1_2; + QAction* mAction2_1_3; + QAction* mAction2_1_4; + QObject* mObject3_1_1; + QObject* mObject3_2_1_1; + QAction* mAction3_3_1_1; + + void assertFindObject(const QString& objectName, QObject* object) const; + void assertFindAction(const QString& objectName, QAction* widget) const; + +}; + +void KTutorialTest::initTestCase() { + mMainWindow = new KXmlGuiWindow(); + KTutorial::self()->setup(mMainWindow); + + QObject* grandParent1 = new QObject(mMainWindow); + grandParent1->setObjectName("Grand parent1"); + QObject* parent1_1 = new QObject(grandParent1); + parent1_1->setObjectName("Parent1"); + mObject1_1_1 = new QObject(parent1_1); + mObject1_1_1->setObjectName("The object"); + mAction1_1_2 = new QAction(parent1_1); + mAction1_1_2->setObjectName("The widget"); + + QObject* parent1_2 = new QObject(grandParent1); + parent1_2->setObjectName("Parent2"); + mObject1_2_1 = new QObject(parent1_2); + mObject1_2_1->setObjectName("The object"); + + QObject* grandParent2 = new QObject(mMainWindow); + grandParent2->setObjectName("Grand parent2"); + QObject* parent2_1 = new QObject(grandParent2); + parent2_1->setObjectName("Parent1"); + mObject2_1_1 = new QObject(parent2_1); + mObject2_1_1->setObjectName("The object"); + mObject2_1_2 = new QObject(parent2_1); + mObject2_1_2->setObjectName("Another object"); + mAction2_1_3 = new QAction(parent2_1); + mAction2_1_3->setObjectName("The widget"); + mAction2_1_4 = new QAction(parent2_1); + mAction2_1_4->setObjectName("Another widget"); + + QObject* grandParent3 = new QObject(mMainWindow); + grandParent3->setObjectName("Grand parent3"); + QObject* parent3_1 = new QObject(grandParent3); + parent3_1->setObjectName("Parent1"); + mObject3_1_1 = new QObject(parent3_1); + mObject3_1_1->setObjectName("The object"); + + QObject* parent3_2 = new QObject(grandParent3); + parent3_2->setObjectName("Nested parent"); + QObject* parent3_2_1 = new QObject(parent3_2); + mObject3_2_1_1 = new QObject(parent3_2_1); + mObject3_2_1_1->setObjectName("Another object"); + + QTimer* parent3_3 = new QTimer(grandParent3); + parent3_3->setObjectName("Nested timer"); + QTimer* parent3_3_1 = new QTimer(parent3_3); + mAction3_3_1_1 = new QAction(parent3_3_1); + mAction3_3_1_1->setObjectName("Another widget"); +} + +void KTutorialTest::cleanupTestCase() { + delete mMainWindow; +} + +void KTutorialTest::testFindObjectSingleName() { + assertFindObject("The object", mObject1_1_1); +} + +void KTutorialTest::testFindObjectSingleNameUnknown() { + assertFindObject("Unknown object", 0); +} + +void KTutorialTest::testFindObjectComplexNameDirectChild() { + assertFindObject("Grand parent1/Parent1/The object", mObject1_1_1); + assertFindObject("Grand parent1/Parent2/The object", mObject1_2_1); + assertFindObject("Grand parent2/Parent1/The object", mObject2_1_1); + + assertFindAction("Grand parent1/Parent1/The widget", mAction1_1_2); + assertFindAction("Grand parent2/Parent1/The widget", mAction2_1_3); +} + +void KTutorialTest::testFindObjectComplexNameNestedChild() { + assertFindObject("Grand parent2/The object", mObject2_1_1); + assertFindObject("Nested parent/Another object", mObject3_2_1_1); + + assertFindAction("Grand parent2/The widget", mAction2_1_3); + assertFindAction("Nested timer/Another widget", mAction3_3_1_1); +} + +void KTutorialTest::testFindObjectComplexNameAncestorNameNotUnique() { + //The ancestor name is not unique, but the full path is + assertFindObject("Parent1/Another object", mObject2_1_2); + + assertFindAction("Parent1/Another widget", mAction2_1_4); +} + +void KTutorialTest::testFindObjectComplexNameUnknownParent() { + assertFindObject("Unknown grand parent/The object", 0); + assertFindObject("Grand parent1/Unknown parent/The object", 0); +} + +void KTutorialTest::testFindObjectEmptyName() { + assertFindObject("", 0); +} + +void KTutorialTest::testFindObjectSingleSlash() { + assertFindObject("/", 0); +} + +void KTutorialTest::testFindObjectSlashEndedName() { + assertFindObject("Parent/", 0); +} + +void KTutorialTest::testFindObjectSeveralSlashes() { + assertFindObject("Parent1///The object", mObject1_1_1); +} + +/////////////////////////////////Helpers//////////////////////////////////////// + +void KTutorialTest::assertFindObject(const QString& objectName, + QObject* object) const { + QCOMPARE(KTutorial::self()->findObject<QObject*>(objectName), object); +} + +void KTutorialTest::assertFindAction(const QString& objectName, + QAction* widget) const { + QCOMPARE(KTutorial::self()->findObject<QAction*>(objectName), widget); +} + +QTEST_MAIN(KTutorialTest) + +#include "KTutorialTest.moc" Property changes on: trunk/ktutorial/ktutorial-library/tests/KTutorialTest.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...> - 2011-05-06 12:44:42
|
Revision: 302 http://ktutorial.svn.sourceforge.net/ktutorial/?rev=302&view=rev Author: danxuliu Date: 2011-05-06 12:44:36 +0000 (Fri, 06 May 2011) Log Message: ----------- Fix not providing information of a class if it is the class of a widget that was registered while it was being constructed. By the way, I forgot to say it in the commit 300, and now it doesn't really do much sense, but I can't resist... "THIS... IS... KTUTORIAL!!!" :P Modified Paths: -------------- trunk/ktutorial/ktutorial-library/src/editorsupport/ObjectRegister.cpp trunk/ktutorial/ktutorial-library/src/editorsupport/ObjectRegister.h trunk/ktutorial/ktutorial-library/src/editorsupport/ObjectRegisterAdaptor.cpp trunk/ktutorial/ktutorial-library/tests/editorsupport/EditorSupportTest.cpp Modified: trunk/ktutorial/ktutorial-library/src/editorsupport/ObjectRegister.cpp =================================================================== --- trunk/ktutorial/ktutorial-library/src/editorsupport/ObjectRegister.cpp 2011-05-05 14:39:15 UTC (rev 301) +++ trunk/ktutorial/ktutorial-library/src/editorsupport/ObjectRegister.cpp 2011-05-06 12:44:36 UTC (rev 302) @@ -1,5 +1,5 @@ /*************************************************************************** - * Copyright (C) 2010 by Daniel Calviño Sánchez * + * Copyright (C) 2010-2011 by Daniel Calviño Sánchez * * dan...@gm... * * * * This program is free software; you can redistribute it and/or modify * @@ -58,8 +58,6 @@ mRegisteredMetaObjects.clear(); } -//private: - void ObjectRegister::registerMetaObject(const QMetaObject* metaObject) { if (mRegisteredMetaObjects.contains(metaObject->className())) { return; Modified: trunk/ktutorial/ktutorial-library/src/editorsupport/ObjectRegister.h =================================================================== --- trunk/ktutorial/ktutorial-library/src/editorsupport/ObjectRegister.h 2011-05-05 14:39:15 UTC (rev 301) +++ trunk/ktutorial/ktutorial-library/src/editorsupport/ObjectRegister.h 2011-05-06 12:44:36 UTC (rev 302) @@ -1,5 +1,5 @@ /*************************************************************************** - * Copyright (C) 2010 by Daniel Calviño Sánchez * + * Copyright (C) 2010-2011 by Daniel Calviño Sánchez * * dan...@gm... * * * * This program is free software; you can redistribute it and/or modify * @@ -78,6 +78,13 @@ */ void clear(); + /** + * Registers a meta object and the meta objects of all its super classes. + * + * @param metaObject The meta object to register. + */ + void registerMetaObject(const QMetaObject* metaObject); + private: /** @@ -100,13 +107,6 @@ */ QHash<QString, const QMetaObject*> mRegisteredMetaObjects; - /** - * Registers a meta object and the meta objects of all its super classes. - * - * @param metaObject The meta object to register. - */ - void registerMetaObject(const QMetaObject* metaObject); - private Q_SLOTS: /** Modified: trunk/ktutorial/ktutorial-library/src/editorsupport/ObjectRegisterAdaptor.cpp =================================================================== --- trunk/ktutorial/ktutorial-library/src/editorsupport/ObjectRegisterAdaptor.cpp 2011-05-05 14:39:15 UTC (rev 301) +++ trunk/ktutorial/ktutorial-library/src/editorsupport/ObjectRegisterAdaptor.cpp 2011-05-06 12:44:36 UTC (rev 302) @@ -1,5 +1,5 @@ /*************************************************************************** - * Copyright (C) 2010 by Daniel Calviño Sánchez * + * Copyright (C) 2010-2011 by Daniel Calviño Sánchez * * dan...@gm... * * * * This program is free software; you can redistribute it and/or modify * @@ -45,6 +45,16 @@ return ""; } + //Ensure that the meta object is registered. If a widget is registered while + //it is being constructed (if the event spy is enabled, it will register the + //object when it sets its parent, as it sends a ParentChanged event) its + //real class will not be registered, only QWidget, as at that moment the + //object will not be fully constructed and the pointer to the meta object + //will not be set to the real class yet. + //This does not seem to happen with plain objects; only widgets send that + //ParentChanged event in their constructor. + mObjectRegister->registerMetaObject(object->metaObject()); + return object->metaObject()->className(); } Modified: trunk/ktutorial/ktutorial-library/tests/editorsupport/EditorSupportTest.cpp =================================================================== --- trunk/ktutorial/ktutorial-library/tests/editorsupport/EditorSupportTest.cpp 2011-05-05 14:39:15 UTC (rev 301) +++ trunk/ktutorial/ktutorial-library/tests/editorsupport/EditorSupportTest.cpp 2011-05-06 12:44:36 UTC (rev 302) @@ -1,5 +1,5 @@ /*************************************************************************** - * Copyright (C) 2010 by Daniel Calviño Sánchez * + * Copyright (C) 2010-2011 by Daniel Calviño Sánchez * * dan...@gm... * * * * This program is free software; you can redistribute it and/or modify * @@ -42,6 +42,20 @@ //Tutorial* must be declared as a metatype to be used in qvariant_cast Q_DECLARE_METATYPE(Tutorial*); +class SubClassWidget: public QWidget { +Q_OBJECT +public: + SubClassWidget(QWidget* parent = 0): QWidget(parent) { + } +}; + +class SubSubClassWidget: public SubClassWidget { +Q_OBJECT +public: + SubSubClassWidget(QWidget* parent = 0): SubClassWidget(parent) { + } +}; + namespace editorsupport { class EditorSupportTest: public QObject { @@ -75,6 +89,8 @@ void testTestScriptedTutorial(); void testTestScriptedTutorialWithInvalidTutorial(); + void testObjectRegisterWhenEventSpyNotifiesEventBeforeEndingConstructor(); + private: QStringList mEventTypes; @@ -293,8 +309,52 @@ QCOMPARE(startedSpy.count(), 0); } +//Not really a unit test, but sort of an integration test for a strange bug. +void EditorSupportTest:: + testObjectRegisterWhenEventSpyNotifiesEventBeforeEndingConstructor() { + QDBusConnection bus = QDBusConnection::sessionBus(); + QVERIFY(bus.isConnected()); + + EditorSupport editorSupport; + QWidget mainWidget; + + editorSupport.setup(&mainWidget); + editorSupport.enableEventSpy(); + + SubSubClassWidget* childWidget = new SubSubClassWidget(&mainWidget); + + QCOMPARE(childWidget->metaObject()->className(), + "SubSubClassWidget"); + QCOMPARE(childWidget->metaObject()->superClass()->className(), + "SubClassWidget"); + QCOMPARE(childWidget->metaObject()->superClass()->superClass()->className(), + "QWidget"); + + //childWidget gets registered by a ParentChange event. However, that event + //is sent by QWidget constructor itself. The object is not fully + //constructed, so SubClassWidget and SubSubClassWidget are not registered. + ObjectRegister* objectRegister = editorSupport.mObjectRegister; + QCOMPARE(objectRegister->objectForId(1), &mainWidget); + QCOMPARE(objectRegister->objectForId(2), childWidget); + QVERIFY(objectRegister->metaObjectForClassName("QWidget")); + QVERIFY(!objectRegister->metaObjectForClassName("SubClassWidget")); + QVERIFY(!objectRegister->metaObjectForClassName("SubSubClassWidget")); + + //From the outside (the caller DBus client), the only way to get an object + //class is asking the ObjectRegister adaptor about it. So if a class is + //registered after its name was returned by the ObjectRegister adaptor, when + //the client asks for information about that class the register will be able + //to provide it. + ObjectRegisterAdaptor* objectRegisterAdaptor = + objectRegister->findChild<ObjectRegisterAdaptor*>(); + + QCOMPARE(objectRegisterAdaptor->className(2), QString("SubSubClassWidget")); + QVERIFY(objectRegister->metaObjectForClassName("SubClassWidget")); + QVERIFY(objectRegister->metaObjectForClassName("SubSubClassWidget")); } +} + QTEST_MAIN(editorsupport::EditorSupportTest) #include "EditorSupportTest.moc" This was sent by the SourceForge.net collaborative development platform, the world's largest Open Source development site. |
From: <dan...@us...> - 2011-05-08 15:16:18
|
Revision: 304 http://ktutorial.svn.sourceforge.net/ktutorial/?rev=304&view=rev Author: danxuliu Date: 2011-05-08 15:16:11 +0000 (Sun, 08 May 2011) Log Message: ----------- Modify the internal behavior of Tutorial when changing to the next step. Until now, when nextStep(Step*) was called it just changed to the next step, which could cause recursive changes and wrong results when called from the setup method of a Step. Now, the steps to change to are queued and the changes are done one after the other. Modified Paths: -------------- trunk/ktutorial/ktutorial-library/src/Tutorial.cpp trunk/ktutorial/ktutorial-library/src/Tutorial.h trunk/ktutorial/ktutorial-library/tests/TutorialTest.cpp Modified: trunk/ktutorial/ktutorial-library/src/Tutorial.cpp =================================================================== --- trunk/ktutorial/ktutorial-library/src/Tutorial.cpp 2011-05-06 12:49:50 UTC (rev 303) +++ trunk/ktutorial/ktutorial-library/src/Tutorial.cpp 2011-05-08 15:16:11 UTC (rev 304) @@ -1,5 +1,5 @@ /*************************************************************************** - * Copyright (C) 2008-2010 by Daniel Calviño Sánchez * + * Copyright (C) 2008-2011 by Daniel Calviño Sánchez * * dan...@gm... * * * * This program is free software; you can redistribute it and/or modify * @@ -65,6 +65,38 @@ } void Tutorial::nextStep(Step* step) { + mQueuedSteps.append(step); + + if (mQueuedSteps.count() > 1) { + //Nested call to nextStep(Step*) (that is, something called by + //nextStep(Step*) caused the method to be called again before its + //previous execution ended). Once that previous call continues its + //execution it will change to the next queued step. + return; + } + + while (mQueuedSteps.count() > 0) { + changeToStep(mQueuedSteps[0]); + mQueuedSteps.removeFirst(); + } +} + +//public slots: + +void Tutorial::finish() { + if (mCurrentStep != 0) { + mCurrentStep->setActive(false); + mCurrentStep = 0; + } + + tearDown(); + + emit finished(this); +} + +//private: + +void Tutorial::changeToStep(Step* step) { if (mSteps.key(step).isEmpty()) { kError() << "Activate step " << step->id() << " which doesn't belong to tutorial " @@ -84,16 +116,3 @@ emit stepActivated(step); } - -//public slots: - -void Tutorial::finish() { - if (mCurrentStep != 0) { - mCurrentStep->setActive(false); - mCurrentStep = 0; - } - - tearDown(); - - emit finished(this); -} Modified: trunk/ktutorial/ktutorial-library/src/Tutorial.h =================================================================== --- trunk/ktutorial/ktutorial-library/src/Tutorial.h 2011-05-06 12:49:50 UTC (rev 303) +++ trunk/ktutorial/ktutorial-library/src/Tutorial.h 2011-05-08 15:16:11 UTC (rev 304) @@ -1,5 +1,5 @@ /*************************************************************************** - * Copyright (C) 2008-2010 by Daniel Calviño Sánchez * + * Copyright (C) 2008-2011 by Daniel Calviño Sánchez * * dan...@gm... * * * * This program is free software; you can redistribute it and/or modify * @@ -208,6 +208,20 @@ */ Step* mCurrentStep; + /** + * The steps to change to that were not activated yet. + */ + QList<Step*> mQueuedSteps; + + /** + * Activates the given step. + * When calling nextStep(Step*), the tutorial queues the steps to change to. + * The real activation of the step is done by this method. + * + * @param step The Step to activate. + */ + void changeToStep(Step* step); + }; #endif Modified: trunk/ktutorial/ktutorial-library/tests/TutorialTest.cpp =================================================================== --- trunk/ktutorial/ktutorial-library/tests/TutorialTest.cpp 2011-05-06 12:49:50 UTC (rev 303) +++ trunk/ktutorial/ktutorial-library/tests/TutorialTest.cpp 2011-05-08 15:16:11 UTC (rev 304) @@ -1,5 +1,5 @@ /*************************************************************************** - * Copyright (C) 2009-2010 by Daniel Calviño Sánchez * + * Copyright (C) 2009-2011 by Daniel Calviño Sánchez * * dan...@gm... * * * * This program is free software; you can redistribute it and/or modify * @@ -55,6 +55,8 @@ void testNextStepStep(); void testNextStepStepWithInvalidStep(); + void testNextStepFromStepSetup(); + void testFinish(); }; @@ -71,6 +73,46 @@ }; +class StepToSetNextStepInSetup: public Step { +public: + + Tutorial* mTutorial; + Step* mNextStep; + bool mDuringSetup; + + StepToSetNextStepInSetup(const QString& id): Step(id), + mTutorial(0), + mNextStep(0), + mDuringSetup(false) { + } + +protected: + + void setup() { + mDuringSetup = true; + mTutorial->nextStep(mNextStep); + mDuringSetup = false; + } + +}; + +class StepToAssertNoRecursiveStepActivation: public Step { +public: + + StepToSetNextStepInSetup* mPreviousStep; + + StepToAssertNoRecursiveStepActivation(const QString& id): Step(id), + mPreviousStep(0) { + } + +protected: + + void setup() { + QVERIFY(!mPreviousStep->mDuringSetup); + } + +}; + class MockTutorial: public Tutorial { public: @@ -408,6 +450,54 @@ QVERIFY(step1->isActive()); } +//Ensure that if some step calls Tutorial::nextStep from its setup (that is, +//when the step is being activated), the next step is not activated until the +//activation of the previous one ended (that is, steps are not activated +//recursively, but sequentially). +void TutorialTest::testNextStepFromStepSetup() { + Tutorial tutorial(new TutorialInformation("pearlOrientation")); + + Step* stepStart = new Step("start"); + tutorial.addStep(stepStart); + + StepToSetNextStepInSetup* step1 = new StepToSetNextStepInSetup("record"); + tutorial.addStep(step1); + + StepToAssertNoRecursiveStepActivation* step2 = + new StepToAssertNoRecursiveStepActivation("roll"); + tutorial.addStep(step2); + + step1->mTutorial = &tutorial; + step1->mNextStep = step2; + step2->mPreviousStep = step1; + + tutorial.addStep(new Step("send")); + + tutorial.start(); + + //Step* must be registered in order to be used with QSignalSpy + int stepStarType = qRegisterMetaType<Step*>("Step*"); + QSignalSpy stepActivatedSpy(&tutorial, SIGNAL(stepActivated(Step*))); + + //Ensure that the step is already active when the signal is emitted + connect(&tutorial, SIGNAL(stepActivated(Step*)), + this, SLOT(assertStepActive(Step*))); + + tutorial.nextStep(step1); + + QCOMPARE(stepActivatedSpy.count(), 2); + QVariant argument = stepActivatedSpy.at(0).at(0); + QCOMPARE(argument.userType(), stepStarType); + QCOMPARE(qvariant_cast<Step*>(argument), step1); + argument = stepActivatedSpy.at(1).at(0); + QCOMPARE(argument.userType(), stepStarType); + QCOMPARE(qvariant_cast<Step*>(argument), step2); + QCOMPARE(tutorial.mCurrentStep, step2); + QVERIFY(!stepStart->isActive()); + QVERIFY(!step1->isActive()); + QVERIFY(step2->isActive()); +} + void TutorialTest::testFinish() { MockTutorial tutorial(new TutorialInformation("pearlOrientation")); This was sent by the SourceForge.net collaborative development platform, the world's largest Open Source development site. |
From: <dan...@us...> - 2011-05-16 22:42:39
|
Revision: 307 http://ktutorial.svn.sourceforge.net/ktutorial/?rev=307&view=rev Author: danxuliu Date: 2011-05-16 22:42:33 +0000 (Mon, 16 May 2011) Log Message: ----------- Provide the names of the properties of a class in the editor support module. Modified Paths: -------------- trunk/ktutorial/ktutorial-library/src/editorsupport/ClassRegisterAdaptor.cpp trunk/ktutorial/ktutorial-library/src/editorsupport/ClassRegisterAdaptor.h trunk/ktutorial/ktutorial-library/tests/editorsupport/ClassRegisterAdaptorTest.cpp Modified: trunk/ktutorial/ktutorial-library/src/editorsupport/ClassRegisterAdaptor.cpp =================================================================== --- trunk/ktutorial/ktutorial-library/src/editorsupport/ClassRegisterAdaptor.cpp 2011-05-16 16:46:51 UTC (rev 306) +++ trunk/ktutorial/ktutorial-library/src/editorsupport/ClassRegisterAdaptor.cpp 2011-05-16 22:42:33 UTC (rev 307) @@ -1,5 +1,5 @@ /*************************************************************************** - * Copyright (C) 2010 by Daniel Calviño Sánchez * + * Copyright (C) 2010-2011 by Daniel Calviño Sánchez * * dan...@gm... * * * * This program is free software; you can redistribute it and/or modify * @@ -46,6 +46,24 @@ return metaObject->superClass()->className(); } +QStringList ClassRegisterAdaptor::propertyList(const QString& className) const { + const QMetaObject* metaObject = + mObjectRegister->metaObjectForClassName(className); + if (!metaObject) { + return QStringList(); + } + + QStringList propertyList; + for (int i=0; i<metaObject->propertyCount(); ++i) { + QMetaProperty property = metaObject->property(i); + if (isPropertyDefinedInClass(property, metaObject)) { + propertyList.append(property.name()); + } + } + + return propertyList; +} + QStringList ClassRegisterAdaptor::signalList(const QString& className) const { const QMetaObject* metaObject = mObjectRegister->metaObjectForClassName(className); @@ -66,6 +84,19 @@ //private: +bool ClassRegisterAdaptor::isPropertyDefinedInClass( + const QMetaProperty& metaProperty, + const QMetaObject* metaObject) const { + const QMetaObject* superClass = metaObject; + while ((superClass = superClass->superClass())) { + if (superClass->indexOfProperty(metaProperty.name()) != -1) { + return false; + } + } + + return true; +} + bool ClassRegisterAdaptor::isSignalDefinedInClass(const QMetaMethod& metaMethod, const QMetaObject* metaObject) const { if (metaMethod.methodType() != QMetaMethod::Signal) { Modified: trunk/ktutorial/ktutorial-library/src/editorsupport/ClassRegisterAdaptor.h =================================================================== --- trunk/ktutorial/ktutorial-library/src/editorsupport/ClassRegisterAdaptor.h 2011-05-16 16:46:51 UTC (rev 306) +++ trunk/ktutorial/ktutorial-library/src/editorsupport/ClassRegisterAdaptor.h 2011-05-16 22:42:33 UTC (rev 307) @@ -1,5 +1,5 @@ /*************************************************************************** - * Copyright (C) 2010 by Daniel Calviño Sánchez * + * Copyright (C) 2010-2011 by Daniel Calviño Sánchez * * dan...@gm... * * * * This program is free software; you can redistribute it and/or modify * @@ -59,6 +59,18 @@ QString superClass(const QString& className) const; /** + * Returns the properties of the class with the given name. + * If the class is not registered, an empty list is returned. + * + * Only the properties defined in the given class are included in the list. + * Properties from parent classes must be got using the parent class name. + * + * @param className The name of the class. + * @return The list of properties. + */ + QStringList propertyList(const QString& className) const; + + /** * Returns the signals of the class with the given name. * If the class is not registered, an empty list is returned. * @@ -78,6 +90,20 @@ ObjectRegister* mObjectRegister; /** + * Checks whether the given meta property is a property defined in the given + * meta object. + * If the property is inherited in the given meta object instead of defined + * in it, false is also returned. + * + * @param metaProperty The meta property to check. + * @param metaObject The meta object to check the meta property with. + * @return True if the meta property is a property defined in the meta + * object, false otherwise. + */ + bool isPropertyDefinedInClass(const QMetaProperty& metaProperty, + const QMetaObject* metaObject) const; + + /** * Checks whether the given meta method is a signal defined in the given * meta object. * If the signal is inherited in the given meta object instead of defined in Modified: trunk/ktutorial/ktutorial-library/tests/editorsupport/ClassRegisterAdaptorTest.cpp =================================================================== --- trunk/ktutorial/ktutorial-library/tests/editorsupport/ClassRegisterAdaptorTest.cpp 2011-05-16 16:46:51 UTC (rev 306) +++ trunk/ktutorial/ktutorial-library/tests/editorsupport/ClassRegisterAdaptorTest.cpp 2011-05-16 22:42:33 UTC (rev 307) @@ -1,5 +1,5 @@ /*************************************************************************** - * Copyright (C) 2010 by Daniel Calviño Sánchez * + * Copyright (C) 2010-2011 by Daniel Calviño Sánchez * * dan...@gm... * * * * This program is free software; you can redistribute it and/or modify * @@ -26,6 +26,20 @@ class ClassRegisterAdaptorTest: public QObject { Q_OBJECT +Q_PROPERTY(QString dummyProperty READ dummyProperty) +Q_PROPERTY(QString dummyPropertyWithNotifySignal + READ dummyPropertyWithNotifySignal NOTIFY dummySignal) + +public: + + QString dummyProperty() const { + return mDummyProperty; + } + + QString dummyPropertyWithNotifySignal() const { + return mDummyPropertyWithNotifySignal; + } + Q_SIGNALS: void dummySignal(); @@ -38,9 +52,17 @@ void testSuperClass(); void testSuperClassWithUnknownClassName(); + void testPropertyList(); + void testPropertyListWithUnknownClassName(); + void testSignalList(); void testSignalListWithUnknownClassName(); +private: + + QString mDummyProperty; + QString mDummyPropertyWithNotifySignal; + }; void ClassRegisterAdaptorTest::testConstructor() { @@ -68,6 +90,27 @@ QCOMPARE(adaptor->superClass("UnknownClassName"), QString("")); } +void ClassRegisterAdaptorTest::testPropertyList() { + ObjectRegister objectRegister; + ClassRegisterAdaptor* adaptor = new ClassRegisterAdaptor(&objectRegister); + + objectRegister.idForObject(this); + + QStringList propertyList = + adaptor->propertyList("editorsupport::ClassRegisterAdaptorTest"); + QCOMPARE(propertyList.count(), 2); + QCOMPARE(propertyList[0], QString("dummyProperty")); + QCOMPARE(propertyList[1], QString("dummyPropertyWithNotifySignal")); +} + +void ClassRegisterAdaptorTest::testPropertyListWithUnknownClassName() { + ObjectRegister objectRegister; + ClassRegisterAdaptor* adaptor = new ClassRegisterAdaptor(&objectRegister); + + QStringList propertyList = adaptor->propertyList("UnknownClassName"); + QCOMPARE(propertyList.count(), 0); +} + void ClassRegisterAdaptorTest::testSignalList() { ObjectRegister objectRegister; ClassRegisterAdaptor* adaptor = new ClassRegisterAdaptor(&objectRegister); This was sent by the SourceForge.net collaborative development platform, the world's largest Open Source development site. |
From: <dan...@us...> - 2011-07-07 02:31:47
|
Revision: 333 http://ktutorial.svn.sourceforge.net/ktutorial/?rev=333&view=rev Author: danxuliu Date: 2011-07-07 02:31:41 +0000 (Thu, 07 Jul 2011) Log Message: ----------- Fix wrong behaviour of StepTextWidget highlighting of widgets after cancelling the context menu. Modified Paths: -------------- trunk/ktutorial/ktutorial-library/src/view/StepTextWidget.cpp trunk/ktutorial/ktutorial-library/src/view/StepTextWidget.h trunk/ktutorial/ktutorial-library/tests/view/StepTextWidgetTest.cpp Modified: trunk/ktutorial/ktutorial-library/src/view/StepTextWidget.cpp =================================================================== --- trunk/ktutorial/ktutorial-library/src/view/StepTextWidget.cpp 2011-07-06 19:40:06 UTC (rev 332) +++ trunk/ktutorial/ktutorial-library/src/view/StepTextWidget.cpp 2011-07-07 02:31:41 UTC (rev 333) @@ -1,5 +1,5 @@ /*************************************************************************** - * Copyright (C) 2010 by Daniel Calviño Sánchez * + * Copyright (C) 2010-2011 by Daniel Calviño Sánchez * * dan...@gm... * * * * This program is free software; you can redistribute it and/or modify * @@ -34,7 +34,8 @@ StepTextWidget::StepTextWidget(QWidget* parent /*= 0*/): KTextEdit(parent), - mCurrentHighlightedWidget(0) { + mCurrentWidget(0), + mCurrentWidgetIsBeingHighlighted(false) { setReadOnly(true); setFrameShape(QFrame::NoFrame); setFrameShadow(QFrame::Plain); @@ -60,13 +61,13 @@ } StepTextWidget::~StepTextWidget() { - if (mCurrentHighlightedWidget) { + if (mCurrentWidgetIsBeingHighlighted) { stopHighlightingCurrentWidget(); } } bool StepTextWidget::eventFilter(QObject* watched, QEvent* event) { - if (watched != mCurrentHighlightedWidget) { + if (watched != mCurrentWidget) { return false; } @@ -106,16 +107,16 @@ QMenu* menu = new QMenu(this); - if (mCurrentHighlightedWidget && - mCurrentHighlightedWidget != widgetForAnchor(anchor)) { + if (mCurrentWidgetIsBeingHighlighted && + mCurrentWidget != widgetForAnchor(anchor)) { stopHighlightingCurrentWidget(); } - if (!mCurrentHighlightedWidget) { + if (!mCurrentWidgetIsBeingHighlighted) { menu->addAction(i18nc("@item:inmenu", "Highlight"), this, SLOT(highlightCurrentWidget())); - mCurrentHighlightedWidget = widgetForAnchor(anchor); + mCurrentWidget = widgetForAnchor(anchor); } else { menu->addAction(i18nc("@item:inmenu", "Stop highlighting"), this, SLOT(stopHighlightingCurrentWidget())); @@ -143,13 +144,13 @@ return; } - if (mCurrentHighlightedWidget && - mCurrentHighlightedWidget != widgetForAnchor(anchor)) { + if (mCurrentWidgetIsBeingHighlighted && + mCurrentWidget != widgetForAnchor(anchor)) { stopHighlightingCurrentWidget(); } - if (!mCurrentHighlightedWidget) { - mCurrentHighlightedWidget = widgetForAnchor(anchor); + if (!mCurrentWidgetIsBeingHighlighted) { + mCurrentWidget = widgetForAnchor(anchor); highlightCurrentWidget(); } else { @@ -185,32 +186,36 @@ void StepTextWidget::updateText() { updateGeometry(); - if (mCurrentHighlightedWidget) { + if (mCurrentWidgetIsBeingHighlighted) { stopHighlightingCurrentWidget(); } } void StepTextWidget::highlightCurrentWidget() { - if (!mCurrentHighlightedWidget) { + if (!mCurrentWidget) { kWarning() << "The widget to highlight was not found!"; return; } - WidgetHighlighterManager::self()->highlight(mCurrentHighlightedWidget); + WidgetHighlighterManager::self()->highlight(mCurrentWidget); - mCurrentHighlightedWidget->installEventFilter(this); + mCurrentWidget->installEventFilter(this); + + mCurrentWidgetIsBeingHighlighted = true; } void StepTextWidget::stopHighlightingCurrentWidget() { - if (!mCurrentHighlightedWidget) { + if (!mCurrentWidget) { kWarning() << "The widget to stop highlighting was not found!"; return; } - WidgetHighlighterManager::self()->stopHighlighting(mCurrentHighlightedWidget); + WidgetHighlighterManager::self()->stopHighlighting(mCurrentWidget); - mCurrentHighlightedWidget->removeEventFilter(this); - mCurrentHighlightedWidget = 0; + mCurrentWidget->removeEventFilter(this); + mCurrentWidget = 0; + + mCurrentWidgetIsBeingHighlighted = false; } } Modified: trunk/ktutorial/ktutorial-library/src/view/StepTextWidget.h =================================================================== --- trunk/ktutorial/ktutorial-library/src/view/StepTextWidget.h 2011-07-06 19:40:06 UTC (rev 332) +++ trunk/ktutorial/ktutorial-library/src/view/StepTextWidget.h 2011-07-07 02:31:41 UTC (rev 333) @@ -135,12 +135,17 @@ private: /** - * The widget currently being highlighted as a result of activating a link - * in this StepTextWidget. + * The last widget referenced by a link activated or selected in this + * StepTextWidget. */ - QPointer<QWidget> mCurrentHighlightedWidget; + QPointer<QWidget> mCurrentWidget; /** + * Whether the current widget is being highlighted or not. + */ + bool mCurrentWidgetIsBeingHighlighted; + + /** * Returns the size for the given text width. * If the width is < 0, the size is adjusted to the text as a rectangle, * with a width bigger than the height. Modified: trunk/ktutorial/ktutorial-library/tests/view/StepTextWidgetTest.cpp =================================================================== --- trunk/ktutorial/ktutorial-library/tests/view/StepTextWidgetTest.cpp 2011-07-06 19:40:06 UTC (rev 332) +++ trunk/ktutorial/ktutorial-library/tests/view/StepTextWidgetTest.cpp 2011-07-07 02:31:41 UTC (rev 333) @@ -19,6 +19,8 @@ #include <QtTest> #include <qtest_kde.h> +#include <QAction> + #include <KXmlGuiWindow> #include "StepTextWidget.h" @@ -35,14 +37,9 @@ class StepTextWidgetTest: public QObject { Q_OBJECT -public slots: - - void selectFirstContextMenuOption(); - private slots: void init(); - void cleanup(); void testConstructor(); @@ -53,6 +50,7 @@ void testStopHighlightingWidgetClickingOnAnchor(); void testHighlightWidgetUsingContextMenu(); void testStopHighlightingWidgetUsingContextMenu(); + void testCancelContextMenu(); void testHighlightSeveralWidgets(); void testHighlightUnknownWidget(); @@ -69,6 +67,10 @@ void showContextMenuAndSelectFirstOption(const StepTextWidget& widget, const QPoint& position); + void showContextMenuCheckFirstOptionAndCancel(const StepTextWidget& widget, + const QPoint& position, + const QString& text); + }; void StepTextWidgetTest::init() { @@ -76,9 +78,6 @@ KTutorial::sSelf = new KTutorial(); } -void StepTextWidgetTest::cleanup() { -} - void StepTextWidgetTest::testConstructor() { QWidget parent; StepTextWidget* widget = new StepTextWidget(&parent); @@ -206,6 +205,40 @@ QVERIFY(!widgetToHighlight->findChild<WidgetHighlighter*>("")); } +void StepTextWidgetTest::testCancelContextMenu() { + KXmlGuiWindow mainWindow; + KTutorial::self()->setup(&mainWindow); + QWidget* widgetToHighlight = new QWidget(&mainWindow); + widgetToHighlight->setObjectName("widgetName"); + + StepTextWidget widget; + widget.setText("The <a href=\"widget:widgetName\">widget to highlight</a>"); + widget.show(); + + //Give the widget time to be shown + QTest::qWait(500); + + QPoint position = centerOfText(widget, "widget to highlight"); + showContextMenuCheckFirstOptionAndCancel(widget, position, + i18n("Highlight")); + + //Ensure that the option text is the right one after cancelling the menu + showContextMenuCheckFirstOptionAndCancel(widget, position, + i18n("Highlight")); + + //Check again when the widget is highlighted + showContextMenuAndSelectFirstOption(widget, position); + + QVERIFY(widgetToHighlight->findChild<WidgetHighlighter*>("")); + + showContextMenuCheckFirstOptionAndCancel(widget, position, + i18n("Stop highlighting")); + + //Ensure that the option text is the right one after cancelling the menu + showContextMenuCheckFirstOptionAndCancel(widget, position, + i18n("Stop highlighting")); +} + void StepTextWidgetTest::testHighlightSeveralWidgets() { KXmlGuiWindow mainWindow; KTutorial::self()->setup(&mainWindow); @@ -383,12 +416,6 @@ /////////////////////////////////// Helpers //////////////////////////////////// -void StepTextWidgetTest::selectFirstContextMenuOption() { - QVERIFY(QApplication::activePopupWidget()); - QTest::keyClick(QApplication::activePopupWidget(), Qt::Key_Down); - QTest::keyClick(QApplication::activePopupWidget(), Qt::Key_Enter); -} - QPoint StepTextWidgetTest::centerOfText(const StepTextWidget& widget, const QString& text) { QTextCursor cursor = widget.document()->find(text); @@ -400,6 +427,46 @@ return widget.cursorRect(cursor).center(); } +//The context menu contains its own event loop, so it won't return to the test +//code until it is closed. Thus, the commands to execute on the menu must be +//"queued", as calling QTest::keyClick after showing the menu won't work. +class QueuedActionsHelper: public QObject { +Q_OBJECT +public: + + QueuedActionsHelper(QObject* parent = 0): QObject(parent) { + setObjectName("helper"); + } + + void setExpectedMenuItemName(const QString& menuItemName) { + mMenuItemName = menuItemName; + } + +public slots: + + void selectFirstContextMenuOption() { + QVERIFY(QApplication::activePopupWidget()); + QTest::keyClick(QApplication::activePopupWidget(), Qt::Key_Down); + QTest::keyClick(QApplication::activePopupWidget(), Qt::Key_Enter); + } + + void assertFirstContextMenuOptionName() { + QVERIFY(QApplication::activePopupWidget()); + QWidget* menu = QApplication::activePopupWidget(); + QCOMPARE(menu->actions()[0]->text(), mMenuItemName); + } + + void cancelContextMenu() { + QVERIFY(QApplication::activePopupWidget()); + QTest::keyClick(QApplication::activePopupWidget(), Qt::Key_Escape); + } + +private: + + QString mMenuItemName; + +}; + void StepTextWidgetTest::showContextMenuAndSelectFirstOption( const StepTextWidget& widget, const QPoint& position) { //The context menu can't be triggered sending a right mouse button press @@ -410,16 +477,34 @@ QContextMenuEvent event(QContextMenuEvent::Mouse, position, widget.mapToGlobal(position)); - //The context menu contains its own event loop, 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 QTest::keyClick after the button click won't - //work. - QTimer::singleShot(500, this, SLOT(selectFirstContextMenuOption())); + QueuedActionsHelper* helper = new QueuedActionsHelper(this); + QTimer::singleShot(500, helper, SLOT(selectFirstContextMenuOption())); + QApplication::sendEvent(widget.viewport(), &event); } +void StepTextWidgetTest::showContextMenuCheckFirstOptionAndCancel( + const StepTextWidget& widget, + const QPoint& position, + const QString& text) { + //The context menu can't be triggered sending a right mouse button press + //event, as that is platform dependent (that event is not handled by + //QTextEdit or its parents, but by the QApplication for the platform that + //creates a context menu event when needed). An explicit QContextMenuEvent + //must be sent for it to work. + QContextMenuEvent event(QContextMenuEvent::Mouse, position, + widget.mapToGlobal(position)); + + QueuedActionsHelper* helper = new QueuedActionsHelper(this); + helper->setExpectedMenuItemName(text); + QTimer::singleShot(500, helper, SLOT(assertFirstContextMenuOptionName())); + QTimer::singleShot(600, helper, SLOT(cancelContextMenu())); + + QApplication::sendEvent(widget.viewport(), &event); } +} + QTEST_KDEMAIN(view::StepTextWidgetTest, GUI) #include "StepTextWidgetTest.moc" This was sent by the SourceForge.net collaborative development platform, the world's largest Open Source development site. |
From: <dan...@us...> - 2012-07-05 12:38:17
|
Revision: 353 http://ktutorial.svn.sourceforge.net/ktutorial/?rev=353&view=rev Author: danxuliu Date: 2012-07-05 12:38:07 +0000 (Thu, 05 Jul 2012) Log Message: ----------- Improve handling of ambiguity in names when finding objects. Until now, if finding an object yield more than one result the first one was used. Now, a set of rules to try to resolve the ambiguity are used. Those rules try to handle scenarios like, for example, "Ok" buttons in nested dialogs, as, before, looking for the "Parent dialog/Ok button" may return the button from the child dialog instead of the button of the parent dialog. Modified Paths: -------------- trunk/ktutorial/ktutorial-library/src/KTutorial.cpp trunk/ktutorial/ktutorial-library/src/KTutorial.h trunk/ktutorial/ktutorial-library/tests/KTutorialTest.cpp Modified: trunk/ktutorial/ktutorial-library/src/KTutorial.cpp =================================================================== --- trunk/ktutorial/ktutorial-library/src/KTutorial.cpp 2012-07-03 08:59:08 UTC (rev 352) +++ trunk/ktutorial/ktutorial-library/src/KTutorial.cpp 2012-07-05 12:38:07 UTC (rev 353) @@ -1,5 +1,5 @@ /*************************************************************************** - * Copyright (C) 2008-2010 by Daniel Calviño Sánchez * + * Copyright (C) 2008-2012 by Daniel Calviño Sánchez * * dan...@gm... * * * * This program is free software; you can redistribute it and/or modify * @@ -96,6 +96,148 @@ KTutorial* KTutorial::sSelf = new KTutorial(); +QList<QObject*> KTutorial::getBestMatches(const QString& name, + QList< QList<QObject*> > objectPaths) const { + if (name.isEmpty() || objectPaths.isEmpty()) { + return QList<QObject*>(); + } + + if (name.indexOf('/') == -1) { + QList< QList<QObject*> > filteredObjectPaths = + filterObjectPaths(name, objectPaths); + + QList<QObject*> filteredObjects; + foreach (QList<QObject*> filteredObjectPath, filteredObjectPaths) { + filteredObjects.append(filteredObjectPath.first()); + } + + return filteredObjects; + } + + QRegExp slashPattern("/+"); + QString ancestorName = name.left(name.indexOf(slashPattern)); + QString descendantName = name.mid(ancestorName.length() + + slashPattern.matchedLength()); + + return getBestMatches(descendantName, filterObjectPaths(ancestorName, + objectPaths)); +} + +QList< QList<QObject*> > KTutorial::filterObjectPaths(const QString& name, + const QList< QList<QObject*> >& objectPaths) const { + QList< QList<QObject*> > filteredPaths = filterDirectChildren(name, + objectPaths); + if (filteredPaths.size() > 0) { + return filteredPaths; + } + + filteredPaths = filterNestedChildrenWithUnnamedAncestors(name, objectPaths); + if (filteredPaths.size() > 0) { + return filteredPaths; + } + + return filterNestedChildren(name, objectPaths); +} + +QList< QList<QObject*> > KTutorial::filterDirectChildren(const QString& name, + const QList< QList<QObject*> >& objectPaths) const { + QList< QList<QObject*> > filteredPaths; + + foreach (QList<QObject*> objectPath, objectPaths) { + if (objectPath.size() >= 2 && objectPath[1]->objectName() == name) { + objectPath.removeAt(0); + filteredPaths.append(objectPath); + } + } + + return filteredPaths; +} + +QList< QList<QObject*> > KTutorial::filterNestedChildrenWithUnnamedAncestors( + const QString& name, + const QList< QList<QObject*> >& objectPaths) const { + QList< QList<QObject*> > candidatePaths; + + //No need to use std::numeric_limits, as there would never be a 100000 + //levels deep object. + int minimumNumberOfUnnamedAncestors = 100000; + foreach (QList<QObject*> objectPath, objectPaths) { + objectPath.removeAt(0); + + int unnamedAncestorCount = 0; + while (objectPath.size() > unnamedAncestorCount && + objectPath[unnamedAncestorCount]->objectName() == "") { + unnamedAncestorCount++; + } + + if (unnamedAncestorCount > 0 && + objectPath.size() > unnamedAncestorCount && + objectPath[unnamedAncestorCount]->objectName() == name) { + candidatePaths.append(objectPath); + + if (unnamedAncestorCount < minimumNumberOfUnnamedAncestors) { + minimumNumberOfUnnamedAncestors = unnamedAncestorCount; + } + } + } + + QList< QList<QObject*> > filteredPaths; + + foreach (QList<QObject*> candidatePath, candidatePaths) { + if (candidatePath[minimumNumberOfUnnamedAncestors]->objectName() == + name) { + for (int i=0; i<minimumNumberOfUnnamedAncestors; ++i) { + candidatePath.removeAt(0); + } + filteredPaths.append(candidatePath); + } + } + + return filteredPaths; +} + +QList< QList<QObject*> > KTutorial::filterNestedChildren(const QString& name, + const QList< QList<QObject*> >& objectPaths) const { + QList< QList<QObject*> > candidatePaths; + + //No need to use std::numeric_limits, as there would never be a 100000 + //levels deep object. + int minimumNumberOfAncestors = 100000; + foreach (QList<QObject*> objectPath, objectPaths) { + objectPath.removeAt(0); + + int ancestorCount = 0; + while (objectPath.size() > ancestorCount && + objectPath[ancestorCount]->objectName() != name) { + ancestorCount++; + } + + if (ancestorCount > 0 && objectPath.size() > ancestorCount && + objectPath[ancestorCount]->objectName() == name) { + candidatePaths.append(objectPath); + + if (ancestorCount < minimumNumberOfAncestors) { + minimumNumberOfAncestors = ancestorCount; + } + } + } + + QList< QList<QObject*> > filteredPaths; + + foreach (QList<QObject*> candidatePath, candidatePaths) { + if (candidatePath[minimumNumberOfAncestors]->objectName() == name) { + for (int i=0; i<minimumNumberOfAncestors; ++i) { + candidatePath.removeAt(0); + } + filteredPaths.append(candidatePath); + } + } + + return filteredPaths; +} + +//private slots: + void KTutorial::showTutorialManagerDialog() const { QDialog* dialog = new TutorialManagerDialog(mTutorialmanager, mParent); dialog->setAttribute(Qt::WA_DeleteOnClose); Modified: trunk/ktutorial/ktutorial-library/src/KTutorial.h =================================================================== --- trunk/ktutorial/ktutorial-library/src/KTutorial.h 2012-07-03 08:59:08 UTC (rev 352) +++ trunk/ktutorial/ktutorial-library/src/KTutorial.h 2012-07-05 12:38:07 UTC (rev 353) @@ -1,5 +1,5 @@ /*************************************************************************** - * Copyright (C) 2008-2011 by Daniel Calviño Sánchez * + * Copyright (C) 2008-2012 by Daniel Calviño Sánchez * * dan...@gm... * * * * This program is free software; you can redistribute it and/or modify * @@ -123,6 +123,7 @@ * Returns the object with the specified name, if any. * Objects are searched in the children of the main window of the * application. + * * When the name of the desired object is not unique the name of some * ancestor must be included. Ancestor names are separated using a "/". That * is, "Ancestor name/The object with a repeated name". As many ancestor @@ -132,6 +133,36 @@ * name not unique/The object to find" is valid if, among all the objects * called "Ancestor name not unique", there is only one that has a * descendant called "The object to find". + * + * In some cases it may be posible that a unique name can not be provided, + * even using ancestor names. In those cases there are some rules to resolve + * the ambiguity. Between two or more objects with the same name, the + * selected one is: + * -A direct child of the base object. + * -A nested child without named ancestors between it and the base object. + * -If there is more than one, the one nearer to the base object (that is, + * with the lesser number of intermediate ancestors). + * -A nested child with named or unnamed ancestors between it and the base + * object. + * -If there is more than one, the one nearer to the base object (that is, + * with the lesser number of intermediate ancestors). + * + * If the ambiguous name contains ancestor names the rules are applied for + * each component of the name. Each component is searched for only from the + * already selected previous components. That is, if the ambiguous name is + * "Ancestor name/The object", the rules are applied to find the objects + * named "Ancestor name" using the main window as base object. Then, the + * rules are applied to find "The object" using the "Ancestor name" objects + * as base, so "The object" is searched only in the children of the + * "Ancestor name" objects previously found. Note that, even with the + * ambiguity resolving rules, it may be searched for from several "Ancestor + * name" if, for example, there are several "Ancestor name" child of the + * main window. However, if there were other "Ancestor name" objects that + * were not direct children of the main window they will not be used in the + * search, as the direct children would have taken precedence. + * + * If after applying the rules there is still more than one object that + * matches, the first one is selected. * * @param name The name of the object to find. * @return The object with the specified name, or null if there is none. @@ -140,7 +171,18 @@ */ template <typename T> T findObject(const QString& name) const { - return findObject<T>(name, mParent); + QList<T> candidateObjects; + findObjects<T>(name, mParent, candidateObjects); + + if (candidateObjects.isEmpty()) { + return 0; + } + + if (candidateObjects.count() == 1) { + return candidateObjects.first(); + } + + return getBestMatch(name, candidateObjects); } private: @@ -177,24 +219,26 @@ } /** - * Returns the object with the specified name that is descendant of the - * given ancestor, if any. - * The name of the object can contain ancestor names separated by "/". The - * first object that matches the whole path is returned (note that ancestors - * are not necessarily direct parents). + * Adds to the foundObjects list the objects with the specified name that + * are descendant of the given ancestor, if any. + * The name of the objects can contain ancestor names separated by "/". Note + * that ancestors are not necessarily direct parents. * - * @param name The name of the object to find. - * @param ancestor The ancestor to look the object in. - * @return The object with the specified name, or null if there is none. + * @param name The name of the objects to find. + * @param ancestor The ancestor to look the objects in. + * @param foundObjects The list to add to the objects with the specified + * name to. */ template <typename T> - T findObject(const QString& name, const QObject* ancestor) const { + void findObjects(const QString& name, const QObject* ancestor, + QList<T>& foundObjects) const { if (name.isEmpty() || ancestor == 0) { - return T(); + return; } if (name.indexOf('/') == -1) { - return ancestor->findChild<T>(name); + foundObjects.append(ancestor->findChildren<T>(name)); + return; } QRegExp slashPattern("/+"); @@ -205,15 +249,141 @@ QList<QObject*> namedAncestors = ancestor->findChildren<QObject*>(ancestorName); foreach (QObject* namedAncestor, namedAncestors) { - T object = findObject<T>(descendantName, namedAncestor); - if (object) { - return object; + findObjects<T>(descendantName, namedAncestor, foundObjects); + } + } + + /** + * Resolves the ambiguity between several objects that match the given name. + * The ambiguity resolving rules are those specified in + * findObject(const QString&). + * + * @param name The name of the object to find. + * @param candidateObjects A list with objects that match the given name. + * @return The object that matches the best the given name. + */ + template <typename T> + T getBestMatch(const QString& name, QList<T> candidateObjects) const { + QList< QList<QObject*> > objectPaths = getObjectPaths(candidateObjects); + + QList<QObject*> bestMatches = getBestMatches(name, objectPaths); + + //Should not happen, but just in case + if (bestMatches.isEmpty()) { + return 0; + } + + return static_cast<T>(bestMatches[0]); + } + + /** + * Returns a list with the paths to the given objects. + * Each path is a list that contains the object and all its ancestors. The + * first object in the list is the more distant ancestor, and the last + * object is the object itself. + * + * @param objects The objects to get their paths. + * @return A list with the paths to the given objects. + */ + template <typename T> + QList< QList<QObject*> > getObjectPaths(const QList<T> objects) const { + QList< QList<QObject*> > objectPaths; + + foreach (T candidateObject, objects) { + QList<QObject*> objectPath; + + QObject* ancestor = candidateObject; + while (ancestor) { + objectPath.prepend(ancestor); + ancestor = ancestor->parent(); } + + objectPaths.append(objectPath); } - return T(); + return objectPaths; } + /** + * Gets the objects from the given object paths that match the best the + * given name. + * The name can contain ancestor names. The ambiguity resolving rules are + * applied recursively for each component of the name, so the object paths + * used to find each component are the ones filtered with the name of its + * ancestor. + * + * @param name The name of the object to get. + * @param objectPaths The paths to get the object from. + * @return The list of objects that match the best the given name. + */ + QList<QObject*> getBestMatches(const QString& name, + QList< QList<QObject*> > objectPaths) const; + + /** + * Returns the object paths that contain a descendant of the base object + * with the given name. + * If direct children are found, their path is used. If not, if descendants + * without named objects between them and the base object are found, their + * path is used. If not, the path of the shallower descendants is used. + * The name must be a single object name, without any ancestor name. + * The returned paths are trimmed to make the object with the given name the + * new base object of the path. + * + * @param name The name of the descendant to find. + * @param objectPaths The paths to search the object in. + * @return The filtered and trimmed object paths. + */ + QList< QList<QObject*> > filterObjectPaths(const QString& name, + const QList< QList<QObject*> >& objectPaths) const; + + /** + * Returns the object paths that contain a direct child from the base object + * with the given name. + * The name must be a single object name, without any ancestor name. + * The returned paths are trimmed to make the object with the given name the + * new base object of the path. + * + * @param name The name of the direct child to find. + * @param objectPaths The paths to search the object in. + * @return The filtered and trimmed object paths. + */ + QList< QList<QObject*> > filterDirectChildren(const QString& name, + const QList< QList<QObject*> >& objectPaths) const; + + /** + * Returns the object paths that contain a descendant from the base object + * with the given name. + * All the objects between the base object and the descendant with the given + * name must have no name. + * If there is more than one descendant with the given name, only the + * shallower ones are taken into account. + * The name must be a single object name, without any ancestor name. + * The returned paths are trimmed to make the object with the given name the + * new base object of the path. + * + * @param name The name of the descendant to find. + * @param objectPaths The paths to search the object in. + * @return The filtered and trimmed object paths. + */ + QList< QList<QObject*> > filterNestedChildrenWithUnnamedAncestors( + const QString& name, const QList< QList<QObject*> >& objectPaths) const; + + /** + * Returns the object paths that contain a descendant from the base object + * with the given name. + * If there is more than one descendant with the given name, only the + * shallower ones are taken into account. + * The name must be a single object name, without any ancestor name. + * The returned paths are trimmed to make the object with the given name the + * new base object of the path. + * + * @param name The name of the descendant to find. + * @param objectPaths The paths to search the object in. + * @return The filtered and trimmed object paths. + */ + QList< QList<QObject*> > filterNestedChildren(const QString& name, + const QList< QList<QObject*> >& objectPaths) const; + private slots: /** Modified: trunk/ktutorial/ktutorial-library/tests/KTutorialTest.cpp =================================================================== --- trunk/ktutorial/ktutorial-library/tests/KTutorialTest.cpp 2012-07-03 08:59:08 UTC (rev 352) +++ trunk/ktutorial/ktutorial-library/tests/KTutorialTest.cpp 2012-07-05 12:38:07 UTC (rev 353) @@ -36,6 +36,17 @@ void testFindObjectComplexNameNestedChild(); void testFindObjectComplexNameAncestorNameNotUnique(); void testFindObjectComplexNameUnknownParent(); + + void testFindObjectAmbiguousSingleNameDirectChild(); + void testFindObjectAmbiguousSingleNameNestedChildUnnamedAncestors(); + void testFindObjectAmbiguousSingleNameNestedChildUnnamedAncestorsDeeperThanNamed(); + void testFindObjectAmbiguousSingleNameNestedChildNamedAncestors(); + void testFindObjectAmbiguousSingleNameNestedChildNamedAncestorsSameDeepThanMixed(); + void testFindObjectAmbiguousSingleNameNestedChildMixedAncestorsSameDeepThanNamed(); + void testFindObjectAmbiguousComplexName(); + void testFindObjectAmbiguousComplexNameUniqueAncestor(); + void testFindObjectComplexNameDifferentAncestorIfSolvingAmbiguity(); + void testFindObjectEmptyName(); void testFindObjectSingleSlash(); void testFindObjectSlashEndedName(); @@ -54,6 +65,15 @@ QObject* mObject3_1_1; QObject* mObject3_2_1_1; QAction* mAction3_3_1_1; + QObject* mAmbiguousObject5; + QObject* mAmbiguousObject8_1_2; + QObject* mAmbiguousObject10_1; + QObject* mAmbiguousObject11_1_2; + QObject* mAmbiguousObject12_1; + QObject* mAmbiguousObject12_2_3; + QObject* mObject14_1_2; + QObject* mAmbiguousObject15_2_2_1; + QObject* mAmbiguousObject16_2_1_1_1; void assertFindObject(const QString& objectName, QObject* object) const; void assertFindAction(const QString& objectName, QAction* action) const; @@ -64,6 +84,25 @@ mMainWindow = new KXmlGuiWindow(); KTutorial::self()->setup(mMainWindow); + //-Grand parent1 + // |-Parent1 + // | |-The object + // | |-The action + // |-Parent2 + // |-The object + //-Grand parent2 + // |-Parent1 + // |-The object + // |-Another object + // |-The action + // |-Another action + //-Grand parent3 + // |-Parent1 + // | |-The object + // |-Nested parent + // | |-Another object + // |-Nested timer + // |-Another action QObject* grandParent1 = new QObject(mMainWindow); grandParent1->setObjectName("Grand parent1"); QObject* parent1_1 = new QObject(grandParent1); @@ -109,6 +148,184 @@ QTimer* parent3_3_1 = new QTimer(parent3_3); mAction3_3_1_1 = new QAction(parent3_3_1); mAction3_3_1_1->setObjectName("Another action"); + + //-??? + // |-??? + // | |-Ambiguous object + // |-Ambiguous object + //-Ambiguous object + //-Object 6 + // |-Ambiguous object + // |-Object 6_2 + // |-Ambiguous object + //-Ambiguous object + QObject* unnamedObject4 = new QObject(mMainWindow); + QObject* unnamedObject4_1 = new QObject(unnamedObject4); + QObject* ambiguousObject4_1_1 = new QObject(unnamedObject4_1); + ambiguousObject4_1_1->setObjectName("Ambiguous object"); + QObject* ambiguousObject4_2 = new QObject(unnamedObject4); + ambiguousObject4_2->setObjectName("Ambiguous object"); + + mAmbiguousObject5 = new QObject(mMainWindow); + mAmbiguousObject5->setObjectName("Ambiguous object"); + + QObject* namedObject6 = new QObject(mMainWindow); + namedObject6->setObjectName("Object 6"); + QObject* ambiguousObject6_1 = new QObject(namedObject6); + ambiguousObject6_1->setObjectName("Ambiguous object"); + QObject* namedObject6_2 = new QObject(namedObject6); + namedObject6_2->setObjectName("Object 6_2"); + QObject* ambiguousObject6_2_1 = new QObject(namedObject6_2); + ambiguousObject6_2_1->setObjectName("Ambiguous object"); + + QObject* ambiguousObject7 = new QObject(mMainWindow); + ambiguousObject7->setObjectName("Ambiguous object"); + + //-??? + // |-??? + // | |-Ambiguous object2 + // | |-Ambiguous object3 + //-Object 9 + // |-Ambiguous object2 + // |-Object 9_2 + // | |-Ambiguous object2 + // |-Ambiguous object3 + //-??? + // |-Ambiguous object2 + // |-Ambiguous object2 + QObject* unnamedObject8 = new QObject(mMainWindow); + QObject* unnamedObject8_1 = new QObject(unnamedObject8); + QObject* ambiguousObject8_1_1 = new QObject(unnamedObject8_1); + ambiguousObject8_1_1->setObjectName("Ambiguous object2"); + mAmbiguousObject8_1_2 = new QObject(unnamedObject8_1); + mAmbiguousObject8_1_2->setObjectName("Ambiguous object3"); + + QObject* namedObject9 = new QObject(mMainWindow); + namedObject9->setObjectName("Object 9"); + QObject* ambiguousObject9_1 = new QObject(namedObject9); + ambiguousObject9_1->setObjectName("Ambiguous object2"); + QObject* namedObject9_2 = new QObject(namedObject9); + namedObject9_2->setObjectName("Object 9_2"); + QObject* ambiguousObject9_2_1 = new QObject(namedObject9_2); + ambiguousObject9_2_1->setObjectName("Ambiguous object2"); + QObject* ambiguousObject9_3 = new QObject(namedObject9); + ambiguousObject9_3->setObjectName("Ambiguous object3"); + + QObject* unnamedObject10 = new QObject(mMainWindow); + mAmbiguousObject10_1 = new QObject(unnamedObject10); + mAmbiguousObject10_1->setObjectName("Ambiguous object2"); + QObject* ambiguousObject10_2 = new QObject(unnamedObject10); + ambiguousObject10_2->setObjectName("Ambiguous object2"); + + //-Object 11 + // |-Object 11_1 + // |-Ambiguous object4 + // |-Ambiguous object5 + //-Object 12 + // |-Ambiguous object4 + // |-??? + // |-Ambiguous object4 + // |-Ambiguous object5 + // |-Ambiguous object6 + //-Object 13 + // |-Ambiguous object4 + // |-Object 13_2 + // |-Ambiguous object6 + QObject* namedObject11 = new QObject(mMainWindow); + namedObject11->setObjectName("Object 11"); + QObject* namedObject11_1 = new QObject(namedObject11); + namedObject11_1->setObjectName("Object 11_1"); + QObject* ambiguousObject11_1_1 = new QObject(namedObject11_1); + ambiguousObject11_1_1->setObjectName("Ambiguous object4"); + mAmbiguousObject11_1_2 = new QObject(namedObject11_1); + mAmbiguousObject11_1_2->setObjectName("Ambiguous object5"); + + QObject* namedObject12 = new QObject(mMainWindow); + namedObject12->setObjectName("Object 12"); + mAmbiguousObject12_1 = new QObject(namedObject12); + mAmbiguousObject12_1->setObjectName("Ambiguous object4"); + QObject* unnamedObject12_2 = new QObject(namedObject12); + QObject* ambiguousObject12_2_1 = new QObject(unnamedObject12_2); + ambiguousObject12_2_1->setObjectName("Ambiguous object4"); + QObject* ambiguousObject12_2_2 = new QObject(unnamedObject12_2); + ambiguousObject12_2_2->setObjectName("Ambiguous object5"); + mAmbiguousObject12_2_3 = new QObject(unnamedObject12_2); + mAmbiguousObject12_2_3->setObjectName("Ambiguous object6"); + + QObject* namedObject13 = new QObject(mMainWindow); + namedObject13->setObjectName("Object 13"); + QObject* ambiguousObject13_1 = new QObject(namedObject13); + ambiguousObject13_1->setObjectName("Ambiguous object4"); + QObject* namedObject13_2 = new QObject(namedObject13); + namedObject13_2->setObjectName("Object 13_2"); + QObject* ambiguousObject13_2_1 = new QObject(namedObject13_2); + ambiguousObject13_2_1->setObjectName("Ambiguous object6"); + + //-Object 14 + // |-Ambiguous ancestor + // |-Ambiguous object7 + // |-The object + //-??? + // |-Ambiguous ancestor + // | |-Object 15_1_1 + // | |-Ambiguous object7 + // |-Unique ancestor + // |-Object 15_2_1 + // | |-Ambiguous object7 + // |-??? + // |-Ambiguous object7 + //-??? + // |-??? + // | |-Ambiguous ancestor + // | |-Ambiguous object7 + // |-Ambiguous ancestor + // |-??? + // | |-??? + // | |-Ambiguous object7 + // |-Object 16_2_2 + // |-Ambiguous object7 + QObject* namedObject14 = new QObject(mMainWindow); + namedObject14->setObjectName("Object 14"); + QObject* ambiguousAncestor14_1 = new QObject(namedObject14); + ambiguousAncestor14_1->setObjectName("Ambiguous ancestor"); + QObject* ambiguousObject14_1_1 = new QObject(ambiguousAncestor14_1); + ambiguousObject14_1_1->setObjectName("Ambiguous object7"); + mObject14_1_2 = new QObject(ambiguousAncestor14_1); + mObject14_1_2->setObjectName("The object"); + + QObject* unnamedObject15 = new QObject(mMainWindow); + QObject* ambiguousAncestor15_1 = new QObject(unnamedObject15); + ambiguousAncestor15_1->setObjectName("Ambiguous ancestor"); + QObject* namedObject15_1_1 = new QObject(ambiguousAncestor15_1); + namedObject15_1_1->setObjectName("Object 15_1_1"); + QObject* ambiguousObject15_1_1_1 = new QObject(namedObject15_1_1); + ambiguousObject15_1_1_1->setObjectName("Ambiguous object7"); + QObject* uniqueAncestor15_2 = new QObject(unnamedObject15); + uniqueAncestor15_2->setObjectName("Unique ancestor"); + QObject* namedObject15_2_1 = new QObject(uniqueAncestor15_2); + namedObject15_2_1->setObjectName("Object 15_2_1"); + QObject* ambiguousObject15_2_1_1 = new QObject(namedObject15_2_1); + ambiguousObject15_2_1_1->setObjectName("Ambiguous object7"); + QObject* unnamedObject15_2_2 = new QObject(uniqueAncestor15_2); + mAmbiguousObject15_2_2_1 = new QObject(unnamedObject15_2_2); + mAmbiguousObject15_2_2_1->setObjectName("Ambiguous object7"); + + QObject* unnamedObject16 = new QObject(mMainWindow); + QObject* unnamedObject16_1 = new QObject(unnamedObject16); + QObject* ambiguousAncestor16_1_1 = new QObject(unnamedObject16_1); + ambiguousAncestor16_1_1->setObjectName("Ambiguous ancestor"); + QObject* ambiguousObject16_1_1_1 = new QObject(ambiguousAncestor16_1_1); + ambiguousObject16_1_1_1->setObjectName("Ambiguous object7"); + QObject* ambiguousAncestor16_2 = new QObject(unnamedObject16); + ambiguousAncestor16_2->setObjectName("Ambiguous ancestor"); + QObject* unnamedObject16_2_1 = new QObject(ambiguousAncestor16_2); + QObject* unnamedObject16_2_1_1 = new QObject(unnamedObject16_2_1); + mAmbiguousObject16_2_1_1_1 = new QObject(unnamedObject16_2_1_1); + mAmbiguousObject16_2_1_1_1->setObjectName("Ambiguous object7"); + QObject* namedObject16_2_2 = new QObject(ambiguousAncestor16_2); + namedObject16_2_2->setObjectName("Object 16_2_2"); + QObject* ambiguousObject16_2_2_1 = new QObject(namedObject16_2_2); + ambiguousObject16_2_2_1->setObjectName("Ambiguous object7"); } void KTutorialTest::cleanupTestCase() { @@ -152,6 +369,58 @@ assertFindObject("Grand parent1/Unknown parent/The object", 0); } +void KTutorialTest::testFindObjectAmbiguousSingleNameDirectChild() { + assertFindObject("Ambiguous object", mAmbiguousObject5); +} + +void KTutorialTest:: +testFindObjectAmbiguousSingleNameNestedChildUnnamedAncestors() { + assertFindObject("Ambiguous object2", mAmbiguousObject10_1); +} + +void KTutorialTest:: +testFindObjectAmbiguousSingleNameNestedChildUnnamedAncestorsDeeperThanNamed() { + assertFindObject("Ambiguous object3", mAmbiguousObject8_1_2); +} + +void KTutorialTest:: +testFindObjectAmbiguousSingleNameNestedChildNamedAncestors() { + assertFindObject("Ambiguous object4", mAmbiguousObject12_1); +} + +void KTutorialTest:: +testFindObjectAmbiguousSingleNameNestedChildNamedAncestorsSameDeepThanMixed() { + assertFindObject("Ambiguous object5", mAmbiguousObject11_1_2); +} + +void KTutorialTest:: +testFindObjectAmbiguousSingleNameNestedChildMixedAncestorsSameDeepThanNamed() { + assertFindObject("Ambiguous object6", mAmbiguousObject12_2_3); +} + +void KTutorialTest::testFindObjectAmbiguousComplexName() { + //The ancestor is selected by the rule of shallower unnamed ancestors. The + //object is selected by the rule of unnamed ancestor even if there are + //shallower objects, but with named ancestors. + assertFindObject("Ambiguous ancestor/Ambiguous object7", + mAmbiguousObject16_2_1_1_1); +} + +void KTutorialTest::testFindObjectAmbiguousComplexNameUniqueAncestor() { + //The ancestor is unique, although the object itself is ambiguous (even + //among the descendants of that unique ancestor). + assertFindObject("Unique ancestor/Ambiguous object7", + mAmbiguousObject15_2_2_1); +} + +void KTutorialTest:: +testFindObjectComplexNameDifferentAncestorIfSolvingAmbiguity() { + //The full name is unique, but if the rules to resolve ambiguity were + //applied no object would be found, as the "Ambiguous ancestor" found using + //the ambiguity resolving rules have no "The object" descendants. + assertFindObject("Ambiguous ancestor/The object", mObject14_1_2); +} + void KTutorialTest::testFindObjectEmptyName() { assertFindObject("", 0); } This was sent by the SourceForge.net collaborative development platform, the world's largest Open Source development site. |
From: <dan...@us...> - 2012-08-14 22:34:59
|
Revision: 369 http://ktutorial.svn.sourceforge.net/ktutorial/?rev=369&view=rev Author: danxuliu Date: 2012-08-14 22:34:53 +0000 (Tue, 14 Aug 2012) Log Message: ----------- Add KTutorial version support for FindKTutorial.cmake. Modified Paths: -------------- trunk/ktutorial/ktutorial-library/CMakeLists.txt trunk/ktutorial/ktutorial-library/cmake/modules/FindKTutorial.cmake trunk/ktutorial/ktutorial-library/src/CMakeLists.txt Added Paths: ----------- trunk/ktutorial/ktutorial-library/src/version.h.cmake Modified: trunk/ktutorial/ktutorial-library/CMakeLists.txt =================================================================== --- trunk/ktutorial/ktutorial-library/CMakeLists.txt 2012-08-11 01:33:20 UTC (rev 368) +++ trunk/ktutorial/ktutorial-library/CMakeLists.txt 2012-08-14 22:34:53 UTC (rev 369) @@ -3,6 +3,12 @@ set(QT_MIN_VERSION "4.6") find_package(KDE4 REQUIRED) +####### KTutorial version ####### +set(CMAKE_KTUTORIAL_VERSION_MAJOR 0) +set(CMAKE_KTUTORIAL_VERSION_MINOR 4) +set(CMAKE_KTUTORIAL_VERSION_RELEASE 98) +set(CMAKE_KTUTORIAL_VERSION_STRING "${CMAKE_KTUTORIAL_VERSION_MAJOR}.${CMAKE_KTUTORIAL_VERSION_MINOR}.${CMAKE_KTUTORIAL_VERSION_RELEASE}") + enable_testing() add_subdirectory(cmake) Modified: trunk/ktutorial/ktutorial-library/cmake/modules/FindKTutorial.cmake =================================================================== --- trunk/ktutorial/ktutorial-library/cmake/modules/FindKTutorial.cmake 2012-08-11 01:33:20 UTC (rev 368) +++ trunk/ktutorial/ktutorial-library/cmake/modules/FindKTutorial.cmake 2012-08-14 22:34:53 UTC (rev 369) @@ -4,11 +4,12 @@ # KTUTORIAL_FOUND - system has KTutorial # KTUTORIAL_INCLUDE_DIRS - the KTutorial include directories # KTUTORIAL_LIBRARIES - link these to use KTutorial +# KTUTORIAL_VERSION - the KTutorial version (string value) # # KTUTORIAL_INCLUDE_DIR - where to find ktutorial/KTutorial.h, etc # KTUTORIAL_LIBRARY - the KTutorial library # -# Copyright (c) 2010 Daniel Calviño Sánchez <dan...@gm...> +# Copyright (c) 2010-2012 Daniel Calviño Sánchez <dan...@gm...> # # Redistribution and use is allowed according to the terms of the BSD license. # For details see the accompanying COPYING-CMAKE-SCRIPTS file. @@ -23,8 +24,18 @@ PATHS ${KDE4_LIB_DIR} ${LIB_INSTALL_DIR} ) +if(KTUTORIAL_INCLUDE_DIR) + file(READ ${KTUTORIAL_INCLUDE_DIR}/ktutorial/version.h KTUTORIAL_VERSION_CONTENT) + string(REGEX MATCH "KTUTORIAL_VERSION_STRING \"(.*)\"\n" KTUTORIAL_VERSION_MATCH "${KTUTORIAL_VERSION_CONTENT}") + if(KTUTORIAL_VERSION_MATCH) + set(KTUTORIAL_VERSION "${CMAKE_MATCH_1}") + endif(KTUTORIAL_VERSION_MATCH) +endif(KTUTORIAL_INCLUDE_DIR) + include(FindPackageHandleStandardArgs) -find_package_handle_standard_args(KTutorial DEFAULT_MSG KTUTORIAL_LIBRARY KTUTORIAL_INCLUDE_DIR) +find_package_handle_standard_args(KTutorial REQUIRED_VARS KTUTORIAL_LIBRARY KTUTORIAL_INCLUDE_DIR + VERSION_VAR KTUTORIAL_VERSION +) if(KTUTORIAL_FOUND) set(KTUTORIAL_INCLUDE_DIRS ${KTUTORIAL_INCLUDE_DIR}) Modified: trunk/ktutorial/ktutorial-library/src/CMakeLists.txt =================================================================== --- trunk/ktutorial/ktutorial-library/src/CMakeLists.txt 2012-08-11 01:33:20 UTC (rev 368) +++ trunk/ktutorial/ktutorial-library/src/CMakeLists.txt 2012-08-14 22:34:53 UTC (rev 369) @@ -13,6 +13,9 @@ add_subdirectory(editorsupport) endif (QT_QTDBUS_FOUND) +# version.h is used by FindKTutorial.cmake +configure_file(version.h.cmake ${CMAKE_CURRENT_BINARY_DIR}/version.h) + include_directories(${CMAKE_CURRENT_BINARY_DIR} ${KDE4_INCLUDES}) set(ktutorial_LIB_SRCS @@ -66,12 +69,14 @@ WaitForSignal.h WaitForStepActivation.h WaitForWindow.h + ${CMAKE_CURRENT_BINARY_DIR}/version.h ) # Hack to make headers available to other ktutorial modules (like # ktutorial-test-app) when the library is built but not installed yet. foreach(header ${ktutorial_LIB_HEADERS}) - configure_file(${CMAKE_CURRENT_SOURCE_DIR}/${header} ${ktutorial-library_BINARY_DIR}/includes/ktutorial/${header} COPYONLY) + get_filename_component(headerName ${header} NAME) + configure_file(${header} ${ktutorial-library_BINARY_DIR}/includes/ktutorial/${headerName} COPYONLY) endforeach(header) install(FILES ${ktutorial_LIB_HEADERS} DESTINATION ${INCLUDE_INSTALL_DIR}/ktutorial) Added: trunk/ktutorial/ktutorial-library/src/version.h.cmake =================================================================== --- trunk/ktutorial/ktutorial-library/src/version.h.cmake (rev 0) +++ trunk/ktutorial/ktutorial-library/src/version.h.cmake 2012-08-14 22:34:53 UTC (rev 369) @@ -0,0 +1,30 @@ +/*************************************************************************** + * Copyright (C) 2012 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 KTUTORIAL_VERSION_H +#define KTUTORIAL_VERSION_H + +#define KTUTORIAL_VERSION_STRING "${CMAKE_KTUTORIAL_VERSION_STRING}" + +#define KTUTORIAL_VERSION_MAJOR ${CMAKE_KTUTORIAL_VERSION_MAJOR} + +#define KTUTORIAL_VERSION_MINOR ${CMAKE_KTUTORIAL_VERSION_MINOR} + +#define KTUTORIAL_VERSION_RELEASE ${CMAKE_KTUTORIAL_VERSION_RELEASE} + +#endif This was sent by the SourceForge.net collaborative development platform, the world's largest Open Source development site. |