OSDN Git Service

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