gitplugin.cpp 54 KB
Newer Older
hjk's avatar
hjk committed
1
/****************************************************************************
con's avatar
con committed
2
**
3
** Copyright (C) 2013 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
#include "gitplugin.h"
hjk's avatar
hjk committed
31
32
33

#include "changeselectiondialog.h"
#include "commitdata.h"
con's avatar
con committed
34
35
#include "gitclient.h"
#include "gitconstants.h"
hjk's avatar
hjk committed
36
#include "giteditor.h"
con's avatar
con committed
37
#include "gitsubmiteditor.h"
hjk's avatar
hjk committed
38
#include "gitversioncontrol.h"
39
#include "branchdialog.h"
40
#include "remotedialog.h"
41
#include "clonewizard.h"
42
#include "gitorious/gitoriousclonewizard.h"
43
#include "stashdialog.h"
44
#include "settingspage.h"
45
#include "logchangedialog.h"
46
#include "mergetool.h"
Orgad Shaneh's avatar
Orgad Shaneh committed
47
#include "gitutils.h"
con's avatar
con committed
48

49
#include "gerrit/gerritplugin.h"
50

con's avatar
con committed
51
52
#include <coreplugin/icore.h>
#include <coreplugin/coreconstants.h>
53
#include <coreplugin/documentmanager.h>
con's avatar
con committed
54
#include <coreplugin/messagemanager.h>
55
#include <coreplugin/actionmanager/actionmanager.h>
56
57
#include <coreplugin/actionmanager/actioncontainer.h>
#include <coreplugin/actionmanager/command.h>
58
#include <coreplugin/id.h>
Orgad Shaneh's avatar
Orgad Shaneh committed
59
#include <coreplugin/infobar.h>
con's avatar
con committed
60
#include <coreplugin/editormanager/editormanager.h>
61
#include <coreplugin/editormanager/ieditor.h>
62
#include <coreplugin/documentmanager.h>
hjk's avatar
hjk committed
63
64

#include <utils/qtcassert.h>
65
#include <utils/parameteraction.h>
66
#include <utils/fileutils.h>
hjk's avatar
hjk committed
67

con's avatar
con committed
68
#include <vcsbase/basevcseditorfactory.h>
69
#include <vcsbase/submitfilemodel.h>
con's avatar
con committed
70
71
#include <vcsbase/vcsbaseeditor.h>
#include <vcsbase/basevcssubmiteditorfactory.h>
72
#include <vcsbase/vcsbaseoutputwindow.h>
73
#include <vcsbase/cleandialog.h>
Friedemann Kleint's avatar
Friedemann Kleint committed
74
#include <locator/commandlocator.h>
con's avatar
con committed
75

76
77
78
79
#include <QDebug>
#include <QDir>
#include <QFileInfo>
#include <QtPlugin>
hjk's avatar
hjk committed
80

81
82
83
84
#include <QAction>
#include <QFileDialog>
#include <QMenu>
#include <QMessageBox>
con's avatar
con committed
85

Orgad Shaneh's avatar
Orgad Shaneh committed
86
87
static const unsigned minimumRequiredVersion = 0x010702;

hjk's avatar
hjk committed
88
static const VcsBase::VcsBaseEditorParameters editorParameters[] = {
con's avatar
con committed
89
{
hjk's avatar
hjk committed
90
    VcsBase::RegularCommandOutput,
91
92
    Git::Constants::GIT_COMMAND_LOG_EDITOR_ID,
    Git::Constants::GIT_COMMAND_LOG_EDITOR_DISPLAY_NAME,
93
    Git::Constants::C_GIT_COMMAND_LOG_EDITOR,
con's avatar
con committed
94
95
    "application/vnd.nokia.text.scs_git_commandlog",
    "gitlog"},
hjk's avatar
hjk committed
96
{   VcsBase::LogOutput,
97
98
    Git::Constants::GIT_LOG_EDITOR_ID,
    Git::Constants::GIT_LOG_EDITOR_DISPLAY_NAME,
99
    Git::Constants::C_GIT_LOG_EDITOR,
con's avatar
con committed
100
101
    "application/vnd.nokia.text.scs_git_filelog",
    "gitfilelog"},
hjk's avatar
hjk committed
102
{   VcsBase::AnnotateOutput,
103
104
    Git::Constants::GIT_BLAME_EDITOR_ID,
    Git::Constants::GIT_BLAME_EDITOR_DISPLAY_NAME,
105
    Git::Constants::C_GIT_BLAME_EDITOR,
con's avatar
con committed
106
107
    "application/vnd.nokia.text.scs_git_annotation",
    "gitsannotate"},
hjk's avatar
hjk committed
108
{   VcsBase::DiffOutput,
109
110
    Git::Constants::GIT_DIFF_EDITOR_ID,
    Git::Constants::GIT_DIFF_EDITOR_DISPLAY_NAME,
111
    Git::Constants::C_GIT_DIFF_EDITOR,
con's avatar
con committed
112
113
114
115
    "text/x-patch","diff"}
};

// Utility to find a parameter set by type
hjk's avatar
hjk committed
116
static inline const VcsBase::VcsBaseEditorParameters *findType(int ie)
con's avatar
con committed
117
{
hjk's avatar
hjk committed
118
119
    const VcsBase::EditorContentType et = static_cast<VcsBase::EditorContentType>(ie);
    return  VcsBase::VcsBaseEditorWidget::findType(editorParameters, sizeof(editorParameters)/sizeof(VcsBase::VcsBaseEditorParameters), et);
con's avatar
con committed
120
121
}

122
123
Q_DECLARE_METATYPE(Git::Internal::GitClientMemberFunc)

con's avatar
con committed
124
125
126
127
128
129
130
131
using namespace Git;
using namespace Git::Internal;

// GitPlugin

GitPlugin *GitPlugin::m_instance = 0;

GitPlugin::GitPlugin() :
hjk's avatar
hjk committed
132
    VcsBase::VcsBasePlugin(QLatin1String(Git::Constants::GITSUBMITEDITOR_ID)),
Friedemann Kleint's avatar
Friedemann Kleint committed
133
    m_commandLocator(0),
con's avatar
con committed
134
135
136
137
138
    m_showAction(0),
    m_submitCurrentAction(0),
    m_diffSelectedFilesAction(0),
    m_undoAction(0),
    m_redoAction(0),
139
    m_menuAction(0),
140
    m_applyCurrentFilePatchAction(0),
con's avatar
con committed
141
142
    m_gitClient(0),
    m_changeSelectionDialog(0),
143
    m_submitActionTriggered(false)
con's avatar
con committed
144
145
{
    m_instance = this;
146
147
148
149
150
    const int mid = qRegisterMetaType<GitClientMemberFunc>();
    Q_UNUSED(mid)
    m_fileActions.reserve(10);
    m_projectActions.reserve(10);
    m_repositoryActions.reserve(15);
con's avatar
con committed
151
152
153
154
}

GitPlugin::~GitPlugin()
{
155
    cleanCommitMessageFile();
con's avatar
con committed
156
157
158
159
    delete m_gitClient;
    m_instance = 0;
}

160
void GitPlugin::cleanCommitMessageFile()
con's avatar
con committed
161
{
162
163
164
    if (!m_commitMessageFileName.isEmpty()) {
        QFile::remove(m_commitMessageFileName);
        m_commitMessageFileName.clear();
con's avatar
con committed
165
166
167
    }
}

168
169
170
171
172
bool GitPlugin::isCommitEditorOpen() const
{
    return !m_commitMessageFileName.isEmpty();
}

con's avatar
con committed
173
174
175
176
177
GitPlugin *GitPlugin::instance()
{
    return m_instance;
}

hjk's avatar
hjk committed
178
static const VcsBase::VcsBaseSubmitEditorParameters submitParameters = {
con's avatar
con committed
179
    Git::Constants::SUBMIT_MIMETYPE,
180
181
    Git::Constants::GITSUBMITEDITOR_ID,
    Git::Constants::GITSUBMITEDITOR_DISPLAY_NAME,
182
183
    Git::Constants::C_GITSUBMITEDITOR,
    VcsBase::VcsBaseSubmitEditorParameters::DiffRows
con's avatar
con committed
184
185
};

186
187
// Create a parameter action
ParameterActionCommandPair
Eike Ziller's avatar
Eike Ziller committed
188
        GitPlugin::createParameterAction(Core::ActionContainer *ac,
189
                                         const QString &defaultText, const QString &parameterText,
hjk's avatar
hjk committed
190
                                         const Core::Id &id, const Core::Context &context,
191
192
193
                                         bool addToLocator)
{
    Utils::ParameterAction *action = new Utils::ParameterAction(defaultText, parameterText,
194
195
                                                                Utils::ParameterAction::EnabledWithParameter,
                                                                this);
Eike Ziller's avatar
Eike Ziller committed
196
    Core::Command *command = Core::ActionManager::registerAction(action, id, context);
197
198
199
200
201
202
203
204
205
    command->setAttribute(Core::Command::CA_UpdateText);
    ac->addAction(command);
    if (addToLocator)
        m_commandLocator->appendCommand(command);
    return ParameterActionCommandPair(action, command);
}

// Create an action to act on a file with a slot.
ParameterActionCommandPair
Eike Ziller's avatar
Eike Ziller committed
206
        GitPlugin::createFileAction(Core::ActionContainer *ac,
207
                                    const QString &defaultText, const QString &parameterText,
hjk's avatar
hjk committed
208
                                    const Core::Id &id, const Core::Context &context, bool addToLocator,
209
210
                                    const char *pluginSlot)
{
Eike Ziller's avatar
Eike Ziller committed
211
    const ParameterActionCommandPair rc = createParameterAction(ac, defaultText, parameterText, id, context, addToLocator);
212
213
214
215
216
217
218
    m_fileActions.push_back(rc.first);
    connect(rc.first, SIGNAL(triggered()), this, pluginSlot);
    return rc;
}

// Create an action to act on a project with slot.
ParameterActionCommandPair
Eike Ziller's avatar
Eike Ziller committed
219
        GitPlugin::createProjectAction(Core::ActionContainer *ac,
220
                                       const QString &defaultText, const QString &parameterText,
hjk's avatar
hjk committed
221
                                       const Core::Id &id, const Core::Context &context, bool addToLocator,
222
223
                                       const char *pluginSlot)
{
Eike Ziller's avatar
Eike Ziller committed
224
    const ParameterActionCommandPair rc = createParameterAction(ac, defaultText, parameterText, id, context, addToLocator);
225
226
227
228
229
230
231
    m_projectActions.push_back(rc.first);
    connect(rc.first, SIGNAL(triggered()), this, pluginSlot);
    return rc;
}

// Create an action to act on the repository
ActionCommandPair
Eike Ziller's avatar
Eike Ziller committed
232
        GitPlugin::createRepositoryAction(Core::ActionContainer *ac,
hjk's avatar
hjk committed
233
                                          const QString &text, const Core::Id &id,
234
                                          const Core::Context &context, bool addToLocator)
235
236
{
    QAction  *action = new QAction(text, this);
Eike Ziller's avatar
Eike Ziller committed
237
    Core::Command *command = Core::ActionManager::registerAction(action, id, context);
238
239
240
241
242
243
244
245
246
    ac->addAction(command);
    m_repositoryActions.push_back(action);
    if (addToLocator)
        m_commandLocator->appendCommand(command);
    return ActionCommandPair(action, command);
}

// Create an action to act on the repository with slot
ActionCommandPair
Eike Ziller's avatar
Eike Ziller committed
247
        GitPlugin::createRepositoryAction(Core::ActionContainer *ac,
hjk's avatar
hjk committed
248
                                          const QString &text, const Core::Id &id,
249
                                          const Core::Context &context, bool addToLocator,
250
251
                                          const char *pluginSlot)
{
Eike Ziller's avatar
Eike Ziller committed
252
    const ActionCommandPair rc = createRepositoryAction(ac, text, id, context, addToLocator);
253
254
255
256
257
258
259
    connect(rc.first, SIGNAL(triggered()), this, pluginSlot);
    return rc;
}

// Action to act on the repository forwarded to a git client member function
// taking the directory. Store the member function as data on the action.
ActionCommandPair
Eike Ziller's avatar
Eike Ziller committed
260
        GitPlugin::createRepositoryAction(Core::ActionContainer *ac,
hjk's avatar
hjk committed
261
                                          const QString &text, const Core::Id &id,
262
                                          const Core::Context &context, bool addToLocator,
263
264
265
                                          GitClientMemberFunc func)
{
    // Set the member func as data and connect to generic slot
Eike Ziller's avatar
Eike Ziller committed
266
    const ActionCommandPair rc = createRepositoryAction(ac, text, id, context, addToLocator);
267
268
269
270
271
    rc.first->setData(qVariantFromValue(func));
    connect(rc.first, SIGNAL(triggered()), this, SLOT(gitClientMemberFuncRepositoryAction()));
    return rc;
}

272
bool GitPlugin::initialize(const QStringList &arguments, QString *errorMessage)
con's avatar
con committed
273
{
274
275
276
    Q_UNUSED(arguments)
    Q_UNUSED(errorMessage)

hjk's avatar
hjk committed
277
    m_settings.readSettings(Core::ICore::settings());
278
279

    m_gitClient = new GitClient(&m_settings);
280

hjk's avatar
hjk committed
281
282
    typedef VcsBase::VcsEditorFactory<GitEditor> GitEditorFactory;
    typedef VcsBase::VcsSubmitEditorFactory<GitSubmitEditor> GitSubmitEditorFactory;
con's avatar
con committed
283

284
    initializeVcs(new GitVersionControl(m_gitClient));
con's avatar
con committed
285

286
    // Create the globalcontext list to register actions accordingly
287
    Core::Context globalcontext(Core::Constants::C_GLOBAL);
con's avatar
con committed
288
289

    // Create the settings Page
290
    addAutoReleasedObject(new SettingsPage());
con's avatar
con committed
291
292

    static const char *describeSlot = SLOT(show(QString,QString));
hjk's avatar
hjk committed
293
    const int editorCount = sizeof(editorParameters)/sizeof(VcsBase::VcsBaseEditorParameters);
294
295
    for (int i = 0; i < editorCount; i++)
        addAutoReleasedObject(new GitEditorFactory(editorParameters + i, m_gitClient, describeSlot));
con's avatar
con committed
296

297
298
    addAutoReleasedObject(new GitSubmitEditorFactory(&submitParameters));
    addAutoReleasedObject(new CloneWizard);
299
    addAutoReleasedObject(new Gitorious::Internal::GitoriousCloneWizard);
300

Friedemann Kleint's avatar
Friedemann Kleint committed
301
    const QString prefix = QLatin1String("git");
302
    m_commandLocator = new Locator::CommandLocator("Git", prefix, prefix);
Friedemann Kleint's avatar
Friedemann Kleint committed
303
304
    addAutoReleasedObject(m_commandLocator);

con's avatar
con committed
305
    //register actions
306
    Core::ActionContainer *toolsContainer =
Eike Ziller's avatar
Eike Ziller committed
307
        Core::ActionManager::actionContainer(Core::Constants::M_TOOLS);
con's avatar
con committed
308

Eike Ziller's avatar
Eike Ziller committed
309
    Core::ActionContainer *gitContainer = Core::ActionManager::createMenu("Git");
con's avatar
con committed
310
311
    gitContainer->menu()->setTitle(tr("&Git"));
    toolsContainer->addMenu(gitContainer);
312
    m_menuAction = gitContainer->menu()->menuAction();
313

Petar Perisin's avatar
Petar Perisin committed
314
315
316
317
    /*  "Current File" menu */
    Core::ActionContainer *currentFileMenu = Core::ActionManager::createMenu(Core::Id("Git.CurrentFileMenu"));
    currentFileMenu->menu()->setTitle(tr("Current &File"));
    gitContainer->addMenu(currentFileMenu);
318

Petar Perisin's avatar
Petar Perisin committed
319
320
    ParameterActionCommandPair parameterActionCommand
            = createFileAction(currentFileMenu,
321
                               tr("Diff Current File"), tr("Diff of \"%1\""),
hjk's avatar
hjk committed
322
                               Core::Id("Git.Diff"), globalcontext, true,
323
                               SLOT(diffCurrentFile()));
324
    parameterActionCommand.second->setDefaultKeySequence(QKeySequence(Core::UseMacShortcuts ? tr("Meta+G,Meta+D") : tr("Alt+G,Alt+D")));
325

326
    parameterActionCommand
Petar Perisin's avatar
Petar Perisin committed
327
            = createFileAction(currentFileMenu,
328
                               tr("Log Current File"), tr("Log of \"%1\""),
hjk's avatar
hjk committed
329
                               Core::Id("Git.Log"), globalcontext, true, SLOT(logFile()));
330
    parameterActionCommand.second->setDefaultKeySequence(QKeySequence(Core::UseMacShortcuts ? tr("Meta+G,Meta+L") : tr("Alt+G,Alt+L")));
331

Petar Perisin's avatar
Petar Perisin committed
332
333
334
335
336
337
338
    parameterActionCommand
                = createFileAction(currentFileMenu,
                                   tr("Blame Current File"), tr("Blame for \"%1\""),
                                   Core::Id("Git.Blame"),
                                   globalcontext, true, SLOT(blameFile()));
    parameterActionCommand.second->setDefaultKeySequence(QKeySequence(Core::UseMacShortcuts ? tr("Meta+G,Meta+B") : tr("Alt+G,Alt+B")));

339
    // ------
Petar Perisin's avatar
Petar Perisin committed
340
    currentFileMenu->addSeparator(globalcontext);
341
342

    parameterActionCommand
Petar Perisin's avatar
Petar Perisin committed
343
            = createFileAction(currentFileMenu,
344
                               tr("Stage File for Commit"), tr("Stage \"%1\" for Commit"),
hjk's avatar
hjk committed
345
                               Core::Id("Git.Stage"), globalcontext, true, SLOT(stageFile()));
346
    parameterActionCommand.second->setDefaultKeySequence(QKeySequence(Core::UseMacShortcuts ? tr("Meta+G,Meta+A") : tr("Alt+G,Alt+A")));
347
348

    parameterActionCommand
Petar Perisin's avatar
Petar Perisin committed
349
            = createFileAction(currentFileMenu,
350
                               tr("Unstage File from Commit"), tr("Unstage \"%1\" from Commit"),
hjk's avatar
hjk committed
351
                               Core::Id("Git.Unstage"), globalcontext, true, SLOT(unstageFile()));
352

353
    parameterActionCommand
Petar Perisin's avatar
Petar Perisin committed
354
            = createFileAction(currentFileMenu,
355
                               tr("Undo Unstaged Changes"), tr("Undo Unstaged Changes for \"%1\""),
hjk's avatar
hjk committed
356
                               Core::Id("Git.UndoUnstaged"), globalcontext,
357
358
359
                               true, SLOT(undoUnstagedFileChanges()));

    parameterActionCommand
Petar Perisin's avatar
Petar Perisin committed
360
            = createFileAction(currentFileMenu,
361
                               tr("Undo Uncommitted Changes"), tr("Undo Uncommitted Changes for \"%1\""),
hjk's avatar
hjk committed
362
                               Core::Id("Git.Undo"), globalcontext,
363
                               true, SLOT(undoFileChanges()));
364
    parameterActionCommand.second->setDefaultKeySequence(QKeySequence(Core::UseMacShortcuts ? tr("Meta+G,Meta+U") : tr("Alt+G,Alt+U")));
365

Petar Perisin's avatar
Petar Perisin committed
366
367
    /* \"Current File" menu */

368
    // ------------
Petar Perisin's avatar
Petar Perisin committed
369
370
371
372
373

    /*  "Current Project" menu */
    Core::ActionContainer *currentProjectMenu = Core::ActionManager::createMenu(Core::Id("Git.CurrentProjectMenu"));
    currentProjectMenu->menu()->setTitle(tr("Current &Project"));
    gitContainer->addMenu(currentProjectMenu);
con's avatar
con committed
374

375
    parameterActionCommand
Petar Perisin's avatar
Petar Perisin committed
376
            = createProjectAction(currentProjectMenu,
377
                                  tr("Diff Current Project"), tr("Diff Project \"%1\""),
hjk's avatar
hjk committed
378
                                  Core::Id("Git.DiffProject"),
379
380
                                  globalcontext, true,
                                  SLOT(diffCurrentProject()));
381
    parameterActionCommand.second->setDefaultKeySequence(QKeySequence(Core::UseMacShortcuts ? tr("Meta+G,Meta+Shift+D") : tr("Alt+G,Alt+Shift+D")));
382
383

    parameterActionCommand
Petar Perisin's avatar
Petar Perisin committed
384
            = createProjectAction(currentProjectMenu,
385
                                  tr("Log Project"), tr("Log Project \"%1\""),
hjk's avatar
hjk committed
386
                                  Core::Id("Git.LogProject"), globalcontext, true,
387
                                  SLOT(logProject()));
388
    parameterActionCommand.second->setDefaultKeySequence(QKeySequence(Core::UseMacShortcuts ? tr("Meta+G,Meta+K") : tr("Alt+G,Alt+K")));
389
390

    parameterActionCommand
Petar Perisin's avatar
Petar Perisin committed
391
                = createProjectAction(currentProjectMenu,
392
                                      tr("Clean Project..."), tr("Clean Project \"%1\"..."),
hjk's avatar
hjk committed
393
                                      Core::Id("Git.CleanProject"), globalcontext,
394
                                      true, SLOT(cleanProject()));
con's avatar
con committed
395

Petar Perisin's avatar
Petar Perisin committed
396
    /* \"Current Project" menu */
397
398

    // --------------
con's avatar
con committed
399

Petar Perisin's avatar
Petar Perisin committed
400
401
402
403
404
405
    /*  "Local Repository" menu */
    Core::ActionContainer *localRepositoryMenu = Core::ActionManager::createMenu(Core::Id("Git.LocalRepositoryMenu"));
    localRepositoryMenu->menu()->setTitle(tr("&Local Repository"));
    gitContainer->addMenu(localRepositoryMenu);

    createRepositoryAction(localRepositoryMenu,
hjk's avatar
hjk committed
406
                           tr("Diff"), Core::Id("Git.DiffRepository"),
407
                           globalcontext, true, SLOT(diffRepository()));
408

Petar Perisin's avatar
Petar Perisin committed
409
    createRepositoryAction(localRepositoryMenu,
hjk's avatar
hjk committed
410
                           tr("Log"), Core::Id("Git.LogRepository"),
411
                           globalcontext, true, &GitClient::graphLog);
412

Petar Perisin's avatar
Petar Perisin committed
413
414
415
416
417
    createRepositoryAction(localRepositoryMenu,
                           tr("Clean..."), Core::Id("Git.CleanRepository"),
                           globalcontext, true, SLOT(cleanRepository()));

    createRepositoryAction(localRepositoryMenu,
hjk's avatar
hjk committed
418
                           tr("Status"), Core::Id("Git.StatusRepository"),
419
                           globalcontext, true, &GitClient::status);
420

Petar Perisin's avatar
Petar Perisin committed
421
422
    // --------------
    localRepositoryMenu->addSeparator(globalcontext);
con's avatar
con committed
423

Petar Perisin's avatar
Petar Perisin committed
424
425
426
427
    ActionCommandPair actionCommand = createRepositoryAction(localRepositoryMenu,
                                                             tr("Commit..."), Core::Id("Git.Commit"),
                                                             globalcontext, true, SLOT(startCommit()));
    actionCommand.second->setDefaultKeySequence(QKeySequence(Core::UseMacShortcuts ? tr("Meta+G,Meta+C") : tr("Alt+G,Alt+C")));
428

Petar Perisin's avatar
Petar Perisin committed
429
430
431
    createRepositoryAction(localRepositoryMenu,
                           tr("Amend Last Commit..."), Core::Id("Git.AmendCommit"),
                           globalcontext, true, SLOT(startAmendCommit()));
432
433
    // --------------
    localRepositoryMenu->addSeparator(globalcontext);
434

Petar Perisin's avatar
Petar Perisin committed
435
436
437
    createRepositoryAction(localRepositoryMenu,
                           tr("Reset..."), Core::Id("Git.Reset"),
                           globalcontext, false, SLOT(resetRepository()));
438

439
440
441
442
443
444
445
446
    createRepositoryAction(localRepositoryMenu,
                           tr("Revert Single Commit..."), Core::Id("Git.Revert"),
                           globalcontext, true, SLOT(startRevertCommit()));

    createRepositoryAction(localRepositoryMenu,
                           tr("Cherry-Pick Commit..."), Core::Id("Git.CherryPick"),
                           globalcontext, true, SLOT(startCherryPickCommit()));

447
    // --------------
Petar Perisin's avatar
Petar Perisin committed
448
    localRepositoryMenu->addSeparator(globalcontext);
449

Petar Perisin's avatar
Petar Perisin committed
450
    createRepositoryAction(localRepositoryMenu,
hjk's avatar
hjk committed
451
                           tr("Branches..."), Core::Id("Git.BranchList"),
Yuchen Deng's avatar
Yuchen Deng committed
452
                           globalcontext, true, SLOT(branchList()));
453
454

    // --------------
Petar Perisin's avatar
Petar Perisin committed
455
    localRepositoryMenu->addSeparator(globalcontext);
456

Petar Perisin's avatar
Petar Perisin committed
457
    // "Patch" menu
Eike Ziller's avatar
Eike Ziller committed
458
    Core::ActionContainer *patchMenu = Core::ActionManager::createMenu(Core::Id("Git.PatchMenu"));
Petar Perisin's avatar
Petar Perisin committed
459
460
    patchMenu->menu()->setTitle(tr("&Patch"));
    localRepositoryMenu->addMenu(patchMenu);
461
462
463

    // Apply current file as patch is handled specially.
    parameterActionCommand =
Eike Ziller's avatar
Eike Ziller committed
464
            createParameterAction(patchMenu,
465
                                  tr("Apply from Editor"), tr("Apply \"%1\""),
hjk's avatar
hjk committed
466
                                  Core::Id("Git.ApplyCurrentFilePatch"),
467
468
469
470
471
                                  globalcontext, true);
    m_applyCurrentFilePatchAction = parameterActionCommand.first;
    connect(m_applyCurrentFilePatchAction, SIGNAL(triggered()), this,
            SLOT(applyCurrentFilePatch()));

Eike Ziller's avatar
Eike Ziller committed
472
    createRepositoryAction(patchMenu,
hjk's avatar
hjk committed
473
                           tr("Apply from File..."), Core::Id("Git.ApplyPatch"),
474
475
                           globalcontext, true, SLOT(promptApplyPatch()));

Petar Perisin's avatar
Petar Perisin committed
476
    // "Stash" menu
Eike Ziller's avatar
Eike Ziller committed
477
    Core::ActionContainer *stashMenu = Core::ActionManager::createMenu(Core::Id("Git.StashMenu"));
Petar Perisin's avatar
Petar Perisin committed
478
479
    stashMenu->menu()->setTitle(tr("&Stash"));
    localRepositoryMenu->addMenu(stashMenu);
480

Eike Ziller's avatar
Eike Ziller committed
481
    createRepositoryAction(stashMenu,
hjk's avatar
hjk committed
482
                           tr("Stashes..."), Core::Id("Git.StashList"),
483
484
                           globalcontext, false, SLOT(stashList()));

485
    stashMenu->addSeparator(globalcontext);
486

Petar Perisin's avatar
Petar Perisin committed
487
488
489
    actionCommand = createRepositoryAction(stashMenu,
                                           tr("Stash"), Core::Id("Git.Stash"),
                                           globalcontext, true, SLOT(stash()));
490
491
    actionCommand.first->setToolTip(tr("Saves the current state of your work and resets the repository."));

Eike Ziller's avatar
Eike Ziller committed
492
    actionCommand = createRepositoryAction(stashMenu,
hjk's avatar
hjk committed
493
                                           tr("Take Snapshot..."), Core::Id("Git.StashSnapshot"),
494
495
496
                                           globalcontext, true, SLOT(stashSnapshot()));
    actionCommand.first->setToolTip(tr("Saves the current state of your work."));

497
    stashMenu->addSeparator(globalcontext);
498

Eike Ziller's avatar
Eike Ziller committed
499
    actionCommand = createRepositoryAction(stashMenu,
hjk's avatar
hjk committed
500
                                           tr("Stash Pop"), Core::Id("Git.StashPop"),
501
502
503
                                           globalcontext, true, &GitClient::stashPop);
    actionCommand.first->setToolTip(tr("Restores changes saved to the stash list using \"Stash\"."));

Petar Perisin's avatar
Petar Perisin committed
504
505
506
507
508
509
510
511
512
513
514
515
516
517
518
519
520
521
522
523
524
525
526
527
528
529

    /* \"Local Repository" menu */

    // --------------

    /*  "Remote Repository" menu */
    Core::ActionContainer *remoteRepositoryMenu = Core::ActionManager::createMenu(Core::Id("Git.RemoteRepositoryMenu"));
    remoteRepositoryMenu->menu()->setTitle(tr("&Remote Repository"));
    gitContainer->addMenu(remoteRepositoryMenu);

    createRepositoryAction(remoteRepositoryMenu,
                           tr("Fetch"), Core::Id("Git.Fetch"),
                           globalcontext, true, SLOT(fetch()));

    createRepositoryAction(remoteRepositoryMenu,
                           tr("Pull"), Core::Id("Git.Pull"),
                           globalcontext, true, SLOT(pull()));

    actionCommand = createRepositoryAction(remoteRepositoryMenu,
                                           tr("Push"), Core::Id("Git.Push"),
                                           globalcontext, true, SLOT(push()));

    // --------------
    remoteRepositoryMenu->addSeparator(globalcontext);

    // "Subversion" menu
Eike Ziller's avatar
Eike Ziller committed
530
    Core::ActionContainer *subversionMenu = Core::ActionManager::createMenu(Core::Id("Git.Subversion"));
Petar Perisin's avatar
Petar Perisin committed
531
532
    subversionMenu->menu()->setTitle(tr("&Subversion"));
    remoteRepositoryMenu->addMenu(subversionMenu);
533

Eike Ziller's avatar
Eike Ziller committed
534
    createRepositoryAction(subversionMenu,
hjk's avatar
hjk committed
535
                           tr("Log"), Core::Id("Git.Subversion.Log"),
536
537
                           globalcontext, false, &GitClient::subversionLog);

Eike Ziller's avatar
Eike Ziller committed
538
    createRepositoryAction(subversionMenu,
hjk's avatar
hjk committed
539
                           tr("Fetch"), Core::Id("Git.Subversion.Fetch"),
540
541
                           globalcontext, false, &GitClient::synchronousSubversionFetch);

Petar Perisin's avatar
Petar Perisin committed
542
543
    // --------------
    remoteRepositoryMenu->addSeparator(globalcontext);
544

Petar Perisin's avatar
Petar Perisin committed
545
546
547
    createRepositoryAction(remoteRepositoryMenu,
                           tr("Manage Remotes..."), Core::Id("Git.RemoteList"),
                           globalcontext, false, SLOT(remoteList()));
548

Petar Perisin's avatar
Petar Perisin committed
549
    /* \"Remote Repository" menu */
Robert Loehning's avatar
Robert Loehning committed
550

Petar Perisin's avatar
Petar Perisin committed
551
    // --------------
552

Petar Perisin's avatar
Petar Perisin committed
553
554
555
556
    /*  "Git Tools" menu */
    Core::ActionContainer *gitToolsMenu = Core::ActionManager::createMenu(Core::Id("Git.GitToolsMenu"));
    gitToolsMenu->menu()->setTitle(tr("Git &Tools"));
    gitContainer->addMenu(gitToolsMenu);
557

Petar Perisin's avatar
Petar Perisin committed
558
559
560
    createRepositoryAction(gitToolsMenu,
                           tr("Gitk"), Core::Id("Git.LaunchGitK"),
                           globalcontext, true, &GitClient::launchGitK);
561

Petar Perisin's avatar
Petar Perisin committed
562
563
564
565
566
567
568
569
570
571
572
573
574
    parameterActionCommand
            = createFileAction(gitToolsMenu,
                               tr("Gitk Current File"), tr("Gitk of \"%1\""),
                               Core::Id("Git.GitkFile"), globalcontext, true, SLOT(gitkForCurrentFile()));

    parameterActionCommand
            = createFileAction(gitToolsMenu,
                               tr("Gitk for folder of Current File"), tr("Gitk for folder of \"%1\""),
                               Core::Id("Git.GitkFolder"), globalcontext, true, SLOT(gitkForCurrentFolder()));

    // --------------
    gitToolsMenu->addSeparator(globalcontext);

Petar Perisin's avatar
Petar Perisin committed
575
576
577
578
    m_repositoryBrowserAction
            = createRepositoryAction(gitToolsMenu,
                                     tr("Repository Browser"), Core::Id("Git.LaunchRepositoryBrowser"),
                                     globalcontext, true, &GitClient::launchRepositoryBrowser).first;
579

Petar Perisin's avatar
Petar Perisin committed
580
    createRepositoryAction(gitToolsMenu,
581
582
583
                           tr("Merge Tool"), Core::Id("Git.MergeTool"),
                           globalcontext, true, SLOT(startMergeTool()));

Petar Perisin's avatar
Petar Perisin committed
584
585
586
    /* \"Git Tools" menu */

    // --------------
587
    gitContainer->addSeparator(globalcontext);
588

Daniel Teske's avatar
Daniel Teske committed
589
590
591
592
    m_showAction
            = createRepositoryAction(gitContainer,
                                     tr("Show..."), Core::Id("Git.ShowCommit"),
                                     globalcontext, true, SLOT(showCommit())).first;
Petar Perisin's avatar
Petar Perisin committed
593
594
595
596
597
598

    m_createRepositoryAction = new QAction(tr("Create Repository..."), this);
    Core::Command *createRepositoryCommand = Core::ActionManager::registerAction(m_createRepositoryAction, "Git.CreateRepository", globalcontext);
    connect(m_createRepositoryAction, SIGNAL(triggered()), this, SLOT(createRepository()));
    gitContainer->addAction(createRepositoryCommand);

599
600
601
602
    if (0) {
        const QList<QAction*> snapShotActions = createSnapShotTestActions();
        const int count = snapShotActions.size();
        for (int i = 0; i < count; i++) {
603
            Core::Command *tCommand
Eike Ziller's avatar
Eike Ziller committed
604
                    = Core::ActionManager::registerAction(snapShotActions.at(i),
hjk's avatar
hjk committed
605
                                                    Core::Id(QLatin1String("Git.Snapshot.") + QString::number(i)),
606
                                                    globalcontext);
607
            gitContainer->addAction(tCommand);
608
609
610
        }
    }

con's avatar
con committed
611
    // Submit editor
612
    Core::Context submitContext(Constants::C_GITSUBMITEDITOR);
hjk's avatar
hjk committed
613
    m_submitCurrentAction = new QAction(VcsBase::VcsBaseSubmitEditor::submitIcon(), tr("Commit"), this);
Eike Ziller's avatar
Eike Ziller committed
614
    Core::Command *command = Core::ActionManager::registerAction(m_submitCurrentAction, Constants::SUBMIT_CURRENT, submitContext);
615
    command->setAttribute(Core::Command::CA_UpdateText);
con's avatar
con committed
616
617
    connect(m_submitCurrentAction, SIGNAL(triggered()), this, SLOT(submitCurrentLog()));

hjk's avatar
hjk committed
618
    m_diffSelectedFilesAction = new QAction(VcsBase::VcsBaseSubmitEditor::diffIcon(), tr("Diff &Selected Files"), this);
Eike Ziller's avatar
Eike Ziller committed
619
    command = Core::ActionManager::registerAction(m_diffSelectedFilesAction, Constants::DIFF_SELECTED, submitContext);
con's avatar
con committed
620
621

    m_undoAction = new QAction(tr("&Undo"), this);
Eike Ziller's avatar
Eike Ziller committed
622
    command = Core::ActionManager::registerAction(m_undoAction, Core::Constants::UNDO, submitContext);
con's avatar
con committed
623
624

    m_redoAction = new QAction(tr("&Redo"), this);
Eike Ziller's avatar
Eike Ziller committed
625
    command = Core::ActionManager::registerAction(m_redoAction, Core::Constants::REDO, submitContext);
con's avatar
con committed
626

627

Petar Perisin's avatar
Petar Perisin committed
628
    /* "Gerrit" */
629
    Gerrit::Internal::GerritPlugin *gp = new Gerrit::Internal::GerritPlugin(this);
Petar Perisin's avatar
Petar Perisin committed
630
    return gp->initialize(remoteRepositoryMenu);
con's avatar
con committed
631
632
}

633
GitVersionControl *GitPlugin::gitVersionControl() const
634
{
635
    return static_cast<GitVersionControl *>(versionControl());
636
637
}

638
void GitPlugin::submitEditorDiff(const QStringList &unstaged, const QStringList &staged)
con's avatar
con committed
639
{
640
    m_gitClient->diff(m_submitRepository, QStringList(), unstaged, staged);
con's avatar
con committed
641
642
}

643
644
645
646
647
void GitPlugin::submitEditorMerge(const QStringList &unmerged)
{
    m_gitClient->merge(m_submitRepository, unmerged);
}

con's avatar
con committed
648
649
void GitPlugin::diffCurrentFile()
{
hjk's avatar
hjk committed
650
    const VcsBase::VcsBasePluginState state = currentState();
651
    QTC_ASSERT(state.hasFile(), return);
652
    m_gitClient->diff(state.currentFileTopLevel(), QStringList(), state.relativeCurrentFile());
con's avatar
con committed
653
654
655
656
}

void GitPlugin::diffCurrentProject()
{
hjk's avatar
hjk committed
657
    const VcsBase::VcsBasePluginState state = currentState();
658
    QTC_ASSERT(state.hasProject(), return);
659
    m_gitClient->diff(state.currentProjectTopLevel(), QStringList(), state.relativeCurrentProject());
con's avatar
con committed
660
661
}

662
663
void GitPlugin::diffRepository()
{
hjk's avatar
hjk committed
664
    const VcsBase::VcsBasePluginState state = currentState();
665
    QTC_ASSERT(state.hasTopLevel(), return);
666
667
668
    m_gitClient->diff(state.topLevel(), QStringList(), QStringList());
}

con's avatar
con committed
669
670
void GitPlugin::logFile()
{
hjk's avatar
hjk committed
671
    const VcsBase::VcsBasePluginState state = currentState();
672
    QTC_ASSERT(state.hasFile(), return);
673
    m_gitClient->log(state.currentFileTopLevel(), QStringList(state.relativeCurrentFile()), true);
con's avatar
con committed
674
675
676
677
}

void GitPlugin::blameFile()
{
hjk's avatar
hjk committed
678
    const VcsBase::VcsBasePluginState state = currentState();
679
    QTC_ASSERT(state.hasFile(), return);
hjk's avatar
hjk committed
680
    const int lineNumber = VcsBase::VcsBaseEditorWidget::lineNumberOfCurrentEditor(state.currentFile());
681
    m_gitClient->blame(state.currentFileTopLevel(), QStringList(), state.relativeCurrentFile(), QString(), lineNumber);
con's avatar
con committed
682
683
684
685
}

void GitPlugin::logProject()
{
hjk's avatar
hjk committed
686
    const VcsBase::VcsBasePluginState state = currentState();
687
    QTC_ASSERT(state.hasProject(), return);
688
    m_gitClient->log(state.currentProjectTopLevel(), state.relativeCurrentProject());
con's avatar
con committed
689
690
}

691
void GitPlugin::undoFileChanges(bool revertStaging)
con's avatar
con committed
692
{
hjk's avatar
hjk committed
693
    const VcsBase::VcsBasePluginState state = currentState();
694
    QTC_ASSERT(state.hasFile(), return);
695
    Core::FileChangeBlocker fcb(state.currentFile());
696
697
698
699
700
701
    m_gitClient->revert(QStringList(state.currentFile()), revertStaging);
}

void GitPlugin::undoUnstagedFileChanges()
{
    undoFileChanges(false);
con's avatar
con committed
702
703
}

704
void GitPlugin::resetRepository()
con's avatar
con committed
705
{
hjk's avatar
hjk committed
706
    const VcsBase::VcsBasePluginState state = currentState();
707
    QTC_ASSERT(state.hasTopLevel(), return);
708
    QString topLevel = state.topLevel();
709

710
    LogChangeDialog dialog(true);
711
712
    dialog.setWindowTitle(tr("Undo Changes to %1").arg(QDir::toNativeSeparators(topLevel)));
    if (dialog.runDialog(topLevel))
Petar Perisin's avatar
Petar Perisin committed
713
714
        switch (dialog.resetType()) {
        case HardReset:
715
            m_gitClient->hardReset(topLevel, dialog.commit());
Petar Perisin's avatar
Petar Perisin committed
716
717
            break;
        case SoftReset:
718
            m_gitClient->softReset(topLevel, dialog.commit());
Petar Perisin's avatar
Petar Perisin committed
719
720
            break;
        }
con's avatar
con committed
721
722
}

723
724
void GitPlugin::startRevertCommit()
{
Orgad Shaneh's avatar
Orgad Shaneh committed
725
726
727
728
729
730
731
732
    const VcsBase::VcsBasePluginState state = currentState();
    QString workingDirectory = state.currentDirectoryOrTopLevel();
    if (workingDirectory.isEmpty())
        return;
    GitClient::StashGuard stashGuard(workingDirectory, QLatin1String("Revert"));
    if (stashGuard.stashingFailed(true))
        return;
    ChangeSelectionDialog changeSelectionDialog(workingDirectory);
733

Orgad Shaneh's avatar
Orgad Shaneh committed
734
735
736
737
738
    if (changeSelectionDialog.exec() != QDialog::Accepted)
        return;
    const QString change = changeSelectionDialog.change();
    if (!change.isEmpty() && !m_gitClient->revertCommit(workingDirectory, change))
        stashGuard.preventPop();
739
740
}

Orgad Shaneh's avatar
Orgad Shaneh committed
741
void GitPlugin::startCherryPickCommit()
742
743
{
    const VcsBase::VcsBasePluginState state = currentState();
Orgad Shaneh's avatar
Orgad Shaneh committed
744
745
    QString workingDirectory = state.currentDirectoryOrTopLevel();
    if (workingDirectory.isEmpty())
746
        return;
Orgad Shaneh's avatar
Orgad Shaneh committed
747
748
    GitClient::StashGuard stashGuard(state.topLevel(), QLatin1String("Cherry-pick"));
    if (stashGuard.stashingFailed(true))
749
750
751
752
753
754
        return;
    ChangeSelectionDialog changeSelectionDialog(workingDirectory);

    if (changeSelectionDialog.exec() != QDialog::Accepted)
        return;
    const QString change = changeSelectionDialog.change();
Orgad Shaneh's avatar
Orgad Shaneh committed
755
756
    if (!change.isEmpty() && !m_gitClient->cherryPickCommit(workingDirectory, change))
        stashGuard.preventPop();
757
758
}

759
void GitPlugin::stageFile()
con's avatar
con committed
760
{
hjk's avatar
hjk committed
761
    const VcsBase::VcsBasePluginState state = currentState();
762
    QTC_ASSERT(state.hasFile(), return);
763
    m_gitClient->addFile(state.currentFileTopLevel(), state.relativeCurrentFile());
con's avatar
con committed
764
765
}

766
767
void GitPlugin::unstageFile()
{
hjk's avatar
hjk committed
768
    const VcsBase::VcsBasePluginState state = currentState();
769
    QTC_ASSERT(state.hasFile(), return);
770
    m_gitClient->synchronousReset(state.currentFileTopLevel(), QStringList(state.relativeCurrentFile()));
771
772
}

Petar Perisin's avatar
Petar Perisin committed
773
774
775
776
777
778
779
780
781
782
783
784
785
786
787
788
789
790
791
792
793
794
795
796
797
798
799
800
801
802
803
804
805
806
807
808
809
void GitPlugin::gitkForCurrentFile()
{
    const VcsBase::VcsBasePluginState state = currentState();
    QTC_ASSERT(state.hasFile(), return);
    m_gitClient->launchGitK(state.currentFileTopLevel(), state.relativeCurrentFile());
}

void GitPlugin::gitkForCurrentFolder()
{
    const VcsBase::VcsBasePluginState state = currentState();
    QTC_ASSERT(state.hasFile(), return);

    /*
     *  entire lower part of the code can be easily replaced with one line:
     *
     *  m_gitClient->launchGitK(dir.currentFileDirectory(), QLatin1String("."));
     *
     *  However, there is a bug in gitk in version 1.7.9.5, and if you run above
     *  command, there will be no documents listed in lower right section.
     *
     *  This is why I use lower combination in order to avoid this problems in gitk.
     *
     *  Git version 1.7.10.4 does not have this issue, and it can easily use
     *  one line command mentioned above.
     *
     */
    QDir dir(state.currentFileDirectory());
    if (QFileInfo(dir,QLatin1String(".git")).exists() || dir.cd(QLatin1String(".git")))
        m_gitClient->launchGitK(state.currentFileDirectory());
    else {
        QString folderName = dir.absolutePath();
        dir.cdUp();
        folderName = folderName.remove(0, dir.absolutePath().length() + 1);
        m_gitClient->launchGitK(dir.absolutePath(), folderName);
    }
}

810
811
812
813
814
void GitPlugin::startAmendCommit()
{
    startCommit(true);
}

con's avatar
con committed
815
816
void GitPlugin::startCommit()
{
817
818
819
820
821
    startCommit(false);
}

void GitPlugin::startCommit(bool amend)
{
hjk's avatar
hjk committed
822
    if (VcsBase::VcsBaseSubmitEditor::raiseSubmitEditor())
823
        return;
824
    if (isCommitEditorOpen()) {
hjk's avatar
hjk committed
825
        VcsBase::VcsBaseOutputWindow::instance()->appendWarning(tr("Another submit is currently being executed."));
con's avatar
con committed
826
827
828
        return;
    }

hjk's avatar
hjk committed
829
    const VcsBase::VcsBasePluginState state = currentState();
830
    QTC_ASSERT(state.hasTopLevel(), return);
con's avatar
con committed
831
832
833

    QString errorMessage, commitTemplate;
    CommitData data;
834
    if (!m_gitClient->getCommitData(state.topLevel(), amend, &commitTemplate, &data, &errorMessage)) {
hjk's avatar
hjk committed
835
        VcsBase::VcsBaseOutputWindow::instance()->append(errorMessage);
con's avatar
con committed
836
837
838
        return;
    }

839
840
    // Store repository for diff and the original list of
    // files to be able to unstage files the user unchecks
con's avatar
con committed
841
    m_submitRepository = data.panelInfo.repository;
842
    m_commitAmendSHA1 = data.amendSHA1;
con's avatar
con committed
843
844

    // Start new temp file with message template
845
846
847
848
849
    Utils::TempFileSaver saver;
    // Keep the file alive, else it removes self and forgets its name
    saver.setAutoRemove(false);
    saver.write(commitTemplate.toLocal8Bit());
    if (!saver.finalize()) {
hjk's avatar
hjk committed
850
        VcsBase::VcsBaseOutputWindow::instance()->append(saver.errorString());
con's avatar
con committed
851
852
        return;
    }
853
    m_commitMessageFileName = saver.fileName();
854
    openSubmitEditor(m_commitMessageFileName, data, amend);
con's avatar
con committed
855
856
}

Orgad Shaneh's avatar
Orgad Shaneh committed
857
858
859
860
861
862
863
864
865
866
867
868
869
870
871
872
873
874
875
876
void GitPlugin::updateVersionWarning()
{
    if (m_gitClient->gitVersion() >= minimumRequiredVersion)
        return;
    Core::IEditor *curEditor = Core::EditorManager::currentEditor();
    if (!curEditor)
        return;
    Core::IDocument *curDocument = curEditor->document();
    if (!curDocument)
        return;
    Core::InfoBar *infoBar = curDocument->infoBar();
    Core::Id gitVersionWarning("GitVersionWarning");
    if (!infoBar->canInfoBeAdded(gitVersionWarning))
        return;
    infoBar->addInfo(Core::InfoBarEntry(gitVersionWarning,
                        tr("Unsupported version of Git found. Git %1 or later required.")
                        .arg(versionString(minimumRequiredVersion)),
                        Core::InfoBarEntry::GlobalSuppressionEnabled));
}

877
Core::IEditor *GitPlugin::openSubmitEditor(const QString &fileName, const CommitData &cd, bool amend)
con's avatar
con committed
878
{
hjk's avatar
hjk committed
879
880
    Core::IEditor *editor = Core::EditorManager::openEditor(fileName, Constants::GITSUBMITEDITOR_ID,
                                                Core::EditorManager::ModeSwitch);
con's avatar
con committed
881
    GitSubmitEditor *submitEditor = qobject_cast<GitSubmitEditor*>(editor);
hjk's avatar
hjk committed
882
    QTC_ASSERT(submitEditor, return 0);
con's avatar
con committed
883
884
    // The actions are for some reason enabled by the context switching
    // mechanism. Disable them correctly.
885
    submitEditor->registerActions(m_undoAction, m_redoAction, m_submitCurrentAction, m_diffSelectedFilesAction);
con's avatar
con committed
886
    submitEditor->setCommitData(cd);
887
    submitEditor->setCheckScriptWorkingDirectory(m_submitRepository);
888
889
    const QString title = amend ? tr("Amend %1").arg(cd.amendSHA1) : tr("Git Commit");
    submitEditor->setDisplayName(title);
890
    submitEditor->setAmend(amend);