projectfilewizardextension.cpp 23.3 KB
Newer Older
hjk's avatar
hjk committed
1
/****************************************************************************
con's avatar
con committed
2
**
3
** Copyright (C) 2014 Digia Plc and/or its subsidiary(-ies).
hjk's avatar
hjk committed
4
** Contact: http://www.qt-project.org/legal
con's avatar
con committed
5
**
hjk's avatar
hjk committed
6
** This file is part of Qt Creator.
con's avatar
con committed
7
**
hjk's avatar
hjk committed
8
9
10
11
12
13
14
** Commercial License Usage
** Licensees holding valid commercial Qt licenses may use this file in
** accordance with the commercial license agreement provided with the
** Software or, alternatively, in accordance with the terms contained in
** a written agreement between you and Digia.  For licensing terms and
** conditions see http://qt.digia.com/licensing.  For further information
** use the contact form at http://qt.digia.com/contact-us.
15
**
16
** GNU Lesser General Public License Usage
hjk's avatar
hjk committed
17
18
19
20
21
22
23
24
25
** Alternatively, this file may be used under the terms of the GNU Lesser
** General Public License version 2.1 as published by the Free Software
** Foundation and appearing in the file LICENSE.LGPL included in the
** packaging of this file.  Please review the following information to
** ensure the GNU Lesser General Public License version 2.1 requirements
** will be met: http://www.gnu.org/licenses/old-licenses/lgpl-2.1.html.
**
** In addition, as a special exception, Digia gives you certain additional
** rights.  These rights are described in the Digia Qt LGPL Exception
con's avatar
con committed
26
27
** version 1.1, included in the file LGPL_EXCEPTION.txt in this package.
**
hjk's avatar
hjk committed
28
****************************************************************************/
hjk's avatar
hjk committed
29

con's avatar
con committed
30
31
#include "projectfilewizardextension.h"
#include "projectexplorer.h"
32
#include "session.h"
con's avatar
con committed
33
34
35
36
#include "projectnodes.h"
#include "nodesvisitor.h"
#include "projectwizardpage.h"

37
38
39
#include <utils/qtcassert.h>
#include <utils/stringutils.h>

con's avatar
con committed
40
41
42
43
#include <coreplugin/basefilewizard.h>
#include <coreplugin/icore.h>
#include <coreplugin/iversioncontrol.h>
#include <coreplugin/vcsmanager.h>
44
#include <coreplugin/mimedatabase.h>
45
#include <extensionsystem/pluginmanager.h>
46
#include <texteditor/texteditorsettings.h>
Jarek Kobus's avatar
Jarek Kobus committed
47
#include <texteditor/icodestylepreferences.h>
48
49
#include <texteditor/icodestylepreferencesfactory.h>
#include <texteditor/normalindenter.h>
Jarek Kobus's avatar
Jarek Kobus committed
50
#include <texteditor/tabsettings.h>
51
#include <texteditor/storagesettings.h>
52
53
#include <projectexplorer/project.h>
#include <projectexplorer/editorconfiguration.h>
con's avatar
con committed
54

55
#include <QtAlgorithms>
56
#include <QPointer>
57
58
59
60
61
62
#include <QDebug>
#include <QFileInfo>
#include <QMultiMap>
#include <QDir>
#include <QTextDocument>
#include <QTextCursor>
63
#include <QMessageBox>
con's avatar
con committed
64

65
66
67
using namespace TextEditor;
using namespace Core;

68
69
70
/*!
    \class ProjectExplorer::Internal::ProjectFileWizardExtension

71
72
    \brief The ProjectFileWizardExtension class implements the post-file
    generating steps of a project wizard.
73

74
    This class provides the following functions:
75
    \list
76
    \li Add to a project file (*.pri/ *.pro)
77
    \li Initialize a version control system repository (unless the path is already
78
79
80
81
82
83
        managed) and do 'add' if the VCS supports it.
    \endlist

    \sa ProjectExplorer::Internal::ProjectWizardPage
*/

con's avatar
con committed
84
85
86
87
enum { debugExtension = 0 };

namespace ProjectExplorer {

88
typedef QList<FolderNode *> FolderNodeList;
con's avatar
con committed
89
90
91
92
typedef QList<ProjectNode *> ProjectNodeList;

namespace Internal {

93
94
// AddNewFileNodesVisitor: Retrieve all folders which support AddNew
class AddNewFileNodesVisitor : public NodesVisitor
con's avatar
con committed
95
96
{
public:
97
    AddNewFileNodesVisitor();
dt's avatar
dt committed
98

99
100
101
102
103
104
105
106
107
108
109
110
111
112
113
114
115
116
117
118
119
120
121
122
123
124
125
126
127
128
129
130
131
132
133
134
135
136
137
    static FolderNodeList allFolders();

    virtual void visitProjectNode(ProjectNode *node);
    virtual void visitFolderNode(FolderNode *node);

private:
    FolderNodeList m_folderNodes;
};

AddNewFileNodesVisitor::AddNewFileNodesVisitor()
{}

FolderNodeList AddNewFileNodesVisitor::allFolders()
{
    AddNewFileNodesVisitor visitor;
    SessionManager::sessionNode()->accept(&visitor);
    return visitor.m_folderNodes;
}

void AddNewFileNodesVisitor::visitProjectNode(ProjectNode *node)
{
    visitFolderNode(node);
}

void AddNewFileNodesVisitor::visitFolderNode(FolderNode *node)
{
    const QList<ProjectExplorer::ProjectAction> &list = node->supportedActions(node);
    if (list.contains(ProjectExplorer::AddNewFile) && !list.contains(ProjectExplorer::InheritedFromParent))
        m_folderNodes.push_back(node);
}

// AddNewProjectNodesVisitor: Retrieve all folders which support AddNewProject
// also checks the path of the added subproject
class AddNewProjectNodesVisitor : public NodesVisitor
{
public:
    AddNewProjectNodesVisitor(const QString &subProjectPath);

    static ProjectNodeList projectNodes(const QString &subProjectPath);
con's avatar
con committed
138
139
140
141

    virtual void visitProjectNode(ProjectNode *node);

private:
142
    ProjectNodeList m_projectNodes;
143
    QString m_subProjectPath;
con's avatar
con committed
144
145
};

146
147
148
149
150
AddNewProjectNodesVisitor::AddNewProjectNodesVisitor(const QString &subProjectPath)
    : m_subProjectPath(subProjectPath)
{}

ProjectNodeList AddNewProjectNodesVisitor::projectNodes(const QString &subProjectPath)
con's avatar
con committed
151
{
152
    AddNewProjectNodesVisitor visitor(subProjectPath);
hjk's avatar
hjk committed
153
    SessionManager::sessionNode()->accept(&visitor);
154
    return visitor.m_projectNodes;
con's avatar
con committed
155
156
}

157
void AddNewProjectNodesVisitor::visitProjectNode(ProjectNode *node)
con's avatar
con committed
158
{
159
160
161
162
    const QList<ProjectExplorer::ProjectAction> &list = node->supportedActions(node);
    if (list.contains(ProjectExplorer::AddSubProject) && !list.contains(ProjectExplorer::InheritedFromParent))
        if (m_subProjectPath.isEmpty() || node->canAddSubProject(m_subProjectPath))
            m_projectNodes.push_back(node);
163
164
165
166
}

// ProjectEntry: Context entry for a *.pri/*.pro file. Stores name and path
// for quick sort and path search, provides operator<() for maps.
167
168
struct FolderEntry {
    FolderEntry() : node(0), priority(-1) {}
169
    explicit FolderEntry(FolderNode *node, const QStringList &generatedFiles, Node *contextNode);
170

171
    int compare(const FolderEntry &rhs) const;
172

173
    FolderNode *node;
174
    QString directory; // For matching against wizards' files, which are native.
175
    QString displayName;
176
    QString baseName;
177
    int priority;
178
179
};

180
FolderEntry::FolderEntry(FolderNode *n, const QStringList &generatedFiles, Node *contextNode) :
181
    node(n)
182
{
183
    FolderNode::AddNewInformation info = node->addNewInformation(generatedFiles, contextNode);
184
185
    displayName = info.displayName;
    const QFileInfo fi(ProjectExplorerPlugin::pathFor(node));
186
    baseName = fi.baseName();
187
188
    priority = info.priority;
    directory = ProjectExplorerPlugin::directoryFor(node);
189
190
191
}

// Sort helper that sorts by base name and puts '*.pro' before '*.pri'
192
int FolderEntry::compare(const FolderEntry &rhs) const
193
{
194
195
    if (const int drc = displayName.compare(rhs.displayName))
        return drc;
196
    if (const int drc = directory.compare(rhs.directory))
197
        return drc;
198
199
    if (const int brc = baseName.compare(rhs.baseName))
        return brc;
200
    if (priority > rhs.priority)
201
        return -1;
202
    if (priority < rhs.priority)
203
204
205
206
        return 1;
    return 0;
}

207
inline bool operator<(const FolderEntry &pe1, const FolderEntry &pe2)
208
209
210
211
{
    return pe1.compare(pe2) < 0;
}

212
QDebug operator<<(QDebug d, const FolderEntry &e)
213
{
214
    d.nospace() << e.directory << ' ' << e.displayName << ' ' << e.priority;
215
    return d;
con's avatar
con committed
216
217
218
}

// --------- ProjectWizardContext
219
220
struct ProjectWizardContext
{
221
222
223
    ProjectWizardContext();
    void clear();

224
225
    QList<IVersionControl*> versionControls;
    QList<IVersionControl*> activeVersionControls;
226
    QList<FolderEntry> projects;
227
    QPointer<ProjectWizardPage> page; // this is managed by the wizard!
228
229
    bool repositoryExists; // Is VCS 'add' sufficient, or should a repository be created?
    QString commonDirectory;
230
    const IWizard *wizard;
con's avatar
con committed
231
232
};

233
234
ProjectWizardContext::ProjectWizardContext() :
    page(0),
235
236
    repositoryExists(false),
    wizard(0)
237
238
239
240
241
{
}

void ProjectWizardContext::clear()
{
242
    activeVersionControls.clear();
243
244
    projects.clear();
    commonDirectory.clear();
245
    page = 0;
246
    repositoryExists = false;
247
    wizard = 0;
248
249
}

con's avatar
con committed
250
// ---- ProjectFileWizardExtension
251
252
ProjectFileWizardExtension::ProjectFileWizardExtension()
  : m_context(0)
con's avatar
con committed
253
254
255
256
257
258
259
260
{
}

ProjectFileWizardExtension::~ProjectFileWizardExtension()
{
    delete m_context;
}

261
static QList<FolderEntry> findDeployProject(const QList<FolderEntry> &folders,
dt's avatar
dt committed
262
263
                                 QString &commonPath)
{
264
265
266
267
268
    QList<FolderEntry> filtered;
    foreach (const FolderEntry &folder, folders)
        if (folder.node->nodeType() == ProjectNodeType)
            if (static_cast<ProjectNode *>(folder.node)->deploysFolder(commonPath))
                filtered << folder;
dt's avatar
dt committed
269
270
271
    return filtered;
}

272
273
274
275
// Find the project the new files should be added to given their common
// path. Either a direct match on the directory or the directory with
// the longest matching path (list containing"/project/subproject1" matching
// common path "/project/subproject1/newuserpath").
276
static int findMatchingProject(const QList<FolderEntry> &projects,
277
                               const QString &commonPath)
278
279
280
281
{
    if (projects.isEmpty() || commonPath.isEmpty())
        return -1;

282
    const int count = projects.size();
283
284
    int bestMatch = -1;
    int bestMatchLength = 0;
285
    int bestMatchPriority = -1;
286
287
    for (int p = 0; p < count; p++) {
        // Direct match or better match? (note that the wizards' files are native).
288
        const FolderEntry &entry = projects.at(p);
289
290
        const QString &projectDirectory = entry.directory;
        const int projectDirectorySize = projectDirectory.size();
291
292
293
294
295
296
297
298
299
300
301
302
303
        if (entry.priority > bestMatchPriority) {
            if (commonPath.startsWith(projectDirectory)) {
                bestMatchPriority = entry.priority;
                bestMatchLength = projectDirectory.size();
                bestMatch = p;
            }
        } else if (entry.priority == bestMatchPriority) {
            if (projectDirectorySize > bestMatchLength
                    && commonPath.startsWith(projectDirectory)) {
                bestMatchPriority = entry.priority;
                bestMatchLength = projectDirectory.size();
                bestMatch = p;
            }
304
305
306
307
308
        }
    }
    return bestMatch;
}

309
static QString generatedProjectFilePath(const QList<GeneratedFile> &files)
310
{
311
312
    foreach (const GeneratedFile &file, files)
        if (file.attributes() & GeneratedFile::OpenProjectAttribute)
313
314
315
316
            return file.path();
    return QString();
}

317
void ProjectFileWizardExtension::firstExtensionPageShown(
318
        const QList<GeneratedFile> &files,
319
        const QVariantMap &extraValues)
con's avatar
con committed
320
{
321
    initProjectChoices(files, extraValues);
322

con's avatar
con committed
323
324
    if (debugExtension)
        qDebug() << Q_FUNC_INFO << files.size();
325

326
327
    // Parametrize wizard page: find best project to add to, set up files display and
    // version control depending on path
con's avatar
con committed
328
    QStringList fileNames;
329
    foreach (const GeneratedFile &f, files)
con's avatar
con committed
330
        fileNames.push_back(f.path());
331
332
333
    m_context->commonDirectory = Utils::commonPath(fileNames);
    m_context->page->setFilesDisplay(m_context->commonDirectory, fileNames);
    // Find best project (Entry at 0 is 'None').
dt's avatar
dt committed
334
335
336

    int bestProjectIndex = -1;

337
    QList<FolderEntry> deployingProjects = findDeployProject(m_context->projects, m_context->commonDirectory);
dt's avatar
dt committed
338
339
340
341
    if (!deployingProjects.isEmpty()) {
        // Oh we do have someone that deploys it
        // then the best match is NONE
        // We display a label explaining that and rename <None> to
342
343
        // <Implicitly Add>
        m_context->page->setNoneLabel(tr("<Implicitly Add>"));
dt's avatar
dt committed
344

345
346
        QString text = tr("The files are implicitly added to the projects:");
        text += QLatin1Char('\n');
347
348
        foreach (const FolderEntry &project, deployingProjects) {
            text += project.displayName;
349
350
            text += QLatin1Char('\n');
        }
dt's avatar
dt committed
351
352
353
354

        m_context->page->setAdditionalInfo(text);
        bestProjectIndex = -1;
    } else {
355
        bestProjectIndex = findMatchingProject(m_context->projects, m_context->commonDirectory);
dt's avatar
dt committed
356
357
358
        m_context->page->setNoneLabel(tr("<None>"));
    }

359
    if (bestProjectIndex == -1)
360
        m_context->page->setCurrentProjectIndex(0);
361
    else
362
        m_context->page->setCurrentProjectIndex(bestProjectIndex + 1);
363
364

    // Store all version controls for later use:
365
    if (m_context->versionControls.isEmpty()) {
366
        foreach (IVersionControl *vc, ExtensionSystem::PluginManager::getObjects<IVersionControl>()) {
367
368
369
            m_context->versionControls.append(vc);
            connect(vc, SIGNAL(configurationChanged()), this, SLOT(initializeVersionControlChoices()));
        }
370
371
    }

372
    initializeVersionControlChoices();
con's avatar
con committed
373
374
}

375
void ProjectFileWizardExtension::initializeVersionControlChoices()
con's avatar
con committed
376
{
377
378
379
    if (m_context->page.isNull())
        return;

380
381
382
383
    // Figure out version control situation:
    // 1) Directory is managed and VCS supports "Add" -> List it
    // 2) Directory is managed and VCS does not support "Add" -> None available
    // 3) Directory is not managed -> Offer all VCS that support "CreateRepository"
384

385
    IVersionControl *currentSelection = 0;
386
387
388
389
390
391
392
    int currentIdx = m_context->page->versionControlIndex() - 1;
    if (currentIdx >= 0 && currentIdx <= m_context->activeVersionControls.size() - 1)
        currentSelection = m_context->activeVersionControls.at(currentIdx);

    m_context->activeVersionControls.clear();

    QStringList versionControlChoices = QStringList(tr("<None>"));
393
    if (!m_context->commonDirectory.isEmpty()) {
394
        IVersionControl *managingControl = VcsManager::findVersionControlForDirectory(m_context->commonDirectory);
395
396
        if (managingControl) {
            // Under VCS
397
            if (managingControl->supportsOperation(IVersionControl::AddOperation)) {
398
                versionControlChoices.append(managingControl->displayName());
399
                m_context->activeVersionControls.push_back(managingControl);
400
401
402
403
                m_context->repositoryExists = true;
            }
        } else {
            // Create
404
405
            foreach (IVersionControl *vc, m_context->versionControls)
                if (vc->supportsOperation(IVersionControl::CreateRepositoryOperation)) {
406
407
408
                    versionControlChoices.append(vc->displayName());
                    m_context->activeVersionControls.append(vc);
                }
409
410
411
            m_context->repositoryExists = false;
        }
    } // has a common root.
412

413
414
415
416
    m_context->page->setVersionControls(versionControlChoices);
    // Enable adding to version control by default.
    if (m_context->repositoryExists && versionControlChoices.size() >= 2)
        m_context->page->setVersionControlIndex(1);
417
418
419
420
    if (!m_context->repositoryExists) {
        int newIdx = m_context->activeVersionControls.indexOf(currentSelection) + 1;
        m_context->page->setVersionControlIndex(newIdx);
    }
con's avatar
con committed
421
422
}

423
QList<QWizardPage *> ProjectFileWizardExtension::extensionPages(const IWizard *wizard)
con's avatar
con committed
424
{
425
    if (!m_context)
con's avatar
con committed
426
        m_context = new ProjectWizardContext;
427
    else
428
        m_context->clear();
con's avatar
con committed
429
430
    // Init context with page and projects
    m_context->page = new ProjectWizardPage;
431
    m_context->wizard = wizard;
432
433
434
    return QList<QWizardPage *>() << m_context->page;
}

435
436
437

static inline void getProjectChoicesAndToolTips(QStringList *projectChoicesParam,
                                                QStringList *projectToolTipsParam,
438
                                                ProjectExplorer::ProjectAction *projectActionParam,
439
                                                const QList<GeneratedFile> &generatedFiles,
440
441
                                                ProjectWizardContext *context,
                                                Node *contextNode)
442
{
con's avatar
con committed
443
    // Set up project list which remains the same over duration of wizard execution
444
445
    // As tooltip, set the directory for disambiguation (should someone have
    // duplicate base names in differing directories).
446
    //: No project selected
447
    QStringList projectChoices(ProjectFileWizardExtension::tr("<None>"));
hjk's avatar
hjk committed
448
    QStringList projectToolTips((QString()));
dt's avatar
dt committed
449

450
    typedef QMap<FolderEntry, bool> FolderEntryMap;
451
452
    // Sort by base name and purge duplicated entries (resulting from dependencies)
    // via Map.
453
454
455
456
    FolderEntryMap entryMap;
    ProjectExplorer::ProjectAction projectAction;
    if (context->wizard->kind()== IWizard::ProjectWizard) {
        const QString projectFilePath = generatedProjectFilePath(generatedFiles);
457
        projectAction = ProjectExplorer::AddSubProject;
458
        foreach (ProjectNode *pn, AddNewProjectNodesVisitor::projectNodes(projectFilePath))
459
            entryMap.insert(FolderEntry(pn, QStringList() << projectFilePath, contextNode), true);
460
461
462
463
464
465

    } else {
        QStringList filePaths;
        foreach (const GeneratedFile &gf, generatedFiles)
            filePaths << gf.path();

466
        projectAction = ProjectExplorer::AddNewFile;
467
        foreach (FolderNode *fn, AddNewFileNodesVisitor::allFolders())
468
            entryMap.insert(FolderEntry(fn, filePaths, contextNode), true);
con's avatar
con committed
469
    }
470

471
    context->projects.clear();
472
473

    // Collect names
474
475
    const FolderEntryMap::const_iterator cend = entryMap.constEnd();
    for (FolderEntryMap::const_iterator it = entryMap.constBegin(); it != cend; ++it) {
476
        context->projects.push_back(it.key());
477
        projectChoices.push_back(it.key().displayName);
478
        projectToolTips.push_back(QDir::toNativeSeparators(it.key().directory));
479
    }
480

481
482
483
484
485
    *projectChoicesParam  = projectChoices;
    *projectToolTipsParam = projectToolTips;
    *projectActionParam = projectAction;
}

486
void ProjectFileWizardExtension::initProjectChoices(const QList<GeneratedFile> generatedFiles, const QVariantMap &extraValues)
487
488
489
{
    QStringList projectChoices;
    QStringList projectToolTips;
490
    ProjectExplorer::ProjectAction projectAction;
491
492

    getProjectChoicesAndToolTips(&projectChoices, &projectToolTips, &projectAction,
493
                                 generatedFiles, m_context,
Kai Koehne's avatar
Kai Koehne committed
494
                                 extraValues.value(QLatin1String(Constants::PREFERRED_PROJECT_NODE)).value<Node *>());
495

496
    m_context->page->setProjects(projectChoices);
497
    m_context->page->setProjectToolTips(projectToolTips);
498
    m_context->page->setAddingSubProject(projectAction == ProjectExplorer::AddSubProject);
con's avatar
con committed
499
500
}

501
bool ProjectFileWizardExtension::processFiles(
502
        const QList<GeneratedFile> &files,
503
        bool *removeOpenProjectAttribute, QString *errorMessage)
504
{
505
506
507
508
509
510
511
512
513
514
    if (!processProject(files, removeOpenProjectAttribute, errorMessage))
        return false;
    if (!processVersionControl(files, errorMessage)) {
        QString message;
        if (errorMessage) {
            message = *errorMessage;
            message.append(QLatin1String("\n\n"));
            errorMessage->clear();
        }
        message.append(tr("Open project anyway?"));
515
        if (QMessageBox::question(ICore::mainWindow(), tr("Version Control Failure"), message,
516
517
518
519
                                  QMessageBox::Yes, QMessageBox::No) == QMessageBox::No)
            return false;
    }
    return true;
520
521
522
}

// Add files to project && version control
523
bool ProjectFileWizardExtension::processProject(
524
        const QList<GeneratedFile> &files,
525
        bool *removeOpenProjectAttribute, QString *errorMessage)
con's avatar
con committed
526
{
527
528
    *removeOpenProjectAttribute = false;

529
530
    QString generatedProject = generatedProjectFilePath(files);

531
532
533
    // Add files to folder (Entry at 0 is 'None').
    const int folderIndex = m_context->page->currentProjectIndex() - 1;
    if (folderIndex < 0 || folderIndex >= m_context->projects.size())
534
        return true;
535
    FolderNode *folder = m_context->projects.at(folderIndex).node;
536
    if (m_context->wizard->kind() == IWizard::ProjectWizard) {
537
        if (!static_cast<ProjectNode *>(folder)->addSubProjects(QStringList(generatedProject))) {
538
            *errorMessage = tr("Failed to add subproject '%1'\nto project '%2'.")
539
                            .arg(generatedProject).arg(folder->path());
540
            return false;
con's avatar
con committed
541
        }
542
543
        *removeOpenProjectAttribute = true;
    } else {
544
        QStringList filePaths;
545
        foreach (const GeneratedFile &generatedFile, files)
546
            filePaths << generatedFile.path();
547
        if (!folder->addFiles(filePaths)) {
548
            *errorMessage = tr("Failed to add one or more files to project\n'%1' (%2).").
549
                    arg(folder->path(), filePaths.join(QString(QLatin1Char(','))));
550
            return false;
551
        }
552
553
554
555
    }
    return true;
}

556
bool ProjectFileWizardExtension::processVersionControl(const QList<GeneratedFile> &files, QString *errorMessage)
557
558
559
{
    // Add files to  version control (Entry at 0 is 'None').
    const int vcsIndex = m_context->page->versionControlIndex() - 1;
560
    if (vcsIndex < 0 || vcsIndex >= m_context->activeVersionControls.size())
561
562
        return true;
    QTC_ASSERT(!m_context->commonDirectory.isEmpty(), return false);
563
    IVersionControl *versionControl = m_context->activeVersionControls.at(vcsIndex);
564
565
    // Create repository?
    if (!m_context->repositoryExists) {
566
        QTC_ASSERT(versionControl->supportsOperation(IVersionControl::CreateRepositoryOperation), return false);
567
568
569
        if (!versionControl->vcsCreateRepository(m_context->commonDirectory)) {
            *errorMessage = tr("A version control system repository could not be created in '%1'.").arg(m_context->commonDirectory);
            return false;
con's avatar
con committed
570
571
        }
    }
572
    // Add files if supported.
573
574
    if (versionControl->supportsOperation(IVersionControl::AddOperation)) {
        foreach (const GeneratedFile &generatedFile, files) {
575
            if (!versionControl->vcsAdd(generatedFile.path())) {
con's avatar
con committed
576
577
578
579
580
581
582
583
                *errorMessage = tr("Failed to add '%1' to the version control system.").arg(generatedFile.path());
                return false;
            }
        }
    }
    return true;
}

584
static ICodeStylePreferences *codeStylePreferences(Project *project, Id languageId)
585
{
Orgad Shaneh's avatar
Orgad Shaneh committed
586
    if (!languageId.isValid())
587
588
589
        return 0;

    if (project)
Jarek Kobus's avatar
Jarek Kobus committed
590
        return project->editorConfiguration()->codeStyle(languageId);
591

592
    return TextEditorSettings::codeStyle(languageId);
593
594
}

595
void ProjectFileWizardExtension::applyCodeStyle(GeneratedFile *file) const
596
597
598
599
{
    if (file->isBinary() || file->contents().isEmpty())
        return; // nothing to do

600
601
    MimeType mt = MimeDatabase::findByFile(QFileInfo(file->path()));
    Id languageId = TextEditorSettings::languageId(mt.type());
602

Orgad Shaneh's avatar
Orgad Shaneh committed
603
    if (!languageId.isValid())
604
605
        return; // don't modify files like *.ui *.pro

606
    FolderNode *folder = 0;
607
608
    const int projectIndex = m_context->page->currentProjectIndex() - 1;
    if (projectIndex >= 0 && projectIndex < m_context->projects.size())
609
        folder = m_context->projects.at(projectIndex).node;
610

611
    Project *baseProject = SessionManager::projectForNode(folder);
612

613
    ICodeStylePreferencesFactory *factory = TextEditorSettings::codeStyleFactory(languageId);
614

615
    Indenter *indenter = 0;
616
617
618
    if (factory)
        indenter = factory->createIndenter();
    if (!indenter)
619
        indenter = new NormalIndenter();
620

621
    ICodeStylePreferences *codeStylePrefs = codeStylePreferences(baseProject, languageId);
622
623
624
625
    indenter->setCodeStylePreferences(codeStylePrefs);
    QTextDocument doc(file->contents());
    QTextCursor cursor(&doc);
    cursor.select(QTextCursor::Document);
Jarek Kobus's avatar
Jarek Kobus committed
626
    indenter->indent(&doc, cursor, QChar::Null, codeStylePrefs->currentTabSettings());
627
    delete indenter;
628
    if (TextEditorSettings::storageSettings().m_cleanWhitespace) {
629
630
631
632
633
634
635
        QTextBlock block = doc.firstBlock();
        while (block.isValid()) {
            codeStylePrefs->currentTabSettings().removeTrailingWhitespace(cursor, block);
            block = block.next();
        }
    }
    file->setContents(doc.toPlainText());
636
637
}

638
639
640
641
642
643
644
645
646
647
void ProjectFileWizardExtension::hideProjectComboBox()
{
    m_context->page->setProjectComoBoxVisible(false);
}

void ProjectFileWizardExtension::setProjectIndex(int i)
{
    m_context->page->setCurrentProjectIndex(i);
}

hjk's avatar
hjk committed
648
649
} // namespace Internal
} // namespace ProjectExplorer