1 /**************************************************************************
3 ** This file is part of Qt Creator
5 ** Copyright (c) 2011 Nokia Corporation and/or its subsidiary(-ies).
7 ** Contact: Nokia Corporation (qt-info@nokia.com)
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
16 ** GNU Lesser General Public License Usage
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.
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.
29 ** If you have questions regarding the use of this file, please contact
30 ** Nokia at qt-info@nokia.com.
32 **************************************************************************/
34 #include "cmakeproject.h"
35 #include "cmakeprojectconstants.h"
36 #include "cmakeprojectnodes.h"
37 #include "cmakerunconfiguration.h"
38 #include "cmaketarget.h"
40 #include "cmakeopenprojectwizard.h"
41 #include "cmakebuildconfiguration.h"
42 #include "cmakeuicodemodelsupport.h"
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>
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>
66 using namespace CMakeProjectManager;
67 using namespace CMakeProjectManager::Internal;
68 using namespace ProjectExplorer;
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
77 // Who sets up the environment for cl.exe ? INCLUDEPATH and so on
79 // Test for form editor (loosely coupled)
80 static inline bool isFormWindowEditor(const QObject *o)
82 return o && !qstrcmp(o->metaObject()->className(), "Designer::FormWindowEditor");
85 // Return contents of form editor (loosely coupled)
86 static inline QString formWindowEditorContents(const QObject *editor)
88 const QVariant contentV = editor->property("contents");
89 QTC_ASSERT(contentV.isValid(), return QString(); )
90 return contentV.toString();
96 CMakeProject::CMakeProject(CMakeManager *manager, const QString &fileName)
99 m_rootNode(new CMakeProjectNode(m_fileName)),
100 m_insideFileChanged(false),
103 m_file = new CMakeFile(this, fileName);
105 connect(this, SIGNAL(addedTarget(ProjectExplorer::Target*)),
106 SLOT(targetAdded(ProjectExplorer::Target*)));
109 CMakeProject::~CMakeProject()
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());
122 m_codeModelFuture.cancel();
126 void CMakeProject::fileChanged(const QString &fileName)
129 if (!activeTarget() ||
130 !activeTarget()->activeBuildConfiguration())
133 if (m_insideFileChanged)
135 m_insideFileChanged = true;
136 changeActiveBuildConfiguration(activeTarget()->activeBuildConfiguration());
137 m_insideFileChanged = false;
140 void CMakeProject::changeActiveBuildConfiguration(ProjectExplorer::BuildConfiguration *bc)
142 if (!bc || bc->target() != activeTarget())
145 CMakeBuildConfiguration * cmakebc(qobject_cast<CMakeBuildConfiguration *>(bc));
149 // Pop up a dialog asking the user to rerun cmake
150 QFileInfo sourceFileInfo(m_fileName);
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;
158 foreach(const QString &file, m_watchedFiles) {
159 if (QFileInfo(file).lastModified() > cbpFileFi.lastModified()) {
160 mode = CMakeOpenProjectWizard::NeedToUpdate;
166 if (mode != CMakeOpenProjectWizard::Nothing) {
167 CMakeOpenProjectWizard copw(m_manager,
168 sourceFileInfo.absolutePath(),
169 cmakebc->buildDirectory(),
171 cmakebc->environment());
178 void CMakeProject::targetAdded(ProjectExplorer::Target *t)
183 connect(t, SIGNAL(activeBuildConfigurationChanged(ProjectExplorer::BuildConfiguration*)),
184 SLOT(changeActiveBuildConfiguration(ProjectExplorer::BuildConfiguration*)));
187 void CMakeProject::changeBuildDirectory(CMakeBuildConfiguration *bc, const QString &newBuildDirectory)
189 bc->setBuildDirectory(newBuildDirectory);
193 QString CMakeProject::defaultBuildDirectory() const
195 return projectDirectory() + QLatin1String("/qtcreator-build");
198 bool CMakeProject::parseCMakeLists()
200 if (!activeTarget() ||
201 !activeTarget()->activeBuildConfiguration())
205 CMakeBuildConfiguration *activeBC = activeTarget()->activeBuildConfiguration();
206 QString cbpFile = CMakeManager::findCbpFile(activeBC->buildDirectory());
209 m_rootNode->setDisplayName(QFileInfo(cbpFile).completeBaseName());
210 CMakeCbpParser cbpparser;
212 //qDebug()<<"Parsing file "<<cbpFile;
213 if (!cbpparser.parseCbpFile(cbpFile)) {
215 qDebug()<<"Parsing failed";
216 // activeBC->updateToolChain(QString::null);
217 emit buildTargetsChanged();
222 // activeBC->updateToolChain(cbpparser.compilerName());
223 m_projectName = cbpparser.projectName();
224 m_rootNode->setDisplayName(cbpparser.projectName());
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());
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);
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;
250 foreach (ProjectExplorer::FileNode *fn, fileList)
251 m_files.append(fn->path());
254 buildTree(m_rootNode, fileList);
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;
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();
282 //qDebug()<<"Updating CodeModel";
283 createUiCodeModelSupport();
285 if (!activeBC->toolChain())
288 QStringList allIncludePaths;
289 // This explicitly adds -I. to the include paths
290 allIncludePaths.append(projectDirectory());
291 allIncludePaths.append(cbpparser.includeFiles());
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());
299 allIncludePaths.append(headerPath.path());
302 CPlusPlus::CppModelManagerInterface *modelmanager =
303 CPlusPlus::CppModelManagerInterface::instance();
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);
321 emit buildTargetsChanged();
322 emit fileListChanged();
326 QList<CMakeBuildTarget> CMakeProject::buildTargets() const
328 return m_buildTargets;
331 QStringList CMakeProject::buildTargetTitles() const
334 foreach (const CMakeBuildTarget &ct, m_buildTargets) {
335 if (ct.executable.isEmpty())
337 if (ct.title.endsWith(QLatin1String("/fast")))
344 bool CMakeProject::hasBuildTarget(const QString &title) const
346 foreach (const CMakeBuildTarget &ct, m_buildTargets) {
347 if (ct.executable.isEmpty())
349 if (ct.title.endsWith(QLatin1String("/fast")))
351 if (ct.title == title)
357 void CMakeProject::gatherFileNodes(ProjectExplorer::FolderNode *parent, QList<ProjectExplorer::FileNode *> &list)
359 foreach(ProjectExplorer::FolderNode *folder, parent->subFolderNodes())
360 gatherFileNodes(folder, list);
361 foreach(ProjectExplorer::FileNode *file, parent->fileNodes())
365 void CMakeProject::buildTree(CMakeProjectNode *rootNode, QList<ProjectExplorer::FileNode *> newList)
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);
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();
379 QList<ProjectExplorer::FileNode *> added;
380 QList<ProjectExplorer::FileNode *> deleted;
383 while(oldIt != oldEnd && newIt != newEnd) {
384 if ( (*oldIt)->path() == (*newIt)->path()) {
388 } else if ((*oldIt)->path() < (*newIt)->path()) {
389 deleted.append(*oldIt);
392 added.append(*newIt);
397 while (oldIt != oldEnd) {
398 deleted.append(*oldIt);
402 while (newIt != newEnd) {
403 added.append(*newIt);
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);
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)
432 ProjectExplorer::FolderNode *CMakeProject::findOrCreateFolder(CMakeProjectNode *rootNode, QString directory)
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('/');
441 // Find folder in subFolders
443 foreach (ProjectExplorer::FolderNode *folder, parent->subFolderNodes()) {
444 if (folder->path() == path) {
445 // yeah found something :)
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);
462 QString CMakeProject::displayName() const
464 return m_projectName;
467 QString CMakeProject::id() const
469 return QLatin1String(Constants::CMAKEPROJECT_ID);
472 Core::IFile *CMakeProject::file() const
477 CMakeManager *CMakeProject::projectManager() const
482 CMakeTarget *CMakeProject::activeTarget() const
484 return static_cast<CMakeTarget *>(Project::activeTarget());
487 QList<ProjectExplorer::Project *> CMakeProject::dependsOn()
489 return QList<Project *>();
492 QList<ProjectExplorer::BuildConfigWidget*> CMakeProject::subConfigWidgets()
494 QList<ProjectExplorer::BuildConfigWidget*> list;
495 list << new BuildEnvironmentWidget;
499 ProjectExplorer::ProjectNode *CMakeProject::rootProjectNode() const
505 QStringList CMakeProject::files(FilesMode fileMode) const
511 bool CMakeProject::fromMap(const QVariantMap &map)
513 if (!Project::fromMap(map))
516 bool hasUserFile = activeTarget();
518 CMakeTargetFactory *factory =
519 ExtensionSystem::PluginManager::instance()->getObject<CMakeTargetFactory>();
520 CMakeTarget *t = factory->create(this, QLatin1String(DEFAULT_CMAKE_TARGET_ID));
523 Q_ASSERT(t->activeBuildConfiguration());
525 // Ask the user for where he wants to build it
526 // and the cmake command line
528 CMakeOpenProjectWizard copw(m_manager, projectDirectory(), Utils::Environment::systemEnvironment());
529 if (copw.exec() != QDialog::Accepted)
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());
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);
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;
553 if (mode != CMakeOpenProjectWizard::Nothing) {
554 CMakeOpenProjectWizard copw(m_manager,
555 sourceFileInfo.absolutePath(),
556 activeBC->buildDirectory(),
558 activeBC->environment());
559 if (copw.exec() != QDialog::Accepted)
561 activeBC->setToolChain(copw.toolChain());
565 m_watcher = new ProjectExplorer::FileWatcher(this);
566 connect(m_watcher, SIGNAL(fileChanged(QString)), this, SLOT(fileChanged(QString)));
568 if (!parseCMakeLists()) // Gets the directory from the active buildconfiguration
571 if (!hasUserFile && hasBuildTarget("all")) {
572 MakeStep *makeStep = qobject_cast<MakeStep *>(
573 activeTarget()->activeBuildConfiguration()->stepList(ProjectExplorer::Constants::BUILDSTEPS_BUILD)->at(0));
575 makeStep->setBuildTarget("all", true);
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()));
585 connect(Core::EditorManager::instance(), SIGNAL(editorAboutToClose(Core::IEditor*)),
586 this, SLOT(editorAboutToClose(Core::IEditor*)));
588 connect(Core::EditorManager::instance(), SIGNAL(currentEditorChanged(Core::IEditor*)),
589 this, SLOT(editorChanged(Core::IEditor*)));
591 connect(ProjectExplorer::ProjectExplorerPlugin::instance()->buildManager(), SIGNAL(buildStateChanged(ProjectExplorer::Project*)),
592 this, SLOT(buildStateChanged(ProjectExplorer::Project*)));
597 CMakeBuildTarget CMakeProject::buildTargetForTitle(const QString &title)
599 foreach(const CMakeBuildTarget &ct, m_buildTargets)
600 if (ct.title == title)
602 return CMakeBuildTarget();
605 QString CMakeProject::uicCommand() const
610 QString CMakeProject::uiHeaderFile(const QString &uiFile)
612 QDir srcDirRoot = QDir(projectDirectory());
613 QString relativePath = srcDirRoot.relativeFilePath(uiFile);
614 QDir buildDir = QDir(activeTarget()->activeBuildConfiguration()->buildDirectory());
615 QString uiHeaderFilePath = buildDir.absoluteFilePath(relativePath);
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);
625 void CMakeProject::createUiCodeModelSupport()
627 // qDebug()<<"creatUiCodeModelSupport()";
628 CPlusPlus::CppModelManagerInterface *modelManager
629 = CPlusPlus::CppModelManagerInterface::instance();
632 QMap<QString, CMakeUiCodeModelSupport *> oldCodeModelSupport;
633 oldCodeModelSupport = m_uiCodeModelSupport;
634 m_uiCodeModelSupport.clear();
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);
650 // qDebug()<<"adding new codemodelsupport";
651 CMakeUiCodeModelSupport *cms = new CMakeUiCodeModelSupport(modelManager, this, uiFile, uiHeaderFilePath);
652 m_uiCodeModelSupport.insert(uiFile, cms);
653 modelManager->addEditorSupport(cms);
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());
667 void CMakeProject::updateCodeModelSupportFromEditor(const QString &uiFileName,
668 const QString &contents)
670 const QMap<QString, CMakeUiCodeModelSupport *>::const_iterator it =
671 m_uiCodeModelSupport.constFind(uiFileName);
672 if (it != m_uiCodeModelSupport.constEnd())
673 it.value()->updateFromEditor(contents);
676 void CMakeProject::editorChanged(Core::IEditor *editor)
679 if (isFormWindowEditor(m_lastEditor)) {
680 disconnect(m_lastEditor, SIGNAL(changed()), this, SLOT(uiEditorContentsChanged()));
682 const QString contents = formWindowEditorContents(m_lastEditor);
683 updateCodeModelSupportFromEditor(m_lastEditor->file()->fileName(), contents);
688 m_lastEditor = editor;
691 if (isFormWindowEditor(editor))
692 connect(editor, SIGNAL(changed()), this, SLOT(uiEditorContentsChanged()));
695 void CMakeProject::editorAboutToClose(Core::IEditor *editor)
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()));
703 const QString contents = formWindowEditorContents(m_lastEditor);
704 updateCodeModelSupportFromEditor(m_lastEditor->file()->fileName(), contents);
712 void CMakeProject::uiEditorContentsChanged()
714 // cast sender, get filename
715 if (!m_dirtyUic && isFormWindowEditor(sender()))
719 void CMakeProject::buildStateChanged(ProjectExplorer::Project *project)
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();
734 CMakeFile::CMakeFile(CMakeProject *parent, QString fileName)
735 : Core::IFile(parent), m_project(parent), m_fileName(fileName)
740 bool CMakeFile::save(const QString &fileName)
742 // Once we have an texteditor open for this file, we probably do
743 // need to implement this, don't we.
748 QString CMakeFile::fileName() const
753 QString CMakeFile::defaultPath() const
758 QString CMakeFile::suggestedFileName() const
763 QString CMakeFile::mimeType() const
765 return Constants::CMAKEMIMETYPE;
769 bool CMakeFile::isModified() const
774 bool CMakeFile::isReadOnly() const
779 bool CMakeFile::isSaveAsAllowed() const
784 void CMakeFile::rename(const QString &newName)
791 Core::IFile::ReloadBehavior CMakeFile::reloadBehavior(ChangeTrigger state, ChangeType type) const
795 return BehaviorSilent;
798 void CMakeFile::reload(ReloadFlag flag, ChangeType type)
804 CMakeBuildSettingsWidget::CMakeBuildSettingsWidget(CMakeTarget *target)
805 : m_target(target), m_buildConfiguration(0)
807 QFormLayout *fl = new QFormLayout(this);
808 fl->setContentsMargins(20, -1, 0, -1);
809 fl->setFieldGrowthPolicy(QFormLayout::ExpandingFieldsGrow);
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);
818 m_pathLineEdit = new QLineEdit(this);
819 m_pathLineEdit->setReadOnly(true);
821 QHBoxLayout *hbox = new QHBoxLayout();
822 hbox->addWidget(m_pathLineEdit);
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);
829 fl->addRow("Build directory:", hbox);
832 QString CMakeBuildSettingsWidget::displayName() const
837 void CMakeBuildSettingsWidget::init(BuildConfiguration *bc)
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);
844 m_changeButton->setEnabled(true);
847 void CMakeBuildSettingsWidget::openChangeBuildDirectoryDialog()
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());
860 void CMakeBuildSettingsWidget::runCMake()
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();
878 bool CMakeCbpParser::parseCbpFile(const QString &fileName)
881 if (fi.exists() && fi.open(QFile::ReadOnly)) {
886 if (name() == "CodeBlocks_project_file") {
887 parseCodeBlocks_project_file();
888 } else if (isStartElement()) {
889 parseUnknownElement();
893 m_includeFiles.sort();
894 m_includeFiles.removeDuplicates();
900 void CMakeCbpParser::parseCodeBlocks_project_file()
904 if (isEndElement()) {
906 } else if (name() == "Project") {
908 } else if (isStartElement()) {
909 parseUnknownElement();
914 void CMakeCbpParser::parseProject()
918 if (isEndElement()) {
920 } else if (name() == "Option") {
922 } else if (name() == "Unit") {
924 } else if (name() == "Build") {
926 } else if (isStartElement()) {
927 parseUnknownElement();
932 void CMakeCbpParser::parseBuild()
936 if (isEndElement()) {
938 } else if (name() == "Target") {
940 } else if (isStartElement()) {
941 parseUnknownElement();
946 void CMakeCbpParser::parseBuildTarget()
948 m_buildTargetType = false;
949 m_buildTarget.clear();
951 if (attributes().hasAttribute("title"))
952 m_buildTarget.title = attributes().value("title").toString();
955 if (isEndElement()) {
956 if (m_buildTargetType || m_buildTarget.title == "all" || m_buildTarget.title == "install") {
957 m_buildTargets.append(m_buildTarget);
960 } else if (name() == "Compiler") {
962 } else if (name() == "Option") {
963 parseBuildTargetOption();
964 } else if (isStartElement()) {
965 parseUnknownElement();
970 void CMakeCbpParser::parseBuildTargetOption()
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();
984 if (isEndElement()) {
986 } else if (name() == "MakeCommand") {
988 } else if (isStartElement()) {
989 parseUnknownElement();
994 QString CMakeCbpParser::projectName() const
996 return m_projectName;
999 void CMakeCbpParser::parseOption()
1001 if (attributes().hasAttribute("title"))
1002 m_projectName = attributes().value("title").toString();
1004 if (attributes().hasAttribute("compiler"))
1005 m_compiler = attributes().value("compiler").toString();
1009 if (isEndElement()) {
1011 } else if(isStartElement()) {
1012 parseUnknownElement();
1017 void CMakeCbpParser::parseMakeCommand()
1021 if (isEndElement()) {
1023 } else if (name() == "Build") {
1024 parseBuildTargetBuild();
1025 } else if (name() == "Clean") {
1026 parseBuildTargetClean();
1027 } else if (isStartElement()) {
1028 parseUnknownElement();
1033 void CMakeCbpParser::parseBuildTargetBuild()
1035 if (attributes().hasAttribute("command"))
1036 m_buildTarget.makeCommand = attributes().value("command").toString();
1039 if (isEndElement()) {
1041 } else if (isStartElement()) {
1042 parseUnknownElement();
1047 void CMakeCbpParser::parseBuildTargetClean()
1049 if (attributes().hasAttribute("command"))
1050 m_buildTarget.makeCleanCommand = attributes().value("command").toString();
1053 if (isEndElement()) {
1055 } else if (isStartElement()) {
1056 parseUnknownElement();
1061 void CMakeCbpParser::parseCompiler()
1065 if (isEndElement()) {
1067 } else if (name() == "Add") {
1069 } else if (isStartElement()) {
1070 parseUnknownElement();
1075 void CMakeCbpParser::parseAdd()
1077 m_includeFiles.append(attributes().value("directory").toString());
1080 if (isEndElement()) {
1082 } else if (isStartElement()) {
1083 parseUnknownElement();
1088 void CMakeCbpParser::parseUnit()
1090 //qDebug()<<stream.attributes().value("filename");
1091 QString fileName = attributes().value("filename").toString();
1092 m_parsingCmakeUnit = false;
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));
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")))
1108 if (fileName.endsWith(QLatin1String(".qrc")))
1109 m_fileList.append( new ProjectExplorer::FileNode(fileName, ProjectExplorer::ResourceType, generated));
1111 m_fileList.append( new ProjectExplorer::FileNode(fileName, ProjectExplorer::SourceType, generated));
1113 m_processedUnits.insert(fileName);
1116 } else if (name() == "Option") {
1118 } else if (isStartElement()) {
1119 parseUnknownElement();
1124 void CMakeCbpParser::parseUnitOption()
1126 if (attributes().hasAttribute("virtualFolder"))
1127 m_parsingCmakeUnit = true;
1135 if (isStartElement())
1136 parseUnknownElement();
1140 void CMakeCbpParser::parseUnknownElement()
1142 Q_ASSERT(isStartElement());
1150 if (isStartElement())
1151 parseUnknownElement();
1155 QList<ProjectExplorer::FileNode *> CMakeCbpParser::fileList()
1160 QList<ProjectExplorer::FileNode *> CMakeCbpParser::cmakeFileList()
1162 return m_cmakeFileList;
1165 bool CMakeCbpParser::hasCMakeFiles()
1167 return !m_cmakeFileList.isEmpty();
1170 QStringList CMakeCbpParser::includeFiles()
1172 return m_includeFiles;
1175 QList<CMakeBuildTarget> CMakeCbpParser::buildTargets()
1177 return m_buildTargets;
1180 QString CMakeCbpParser::compilerName() const
1185 void CMakeBuildTarget::clear()
1188 makeCommand.clear();
1189 makeCleanCommand.clear();
1190 workingDirectory.clear();