KTutorial  0.5.1
ObjectFinder.h
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 #ifndef KTUTORIAL_OBJECTFINDER_H
00019 #define KTUTORIAL_OBJECTFINDER_H
00020 
00021 #include <QtCore/QObject>
00022 #include <QtCore/QRegExp>
00023 
00024 #include "ktutorial_export.h"
00025 
00026 namespace ktutorial {
00027 
00033 class KTUTORIAL_EXPORT ObjectFinder: public QObject {
00034 Q_OBJECT
00035 public:
00036     
00042     explicit ObjectFinder(QObject* parent = 0);
00043 
00047     virtual ~ObjectFinder();
00048 
00061     template <typename T>
00062     T findObject(const QString& name, const QObject* baseObject) const {
00063         QList<T> candidateObjects;
00064         findObjects<T>(name, baseObject, candidateObjects);
00065         
00066         if (candidateObjects.isEmpty()) {
00067             return 0;
00068         }
00069         
00070         if (candidateObjects.count() == 1) {
00071             return candidateObjects.first();
00072         }
00073         
00074         return getBestMatch(name, candidateObjects);
00075     }
00076 
00077 private:
00078 
00079     class ObjectFinderPrivate* d;
00080 
00092     template <typename T>
00093     void findObjects(const QString& name, const QObject* ancestor,
00094                      QList<T>& foundObjects) const {
00095         if (name.isEmpty() || ancestor == 0) {
00096             return;
00097         }
00098 
00099         if (name.indexOf('/') == -1) {
00100             foundObjects.append(ancestor->findChildren<T>(name));
00101             return;
00102         }
00103 
00104         QRegExp slashPattern("/+");
00105         QString ancestorName = name.left(name.indexOf(slashPattern));
00106         QString descendantName = name.mid(ancestorName.length() +
00107                                           slashPattern.matchedLength());
00108 
00109         QList<QObject*> namedAncestors =
00110                                 ancestor->findChildren<QObject*>(ancestorName);
00111         foreach (QObject* namedAncestor, namedAncestors) {
00112             findObjects<T>(descendantName, namedAncestor, foundObjects);
00113         }
00114     }
00115 
00125     template <typename T>
00126     T getBestMatch(const QString& name, QList<T> candidateObjects) const {
00127         QList< QList<QObject*> > objectPaths = getObjectPaths(candidateObjects);
00128         
00129         QList<QObject*> bestMatches = getBestMatches(name, objectPaths);
00130         
00131         //Should not happen, but just in case
00132         if (bestMatches.isEmpty()) {
00133             return 0;
00134         }
00135         
00136         return static_cast<T>(bestMatches[0]);
00137     }
00138 
00148     template <typename T>
00149     QList< QList<QObject*> > getObjectPaths(const QList<T> objects) const {
00150         QList< QList<QObject*> > objectPaths;
00151 
00152         foreach (T candidateObject, objects) {
00153             QList<QObject*> objectPath;
00154 
00155             QObject* ancestor = candidateObject;
00156             while (ancestor) {
00157                 objectPath.prepend(ancestor);
00158                 ancestor = ancestor->parent();
00159             }
00160 
00161             objectPaths.append(objectPath);
00162         }
00163 
00164         return objectPaths;
00165     }
00166 
00179     QList<QObject*> getBestMatches(const QString& name,
00180                            QList< QList<QObject*> > objectPaths) const;
00181 
00196     QList< QList<QObject*> > filterObjectPaths(const QString& name,
00197                             const QList< QList<QObject*> >& objectPaths) const;
00198 
00210     QList< QList<QObject*> > filterDirectChildren(const QString& name,
00211                             const QList< QList<QObject*> >& objectPaths) const;
00212 
00228     QList< QList<QObject*> > filterNestedChildrenWithUnnamedAncestors(
00229         const QString& name, const QList< QList<QObject*> >& objectPaths) const;    
00230 
00244     QList< QList<QObject*> > filterNestedChildren(const QString& name,
00245                             const QList< QList<QObject*> >& objectPaths) const;
00246 
00247 };
00248 
00249 }
00250 
00251 #endif