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 "gitconstants.h"
#include "gitplugin.h"
#include "gitsubmiteditor.h"
#include "gitversioncontrol.h"
#include <vcsbase/submitfilemodel.h>
#include <coreplugin/vcsmanager.h>
#include <coreplugin/id.h>
#include <coreplugin/iversioncontrol.h>
#include <utils/synchronousprocess.h>
#include <vcsbase/vcsbaseeditorparameterwidget.h>
#include <vcsbase/vcsbaseoutputwindow.h>
#include <vcsbase/vcsbaseplugin.h>
#include <diffeditor/diffeditorwidget.h>
#include <diffeditor/diffeditoreditable.h>
#include <diffeditor/diffeditorconstants.h>
#include <QSignalMapper>
#include <QToolButton>
#include <QTextCodec>
static const char GIT_DIRECTORY[] = ".git";
static const char graphLogFormatC[] = "%h %d %an %s %ci";
namespace Git {
namespace Internal {
class GitDiffHandler : public QObject
{
Q_OBJECT
public:
GitDiffHandler(DiffEditor::DiffEditorEditable *editor,
const QString &gitPath,
const QString &workingDirectory,
const QProcessEnvironment &environment,
int timeout);
// index -> working tree
void diffFile(const QString &fileName);
// stagedFileNames - files in index, diff will compare the state in HEAD to the one in the index
// unstagedFileNames - diff will compare the state in the index to the one in the working tree
void diffFiles(const QStringList &stagedFileNames, const QStringList &unstagedFileNames);
// index -> working tree
void diffProjects(const QStringList &projectPaths);
// index -> working tree
void diffRepository();
private slots:
void slotFileListReceived(const QByteArray &data);
void slotFileContentsReceived(const QByteArray &data);
private:
void collectFilesList(const QStringList &additionalArguments);
void collectFilesContents();
void feedEditor();
QString workingTreeContents(const QString &fileName) const;
QPointer<DiffEditor::DiffEditorEditable> m_editor;
const QString m_gitPath;
const QString m_workingDirectory;
const QProcessEnvironment m_processEnvironment;
const int m_timeout;
const QString m_waitMessage;
enum RevisionType {
Head = 0x01,
Index = 0x02,
WorkingTree = 0x04
};
QStringList m_requestedHeadFileNames;
QStringList m_requestedIndexFileNames;
QStringList m_headFileNames;
QStringList m_indexFileNames;
QStringList m_headContents;
QStringList m_indexContents;
};
GitDiffHandler::GitDiffHandler(DiffEditor::DiffEditorEditable *editor,
const QString &gitPath,
const QString &workingDirectory,
const QProcessEnvironment &environment,
int timeout)
: m_editor(editor),
m_gitPath(gitPath),
143
144
145
146
147
148
149
150
151
152
153
154
155
156
157
158
159
160
161
162
163
164
165
166
167
168
169
170
171
172
173
174
175
176
177
178
179
180
181
182
183
184
m_workingDirectory(workingDirectory),
m_processEnvironment(environment),
m_timeout(timeout),
m_waitMessage(tr("Waiting for data..."))
{
}
void GitDiffHandler::diffFile(const QString &fileName)
{
m_requestedIndexFileNames << fileName;
collectFilesList(QStringList() << QLatin1String("--") << m_requestedIndexFileNames);
}
void GitDiffHandler::diffFiles(const QStringList &stagedFileNames, const QStringList &unstagedFileNames)
{
m_requestedHeadFileNames = stagedFileNames;
m_requestedHeadFileNames.removeDuplicates();
m_requestedIndexFileNames = unstagedFileNames;
m_requestedIndexFileNames.removeDuplicates();
m_headFileNames = m_requestedHeadFileNames;
m_indexFileNames = m_requestedIndexFileNames;
for (int i = 0; i < m_headFileNames.count(); i++) {
const QString headFileName = m_headFileNames.at(i);
if (!m_indexFileNames.contains(headFileName))
m_indexFileNames.append(headFileName);
}
collectFilesContents();
}
void GitDiffHandler::diffProjects(const QStringList &projectPaths)
{
collectFilesList(QStringList() << QLatin1String("--") << projectPaths);
}
void GitDiffHandler::diffRepository()
{
collectFilesList(QStringList());
}
void GitDiffHandler::collectFilesList(const QStringList &additionalArguments)
{
VcsBase::Command *command = new VcsBase::Command(m_gitPath, m_workingDirectory, m_processEnvironment);
connect(command, SIGNAL(outputData(QByteArray)), this, SLOT(slotFileListReceived(QByteArray)));
QStringList arguments;
arguments << QLatin1String("diff") << QLatin1String("--name-only") << additionalArguments;
command->addJob(arguments, m_timeout);
command->execute();
}
void GitDiffHandler::slotFileListReceived(const QByteArray &data)
{
if (m_editor.isNull())
return;
const QString fileList = m_editor->editorWidget()->codec()->toUnicode(data);
200
201
202
203
204
205
206
207
208
209
210
211
212
213
214
215
216
217
218
219
220
221
222
223
224
225
226
227
228
229
230
231
232
233
234
235
236
237
238
239
m_requestedIndexFileNames = fileList.split(QLatin1Char('\n'), QString::SkipEmptyParts);
m_requestedIndexFileNames.removeDuplicates();
m_indexFileNames = m_requestedIndexFileNames;
collectFilesContents();
}
void GitDiffHandler::collectFilesContents()
{
const int headFilesReceived = m_headContents.count();
const int indexFilesReceived = m_indexContents.count();
if (headFilesReceived < m_headFileNames.count()) {
VcsBase::Command *command = new VcsBase::Command(m_gitPath, m_workingDirectory, m_processEnvironment);
connect(command, SIGNAL(outputData(QByteArray)), this, SLOT(slotFileContentsReceived(QByteArray)));
QStringList arguments;
arguments << QLatin1String("show") << QLatin1String("HEAD:./") + m_headFileNames.at(headFilesReceived);
command->addJob(arguments, m_timeout);
command->execute();
} else if (indexFilesReceived < m_indexFileNames.count()) {
VcsBase::Command *command = new VcsBase::Command(m_gitPath, m_workingDirectory, m_processEnvironment);
connect(command, SIGNAL(outputData(QByteArray)), this, SLOT(slotFileContentsReceived(QByteArray)));
QStringList arguments;
arguments << QLatin1String("show") << QLatin1String(":./") + m_indexFileNames.at(indexFilesReceived);
command->addJob(arguments, m_timeout);
command->execute();
} else {
feedEditor();
}
}
void GitDiffHandler::slotFileContentsReceived(const QByteArray &data)
{
if (m_editor.isNull())
return;
const int headFilesReceived = m_headContents.count();
const int indexFilesReceived = m_indexContents.count();
const QString contents = m_editor->editorWidget()->codec()->toUnicode(data);
241
242
243
244
245
246
247
248
249
250
251
252
253
254
255
256
257
258
259
260
261
262
263
264
265
266
267
268
269
270
271
272
273
274
275
276
277
278
279
280
281
if (headFilesReceived < m_headFileNames.count())
m_headContents.append(contents);
else if (indexFilesReceived < m_indexFileNames.count())
m_indexContents.append(contents);
collectFilesContents();
}
void GitDiffHandler::feedEditor()
{
QList<DiffEditor::DiffEditorWidget::DiffFilesContents> list;
for (int i = 0; i < m_requestedHeadFileNames.count(); i++) {
const QString fileName = m_requestedHeadFileNames.at(i);
const QString original = m_headContents.at(i);
const int idx = m_indexFileNames.indexOf(fileName);
if (idx >= 0) {
const QString modified = m_indexContents.at(idx);
if (original != modified) {
DiffEditor::DiffEditorWidget::DiffFilesContents dfc;
dfc.leftFileInfo = DiffEditor::DiffEditorWidget::DiffFileInfo(fileName, tr("Head"));
dfc.leftText = original;
dfc.rightFileInfo = DiffEditor::DiffEditorWidget::DiffFileInfo(fileName, tr("Index"));
dfc.rightText = modified;
list.append(dfc);
}
}
}
for (int i = 0; i < m_requestedIndexFileNames.count(); i++) {
const QString fileName = m_requestedIndexFileNames.at(i);
const QString original = m_indexContents.at(i);
const QString modified = workingTreeContents(fileName);
if (original != modified) {
DiffEditor::DiffEditorWidget::DiffFilesContents dfc;
dfc.leftFileInfo = DiffEditor::DiffEditorWidget::DiffFileInfo(fileName, tr("Index"));
dfc.leftText = original;
dfc.rightFileInfo = DiffEditor::DiffEditorWidget::DiffFileInfo(fileName, tr("Working tree"));
dfc.rightText = modified;
list.append(dfc);
}
}
m_editor->setDiff(list, m_workingDirectory);
deleteLater();
}
QString GitDiffHandler::workingTreeContents(const QString &fileName) const
{
QDir workingDir(m_workingDirectory);
QString absoluteFileName = workingDir.absoluteFilePath(fileName);
QFile file(absoluteFileName);
if (file.open(QIODevice::ReadOnly | QIODevice::Text)) {
return m_editor->editorWidget()->codec()->toUnicode(file.readAll());
}
return QString();
}
///////////////////////////////////////////////////////////
class BaseGitDiffArgumentsWidget : public VcsBase::VcsBaseEditorParameterWidget
BaseGitDiffArgumentsWidget(GitClient *client, const QString &directory,
QTC_ASSERT(!directory.isEmpty(), return);
QTC_ASSERT(m_client, return);
m_patienceButton = addToggleButton(QLatin1String("--patience"), tr("Patience"),
tr("Use the patience algorithm for calculating the differences."));
mapSetting(m_patienceButton, client->settings()->boolPointer(GitSettings::diffPatienceKey));
m_ignoreWSButton = addToggleButton(QLatin1String("--ignore-space-change"), tr("Ignore Whitespace"),
tr("Ignore whitespace only changes."));
mapSetting(m_ignoreWSButton, m_client->settings()->boolPointer(GitSettings::ignoreSpaceChangesInDiffKey));
QString m_workingDirectory;
GitClient *m_client;
QToolButton *m_patienceButton;
QToolButton *m_ignoreWSButton;
};
class GitCommitDiffArgumentsWidget : public BaseGitDiffArgumentsWidget
{
GitCommitDiffArgumentsWidget(Git::Internal::GitClient *client, const QString &directory,
const QStringList &args, const QStringList &unstaged,
const QStringList &staged) :
BaseGitDiffArgumentsWidget(client, directory, args),
m_unstagedFileNames(unstaged),
m_stagedFileNames(staged)
{ }
m_client->diff(m_workingDirectory, arguments(), m_unstagedFileNames, m_stagedFileNames);
}
private:
const QStringList m_unstagedFileNames;
const QStringList m_stagedFileNames;
};
class GitFileDiffArgumentsWidget : public BaseGitDiffArgumentsWidget
{
GitFileDiffArgumentsWidget(Git::Internal::GitClient *client, const QString &directory,
const QStringList &args, const QString &file) :
BaseGitDiffArgumentsWidget(client, directory, args),
m_client->diff(m_workingDirectory, arguments(), m_fileName);
}
private:
const QString m_fileName;
};
class GitBranchDiffArgumentsWidget : public BaseGitDiffArgumentsWidget
{
GitBranchDiffArgumentsWidget(Git::Internal::GitClient *client, const QString &directory,
const QStringList &args, const QString &branch) :
BaseGitDiffArgumentsWidget(client, directory, args),
m_client->diffBranch(m_workingDirectory, arguments(), m_branchName);
}
private:
const QString m_branchName;
};
class GitShowArgumentsWidget : public BaseGitDiffArgumentsWidget
GitShowArgumentsWidget(Git::Internal::GitClient *client,
const QString &directory,
const QStringList &args,
const QString &id) :
BaseGitDiffArgumentsWidget(client, directory, args),
m_client(client),
m_workingDirectory(directory),
QList<ComboBoxItem> prettyChoices;
prettyChoices << ComboBoxItem(tr("oneline"), QLatin1String("oneline"))
<< ComboBoxItem(tr("short"), QLatin1String("short"))
<< ComboBoxItem(tr("medium"), QLatin1String("medium"))
<< ComboBoxItem(tr("full"), QLatin1String("full"))
<< ComboBoxItem(tr("fuller"), QLatin1String("fuller"))
<< ComboBoxItem(tr("email"), QLatin1String("email"))
<< ComboBoxItem(tr("raw"), QLatin1String("raw"));
mapSetting(addComboBox(QStringList(QLatin1String("--pretty=%1")), prettyChoices),
m_client->settings()->intPointer(GitSettings::showPrettyFormatKey));
m_client->show(m_workingDirectory, m_id, arguments());
GitClient *m_client;
QString m_workingDirectory;
class GitBlameArgumentsWidget : public VcsBase::VcsBaseEditorParameterWidget
GitBlameArgumentsWidget(Git::Internal::GitClient *client,
const QString &directory,
const QStringList &args,
const QString &revision, const QString &fileName) :
m_client(client),
m_workingDirectory(directory),
m_revision(revision),
m_fileName(fileName)
{
mapSetting(addToggleButton(QString(), tr("Omit Date"),
tr("Hide the date of a change from the output.")),
m_client->settings()->boolPointer(GitSettings::omitAnnotationDateKey));
mapSetting(addToggleButton(QLatin1String("-w"), tr("Ignore Whitespace"),
tr("Ignore whitespace only changes.")),
m_client->settings()->boolPointer(GitSettings::ignoreSpaceChangesInBlameKey));
int line = -1;
if (m_editor)
line = m_editor->lineNumberOfCurrentEditor();
m_client->blame(m_workingDirectory, arguments(), m_fileName, m_revision, line);
GitClient *m_client;
QString m_workingDirectory;
QString m_revision;
QString m_fileName;
};
class GitLogArgumentsWidget : public BaseGitDiffArgumentsWidget
{
Q_OBJECT
public:
GitLogArgumentsWidget(Git::Internal::GitClient *client,
const QString &directory,
bool enableAnnotationContextMenu,
const QStringList &args,
const QStringList &fileNames) :
BaseGitDiffArgumentsWidget(client, directory, args),
m_client(client),
m_workingDirectory(directory),
m_enableAnnotationContextMenu(enableAnnotationContextMenu),
m_fileNames(fileNames)
{
QToolButton *diffButton = addToggleButton(QLatin1String("--patch"), tr("Show Diff"),
mapSetting(diffButton, m_client->settings()->boolPointer(GitSettings::logDiffKey));
connect(diffButton, SIGNAL(toggled(bool)), m_patienceButton, SLOT(setVisible(bool)));
connect(diffButton, SIGNAL(toggled(bool)), m_ignoreWSButton, SLOT(setVisible(bool)));
m_patienceButton->setVisible(diffButton->isChecked());
m_ignoreWSButton->setVisible(diffButton->isChecked());
QStringList graphArguments(QLatin1String("--graph"));
graphArguments << QLatin1String("--oneline") << QLatin1String("--topo-order");
graphArguments << (QLatin1String("--pretty=format:") + QLatin1String(graphLogFormatC));
QToolButton *graphButton = addToggleButton(graphArguments, tr("Graph"),
tr("Show textual graph log."));
mapSetting(graphButton, m_client->settings()->boolPointer(GitSettings::graphLogKey));
}
void executeCommand()
{
m_client->log(m_workingDirectory, m_fileNames, m_enableAnnotationContextMenu, arguments());
}
private:
GitClient *m_client;
QString m_workingDirectory;
bool m_enableAnnotationContextMenu;
QStringList m_fileNames;
};
518
519
520
521
522
523
524
525
526
527
528
529
530
531
532
533
534
535
536
537
538
539
540
541
542
543
544
545
546
547
548
549
550
551
552
553
554
555
556
557
558
559
560
561
562
563
class ConflictHandler : public QObject
{
Q_OBJECT
public:
ConflictHandler(QObject *parent,
const QString &workingDirectory,
const QString &command)
: QObject(parent),
m_workingDirectory(workingDirectory),
m_command(command)
{
}
~ConflictHandler()
{
if (m_commit.isEmpty())
GitPlugin::instance()->gitVersionControl()->emitRepositoryChanged(m_workingDirectory);
else
GitPlugin::instance()->gitClient()->handleMergeConflicts(
m_workingDirectory, m_commit, m_command);
}
void readStdOutString(const QString &data)
{
static QRegExp patchFailedRE(QLatin1String("Patch failed at ([^\\n]*)"));
if (patchFailedRE.indexIn(data) != -1)
m_commit = patchFailedRE.cap(1);
}
public slots:
void readStdOut(const QByteArray &data)
{
readStdOutString(QString::fromUtf8(data));
}
void readStdErr(const QString &data)
{
static QRegExp couldNotApplyRE(QLatin1String("[Cc]ould not (?:apply|revert) ([^\\n]*)"));
if (couldNotApplyRE.indexIn(data) != -1)
m_commit = couldNotApplyRE.cap(1);
}
private:
QString m_workingDirectory;
QString m_command;
QString m_commit;
};
class RebaseManager : public QObject
{
Q_OBJECT
public:
RebaseManager(GitClient::StashGuard &stashGuard, QObject *parent) :
QObject(parent),
m_stashGuard(&stashGuard)
~RebaseManager()
{
delete m_stashGuard;
}
public slots:
void readStdErr(const QString &error)
{
// rebase conflict is output to stdOut
QRegExp conflictedCommit(QLatin1String("Could not apply ([^\\n]*)"));
conflictedCommit.indexIn(error);
m_commit = conflictedCommit.cap(1);
}
void finished(bool ok, int exitCode, const QVariant &workingDirectory)
{
Q_UNUSED(ok);
if (exitCode != 0 && !m_commit.isEmpty()) {
GitPlugin::instance()->gitClient()->handleMergeConflicts(
workingDirectory.toString(), m_commit, QLatin1String("rebase"));
}
}
private:
QString m_commit;
GitClient::StashGuard *m_stashGuard;
Core::IEditor *locateEditor(const char *property, const QString &entry)
foreach (Core::IEditor *ed, Core::ICore::editorManager()->openedEditors())
if (ed->document()->property(property).toString() == entry)
// Return converted command output, remove '\r' read on Windows
static inline QString commandOutputFromLocal8Bit(const QByteArray &a)
{
QString output = QString::fromLocal8Bit(a);
output.remove(QLatin1Char('\r'));
return output;
}
// Return converted command output split into lines
static inline QStringList commandOutputLinesFromLocal8Bit(const QByteArray &a)
{
QString output = commandOutputFromLocal8Bit(a);
const QChar newLine = QLatin1Char('\n');
if (output.endsWith(newLine))
output.truncate(output.size() - 1);
if (output.isEmpty())
return QStringList();
return output.split(newLine);
}
static inline QString msgRepositoryNotFound(const QString &dir)
{
return GitClient::tr("Cannot determine the repository for \"%1\".").arg(dir);
}
static inline QString msgParseFilesFailed()
{
return GitClient::tr("Cannot parse the file output.");
}
static inline QString currentDocumentPath()
{
if (Core::IEditor *editor = Core::EditorManager::currentEditor())
return QFileInfo(editor->document()->fileName()).path();
return QString();
// ---------------- GitClient
const char *GitClient::stashNamePrefix = "stash@{";
GitClient::GitClient(GitSettings *settings) :
m_cachedGitVersion(0),
m_repositoryChangedSignalMapper(0),
m_settings(settings),
m_disableEditor(false)
connect(Core::ICore::instance(), SIGNAL(saveSettingsRequested()), this, SLOT(saveSettings()));
m_gitQtcEditor = QString::fromLatin1("\"%1\" -client -block -pid %2")
.arg(QCoreApplication::applicationFilePath())
.arg(QCoreApplication::applicationPid());

Friedemann Kleint
committed
const char *GitClient::noColorOption = "--no-color";
const char *GitClient::decorateOption = "--decorate";

Friedemann Kleint
committed
QString GitClient::findRepositoryForDirectory(const QString &dir)
{
if (dir.endsWith(QLatin1String("/.git")) || dir.contains(QLatin1String("/.git/")))
return QString();
QString dotGit = QLatin1String(GIT_DIRECTORY);
// QFileInfo is outside loop, because it is faster this way
QFileInfo fileInfo;
if (directory.exists(dotGit)) {
fileInfo.setFile(directory, dotGit);
if (fileInfo.isFile())
return directory.absolutePath();
else if (directory.exists(QLatin1String(".git/config")))
return directory.absolutePath();
}
QString GitClient::findGitDirForRepository(const QString &repositoryDir) const
static QHash<QString, QString> repoDirCache;
QString &res = repoDirCache[repositoryDir];
if (!res.isEmpty())
return res;
QByteArray outputText;
QStringList arguments;
arguments << QLatin1String("rev-parse") << QLatin1String("--git-dir");
fullySynchronousGit(repositoryDir, arguments, &outputText, 0, false);
res = QString::fromLocal8Bit(outputText.trimmed());
if (!QDir(res).isAbsolute())
res.prepend(repositoryDir + QLatin1Char('/'));
return res;
VcsBase::VcsBaseEditorWidget *GitClient::findExistingVCSEditor(const char *registerDynamicProperty,
Core::IEditor *outputEditor = locateEditor(registerDynamicProperty, dynamicPropertyValue);
Core::EditorManager::activateEditor(outputEditor, Core::EditorManager::ModeSwitch);
rc = VcsBase::VcsBaseEditorWidget::getVcsBaseEditor(outputEditor);
DiffEditor::DiffEditorEditable *GitClient::findExistingDiffEditor(const char *registerDynamicProperty,
const QString &dynamicPropertyValue) const
{
Core::IEditor *outputEditor = locateEditor(registerDynamicProperty, dynamicPropertyValue);
if (!outputEditor)
return 0;
// Exists already
Core::EditorManager::activateEditor(outputEditor, Core::EditorManager::ModeSwitch);
outputEditor->createNew(m_msgWait);
return qobject_cast<DiffEditor::DiffEditorEditable *>(outputEditor);
/* Create an editor associated to VCS output of a source file/directory
* (using the file's codec). Makes use of a dynamic property to find an
* existing instance and to reuse it (in case, say, 'git diff foo' is
* already open). */
VcsBase::VcsBaseEditorWidget *GitClient::createVcsEditor(const Core::Id &id,
QString title,
// Source file or directory
const QString &source,
CodecType codecType,
// Dynamic property and value to identify that editor
const char *registerDynamicProperty,
const QString &dynamicPropertyValue,
QWidget *configWidget) const
QTC_CHECK(!findExistingVCSEditor(registerDynamicProperty, dynamicPropertyValue));
// Create new, set wait message, set up with source and codec
Core::IEditor *outputEditor = Core::EditorManager::openEditorWithContents(id, &title, m_msgWait);
outputEditor->document()->setProperty(registerDynamicProperty, dynamicPropertyValue);
rc = VcsBase::VcsBaseEditorWidget::getVcsBaseEditor(outputEditor);
connect(rc, SIGNAL(annotateRevisionRequested(QString,QString,int)),
this, SLOT(slotBlameRevisionRequested(QString,QString,int)));
QTC_ASSERT(rc, return 0);
rc->setSource(source);
if (codecType == CodecSource) {
rc->setCodec(getSourceCodec(source));
} else if (codecType == CodecLogOutput) {
QString encodingName = readConfigValue(source, QLatin1String("i18n.logOutputEncoding"));
if (encodingName.isEmpty())
encodingName = QLatin1String("utf-8");
rc->setCodec(QTextCodec::codecForName(encodingName.toLocal8Bit()));
}
rc->setForceReadOnly(true);
Core::EditorManager::activateEditor(outputEditor, Core::EditorManager::ModeSwitch);
if (configWidget)
rc->setConfigurationWidget(configWidget);

Friedemann Kleint
committed
void GitClient::diff(const QString &workingDirectory,
const QStringList &diffArgs,
const QStringList &unstagedFileNames,
const QStringList &stagedFileNames)
if (settings()->boolValue(GitSettings::useDiffEditorKey)) {
const Core::Id editorId = DiffEditor::Constants::DIFF_EDITOR_ID;
QString title = tr("Git Diff");
DiffEditor::DiffEditorEditable *editorEditable = findExistingDiffEditor("originalFileName", workingDirectory);
if (!editorEditable) {
editorEditable = qobject_cast<DiffEditor::DiffEditorEditable *>(
Core::EditorManager::openEditorWithContents(editorId, &title, m_msgWait));
editorEditable->document()->setProperty("originalFileName", workingDirectory);
Core::EditorManager::activateEditor(editorEditable, Core::EditorManager::ModeSwitch); // should probably go outside this block
int timeout = settings()->intValue(GitSettings::timeoutKey);
GitDiffHandler *handler = new GitDiffHandler(editorEditable, gitBinaryPath(), workingDirectory, processEnvironment(), timeout);
if (unstagedFileNames.empty() && stagedFileNames.empty()) {
// local repository diff
handler->diffRepository();
} else if (!stagedFileNames.empty()) {
// diff of selected files only with --cached option, used in commit editor
handler->diffFiles(stagedFileNames, unstagedFileNames);
// current project diff
handler->diffProjects(unstagedFileNames);
} else {
const QString binary = settings()->stringValue(GitSettings::binaryPathKey);
const Core::Id editorId = Git::Constants::GIT_DIFF_EDITOR_ID;
const QString title = tr("Git Diff");
VcsBase::VcsBaseEditorWidget *editor = findExistingVCSEditor("originalFileName", workingDirectory);
if (!editor) {
GitCommitDiffArgumentsWidget *argWidget =
new GitCommitDiffArgumentsWidget(this, workingDirectory, diffArgs,
unstagedFileNames, stagedFileNames);
editor = createVcsEditor(editorId, title,
workingDirectory, CodecSource, "originalFileName", workingDirectory, argWidget);
connect(editor, SIGNAL(diffChunkReverted(VcsBase::DiffChunk)), argWidget, SLOT(executeCommand()));
834
835
836
837
838
839
840
841
842
843
844
845
846
847
848
849
850
851
852
853
854
855
856
857
858
859
860
861
862
863
864
865
866
867
868
869
870
GitCommitDiffArgumentsWidget *argWidget = qobject_cast<GitCommitDiffArgumentsWidget *>(editor->configurationWidget());
QStringList userDiffArgs = argWidget->arguments();
editor->setDiffBaseDirectory(workingDirectory);
// Create a batch of 2 commands to be run after each other in case
// we have a mixture of staged/unstaged files as is the case
// when using the submit dialog.
VcsBase::Command *command = createCommand(workingDirectory, editor);
// Directory diff?
QStringList cmdArgs;
cmdArgs << QLatin1String("diff") << QLatin1String(noColorOption);
int timeout = settings()->intValue(GitSettings::timeoutKey);
if (unstagedFileNames.empty() && stagedFileNames.empty()) {
QStringList arguments(cmdArgs);
arguments << userDiffArgs;
outputWindow()->appendCommand(workingDirectory, binary, arguments);
command->addJob(arguments, timeout);
} else {
// Files diff.
if (!unstagedFileNames.empty()) {
QStringList arguments(cmdArgs);
arguments << userDiffArgs;
arguments << QLatin1String("--") << unstagedFileNames;
outputWindow()->appendCommand(workingDirectory, binary, arguments);
command->addJob(arguments, timeout);
}
if (!stagedFileNames.empty()) {
QStringList arguments(cmdArgs);
arguments << userDiffArgs;
arguments << QLatin1String("--cached") << diffArgs << QLatin1String("--") << stagedFileNames;
outputWindow()->appendCommand(workingDirectory, binary, arguments);
command->addJob(arguments, timeout);
}

Friedemann Kleint
committed
void GitClient::diff(const QString &workingDirectory,
const QStringList &diffArgs,
const QString &fileName)
if (settings()->boolValue(GitSettings::useDiffEditorKey)) {
const Core::Id editorId = DiffEditor::Constants::DIFF_EDITOR_ID;
QString title = tr("Git Diff \"%1\"").arg(fileName);
const QString sourceFile = VcsBase::VcsBaseEditorWidget::getSource(workingDirectory, fileName);
DiffEditor::DiffEditorEditable *editorEditable = findExistingDiffEditor("originalFileName", sourceFile);
if (!editorEditable) {
editorEditable = qobject_cast<DiffEditor::DiffEditorEditable *>(
Core::EditorManager::openEditorWithContents(editorId, &title, m_msgWait));
editorEditable->document()->setProperty("originalFileName", sourceFile);
Core::EditorManager::activateEditor(editorEditable, Core::EditorManager::ModeSwitch);
}
if (!fileName.isEmpty()) {
int timeout = settings()->intValue(GitSettings::timeoutKey);
GitDiffHandler *handler = new GitDiffHandler(editorEditable, gitBinaryPath(), workingDirectory, processEnvironment(), timeout);
handler->diffFile(fileName);
}
} else {
const Core::Id editorId = Git::Constants::GIT_DIFF_EDITOR_ID;
const QString title = tr("Git Diff \"%1\"").arg(fileName);
const QString sourceFile = VcsBase::VcsBaseEditorWidget::getSource(workingDirectory, fileName);
VcsBase::VcsBaseEditorWidget *editor = findExistingVCSEditor("originalFileName", sourceFile);
if (!editor) {
GitFileDiffArgumentsWidget *argWidget =
new GitFileDiffArgumentsWidget(this, workingDirectory, diffArgs, fileName);
editor = createVcsEditor(editorId, title, sourceFile, CodecSource, "originalFileName", sourceFile, argWidget);
connect(editor, SIGNAL(diffChunkReverted(VcsBase::DiffChunk)), argWidget, SLOT(executeCommand()));
}
editor->setDiffBaseDirectory(workingDirectory);
GitFileDiffArgumentsWidget *argWidget = qobject_cast<GitFileDiffArgumentsWidget *>(editor->configurationWidget());
QStringList userDiffArgs = argWidget->arguments();
QStringList cmdArgs;
cmdArgs << QLatin1String("diff") << QLatin1String(noColorOption)
<< userDiffArgs;
if (!fileName.isEmpty())
cmdArgs << QLatin1String("--") << fileName;
executeGit(workingDirectory, cmdArgs, editor);
}
void GitClient::diffBranch(const QString &workingDirectory,
const QStringList &diffArgs,
const QString &branchName)
{
const QString title = tr("Git Diff Branch \"%1\"").arg(branchName);
const QString sourceFile = VcsBase::VcsBaseEditorWidget::getSource(workingDirectory, QStringList());
VcsBase::VcsBaseEditorWidget *editor = findExistingVCSEditor("BranchName", branchName);
editor = createVcsEditor(editorId, title, sourceFile, CodecSource, "BranchName", branchName,
new GitBranchDiffArgumentsWidget(this, workingDirectory,
diffArgs, branchName));
editor->setDiffBaseDirectory(workingDirectory);
GitBranchDiffArgumentsWidget *argWidget = qobject_cast<GitBranchDiffArgumentsWidget *>(editor->configurationWidget());
QStringList userDiffArgs = argWidget->arguments();
QStringList cmdArgs;
cmdArgs << QLatin1String("diff") << QLatin1String(noColorOption)
<< userDiffArgs << branchName;
executeGit(workingDirectory, cmdArgs, editor);
void GitClient::merge(const QString &workingDirectory, const QStringList &unmergedFileNames)
{
MergeTool *mergeTool = new MergeTool(this);
if (!mergeTool->start(workingDirectory, unmergedFileNames))
delete mergeTool;
}

Friedemann Kleint
committed
// @TODO: Use "--no-color" once it is supported
QStringList statusArgs(QLatin1String("status"));
statusArgs << QLatin1String("-u");
outwin->setRepository(workingDirectory);
VcsBase::Command *command = executeGit(workingDirectory, statusArgs, 0, true);
connect(command, SIGNAL(finished(bool,int,QVariant)), outwin, SLOT(clearRepository()),
Qt::QueuedConnection);
void GitClient::log(const QString &workingDirectory, const QStringList &fileNames,
bool enableAnnotationContextMenu, const QStringList &args)
const QString msgArg = fileNames.empty() ? workingDirectory :
fileNames.join(QLatin1String(", "));
const QString title = tr("Git Log \"%1\"").arg(msgArg);
const Core::Id editorId = Git::Constants::GIT_LOG_EDITOR_ID;
const QString sourceFile = VcsBase::VcsBaseEditorWidget::getSource(workingDirectory, fileNames);
VcsBase::VcsBaseEditorWidget *editor = findExistingVCSEditor("logFileName", sourceFile);
editor = createVcsEditor(editorId, title, sourceFile, CodecLogOutput, "logFileName", sourceFile,
new GitLogArgumentsWidget(this, workingDirectory,
enableAnnotationContextMenu,
args, fileNames));
editor->setFileLogAnnotateEnabled(enableAnnotationContextMenu);

Friedemann Kleint
committed
QStringList arguments;
arguments << QLatin1String("log") << QLatin1String(noColorOption)
<< QLatin1String(decorateOption);
int logCount = settings()->intValue(GitSettings::logCountKey);
if (logCount > 0)
arguments << QLatin1String("-n") << QString::number(logCount);
GitLogArgumentsWidget *argWidget = qobject_cast<GitLogArgumentsWidget *>(editor->configurationWidget());
QStringList userArgs = argWidget->arguments();
arguments.append(userArgs);
if (!fileNames.isEmpty())
arguments << QLatin1String("--") << fileNames;