OSDN Git Service

af50c07f718dd94b33ddce5356c6d31d00575eaf
[qt-creator-jp/qt-creator-jp.git] / src / plugins / qt4projectmanager / qt4projectmanager.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 "qt4projectmanager.h"
35
36 #include "qt4projectmanagerconstants.h"
37 #include "qt4projectmanagerplugin.h"
38 #include "qt4nodes.h"
39 #include "qt4project.h"
40 #include "qt4target.h"
41 #include "profilereader.h"
42 #include "qmakestep.h"
43 #include "qt4buildconfiguration.h"
44 #include "wizards/qtquickapp.h"
45 #include "wizards/html5app.h"
46
47 #include <coreplugin/icore.h>
48 #include <coreplugin/basefilewizard.h>
49 #include <coreplugin/messagemanager.h>
50 #include <coreplugin/uniqueidmanager.h>
51 #include <coreplugin/editormanager/editormanager.h>
52 #include <coreplugin/editormanager/ieditor.h>
53 #include <coreplugin/variablemanager.h>
54 #include <projectexplorer/projectexplorer.h>
55 #include <projectexplorer/buildmanager.h>
56 #include <projectexplorer/session.h>
57 #include <projectexplorer/project.h>
58 #include <projectexplorer/projectexplorerconstants.h>
59 #include <utils/qtcassert.h>
60
61 #include <QtCore/QCoreApplication>
62 #include <QtCore/QDir>
63 #include <QtCore/QFileInfo>
64 #include <QtCore/QVariant>
65 #include <QtGui/QFileDialog>
66 #include <QtGui/QMessageBox>
67
68 using namespace Qt4ProjectManager;
69 using namespace Qt4ProjectManager::Internal;
70
71 using ProjectExplorer::BuildStep;
72 using ProjectExplorer::FileType;
73 using ProjectExplorer::HeaderType;
74 using ProjectExplorer::SourceType;
75 using ProjectExplorer::FormType;
76 using ProjectExplorer::ResourceType;
77 using ProjectExplorer::UnknownFileType;
78
79 static const char * const kInstallBins = "CurrentProject:QT_INSTALL_BINS";
80
81 // Known file types of a Qt 4 project
82 static const char* qt4FileTypes[] = {
83     "CppHeaderFiles",
84     "CppSourceFiles",
85     "Qt4FormFiles",
86     "Qt4ResourceFiles"
87 };
88
89 // Test for form editor (loosely coupled)
90 static inline bool isFormWindowEditor(const QObject *o)
91 {
92     return o && !qstrcmp(o->metaObject()->className(), "Designer::FormWindowEditor");
93 }
94
95 // Return contents of form editor (loosely coupled)
96 static inline QString formWindowEditorContents(const QObject *editor)
97 {
98     const QVariant contentV = editor->property("contents");
99     QTC_ASSERT(contentV.isValid(), return QString(); )
100     return contentV.toString();
101 }
102
103 Qt4Manager::Qt4Manager(Qt4ProjectManagerPlugin *plugin)
104   : m_plugin(plugin),
105     m_contextProject(0),
106     m_lastEditor(0),
107     m_dirty(false)
108 {
109 }
110
111 Qt4Manager::~Qt4Manager()
112 {
113 }
114
115 void Qt4Manager::registerProject(Qt4Project *project)
116 {
117     m_projects.append(project);
118 }
119
120 void Qt4Manager::unregisterProject(Qt4Project *project)
121 {
122     m_projects.removeOne(project);
123 }
124
125 void Qt4Manager::notifyChanged(const QString &name)
126 {
127     foreach (Qt4Project *pro, m_projects)
128         pro->notifyChanged(name);
129 }
130
131 void Qt4Manager::init()
132 {
133     connect(Core::EditorManager::instance(), SIGNAL(editorAboutToClose(Core::IEditor*)),
134             this, SLOT(editorAboutToClose(Core::IEditor*)));
135
136     connect(Core::EditorManager::instance(), SIGNAL(currentEditorChanged(Core::IEditor*)),
137             this, SLOT(editorChanged(Core::IEditor*)));
138
139     Core::VariableManager *vm = Core::VariableManager::instance();
140     vm->registerVariable(QLatin1String(kInstallBins),
141         tr("Full path to the bin/ install directory of the current project's Qt version."));
142     connect(vm, SIGNAL(variableUpdateRequested(QString)),
143             this, SLOT(updateVariable(QString)));
144 }
145
146 void Qt4Manager::editorChanged(Core::IEditor *editor)
147 {
148     // Handle old editor
149     if (isFormWindowEditor(m_lastEditor)) {
150         disconnect(m_lastEditor, SIGNAL(changed()), this, SLOT(uiEditorContentsChanged()));
151
152         if (m_dirty) {
153             const QString contents = formWindowEditorContents(m_lastEditor);
154             foreach(Qt4Project *project, m_projects)
155                 project->rootProjectNode()->updateCodeModelSupportFromEditor(m_lastEditor->file()->fileName(), contents);
156             m_dirty = false;
157         }
158     }
159
160     m_lastEditor = editor;
161
162     // Handle new editor
163     if (isFormWindowEditor(m_lastEditor))
164         connect(m_lastEditor, SIGNAL(changed()), this, SLOT(uiEditorContentsChanged()));
165 }
166
167 void Qt4Manager::editorAboutToClose(Core::IEditor *editor)
168 {
169     if (m_lastEditor == editor) {
170         // Oh no our editor is going to be closed
171         // get the content first
172         if (isFormWindowEditor(m_lastEditor)) {
173             disconnect(m_lastEditor, SIGNAL(changed()), this, SLOT(uiEditorContentsChanged()));
174             if (m_dirty) {
175                 const QString contents = formWindowEditorContents(m_lastEditor);
176                 foreach(Qt4Project *project, m_projects)
177                     project->rootProjectNode()->updateCodeModelSupportFromEditor(m_lastEditor->file()->fileName(), contents);
178                 m_dirty = false;
179             }
180         }
181         m_lastEditor = 0;
182     }
183 }
184
185 void Qt4Manager::updateVariable(const QString &variable)
186 {
187     if (variable == QLatin1String(kInstallBins)) {
188         Qt4Project *qt4pro = qobject_cast<Qt4Project *>(projectExplorer()->currentProject());
189         if (!qt4pro) {
190             Core::VariableManager::instance()->remove(QLatin1String(kInstallBins));
191             return;
192         }
193         QString value = qt4pro->activeTarget()->activeBuildConfiguration()
194                 ->qtVersion()->versionInfo().value(QLatin1String("QT_INSTALL_BINS"));
195         Core::VariableManager::instance()->insert(QLatin1String(kInstallBins), value);
196     }
197 }
198
199 void Qt4Manager::uiEditorContentsChanged()
200 {
201     // cast sender, get filename
202     if (!m_dirty && isFormWindowEditor(sender()))
203         m_dirty = true;
204 }
205
206 Core::Context Qt4Manager::projectContext() const
207 {
208      return m_plugin->projectContext();
209 }
210
211 Core::Context Qt4Manager::projectLanguage() const
212 {
213     return Core::Context(ProjectExplorer::Constants::LANG_CXX);
214 }
215
216 QString Qt4Manager::mimeType() const
217 {
218     return QLatin1String(Qt4ProjectManager::Constants::PROFILE_MIMETYPE);
219 }
220
221 static void updateBoilerPlateCodeFiles(const AbstractMobileApp *app, const QString &proFile)
222 {
223     const QList<AbstractGeneratedFileInfo> updates =
224             app->fileUpdates(proFile);
225     if (!updates.empty()) {
226         const QString title = Qt4Manager::tr("Update of Generated Files");
227         QStringList fileNames;
228         foreach (const AbstractGeneratedFileInfo &info, updates)
229             fileNames.append(QDir::toNativeSeparators(info.fileInfo.fileName()));
230         const QString message =
231                 Qt4Manager::tr("The following files are either outdated or have been modified:<br><br>%1"
232                                "<br><br>Do you want Qt Creator to update the files? Any changes will be lost.")
233                 .arg(fileNames.join(QLatin1String(", ")));
234         if (QMessageBox::question(0, title, message, QMessageBox::Yes | QMessageBox::No) == QMessageBox::Yes) {
235             QString error;
236             if (!app->updateFiles(updates, error))
237                 QMessageBox::critical(0, title, error);
238         }
239     }
240 }
241
242 ProjectExplorer::Project *Qt4Manager::openProject(const QString &fileName)
243 {
244     Core::MessageManager *messageManager = Core::ICore::instance()->messageManager();
245
246     // TODO Make all file paths relative & remove this hack
247     // We convert the path to an absolute one here because qt4project.cpp
248     // && profileevaluator use absolute/canonical file paths all over the place
249     // Correct fix would be to remove these calls ...
250     QString canonicalFilePath = QFileInfo(fileName).canonicalFilePath();
251
252     if (canonicalFilePath.isEmpty()) {
253         messageManager->printToOutputPane(tr("Failed opening project '%1': Project file does not exist").arg(QDir::toNativeSeparators(canonicalFilePath)));
254         return 0;
255     }
256
257     foreach (ProjectExplorer::Project *pi, projectExplorer()->session()->projects()) {
258         if (canonicalFilePath == pi->file()->fileName()) {
259             messageManager->printToOutputPane(tr("Failed opening project '%1': Project already open").arg(QDir::toNativeSeparators(canonicalFilePath)));
260             return 0;
261         }
262     }
263
264     const QtQuickApp qtQuickApp;
265     updateBoilerPlateCodeFiles(&qtQuickApp, canonicalFilePath);
266     const Html5App html5App;
267     updateBoilerPlateCodeFiles(&html5App, canonicalFilePath);
268
269     Qt4Project *pro = new Qt4Project(this, canonicalFilePath);
270     return pro;
271 }
272
273 ProjectExplorer::ProjectExplorerPlugin *Qt4Manager::projectExplorer() const
274 {
275     return ProjectExplorer::ProjectExplorerPlugin::instance();
276 }
277
278 ProjectExplorer::Node *Qt4Manager::contextNode() const
279 {
280     return m_contextNode;
281 }
282
283 void Qt4Manager::setContextNode(ProjectExplorer::Node *node)
284 {
285     m_contextNode = node;
286 }
287
288 void Qt4Manager::setContextProject(ProjectExplorer::Project *project)
289 {
290     m_contextProject = project;
291 }
292
293 ProjectExplorer::Project *Qt4Manager::contextProject() const
294 {
295     return m_contextProject;
296 }
297
298 void Qt4Manager::runQMake()
299 {
300     runQMake(projectExplorer()->startupProject(), 0);
301 }
302
303 void Qt4Manager::runQMakeContextMenu()
304 {
305     runQMake(m_contextProject, m_contextNode);
306 }
307
308 void Qt4Manager::runQMake(ProjectExplorer::Project *p, ProjectExplorer::Node *node)
309 {
310     if (!ProjectExplorer::ProjectExplorerPlugin::instance()->saveModifiedFiles())
311         return;
312     Qt4Project *qt4pro = qobject_cast<Qt4Project *>(p);
313     QTC_ASSERT(qt4pro, return);
314
315     if (!qt4pro->activeTarget() ||
316         !qt4pro->activeTarget()->activeBuildConfiguration())
317     return;
318
319     Qt4BuildConfiguration *bc = qt4pro->activeTarget()->activeBuildConfiguration();
320     QMakeStep *qs = bc->qmakeStep();
321
322     if (!qs)
323         return;
324     //found qmakeStep, now use it
325     qs->setForced(true);
326
327     if (node != 0 && node != qt4pro->rootProjectNode())
328         if (Qt4ProFileNode *profile = qobject_cast<Qt4ProFileNode *>(node))
329             bc->setSubNodeBuild(profile);
330
331     projectExplorer()->buildManager()->appendStep(qs);
332     bc->setSubNodeBuild(0);
333 }
334
335 void Qt4Manager::buildSubDirContextMenu()
336 {
337     handleSubDirContexMenu(BUILD);
338 }
339
340 void Qt4Manager::cleanSubDirContextMenu()
341 {
342     handleSubDirContexMenu(CLEAN);
343 }
344
345 void Qt4Manager::rebuildSubDirContextMenu()
346 {
347     handleSubDirContexMenu(REBUILD);
348 }
349
350 void Qt4Manager::handleSubDirContexMenu(Qt4Manager::Action action)
351 {
352     Qt4Project *qt4pro = qobject_cast<Qt4Project *>(m_contextProject);
353     QTC_ASSERT(qt4pro, return);
354
355     if (!qt4pro->activeTarget() ||
356         !qt4pro->activeTarget()->activeBuildConfiguration())
357     return;
358
359     Qt4BuildConfiguration *bc = qt4pro->activeTarget()->activeBuildConfiguration();
360     if (m_contextNode != 0 && m_contextNode != qt4pro->rootProjectNode())
361         if (Qt4ProFileNode *profile = qobject_cast<Qt4ProFileNode *>(m_contextNode))
362             bc->setSubNodeBuild(profile);
363
364     if (projectExplorer()->saveModifiedFiles()) {
365         if (action == BUILD) {
366             projectExplorer()->buildManager()->buildList(bc->stepList(ProjectExplorer::Constants::BUILDSTEPS_BUILD));
367         } else if (action == CLEAN) {
368             projectExplorer()->buildManager()->buildList(bc->stepList(ProjectExplorer::Constants::BUILDSTEPS_CLEAN));
369         } else if (action == REBUILD) {
370             QList<ProjectExplorer::BuildStepList *> stepLists;
371             stepLists << bc->stepList(ProjectExplorer::Constants::BUILDSTEPS_CLEAN);
372             stepLists << bc->stepList(ProjectExplorer::Constants::BUILDSTEPS_BUILD);
373             projectExplorer()->buildManager()->buildLists(stepLists);
374         }
375     }
376
377     bc->setSubNodeBuild(0);
378 }
379
380 QString Qt4Manager::fileTypeId(ProjectExplorer::FileType type)
381 {
382     switch (type) {
383     case HeaderType:
384         return QLatin1String(qt4FileTypes[0]);
385     case SourceType:
386         return QLatin1String(qt4FileTypes[1]);
387     case FormType:
388         return QLatin1String(qt4FileTypes[2]);
389     case ResourceType:
390         return QLatin1String(qt4FileTypes[3]);
391     case UnknownFileType:
392     default:
393         break;
394     }
395     return QString();
396 }
397