VCS[git]: Add 'Revert this chunk' context menu option to diff view.

Implement in git. Add infrastructure to revert single chhunks
by using patch -R. Currently only implemented in git since
only that has functionality to re-run diff.

Rubber-stamped-by: hunger <tobias.hunger@nokia.com>
This commit is contained in:
Friedemann Kleint
2011-03-24 15:44:39 +01:00
parent fbe9925d8c
commit 491a27163a
10 changed files with 251 additions and 21 deletions

View File

@@ -36,6 +36,8 @@
#include "baseannotationhighlighter.h"
#include "vcsbasetextdocument.h"
#include "vcsbaseconstants.h"
#include "vcsbaseoutputwindow.h"
#include "vcsbaseplugin.h"
#include <coreplugin/editormanager/editormanager.h>
#include <coreplugin/ifile.h>
@@ -53,6 +55,7 @@
#include <QtCore/QDebug>
#include <QtCore/QFileInfo>
#include <QtCore/QFile>
#include <QtCore/QProcess>
#include <QtCore/QRegExp>
#include <QtCore/QSet>
@@ -69,9 +72,27 @@
#include <QtGui/QToolBar>
#include <QtGui/QClipboard>
#include <QtGui/QApplication>
#include <QtGui/QMessageBox>
namespace VCSBase {
bool DiffChunk::isValid() const
{
return !fileName.isEmpty() && !chunk.isEmpty();
}
QByteArray DiffChunk::asPatch() const
{
const QByteArray fileNameBA = QFile::encodeName(fileName);
QByteArray rc = "--- ";
rc += fileNameBA;
rc += "\n+++ ";
rc += fileNameBA;
rc += '\n';
rc += chunk;
return rc;
}
// VCSBaseEditor: An editor with no support for duplicates.
// Creates a browse combo in the toolbar for diff output.
// It also mirrors the signals of the VCSBaseEditor since the editor
@@ -161,6 +182,7 @@ struct VCSBaseEditorWidgetPrivate
bool m_fileLogAnnotateEnabled;
TextEditor::BaseTextEditor *m_editor;
QWidget *m_configurationWidget;
bool m_revertChunkEnabled;
};
VCSBaseEditorWidgetPrivate::VCSBaseEditorWidgetPrivate(const VCSBaseEditorParameters *type) :
@@ -170,7 +192,8 @@ VCSBaseEditorWidgetPrivate::VCSBaseEditorWidgetPrivate(const VCSBaseEditorParame
m_copyRevisionTextFormat(VCSBaseEditorWidget::tr("Copy \"%1\"")),
m_fileLogAnnotateEnabled(false),
m_editor(0),
m_configurationWidget(0)
m_configurationWidget(0),
m_revertChunkEnabled(false)
{
}
@@ -444,7 +467,9 @@ void VCSBaseEditorWidget::contextMenuEvent(QContextMenuEvent *e)
{
QMenu *menu = createStandardContextMenu();
// 'click on change-interaction'
if (d->m_parameters->type == LogOutput || d->m_parameters->type == AnnotateOutput) {
switch (d->m_parameters->type) {
case LogOutput:
case AnnotateOutput:
d->m_currentChange = changeUnderCursor(cursorForPosition(e->pos()));
if (!d->m_currentChange.isEmpty()) {
switch (d->m_parameters->type) {
@@ -471,6 +496,18 @@ void VCSBaseEditorWidget::contextMenuEvent(QContextMenuEvent *e)
break;
} // switch type
} // has current change
break;
case DiffOutput: {
menu->addSeparator();
QAction *revertAction = menu->addAction(tr("Revert Chunk..."));
const DiffChunk chunk = diffChunk(cursorForPosition(e->pos()));
revertAction->setEnabled(canRevertDiffChunk(chunk));
revertAction->setData(qVariantFromValue(chunk));
connect(revertAction, SIGNAL(triggered()), this, SLOT(slotRevertDiffChunk()));
}
break;
default:
break;
}
menu->exec(e->globalPos());
delete menu;
@@ -643,6 +680,40 @@ void VCSBaseEditorWidget::jumpToChangeFromDiff(QTextCursor cursor)
editor->gotoLine(chunkStart + lineCount);
}
// cut out chunk and determine file name.
DiffChunk VCSBaseEditorWidget::diffChunk(QTextCursor cursor) const
{
QTC_ASSERT(d->m_parameters->type == DiffOutput, return DiffChunk(); )
DiffChunk rc;
// Search back for start of chunk.
QTextBlock block = cursor.block();
int chunkStart = 0;
for ( ; block.isValid() ; block = block.previous()) {
if (checkChunkLine(block.text(), &chunkStart)) {
break;
}
}
if (!chunkStart || !block.isValid())
return rc;
rc.fileName = fileNameFromDiffSpecification(block);
if (rc.fileName.isEmpty())
return rc;
// Concatenate chunk and convert
QString unicode = block.text();
for (block = block.next() ; block.isValid() ; block = block.next()) {
const QString line = block.text();
if (checkChunkLine(line, &chunkStart)) {
break;
} else {
unicode += line;
unicode += QLatin1Char('\n');
}
}
const QTextCodec *cd = textCodec();
rc.chunk = cd ? cd->fromUnicode(unicode) : unicode.toLocal8Bit();
return rc;
}
void VCSBaseEditorWidget::setPlainTextData(const QByteArray &data)
{
if (data.size() > Core::EditorManager::maxTextFileSize()) {
@@ -901,6 +972,46 @@ QStringList VCSBaseEditorWidget::annotationPreviousVersions(const QString &) con
return QStringList();
}
bool VCSBaseEditorWidget::isRevertDiffChunkEnabled() const
{
return d->m_revertChunkEnabled;
}
void VCSBaseEditorWidget::setRevertDiffChunkEnabled(bool e)
{
d->m_revertChunkEnabled = e;
}
bool VCSBaseEditorWidget::canRevertDiffChunk(const DiffChunk &dc) const
{
if (!isRevertDiffChunkEnabled() || !dc.isValid())
return false;
const QFileInfo fi(dc.fileName);
// Default implementation using patch.exe relies on absolute paths.
return fi.isFile() && fi.isAbsolute() && fi.isWritable();
}
// Default implementation of revert: Revert a chunk by piping it into patch
// with '-R', assuming we got absolute paths from the VCS plugins.
bool VCSBaseEditorWidget::revertDiffChunk(const DiffChunk &dc) const
{
return VCSBasePlugin::runPatch(dc.asPatch(), QString(), 0, true);
}
void VCSBaseEditorWidget::slotRevertDiffChunk()
{
const QAction *a = qobject_cast<QAction *>(sender());
QTC_ASSERT(a, return ; )
const DiffChunk chunk = qvariant_cast<DiffChunk>(a->data());
if (QMessageBox::No == QMessageBox::question(this, tr("Revert Chunk"),
tr("Would you like to revert the chunk?"),
QMessageBox::Yes|QMessageBox::No))
return;
if (revertDiffChunk(chunk))
emit diffChunkReverted(chunk);
}
} // namespace VCSBase
#include "vcsbaseeditor.moc"