OSDN Git Service

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