Skip to content
Snippets Groups Projects
gitclient.cpp 152 KiB
Newer Older
hjk's avatar
hjk committed
/****************************************************************************
con's avatar
con committed
**
** Copyright (C) 2014 Digia Plc and/or its subsidiary(-ies).
hjk's avatar
hjk committed
** Contact: http://www.qt-project.org/legal
con's avatar
con committed
**
hjk's avatar
hjk committed
** This file is part of Qt Creator.
con's avatar
con committed
**
hjk's avatar
hjk committed
** 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
hjk's avatar
hjk committed
** 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
** version 1.1, included in the file LGPL_EXCEPTION.txt in this package.
**
hjk's avatar
hjk committed
****************************************************************************/
hjk's avatar
hjk committed

con's avatar
con committed
#include "gitclient.h"
#include "gitutils.h"
con's avatar
con committed
#include "commitdata.h"
hjk's avatar
hjk committed
#include "gitconstants.h"
#include "gitplugin.h"
#include "gitversioncontrol.h"
#include "mergetool.h"
#include "branchadddialog.h"
Christian Kandeler's avatar
Christian Kandeler committed
#include "gerrit/gerritplugin.h"
con's avatar
con committed

#include <vcsbase/submitfilemodel.h>

con's avatar
con committed
#include <coreplugin/editormanager/editormanager.h>
hjk's avatar
hjk committed
#include <coreplugin/icore.h>
#include <coreplugin/vcsmanager.h>
#include <coreplugin/iversioncontrol.h>
#include <coreplugin/coreconstants.h>
#include <utils/hostosinfo.h>
hjk's avatar
hjk committed
#include <utils/qtcassert.h>
#include <utils/qtcprocess.h>
#include <utils/synchronousprocess.h>
#include <utils/fileutils.h>
Tobias Hunger's avatar
Tobias Hunger committed
#include <vcsbase/command.h>
hjk's avatar
hjk committed
#include <vcsbase/vcsbaseeditor.h>
#include <vcsbase/vcsbaseeditorparameterwidget.h>
#include <vcsbase/vcsbaseoutputwindow.h>
#include <vcsbase/vcsbaseplugin.h>
con's avatar
con committed

#include <diffeditor/diffeditorconstants.h>
#include <diffeditor/diffeditorcontroller.h>
#include <diffeditor/diffeditordocument.h>
#include <diffeditor/diffeditormanager.h>
#include <QCoreApplication>
#include <QFileInfo>
#include <QHash>
#include <QRegExp>
#include <QSignalMapper>
#include <QTime>
con's avatar
con committed

#include <QMessageBox>
#include <QPushButton>
#include <QToolButton>
#include <QTextCodec>
con's avatar
con committed

static const char GIT_DIRECTORY[] = ".git";
static const char graphLogFormatC[] = "%h %d %an %s %ci";
static const char HEAD[] = "HEAD";
static const char noColorOption[] = "--no-color";
static const char decorateOption[] = "--decorate";
con's avatar
con committed

namespace Git {
namespace Internal {

// Suppress git diff warnings about "LF will be replaced by CRLF..." on Windows.
static inline unsigned diffExecutionFlags()
{
    return Utils::HostOsInfo::isWindowsHost() ? unsigned(VcsBase::VcsBasePlugin::SuppressStdErrInLogWindow) : 0u;
}

using VcsBase::VcsBasePlugin;

class GitDiffSwitcher : public QObject
{
    Q_OBJECT

public:
    enum DiffType {
        DiffRepository,
        DiffFile,
        DiffFileList,
        DiffProjectList,
        DiffBranch,
        DiffShow
    };

    GitDiffSwitcher(Core::IDocument *parentDocument, GitClient *gitClient);

    void setWorkingDirectory(const QString &workingDir) { m_workingDirectory = workingDir; }
    void setDiffType(DiffType type) { m_diffType = type; }
    void setFileName(const QString &fileName) { m_fileName = fileName; }
    void setFileList(const QStringList &stagedFiles, const QStringList &unstagedFiles)
    {
        m_stagedFiles = stagedFiles;
        m_unstagedFiles = unstagedFiles;
    }
    void setProjectList(const QStringList &projectFiles) { m_projectFiles = projectFiles; }
    void setBranchName(const QString &branchName) { m_branchName = branchName; }
    void setId(const QString &id) { m_id = id; }
    void setDisplayName(const QString &displayName) { m_displayName = displayName; }
    void setBaseArguments(const QStringList &args) { m_baseArguments = args; }

private slots:
    void slotEditorOpened(Core::IEditor *editor);
    void slotEditorClosed(Core::IEditor *editor);
    void execute(QObject *editor);
    void attachAction(Core::IEditor *editor);
    QString actionText();

    Core::IDocument *m_document;
    GitClient *m_gitClient;
    QString m_workingDirectory;
    DiffType m_diffType;
    bool m_usingDiffEditor;
    QString m_fileName;
    QStringList m_stagedFiles;
    QStringList m_unstagedFiles;
    QStringList m_projectFiles;
    QString m_branchName;
    QString m_id;
    QString m_displayName;
    QStringList m_baseArguments;

    QSignalMapper *m_signalMapper;
    QMap<QObject *, bool> m_editorToUsingSideBySideDiffEditor;
GitDiffSwitcher::GitDiffSwitcher(Core::IDocument *parentDocument, GitClient *gitClient)
    : QObject(parentDocument),
      m_document(parentDocument),
      m_gitClient(gitClient),
      m_signalMapper(new QSignalMapper(this))
{
    Core::DocumentModel *documentModel = Core::EditorManager::documentModel();
    QList<Core::IEditor *> editors = documentModel->editorsForDocument(m_document);
    for (int i = 0; i < editors.count(); i++)
        attachAction(editors.at(i));

    // must be queued connection because execute() removes the editor & tool bar that the action was added to
    connect(m_signalMapper, SIGNAL(mapped(QObject*)), this, SLOT(execute(QObject*)), Qt::QueuedConnection);
    connect(Core::EditorManager::instance(), SIGNAL(editorOpened(Core::IEditor*)),
            this, SLOT(slotEditorOpened(Core::IEditor*)));
    connect(Core::EditorManager::instance(), SIGNAL(editorAboutToClose(Core::IEditor*)),
            this, SLOT(slotEditorClosed(Core::IEditor*)));
}

void GitDiffSwitcher::attachAction(Core::IEditor *editor)
    if (m_editorToUsingSideBySideDiffEditor.contains(editor))
        return;

    const bool usingSideBySideDiffEditor = m_gitClient->settings()->boolValue(GitSettings::useDiffEditorKey);
    QIcon actionIcon = usingSideBySideDiffEditor
            ? QIcon(QLatin1String(Core::Constants::ICON_TEXT_DIFF))
            : QIcon(QLatin1String(Core::Constants::ICON_SIDE_BY_SIDE_DIFF));

    const QString actionToolTip = usingSideBySideDiffEditor
            ? tr("Switch to Text Diff Editor")
            : tr("Switch to Side By Side Diff Editor");

    QAction *switchAction = new QAction(actionIcon, actionToolTip, editor);
    editor->toolBar()->addAction(switchAction);
    connect(switchAction, SIGNAL(triggered()),
            m_signalMapper, SLOT(map()));
    m_signalMapper->setMapping(switchAction, editor);

    m_editorToUsingSideBySideDiffEditor.insert(editor, usingSideBySideDiffEditor);
}

void GitDiffSwitcher::slotEditorOpened(Core::IEditor *editor)
{
    Core::IDocument *document = editor->document();
    if (document != m_document)
        return;
Loading
Loading full blame...