[Ktutorial-commits] SF.net SVN: ktutorial:[360] trunk/ktutorial
Status: Alpha
Brought to you by:
danxuliu
From: <dan...@us...> - 2012-08-10 10:57:43
|
Revision: 360 http://ktutorial.svn.sourceforge.net/ktutorial/?rev=360&view=rev Author: danxuliu Date: 2012-08-10 10:57:33 +0000 (Fri, 10 Aug 2012) Log Message: ----------- Improve the unique name generation to take into account ambiguity solving rules. Now only objects with a unique name (or a unique name after applying the ambiguity solving rules) can be chosen by the user; if he tries to chose an object that has no unique name a warning is shown. Also, the concept of "best name" is introduced, so the objects that have no unique name are still shown in the completion box with their full path to help the user identify them and fix the target application. Modified Paths: -------------- trunk/ktutorial/ktutorial-editor/src/targetapplication/RemoteEditorSupport.cpp trunk/ktutorial/ktutorial-editor/src/targetapplication/RemoteEditorSupport.h trunk/ktutorial/ktutorial-editor/src/view/RemoteObjectNameRegister.cpp trunk/ktutorial/ktutorial-editor/src/view/RemoteObjectNameRegister.h trunk/ktutorial/ktutorial-editor/src/view/RemoteObjectNameWidget.cpp trunk/ktutorial/ktutorial-editor/src/view/RemoteObjectNameWidget.h trunk/ktutorial/ktutorial-editor/tests/unit/targetapplication/RemoteClassStubs.h trunk/ktutorial/ktutorial-editor/tests/unit/targetapplication/RemoteEditorSupportTest.cpp trunk/ktutorial/ktutorial-editor/tests/unit/targetapplication/RemoteObjectTest.cpp trunk/ktutorial/ktutorial-editor/tests/unit/view/RemoteObjectNameRegisterTest.cpp trunk/ktutorial/ktutorial-editor/tests/unit/view/RemoteObjectNameWidgetTest.cpp trunk/ktutorial/ktutorial-library/src/KTutorial.cpp 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/editorsupport/EditorSupportAdaptorTest.cpp trunk/ktutorial/ktutorial-library/tests/editorsupport/EditorSupportTest.cpp Modified: trunk/ktutorial/ktutorial-editor/src/targetapplication/RemoteEditorSupport.cpp =================================================================== --- trunk/ktutorial/ktutorial-editor/src/targetapplication/RemoteEditorSupport.cpp 2012-08-09 15:59:47 UTC (rev 359) +++ trunk/ktutorial/ktutorial-editor/src/targetapplication/RemoteEditorSupport.cpp 2012-08-10 10:57:33 UTC (rev 360) @@ -1,5 +1,5 @@ /*************************************************************************** - * Copyright (C) 2010-2011 by Daniel Calviño Sánchez * + * Copyright (C) 2010-2012 by Daniel Calviño Sánchez * * dan...@gm... * * * * This program is free software; you can redistribute it and/or modify * @@ -49,6 +49,16 @@ return mMapper->remoteObject(reply.value()); } +RemoteObject* RemoteEditorSupport::findObject(const QString& name) + throw (DBusException) { + QDBusReply<int> reply = call("findObject", name); + if (!reply.isValid()) { + throw DBusException(reply.error().message()); + } + + return mMapper->remoteObject(reply.value()); +} + void RemoteEditorSupport::highlight(RemoteObject* remoteWidget) throw (DBusException) { QDBusReply<void> reply = call("highlight", remoteWidget->objectId()); Modified: trunk/ktutorial/ktutorial-editor/src/targetapplication/RemoteEditorSupport.h =================================================================== --- trunk/ktutorial/ktutorial-editor/src/targetapplication/RemoteEditorSupport.h 2012-08-09 15:59:47 UTC (rev 359) +++ trunk/ktutorial/ktutorial-editor/src/targetapplication/RemoteEditorSupport.h 2012-08-10 10:57:33 UTC (rev 360) @@ -1,5 +1,5 @@ /*************************************************************************** - * Copyright (C) 2010-2011 by Daniel Calviño Sánchez * + * Copyright (C) 2010-2012 by Daniel Calviño Sánchez * * dan...@gm... * * * * This program is free software; you can redistribute it and/or modify * @@ -70,6 +70,15 @@ RemoteObject* mainWindow() throw (DBusException); /** + * Returns the RemoteObject with the given name. + * The name can include ancestor names. + * + * @param name The name of the RemoteObject to find. + * @return The RemoteObject with the given name, or 0 if there is none. + */ + RemoteObject* findObject(const QString& name) throw (DBusException); + + /** * Highlights the widget represented by the given remote object. * If the object does not represent a widget nothing is highlighted. * Modified: trunk/ktutorial/ktutorial-editor/src/view/RemoteObjectNameRegister.cpp =================================================================== --- trunk/ktutorial/ktutorial-editor/src/view/RemoteObjectNameRegister.cpp 2012-08-09 15:59:47 UTC (rev 359) +++ trunk/ktutorial/ktutorial-editor/src/view/RemoteObjectNameRegister.cpp 2012-08-10 10:57:33 UTC (rev 360) @@ -52,60 +52,58 @@ QString RemoteObjectNameRegister::uniqueName(RemoteObject* remoteObject) const throw (DBusException) { - QString name = remoteObject->name(); - if (name.isEmpty()) { - return ""; - } + QStringList reversedPath = bestNameAsReversedPath(remoteObject); + QString name = reversedPathAsName(reversedPath); QList<QStringList> reversedPathsToHomonyms = reversedPathsToHomonymsOf(remoteObject); - if (reversedPathsToHomonyms.count() == 0) { + if (isUniquePath(reversedPath, reversedPathsToHomonyms)) { return name; } - QStringList reversedFullPath = reversedPathTo(remoteObject); - - for (int i=1; i<reversedFullPath.size(); ++i) { - if (ancestorNotInPaths(reversedFullPath[i], reversedPathsToHomonyms)) { - return reversedFullPath[i] + '/' + reversedFullPath[0]; - } + //Although the name is ambiguous, it identifies the given remote object + if (findRemoteObject(name) == remoteObject) { + return name; } - QStringList reversedUniquePath; - reversedUniquePath.append(reversedFullPath[0]); - - for (int i=1; i<reversedFullPath.size(); ++i) { - reversedUniquePath.append(reversedFullPath[i]); - - if (isUniquePath(reversedUniquePath, reversedPathsToHomonyms)) { - return reversedPathAsName(reversedUniquePath); - } - } - - return reversedPathAsName(reversedUniquePath); + return ""; } -QStringList RemoteObjectNameRegister::uniqueNames(const QString& name) const +QStringList RemoteObjectNameRegister::bestNames(const QString& name) const throw (DBusException) { Q_ASSERT(mRemoteObjectForName.values(name).count() > 0); - QStringList uniqueNames; + QStringList bestNames; if (mRemoteObjectForName.values(name).count() <= 1) { - uniqueNames.append(name); - return uniqueNames; + bestNames.append(name); + return bestNames; } foreach (RemoteObject* remoteObject, mRemoteObjectForName.values(name)) { - uniqueNames.append(uniqueName(remoteObject)); + bestNames.append(bestName(remoteObject)); } - return uniqueNames; + return bestNames; } + +//As KTutorial applies several rules to resolve ambiguous names (a name that +//represents two or more objects), and querying the editor support is relatively +//quick (around 5-6 miliseconds on average for Showfoto on a computer from the +//year 2002), the target application itself is queried instead of reimplementing +//those rules in the editor, as they would be very cumbersome to be tested +//properly, and prevents having to duplicate the changes when some rule is +//modified in the library. RemoteObject* RemoteObjectNameRegister::findRemoteObject(const QString& name) - const { - return findRemoteObject(name, 0); + const +throw (DBusException) { + if (TargetApplication::self()->remoteEditorSupport()) { + return TargetApplication::self()->remoteEditorSupport()-> + findObject(name); + } + + return 0; } bool RemoteObjectNameRegister::isBeingUpdated() const { @@ -149,13 +147,78 @@ } } +QString RemoteObjectNameRegister::bestName(RemoteObject* remoteObject) const +throw (DBusException) { + return reversedPathAsName(bestNameAsReversedPath(remoteObject)); +} + +QStringList RemoteObjectNameRegister::bestNameAsReversedPath( + RemoteObject* remoteObject) const +throw (DBusException) { + QStringList reversedUniquePath; + + QString name = remoteObject->name(); + if (name.isEmpty()) { + return reversedUniquePath; + } + + reversedUniquePath.append(name); + + QList<QStringList> reversedPathsToHomonyms = + reversedPathsToHomonymsOf(remoteObject); + if (reversedPathsToHomonyms.count() == 0) { + return reversedUniquePath; + } + + QStringList reversedFullPath = reversedPathTo(remoteObject); + + //Get deepest ancestor with unique name + int uniqueAncestorIndex = -1; + for (int i=1; i<reversedFullPath.size() && uniqueAncestorIndex == -1; ++i) { + if (mRemoteObjectForName.values(reversedFullPath[i]).count() == 1) { + uniqueAncestorIndex = i; + } + } + + //If there is an ancestor with a unique name and it has only one descendant + //with the name of the remote object (that is, the remote object itself), + //return "ancestor/object". + if (uniqueAncestorIndex != -1 && + ancestorNotInPaths(reversedFullPath[uniqueAncestorIndex], + reversedPathsToHomonyms)) { + reversedUniquePath.append(reversedFullPath[uniqueAncestorIndex]); + return reversedUniquePath; + } + + //If there is more than one descendant with that name, mark the ancestor + //with the unique name as the limit to descend when looking for a unique + //path + int limit = uniqueAncestorIndex; + if (limit == -1) { + //If no ancestor has a unique name, mark the shallowest ancestor as the + //limit to descend + limit = reversedFullPath.size() - 1; + } + + //Add ancestors to the path until limit or until a unique path is found + for (int i=1; i <= limit; ++i) { + reversedUniquePath.append(reversedFullPath[i]); + + if (isUniquePath(reversedUniquePath, reversedPathsToHomonyms)) { + return reversedUniquePath; + } + } + + return reversedUniquePath; +} + QStringList RemoteObjectNameRegister::reversedPathTo( RemoteObject* remoteObject) const throw (DBusException) { QStringList reversedPath; RemoteObject* parent = remoteObject; - while (parent) { + while (parent && mRemoteObjectForParent.key(parent)) { QString name = parent->name(); if (!name.isEmpty() && !name.startsWith(QLatin1String("qt_"))) { reversedPath.append(name); @@ -222,6 +285,10 @@ QString RemoteObjectNameRegister::reversedPathAsName( const QStringList& reversedPath) const { + if (reversedPath.isEmpty()) { + return ""; + } + QString name = reversedPath[0]; for (int i=1; i<reversedPath.size(); ++i) { name = reversedPath[i] + '/' + name; @@ -230,56 +297,6 @@ return name; } -RemoteObject* RemoteObjectNameRegister::findRemoteObject(const QString& name, - RemoteObject* ancestor) const { - if (name.indexOf('/') == -1) { - QList<RemoteObject*> remoteObjects = mRemoteObjectForName.values(name); - foreach (RemoteObject* remoteObject, remoteObjects) { - if (isDescendantOf(remoteObject, ancestor)) { - return remoteObject; - } - } - - return 0; - } - - QRegExp slashPattern("/+"); - QString ancestorName = name.left(name.indexOf(slashPattern)); - QString descendantName = name.mid(ancestorName.length() + - slashPattern.matchedLength()); - - QList<RemoteObject*> namedAncestors = - mRemoteObjectForName.values(ancestorName); - - foreach (RemoteObject* namedAncestor, namedAncestors) { - if (isDescendantOf(namedAncestor, ancestor)) { - RemoteObject* remoteObject = findRemoteObject(descendantName, - namedAncestor); - if (remoteObject) { - return remoteObject; - } - } - } - - return 0; -} - -bool RemoteObjectNameRegister::isDescendantOf(RemoteObject* remoteObject, - RemoteObject* ancestor) const { - if (!ancestor) { - return true; - } - - QList<RemoteObject*> children = mRemoteObjectForParent.values(ancestor); - foreach (RemoteObject* child, children) { - if (child == remoteObject || isDescendantOf(remoteObject, child)) { - return true; - } - } - - return false; -} - void RemoteObjectNameRegister::startNameUpdate() { mIsBeingUpdated = true; emit nameUpdateStarted(); Modified: trunk/ktutorial/ktutorial-editor/src/view/RemoteObjectNameRegister.h =================================================================== --- trunk/ktutorial/ktutorial-editor/src/view/RemoteObjectNameRegister.h 2012-08-09 15:59:47 UTC (rev 359) +++ trunk/ktutorial/ktutorial-editor/src/view/RemoteObjectNameRegister.h 2012-08-10 10:57:33 UTC (rev 360) @@ -41,9 +41,31 @@ * object can be got using uniqueName(RemoteObject*). Also, given a name, the * remote object that it represents can be got using findObject(QString). An * unqualified name (without any ancestor names, just the name of the remote - * object itself) can be used to get the unique names of all the remote objects + * object itself) can be used to get the best names of all the remote objects * represented by that unqualified name. * + * The best name and the unique name of a remote object are tightly related. + * When the name of a remote object is unique by itself, the best name of the + * remote object is the name itself. + * When there are other remote objects with the same name, but the remote object + * has an ancestor with a unique name, and the remote object is the only + * descendant of that ancestor with that name, its best name (which is also + * unique) is the name of the ancestor and the name of the remote object. The + * ancestor with a unique name used is the nearest one to the remote object + * (parent preferred to grandparent, grandparent preferred to great-grandparent + * and so on). + * If there are more descendants of the ancestor with that name, or if there + * is no ancestor with a unique name, the best name is composed by the name of + * the remote object itself and the name of as many ancestors as needed to + * obtain a unique name. + * If there is no unique name for the remote object, the best name is composed + * by the name of the remote object itself and the name of all of its ancestors + * from the remote object to the deepest ancestor with a unique name, or all its + * ancestors if none has a unique name. + * A best name that is ambiguous, that is, identifies more than one remote + * object, may become unique if the ambiguity solving rules from KTutorial are + * taken into account. + * * Note that a name and the remote object it represents depends on the state of * the target application. For example, if there is a dialog named * "Configuration dialog" with a button named "Ok button", its unique name could @@ -97,51 +119,40 @@ /** * Returns a unique name for the given remote object. - * When the remote object name is unique by itself, its name is returned. - * When there are other remote objects with the same name as the given one, - * but it has an ancestor with a unique name, the returned name includes - * both names. The ancestor with a unique name used is the nearest one to - * the remote object (parent preferred to grandparent, grandparent preferred - * to great-grandparent and so on). - * When there are other remote objects with the same name as the given one, - * and no ancestor has a unique name, the returned name includes as many - * ancestor names as necessary to create a name unique to the given remote - * object. - * + * If the best name of the given remote object is unique, or if it is not + * unique, but the object found when applying the ambiguity solving rules is + * the given remote object, the best name is returned. + * Otherwise, there is no unique name for the given remote object, and an + * empty string is returned instead. + * * @param remoteObject The remote object to get its unique name. - * @return A unique name for the given remote object. + * @return A unique name for the given remote object, if any. * @throws DBusException If a DBus error happens. */ QString uniqueName(RemoteObject* remoteObject) const throw (DBusException); /** - * Returns the unique names of the remote objects that have the given name. + * Returns the best names of the remote objects that have the given name. * The given name can not contain any ancestor names, and it must be a * registered name. * - * @param name The name of the remote objects to get their unique names. - * @return The unique names of the remote objects that have the given name. + * @param name The name of the remote objects to get their best names. + * @return The best names of the remote objects that have the given name. * @throws DBusException If a DBus error happens. */ - QStringList uniqueNames(const QString& name) const throw (DBusException); + QStringList bestNames(const QString& name) const throw (DBusException); /** * Returns the remote object with the given name, if any. - * When the name of the desired remote object is not unique the name of some - * ancestor must be included. Ancestor names are separated using a "/". That - * is, "Ancestor name/The remote object with a repeated name". As many - * ancestor names as desired can be included, not just one. - * The name of the ancestors does not need to be unique either; what has to - * be unique is the full path to the remote object to find. For example, - * "Ancestor name not unique/The remote object to find" is valid if, among - * all the remote objects called "Ancestor name not unique", there is only - * one that has a descendant called "The remote object to find". + * The editor support module in the target application is queried to find + * the object with the given name. * * @param name The name of the remote object to find. * @return The remote object with the specified name, or a null pointer if * there is none. */ - RemoteObject* findRemoteObject(const QString& name) const; + RemoteObject* findRemoteObject(const QString& name) const + throw (DBusException); /** * Returns whether the names are being registered or not. @@ -229,12 +240,32 @@ throw (DBusException); /** + * Returns the best name for the given remote object. + * + * @param remoteObject The remote object to get its best name. + * @return The best name of the given remote object. + * @throws DBusException If a DBus error happens. + */ + QString bestName(RemoteObject* remoteObject) const + throw (DBusException); + + /** + * Returns the best name for the given remote object as a reversed path. + * + * @param remoteObject The remote object to get its best name. + * @return The reversed path for the best name of the given remote object. + * @throws DBusException If a DBus error happens. + */ + QStringList bestNameAsReversedPath(RemoteObject* remoteObject) const + throw (DBusException); + + /** * Returns the reversed path to the given remote object. * The path contains the name of the remote object itself and all its named - * ancestors. The order of the items is reversed from the natural path, that - * is, the first item in the returned path is the remote object name, the - * second item is the name of its parent, the third is the name of its - * grandparent... + * ancestors (except for the root ancestor). The order of the items is + * reversed from the natural path, that is, the first item in the returned + * path is the remote object name, the second item is the name of its + * parent, the third is the name of its grandparent... * Empty names and Qt default names (like "qt_scrollarea_viewport") are not * included in the path. * @@ -311,6 +342,7 @@ * The name contains all the items in the path separated by "/". The order * of the items in the name is their natural order, that is, the last item * is the first one, the penultimate is the second one... + * If the given path is empty an empty string is returned. * * @param path The reversed path to get its equivalent name. * @return The name equivalent to the given reversed path. @@ -318,31 +350,6 @@ QString reversedPathAsName(const QStringList& reversedPath) const; /** - * Returns the remote object with the given name, if any. - * The name can contain also the ancestor names, separated by "/". The - * first object that matches the whole path is returned (note that ancestor - * are not necessarily direct parents). - * - * @param name The name of the remote object to find. - * @param ancestor The ancestor to look the remote object in. - * @return The remote object with the specified name, or a null pointer if - * there is none. - */ - RemoteObject* findRemoteObject(const QString& name, RemoteObject* ancestor) - const; - - /** - * Returns true if remoteObject is descendant of ancestor, false otherwise. - * When ancestor is null, it always returns true. - * - * @param remoteObject The remote object to check. - * @param ancestor The ancestor to check. - * @return True if remoteObject is descendant of ancestor, false otherwise. - */ - bool isDescendantOf(RemoteObject* remoteObject, - RemoteObject* ancestor) const; - - /** * Sets this RemoteObjectNameRegister as being updated and emits the * nameUpdateStarted() signal. */ Modified: trunk/ktutorial/ktutorial-editor/src/view/RemoteObjectNameWidget.cpp =================================================================== --- trunk/ktutorial/ktutorial-editor/src/view/RemoteObjectNameWidget.cpp 2012-08-09 15:59:47 UTC (rev 359) +++ trunk/ktutorial/ktutorial-editor/src/view/RemoteObjectNameWidget.cpp 2012-08-10 10:57:33 UTC (rev 360) @@ -32,7 +32,10 @@ * The items added for completion should be the unqualified remote object names, * that is, just the name of the remote objects, without any ancestor. When a * match is found, and it represents more than one remote object, the match is - * replaced by the unique names of its remote objects. + * replaced by the best names of its remote objects. Note that an object without + * a unique name will have the same best name as another object. Showing two or + * more objects with the same best name in the completion list will hopefully + * help the user to identify problems with the names in the target application. */ class RemoteObjectNameCompletion: public KCompletion { public: @@ -64,30 +67,30 @@ /** * Processes the matches to provide unique names. * When a match is a name that represents several remote objects that match - * is replaced by all the unique names of the remote objects it represents. + * is replaced by the best names of the remote objects it represents. * * @param matches The matches to process. */ virtual void postProcessMatches(QStringList* matches) const { QMutableListIterator<QString> it(*matches); while (it.hasNext()) { - QStringList uniqueNames; + QStringList bestNames; try { - uniqueNames = mNameRegister->uniqueNames(it.next()); + bestNames = mNameRegister->bestNames(it.next()); } catch (DBusException e) { kWarning() << "The unique names for the remote objects named " << it.value() << "could not be added to the " << "completion matches (" << e.message() << ")"; } - if (uniqueNames.count() > 1) { + if (bestNames.count() > 1) { it.remove(); - qSort(uniqueNames); + qSort(bestNames); - foreach (const QString& uniqueName, uniqueNames) { - it.insert(uniqueName); + foreach (const QString& bestName, bestNames) { + it.insert(bestName); } } } @@ -193,16 +196,29 @@ return; } + QString uniqueName; try { - ui->objectNameLineEdit->setText( - mRemoteObjectNameRegister->uniqueName(remoteObject)); + uniqueName = mRemoteObjectNameRegister->uniqueName(remoteObject); } catch (DBusException e) { QString text = i18nc("@label", "The object name can not be set, there " "was a problem getting the name from the target application: %1", e.message()); QString title = i18nc("@title", "Can't communicate with the target " "application"); KMessageBox::sorry(this, text, title); + return; } + + if (uniqueName.isEmpty()) { + QString text = i18nc("@label", "There is no unique name for the chosen " +"object (at least, in the current state of the target application), so it is " +"not possible to refer to that object in a tutorial. The target application " +"must be modified to provide a unique name for that object."); + QString title = i18nc("@title", "The chosen object has no unique name"); + KMessageBox::sorry(this, text, title); + return; + } + + ui->objectNameLineEdit->setText(uniqueName); } void RemoteObjectNameWidget::handleNameChanged(const QString& name) { @@ -211,7 +227,16 @@ return; } - emit remoteObjectChosen(mRemoteObjectNameRegister->findRemoteObject(name)); + RemoteObject* remoteObject; + try { + remoteObject = mRemoteObjectNameRegister->findRemoteObject(name); + } catch (DBusException e) { + kWarning() << "There was a problem finding the remote object (" + << e.message() << ")."; + return; + } + + emit remoteObjectChosen(remoteObject); } void RemoteObjectNameWidget::handleCompletion() { Modified: trunk/ktutorial/ktutorial-editor/src/view/RemoteObjectNameWidget.h =================================================================== --- trunk/ktutorial/ktutorial-editor/src/view/RemoteObjectNameWidget.h 2012-08-09 15:59:47 UTC (rev 359) +++ trunk/ktutorial/ktutorial-editor/src/view/RemoteObjectNameWidget.h 2012-08-10 10:57:33 UTC (rev 360) @@ -39,7 +39,7 @@ * in the target application. If there is no target application running, no * completion is provided. As soon as it starts, the completion is enabled. * When the completion matches contain a name that represents several remote - * objects that match is replaced by the unique name of each remote object. + * objects that match is replaced by the best name of each remote object. * * When a name is set in the line edit the signal * remoteObjectChosen(RemoteObject*) is emitted. @@ -159,14 +159,17 @@ * If the name register is being updated, nothing will be done, but marking * setting the chosen remote object as a pending operation. * If the given remote object is null no name is set. + * If the given remote object has no unique name, no name is set and a + * message box is shown to inform the user that the target application must + * be modified in order to be able to use that object in a tutorial. * * @param remoteObject The chosen RemoteObject. */ void setChosenRemoteObject(RemoteObject* remoteObject); /** - * Emits remoteObjectChosen(RemoteObject*) with the remote object with the - * given name. + * Emits remoteObjectChosen(RemoteObject*) with the remote object found with + * the given name (which can include ancestor names). * If the name register is being updated, nothing will be done, but marking * handling the name change as a pending operation. * Modified: trunk/ktutorial/ktutorial-editor/tests/unit/targetapplication/RemoteClassStubs.h =================================================================== --- trunk/ktutorial/ktutorial-editor/tests/unit/targetapplication/RemoteClassStubs.h 2012-08-09 15:59:47 UTC (rev 359) +++ trunk/ktutorial/ktutorial-editor/tests/unit/targetapplication/RemoteClassStubs.h 2012-08-10 10:57:33 UTC (rev 360) @@ -1,5 +1,5 @@ /*************************************************************************** - * Copyright (C) 2010-2011 by Daniel Calviño Sánchez * + * Copyright (C) 2010-2012 by Daniel Calviño Sánchez * * dan...@gm... * * * * This program is free software; you can redistribute it and/or modify * @@ -101,21 +101,36 @@ * | | |... * | |... * |-8: "The object name 8" - * |-80: "" (The class name 80) - * | |-800: "Duplicated object" - * | |-801: "The object name 801" - * | |-802: "" - * | |-803: "The object name 803" - * |-81: "" (QWidgetChildChild) - * | |-810: "" - * | |-811: "" - * | |-812: "" - * | |-813: "" - * |-82: "The object name 82" (ChildChildQWidget) - * | |-820: "The object name 820" + * | |-80: "" (The class name 80) + * | | |-800: "Duplicated object" + * | | |-801: "The object name 801" + * | | |-802: "" + * | | |-803: "The object name 803" + * | |-81: "" (QWidgetChildChild) + * | | |-810: "" + * | | |-811: "" + * | | |-812: "" + * | | |-813: "" + * | |-82: "The object name 82" (ChildChildQWidget) + * | | |-820: "The object name 820" + * | | |... + * | |-83: "The object name 83" (The class name 83) + * | |-830: "The object name 830" (ChildQWidget) + * | |... + * |-9: "Duplicated grandparent" + * |-90: "The object name 90" + * | |-900: "Duplicated object" + * | |-901: "Duplicated object" * | |... - * |-83: "The object name 83" (The class name 83) - * |-830: "The object name 830" (ChildQWidget) + * |-91: "Another duplicated parent" + * | |-910: "Duplicated object" + * | |... + * |-92: "Another duplicated parent" + * | |-920: "Duplicated object" + * | |... + * |-93: "" + * |-930: "Duplicated object" + * |-931: "Duplicated object" * |... */ class StubObjectRegisterAdaptor: public QDBusAbstractAdaptor { @@ -130,7 +145,9 @@ QString objectName(int objectId) { if (objectId == 500 || objectId == 600 || objectId == 700 || - objectId == 800) { + objectId == 800 || objectId == 900 || objectId == 901 || + objectId == 910 || objectId == 920 || objectId == 930 || + objectId == 931) { return "Duplicated object"; } @@ -138,13 +155,17 @@ return "Duplicated parent"; } - if (objectId == 5 || objectId == 6) { + if (objectId == 91 || objectId == 92) { + return "Another duplicated parent"; + } + + if (objectId == 5 || objectId == 6 || objectId == 9) { return "Duplicated grandparent"; } if (objectId == 80 || objectId == 81 || objectId == 802 || objectId == 810 || objectId == 811 || objectId == 812 || - objectId == 813) { + objectId == 813 || objectId == 93) { return ""; } @@ -186,6 +207,7 @@ ids.append(6); ids.append(7); ids.append(8); + ids.append(9); } return ids; @@ -230,6 +252,51 @@ return 42; } + int findObject(const QString& name) { + //Used in RemoteEditorSupportTest + if (name == "The object name 423") { + return 423; + } + + //Used in WaitForPropertyWidgetTest + if (name == "The object name 830") { + return 830; + } + + //Used in RemoteObjectNameRegisterTest/RemoteObjectNameWidgetTest + if (name == "The object name 50/Duplicated object") { + return 500; + } + + if (name == "The object name 501") { + return 501; + } + + if (name == "Duplicated grandparent/Duplicated parent/" + "Duplicated object") { + return 600; + } + + if (name == "The object name 7/Duplicated object") { + return 700; + } + + if (name == "The object name 90/Duplicated object") { + return 900; + } + + if (name == "Duplicated grandparent/Another duplicated parent/" + "Duplicated object") { + return 910; + } + + if (name == "Duplicated grandparent/Duplicated object") { + return 930; + } + + return 0; + } + void highlight(int objectId) { mHighlightRemoteWidgetIds.append(objectId); } Modified: trunk/ktutorial/ktutorial-editor/tests/unit/targetapplication/RemoteEditorSupportTest.cpp =================================================================== --- trunk/ktutorial/ktutorial-editor/tests/unit/targetapplication/RemoteEditorSupportTest.cpp 2012-08-09 15:59:47 UTC (rev 359) +++ trunk/ktutorial/ktutorial-editor/tests/unit/targetapplication/RemoteEditorSupportTest.cpp 2012-08-10 10:57:33 UTC (rev 360) @@ -1,5 +1,5 @@ /*************************************************************************** - * Copyright (C) 2010-2011 by Daniel Calviño Sánchez * + * Copyright (C) 2010-2012 by Daniel Calviño Sánchez * * dan...@gm... * * * * This program is free software; you can redistribute it and/or modify * @@ -50,6 +50,9 @@ void testMainWindowTwice(); void testMainWindowWhenRemoteEditorSupportIsNotAvailable(); + void testFindObject(); + void testFindObjectWhenRemoteEditorSupportIsNotAvailable(); + void testHighlight(); void testHighlightWhenRemoteEditorSupportIsNotAvailable(); @@ -132,6 +135,28 @@ EXPECT_EXCEPTION(remoteEditorSupport.mainWindow(), DBusException); } +void RemoteEditorSupportTest::testFindObject() { + RemoteObjectMapper mapper(QDBusConnection::sessionBus().baseService()); + RemoteEditorSupport remoteEditorSupport( + QDBusConnection::sessionBus().baseService(), &mapper); + + RemoteObject* object = remoteEditorSupport.mainWindow()->children()[3]; + + QCOMPARE(remoteEditorSupport.findObject("The object name 423"), object); +} + +void RemoteEditorSupportTest:: +testFindObjectWhenRemoteEditorSupportIsNotAvailable() { + RemoteObjectMapper mapper(QDBusConnection::sessionBus().baseService()); + RemoteEditorSupport remoteEditorSupport( + QDBusConnection::sessionBus().baseService(), &mapper); + + QDBusConnection::sessionBus().unregisterObject("/ktutorial"); + + EXPECT_EXCEPTION(remoteEditorSupport.findObject("The object name 423"), + DBusException); +} + void RemoteEditorSupportTest::testHighlight() { RemoteObjectMapper mapper(QDBusConnection::sessionBus().baseService()); RemoteEditorSupport remoteEditorSupport( Modified: trunk/ktutorial/ktutorial-editor/tests/unit/targetapplication/RemoteObjectTest.cpp =================================================================== --- trunk/ktutorial/ktutorial-editor/tests/unit/targetapplication/RemoteObjectTest.cpp 2012-08-09 15:59:47 UTC (rev 359) +++ trunk/ktutorial/ktutorial-editor/tests/unit/targetapplication/RemoteObjectTest.cpp 2012-08-10 10:57:33 UTC (rev 360) @@ -1,5 +1,5 @@ /*************************************************************************** - * Copyright (C) 2010-2011 by Daniel Calviño Sánchez * + * Copyright (C) 2010-2012 by Daniel Calviño Sánchez * * dan...@gm... * * * * This program is free software; you can redistribute it and/or modify * @@ -122,7 +122,7 @@ RemoteObject remoteObject(mService, mMapper, 42); QList<RemoteObject*> children = remoteObject.children(); - QCOMPARE(children.count(), 8); + QCOMPARE(children.count(), 9); QCOMPARE(children[0]->objectId(), 420); QCOMPARE(children[1]->objectId(), 421); QCOMPARE(children[2]->objectId(), 422); @@ -131,6 +131,7 @@ QCOMPARE(children[5]->objectId(), 6); QCOMPARE(children[6]->objectId(), 7); QCOMPARE(children[7]->objectId(), 8); + QCOMPARE(children[8]->objectId(), 9); } void RemoteObjectTest::testChildrenWhenRemoteObjectIsNotAvailable() { Modified: trunk/ktutorial/ktutorial-editor/tests/unit/view/RemoteObjectNameRegisterTest.cpp =================================================================== --- trunk/ktutorial/ktutorial-editor/tests/unit/view/RemoteObjectNameRegisterTest.cpp 2012-08-09 15:59:47 UTC (rev 359) +++ trunk/ktutorial/ktutorial-editor/tests/unit/view/RemoteObjectNameRegisterTest.cpp 2012-08-10 10:57:33 UTC (rev 360) @@ -50,6 +50,9 @@ void testFindRemoteObjectWithParentName(); void testFindRemoteObjectWithGrandparentName(); void testFindRemoteObjectWithParentAndGrandparentNames(); + void testFindRemoteObjectWithAmbiguousNameAndUniqueParent(); + void testFindRemoteObjectWithAmbiguousNameAndDuplicatedParent(); + void testFindRemoteObjectWithAmbiguousNameAndEmptyParent(); void testFindRemoteObjectWithUnknownName(); void testUniqueName(); @@ -57,10 +60,14 @@ void testUniqueNameWhenUniqueGrandparentAndEmptyParent(); void testUniqueNameWhenUniqueGrandparentAndDuplicatedParent(); void testUniqueNameWhenUniqueUnionOfGrandparentAndParent(); + void testUniqueNameWhenAmbiguousNameWithUniqueParent(); + void testUniqueNameWhenAmbiguousNameWithDuplicatedParent(); + void testUniqueNameWhenAmbiguousNameWithEmptyParent(); void testUniqueNameWhenEmptyName(); + void testUniqueNameWhenNameNotUnique(); - void testUniqueNames(); - void testUniqueNamesWithSingleRemoteObject(); + void testBestNames(); + void testBestNamesWithSingleRemoteObject(); private: @@ -133,7 +140,7 @@ QCOMPARE(nameUpdateFinishedSpy.count(), 1); assertNames(remoteObjectNameRegister.names()); - QCOMPARE(nameAddedSpy.count(), 82); + QCOMPARE(nameAddedSpy.count(), 102); QCOMPARE(nameAddedSpy.at(0).at(0).toString(), QString("The object name 42")); QCOMPARE(nameAddedSpy.at(1).at(0).toString(), @@ -305,6 +312,63 @@ mainWindow->children()[5]->children()[0]->children()[0]); } +void RemoteObjectNameRegisterTest:: + testFindRemoteObjectWithAmbiguousNameAndUniqueParent() { + TargetApplication::self()->setTargetApplicationFilePath(mPath); + TargetApplication::self()->start(); + + QVERIFY(waitForTargetApplicationToStart(10000)); + + RemoteObjectNameRegister remoteObjectNameRegister; + + QVERIFY(waitForNamesToBeRegistered(remoteObjectNameRegister, 10000)); + + RemoteObject* mainWindow = + TargetApplication::self()->remoteEditorSupport()->mainWindow(); + + QCOMPARE(remoteObjectNameRegister.findRemoteObject( + "The object name 90/Duplicated object"), + mainWindow->children()[8]->children()[0]->children()[0]); +} + +void RemoteObjectNameRegisterTest:: + testFindRemoteObjectWithAmbiguousNameAndDuplicatedParent() { + TargetApplication::self()->setTargetApplicationFilePath(mPath); + TargetApplication::self()->start(); + + QVERIFY(waitForTargetApplicationToStart(10000)); + + RemoteObjectNameRegister remoteObjectNameRegister; + + QVERIFY(waitForNamesToBeRegistered(remoteObjectNameRegister, 10000)); + + RemoteObject* mainWindow = + TargetApplication::self()->remoteEditorSupport()->mainWindow(); + + QCOMPARE(remoteObjectNameRegister.findRemoteObject( + "Duplicated grandparent/Another duplicated parent/Duplicated object"), + mainWindow->children()[8]->children()[1]->children()[0]); +} + +void RemoteObjectNameRegisterTest:: + testFindRemoteObjectWithAmbiguousNameAndEmptyParent() { + TargetApplication::self()->setTargetApplicationFilePath(mPath); + TargetApplication::self()->start(); + + QVERIFY(waitForTargetApplicationToStart(10000)); + + RemoteObjectNameRegister remoteObjectNameRegister; + + QVERIFY(waitForNamesToBeRegistered(remoteObjectNameRegister, 10000)); + + RemoteObject* mainWindow = + TargetApplication::self()->remoteEditorSupport()->mainWindow(); + + QCOMPARE(remoteObjectNameRegister.findRemoteObject( + "Duplicated grandparent/Duplicated object"), + mainWindow->children()[8]->children()[3]->children()[0]); +} + void RemoteObjectNameRegisterTest::testFindRemoteObjectWithUnknownName() { TargetApplication::self()->setTargetApplicationFilePath(mPath); TargetApplication::self()->start(); @@ -418,6 +482,67 @@ "Duplicated object")); } +void RemoteObjectNameRegisterTest:: + testUniqueNameWhenAmbiguousNameWithUniqueParent() { + TargetApplication::self()->setTargetApplicationFilePath(mPath); + TargetApplication::self()->start(); + + QVERIFY(waitForTargetApplicationToStart(10000)); + + RemoteObjectNameRegister remoteObjectNameRegister; + + QVERIFY(waitForNamesToBeRegistered(remoteObjectNameRegister, 10000)); + + RemoteObject* mainWindow = + TargetApplication::self()->remoteEditorSupport()->mainWindow(); + RemoteObject* remoteObject = + mainWindow->children()[8]->children()[0]->children()[0]; + + QCOMPARE(remoteObjectNameRegister.uniqueName(remoteObject), + QString("The object name 90/Duplicated object")); +} + +void RemoteObjectNameRegisterTest:: + testUniqueNameWhenAmbiguousNameWithDuplicatedParent() { + TargetApplication::self()->setTargetApplicationFilePath(mPath); + TargetApplication::self()->start(); + + QVERIFY(waitForTargetApplicationToStart(10000)); + + RemoteObjectNameRegister remoteObjectNameRegister; + + QVERIFY(waitForNamesToBeRegistered(remoteObjectNameRegister, 10000)); + + RemoteObject* mainWindow = + TargetApplication::self()->remoteEditorSupport()->mainWindow(); + RemoteObject* remoteObject = + mainWindow->children()[8]->children()[1]->children()[0]; + + QCOMPARE(remoteObjectNameRegister.uniqueName(remoteObject), + QString("Duplicated grandparent/Another duplicated parent/" + "Duplicated object")); +} + +void RemoteObjectNameRegisterTest:: + testUniqueNameWhenAmbiguousNameWithEmptyParent() { + TargetApplication::self()->setTargetApplicationFilePath(mPath); + TargetApplication::self()->start(); + + QVERIFY(waitForTargetApplicationToStart(10000)); + + RemoteObjectNameRegister remoteObjectNameRegister; + + QVERIFY(waitForNamesToBeRegistered(remoteObjectNameRegister, 10000)); + + RemoteObject* mainWindow = + TargetApplication::self()->remoteEditorSupport()->mainWindow(); + RemoteObject* remoteObject = + mainWindow->children()[8]->children()[3]->children()[0]; + + QCOMPARE(remoteObjectNameRegister.uniqueName(remoteObject), + QString("Duplicated grandparent/Duplicated object")); +} + void RemoteObjectNameRegisterTest::testUniqueNameWhenEmptyName() { TargetApplication::self()->setTargetApplicationFilePath(mPath); TargetApplication::self()->start(); @@ -435,7 +560,7 @@ QCOMPARE(remoteObjectNameRegister.uniqueName(remoteObject), QString("")); } -void RemoteObjectNameRegisterTest::testUniqueNames() { +void RemoteObjectNameRegisterTest::testUniqueNameWhenNameNotUnique() { TargetApplication::self()->setTargetApplicationFilePath(mPath); TargetApplication::self()->start(); @@ -445,18 +570,52 @@ QVERIFY(waitForNamesToBeRegistered(remoteObjectNameRegister, 10000)); - QStringList uniqueNames = - remoteObjectNameRegister.uniqueNames("Duplicated object"); + RemoteObject* mainWindow = + TargetApplication::self()->remoteEditorSupport()->mainWindow(); + RemoteObject* remoteObject = + mainWindow->children()[8]->children()[0]->children()[1]; - QCOMPARE(uniqueNames.count(), 4); - QVERIFY(uniqueNames.contains("The object name 50/Duplicated object")); - QVERIFY(uniqueNames.contains("Duplicated grandparent/Duplicated parent/" + QCOMPARE(remoteObjectNameRegister.uniqueName(remoteObject), QString("")); + + remoteObject = mainWindow->children()[8]->children()[2]->children()[0]; + + QCOMPARE(remoteObjectNameRegister.uniqueName(remoteObject), QString("")); + + remoteObject = mainWindow->children()[8]->children()[3]->children()[1]; + + QCOMPARE(remoteObjectNameRegister.uniqueName(remoteObject), QString("")); +} + +void RemoteObjectNameRegisterTest::testBestNames() { + TargetApplication::self()->setTargetApplicationFilePath(mPath); + TargetApplication::self()->start(); + + QVERIFY(waitForTargetApplicationToStart(10000)); + + RemoteObjectNameRegister remoteObjectNameRegister; + + QVERIFY(waitForNamesToBeRegistered(remoteObjectNameRegister, 10000)); + + QStringList bestNames = + remoteObjectNameRegister.bestNames("Duplicated object"); + + QCOMPARE(bestNames.count(), 10); + QVERIFY(bestNames.contains("The object name 50/Duplicated object")); + QVERIFY(bestNames.contains("Duplicated grandparent/Duplicated parent/" "Duplicated object")); - QVERIFY(uniqueNames.contains("The object name 7/Duplicated object")); - QVERIFY(uniqueNames.contains("The object name 8/Duplicated object")); + QVERIFY(bestNames.contains("The object name 7/Duplicated object")); + QVERIFY(bestNames.contains("The object name 8/Duplicated object")); + QVERIFY(bestNames.contains("The object name 90/Duplicated object")); + QVERIFY(bestNames.contains("The object name 90/Duplicated object")); + QVERIFY(bestNames.contains("Duplicated grandparent/Another duplicated " + "parent/Duplicated object")); + QVERIFY(bestNames.contains("Duplicated grandparent/Another duplicated " + "parent/Duplicated object")); + QVERIFY(bestNames.contains("Duplicated grandparent/Duplicated object")); + QVERIFY(bestNames.contains("Duplicated grandparent/Duplicated object")); } -void RemoteObjectNameRegisterTest::testUniqueNamesWithSingleRemoteObject() { +void RemoteObjectNameRegisterTest::testBestNamesWithSingleRemoteObject() { TargetApplication::self()->setTargetApplicationFilePath(mPath); TargetApplication::self()->start(); @@ -466,11 +625,11 @@ QVERIFY(waitForNamesToBeRegistered(remoteObjectNameRegister, 10000)); - QStringList uniqueNames = - remoteObjectNameRegister.uniqueNames("The object name 423"); + QStringList bestNames = + remoteObjectNameRegister.bestNames("The object name 423"); - QCOMPARE(uniqueNames.count(), 1); - QVERIFY(uniqueNames.contains("The object name 423")); + QCOMPARE(bestNames.count(), 1); + QVERIFY(bestNames.contains("The object name 423")); } /////////////////////////////////// Helpers //////////////////////////////////// @@ -541,7 +700,7 @@ } void RemoteObjectNameRegisterTest::assertNames(const QStringList& names) const { - QCOMPARE(names.count(), 82); + QCOMPARE(names.count(), 102); QVERIFY(names.contains("The object name 42")); QVERIFY(names.contains("The object name 420")); QVERIFY(names.contains("The object name 421")); Modified: trunk/ktutorial/ktutorial-editor/tests/unit/view/RemoteObjectNameWidgetTest.cpp =================================================================== --- trunk/ktutorial/ktutorial-editor/tests/unit/view/RemoteObjectNameWidgetTest.cpp 2012-08-09 15:59:47 UTC (rev 359) +++ trunk/ktutorial/ktutorial-editor/tests/unit/view/RemoteObjectNameWidgetTest.cpp 2012-08-10 10:57:33 UTC (rev 360) @@ -29,6 +29,7 @@ #include <QtDBus/QtDBus> #include <KCompletionBox> +#include <KDialog> #include <KLineEdit> #include <KProcess> @@ -59,6 +60,7 @@ void testSetNameDuringNameRegisterUpdate(); void testSetChosenRemoteObject(); + void testSetChosenRemoteObjectWithUniqueComplexName(); void testSetChosenRemoteObjectWithNameNotUnique(); void testSetChosenRemoteObjectDuringNameRegisterUpdate(); void testSetChosenRemoteObjectDuringNameRegisterUpdateKillingApplication(); @@ -94,6 +96,8 @@ bool waitForNamesToBeRegistered(const RemoteObjectNameWidget* widget, int timeout) const; + void closeSorryMessageBox(QWidget* widget, int timeToWait); + void assertRemoteObjectSignal(const QSignalSpy& spy, int index, const RemoteObject* remoteObject) const; @@ -261,7 +265,8 @@ assertRemoteObjectSignal(remoteObjectChosenSpy, 0, remoteObject); } -void RemoteObjectNameWidgetTest::testSetChosenRemoteObjectWithNameNotUnique() { +void RemoteObjectNameWidgetTest:: + testSetChosenRemoteObjectWithUniqueComplexName() { TargetApplication::self()->setTargetApplicationFilePath(mPath); TargetApplication::self()->start(); @@ -300,6 +305,38 @@ assertRemoteObjectSignal(remoteObjectChosenSpy, 2, remoteObject); } +void RemoteObjectNameWidgetTest::testSetChosenRemoteObjectWithNameNotUnique() { + TargetApplication::self()->setTargetApplicationFilePath(mPath); + TargetApplication::self()->start(); + + QVERIFY(waitForTargetApplicationToStart(10000)); + + RemoteObjectNameWidget widget; + + QVERIFY(waitForNamesToBeRegistered(&widget, 10000)); + + widget.setName("An object name"); + + QSignalSpy remoteObjectChosenSpy(&widget, + SIGNAL(remoteObjectChosen(RemoteObject*))); + + RemoteObject* mainWindow = + TargetApplication::self()->remoteEditorSupport()->mainWindow(); + RemoteObject* remoteObject = + mainWindow->children()[8]->children()[0]->children()[1]; + + //The widget must be shown for a proper parenting of the sorry message box + widget.show(); + + //Queue closing the sorry message box + closeSorryMessageBox(&widget, 10000); + + widget.setChosenRemoteObject(remoteObject); + + QCOMPARE(widget.name(), QString("An object name")); + QCOMPARE(remoteObjectChosenSpy.count(), 0); +} + void RemoteObjectNameWidgetTest:: testSetChosenRemoteObjectDuringNameRegisterUpdate() { TargetApplication::self()->setTargetApplicationFilePath(mPath); @@ -429,16 +466,30 @@ QVERIFY(completionBox->isVisible()); - QCOMPARE(completionItems.count(), 4); + QCOMPARE(completionItems.count(), 10); QCOMPARE(completionItems[0], + QString("Duplicated grandparent/Another duplicated parent/" + "Duplicated object")); + QCOMPARE(completionItems[1], + QString("Duplicated grandparent/Another duplicated parent/" + "Duplicated object")); + QCOMPARE(completionItems[2], + QString("Duplicated grandparent/Duplicated object")); + QCOMPARE(completionItems[3], + QString("Duplicated grandparent/Duplicated object")); + QCOMPARE(completionItems[4], QString("Duplicated grandparent/Duplicated parent/" "Duplicated object")); - QCOMPARE(completionItems[1], + QCOMPARE(completionItems[5], QString("The object name 50/Duplicated object")); - QCOMPARE(completionItems[2], + QCOMPARE(completionItems[6], QString("The object name 7/Duplicated object")); - QCOMPARE(completionItems[3], + QCOMPARE(completionItems[7], QString("The object name 8/Duplicated object")); + QCOMPARE(completionItems[8], + QString("The object name 90/Duplicated object")); + QCOMPARE(completionItems[9], + QString("The object name 90/Duplicated object")); } void RemoteObjectNameWidgetTest::testNameCompletionDuringNameRegisterUpdate() { @@ -470,16 +521,30 @@ QVERIFY(completionBox->isVisible()); - QCOMPARE(completionItems.count(), 4); + QCOMPARE(completionItems.count(), 10); QCOMPARE(completionItems[0], + QString("Duplicated grandparent/Another duplicated parent/" + "Duplicated object")); + QCOMPARE(completionItems[1], + QString("Duplicated grandparent/Another duplicated parent/" + "Duplicated object")); + QCOMPARE(completionItems[2], + QString("Duplicated grandparent/Duplicated object")); + QCOMPARE(completionItems[3], + QString("Duplicated grandparent/Duplicated object")); + QCOMPARE(completionItems[4], QString("Duplicated grandparent/Duplicated parent/" "Duplicated object")); - QCOMPARE(completionItems[1], + QCOMPARE(completionItems[5], QString("The object name 50/Duplicated object")); - QCOMPARE(completionItems[2], + QCOMPARE(completionItems[6], QString("The object name 7/Duplicated object")); - QCOMPARE(completionItems[3], + QCOMPARE(completionItems[7], QString("The object name 8/Duplicated object")); + QCOMPARE(completionItems[8], + QString("The object name 90/Duplicated object")); + QCOMPARE(completionItems[9], + QString("The object name 90/Duplicated object")); } void RemoteObjectNameWidgetTest:: @@ -515,7 +580,7 @@ QVERIFY(completionBox->isVisible()); - QCOMPARE(completionItems.count(), 82); + QCOMPARE(completionItems.count(), 102); QVERIFY(completionItems.contains("The object name 42")); QVERIFY(completionItems.contains("The object name 420")); QVERIFY(completionItems.contains("The object name 421")); @@ -723,6 +788,101 @@ timeout); } +//The message boxes are modal, so they won't return to the test code until they +//are closed. Thus, the actions to be performed while the message boxes are +//being shown (like closing the message boxes themselves) must be "queued". +//Instead of queueing them to be performed after some fixed amount of time, +//it is checked if the action can be performed and, if not, the action is +//retried again after a little amount of time. The retries continue until the +//timeout expires. +class QueuedAction: public QObject { +Q_OBJECT +public: + + QueuedAction(int timeout, QObject* parent): QObject(parent), + mTimeout(timeout), + mFinished(false), + mActionDone(false) { + } + + void run() { + mElapsedTime.start(); + mFinished = false; + + checkAction(); + } + + bool isFinished() const { + return mFinished; + } + + bool isActionDone() const { + return mActionDone; + } + +public slots: + + void checkAction() { + mActionDone = action(); + if (!mActionDone && mElapsedTime.elapsed() < mTimeout) { + QTimer::singleShot(100, this, SLOT(checkAction())); + } else { + mFinished = true; + } + } + +protected: + + virtual bool action() = 0; + +private: + + int mTimeout; + QTime mElapsedTime; + bool mFinished; + bool mActionDone; + +}; + +class CloseSorryMessageBoxHelper: public QueuedAction { +public: + + CloseSorryMessageBoxHelper(int timeout, QObject* parent): + QueuedAction(timeout, parent), + mWidget(0) { + } + + void setWidget(QWidget* widget) { + mWidget = widget; + } + +protected: + + virtual bool action() { + KDialog* messageBox = mWidget->findChild<KDialog*>("sorry"); + if (!messageBox) { + return false; + } + + delete messageBox; + + return true; + } + +private: + + QWidget* mWidget; + +}; + +void RemoteObjectNameWidgetTest::closeSorryMessageBox(QWidget* widget, + int timeToWait) { + CloseSorryMessageBoxHelper* helper = new CloseSorryMessageBoxHelper( + timeToWait, this); + helper->setWidget(widget); + helper->run(); +} + //RemoteObject* must be declared as a metatype to be used in qvariant_cast Q_DECLARE_METATYPE(RemoteObject*); @@ -735,7 +895,7 @@ void RemoteObjectNameWidgetTest::assertCompletionItems( const QStringList& items) const { - QCOMPARE(items.count(), 77); + QCOMPARE(items.count(), 89); QVERIFY(items.contains("The object name 42")); QVERIFY(items.contains("The object name 420")); QVERIFY(items.contains("The object name 421")); Modified: trunk/ktutorial/ktutorial-library/src/KTutorial.cpp =================================================================== --- trunk/ktutorial/ktutorial-library/src/KTutorial.cpp 2012-08-09 15:59:47 UTC (rev 359) +++ trunk/ktutorial/ktutorial-library/src/KTutorial.cpp 2012-08-10 10:57:33 UTC (rev 360) @@ -86,6 +86,7 @@ #ifdef QT_QTDBUS_FOUND editorsupport::EditorSupport* editorSupport = new editorsupport::EditorSupport(this); + editorSupport->setObjectFinder(mObjectFinder); editorSupport->setup(window); connect(editorSupport, SIGNAL(started(Tutorial*)), this, SLOT(showStepWidget(Tutorial*))); Modified: trunk/ktutorial/ktutorial-library/src/editorsupport/EditorSupport.cpp =================================================================== --- trunk/ktutorial/ktutorial-library/src/editorsupport/EditorSupport.cpp 2012-08-09 15:59:47 UTC (rev 359) +++ trunk/ktutorial/ktutorial-library/src/editorsupport/EditorSupport.cpp 2012-08-10 10:57:33 UTC (rev 360) @@ -1,5 +1,5 @@ /*************************************************************************** - * Copyright (C) 2010-2011 by Daniel Calviño Sánchez * + * Copyright (C) 2010-2012 by Daniel Calviño Sánchez * * dan...@gm... * * * * This program is free software; you can redistribute it and/or modify * @@ -28,6 +28,7 @@ #include "EventSpyAdaptor.h" #include "ObjectRegister.h" #include "ObjectRegisterAdaptor.h" +#include "../ObjectFinder.h" #include ".... [truncated message content] |