KTutorial
0.5.1
|
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 }