OSDN Git Service

hot fix to allow running projects again.
[qt-creator-jp/qt-creator-jp.git] / src / plugins / qt4projectmanager / qt4project.cpp
1 /**************************************************************************
2 **
3 ** This file is part of Qt Creator
4 **
5 ** Copyright (c) 2010 Nokia Corporation and/or its subsidiary(-ies).
6 **
7 ** Contact: Nokia Corporation (qt-info@nokia.com)
8 **
9 ** Commercial Usage
10 **
11 ** Licensees holding valid Qt Commercial licenses may use this file in
12 ** accordance with the Qt Commercial License Agreement provided with the
13 ** Software or, alternatively, in accordance with the terms contained in
14 ** a written agreement between you and Nokia.
15 **
16 ** GNU Lesser General Public License Usage
17 **
18 ** Alternatively, this file may be used under the terms of the GNU Lesser
19 ** General Public License version 2.1 as published by the Free Software
20 ** Foundation and appearing in the file LICENSE.LGPL included in the
21 ** packaging of this file.  Please review the following information to
22 ** ensure the GNU Lesser General Public License version 2.1 requirements
23 ** will be met: http://www.gnu.org/licenses/old-licenses/lgpl-2.1.html.
24 **
25 ** If you are unsure which license is appropriate for your use, please
26 ** contact the sales department at http://qt.nokia.com/contact.
27 **
28 **************************************************************************/
29
30 #include "qt4project.h"
31
32 #include "profilereader.h"
33 #include "qt4projectmanager.h"
34 #include "makestep.h"
35 #include "qmakestep.h"
36 #include "qt4runconfiguration.h"
37 #include "qt4nodes.h"
38 #include "qt4projectconfigwidget.h"
39 #include "qt4projectmanagerconstants.h"
40 #include "projectloadwizard.h"
41 #include "qt4buildconfiguration.h"
42 #include "findqt4profiles.h"
43 #include "qmldumptool.h"
44
45 #include <coreplugin/icore.h>
46 #include <coreplugin/messagemanager.h>
47 #include <coreplugin/coreconstants.h>
48 #include <coreplugin/progressmanager/progressmanager.h>
49 #include <extensionsystem/pluginmanager.h>
50 #include <cpptools/cppmodelmanagerinterface.h>
51 #include <qmljs/qmljsmodelmanagerinterface.h>
52 #include <projectexplorer/buildenvironmentwidget.h>
53 #include <projectexplorer/customexecutablerunconfiguration.h>
54 #include <projectexplorer/projectexplorer.h>
55 #include <utils/qtcassert.h>
56
57 #include <QtCore/QDebug>
58 #include <QtCore/QDir>
59 #include <QtGui/QFileDialog>
60 #include <QtGui/QInputDialog>
61
62 using namespace Qt4ProjectManager;
63 using namespace Qt4ProjectManager::Internal;
64 using namespace ProjectExplorer;
65
66 enum { debug = 0 };
67
68 namespace Qt4ProjectManager {
69 namespace Internal {
70
71 // Qt4ProjectFiles: Struct for (Cached) lists of files in a project
72 struct Qt4ProjectFiles {
73     void clear();
74     bool equals(const Qt4ProjectFiles &f) const;
75
76     QStringList files[ProjectExplorer::FileTypeSize];
77     QStringList generatedFiles[ProjectExplorer::FileTypeSize];
78     QStringList proFiles;
79 };
80
81 void Qt4ProjectFiles::clear()
82 {
83     for (int i = 0; i < FileTypeSize; ++i) {
84         files[i].clear();
85         generatedFiles[i].clear();
86     }
87     proFiles.clear();
88 }
89
90 bool Qt4ProjectFiles::equals(const Qt4ProjectFiles &f) const
91 {
92     for (int i = 0; i < FileTypeSize; ++i)
93         if (files[i] != f.files[i] || generatedFiles[i] != f.generatedFiles[i])
94             return false;
95     if (proFiles != f.proFiles)
96         return false;
97     return true;
98 }
99
100 inline bool operator==(const Qt4ProjectFiles &f1, const Qt4ProjectFiles &f2)
101 {       return f1.equals(f2); }
102
103 inline bool operator!=(const Qt4ProjectFiles &f1, const Qt4ProjectFiles &f2)
104 {       return !f1.equals(f2); }
105
106 QDebug operator<<(QDebug d, const  Qt4ProjectFiles &f)
107 {
108     QDebug nsp = d.nospace();
109     nsp << "Qt4ProjectFiles: proFiles=" <<  f.proFiles << '\n';
110     for (int i = 0; i < FileTypeSize; ++i)
111         nsp << "Type " << i << " files=" << f.files[i] <<  " generated=" << f.generatedFiles[i] << '\n';
112     return d;
113 }
114
115 // A visitor to collect all files of a project in a Qt4ProjectFiles struct
116 class ProjectFilesVisitor : public ProjectExplorer::NodesVisitor
117 {
118     Q_DISABLE_COPY(ProjectFilesVisitor)
119     ProjectFilesVisitor(Qt4ProjectFiles *files);
120 public:
121
122     static void findProjectFiles(Qt4ProFileNode *rootNode, Qt4ProjectFiles *files);
123
124     void visitProjectNode(ProjectNode *projectNode);
125     void visitFolderNode(FolderNode *folderNode);
126
127 private:
128     Qt4ProjectFiles *m_files;
129 };
130
131 ProjectFilesVisitor::ProjectFilesVisitor(Qt4ProjectFiles *files) :
132     m_files(files)
133 {
134 }
135
136 void ProjectFilesVisitor::findProjectFiles(Qt4ProFileNode *rootNode, Qt4ProjectFiles *files)
137 {
138     files->clear();
139     ProjectFilesVisitor visitor(files);
140     rootNode->accept(&visitor);
141     for (int i = 0; i < FileTypeSize; ++i) {
142         qSort(files->files[i]);
143         qSort(files->generatedFiles[i]);
144     }
145     qSort(files->proFiles);
146 }
147
148 void ProjectFilesVisitor::visitProjectNode(ProjectNode *projectNode)
149 {
150     const QString path = projectNode->path();
151     if (!m_files->proFiles.contains(path))
152         m_files->proFiles.append(path);
153     visitFolderNode(projectNode);
154 }
155
156 void ProjectFilesVisitor::visitFolderNode(FolderNode *folderNode)
157 {
158     foreach (FileNode *fileNode, folderNode->fileNodes()) {
159         const QString path = fileNode->path();
160         const int type = fileNode->fileType();
161         QStringList &targetList = fileNode->isGenerated() ? m_files->generatedFiles[type] : m_files->files[type];
162         if (!targetList.contains(path))
163             targetList.push_back(path);
164     }
165 }
166
167 }
168 }
169
170 // ----------- Qt4ProjectFile
171 Qt4ProjectFile::Qt4ProjectFile(Qt4Project *project, const QString &filePath, QObject *parent)
172     : Core::IFile(parent),
173       m_mimeType(QLatin1String(Qt4ProjectManager::Constants::PROFILE_MIMETYPE)),
174       m_project(project),
175       m_filePath(filePath)
176 {
177 }
178
179 bool Qt4ProjectFile::save(const QString &)
180 {
181     // This is never used
182     return false;
183 }
184
185 void Qt4ProjectFile::rename(const QString &newName)
186 {
187     // Can't happen
188     Q_UNUSED(newName);
189     Q_ASSERT(false);
190 }
191
192 QString Qt4ProjectFile::fileName() const
193 {
194     return m_filePath;
195 }
196
197 QString Qt4ProjectFile::defaultPath() const
198 {
199     return QString();
200 }
201
202 QString Qt4ProjectFile::suggestedFileName() const
203 {
204     return QString();
205 }
206
207 QString Qt4ProjectFile::mimeType() const
208 {
209     return m_mimeType;
210 }
211
212 bool Qt4ProjectFile::isModified() const
213 {
214     return false; // we save after changing anyway
215 }
216
217 bool Qt4ProjectFile::isReadOnly() const
218 {
219     QFileInfo fi(m_filePath);
220     return !fi.isWritable();
221 }
222
223 bool Qt4ProjectFile::isSaveAsAllowed() const
224 {
225     return false;
226 }
227
228 Core::IFile::ReloadBehavior Qt4ProjectFile::reloadBehavior(ChangeTrigger state, ChangeType type) const
229 {
230     Q_UNUSED(state)
231     Q_UNUSED(type)
232     return BehaviorSilent;
233 }
234
235 void Qt4ProjectFile::reload(ReloadFlag flag, ChangeType type)
236 {
237     Q_UNUSED(flag)
238     Q_UNUSED(type)
239 }
240
241 /*!
242   \class Qt4Project
243
244   Qt4Project manages information about an individual Qt 4 (.pro) project file.
245   */
246
247 Qt4Project::Qt4Project(Qt4Manager *manager, const QString& fileName) :
248     m_manager(manager),
249     m_rootProjectNode(0),
250     m_nodesWatcher(new Internal::Qt4NodesWatcher(this)),
251     m_targetFactory(new Qt4TargetFactory(this)),
252     m_fileInfo(new Qt4ProjectFile(this, fileName, this)),
253     m_projectFiles(new Qt4ProjectFiles),
254     m_proFileOption(0),
255     m_asyncUpdateFutureInterface(0),
256     m_pendingEvaluateFuturesCount(0),
257     m_asyncUpdateState(NoState),
258     m_cancelEvaluate(false)
259 {
260     m_asyncUpdateTimer.setSingleShot(true);
261     m_asyncUpdateTimer.setInterval(3000);
262     connect(&m_asyncUpdateTimer, SIGNAL(timeout()), this, SLOT(asyncUpdate()));
263
264     setSupportedTargetIds(QtVersionManager::instance()->supportedTargetIds());
265 }
266
267 Qt4Project::~Qt4Project()
268 {
269     m_codeModelFuture.cancel();
270     m_asyncUpdateState = ShuttingDown;
271     m_manager->unregisterProject(this);
272     delete m_projectFiles;
273     m_cancelEvaluate = true;
274     delete m_rootProjectNode;
275 }
276
277 void Qt4Project::updateFileList()
278 {
279     Qt4ProjectFiles newFiles;
280     ProjectFilesVisitor::findProjectFiles(m_rootProjectNode, &newFiles);
281     if (newFiles != *m_projectFiles) {
282         *m_projectFiles = newFiles;
283         emit fileListChanged();
284         if (debug)
285             qDebug() << Q_FUNC_INFO << *m_projectFiles;
286     }
287 }
288
289 bool Qt4Project::fromMap(const QVariantMap &map)
290 {
291     if (!Project::fromMap(map))
292         return false;
293
294     // Prune targets without buildconfigurations:
295     // This can happen esp. when updating from a old version of Qt Creator
296     QList<Target *>ts(targets());
297     foreach (Target *t, ts) {
298         if (t->buildConfigurations().isEmpty()) {
299             qWarning() << "Removing" << t->id() << "since it has no buildconfigurations!";
300             removeTarget(t);
301         }
302     }
303
304     // Add buildconfigurations so we can parse the pro-files.
305     if (targets().isEmpty())
306         addDefaultBuild();
307
308     if (targets().isEmpty()) {
309         qWarning() << "Unable to create targets!";
310         return false;
311     }
312
313     Q_ASSERT(activeTarget());
314     Q_ASSERT(activeTarget()->activeBuildConfiguration());
315
316     m_manager->registerProject(this);
317
318     m_rootProjectNode = new Qt4ProFileNode(this, m_fileInfo->fileName(), this);
319     m_rootProjectNode->registerWatcher(m_nodesWatcher);
320
321     update();
322     updateFileList();
323     // This might be incorrect, need a full update
324     updateCodeModels();
325
326     createApplicationProjects();
327
328     foreach (Target *t, targets())
329         onAddedTarget(t);
330
331     setSupportedTargetIds(QtVersionManager::instance()->supportedTargetIds());
332
333     // Setup Qt versions supported (== possible targets).
334     connect(this, SIGNAL(addedTarget(ProjectExplorer::Target*)),
335             this, SLOT(onAddedTarget(ProjectExplorer::Target*)));
336
337     connect(QtVersionManager::instance(), SIGNAL(qtVersionsChanged(QList<int>)),
338             this, SLOT(qtVersionsChanged()));
339
340     connect(m_nodesWatcher, SIGNAL(proFileUpdated(Qt4ProjectManager::Internal::Qt4ProFileNode*,bool)),
341             this, SIGNAL(proFileUpdated(Qt4ProjectManager::Internal::Qt4ProFileNode *,bool)));
342
343     connect(m_nodesWatcher, SIGNAL(proFileInvalidated(Qt4ProjectManager::Internal::Qt4ProFileNode*)),
344             this, SIGNAL(proFileInvalidated(Qt4ProjectManager::Internal::Qt4ProFileNode*)));
345
346     connect(this, SIGNAL(activeTargetChanged(ProjectExplorer::Target*)),
347             this, SLOT(activeTargetWasChanged()));
348
349     return true;
350 }
351
352 Qt4TargetFactory *Qt4Project::targetFactory() const
353 {
354     return m_targetFactory;
355 }
356
357 Qt4Target *Qt4Project::activeTarget() const
358 {
359     return static_cast<Qt4Target *>(Project::activeTarget());
360 }
361
362 void Qt4Project::onAddedTarget(ProjectExplorer::Target *t)
363 {
364     Q_ASSERT(t);
365     Qt4Target *qt4target = qobject_cast<Qt4Target *>(t);
366     Q_ASSERT(qt4target);
367     connect(qt4target, SIGNAL(buildDirectoryInitialized()),
368             this, SIGNAL(buildDirectoryInitialized()));
369     connect(qt4target, SIGNAL(proFileEvaluateNeeded(Qt4ProjectManager::Internal::Qt4Target*)),
370             this, SLOT(proFileEvaluateNeeded(Qt4ProjectManager::Internal::Qt4Target*)));
371 }
372
373 void Qt4Project::proFileEvaluateNeeded(Qt4ProjectManager::Internal::Qt4Target *target)
374 {
375     if (activeTarget() == target)
376         scheduleAsyncUpdate();
377 }
378
379 /// equalFileList compares two file lists ignoring
380 /// <configuration> without generating temporary lists
381
382 bool Qt4Project::equalFileList(const QStringList &a, const QStringList &b)
383 {
384     if (abs(a.length() - b.length()) > 1)
385         return false;
386     QStringList::const_iterator ait = a.constBegin();
387     QStringList::const_iterator bit = b.constBegin();
388     QStringList::const_iterator aend = a.constEnd();
389     QStringList::const_iterator bend = b.constEnd();
390
391     while (ait != aend && bit != bend) {
392         if (*ait == QLatin1String("<configuration>"))
393             ++ait;
394         else if (*bit == QLatin1String("<configuration>"))
395             ++bit;
396         else if (*ait == *bit)
397             ++ait, ++bit;
398         else
399            return false;
400     }
401     return (ait == aend && bit == bend);
402 }
403
404 void Qt4Project::updateCodeModels()
405 {
406     if (debug)
407         qDebug()<<"Qt4Project::updateCodeModel()";
408
409     if (!activeTarget() || !activeTarget()->activeBuildConfiguration())
410         return;
411
412     updateCppCodeModel();
413     updateQmlJSCodeModel();
414 }
415
416 void Qt4Project::updateCppCodeModel()
417 {
418     Qt4BuildConfiguration *activeBC = activeTarget()->activeBuildConfiguration();
419
420     CppTools::CppModelManagerInterface *modelmanager =
421         ExtensionSystem::PluginManager::instance()
422             ->getObject<CppTools::CppModelManagerInterface>();
423
424     if (!modelmanager)
425         return;
426
427     // Collect global headers/defines
428     QStringList predefinedIncludePaths;
429     QStringList predefinedFrameworkPaths;
430     QByteArray predefinedMacros;
431
432     QString qtFrameworkPath = activeBC->qtVersion()->frameworkInstallPath();
433     if (!qtFrameworkPath.isEmpty())
434         predefinedFrameworkPaths.append(qtFrameworkPath);
435
436     ToolChain *tc = activeBC->toolChain();
437     if (tc) {
438         predefinedMacros = tc->predefinedMacros();
439         //qDebug()<<"Predefined Macros";
440         //qDebug()<<tc->predefinedMacros();
441         //qDebug()<<"";
442         //qDebug()<<"System Header Paths";
443         //foreach(const HeaderPath &hp, tc->systemHeaderPaths())
444         //    qDebug()<<hp.path();
445
446         foreach (const HeaderPath &headerPath, tc->systemHeaderPaths()) {
447             if (headerPath.kind() == HeaderPath::FrameworkHeaderPath)
448                 predefinedFrameworkPaths.append(headerPath.path());
449             else
450                 predefinedIncludePaths.append(headerPath.path());
451         }
452     }
453
454     FindQt4ProFiles findQt4ProFiles;
455     QList<Qt4ProFileNode *> proFiles = findQt4ProFiles(rootProjectNode());
456     QByteArray allDefinedMacros = predefinedMacros;
457     QStringList allIncludePaths;
458     QStringList allFrameworkPaths = predefinedFrameworkPaths;
459     QStringList allPrecompileHeaders;
460
461     // Collect per .pro file information
462     foreach (Qt4ProFileNode *pro, proFiles) {
463         Internal::CodeModelInfo info;
464         info.defines = predefinedMacros;
465         info.frameworkPaths = predefinedFrameworkPaths;
466
467         info.precompiledHeader = pro->variableValue(PrecompiledHeaderVar);
468
469         allPrecompileHeaders.append(info.precompiledHeader);
470
471         // Add custom defines
472
473         foreach (const QString &def, pro->variableValue(DefinesVar)) {
474             allDefinedMacros += "#define ";
475             info.defines += "#define ";
476             const int index = def.indexOf(QLatin1Char('='));
477             if (index == -1) {
478                 allDefinedMacros += def.toLatin1();
479                 allDefinedMacros += " 1\n";
480                 info.defines += def.toLatin1();
481                 info.defines += " 1\n";
482             } else {
483                 const QString name = def.left(index);
484                 const QString value = def.mid(index + 1);
485                 allDefinedMacros += name.toLatin1();
486                 allDefinedMacros += ' ';
487                 allDefinedMacros += value.toLocal8Bit();
488                 allDefinedMacros += '\n';
489                 info.defines += name.toLatin1();
490                 info.defines += ' ';
491                 info.defines += value.toLocal8Bit();
492                 info.defines += '\n';
493             }
494         }
495
496         const QStringList proIncludePaths = pro->variableValue(IncludePathVar);
497         foreach (const QString &includePath, proIncludePaths) {
498             if (!allIncludePaths.contains(includePath))
499                 allIncludePaths.append(includePath);
500             if (!info.includes.contains(includePath))
501                 info.includes.append(includePath);
502         }
503
504 #if 0 // Experimental PKGCONFIG support
505         { // Pkg Config support
506             QStringList pkgConfig = pro->variableValue(PkgConfigVar);
507             if (!pkgConfig.isEmpty()) {
508                 pkgConfig.prepend("--cflags-only-I");
509                 QProcess process;
510                 process.start("pkg-config", pkgConfig);
511                 process.waitForFinished();
512                 QString result = process.readAllStandardOutput();
513                 foreach(const QString &part, result.trimmed().split(' ', QString::SkipEmptyParts)) {
514                     info.includes.append(part.mid(2)); // Chop off "-I"
515                 }
516             }
517         }
518 #endif
519
520         // Add mkspec directory
521         info.includes.append(activeBC->qtVersion()->mkspecPath());
522         info.includes.append(predefinedIncludePaths);
523
524 //        qDebug()<<"Dumping code model information";
525 //        qDebug()<<"for .pro file"<< pro->path();
526 //        qDebug()<<info.defines;
527 //        qDebug()<<info.includes;
528 //        qDebug()<<info.frameworkPaths;
529 //        qDebug()<<"\n";
530     }
531
532     // Add mkspec directory
533     allIncludePaths.append(activeBC->qtVersion()->mkspecPath());
534
535     allIncludePaths.append(predefinedIncludePaths);
536
537     QStringList files;
538     files += m_projectFiles->files[HeaderType];
539     files += m_projectFiles->generatedFiles[HeaderType];
540     files += m_projectFiles->files[SourceType];
541     files += m_projectFiles->generatedFiles[SourceType];
542
543     CppTools::CppModelManagerInterface::ProjectInfo pinfo = modelmanager->projectInfo(this);
544
545     //qDebug()<<"Using precompiled header"<<allPrecompileHeaders;
546
547     bool fileList = equalFileList(pinfo.sourceFiles, files);
548
549     if (pinfo.defines == allDefinedMacros
550         && pinfo.includePaths == allIncludePaths
551         && pinfo.frameworkPaths == allFrameworkPaths
552         && fileList
553         && pinfo.precompiledHeaders == allPrecompileHeaders) {
554         // Nothing to update...
555     } else {
556         pinfo.sourceFiles.clear();
557         if (pinfo.defines != allDefinedMacros
558             || pinfo.includePaths != allIncludePaths
559             || pinfo.frameworkPaths != allFrameworkPaths
560             || pinfo.precompiledHeaders != allPrecompileHeaders)
561         {
562             pinfo.sourceFiles.append(QLatin1String("<configuration>"));
563         }
564
565         //pinfo.defines = predefinedMacros;
566         pinfo.defines = allDefinedMacros;
567         pinfo.includePaths = allIncludePaths;
568         pinfo.frameworkPaths = allFrameworkPaths;
569         pinfo.sourceFiles += files;
570         pinfo.precompiledHeaders = allPrecompileHeaders;
571
572         modelmanager->updateProjectInfo(pinfo);
573         m_codeModelFuture = modelmanager->updateSourceFiles(pinfo.sourceFiles);
574     }
575 }
576
577 void Qt4Project::updateQmlJSCodeModel()
578 {
579     if (m_projectFiles->files[QMLType].isEmpty())
580         return;
581
582     QmlJS::ModelManagerInterface *modelManager = QmlJS::ModelManagerInterface::instance();
583     if (!modelManager)
584         return;
585
586     QmlJS::ModelManagerInterface::ProjectInfo projectInfo = modelManager->projectInfo(this);
587
588     // Not essential since the QmlJS engine parses required files on demand.
589     //projectInfo.sourceFiles = ...
590
591     FindQt4ProFiles findQt4ProFiles;
592     QList<Qt4ProFileNode *> proFiles = findQt4ProFiles(rootProjectNode());
593
594     foreach (Qt4ProFileNode *node, proFiles) {
595         projectInfo.importPaths.append(node->variableValue(QmlImportPathVar));
596     }
597     if (activeTarget() && activeTarget()->activeBuildConfiguration()) {
598         const QtVersion *qtVersion = activeTarget()->activeBuildConfiguration()->qtVersion();
599         if (qtVersion->isValid()) {
600             const QString qtVersionImportPath = qtVersion->versionInfo().value("QT_INSTALL_IMPORTS");
601             if (!qtVersionImportPath.isEmpty())
602                 projectInfo.importPaths += qtVersionImportPath;
603         }
604     }
605     QmlDumpTool::pathAndEnvironment(this, &projectInfo.qmlDumpPath, &projectInfo.qmlDumpEnvironment);
606     projectInfo.importPaths.removeDuplicates();
607
608     modelManager->updateProjectInfo(projectInfo);
609 }
610
611 void Qt4Project::qtVersionsChanged()
612 {
613     setSupportedTargetIds(QtVersionManager::instance()->supportedTargetIds());
614 }
615
616 ///*!
617 //  Updates complete project
618 //  */
619 void Qt4Project::update()
620 {
621     if (debug)
622         qDebug()<<"Doing sync update";
623     m_rootProjectNode->update();
624
625     if (debug)
626         qDebug()<<"State is now Base";
627     m_asyncUpdateState = Base;
628 }
629
630 void Qt4Project::scheduleAsyncUpdate(Qt4ProFileNode *node)
631 {
632     if (m_asyncUpdateState == ShuttingDown)
633         return;
634
635     if (debug)
636         qDebug()<<"schduleAsyncUpdate (node)";
637     Q_ASSERT(m_asyncUpdateState != NoState);
638
639     if (m_cancelEvaluate) {
640         if (debug)
641             qDebug()<<"  Already canceling, nothing to do";
642         // A cancel is in progress
643         // That implies that a full update is going to happen afterwards
644         // So we don't need to do anything
645         return;
646     }
647
648     if (m_asyncUpdateState == AsyncFullUpdatePending) {
649         // Just postpone
650         if (debug)
651             qDebug()<<"  full update pending, restarting timer";
652         m_asyncUpdateTimer.start();
653     } else if (m_asyncUpdateState == AsyncPartialUpdatePending
654                || m_asyncUpdateState == Base) {
655         if (debug)
656             qDebug()<<"  adding node to async update list, setting state to AsyncPartialUpdatePending";
657         // Add the node
658         m_asyncUpdateState = AsyncPartialUpdatePending;
659
660         QList<Internal::Qt4ProFileNode *>::iterator it;
661         bool add = true;
662         if (debug)
663             qDebug()<<"scheduleAsyncUpdate();"<<m_partialEvaluate.size()<<"nodes";
664         it = m_partialEvaluate.begin();
665         while (it != m_partialEvaluate.end()) {
666             if (*it == node) {
667                 add = false;
668                 break;
669             } else if (node->isParent(*it)) { // We already have the parent in the list, nothing to do
670                 add = false;
671                 break;
672             } else if ((*it)->isParent(node)) { // The node is the parent of a child already in the list
673                 it = m_partialEvaluate.erase(it);
674             } else {
675                 ++it;
676             }
677         }
678
679         if (add)
680             m_partialEvaluate.append(node);
681         // and start the timer anew
682         m_asyncUpdateTimer.start();
683     } else if (m_asyncUpdateState == AsyncUpdateInProgress) {
684         // A update is in progress
685         // And this slot only gets called if a file changed on disc
686         // So we'll play it safe and schedule a complete evaluate
687         // This might trigger if due to version control a few files
688         // change a partial update gets in progress and then another
689         // batch of changes come in, which triggers a full update
690         // even if that's not really needed
691         if (debug)
692             qDebug()<<"  Async update in progress, scheduling new one afterwards";
693         scheduleAsyncUpdate();
694     }
695 }
696
697 void Qt4Project::scheduleAsyncUpdate()
698 {
699     if (debug)
700         qDebug()<<"scheduleAsyncUpdate";
701     if (m_asyncUpdateState == ShuttingDown)
702         return;
703
704     Q_ASSERT(m_asyncUpdateState != NoState);
705     if (m_cancelEvaluate) { // we are in progress of canceling
706                             // and will start the evaluation after that
707         if (debug)
708             qDebug()<<"  canceling is in progress, doing nothing";
709         return;
710     }
711     if (m_asyncUpdateState == AsyncUpdateInProgress) {
712         if (debug)
713             qDebug()<<"  update in progress, canceling and setting state to full update pending";
714         m_cancelEvaluate = true;
715         m_asyncUpdateState = AsyncFullUpdatePending;
716         m_rootProjectNode->emitProFileInvalidated();
717         return;
718     }
719
720     if (debug)
721         qDebug()<<"  starting timer for full update, setting state to full update pending";
722     m_partialEvaluate.clear();
723     m_rootProjectNode->emitProFileInvalidated();
724     m_asyncUpdateState = AsyncFullUpdatePending;
725     m_asyncUpdateTimer.start();
726
727     // Cancel running code model update
728     m_codeModelFuture.cancel();
729 }
730
731
732 void Qt4Project::incrementPendingEvaluateFutures()
733 {
734     ++m_pendingEvaluateFuturesCount;
735     if (debug)
736         qDebug()<<"incrementPendingEvaluateFutures to"<<m_pendingEvaluateFuturesCount;
737
738     m_asyncUpdateFutureInterface->setProgressRange(m_asyncUpdateFutureInterface->progressMinimum(),
739                                                   m_asyncUpdateFutureInterface->progressMaximum() + 1);
740 }
741
742 void Qt4Project::decrementPendingEvaluateFutures()
743 {
744     --m_pendingEvaluateFuturesCount;
745
746     if (debug)
747         qDebug()<<"decrementPendingEvaluateFutures to"<<m_pendingEvaluateFuturesCount;
748
749     m_asyncUpdateFutureInterface->setProgressValue(m_asyncUpdateFutureInterface->progressValue() + 1);
750     if (m_pendingEvaluateFuturesCount == 0) {
751         if (debug)
752             qDebug()<<"  WOHOO, no pending futures, cleaning up";
753         // We are done!
754         if (debug)
755             qDebug()<<"  reporting finished";
756         m_asyncUpdateFutureInterface->reportFinished();
757         delete m_asyncUpdateFutureInterface;
758         m_asyncUpdateFutureInterface = 0;
759         m_cancelEvaluate = false;
760
761         // TODO clear the profile cache ?
762         if (m_asyncUpdateState == AsyncFullUpdatePending || m_asyncUpdateState == AsyncPartialUpdatePending) {
763             if (debug)
764                 qDebug()<<"  Oh update is pending start the timer";
765             m_asyncUpdateTimer.start();
766         } else  if (m_asyncUpdateState != ShuttingDown){
767             // After beeing done, we need to call:
768             updateFileList();
769             updateCodeModels();
770             if (debug)
771                 qDebug()<<"  Setting state to Base";
772             m_asyncUpdateState = Base;
773         }
774     }
775 }
776
777 bool Qt4Project::wasEvaluateCanceled()
778 {
779     return m_cancelEvaluate;
780 }
781
782 QString Qt4Project::defaultTopLevelBuildDirectory() const
783 {
784     return defaultTopLevelBuildDirectory(file()->fileName());
785 }
786
787 QString Qt4Project::defaultTopLevelBuildDirectory(const QString &profilePath)
788 {
789     if (profilePath.isEmpty())
790         return QString();
791     QFileInfo info(profilePath);
792     return QDir(projectDirectory(profilePath) + QLatin1String("/../") + info.baseName() + QLatin1String("-build")).absolutePath();
793 }
794
795 void Qt4Project::asyncUpdate()
796 {
797     if (debug)
798         qDebug()<<"async update, timer expired, doing now";
799     Q_ASSERT(!m_asyncUpdateFutureInterface);
800     m_asyncUpdateFutureInterface = new QFutureInterface<void>();
801
802     Core::ProgressManager *progressManager = Core::ICore::instance()->progressManager();
803
804     m_asyncUpdateFutureInterface->setProgressRange(0, 0);
805     progressManager->addTask(m_asyncUpdateFutureInterface->future(), tr("Evaluating"), Constants::PROFILE_EVALUATE);
806     if (debug)
807         qDebug()<<"  adding task";
808
809     m_asyncUpdateFutureInterface->reportStarted();
810
811     if (m_asyncUpdateState == AsyncFullUpdatePending) {
812         if (debug)
813             qDebug()<<"  full update, starting with root node";
814         m_rootProjectNode->asyncUpdate();
815     } else {
816         if (debug)
817             qDebug()<<"  partial update,"<<m_partialEvaluate.size()<<"nodes to update";
818         foreach(Qt4ProFileNode *node, m_partialEvaluate)
819             node->asyncUpdate();
820     }
821
822     m_partialEvaluate.clear();
823     if (debug)
824         qDebug()<<"  Setting state to AsyncUpdateInProgress";
825     m_asyncUpdateState = AsyncUpdateInProgress;
826 }
827
828 ProjectExplorer::IProjectManager *Qt4Project::projectManager() const
829 {
830     return m_manager;
831 }
832
833 Qt4Manager *Qt4Project::qt4ProjectManager() const
834 {
835     return m_manager;
836 }
837
838 QString Qt4Project::displayName() const
839 {
840     return QFileInfo(file()->fileName()).completeBaseName();
841 }
842
843 QString Qt4Project::id() const
844 {
845     return QLatin1String(Constants::QT4PROJECT_ID);
846 }
847
848 Core::IFile *Qt4Project::file() const
849 {
850     return m_fileInfo;
851 }
852
853 QStringList Qt4Project::files(FilesMode fileMode) const
854 {
855     QStringList files;
856     for (int i = 0; i < FileTypeSize; ++i) {
857         files += m_projectFiles->files[i];
858         if (fileMode == AllFiles)
859             files += m_projectFiles->generatedFiles[i];
860     }
861     return files;
862 }
863
864 // Find the folder that contains a file a certain type (recurse down)
865 static FolderNode *folderOf(FolderNode *in, FileType fileType, const QString &fileName)
866 {
867     foreach(FileNode *fn, in->fileNodes())
868         if (fn->fileType() == fileType && fn->path() == fileName)
869             return in;
870     foreach(FolderNode *folder, in->subFolderNodes())
871         if (FolderNode *pn = folderOf(folder, fileType, fileName))
872             return pn;
873     return 0;
874 }
875
876 // Find the Qt4ProFileNode that contains a file of a certain type.
877 // First recurse down to folder, then find the pro-file.
878 static Qt4ProFileNode *proFileNodeOf(Qt4ProFileNode *in, FileType fileType, const QString &fileName)
879 {
880     for (FolderNode *folder =  folderOf(in, fileType, fileName); folder; folder = folder->parentFolderNode())
881         if (Qt4ProFileNode *proFile = qobject_cast<Qt4ProFileNode *>(folder))
882             return proFile;
883     return 0;
884 }
885
886 QString Qt4Project::generatedUiHeader(const QString &formFile) const
887 {
888     // Look in sub-profiles as SessionManager::projectForFile returns
889     // the top-level project only.
890     if (m_rootProjectNode)
891         if (const Qt4ProFileNode *pro = proFileNodeOf(m_rootProjectNode, FormType, formFile))
892             return Qt4ProFileNode::uiHeaderFile(pro->uiDirectory(), formFile);
893     return QString();
894 }
895
896 QList<ProjectExplorer::Project*> Qt4Project::dependsOn()
897 {
898     // NBS implement dependsOn
899     return QList<Project *>();
900 }
901
902 void Qt4Project::addDefaultBuild()
903 {
904     // TODO this could probably refactored
905     // That is the ProjectLoadWizard divided into useful bits
906     // and this code then called here, instead of that strange forwarding
907     // to a wizard, which doesn't even show up
908     ProjectLoadWizard wizard(this);
909     wizard.execDialog();
910 }
911
912 void Qt4Project::proFileParseError(const QString &errorMessage)
913 {
914     Core::ICore::instance()->messageManager()->printToOutputPane(errorMessage);
915 }
916
917 ProFileReader *Qt4Project::createProFileReader(Qt4ProFileNode *qt4ProFileNode)
918 {
919     if (!m_proFileOption) {
920         m_proFileOption = new ProFileOption;
921         m_proFileOptionRefCnt = 0;
922
923         if (activeTarget() &&
924             activeTarget()->activeBuildConfiguration()) {
925             QtVersion *version = activeTarget()->activeBuildConfiguration()->qtVersion();
926             if (version->isValid())
927                 m_proFileOption->properties = version->versionInfo();
928         }
929
930         ProFileCacheManager::instance()->incRefCount();
931     }
932     ++m_proFileOptionRefCnt;
933
934     ProFileReader *reader = new ProFileReader(m_proFileOption);
935
936     reader->setOutputDir(qt4ProFileNode->buildDir());
937
938     return reader;
939 }
940
941 void Qt4Project::destroyProFileReader(ProFileReader *reader)
942 {
943     delete reader;
944     if (!--m_proFileOptionRefCnt) {
945         QString dir = QFileInfo(m_fileInfo->fileName()).absolutePath();
946         if (!dir.endsWith(QLatin1Char('/')))
947             dir += QLatin1Char('/');
948         ProFileCacheManager::instance()->discardFiles(dir);
949         ProFileCacheManager::instance()->decRefCount();
950
951         delete m_proFileOption;
952         m_proFileOption = 0;
953     }
954 }
955
956 Qt4ProFileNode *Qt4Project::rootProjectNode() const
957 {
958     return m_rootProjectNode;
959 }
960
961 bool Qt4Project::validParse(const QString &proFilePath) const
962 {
963     return true;
964     if (!m_rootProjectNode)
965         return false;
966     const Qt4ProFileNode *node = m_rootProjectNode->findProFileFor(proFilePath);
967     return node && node->validParse();
968 }
969
970 BuildConfigWidget *Qt4Project::createConfigWidget()
971 {
972     return new Qt4ProjectConfigWidget(this);
973 }
974
975 QList<BuildConfigWidget*> Qt4Project::subConfigWidgets()
976 {
977     QList<BuildConfigWidget*> subWidgets;
978     subWidgets << new BuildEnvironmentWidget;
979     return subWidgets;
980 }
981
982 void Qt4Project::collectLeafProFiles(QList<Qt4ProFileNode *> &list, Qt4ProFileNode *node)
983 {
984     if (node->projectType() != Internal::SubDirsTemplate) {
985         list.append(node);
986     }
987     foreach (ProjectNode *n, node->subProjectNodes()) {
988         Qt4ProFileNode *qt4ProFileNode = qobject_cast<Qt4ProFileNode *>(n);
989         if (qt4ProFileNode)
990             collectLeafProFiles(list, qt4ProFileNode);
991     }
992 }
993
994
995 void Qt4Project::collectApplicationProFiles(QList<Qt4ProFileNode *> &list, Qt4ProFileNode *node)
996 {
997     if (node->projectType() == Internal::ApplicationTemplate
998         || node->projectType() == Internal::ScriptTemplate) {
999         list.append(node);
1000     }
1001     foreach (ProjectNode *n, node->subProjectNodes()) {
1002         Qt4ProFileNode *qt4ProFileNode = qobject_cast<Qt4ProFileNode *>(n);
1003         if (qt4ProFileNode)
1004             collectApplicationProFiles(list, qt4ProFileNode);
1005     }
1006 }
1007
1008 void Qt4Project::createApplicationProjects()
1009 {
1010     foreach (Target *target, targets()) {
1011         if (target->runConfigurations().count()) {
1012             // Remove all run configurations which the new project wizard created
1013             QList<RunConfiguration*> toRemove;
1014             foreach (RunConfiguration * rc, target->runConfigurations()) {
1015                 CustomExecutableRunConfiguration *cerc = qobject_cast<CustomExecutableRunConfiguration *>(rc);
1016                 if (cerc && !cerc->isConfigured())
1017                     toRemove.append(rc);
1018             }
1019             foreach (RunConfiguration *rc, toRemove)
1020                 target->removeRunConfiguration(rc);
1021         }
1022
1023         // We use the list twice
1024         QList<Qt4ProFileNode *> profiles = applicationProFiles();
1025         QStringList paths;
1026         foreach (Qt4ProFileNode *pro, profiles)
1027             paths << pro->path();
1028
1029         foreach (RunConfiguration *rc, target->runConfigurations()) {
1030             if (Qt4RunConfiguration *qt4rc = qobject_cast<Qt4RunConfiguration *>(rc)) {
1031                 if (!paths.contains(qt4rc->proFilePath())) {
1032                     // A deleted .pro file? or a change template
1033                     // We do remove those though
1034                     target->removeRunConfiguration(rc);
1035                 }
1036             }
1037         }
1038
1039         // Only add new runconfigurations if there are none.
1040         if (target->runConfigurations().isEmpty()) {
1041             Qt4Target *qt4Target = static_cast<Qt4Target *>(target);
1042             foreach (Qt4ProFileNode *qt4proFile, profiles) {
1043                 qt4Target->addRunConfigurationForPath(qt4proFile->path());
1044             }
1045         }
1046         // Oh still none? Add a custom executable runconfiguration
1047         if (target->runConfigurations().isEmpty()) {
1048             target->addRunConfiguration(new ProjectExplorer::CustomExecutableRunConfiguration(target));
1049         }
1050     }
1051 }
1052
1053 QList<Qt4ProFileNode *> Qt4Project::leafProFiles() const
1054 {
1055     QList<Qt4ProFileNode *> list;
1056     if (!rootProjectNode())
1057         return list;
1058     collectLeafProFiles(list, rootProjectNode());
1059     return list;
1060 }
1061
1062 QList<Qt4ProFileNode *> Qt4Project::applicationProFiles() const
1063 {
1064     QList<Qt4ProFileNode *> list;
1065     if (!rootProjectNode())
1066         return list;
1067     collectApplicationProFiles(list, rootProjectNode());
1068     return list;
1069 }
1070
1071 bool Qt4Project::hasApplicationProFile(const QString &path) const
1072 {
1073     if (path.isEmpty())
1074         return false;
1075
1076     QList<Qt4ProFileNode *> list = applicationProFiles();
1077     foreach (Qt4ProFileNode * node, list)
1078         if (node->path() == path)
1079             return true;
1080     return false;
1081 }
1082
1083 QStringList Qt4Project::applicationProFilePathes(const QString &prepend) const
1084 {
1085     QStringList proFiles;
1086     foreach (Qt4ProFileNode *node, applicationProFiles())
1087         proFiles.append(prepend + node->path());
1088     return proFiles;
1089 }
1090
1091 void Qt4Project::activeTargetWasChanged()
1092 {
1093     if (!activeTarget())
1094         return;
1095
1096     scheduleAsyncUpdate();
1097 }
1098
1099 bool Qt4Project::hasSubNode(Qt4PriFileNode *root, const QString &path)
1100 {
1101     if (root->path() == path)
1102         return true;
1103     foreach (FolderNode *fn, root->subFolderNodes()) {
1104         if (qobject_cast<Qt4ProFileNode *>(fn)) {
1105             // we aren't interested in pro file nodes
1106         } else if (Qt4PriFileNode *qt4prifilenode = qobject_cast<Qt4PriFileNode *>(fn)) {
1107             if (hasSubNode(qt4prifilenode, path))
1108                 return true;
1109         }
1110     }
1111     return false;
1112 }
1113
1114 void Qt4Project::findProFile(const QString& fileName, Qt4ProFileNode *root, QList<Qt4ProFileNode *> &list)
1115 {
1116     if (hasSubNode(root, fileName))
1117         list.append(root);
1118
1119     foreach (FolderNode *fn, root->subFolderNodes())
1120         if (Qt4ProFileNode *qt4proFileNode =  qobject_cast<Qt4ProFileNode *>(fn))
1121             findProFile(fileName, qt4proFileNode, list);
1122 }
1123
1124 void Qt4Project::notifyChanged(const QString &name)
1125 {
1126     if (files(Qt4Project::ExcludeGeneratedFiles).contains(name)) {
1127         QList<Qt4ProFileNode *> list;
1128         findProFile(name, rootProjectNode(), list);
1129         foreach(Qt4ProFileNode *node, list) {
1130             ProFileCacheManager::instance()->discardFile(name);
1131             node->update();
1132         }
1133     }
1134 }
1135
1136 CentralizedFolderWatcher *Qt4Project::centralizedFolderWatcher()
1137 {
1138     return &m_centralizedFolderWatcher;
1139 }
1140
1141 /////////////
1142 /// Centralized Folder Watcher
1143 ////////////
1144
1145 // All the folder have a trailing slash!
1146
1147 namespace {
1148    bool debugCFW = false;
1149 }
1150
1151 CentralizedFolderWatcher::CentralizedFolderWatcher()
1152 {
1153     m_compressTimer.setSingleShot(true);
1154     m_compressTimer.setInterval(200);
1155     connect(&m_compressTimer, SIGNAL(timeout()),
1156             this, SLOT(onTimer()));
1157     connect (&m_watcher, SIGNAL(directoryChanged(QString)),
1158              this, SLOT(folderChanged(QString)));
1159 }
1160
1161 CentralizedFolderWatcher::~CentralizedFolderWatcher()
1162 {
1163
1164 }
1165
1166 QSet<QString> CentralizedFolderWatcher::recursiveDirs(const QString &folder)
1167 {
1168     QSet<QString> result;
1169     QDir dir(folder);
1170     QStringList list = dir.entryList(QDir::Dirs | QDir::NoSymLinks | QDir::NoDotAndDotDot);
1171     foreach (const QString &f, list) {
1172         result.insert(folder + f + "/");
1173         result += recursiveDirs(folder + f + "/");
1174     }
1175     return result;
1176 }
1177
1178 void CentralizedFolderWatcher::watchFolders(const QList<QString> &folders, Qt4PriFileNode *node)
1179 {
1180     if (debugCFW)
1181         qDebug()<<"CFW::watchFolders()"<<folders<<"for node"<<node->path();
1182     m_watcher.addPaths(folders);
1183
1184     foreach (const QString &f, folders) {
1185         QString folder = f;
1186         if (!folder.endsWith('/'))
1187             folder.append('/');
1188         m_map.insert(folder, node);
1189
1190         // Support for recursive watching
1191         // we add the recursive directories we find
1192         QSet<QString> tmp = recursiveDirs(folder);
1193         if (!tmp.isEmpty())
1194             m_watcher.addPaths(tmp.toList());
1195         m_recursiveWatchedFolders += tmp;
1196
1197         if (debugCFW)
1198             qDebug()<<"adding recursive dirs for"<< folder<<":"<<tmp;
1199     }
1200 }
1201
1202 void CentralizedFolderWatcher::unwatchFolders(const QList<QString> &folders, Qt4PriFileNode *node)
1203 {
1204     if (debugCFW)
1205         qDebug()<<"CFW::unwatchFolders()"<<folders<<"for node"<<node->path();
1206     foreach (const QString &f, folders) {
1207         QString folder = f;
1208         if (!folder.endsWith('/'))
1209             folder.append('/');
1210         m_map.remove(folder, node);
1211         if (!m_map.contains(folder)) {
1212             m_watcher.removePath(folder);
1213         }
1214
1215         // Figure out which recursive directories we can remove
1216         // TODO this might not scale. I'm pretty sure it doesn't
1217         // A scaling implementation would need to save more information
1218         // where a given directory watcher actual comes from...
1219
1220         QStringList toRemove;
1221         foreach (const QString &rwf, m_recursiveWatchedFolders) {
1222             if (rwf.startsWith(folder)) {
1223                 // So the rwf is a subdirectory of a folder we aren't watching
1224                 // but maybe someone else wants us to watch
1225                 bool needToWatch = false;
1226                 QMultiMap<QString, Qt4PriFileNode *>::const_iterator it, end;
1227                 end = m_map.constEnd();
1228                 for (it = m_map.constEnd(); it != end; ++it) {
1229                     if (rwf.startsWith(it.key())) {
1230                         needToWatch = true;
1231                         break;
1232                     }
1233                 }
1234                 if (!needToWatch) {
1235                     m_watcher.removePath(rwf);
1236                     toRemove << rwf;
1237                 }
1238             }
1239         }
1240
1241         if (debugCFW)
1242             qDebug()<<"removing recursive dirs for"<<folder<<":"<<toRemove;
1243
1244         foreach (const QString &tr, toRemove) {
1245             m_recursiveWatchedFolders.remove(tr);
1246         }
1247     }
1248 }
1249
1250 void CentralizedFolderWatcher::folderChanged(const QString &folder)
1251 {
1252     m_changedFolders.insert(folder);
1253     m_compressTimer.start();
1254 }
1255
1256 void CentralizedFolderWatcher::onTimer()
1257 {
1258     foreach(const QString &folder, m_changedFolders)
1259         delayedFolderChanged(folder);
1260     m_changedFolders.clear();
1261 }
1262
1263 void CentralizedFolderWatcher::delayedFolderChanged(const QString &folder)
1264 {
1265     if (debugCFW)
1266         qDebug()<<"CFW::folderChanged"<<folder;
1267     // Figure out whom to inform
1268
1269     QString dir = folder;
1270     while (true) {
1271         if (!dir.endsWith('/'))
1272             dir.append('/');
1273         QList<Qt4PriFileNode *> nodes = m_map.values(dir);
1274         foreach (Qt4PriFileNode *node, nodes) {
1275             node->folderChanged(folder);
1276         }
1277
1278         // Chop off last part, and break if there's nothing to chop off
1279         //
1280         if (dir.length() < 2)
1281             break;
1282
1283         // We start before the last slash
1284         int index = dir.lastIndexOf('/', dir.length() - 2);
1285         if (index == -1)
1286             break;
1287         dir = dir.left(index + 1);
1288     }
1289
1290
1291     QString folderWithSlash = folder;
1292     if (!folder.endsWith('/'))
1293         folderWithSlash.append('/');
1294
1295     // If a subdirectory was added, watch it too
1296     QSet<QString> tmp = recursiveDirs(folderWithSlash);
1297     if (!tmp.isEmpty()) {
1298         if (debugCFW)
1299             qDebug()<<"found new recursive dirs"<<tmp;
1300
1301         QSet<QString> alreadyAdded = m_watcher.directories().toSet();
1302         tmp.subtract(alreadyAdded);
1303         if (!tmp.isEmpty())
1304             m_watcher.addPaths(tmp.toList());
1305         m_recursiveWatchedFolders += tmp;
1306     }
1307 }
1308
1309 /*!
1310   Handle special case were a subproject of the qt directory is opened, and
1311   qt was configured to be built as a shadow build -> also build in the sub-
1312   project in the correct shadow build directory.
1313   */
1314
1315 // TODO this function should be called on project first load
1316 // and it should check against all configured qt versions ?
1317 //void Qt4Project::detectQtShadowBuild(const QString &buildConfiguration) const
1318 //{
1319 //    if (project()->activeBuildConfiguration() == buildConfiguration)
1320 //        return;
1321 //
1322 //    const QString currentQtDir = static_cast<Qt4Project *>(project())->qtDir(buildConfiguration);
1323 //    const QString qtSourceDir = static_cast<Qt4Project *>(project())->qtVersion(buildConfiguration)->sourcePath();
1324 //
1325 //    // if the project is a sub-project of Qt and Qt was shadow-built then automatically
1326 //    // adjust the build directory of the sub-project.
1327 //    if (project()->file()->fileName().startsWith(qtSourceDir) && qtSourceDir != currentQtDir) {
1328 //        project()->setValue(buildConfiguration, "useShadowBuild", true);
1329 //        QString buildDir = project()->projectDirectory();
1330 //        buildDir.replace(qtSourceDir, currentQtDir);
1331 //        project()->setValue(buildConfiguration, "buildDirectory", buildDir);
1332 //        project()->setValue(buildConfiguration, "autoShadowBuild", true);
1333 //    }
1334 //}
1335
1336