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 "resetdialog.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 <coreplugin/documentmanager.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 <QMenu>
#include <QMessageBox>
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(QLatin1String(Git::Constants::GITSUBMITEDITOR_ID)),
m_showAction(0),
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("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()));
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\"."));
500
501
502
503
504
505
506
507
508
509
510
511
512
513
514
515
516
517
518
519
520
521
522
523
524
525
/* \"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_showAction = new QAction(tr("Show..."), this);
Core::Command *showCommitCommand = Core::ActionManager::registerAction(m_showAction, "Git.ShowCommit", globalcontext);
connect(m_showAction, SIGNAL(triggered()), this, SLOT(showCommit()));
gitContainer->addAction(showCommitCommand);
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);
Gerrit::Internal::GerritPlugin *gp = new Gerrit::Internal::GerritPlugin(this);
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);
ResetDialog dialog;
if (dialog.runDialog(state.topLevel()))
switch (dialog.resetType()) {
case HardReset:
m_gitClient->hardReset(state.topLevel(), dialog.commit());
break;
case SoftReset:
m_gitClient->softReset(state.topLevel(), dialog.commit());
break;
}
void GitPlugin::startRevertCommit()
{
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);
if (changeSelectionDialog.exec() != QDialog::Accepted)
return;
const QString change = changeSelectionDialog.change();
if (!change.isEmpty() && !m_gitClient->revertCommit(workingDirectory, change))
stashGuard.preventPop();
{
const VcsBase::VcsBasePluginState state = currentState();
QString workingDirectory = state.currentDirectoryOrTopLevel();
if (workingDirectory.isEmpty())
GitClient::StashGuard stashGuard(state.topLevel(), QLatin1String("Cherry-pick"));
if (stashGuard.stashingFailed(true))
return;
ChangeSelectionDialog changeSelectionDialog(workingDirectory);
if (changeSelectionDialog.exec() != QDialog::Accepted)
return;
const QString change = changeSelectionDialog.change();
if (!change.isEmpty() && !m_gitClient->cherryPickCommit(workingDirectory, change))
stashGuard.preventPop();
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()));
}
767
768
769
770
771
772
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
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);
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);
editor->promptSubmit(tr("Closing Git Editor"),

Friedemann Kleint
committed
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);
if (closeEditor)
cleanCommitMessageFile();
return closeEditor;
m_gitClient->synchronousFetch(currentState().topLevel(), QString());
bool rebase = m_gitClient->settings()->boolValue(GitSettings::pullRebaseKey);
if (!rebase) {
bool isDetached;
QString branchRebaseConfig = m_gitClient->synchronousRepositoryBranches(state.topLevel(), &isDetached).at(0);
if (!isDetached) {
branchRebaseConfig.prepend(QLatin1String("branch."));
branchRebaseConfig.append(QLatin1String(".rebase"));
rebase = (m_gitClient->readConfigValue(state.topLevel(), branchRebaseConfig) == QLatin1String("true"));
}
}

Friedemann Kleint
committed
GitClient::StashGuard stashGuard(state.topLevel(), QLatin1String("Pull"));
if (stashGuard.stashingFailed(false) || (rebase && (stashGuard.result() == GitClient::NotStashed)))
return;
if (!m_gitClient->synchronousPull(state.topLevel(), rebase))
QTC_ASSERT(state.hasTopLevel(), return);
m_gitClient->synchronousPush(state.topLevel());
void GitPlugin::startMergeTool()
{
const VcsBase::VcsBasePluginState state = currentState();
QTC_ASSERT(state.hasTopLevel(), return);
m_gitClient->merge(state.topLevel());
}
// Retrieve member function of git client stored as user data of action
static inline GitClientMemberFunc memberFunctionFromAction(const QObject *o)
{
if (o) {
if (const QAction *action = qobject_cast<const QAction *>(o)) {
const QVariant v = action->data();
if (v.canConvert<GitClientMemberFunc>())
return qvariant_cast<GitClientMemberFunc>(v);
}
}
return 0;
}
void GitPlugin::gitClientMemberFuncRepositoryAction()
{
QTC_ASSERT(state.hasTopLevel(), return);
// Retrieve member function and invoke on repository
GitClientMemberFunc func = memberFunctionFromAction(sender());
QTC_ASSERT(func, return);
(m_gitClient->*func)(state.topLevel());
}
QTC_ASSERT(state.hasProject(), return);
cleanRepository(state.currentProjectPath());
}
void GitPlugin::cleanRepository()