OSDN Git Service

Update license.
[qt-creator-jp/qt-creator-jp.git] / src / plugins / cmakeprojectmanager / cmakeproject.cpp
1 /**************************************************************************
2 **
3 ** This file is part of Qt Creator
4 **
5 ** Copyright (c) 2011 Nokia Corporation and/or its subsidiary(-ies).
6 **
7 ** Contact: Nokia Corporation (info@qt.nokia.com)
8 **
9 **
10 ** GNU Lesser General Public License Usage
11 **
12 ** This file may be used under the terms of the GNU Lesser General Public
13 ** License version 2.1 as published by the Free Software Foundation and
14 ** appearing in the file LICENSE.LGPL included in the packaging of this file.
15 ** Please review the following information to ensure the GNU Lesser General
16 ** Public License version 2.1 requirements will be met:
17 ** http://www.gnu.org/licenses/old-licenses/lgpl-2.1.html.
18 **
19 ** In addition, as a special exception, Nokia gives you certain additional
20 ** rights. These rights are described in the Nokia Qt LGPL Exception
21 ** version 1.1, included in the file LGPL_EXCEPTION.txt in this package.
22 **
23 ** Other Usage
24 **
25 ** Alternatively, this file may be used in accordance with the terms and
26 ** conditions contained in a signed written agreement between you and Nokia.
27 **
28 ** If you have questions regarding the use of this file, please contact
29 ** Nokia at qt-info@nokia.com.
30 **
31 **************************************************************************/
32
33 #include "cmakeproject.h"
34 #include "cmakeprojectconstants.h"
35 #include "cmakeprojectnodes.h"
36 #include "cmakerunconfiguration.h"
37 #include "cmaketarget.h"
38 #include "makestep.h"
39 #include "cmakeopenprojectwizard.h"
40 #include "cmakebuildconfiguration.h"
41 #include "cmakeuicodemodelsupport.h"
42
43 #include <projectexplorer/projectexplorerconstants.h>
44 #include <projectexplorer/projectexplorer.h>
45 #include <projectexplorer/headerpath.h>
46 #include <projectexplorer/buildenvironmentwidget.h>
47 #include <projectexplorer/buildsteplist.h>
48 #include <projectexplorer/buildmanager.h>
49 #include <projectexplorer/toolchain.h>
50 #include <cplusplus/ModelManagerInterface.h>
51 #include <extensionsystem/pluginmanager.h>
52 #include <utils/qtcassert.h>
53 #include <coreplugin/icore.h>
54 #include <coreplugin/editormanager/editormanager.h>
55
56 #include <QtCore/QMap>
57 #include <QtCore/QDebug>
58 #include <QtCore/QDir>
59 #include <QtCore/QDateTime>
60 #include <QtCore/QProcess>
61 #include <QtGui/QFormLayout>
62 #include <QtGui/QMainWindow>
63 #include <QtGui/QInputDialog>
64
65 using namespace CMakeProjectManager;
66 using namespace CMakeProjectManager::Internal;
67 using namespace ProjectExplorer;
68
69 // QtCreator CMake Generator wishlist:
70 // Which make targets we need to build to get all executables
71 // What is the make we need to call
72 // What is the actual compiler executable
73 // DEFINES
74
75 // Open Questions
76 // Who sets up the environment for cl.exe ? INCLUDEPATH and so on
77
78 // Test for form editor (loosely coupled)
79 static inline bool isFormWindowEditor(const QObject *o)
80 {
81     return o && !qstrcmp(o->metaObject()->className(), "Designer::FormWindowEditor");
82 }
83
84 // Return contents of form editor (loosely coupled)
85 static inline QString formWindowEditorContents(const QObject *editor)
86 {
87     const QVariant contentV = editor->property("contents");
88     QTC_ASSERT(contentV.isValid(), return QString(); )
89     return contentV.toString();
90 }
91
92 /*!
93   \class CMakeProject
94 */
95 CMakeProject::CMakeProject(CMakeManager *manager, const QString &fileName)
96     : m_manager(manager),
97       m_fileName(fileName),
98       m_rootNode(new CMakeProjectNode(m_fileName)),
99       m_insideFileChanged(false),
100       m_lastEditor(0)
101 {
102     m_file = new CMakeFile(this, fileName);
103
104     connect(this, SIGNAL(addedTarget(ProjectExplorer::Target*)),
105             SLOT(targetAdded(ProjectExplorer::Target*)));
106 }
107
108 CMakeProject::~CMakeProject()
109 {
110     // Remove CodeModel support
111     CPlusPlus::CppModelManagerInterface *modelManager
112             = CPlusPlus::CppModelManagerInterface::instance();
113     QMap<QString, CMakeUiCodeModelSupport *>::const_iterator it, end;
114     it = m_uiCodeModelSupport.constBegin();
115     end = m_uiCodeModelSupport.constEnd();
116     for (; it!=end; ++it) {
117         modelManager->removeEditorSupport(it.value());
118         delete it.value();
119     }
120
121     m_codeModelFuture.cancel();
122     delete m_rootNode;
123 }
124
125 void CMakeProject::fileChanged(const QString &fileName)
126 {
127     Q_UNUSED(fileName)
128     if (!activeTarget() ||
129         !activeTarget()->activeBuildConfiguration())
130         return;
131
132     if (m_insideFileChanged)
133         return;
134     m_insideFileChanged = true;
135     changeActiveBuildConfiguration(activeTarget()->activeBuildConfiguration());
136     m_insideFileChanged = false;
137 }
138
139 void CMakeProject::changeActiveBuildConfiguration(ProjectExplorer::BuildConfiguration *bc)
140 {
141     if (!bc || bc->target() != activeTarget())
142         return;
143
144     CMakeBuildConfiguration * cmakebc(qobject_cast<CMakeBuildConfiguration *>(bc));
145     if (!cmakebc)
146         return;
147
148     // Pop up a dialog asking the user to rerun cmake
149     QFileInfo sourceFileInfo(m_fileName);
150
151     QString cbpFile = CMakeManager::findCbpFile(QDir(bc->buildDirectory()));
152     QFileInfo cbpFileFi(cbpFile);
153     CMakeOpenProjectWizard::Mode mode = CMakeOpenProjectWizard::Nothing;
154     if (!cbpFileFi.exists()) {
155         mode = CMakeOpenProjectWizard::NeedToCreate;
156     } else {
157         foreach(const QString &file, m_watchedFiles) {
158             if (QFileInfo(file).lastModified() > cbpFileFi.lastModified()) {
159                 mode = CMakeOpenProjectWizard::NeedToUpdate;
160                 break;
161             }
162         }
163     }
164
165     if (mode != CMakeOpenProjectWizard::Nothing) {
166         CMakeOpenProjectWizard copw(m_manager,
167                                     sourceFileInfo.absolutePath(),
168                                     cmakebc->buildDirectory(),
169                                     mode,
170                                     cmakebc->environment());
171         copw.exec();
172     }
173     // reparse
174     parseCMakeLists();
175 }
176
177 void CMakeProject::targetAdded(ProjectExplorer::Target *t)
178 {
179     if (!t)
180         return;
181
182     connect(t, SIGNAL(activeBuildConfigurationChanged(ProjectExplorer::BuildConfiguration*)),
183             SLOT(changeActiveBuildConfiguration(ProjectExplorer::BuildConfiguration*)));
184 }
185
186 void CMakeProject::changeBuildDirectory(CMakeBuildConfiguration *bc, const QString &newBuildDirectory)
187 {
188     bc->setBuildDirectory(newBuildDirectory);
189     parseCMakeLists();
190 }
191
192 QString CMakeProject::defaultBuildDirectory() const
193 {
194     return projectDirectory() + QLatin1String("/qtcreator-build");
195 }
196
197 bool CMakeProject::parseCMakeLists()
198 {
199     if (!activeTarget() ||
200         !activeTarget()->activeBuildConfiguration())
201         return false;
202
203     // Find cbp file
204     CMakeBuildConfiguration *activeBC = activeTarget()->activeBuildConfiguration();
205     QString cbpFile = CMakeManager::findCbpFile(activeBC->buildDirectory());
206
207     // setFolderName
208     m_rootNode->setDisplayName(QFileInfo(cbpFile).completeBaseName());
209     CMakeCbpParser cbpparser;
210     // Parsing
211     //qDebug()<<"Parsing file "<<cbpFile;
212     if (!cbpparser.parseCbpFile(cbpFile)) {
213         // TODO report error
214         qDebug()<<"Parsing failed";
215         // activeBC->updateToolChain(QString::null);
216         emit buildTargetsChanged();
217         return false;
218     }
219
220     // ToolChain
221     // activeBC->updateToolChain(cbpparser.compilerName());
222     m_projectName = cbpparser.projectName();
223     m_rootNode->setDisplayName(cbpparser.projectName());
224
225     //qDebug()<<"Building Tree";
226     QList<ProjectExplorer::FileNode *> fileList = cbpparser.fileList();
227     QSet<QString> projectFiles;
228     if (cbpparser.hasCMakeFiles()) {
229         fileList.append(cbpparser.cmakeFileList());
230         foreach(const ProjectExplorer::FileNode *node, cbpparser.cmakeFileList())
231             projectFiles.insert(node->path());
232     } else {
233         // Manually add the CMakeLists.txt file
234         QString cmakeListTxt = projectDirectory() + "/CMakeLists.txt";
235         bool generated = false;
236         fileList.append(new ProjectExplorer::FileNode(cmakeListTxt, ProjectExplorer::ProjectFileType, generated));
237         projectFiles.insert(cmakeListTxt);
238     }
239
240     QSet<QString> added = projectFiles;
241     added.subtract(m_watchedFiles);
242     foreach(const QString &add, added)
243         m_watcher->addFile(add);
244     foreach(const QString &remove, m_watchedFiles.subtract(projectFiles))
245         m_watcher->removeFile(remove);
246     m_watchedFiles = projectFiles;
247
248     m_files.clear();
249     foreach (ProjectExplorer::FileNode *fn, fileList)
250         m_files.append(fn->path());
251     m_files.sort();
252
253     buildTree(m_rootNode, fileList);
254
255     //qDebug()<<"Adding Targets";
256     m_buildTargets = cbpparser.buildTargets();
257 //        qDebug()<<"Printing targets";
258 //        foreach(CMakeBuildTarget ct, m_buildTargets) {
259 //            qDebug()<<ct.title<<" with executable:"<<ct.executable;
260 //            qDebug()<<"WD:"<<ct.workingDirectory;
261 //            qDebug()<<ct.makeCommand<<ct.makeCleanCommand;
262 //            qDebug()<<"";
263 //        }
264
265
266     // TOOD this code ain't very pretty ...
267     m_uicCommand.clear();
268     QFile cmakeCache(activeBC->buildDirectory() + "/CMakeCache.txt");
269     cmakeCache.open(QIODevice::ReadOnly);
270     while (!cmakeCache.atEnd()) {
271         QString line = cmakeCache.readLine();
272         if (line.startsWith("QT_UIC_EXECUTABLE")) {
273             if (int pos = line.indexOf('=')) {
274                 m_uicCommand = line.mid(pos + 1).trimmed();
275             }
276             break;
277         }
278     }
279     cmakeCache.close();
280
281     //qDebug()<<"Updating CodeModel";
282     createUiCodeModelSupport();
283
284     if (!activeBC->toolChain())
285         return true;
286
287     QStringList allIncludePaths;
288     // This explicitly adds -I. to the include paths
289     allIncludePaths.append(projectDirectory());
290     allIncludePaths.append(cbpparser.includeFiles());
291
292     QStringList allFrameworkPaths;
293     QList<ProjectExplorer::HeaderPath> allHeaderPaths = activeBC->toolChain()->systemHeaderPaths();
294     foreach (const ProjectExplorer::HeaderPath &headerPath, allHeaderPaths) {
295         if (headerPath.kind() == ProjectExplorer::HeaderPath::FrameworkHeaderPath)
296             allFrameworkPaths.append(headerPath.path());
297         else
298             allIncludePaths.append(headerPath.path());
299     }
300
301     CPlusPlus::CppModelManagerInterface *modelmanager =
302             CPlusPlus::CppModelManagerInterface::instance();
303     if (modelmanager) {
304         CPlusPlus::CppModelManagerInterface::ProjectInfo pinfo = modelmanager->projectInfo(this);
305         if (pinfo.includePaths != allIncludePaths
306             || pinfo.sourceFiles != m_files
307             || pinfo.defines != activeBC->toolChain()->predefinedMacros()
308             || pinfo.frameworkPaths != allFrameworkPaths)  {
309             pinfo.includePaths = allIncludePaths;
310             // TODO we only want C++ files, not all other stuff that might be in the project
311             pinfo.sourceFiles = m_files;
312             pinfo.defines = activeBC->toolChain()->predefinedMacros(); // TODO this is to simplistic
313             pinfo.frameworkPaths = allFrameworkPaths;
314             modelmanager->updateProjectInfo(pinfo);
315             m_codeModelFuture.cancel();
316             m_codeModelFuture = modelmanager->updateSourceFiles(pinfo.sourceFiles);
317         }
318     }
319
320     emit buildTargetsChanged();
321     emit fileListChanged();
322     return true;
323 }
324
325 QList<CMakeBuildTarget> CMakeProject::buildTargets() const
326 {
327     return m_buildTargets;
328 }
329
330 QStringList CMakeProject::buildTargetTitles() const
331 {
332     QStringList results;
333     foreach (const CMakeBuildTarget &ct, m_buildTargets) {
334         if (ct.executable.isEmpty())
335             continue;
336         if (ct.title.endsWith(QLatin1String("/fast")))
337             continue;
338         results << ct.title;
339     }
340     return results;
341 }
342
343 bool CMakeProject::hasBuildTarget(const QString &title) const
344 {
345     foreach (const CMakeBuildTarget &ct, m_buildTargets) {
346         if (ct.executable.isEmpty())
347             continue;
348         if (ct.title.endsWith(QLatin1String("/fast")))
349             continue;
350         if (ct.title == title)
351             return true;
352     }
353     return false;
354 }
355
356 void CMakeProject::gatherFileNodes(ProjectExplorer::FolderNode *parent, QList<ProjectExplorer::FileNode *> &list)
357 {
358     foreach(ProjectExplorer::FolderNode *folder, parent->subFolderNodes())
359         gatherFileNodes(folder, list);
360     foreach(ProjectExplorer::FileNode *file, parent->fileNodes())
361         list.append(file);
362 }
363
364 void CMakeProject::buildTree(CMakeProjectNode *rootNode, QList<ProjectExplorer::FileNode *> newList)
365 {
366     // Gather old list
367     QList<ProjectExplorer::FileNode *> oldList;
368     gatherFileNodes(rootNode, oldList);
369     qSort(oldList.begin(), oldList.end(), ProjectExplorer::ProjectNode::sortNodesByPath);
370     qSort(newList.begin(), newList.end(), ProjectExplorer::ProjectNode::sortNodesByPath);
371
372     // generate added and deleted list
373     QList<ProjectExplorer::FileNode *>::const_iterator oldIt  = oldList.constBegin();
374     QList<ProjectExplorer::FileNode *>::const_iterator oldEnd = oldList.constEnd();
375     QList<ProjectExplorer::FileNode *>::const_iterator newIt  = newList.constBegin();
376     QList<ProjectExplorer::FileNode *>::const_iterator newEnd = newList.constEnd();
377
378     QList<ProjectExplorer::FileNode *> added;
379     QList<ProjectExplorer::FileNode *> deleted;
380
381
382     while(oldIt != oldEnd && newIt != newEnd) {
383         if ( (*oldIt)->path() == (*newIt)->path()) {
384             delete *newIt;
385             ++oldIt;
386             ++newIt;
387         } else if ((*oldIt)->path() < (*newIt)->path()) {
388             deleted.append(*oldIt);
389             ++oldIt;
390         } else {
391             added.append(*newIt);
392             ++newIt;
393         }
394     }
395
396     while (oldIt != oldEnd) {
397         deleted.append(*oldIt);
398         ++oldIt;
399     }
400
401     while (newIt != newEnd) {
402         added.append(*newIt);
403         ++newIt;
404     }
405
406     // add added nodes
407     foreach (ProjectExplorer::FileNode *fn, added) {
408 //        qDebug()<<"added"<<fn->path();
409         // Get relative path to rootNode
410         QString parentDir = QFileInfo(fn->path()).absolutePath();
411         ProjectExplorer::FolderNode *folder = findOrCreateFolder(rootNode, parentDir);
412         rootNode->addFileNodes(QList<ProjectExplorer::FileNode *>()<< fn, folder);
413     }
414
415     // remove old file nodes and check whether folder nodes can be removed
416     foreach (ProjectExplorer::FileNode *fn, deleted) {
417         ProjectExplorer::FolderNode *parent = fn->parentFolderNode();
418 //        qDebug()<<"removed"<<fn->path();
419         rootNode->removeFileNodes(QList<ProjectExplorer::FileNode *>() << fn, parent);
420         // Check for empty parent
421         while (parent->subFolderNodes().isEmpty() && parent->fileNodes().isEmpty()) {
422             ProjectExplorer::FolderNode *grandparent = parent->parentFolderNode();
423             rootNode->removeFolderNodes(QList<ProjectExplorer::FolderNode *>() << parent, grandparent);
424             parent = grandparent;
425             if (parent == rootNode)
426                 break;
427         }
428     }
429 }
430
431 ProjectExplorer::FolderNode *CMakeProject::findOrCreateFolder(CMakeProjectNode *rootNode, QString directory)
432 {
433     QString relativePath = QDir(QFileInfo(rootNode->path()).path()).relativeFilePath(directory);
434     QStringList parts = relativePath.split(QLatin1Char('/'), QString::SkipEmptyParts);
435     ProjectExplorer::FolderNode *parent = rootNode;
436     QString path = QFileInfo(rootNode->path()).path();
437     foreach (const QString &part, parts) {
438         path += QLatin1Char('/');
439         path += part;
440         // Find folder in subFolders
441         bool found = false;
442         foreach (ProjectExplorer::FolderNode *folder, parent->subFolderNodes()) {
443             if (folder->path() == path) {
444                 // yeah found something :)
445                 parent = folder;
446                 found = true;
447                 break;
448             }
449         }
450         if (!found) {
451             // No FolderNode yet, so create it
452             ProjectExplorer::FolderNode *tmp = new ProjectExplorer::FolderNode(path);
453             tmp->setDisplayName(part);
454             rootNode->addFolderNodes(QList<ProjectExplorer::FolderNode *>() << tmp, parent);
455             parent = tmp;
456         }
457     }
458     return parent;
459 }
460
461 QString CMakeProject::displayName() const
462 {
463     return m_projectName;
464 }
465
466 QString CMakeProject::id() const
467 {
468     return QLatin1String(Constants::CMAKEPROJECT_ID);
469 }
470
471 Core::IFile *CMakeProject::file() const
472 {
473     return m_file;
474 }
475
476 CMakeManager *CMakeProject::projectManager() const
477 {
478     return m_manager;
479 }
480
481 CMakeTarget *CMakeProject::activeTarget() const
482 {
483     return static_cast<CMakeTarget *>(Project::activeTarget());
484 }
485
486 QList<ProjectExplorer::Project *> CMakeProject::dependsOn()
487 {
488     return QList<Project *>();
489 }
490
491 QList<ProjectExplorer::BuildConfigWidget*> CMakeProject::subConfigWidgets()
492 {
493     QList<ProjectExplorer::BuildConfigWidget*> list;
494     list << new BuildEnvironmentWidget;
495     return list;
496 }
497
498 ProjectExplorer::ProjectNode *CMakeProject::rootProjectNode() const
499 {
500     return m_rootNode;
501 }
502
503
504 QStringList CMakeProject::files(FilesMode fileMode) const
505 {
506     Q_UNUSED(fileMode)
507     return m_files;
508 }
509
510 bool CMakeProject::fromMap(const QVariantMap &map)
511 {
512     if (!Project::fromMap(map))
513         return false;
514
515     bool hasUserFile = activeTarget();
516     if (!hasUserFile) {
517         CMakeTargetFactory *factory =
518                 ExtensionSystem::PluginManager::instance()->getObject<CMakeTargetFactory>();
519         CMakeTarget *t = factory->create(this, QLatin1String(DEFAULT_CMAKE_TARGET_ID));
520
521         Q_ASSERT(t);
522         Q_ASSERT(t->activeBuildConfiguration());
523
524         // Ask the user for where he wants to build it
525         // and the cmake command line
526
527         CMakeOpenProjectWizard copw(m_manager, projectDirectory(), Utils::Environment::systemEnvironment());
528         if (copw.exec() != QDialog::Accepted)
529             return false;
530
531         CMakeBuildConfiguration *bc =
532                 static_cast<CMakeBuildConfiguration *>(t->buildConfigurations().at(0));
533         if (!copw.buildDirectory().isEmpty())
534             bc->setBuildDirectory(copw.buildDirectory());
535         bc->setToolChain(copw.toolChain());
536
537         addTarget(t);
538     } else {
539         // We have a user file, but we could still be missing the cbp file
540         // or simply run createXml with the saved settings
541         QFileInfo sourceFileInfo(m_fileName);
542         CMakeBuildConfiguration *activeBC = activeTarget()->activeBuildConfiguration();
543         QString cbpFile = CMakeManager::findCbpFile(QDir(activeBC->buildDirectory()));
544         QFileInfo cbpFileFi(cbpFile);
545
546         CMakeOpenProjectWizard::Mode mode = CMakeOpenProjectWizard::Nothing;
547         if (!cbpFileFi.exists())
548             mode = CMakeOpenProjectWizard::NeedToCreate;
549         else if (cbpFileFi.lastModified() < sourceFileInfo.lastModified())
550             mode = CMakeOpenProjectWizard::NeedToUpdate;
551
552         if (mode != CMakeOpenProjectWizard::Nothing) {
553             CMakeOpenProjectWizard copw(m_manager,
554                                         sourceFileInfo.absolutePath(),
555                                         activeBC->buildDirectory(),
556                                         mode,
557                                         activeBC->environment());
558             if (copw.exec() != QDialog::Accepted)
559                 return false;
560             activeBC->setToolChain(copw.toolChain());
561         }
562     }
563
564     m_watcher = new ProjectExplorer::FileWatcher(this);
565     connect(m_watcher, SIGNAL(fileChanged(QString)), this, SLOT(fileChanged(QString)));
566
567     if (!parseCMakeLists()) // Gets the directory from the active buildconfiguration
568         return false;
569
570     if (!hasUserFile && hasBuildTarget("all")) {
571         MakeStep *makeStep = qobject_cast<MakeStep *>(
572                     activeTarget()->activeBuildConfiguration()->stepList(ProjectExplorer::Constants::BUILDSTEPS_BUILD)->at(0));
573         Q_ASSERT(makeStep);
574         makeStep->setBuildTarget("all", true);
575     }
576
577     foreach (Target *t, targets()) {
578         connect(t, SIGNAL(activeBuildConfigurationChanged(ProjectExplorer::BuildConfiguration*)),
579                 this, SLOT(changeActiveBuildConfiguration(ProjectExplorer::BuildConfiguration*)));
580         connect(t, SIGNAL(environmentChanged()),
581                 this, SLOT(changeEnvironment()));
582     }
583
584     connect(Core::EditorManager::instance(), SIGNAL(editorAboutToClose(Core::IEditor*)),
585             this, SLOT(editorAboutToClose(Core::IEditor*)));
586
587     connect(Core::EditorManager::instance(), SIGNAL(currentEditorChanged(Core::IEditor*)),
588             this, SLOT(editorChanged(Core::IEditor*)));
589
590     connect(ProjectExplorer::ProjectExplorerPlugin::instance()->buildManager(), SIGNAL(buildStateChanged(ProjectExplorer::Project*)),
591             this, SLOT(buildStateChanged(ProjectExplorer::Project*)));
592
593     return true;
594 }
595
596 CMakeBuildTarget CMakeProject::buildTargetForTitle(const QString &title)
597 {
598     foreach(const CMakeBuildTarget &ct, m_buildTargets)
599         if (ct.title == title)
600             return ct;
601     return CMakeBuildTarget();
602 }
603
604 QString CMakeProject::uicCommand() const
605 {
606     return m_uicCommand;
607 }
608
609 QString CMakeProject::uiHeaderFile(const QString &uiFile)
610 {
611     QDir srcDirRoot = QDir(projectDirectory());
612     QString relativePath = srcDirRoot.relativeFilePath(uiFile);
613     QDir buildDir = QDir(activeTarget()->activeBuildConfiguration()->buildDirectory());
614     QString uiHeaderFilePath = buildDir.absoluteFilePath(relativePath);
615
616     QFileInfo fi(uiHeaderFilePath);
617     uiHeaderFilePath = fi.absolutePath();
618     uiHeaderFilePath += QLatin1String("/ui_");
619     uiHeaderFilePath += fi.completeBaseName();
620     uiHeaderFilePath += QLatin1String(".h");
621     return QDir::cleanPath(uiHeaderFilePath);
622 }
623
624 void CMakeProject::createUiCodeModelSupport()
625 {
626 //    qDebug()<<"creatUiCodeModelSupport()";
627     CPlusPlus::CppModelManagerInterface *modelManager
628             = CPlusPlus::CppModelManagerInterface::instance();
629
630     // First move all to
631     QMap<QString, CMakeUiCodeModelSupport *> oldCodeModelSupport;
632     oldCodeModelSupport = m_uiCodeModelSupport;
633     m_uiCodeModelSupport.clear();
634
635     // Find all ui files
636     foreach (const QString &uiFile, m_files) {
637         if (uiFile.endsWith(".ui")) {
638             // UI file, not convert to
639             QString uiHeaderFilePath = uiHeaderFile(uiFile);
640             QMap<QString, CMakeUiCodeModelSupport *>::iterator it
641                     = oldCodeModelSupport.find(uiFile);
642             if (it != oldCodeModelSupport.end()) {
643                 //                qDebug()<<"updated old codemodelsupport";
644                 CMakeUiCodeModelSupport *cms = it.value();
645                 cms->setFileName(uiHeaderFilePath);
646                 m_uiCodeModelSupport.insert(it.key(), cms);
647                 oldCodeModelSupport.erase(it);
648             } else {
649                 //                qDebug()<<"adding new codemodelsupport";
650                 CMakeUiCodeModelSupport *cms = new CMakeUiCodeModelSupport(modelManager, this, uiFile, uiHeaderFilePath);
651                 m_uiCodeModelSupport.insert(uiFile, cms);
652                 modelManager->addEditorSupport(cms);
653             }
654         }
655     }
656
657     // Remove old
658     QMap<QString, CMakeUiCodeModelSupport *>::const_iterator it, end;
659     end = oldCodeModelSupport.constEnd();
660     for (it = oldCodeModelSupport.constBegin(); it!=end; ++it) {
661         modelManager->removeEditorSupport(it.value());
662         delete it.value();
663     }
664 }
665
666 void CMakeProject::updateCodeModelSupportFromEditor(const QString &uiFileName,
667                                                     const QString &contents)
668 {
669     const QMap<QString, CMakeUiCodeModelSupport *>::const_iterator it =
670             m_uiCodeModelSupport.constFind(uiFileName);
671     if (it != m_uiCodeModelSupport.constEnd())
672         it.value()->updateFromEditor(contents);
673 }
674
675 void CMakeProject::editorChanged(Core::IEditor *editor)
676 {
677     // Handle old editor
678     if (isFormWindowEditor(m_lastEditor)) {
679         disconnect(m_lastEditor, SIGNAL(changed()), this, SLOT(uiEditorContentsChanged()));
680         if (m_dirtyUic) {
681             const QString contents =  formWindowEditorContents(m_lastEditor);
682             updateCodeModelSupportFromEditor(m_lastEditor->file()->fileName(), contents);
683             m_dirtyUic = false;
684         }
685     }
686
687     m_lastEditor = editor;
688
689     // Handle new editor
690     if (isFormWindowEditor(editor))
691         connect(editor, SIGNAL(changed()), this, SLOT(uiEditorContentsChanged()));
692 }
693
694 void CMakeProject::editorAboutToClose(Core::IEditor *editor)
695 {
696     if (m_lastEditor == editor) {
697         // Oh no our editor is going to be closed
698         // get the content first
699         if (isFormWindowEditor(m_lastEditor)) {
700             disconnect(m_lastEditor, SIGNAL(changed()), this, SLOT(uiEditorContentsChanged()));
701             if (m_dirtyUic) {
702                 const QString contents = formWindowEditorContents(m_lastEditor);
703                 updateCodeModelSupportFromEditor(m_lastEditor->file()->fileName(), contents);
704                 m_dirtyUic = false;
705             }
706         }
707         m_lastEditor = 0;
708     }
709 }
710
711 void CMakeProject::uiEditorContentsChanged()
712 {
713     // cast sender, get filename
714     if (!m_dirtyUic && isFormWindowEditor(sender()))
715         m_dirtyUic = true;
716 }
717
718 void CMakeProject::buildStateChanged(ProjectExplorer::Project *project)
719 {
720     if (project == this) {
721         if (!ProjectExplorer::ProjectExplorerPlugin::instance()->buildManager()->isBuilding(this)) {
722             QMap<QString, CMakeUiCodeModelSupport *>::const_iterator it, end;
723             end = m_uiCodeModelSupport.constEnd();
724             for (it = m_uiCodeModelSupport.constBegin(); it != end; ++it) {
725                 it.value()->updateFromBuild();
726             }
727         }
728     }
729 }
730
731 // CMakeFile
732
733 CMakeFile::CMakeFile(CMakeProject *parent, QString fileName)
734     : Core::IFile(parent), m_project(parent), m_fileName(fileName)
735 {
736
737 }
738
739 bool CMakeFile::save(const QString &fileName)
740 {
741     // Once we have an texteditor open for this file, we probably do
742     // need to implement this, don't we.
743     Q_UNUSED(fileName)
744     return false;
745 }
746
747 QString CMakeFile::fileName() const
748 {
749     return m_fileName;
750 }
751
752 QString CMakeFile::defaultPath() const
753 {
754     return QString();
755 }
756
757 QString CMakeFile::suggestedFileName() const
758 {
759     return QString();
760 }
761
762 QString CMakeFile::mimeType() const
763 {
764     return Constants::CMAKEMIMETYPE;
765 }
766
767
768 bool CMakeFile::isModified() const
769 {
770     return false;
771 }
772
773 bool CMakeFile::isReadOnly() const
774 {
775     return true;
776 }
777
778 bool CMakeFile::isSaveAsAllowed() const
779 {
780     return false;
781 }
782
783 void CMakeFile::rename(const QString &newName)
784 {
785     Q_ASSERT(false);
786     Q_UNUSED(newName);
787     // Can't happen....
788 }
789
790 Core::IFile::ReloadBehavior CMakeFile::reloadBehavior(ChangeTrigger state, ChangeType type) const
791 {
792     Q_UNUSED(state)
793     Q_UNUSED(type)
794     return BehaviorSilent;
795 }
796
797 void CMakeFile::reload(ReloadFlag flag, ChangeType type)
798 {
799     Q_UNUSED(flag)
800     Q_UNUSED(type)
801 }
802
803 CMakeBuildSettingsWidget::CMakeBuildSettingsWidget(CMakeTarget *target)
804     : m_target(target), m_buildConfiguration(0)
805 {
806     QFormLayout *fl = new QFormLayout(this);
807     fl->setContentsMargins(20, -1, 0, -1);
808     fl->setFieldGrowthPolicy(QFormLayout::ExpandingFieldsGrow);
809     setLayout(fl);
810
811     // TODO add action to Build menu?
812     QPushButton *runCmakeButton = new QPushButton("Run cmake");
813     connect(runCmakeButton, SIGNAL(clicked()),
814             this, SLOT(runCMake()));
815     fl->addRow(tr("Reconfigure project:"), runCmakeButton);
816
817     m_pathLineEdit = new QLineEdit(this);
818     m_pathLineEdit->setReadOnly(true);
819
820     QHBoxLayout *hbox = new QHBoxLayout();
821     hbox->addWidget(m_pathLineEdit);
822
823     m_changeButton = new QPushButton(this);
824     m_changeButton->setText(tr("&Change"));
825     connect(m_changeButton, SIGNAL(clicked()), this, SLOT(openChangeBuildDirectoryDialog()));
826     hbox->addWidget(m_changeButton);
827
828     fl->addRow("Build directory:", hbox);
829 }
830
831 QString CMakeBuildSettingsWidget::displayName() const
832 {
833     return "CMake";
834 }
835
836 void CMakeBuildSettingsWidget::init(BuildConfiguration *bc)
837 {
838     m_buildConfiguration = static_cast<CMakeBuildConfiguration *>(bc);
839     m_pathLineEdit->setText(m_buildConfiguration->buildDirectory());
840     if (m_buildConfiguration->buildDirectory() == m_target->cmakeProject()->projectDirectory())
841         m_changeButton->setEnabled(false);
842     else
843         m_changeButton->setEnabled(true);
844 }
845
846 void CMakeBuildSettingsWidget::openChangeBuildDirectoryDialog()
847 {
848     CMakeProject *project = m_target->cmakeProject();
849     CMakeOpenProjectWizard copw(project->projectManager(),
850                                 project->projectDirectory(),
851                                 m_buildConfiguration->buildDirectory(),
852                                 m_buildConfiguration->environment());
853     if (copw.exec() == QDialog::Accepted) {
854         project->changeBuildDirectory(m_buildConfiguration, copw.buildDirectory());
855         m_pathLineEdit->setText(m_buildConfiguration->buildDirectory());
856     }
857 }
858
859 void CMakeBuildSettingsWidget::runCMake()
860 {
861     // TODO skip build directory
862     CMakeProject *project = m_target->cmakeProject();
863     CMakeOpenProjectWizard copw(project->projectManager(),
864                                 project->projectDirectory(),
865                                 m_buildConfiguration->buildDirectory(),
866                                 CMakeOpenProjectWizard::WantToUpdate,
867                                 m_buildConfiguration->environment());
868     if (copw.exec() == QDialog::Accepted) {
869         project->parseCMakeLists();
870     }
871 }
872
873 /////
874 // CMakeCbpParser
875 ////
876
877 bool CMakeCbpParser::parseCbpFile(const QString &fileName)
878 {
879     QFile fi(fileName);
880     if (fi.exists() && fi.open(QFile::ReadOnly)) {
881         setDevice(&fi);
882
883         while (!atEnd()) {
884             readNext();
885             if (name() == "CodeBlocks_project_file") {
886                 parseCodeBlocks_project_file();
887             } else if (isStartElement()) {
888                 parseUnknownElement();
889             }
890         }
891         fi.close();
892         m_includeFiles.sort();
893         m_includeFiles.removeDuplicates();
894         return true;
895     }
896     return false;
897 }
898
899 void CMakeCbpParser::parseCodeBlocks_project_file()
900 {
901     while (!atEnd()) {
902         readNext();
903         if (isEndElement()) {
904             return;
905         } else if (name() == "Project") {
906             parseProject();
907         } else if (isStartElement()) {
908             parseUnknownElement();
909         }
910     }
911 }
912
913 void CMakeCbpParser::parseProject()
914 {
915     while (!atEnd()) {
916         readNext();
917         if (isEndElement()) {
918             return;
919         } else if (name() == "Option") {
920             parseOption();
921         } else if (name() == "Unit") {
922             parseUnit();
923         } else if (name() == "Build") {
924             parseBuild();
925         } else if (isStartElement()) {
926             parseUnknownElement();
927         }
928     }
929 }
930
931 void CMakeCbpParser::parseBuild()
932 {
933     while (!atEnd()) {
934         readNext();
935         if (isEndElement()) {
936             return;
937         } else if (name() == "Target") {
938             parseBuildTarget();
939         } else if (isStartElement()) {
940             parseUnknownElement();
941         }
942     }
943 }
944
945 void CMakeCbpParser::parseBuildTarget()
946 {
947     m_buildTargetType = false;
948     m_buildTarget.clear();
949
950     if (attributes().hasAttribute("title"))
951         m_buildTarget.title = attributes().value("title").toString();
952     while (!atEnd()) {
953         readNext();
954         if (isEndElement()) {
955             if (m_buildTargetType || m_buildTarget.title == "all" || m_buildTarget.title == "install") {
956                 m_buildTargets.append(m_buildTarget);
957             }
958             return;
959         } else if (name() == "Compiler") {
960             parseCompiler();
961         } else if (name() == "Option") {
962             parseBuildTargetOption();
963         } else if (isStartElement()) {
964             parseUnknownElement();
965         }
966     }
967 }
968
969 void CMakeCbpParser::parseBuildTargetOption()
970 {
971     if (attributes().hasAttribute("output")) {
972         m_buildTarget.executable = attributes().value("output").toString();
973     } else if (attributes().hasAttribute("type") && (attributes().value("type") == "1" || attributes().value("type") == "0")) {
974         m_buildTargetType = true;
975     } else if (attributes().hasAttribute("type") && (attributes().value("type") == "3" || attributes().value("type") == "2")) {
976         m_buildTargetType = true;
977         m_buildTarget.library = true;
978     } else if (attributes().hasAttribute("working_dir")) {
979         m_buildTarget.workingDirectory = attributes().value("working_dir").toString();
980     }
981     while (!atEnd()) {
982         readNext();
983         if (isEndElement()) {
984             return;
985         } else if (name() == "MakeCommand") {
986             parseMakeCommand();
987         } else if (isStartElement()) {
988             parseUnknownElement();
989         }
990     }
991 }
992
993 QString CMakeCbpParser::projectName() const
994 {
995     return m_projectName;
996 }
997
998 void CMakeCbpParser::parseOption()
999 {
1000     if (attributes().hasAttribute("title"))
1001         m_projectName = attributes().value("title").toString();
1002
1003     if (attributes().hasAttribute("compiler"))
1004         m_compiler = attributes().value("compiler").toString();
1005
1006     while (!atEnd()) {
1007         readNext();
1008         if (isEndElement()) {
1009             return;
1010         } else if(isStartElement()) {
1011             parseUnknownElement();
1012         }
1013     }
1014 }
1015
1016 void CMakeCbpParser::parseMakeCommand()
1017 {
1018     while (!atEnd()) {
1019         readNext();
1020         if (isEndElement()) {
1021             return;
1022         } else if (name() == "Build") {
1023             parseBuildTargetBuild();
1024         } else if (name() == "Clean") {
1025             parseBuildTargetClean();
1026         } else if (isStartElement()) {
1027             parseUnknownElement();
1028         }
1029     }
1030 }
1031
1032 void CMakeCbpParser::parseBuildTargetBuild()
1033 {
1034     if (attributes().hasAttribute("command"))
1035         m_buildTarget.makeCommand = attributes().value("command").toString();
1036     while (!atEnd()) {
1037         readNext();
1038         if (isEndElement()) {
1039             return;
1040         } else if (isStartElement()) {
1041             parseUnknownElement();
1042         }
1043     }
1044 }
1045
1046 void CMakeCbpParser::parseBuildTargetClean()
1047 {
1048     if (attributes().hasAttribute("command"))
1049         m_buildTarget.makeCleanCommand = attributes().value("command").toString();
1050     while (!atEnd()) {
1051         readNext();
1052         if (isEndElement()) {
1053             return;
1054         } else if (isStartElement()) {
1055             parseUnknownElement();
1056         }
1057     }
1058 }
1059
1060 void CMakeCbpParser::parseCompiler()
1061 {
1062     while (!atEnd()) {
1063         readNext();
1064         if (isEndElement()) {
1065             return;
1066         } else if (name() == "Add") {
1067             parseAdd();
1068         } else if (isStartElement()) {
1069             parseUnknownElement();
1070         }
1071     }
1072 }
1073
1074 void CMakeCbpParser::parseAdd()
1075 {
1076     m_includeFiles.append(attributes().value("directory").toString());
1077     while (!atEnd()) {
1078         readNext();
1079         if (isEndElement()) {
1080             return;
1081         } else if (isStartElement()) {
1082             parseUnknownElement();
1083         }
1084     }
1085 }
1086
1087 void CMakeCbpParser::parseUnit()
1088 {
1089     //qDebug()<<stream.attributes().value("filename");
1090     QString fileName = attributes().value("filename").toString();
1091     m_parsingCmakeUnit = false;
1092     while (!atEnd()) {
1093         readNext();
1094         if (isEndElement()) {
1095             if (!fileName.endsWith(QLatin1String(".rule")) && !m_processedUnits.contains(fileName)) {
1096                 // Now check whether we found a virtual element beneath
1097                 if (m_parsingCmakeUnit) {
1098                     m_cmakeFileList.append( new ProjectExplorer::FileNode(fileName, ProjectExplorer::ProjectFileType, false));
1099                 } else {
1100                     bool generated = false;
1101                     QString onlyFileName = QFileInfo(fileName).fileName();
1102                     if (   (onlyFileName.startsWith("moc_") && onlyFileName.endsWith(".cxx"))
1103                         || (onlyFileName.startsWith("ui_") && onlyFileName.endsWith(".h"))
1104                         || (onlyFileName.startsWith("qrc_") && onlyFileName.endsWith(".cxx")))
1105                         generated = true;
1106
1107                     if (fileName.endsWith(QLatin1String(".qrc")))
1108                         m_fileList.append( new ProjectExplorer::FileNode(fileName, ProjectExplorer::ResourceType, generated));
1109                     else
1110                         m_fileList.append( new ProjectExplorer::FileNode(fileName, ProjectExplorer::SourceType, generated));
1111                 }
1112                 m_processedUnits.insert(fileName);
1113             }
1114             return;
1115         } else if (name() == "Option") {
1116             parseUnitOption();
1117         } else if (isStartElement()) {
1118             parseUnknownElement();
1119         }
1120     }
1121 }
1122
1123 void CMakeCbpParser::parseUnitOption()
1124 {
1125     if (attributes().hasAttribute("virtualFolder"))
1126         m_parsingCmakeUnit = true;
1127
1128     while (!atEnd()) {
1129         readNext();
1130
1131         if (isEndElement())
1132             break;
1133
1134         if (isStartElement())
1135             parseUnknownElement();
1136     }
1137 }
1138
1139 void CMakeCbpParser::parseUnknownElement()
1140 {
1141     Q_ASSERT(isStartElement());
1142
1143     while (!atEnd()) {
1144         readNext();
1145
1146         if (isEndElement())
1147             break;
1148
1149         if (isStartElement())
1150             parseUnknownElement();
1151     }
1152 }
1153
1154 QList<ProjectExplorer::FileNode *> CMakeCbpParser::fileList()
1155 {
1156     return m_fileList;
1157 }
1158
1159 QList<ProjectExplorer::FileNode *> CMakeCbpParser::cmakeFileList()
1160 {
1161     return m_cmakeFileList;
1162 }
1163
1164 bool CMakeCbpParser::hasCMakeFiles()
1165 {
1166     return !m_cmakeFileList.isEmpty();
1167 }
1168
1169 QStringList CMakeCbpParser::includeFiles()
1170 {
1171     return m_includeFiles;
1172 }
1173
1174 QList<CMakeBuildTarget> CMakeCbpParser::buildTargets()
1175 {
1176     return m_buildTargets;
1177 }
1178
1179 QString CMakeCbpParser::compilerName() const
1180 {
1181     return m_compiler;
1182 }
1183
1184 void CMakeBuildTarget::clear()
1185 {
1186     executable.clear();
1187     makeCommand.clear();
1188     makeCleanCommand.clear();
1189     workingDirectory.clear();
1190     title.clear();
1191     library = false;
1192 }
1193