[Ktutorial-commits] SF.net SVN: ktutorial:[353] trunk/ktutorial/ktutorial-library
Status: Alpha
Brought to you by:
danxuliu
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. |