Newer
Older
/****************************************************************************
** Copyright (C) 2013 Digia Plc and/or its subsidiary(-ies).
** 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.
** GNU Lesser General Public License Usage
** 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
** version 1.1, included in the file LGPL_EXCEPTION.txt in this package.
**
****************************************************************************/
#include "changeselectiondialog.h"
#include "commitdata.h"
#include "clonewizard.h"
#include "gitorious/gitoriousclonewizard.h"
#include "gerrit/gerritplugin.h"
#include <coreplugin/icore.h>
#include <coreplugin/coreconstants.h>
#include <coreplugin/documentmanager.h>
#include <coreplugin/actionmanager/actionmanager.h>
#include <coreplugin/actionmanager/actioncontainer.h>
#include <coreplugin/actionmanager/command.h>
#include <coreplugin/id.h>
#include <coreplugin/editormanager/ieditor.h>
#include <utils/parameteraction.h>
#include <vcsbase/submitfilemodel.h>
#include <vcsbase/vcsbaseeditor.h>
#include <vcsbase/basevcssubmiteditorfactory.h>
#include <vcsbase/vcsbaseoutputwindow.h>
#include <vcsbase/cleandialog.h>
#include <QDebug>
#include <QDir>
#include <QFileInfo>
#include <QtPlugin>
#include <QAction>
#include <QFileDialog>
#include <QMessageBox>
static const unsigned minimumRequiredVersion = 0x010702;
static const VcsBase::VcsBaseEditorParameters editorParameters[] = {
Git::Constants::GIT_COMMAND_LOG_EDITOR_ID,
Git::Constants::GIT_COMMAND_LOG_EDITOR_DISPLAY_NAME,
Git::Constants::C_GIT_COMMAND_LOG_EDITOR,
Git::Constants::GIT_LOG_EDITOR_ID,
Git::Constants::GIT_LOG_EDITOR_DISPLAY_NAME,
Git::Constants::C_GIT_LOG_EDITOR,
Git::Constants::GIT_BLAME_EDITOR_ID,
Git::Constants::GIT_BLAME_EDITOR_DISPLAY_NAME,
Git::Constants::C_GIT_BLAME_EDITOR,
"application/vnd.nokia.text.scs_git_annotation",
"gitsannotate"},
Git::Constants::GIT_DIFF_EDITOR_ID,
Git::Constants::GIT_DIFF_EDITOR_DISPLAY_NAME,
Git::Constants::C_GIT_DIFF_EDITOR,
"text/x-patch","diff"}
};
// Utility to find a parameter set by type
static inline const VcsBase::VcsBaseEditorParameters *findType(int ie)
const VcsBase::EditorContentType et = static_cast<VcsBase::EditorContentType>(ie);
return VcsBase::VcsBaseEditorWidget::findType(editorParameters, sizeof(editorParameters)/sizeof(VcsBase::VcsBaseEditorParameters), et);
Q_DECLARE_METATYPE(Git::Internal::GitClientMemberFunc)
using namespace Git;
using namespace Git::Internal;
// GitPlugin
GitPlugin *GitPlugin::m_instance = 0;
GitPlugin::GitPlugin() :
VcsBase::VcsBasePlugin(Git::Constants::GITSUBMITEDITOR_ID),
m_submitCurrentAction(0),
m_diffSelectedFilesAction(0),
m_undoAction(0),
m_redoAction(0),
m_menuAction(0),
m_applyCurrentFilePatchAction(0),
m_submitActionTriggered(false)
const int mid = qRegisterMetaType<GitClientMemberFunc>();
Q_UNUSED(mid)
m_fileActions.reserve(10);
m_projectActions.reserve(10);
m_repositoryActions.reserve(15);
cleanCommitMessageFile();
void GitPlugin::cleanCommitMessageFile()
if (!m_commitMessageFileName.isEmpty()) {
QFile::remove(m_commitMessageFileName);
m_commitMessageFileName.clear();
bool GitPlugin::isCommitEditorOpen() const
{
return !m_commitMessageFileName.isEmpty();
}
GitPlugin *GitPlugin::instance()
{
return m_instance;
}
static const VcsBase::VcsBaseSubmitEditorParameters submitParameters = {
Git::Constants::GITSUBMITEDITOR_ID,
Git::Constants::GITSUBMITEDITOR_DISPLAY_NAME,
Git::Constants::C_GITSUBMITEDITOR,
VcsBase::VcsBaseSubmitEditorParameters::DiffRows
// Create a parameter action
ParameterActionCommandPair
GitPlugin::createParameterAction(Core::ActionContainer *ac,
const QString &defaultText, const QString ¶meterText,
bool addToLocator)
{
Utils::ParameterAction *action = new Utils::ParameterAction(defaultText, parameterText,
Utils::ParameterAction::EnabledWithParameter,
this);
Core::Command *command = Core::ActionManager::registerAction(action, id, context);
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
GitPlugin::createFileAction(Core::ActionContainer *ac,
const QString &defaultText, const QString ¶meterText,
const Core::Id &id, const Core::Context &context, bool addToLocator,
const char *pluginSlot)
{
const ParameterActionCommandPair rc = createParameterAction(ac, defaultText, parameterText, id, context, addToLocator);
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
GitPlugin::createProjectAction(Core::ActionContainer *ac,
const QString &defaultText, const QString ¶meterText,
const Core::Id &id, const Core::Context &context, bool addToLocator,
const char *pluginSlot)
{
const ParameterActionCommandPair rc = createParameterAction(ac, defaultText, parameterText, id, context, addToLocator);
m_projectActions.push_back(rc.first);
connect(rc.first, SIGNAL(triggered()), this, pluginSlot);
return rc;
}
// Create an action to act on the repository
ActionCommandPair
GitPlugin::createRepositoryAction(Core::ActionContainer *ac,
const Core::Context &context, bool addToLocator)
{
QAction *action = new QAction(text, this);
Core::Command *command = Core::ActionManager::registerAction(action, id, context);
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
GitPlugin::createRepositoryAction(Core::ActionContainer *ac,
const Core::Context &context, bool addToLocator,
const char *pluginSlot)
{
const ActionCommandPair rc = createRepositoryAction(ac, text, id, context, addToLocator);
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
GitPlugin::createRepositoryAction(Core::ActionContainer *ac,
const Core::Context &context, bool addToLocator,
GitClientMemberFunc func)
{
// Set the member func as data and connect to generic slot
const ActionCommandPair rc = createRepositoryAction(ac, text, id, context, addToLocator);
rc.first->setData(qVariantFromValue(func));
connect(rc.first, SIGNAL(triggered()), this, SLOT(gitClientMemberFuncRepositoryAction()));
return rc;
}
bool GitPlugin::initialize(const QStringList &arguments, QString *errorMessage)
Q_UNUSED(arguments)
Q_UNUSED(errorMessage)
m_gitClient = new GitClient(&m_settings);
typedef VcsBase::VcsEditorFactory<GitEditor> GitEditorFactory;
typedef VcsBase::VcsSubmitEditorFactory<GitSubmitEditor> GitSubmitEditorFactory;
initializeVcs(new GitVersionControl(m_gitClient));
// Create the globalcontext list to register actions accordingly
Core::Context globalcontext(Core::Constants::C_GLOBAL);
addAutoReleasedObject(new SettingsPage());
const int editorCount = sizeof(editorParameters)/sizeof(VcsBase::VcsBaseEditorParameters);
for (int i = 0; i < editorCount; i++)
addAutoReleasedObject(new GitEditorFactory(editorParameters + i, m_gitClient, describeSlot));
addAutoReleasedObject(new GitSubmitEditorFactory(&submitParameters));
addAutoReleasedObject(new CloneWizard);
addAutoReleasedObject(new Gitorious::Internal::GitoriousCloneWizard);
m_commandLocator = new Locator::CommandLocator("Git", prefix, prefix);
Core::ActionContainer *toolsContainer =
Core::ActionManager::actionContainer(Core::Constants::M_TOOLS);
Core::ActionContainer *gitContainer = Core::ActionManager::createMenu("Git");
gitContainer->menu()->setTitle(tr("&Git"));
toolsContainer->addMenu(gitContainer);
m_menuAction = gitContainer->menu()->menuAction();
/* "Current File" menu */
Core::ActionContainer *currentFileMenu = Core::ActionManager::createMenu(Core::Id("Git.CurrentFileMenu"));
currentFileMenu->menu()->setTitle(tr("Current &File"));
gitContainer->addMenu(currentFileMenu);
ParameterActionCommandPair parameterActionCommand
= createFileAction(currentFileMenu,
tr("Diff Current File"), tr("Diff of \"%1\""),
parameterActionCommand.second->setDefaultKeySequence(QKeySequence(Core::UseMacShortcuts ? tr("Meta+G,Meta+D") : tr("Alt+G,Alt+D")));
parameterActionCommand
tr("Log Current File"), tr("Log of \"%1\""),
parameterActionCommand.second->setDefaultKeySequence(QKeySequence(Core::UseMacShortcuts ? tr("Meta+G,Meta+L") : tr("Alt+G,Alt+L")));
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")));
parameterActionCommand
tr("Stage File for Commit"), tr("Stage \"%1\" for Commit"),
Core::Id("Git.Stage"), globalcontext, true, SLOT(stageFile()));
parameterActionCommand.second->setDefaultKeySequence(QKeySequence(Core::UseMacShortcuts ? tr("Meta+G,Meta+A") : tr("Alt+G,Alt+A")));
parameterActionCommand
tr("Unstage File from Commit"), tr("Unstage \"%1\" from Commit"),
Core::Id("Git.Unstage"), globalcontext, true, SLOT(unstageFile()));
tr("Undo Unstaged Changes"), tr("Undo Unstaged Changes for \"%1\""),
true, SLOT(undoUnstagedFileChanges()));
parameterActionCommand
tr("Undo Uncommitted Changes"), tr("Undo Uncommitted Changes for \"%1\""),
true, SLOT(undoFileChanges()));
parameterActionCommand.second->setDefaultKeySequence(QKeySequence(Core::UseMacShortcuts ? tr("Meta+G,Meta+U") : tr("Alt+G,Alt+U")));
/* "Current Project" menu */
Core::ActionContainer *currentProjectMenu = Core::ActionManager::createMenu(Core::Id("Git.CurrentProjectMenu"));
currentProjectMenu->menu()->setTitle(tr("Current &Project"));
gitContainer->addMenu(currentProjectMenu);
parameterActionCommand
tr("Diff Current Project"), tr("Diff Project \"%1\""),
globalcontext, true,
SLOT(diffCurrentProject()));
parameterActionCommand.second->setDefaultKeySequence(QKeySequence(Core::UseMacShortcuts ? tr("Meta+G,Meta+Shift+D") : tr("Alt+G,Alt+Shift+D")));
parameterActionCommand
tr("Log Project"), tr("Log Project \"%1\""),
SLOT(logProject()));
parameterActionCommand.second->setDefaultKeySequence(QKeySequence(Core::UseMacShortcuts ? tr("Meta+G,Meta+K") : tr("Alt+G,Alt+K")));
parameterActionCommand
tr("Clean Project..."), tr("Clean Project \"%1\"..."),
true, SLOT(cleanProject()));
/* "Local Repository" menu */
Core::ActionContainer *localRepositoryMenu = Core::ActionManager::createMenu(Core::Id("Git.LocalRepositoryMenu"));
localRepositoryMenu->menu()->setTitle(tr("&Local Repository"));
gitContainer->addMenu(localRepositoryMenu);
createRepositoryAction(localRepositoryMenu,
globalcontext, true, SLOT(diffRepository()));
globalcontext, true, &GitClient::graphLog);
createRepositoryAction(localRepositoryMenu,
tr("Clean..."), Core::Id("Git.CleanRepository"),
globalcontext, true, SLOT(cleanRepository()));
createRepositoryAction(localRepositoryMenu,
globalcontext, true, &GitClient::status);
// --------------
localRepositoryMenu->addSeparator(globalcontext);
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")));
createRepositoryAction(localRepositoryMenu,
tr("Amend Last Commit..."), Core::Id("Git.AmendCommit"),
globalcontext, true, SLOT(startAmendCommit()));
// --------------
localRepositoryMenu->addSeparator(globalcontext);
createRepositoryAction(localRepositoryMenu,
tr("Reset..."), Core::Id("Git.Reset"),
globalcontext, false, SLOT(resetRepository()));
createRepositoryAction(localRepositoryMenu,
tr("Interactive Rebase..."), Core::Id("Git.Rebase"),
globalcontext, true, SLOT(startRebase()));
createRepositoryAction(localRepositoryMenu,
tr("Change-related Actions..."), Core::Id("Git.ChangeRelatedActions"),
globalcontext, true, SLOT(startChangeRelatedAction()));
m_submoduleUpdateAction =
createRepositoryAction(localRepositoryMenu,
tr("Update Submodules"), Core::Id("Git.SubmoduleUpdate"),
globalcontext, true, SLOT(updateSubmodules())).first;
Core::ActionContainer *patchMenu = Core::ActionManager::createMenu(Core::Id("Git.PatchMenu"));
patchMenu->menu()->setTitle(tr("&Patch"));
localRepositoryMenu->addMenu(patchMenu);
// Apply current file as patch is handled specially.
parameterActionCommand =
tr("Apply from Editor"), tr("Apply \"%1\""),
globalcontext, true);
m_applyCurrentFilePatchAction = parameterActionCommand.first;
connect(m_applyCurrentFilePatchAction, SIGNAL(triggered()), this,
SLOT(applyCurrentFilePatch()));
globalcontext, true, SLOT(promptApplyPatch()));
Core::ActionContainer *stashMenu = Core::ActionManager::createMenu(Core::Id("Git.StashMenu"));
stashMenu->menu()->setTitle(tr("&Stash"));
localRepositoryMenu->addMenu(stashMenu);
globalcontext, false, SLOT(stashList()));
stashMenu->addSeparator(globalcontext);
actionCommand = createRepositoryAction(stashMenu,
tr("Stash"), Core::Id("Git.Stash"),
globalcontext, true, SLOT(stash()));
actionCommand.first->setToolTip(tr("Saves the current state of your work and resets the repository."));
actionCommand = createRepositoryAction(stashMenu,
globalcontext, true, SLOT(stashSnapshot()));
actionCommand.first->setToolTip(tr("Saves the current state of your work."));
stashMenu->addSeparator(globalcontext);
actionCommand = createRepositoryAction(stashMenu,
globalcontext, true, &GitClient::stashPop);
actionCommand.first->setToolTip(tr("Restores changes saved to the stash list using \"Stash\"."));
503
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
/* \"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
Core::ActionContainer *subversionMenu = Core::ActionManager::createMenu(Core::Id("Git.Subversion"));
subversionMenu->menu()->setTitle(tr("&Subversion"));
remoteRepositoryMenu->addMenu(subversionMenu);
globalcontext, false, &GitClient::subversionLog);
globalcontext, false, &GitClient::synchronousSubversionFetch);
// --------------
remoteRepositoryMenu->addSeparator(globalcontext);
createRepositoryAction(remoteRepositoryMenu,
tr("Manage Remotes..."), Core::Id("Git.RemoteList"),
globalcontext, false, SLOT(remoteList()));
/* "Git Tools" menu */
Core::ActionContainer *gitToolsMenu = Core::ActionManager::createMenu(Core::Id("Git.GitToolsMenu"));
gitToolsMenu->menu()->setTitle(tr("Git &Tools"));
gitContainer->addMenu(gitToolsMenu);
createRepositoryAction(gitToolsMenu,
tr("Gitk"), Core::Id("Git.LaunchGitK"),
globalcontext, true, &GitClient::launchGitK);
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);
m_repositoryBrowserAction
= createRepositoryAction(gitToolsMenu,
tr("Repository Browser"), Core::Id("Git.LaunchRepositoryBrowser"),
globalcontext, true, &GitClient::launchRepositoryBrowser).first;
tr("Merge Tool"), Core::Id("Git.MergeTool"),
globalcontext, true, SLOT(startMergeTool()));
gitContainer->addSeparator(globalcontext);
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);
if (0) {
const QList<QAction*> snapShotActions = createSnapShotTestActions();
const int count = snapShotActions.size();
for (int i = 0; i < count; i++) {
Core::Command *tCommand
= Core::ActionManager::registerAction(snapShotActions.at(i),
gitContainer->addAction(tCommand);
Core::Context submitContext(Constants::C_GITSUBMITEDITOR);
m_submitCurrentAction = new QAction(VcsBase::VcsBaseSubmitEditor::submitIcon(), tr("Commit"), this);
Core::Command *command = Core::ActionManager::registerAction(m_submitCurrentAction, Constants::SUBMIT_CURRENT, submitContext);
command->setAttribute(Core::Command::CA_UpdateText);
connect(m_submitCurrentAction, SIGNAL(triggered()), this, SLOT(submitCurrentLog()));
m_diffSelectedFilesAction = new QAction(VcsBase::VcsBaseSubmitEditor::diffIcon(), tr("Diff &Selected Files"), this);
command = Core::ActionManager::registerAction(m_diffSelectedFilesAction, Constants::DIFF_SELECTED, submitContext);
command = Core::ActionManager::registerAction(m_undoAction, Core::Constants::UNDO, submitContext);
command = Core::ActionManager::registerAction(m_redoAction, Core::Constants::REDO, submitContext);
m_gerritPlugin = new Gerrit::Internal::GerritPlugin(this);
const bool ok = m_gerritPlugin->initialize(remoteRepositoryMenu);
m_gerritPlugin->updateActions(currentState().hasTopLevel());
m_gerritPlugin->addToLocator(m_commandLocator);
return ok;
GitVersionControl *GitPlugin::gitVersionControl() const
return static_cast<GitVersionControl *>(versionControl());
void GitPlugin::submitEditorDiff(const QStringList &unstaged, const QStringList &staged)
m_gitClient->diff(m_submitRepository, QStringList(), unstaged, staged);
void GitPlugin::submitEditorMerge(const QStringList &unmerged)
{
m_gitClient->merge(m_submitRepository, unmerged);
}
QTC_ASSERT(state.hasFile(), return);
m_gitClient->diff(state.currentFileTopLevel(), QStringList(), state.relativeCurrentFile());
QTC_ASSERT(state.hasProject(), return);
m_gitClient->diff(state.currentProjectTopLevel(), QStringList(), state.relativeCurrentProject());
void GitPlugin::diffRepository()
{
QTC_ASSERT(state.hasTopLevel(), return);
m_gitClient->diff(state.topLevel(), QStringList(), QStringList());
}
QTC_ASSERT(state.hasFile(), return);
m_gitClient->log(state.currentFileTopLevel(), QStringList(state.relativeCurrentFile()), true);
QTC_ASSERT(state.hasFile(), return);
const int lineNumber = VcsBase::VcsBaseEditorWidget::lineNumberOfCurrentEditor(state.currentFile());
m_gitClient->blame(state.currentFileTopLevel(), QStringList(), state.relativeCurrentFile(), QString(), lineNumber);
QTC_ASSERT(state.hasProject(), return);
m_gitClient->log(state.currentProjectTopLevel(), state.relativeCurrentProject());
void GitPlugin::undoFileChanges(bool revertStaging)
QTC_ASSERT(state.hasFile(), return);
Core::FileChangeBlocker fcb(state.currentFile());
m_gitClient->revert(QStringList(state.currentFile()), revertStaging);
}
void GitPlugin::undoUnstagedFileChanges()
{
undoFileChanges(false);
void GitPlugin::resetRepository()
QTC_ASSERT(state.hasTopLevel(), return);
QString topLevel = state.topLevel();
dialog.setWindowTitle(tr("Undo Changes to %1").arg(QDir::toNativeSeparators(topLevel)));
if (dialog.runDialog(topLevel))
m_gitClient->hardReset(topLevel, dialog.commit());
m_gitClient->softReset(topLevel, dialog.commit());
void GitPlugin::startRebase()
{
QString workingDirectory = currentState().currentDirectoryOrTopLevel();
if (workingDirectory.isEmpty() || !m_gitClient->canRebase(workingDirectory))
return;
GitClient::StashGuard stashGuard(workingDirectory, QLatin1String("Rebase-i"));
if (stashGuard.stashingFailed())
return;
stashGuard.preventPop();
LogChangeDialog dialog(false);
dialog.setWindowTitle(tr("Interactive Rebase"));
if (!dialog.runDialog(workingDirectory))
return;
const QString change = dialog.commit() + QLatin1Char('^');
if (!change.isEmpty())
m_gitClient->interactiveRebase(workingDirectory, change);
}
void GitPlugin::startChangeRelatedAction()
const VcsBase::VcsBasePluginState state = currentState();
const QString workingDirectory = state.currentDirectoryOrTopLevel();
QPointer<ChangeSelectionDialog> dialog = new ChangeSelectionDialog
(workingDirectory, Core::ICore::mainWindow());
int result = dialog->exec();
if (dialog.isNull() || (result == QDialog::Rejected) || dialog->change().isEmpty())
const QString change = dialog->change();
if (dialog->command() == Show) {
m_gitClient->show(workingDirectory, change);
QString command;
bool (GitClient::*commandFunction)(const QString&, const QString&);
switch (dialog->command()) {
case CherryPick:
command = QLatin1String("Cherry-pick");
commandFunction = &GitClient::cherryPickCommit;
break;
case Revert:
command = QLatin1String("Revert");
commandFunction = &GitClient::revertCommit;
break;
case Checkout:
command = QLatin1String("Checkout");
commandFunction = &GitClient::synchronousCheckout;
break;
}
GitClient::StashGuard stashGuard(workingDirectory, command);
if (stashGuard.stashingFailed())
if (!(m_gitClient->*commandFunction)(workingDirectory, change))
void GitPlugin::stageFile()
QTC_ASSERT(state.hasFile(), return);
m_gitClient->addFile(state.currentFileTopLevel(), state.relativeCurrentFile());
void GitPlugin::unstageFile()
{
QTC_ASSERT(state.hasFile(), return);
m_gitClient->synchronousReset(state.currentFileTopLevel(), QStringList(state.relativeCurrentFile()));
}
804
805
806
807
808
809
810
811
812
813
814
815
816
817
818
819
820
821
822
823
824
825
826
827
828
829
830
831
832
833
834
835
836
837
838
839
840
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);
}
}
void GitPlugin::startAmendCommit()
{
startCommit(true);
}
startCommit(false);
}
void GitPlugin::startCommit(bool amend)
{
return;
if (isCommitEditorOpen()) {
VcsBase::VcsBaseOutputWindow::instance()->appendWarning(tr("Another submit is currently being executed."));
QTC_ASSERT(state.hasTopLevel(), return);
if (!m_gitClient->getCommitData(state.topLevel(), amend, &commitTemplate, &data, &errorMessage)) {
// Store repository for diff and the original list of
// files to be able to unstage files the user unchecks
m_commitAmendSHA1 = data.amendSHA1;
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()) {
VcsBase::VcsBaseOutputWindow::instance()->append(saver.errorString());
m_commitMessageFileName = saver.fileName();
openSubmitEditor(m_commitMessageFileName, data, amend);
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));
}
Core::IEditor *GitPlugin::openSubmitEditor(const QString &fileName, const CommitData &cd, bool amend)
Core::IEditor *editor = Core::EditorManager::openEditor(fileName, Constants::GITSUBMITEDITOR_ID,
Core::EditorManager::ModeSwitch);
GitSubmitEditor *submitEditor = qobject_cast<GitSubmitEditor*>(editor);
// The actions are for some reason enabled by the context switching
// mechanism. Disable them correctly.

Friedemann Kleint
committed
submitEditor->registerActions(m_undoAction, m_redoAction, m_submitCurrentAction, m_diffSelectedFilesAction);
submitEditor->setCheckScriptWorkingDirectory(m_submitRepository);
const QString title = amend ? tr("Amend %1").arg(cd.amendSHA1) : tr("Git Commit");
submitEditor->setDisplayName(title);
submitEditor->setAmend(amend);
connect(submitEditor, SIGNAL(diff(QStringList,QStringList)), this, SLOT(submitEditorDiff(QStringList,QStringList)));
connect(submitEditor, SIGNAL(merge(QStringList)), this, SLOT(submitEditorMerge(QStringList)));
return editor;
}
void GitPlugin::submitCurrentLog()
{
// Close the submit editor
m_submitActionTriggered = true;
bool GitPlugin::submitEditorAboutToClose(VcsBase::VcsBaseSubmitEditor *submitEditor)
if (!isCommitEditorOpen())
return false;
Core::IDocument *editorDocument = submitEditor->document();
const GitSubmitEditor *editor = qobject_cast<GitSubmitEditor *>(submitEditor);
if (!editorDocument || !editor)
return true;
// Submit editor closing. Make it write out the commit message
// and retrieve files
const QFileInfo editorFile(editorDocument->fileName());
const QFileInfo changeFile(m_commitMessageFileName);
// Paranoia!
if (editorFile.absoluteFilePath() != changeFile.absoluteFilePath())
return true;
// Prompt user. Force a prompt unless submit was actually invoked (that
// is, the editor was closed or shutdown).
bool *promptData = m_settings.boolPointer(GitSettings::promptOnSubmitKey);
VcsBase::VcsBaseSubmitEditor::PromptSubmitResult answer;
if (editor->forceClose()) {
answer = VcsBase::VcsBaseSubmitEditor::SubmitDiscarded;
} else {
answer = editor->promptSubmit(tr("Closing Git Editor"),
tr("Do you want to commit the change?"),
tr("Git will not accept this commit. Do you want to continue to edit it?"),
promptData, !m_submitActionTriggered, false);
}
m_submitActionTriggered = false;
cleanCommitMessageFile();
VcsBase::SubmitFileModel *model = qobject_cast<VcsBase::SubmitFileModel *>(editor->fileModel());
bool closeEditor = true;
if (model->hasCheckedFiles() || !m_commitAmendSHA1.isEmpty()) {
if (!Core::DocumentManager::saveDocument(editorDocument))
closeEditor = m_gitClient->addAndCommit(m_submitRepository, editor->panelData(),
m_commitAmendSHA1, m_commitMessageFileName, model);
cleanCommitMessageFile();
m_gitClient->continueCommandIfNeeded(m_submitRepository);
}
return closeEditor;
m_gitClient->synchronousFetch(currentState().topLevel(), QString());
QString topLevel = state.topLevel();