KTutorial  0.5.1
ObjectFinder.cpp
00001 /***************************************************************************
00002  *   Copyright (C) 2012 by Daniel Calviño Sánchez <danxuliu@gmail.com>     *
00003  *                                                                         *
00004  *   This program is free software; you can redistribute it and/or modify  *
00005  *   it under the terms of the GNU General Public License as published by  *
00006  *   the Free Software Foundation; either version 2 of the License, or     *
00007  *   (at your option) any later version.                                   *
00008  *                                                                         *
00009  *   This program is distributed in the hope that it will be useful,       *
00010  *   but WITHOUT ANY WARRANTY; without even the implied warranty of        *
00011  *   MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the         *
00012  *   GNU General Public License for more details.                          *
00013  *                                                                         *
00014  *   You should have received a copy of the GNU General Public License     *
00015  *   along with this program; If not, see <http://www.gnu.org/licenses/>.  *
00016  ***************************************************************************/
00017 
00018 #include "ObjectFinder.h"
00019 #include "ObjectFinder_p.h"
00020 
00021 namespace ktutorial {
00022 
00023 //public:
00024 
00025 ObjectFinder::ObjectFinder(QObject* parent /*= 0*/): QObject(parent),
00026     d(new ObjectFinderPrivate()) {
00027 }
00028 
00029 ObjectFinder::~ObjectFinder() {
00030     delete d;
00031 }
00032 
00033 //private:
00034 
00035 QList<QObject*> ObjectFinder::getBestMatches(const QString& name,
00036                                 QList< QList<QObject*> > objectPaths) const {
00037     if (name.isEmpty() || objectPaths.isEmpty()) {
00038         return QList<QObject*>();
00039     }
00040 
00041     if (name.indexOf('/') == -1) {
00042         QList< QList<QObject*> > filteredObjectPaths =
00043                                         filterObjectPaths(name, objectPaths);
00044 
00045         QList<QObject*> filteredObjects;
00046         foreach (QList<QObject*> filteredObjectPath, filteredObjectPaths) {
00047             filteredObjects.append(filteredObjectPath.first());
00048         }
00049 
00050         return filteredObjects;
00051     }
00052 
00053     QRegExp slashPattern("/+");
00054     QString ancestorName = name.left(name.indexOf(slashPattern));
00055     QString descendantName = name.mid(ancestorName.length() +
00056                                         slashPattern.matchedLength());
00057 
00058     return getBestMatches(descendantName, filterObjectPaths(ancestorName,
00059                                                             objectPaths));
00060 }
00061 
00062 QList< QList<QObject*> > ObjectFinder::filterObjectPaths(const QString& name,
00063                             const QList< QList<QObject*> >& objectPaths) const {
00064     QList< QList<QObject*> > filteredPaths = filterDirectChildren(name,
00065                                                                   objectPaths);
00066     if (filteredPaths.size() > 0) {
00067         return filteredPaths;
00068     }
00069     
00070     filteredPaths = filterNestedChildrenWithUnnamedAncestors(name, objectPaths);
00071     if (filteredPaths.size() > 0) {
00072         return filteredPaths;
00073     }
00074 
00075     return filterNestedChildren(name, objectPaths);
00076 }
00077 
00078 QList< QList<QObject*> > ObjectFinder::filterDirectChildren(const QString& name, 
00079                             const QList< QList<QObject*> >& objectPaths) const {
00080     QList< QList<QObject*> > filteredPaths;
00081     
00082     foreach (QList<QObject*> objectPath, objectPaths) {
00083         if (objectPath.size() >= 2 && objectPath[1]->objectName() == name) {
00084             objectPath.removeAt(0);
00085             filteredPaths.append(objectPath);
00086         }
00087     }
00088     
00089     return filteredPaths;
00090 }
00091 
00092 QList< QList<QObject*> > ObjectFinder::filterNestedChildrenWithUnnamedAncestors(
00093                             const QString& name, 
00094                             const QList< QList<QObject*> >& objectPaths) const {
00095     QList< QList<QObject*> > candidatePaths;
00096 
00097     //No need to use std::numeric_limits, as there would never be a 100000
00098     //levels deep object.
00099     int minimumNumberOfUnnamedAncestors = 100000;
00100     foreach (QList<QObject*> objectPath, objectPaths) {
00101         objectPath.removeAt(0);
00102 
00103         int unnamedAncestorCount = 0;
00104         while (objectPath.size() > unnamedAncestorCount &&
00105                objectPath[unnamedAncestorCount]->objectName().isEmpty()) {
00106             unnamedAncestorCount++;
00107         }
00108 
00109         if (unnamedAncestorCount > 0 &&
00110             objectPath.size() > unnamedAncestorCount &&
00111             objectPath[unnamedAncestorCount]->objectName() == name) {
00112             candidatePaths.append(objectPath);
00113 
00114             if (unnamedAncestorCount < minimumNumberOfUnnamedAncestors) {
00115                 minimumNumberOfUnnamedAncestors = unnamedAncestorCount;
00116             }
00117         }
00118     }
00119 
00120     QList< QList<QObject*> > filteredPaths;
00121 
00122     foreach (QList<QObject*> candidatePath, candidatePaths) {
00123         if (candidatePath[minimumNumberOfUnnamedAncestors]->objectName() == 
00124                                                                         name) {
00125             for (int i=0; i<minimumNumberOfUnnamedAncestors; ++i) {
00126                 candidatePath.removeAt(0);
00127             }
00128             filteredPaths.append(candidatePath);
00129         }
00130     }
00131 
00132     return filteredPaths;
00133 }
00134 
00135 QList< QList<QObject*> > ObjectFinder::filterNestedChildren(const QString& name, 
00136                             const QList< QList<QObject*> >& objectPaths) const {
00137     QList< QList<QObject*> > candidatePaths;
00138 
00139     //No need to use std::numeric_limits, as there would never be a 100000
00140     //levels deep object.
00141     int minimumNumberOfAncestors = 100000;
00142     foreach (QList<QObject*> objectPath, objectPaths) {
00143         objectPath.removeAt(0);
00144 
00145         int ancestorCount = 0;
00146         while (objectPath.size() > ancestorCount &&
00147                objectPath[ancestorCount]->objectName() != name) {
00148             ancestorCount++;
00149         }
00150 
00151         if (ancestorCount > 0 && objectPath.size() > ancestorCount &&
00152             objectPath[ancestorCount]->objectName() == name) {
00153             candidatePaths.append(objectPath);
00154 
00155             if (ancestorCount < minimumNumberOfAncestors) {
00156                 minimumNumberOfAncestors = ancestorCount;
00157             }
00158         }
00159     }
00160 
00161     QList< QList<QObject*> > filteredPaths;
00162 
00163     foreach (QList<QObject*> candidatePath, candidatePaths) {
00164         if (candidatePath[minimumNumberOfAncestors]->objectName() == name) {
00165             for (int i=0; i<minimumNumberOfAncestors; ++i) {
00166                 candidatePath.removeAt(0);
00167             }
00168             filteredPaths.append(candidatePath);
00169         }
00170     }
00171     
00172     return filteredPaths;
00173 }
00174 
00175 }