Commit a7a7d735 authored by Friedemann Kleint's avatar Friedemann Kleint
Browse files

VCS[cvs,subversion]: Add diff options and enable reverting chunks.

Create VCSBaseEditorParameterWidget as a base class for setting
the diff arguments lists and wire it up to trigger a re-run
of diff on reverting. Enable reverting of chunks for cvs,
subversion.
parent cc35cad5
......@@ -43,9 +43,11 @@
#include <vcsbase/vcsbaseeditor.h>
#include <vcsbase/basevcssubmiteditorfactory.h>
#include <vcsbase/vcsbaseoutputwindow.h>
#include <vcsbase/vcsbaseeditorparameterwidget.h>
#include <locator/commandlocator.h>
#include <utils/synchronousprocess.h>
#include <utils/parameteraction.h>
#include <utils/qtcassert.h>
#include <coreplugin/icore.h>
#include <coreplugin/coreconstants.h>
......@@ -529,22 +531,79 @@ static inline void setDiffBaseDirectory(Core::IEditor *editor, const QString &db
ve->setDiffBaseDirectory(db);
}
// Collect all parameters required for a diff to be able to associate them
// with a diff editor and re-run the diff with parameters.
struct CvsDiffParameters
{
CvsDiffParameters() : reUseEditor(false) {}
QString workingDir;
QStringList arguments;
QStringList files;
bool reUseEditor;
};
// Parameter widget controlling whitespace diff mode, associated with a parameter
// struct.
class CvsDiffParameterWidget : public VCSBase::VCSBaseEditorParameterWidget
{
Q_OBJECT
public:
explicit CvsDiffParameterWidget(const CvsDiffParameters &p, QWidget *parent = 0);
signals:
void reRunDiff(const CVS::Internal::CvsDiffParameters &);
public slots:
void triggerReRun();
private:
const CvsDiffParameters m_parameters;
};
CvsDiffParameterWidget::CvsDiffParameterWidget(const CvsDiffParameters &p, QWidget *parent) :
VCSBase::VCSBaseEditorParameterWidget(parent), m_parameters(p)
{
setBaseArguments(p.arguments);
addIgnoreWhiteSpaceButton(QLatin1String("-w"));
addIgnoreBlankLinesButton(QLatin1String("-B"));
connect(this, SIGNAL(argumentsChanged()),
this, SLOT(triggerReRun()));
}
void CvsDiffParameterWidget::triggerReRun()
{
CvsDiffParameters effectiveParameters = m_parameters;
effectiveParameters.reUseEditor = true;
effectiveParameters.arguments = arguments();
emit reRunDiff(effectiveParameters);
}
void CVSPlugin::cvsDiff(const QString &workingDir, const QStringList &files)
{
CvsDiffParameters p;
p.workingDir = workingDir;
p.files = files;
p.arguments = m_settings.cvsDiffOptions.split(QLatin1Char(' '), QString::SkipEmptyParts);
cvsDiff(p);
}
void CVSPlugin::cvsDiff(const CvsDiffParameters &p)
{
if (CVS::Constants::debug)
qDebug() << Q_FUNC_INFO << files;
const QString source = VCSBase::VCSBaseEditorWidget::getSource(workingDir, files);
QTextCodec *codec = VCSBase::VCSBaseEditorWidget::getCodec(workingDir, files);
const QString id = VCSBase::VCSBaseEditorWidget::getTitleId(workingDir, files);
qDebug() << Q_FUNC_INFO << p.files;
const QString source = VCSBase::VCSBaseEditorWidget::getSource(p.workingDir, p.files);
QTextCodec *codec = VCSBase::VCSBaseEditorWidget::getCodec(p.workingDir, p.files);
const QString id = VCSBase::VCSBaseEditorWidget::getTitleId(p.workingDir, p.files);
QStringList args(QLatin1String("diff"));
args << m_settings.cvsDiffOptions;
args.append(files);
args.append(p.arguments);
args.append(p.files);
// CVS returns the diff exit code (1 if files differ), which is
// undistinguishable from a "file not found" error, unfortunately.
const CVSResponse response =
runCVS(workingDir, args, m_settings.timeOutMS(), 0, codec);
runCVS(p.workingDir, args, m_settings.timeOutMS(), 0, codec);
switch (response.result) {
case CVSResponse::NonNullExitCode:
case CVSResponse::Ok:
......@@ -558,20 +617,31 @@ void CVSPlugin::cvsDiff(const QString &workingDir, const QStringList &files)
output = tr("The files do not differ.");
// diff of a single file? re-use an existing view if possible to support
// the common usage pattern of continuously changing and diffing a file
if (files.count() == 1) {
if (p.files.count() == 1 || p.reUseEditor) {
// Show in the same editor if diff has been executed before
if (Core::IEditor *editor = locateEditor("originalFileName", id)) {
editor->createNew(output);
Core::EditorManager::instance()->activateEditor(editor, Core::EditorManager::ModeSwitch);
setDiffBaseDirectory(editor, workingDir);
setDiffBaseDirectory(editor, p.workingDir);
return;
}
}
const QString title = QString::fromLatin1("cvs diff %1").arg(id);
Core::IEditor *editor = showOutputInEditor(title, output, VCSBase::DiffOutput, source, codec);
if (files.count() == 1)
editor->setProperty("originalFileName", id);
setDiffBaseDirectory(editor, workingDir);
editor->setProperty("originalFileName", id);
setDiffBaseDirectory(editor, p.workingDir);
CVSEditor *diffEditorWidget = qobject_cast<CVSEditor*>(editor->widget());
QTC_ASSERT(diffEditorWidget, return ; )
// Wire up the parameter widget to trigger a re-run on
// parameter change and 'revert' from inside the diff editor.
diffEditorWidget->setRevertDiffChunkEnabled(true);
CvsDiffParameterWidget *pw = new CvsDiffParameterWidget(p);
connect(pw, SIGNAL(reRunDiff(CVS::Internal::CvsDiffParameters)),
this, SLOT(cvsDiff(CVS::Internal::CvsDiffParameters)));
connect(diffEditorWidget, SIGNAL(diffChunkReverted(VCSBase::DiffChunk)),
pw, SLOT(triggerReRun()));
diffEditorWidget->setConfigurationWidget(pw);
}
CVSSubmitEditor *CVSPlugin::openCVSSubmitEditor(const QString &fileName)
......@@ -1339,3 +1409,5 @@ CVSControl *CVSPlugin::cvsVersionControl() const
}
}
Q_EXPORT_PLUGIN(CVS::Internal::CVSPlugin)
#include "cvsplugin.moc"
......@@ -64,7 +64,7 @@ namespace Locator {
namespace CVS {
namespace Internal {
struct CvsDiffParameters;
class CVSSubmitEditor;
class CVSControl;
......@@ -132,6 +132,7 @@ private slots:
void editCurrentFile();
void uneditCurrentFile();
void uneditCurrentRepository();
void cvsDiff(const CVS::Internal::CvsDiffParameters &p);
protected:
virtual void updateActions(VCSBase::VCSBasePlugin::ActionState);
......
......@@ -45,6 +45,7 @@
#include <vcsbase/vcsbaseeditor.h>
#include <vcsbase/basevcssubmiteditorfactory.h>
#include <vcsbase/vcsbaseoutputwindow.h>
#include <vcsbase/vcsbaseeditorparameterwidget.h>
#include <utils/synchronousprocess.h>
#include <utils/parameteraction.h>
......@@ -80,7 +81,8 @@
#include <QtXml/QXmlStreamReader>
#include <limits.h>
using namespace Subversion::Internal;
namespace Subversion {
namespace Internal {
static const char * const CMD_ID_SUBVERSION_MENU = "Subversion.Menu";
static const char * const CMD_ID_ADD = "Subversion.Add";
......@@ -534,6 +536,55 @@ void SubversionPlugin::diffCommitFiles(const QStringList &files)
svnDiff(m_commitRepository, files);
}
// Collect all parameters required for a diff to be able to associate them
// with a diff editor and re-run the diff with parameters.
struct SubversionDiffParameters
{
SubversionDiffParameters() : reUseEditor(false) {}
QString workingDir;
QStringList arguments;
QStringList files;
QString diffName;
bool reUseEditor;
};
// Parameter widget controlling whitespace diff mode, associated with a parameter
class SubversionDiffParameterWidget : public VCSBase::VCSBaseEditorParameterWidget
{
Q_OBJECT
public:
explicit SubversionDiffParameterWidget(const SubversionDiffParameters &p, QWidget *parent = 0);
signals:
void reRunDiff(const Subversion::Internal::SubversionDiffParameters &);
private slots:
void triggerReRun();
private:
const SubversionDiffParameters m_parameters;
};
SubversionDiffParameterWidget::SubversionDiffParameterWidget(const SubversionDiffParameters &p, QWidget *parent) :
VCSBase::VCSBaseEditorParameterWidget(parent), m_parameters(p)
{
setBaseArguments(p.arguments);
addIgnoreWhiteSpaceButton(QString(QLatin1Char('w')));
connect(this, SIGNAL(argumentsChanged()), this, SLOT(triggerReRun()));
}
void SubversionDiffParameterWidget::triggerReRun()
{
SubversionDiffParameters effectiveParameters = m_parameters;
effectiveParameters.reUseEditor = true;
// Subversion wants" -x -<ext-args>", default being -u
const QStringList a = arguments();
if (!a.isEmpty())
effectiveParameters.arguments << QLatin1String("-x") << (QLatin1String("-u") + a.join(QString()));
emit reRunDiff(effectiveParameters);
}
static inline void setDiffBaseDirectory(Core::IEditor *editor, const QString &db)
{
if (VCSBase::VCSBaseEditorWidget *ve = qobject_cast<VCSBase::VCSBaseEditorWidget*>(editor->widget()))
......@@ -541,39 +592,60 @@ static inline void setDiffBaseDirectory(Core::IEditor *editor, const QString &db
}
void SubversionPlugin::svnDiff(const QString &workingDir, const QStringList &files, QString diffname)
{
SubversionDiffParameters p;
p.workingDir = workingDir;
p.files = files;
p.diffName = diffname;
svnDiff(p);
}
void SubversionPlugin::svnDiff(const Subversion::Internal::SubversionDiffParameters &p)
{
if (Subversion::Constants::debug)
qDebug() << Q_FUNC_INFO << files << diffname;
const QString source = VCSBase::VCSBaseEditorWidget::getSource(workingDir, files);
qDebug() << Q_FUNC_INFO << p.files << p.diffName;
const QString source = VCSBase::VCSBaseEditorWidget::getSource(p.workingDir, p.files);
QTextCodec *codec = source.isEmpty() ? static_cast<QTextCodec *>(0) : VCSBase::VCSBaseEditorWidget::getCodec(source);
if (files.count() == 1 && diffname.isEmpty())
diffname = QFileInfo(files.front()).fileName();
const QString diffName = p.files.count() == 1 && p.diffName.isEmpty() ?
QFileInfo(p.files.front()).fileName() : p.diffName;
QStringList args(QLatin1String("diff"));
args << files;
args.append(p.arguments);
args << p.files;
const SubversionResponse response =
runSvn(workingDir, args, m_settings.timeOutMS(), 0, codec);
runSvn(p.workingDir, args, m_settings.timeOutMS(), 0, codec);
if (response.error)
return;
// diff of a single file? re-use an existing view if possible to support
// the common usage pattern of continuously changing and diffing a file
if (files.count() == 1) {
if (p.files.count() == 1 || p.reUseEditor) {
// Show in the same editor if diff has been executed before
if (Core::IEditor *editor = locateEditor("originalFileName", files.front())) {
if (Core::IEditor *editor = locateEditor("originalFileName", p.files.front())) {
editor->createNew(response.stdOut);
Core::EditorManager::instance()->activateEditor(editor, Core::EditorManager::ModeSwitch);
setDiffBaseDirectory(editor, workingDir);
setDiffBaseDirectory(editor, p.workingDir);
return;
}
}
const QString title = QString::fromLatin1("svn diff %1").arg(diffname);
const QString title = QString::fromLatin1("svn diff %1").arg(diffName);
Core::IEditor *editor = showOutputInEditor(title, response.stdOut, VCSBase::DiffOutput, source, codec);
setDiffBaseDirectory(editor, workingDir);
if (files.count() == 1)
editor->setProperty("originalFileName", files.front());
setDiffBaseDirectory(editor, p.workingDir);
editor->setProperty("originalFileName", p.files.front());
SubversionEditor *diffEditorWidget = qobject_cast<SubversionEditor *>(editor->widget());
QTC_ASSERT(diffEditorWidget, return ; )
// Wire up the parameter widget to trigger a re-run on
// parameter change and 'revert' from inside the diff editor.
diffEditorWidget->setRevertDiffChunkEnabled(true);
SubversionDiffParameterWidget *pw = new SubversionDiffParameterWidget(p);
connect(pw, SIGNAL(reRunDiff(Subversion::Internal::SubversionDiffParameters)),
this, SLOT(svnDiff(Subversion::Internal::SubversionDiffParameters)));
connect(diffEditorWidget, SIGNAL(diffChunkReverted(VCSBase::DiffChunk)),
pw, SLOT(triggerReRun()));
diffEditorWidget->setConfigurationWidget(pw);
}
SubversionSubmitEditor *SubversionPlugin::openSubversionSubmitEditor(const QString &fileName)
......@@ -1350,4 +1422,9 @@ SubversionControl *SubversionPlugin::subVersionControl() const
return static_cast<SubversionControl *>(versionControl());
}
Q_EXPORT_PLUGIN(SubversionPlugin)
} // Internal
} // Subversion
Q_EXPORT_PLUGIN(Subversion::Internal::SubversionPlugin)
#include "subversionplugin.moc"
......@@ -66,6 +66,7 @@ namespace Internal {
class SubversionSubmitEditor;
class SubversionControl;
struct SubversionDiffParameters;
struct SubversionResponse
{
......@@ -113,6 +114,7 @@ public:
public slots:
void vcsAnnotate(const QString &workingDir, const QString &file,
const QString &revision = QString(), int lineNumber = -1);
void svnDiff(const Subversion::Internal::SubversionDiffParameters &p);
private slots:
void addCurrentFile();
......
......@@ -30,7 +30,8 @@ HEADERS += vcsbase_global.h \
vcsbaseoptionspage.h \
vcsjobrunner.h \
vcsbaseclient.h \
vcsbaseclientsettings.h
vcsbaseclientsettings.h \
vcsbaseeditorparameterwidget.h
SOURCES += vcsplugin.cpp \
vcsbaseplugin.cpp \
......@@ -57,7 +58,8 @@ SOURCES += vcsplugin.cpp \
vcsbaseoptionspage.cpp \
vcsjobrunner.cpp \
vcsbaseclient.cpp \
vcsbaseclientsettings.cpp
vcsbaseclientsettings.cpp \
vcsbaseeditorparameterwidget.cpp
RESOURCES += vcsbase.qrc
......
/**************************************************************************
**
** This file is part of Qt Creator
**
** Copyright (c) 2011 Nokia Corporation and/or its subsidiary(-ies).
**
** Contact: Nokia Corporation (qt-info@nokia.com)
**
** No Commercial Usage
**
** This file contains pre-release code and may not be distributed.
** You may use this file in accordance with the terms and conditions
** contained in the Technology Preview License Agreement accompanying
** this package.
**
** 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, Nokia gives you certain additional
** rights. These rights are described in the Nokia Qt LGPL Exception
** version 1.1, included in the file LGPL_EXCEPTION.txt in this package.
**
** If you have questions regarding the use of this file, please contact
** Nokia at qt-info@nokia.com.
**
**************************************************************************/
#include "vcsbaseeditorparameterwidget.h"
#include <QtGui/QToolButton>
#include <QtGui/QHBoxLayout>
#include <QtCore/QDebug>
namespace VCSBase {
namespace Internal {
/*!
\class VCSBase::Internal::VCSBaseEditorParameterToggleButton
\brief ToggleButton to be inserted into VCSBase::VCSBaseEditorParameterWidget
Inserts a single option into the argument list depending on whether it is checked.
*/
class VCSBaseEditorParameterToggleButton : public QToolButton
{
Q_OBJECT
public:
explicit VCSBaseEditorParameterToggleButton(QWidget *parent = 0);
void applyToArguments(QStringList *w) const;
void setFromArguments(const QStringList &a);
void setOption(const QString &o) { m_option = o; }
QString option() const { return m_option; }
signals:
void changed();
private:
QString m_option;
};
VCSBaseEditorParameterToggleButton::VCSBaseEditorParameterToggleButton(QWidget *parent) :
QToolButton(parent)
{
setCheckable(true);
connect(this, SIGNAL(toggled(bool)), this, SIGNAL(changed()));
}
void VCSBaseEditorParameterToggleButton::applyToArguments(QStringList *a) const
{
if (isChecked()) {
if (!a->contains(m_option))
a->append(m_option);
} else {
a->removeAll(m_option);
}
}
void VCSBaseEditorParameterToggleButton::setFromArguments(const QStringList &a)
{
setChecked(a.contains(m_option));
}
} // namespace Internal
class VCSBaseEditorParameterWidgetPrivate
{
public:
VCSBaseEditorParameterWidgetPrivate() : m_layout(0) {}
QStringList m_baseArguments;
QHBoxLayout *m_layout;
QList<Internal::VCSBaseEditorParameterToggleButton *> m_toggles;
};
/*!
\class VCSBase::VCSBaseEditorParameterWidget
\brief A toolbar-like widget for use with VCSBase::VCSBaseEditor::setConfigurationWidget()
influencing for example the generation of VCS diff output.
The widget maintains a list of command line arguments (starting from baseArguments())
which are set according to the state of the inside widgets. A change signal is provided
that should trigger the rerun of the VCS operation.
*/
VCSBaseEditorParameterWidget::VCSBaseEditorParameterWidget(QWidget *parent) :
QWidget(parent), d(new VCSBaseEditorParameterWidgetPrivate)
{
d->m_layout = new QHBoxLayout(this);
d->m_layout->setContentsMargins(3, 0, 3, 0);
d->m_layout->setSpacing(2);
}
VCSBaseEditorParameterWidget::~VCSBaseEditorParameterWidget()
{
}
QStringList VCSBaseEditorParameterWidget::baseArguments() const
{
return d->m_baseArguments;
}
void VCSBaseEditorParameterWidget::setBaseArguments(const QStringList &b)
{
d->m_baseArguments = b;
}
QStringList VCSBaseEditorParameterWidget::arguments() const
{
// Compile effective arguments
QStringList args = d->m_baseArguments;
foreach (const Internal::VCSBaseEditorParameterToggleButton *tb, d->m_toggles)
tb->applyToArguments(&args);
return args;
}
void VCSBaseEditorParameterWidget::addToggleButton(const QString &option,
const QString &label,
const QString &toolTip)
{
Internal::VCSBaseEditorParameterToggleButton *tb = new Internal::VCSBaseEditorParameterToggleButton;
tb->setOption(option);
tb->setText(label);
tb->setToolTip(toolTip);
connect(tb, SIGNAL(changed()), this, SIGNAL(argumentsChanged()));
d->m_layout->addWidget(tb);
d->m_toggles.append(tb);
}
void VCSBaseEditorParameterWidget::addIgnoreWhiteSpaceButton(const QString &option)
{
addToggleButton(option, msgIgnoreWhiteSpaceLabel(), msgIgnoreWhiteSpaceToolTip());
}
void VCSBaseEditorParameterWidget::addIgnoreBlankLinesButton(const QString &option)
{
addToggleButton(option, msgIgnoreBlankLinesLabel(), msgIgnoreBlankLinesToolTip());
}
QString VCSBaseEditorParameterWidget::msgIgnoreWhiteSpaceLabel()
{
return tr("Ignore whitespace");
}
QString VCSBaseEditorParameterWidget::msgIgnoreWhiteSpaceToolTip()
{
return tr("Ignore whitespace only changes");
}
QString VCSBaseEditorParameterWidget::msgIgnoreBlankLinesLabel()
{
return tr("Ignore blank lines ");
}
QString VCSBaseEditorParameterWidget::msgIgnoreBlankLinesToolTip()
{
return tr("Ignore changes in blank lines");
}
} // namespace VCSBase
#include "vcsbaseeditorparameterwidget.moc"
/**************************************************************************
**
** This file is part of Qt Creator
**
** Copyright (c) 2011 Nokia Corporation and/or its subsidiary(-ies).
**
** Contact: Nokia Corporation (qt-info@nokia.com)
**
** No Commercial Usage
**
** This file contains pre-release code and may not be distributed.
** You may use this file in accordance with the terms and conditions
** contained in the Technology Preview License Agreement accompanying
** this package.
**
** 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, Nokia gives you certain additional
** rights. These rights are described in the Nokia Qt LGPL Exception
** version 1.1, included in the file LGPL_EXCEPTION.txt in this package.
**
** If you have questions regarding the use of this file, please contact
** Nokia at qt-info@nokia.com.
**
**************************************************************************/
#ifndef VCSBASE_VCSBASEEDITORPARAMETERWIDGET_H
#define VCSBASE_VCSBASEEDITORPARAMETERWIDGET_H
#include "vcsbase_global.h"
#include <QtGui/QWidget>
#include <QtCore/QStringList>
namespace VCSBase {
class VCSBaseEditorParameterWidgetPrivate;
// Documentation->inside.
class VCSBASE_EXPORT VCSBaseEditorParameterWidget : public QWidget
{
Q_OBJECT
public:
explicit VCSBaseEditorParameterWidget(QWidget *parent = 0);
~VCSBaseEditorParameterWidget();
QStringList baseArguments() const;
void setBaseArguments(const QStringList &);
void addToggleButton(const QString &option, const QString &am