OSDN Git Service

It's 2011 now.
[qt-creator-jp/qt-creator-jp.git] / src / plugins / qt4projectmanager / makestep.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 "makestep.h"
35 #include "ui_makestep.h"
36
37 #include "qt4project.h"
38 #include "qt4target.h"
39 #include "qt4buildconfiguration.h"
40 #include "qt4projectmanagerconstants.h"
41 #include "qtparser.h"
42
43 #include <projectexplorer/toolchain.h>
44 #include <projectexplorer/buildsteplist.h>
45 #include <projectexplorer/projectexplorer.h>
46 #include <extensionsystem/pluginmanager.h>
47 #include <utils/qtcprocess.h>
48
49 #include <QtCore/QDir>
50 #include <QtCore/QFileInfo>
51
52 using ExtensionSystem::PluginManager;
53 using namespace Qt4ProjectManager;
54 using namespace Qt4ProjectManager::Internal;
55
56 namespace {
57 const char * const MAKESTEP_BS_ID("Qt4ProjectManager.MakeStep");
58
59 const char * const MAKE_ARGUMENTS_KEY("Qt4ProjectManager.MakeStep.MakeArguments");
60 const char * const MAKE_COMMAND_KEY("Qt4ProjectManager.MakeStep.MakeCommand");
61 const char * const CLEAN_KEY("Qt4ProjectManager.MakeStep.Clean");
62 }
63
64 MakeStep::MakeStep(ProjectExplorer::BuildStepList *bsl) :
65     AbstractProcessStep(bsl, QLatin1String(MAKESTEP_BS_ID)),
66     m_clean(false)
67 {
68     ctor();
69 }
70
71 MakeStep::MakeStep(ProjectExplorer::BuildStepList *bsl, MakeStep *bs) :
72     AbstractProcessStep(bsl, bs),
73     m_clean(bs->m_clean),
74     m_userArgs(bs->m_userArgs),
75     m_makeCmd(bs->m_makeCmd)
76 {
77     ctor();
78 }
79
80 MakeStep::MakeStep(ProjectExplorer::BuildStepList *bsl, const QString &id) :
81     AbstractProcessStep(bsl, id),
82     m_clean(false)
83 {
84     ctor();
85 }
86
87 void MakeStep::ctor()
88 {
89     setDefaultDisplayName(tr("Make", "Qt4 MakeStep display name."));
90 }
91
92 MakeStep::~MakeStep()
93 {
94 }
95
96 Qt4BuildConfiguration *MakeStep::qt4BuildConfiguration() const
97 {
98     return static_cast<Qt4BuildConfiguration *>(buildConfiguration());
99 }
100
101 void MakeStep::setClean(bool clean)
102 {
103     m_clean = clean;
104 }
105
106 QVariantMap MakeStep::toMap() const
107 {
108     QVariantMap map(ProjectExplorer::AbstractProcessStep::toMap());
109     map.insert(QLatin1String(MAKE_ARGUMENTS_KEY), m_userArgs);
110     map.insert(QLatin1String(MAKE_COMMAND_KEY), m_makeCmd);
111     map.insert(QLatin1String(CLEAN_KEY), m_clean);
112     return map;
113 }
114
115 bool MakeStep::fromMap(const QVariantMap &map)
116 {
117     m_makeCmd = map.value(QLatin1String(MAKE_COMMAND_KEY)).toString();
118     m_userArgs = map.value(QLatin1String(MAKE_ARGUMENTS_KEY)).toString();
119     m_clean = map.value(QLatin1String(CLEAN_KEY)).toBool();
120
121     return ProjectExplorer::AbstractProcessStep::fromMap(map);
122 }
123
124 bool MakeStep::init()
125 {
126     Qt4BuildConfiguration *bc = qt4BuildConfiguration();
127     ProjectExplorer::ProcessParameters *pp = processParameters();
128     pp->setMacroExpander(bc->macroExpander());
129
130     Utils::Environment environment = bc->environment();
131     pp->setEnvironment(environment);
132
133     QString workingDirectory;
134     if (bc->subNodeBuild())
135         workingDirectory = bc->subNodeBuild()->buildDir();
136     else
137         workingDirectory = bc->buildDirectory();
138     pp->setWorkingDirectory(workingDirectory);
139
140     QString makeCmd = bc->makeCommand();
141     if (!m_makeCmd.isEmpty())
142         makeCmd = m_makeCmd;
143     pp->setCommand(makeCmd);
144
145     // If we are cleaning, then make can fail with a error code, but that doesn't mean
146     // we should stop the clean queue
147     // That is mostly so that rebuild works on a already clean project
148     setIgnoreReturnValue(m_clean);
149
150     QString args;
151
152     ProjectExplorer::ToolChain *toolchain = bc->toolChain();
153
154     if (bc->subNodeBuild()){
155         if(!bc->subNodeBuild()->makefile().isEmpty()) {
156             Utils::QtcProcess::addArg(&args, QLatin1String("-f"));
157             Utils::QtcProcess::addArg(&args, bc->subNodeBuild()->makefile());
158         }
159     } else if (!bc->makefile().isEmpty()) {
160         Utils::QtcProcess::addArg(&args, QLatin1String("-f"));
161         Utils::QtcProcess::addArg(&args, bc->makefile());
162     }
163
164     Utils::QtcProcess::addArgs(&args, m_userArgs);
165
166     if (!m_clean) {
167         if (!bc->defaultMakeTarget().isEmpty())
168             Utils::QtcProcess::addArg(&args, bc->defaultMakeTarget());
169     }
170     // -w option enables "Enter"/"Leaving directory" messages, which we need for detecting the
171     // absolute file path
172     // FIXME doing this without the user having a way to override this is rather bad
173     // so we only do it for unix and if the user didn't override the make command
174     // but for now this is the least invasive change
175
176     if (toolchain) {
177         if (toolchain->type() != ProjectExplorer::ToolChain_MSVC &&
178             toolchain->type() != ProjectExplorer::ToolChain_WINCE) {
179             if (m_makeCmd.isEmpty())
180                 Utils::QtcProcess::addArg(&args, QLatin1String("-w"));
181         }
182     }
183
184     setEnabled(true);
185     pp->setArguments(args);
186
187     ProjectExplorer::IOutputParser *parser = bc->qtVersion()->createOutputParser();
188     Q_ASSERT(parser);
189     parser->appendOutputParser(new QtParser);
190     if (toolchain)
191         parser->appendOutputParser(toolchain->outputParser());
192
193     parser->setWorkingDirectory(workingDirectory);
194
195     setOutputParser(parser);
196
197     return AbstractProcessStep::init();
198 }
199
200 void MakeStep::run(QFutureInterface<bool> & fi)
201 {
202     if (qt4BuildConfiguration()->qt4Target()->qt4Project()->rootProjectNode()->projectType() == ScriptTemplate) {
203         fi.reportResult(true);
204         return;
205     }
206
207     AbstractProcessStep::run(fi);
208 }
209
210 bool MakeStep::processSucceeded(int exitCode, QProcess::ExitStatus status)
211 {
212     // Symbian does retun 0, even on failed makes! So we check for fatal make errors here.
213     if (outputParser() && outputParser()->hasFatalErrors())
214         return false;
215
216     return AbstractProcessStep::processSucceeded(exitCode, status);
217 }
218
219 bool MakeStep::immutable() const
220 {
221     return false;
222 }
223
224 ProjectExplorer::BuildStepConfigWidget *MakeStep::createConfigWidget()
225 {
226     return new MakeStepConfigWidget(this);
227 }
228
229 QString MakeStep::userArguments()
230 {
231     return m_userArgs;
232 }
233
234 void MakeStep::setUserArguments(const QString &arguments)
235 {
236     m_userArgs = arguments;
237     emit userArgumentsChanged();
238 }
239
240 MakeStepConfigWidget::MakeStepConfigWidget(MakeStep *makeStep)
241     : BuildStepConfigWidget(), m_ui(new Ui::MakeStep), m_makeStep(makeStep), m_ignoreChange(false)
242 {
243     m_ui->setupUi(this);
244
245     m_ui->makePathChooser->setExpectedKind(Utils::PathChooser::ExistingCommand);
246     m_ui->makePathChooser->setBaseDirectory(Utils::PathChooser::homePath());
247
248     connect(m_ui->makePathChooser, SIGNAL(changed(QString)),
249             this, SLOT(makeEdited()));
250     connect(m_ui->makeArgumentsLineEdit, SIGNAL(textEdited(QString)),
251             this, SLOT(makeArgumentsLineEdited()));
252
253     connect(makeStep, SIGNAL(userArgumentsChanged()),
254             this, SLOT(userArgumentsChanged()));
255     connect(makeStep->buildConfiguration(), SIGNAL(buildDirectoryChanged()),
256             this, SLOT(updateDetails()));
257
258     connect(makeStep->qt4BuildConfiguration(), SIGNAL(qtVersionChanged()),
259             this, SLOT(qtVersionChanged()));
260
261     connect(ProjectExplorer::ProjectExplorerPlugin::instance(), SIGNAL(settingsChanged()),
262             this, SLOT(updateMakeOverrideLabel()));
263     connect(ProjectExplorer::ProjectExplorerPlugin::instance(), SIGNAL(settingsChanged()),
264             this, SLOT(updateDetails()));
265 }
266
267 MakeStepConfigWidget::~MakeStepConfigWidget()
268 {
269     delete m_ui;
270 }
271
272 void MakeStepConfigWidget::qtVersionChanged()
273 {
274     updateMakeOverrideLabel();
275     updateDetails();
276 }
277
278 void MakeStepConfigWidget::updateMakeOverrideLabel()
279 {
280     Qt4BuildConfiguration *qt4bc = m_makeStep->qt4BuildConfiguration();
281     m_ui->makeLabel->setText(tr("Override %1:").arg(qt4bc->makeCommand()));
282 }
283
284 void MakeStepConfigWidget::updateDetails()
285 {
286     Qt4BuildConfiguration *bc = m_makeStep->qt4BuildConfiguration();
287
288     ProjectExplorer::ProcessParameters param;
289     param.setMacroExpander(bc->macroExpander());
290     param.setWorkingDirectory(bc->buildDirectory());
291     param.setEnvironment(bc->environment());
292     QString makeCmd = bc->makeCommand();
293     if (!m_makeStep->m_makeCmd.isEmpty())
294         makeCmd = m_makeStep->m_makeCmd;
295     param.setCommand(makeCmd);
296     if (param.commandMissing()) {
297         m_summaryText = tr("<b>Make:</b> %1 not found in the environment.").arg(makeCmd);
298         emit updateSummary();
299         return;
300     }
301     // -w option enables "Enter"/"Leaving directory" messages, which we need for detecting the
302     // absolute file path
303     // FIXME doing this without the user having a way to override this is rather bad
304     // so we only do it for unix and if the user didn't override the make command
305     // but for now this is the least invasive change
306     QString args = m_makeStep->userArguments();
307     ProjectExplorer::ToolChainType t = ProjectExplorer::ToolChain_UNKNOWN;
308     ProjectExplorer::ToolChain *toolChain = bc->toolChain();
309     if (toolChain)
310         t = toolChain->type();
311     if (t != ProjectExplorer::ToolChain_MSVC && t != ProjectExplorer::ToolChain_WINCE) {
312         if (m_makeStep->m_makeCmd.isEmpty())
313             Utils::QtcProcess::addArg(&args, QLatin1String("-w"));
314     }
315     param.setArguments(args);
316     m_summaryText = param.summaryInWorkdir(displayName());
317     emit updateSummary();
318 }
319
320 QString MakeStepConfigWidget::summaryText() const
321 {
322     return m_summaryText;
323 }
324
325 QString MakeStepConfigWidget::displayName() const
326 {
327     return m_makeStep->displayName();
328 }
329
330 void MakeStepConfigWidget::userArgumentsChanged()
331 {
332     if (m_ignoreChange)
333         return;
334     m_ui->makeArgumentsLineEdit->setText(m_makeStep->userArguments());
335     updateDetails();
336 }
337
338 void MakeStepConfigWidget::init()
339 {
340     updateMakeOverrideLabel();
341
342     const QString &makeCmd = m_makeStep->m_makeCmd;
343     m_ui->makePathChooser->setPath(makeCmd);
344
345     m_ui->makeArgumentsLineEdit->setText(m_makeStep->userArguments());
346     updateDetails();
347 }
348
349 void MakeStepConfigWidget::makeEdited()
350 {
351     m_makeStep->m_makeCmd = m_ui->makePathChooser->rawPath();
352     updateDetails();
353 }
354
355 void MakeStepConfigWidget::makeArgumentsLineEdited()
356 {
357     m_ignoreChange = true;
358     m_makeStep->setUserArguments(m_ui->makeArgumentsLineEdit->text());
359     m_ignoreChange = false;
360     updateDetails();
361 }
362
363 ///
364 // MakeStepFactory
365 ///
366
367 MakeStepFactory::MakeStepFactory(QObject *parent) :
368     ProjectExplorer::IBuildStepFactory(parent)
369 {
370 }
371
372 MakeStepFactory::~MakeStepFactory()
373 {
374 }
375
376 bool MakeStepFactory::canCreate(ProjectExplorer::BuildStepList *parent, const QString &id) const
377 {
378     if (parent->target()->project()->id() != QLatin1String(Constants::QT4PROJECT_ID))
379         return false;
380     return (id == QLatin1String(MAKESTEP_BS_ID));
381 }
382
383 ProjectExplorer::BuildStep *MakeStepFactory::create(ProjectExplorer::BuildStepList *parent, const QString &id)
384 {
385     if (!canCreate(parent, id))
386         return 0;
387     return new MakeStep(parent);
388 }
389
390 bool MakeStepFactory::canClone(ProjectExplorer::BuildStepList *parent, ProjectExplorer::BuildStep *source) const
391 {
392     return canCreate(parent, source->id());
393 }
394
395 ProjectExplorer::BuildStep *MakeStepFactory::clone(ProjectExplorer::BuildStepList *parent, ProjectExplorer::BuildStep *source)
396 {
397     if (!canClone(parent, source))
398         return 0;
399     return new MakeStep(parent, static_cast<MakeStep *>(source));
400 }
401
402 bool MakeStepFactory::canRestore(ProjectExplorer::BuildStepList *parent, const QVariantMap &map) const
403 {
404     QString id(ProjectExplorer::idFromMap(map));
405     return canCreate(parent, id);
406 }
407
408 ProjectExplorer::BuildStep *MakeStepFactory::restore(ProjectExplorer::BuildStepList *parent, const QVariantMap &map)
409 {
410     if (!canRestore(parent, map))
411         return 0;
412     MakeStep *bs(new MakeStep(parent));
413     if (bs->fromMap(map))
414         return bs;
415     delete bs;
416     return 0;
417 }
418
419 QStringList MakeStepFactory::availableCreationIds(ProjectExplorer::BuildStepList *parent) const
420 {
421     if (parent->target()->project()->id() == QLatin1String(Constants::QT4PROJECT_ID))
422         return QStringList() << QLatin1String(MAKESTEP_BS_ID);
423     return QStringList();
424 }
425
426 QString MakeStepFactory::displayNameForId(const QString &id) const
427 {
428     if (id == QLatin1String(MAKESTEP_BS_ID))
429         return tr("Make");
430     return QString();
431 }