DiffEditor: Refactor the user-facing parts

* Move all data handling into DiffEditorDocument
* Move much of the logic of how to update views into the
  DiffEditor.
* Introduce a base class for the different views on the diff
  to implement.
* Remove DiffEditorGuiController
* Make DiffEditorController smaller and merge the DiffEditorReloader
  into the class
* Simplify communication between the classes involved
* Make much of the implementation private to the plugin

Change-Id: I7ccb9df6061923bcb34cf3090d6d8331895e83c7
Reviewed-by: Orgad Shaneh <orgads@gmail.com>
Reviewed-by: Jarek Kobus <jaroslaw.kobus@theqtcompany.com>
This commit is contained in:
Tobias Hunger
2015-01-30 16:59:25 +01:00
parent 59640aa7aa
commit b2b8b867d6
28 changed files with 1306 additions and 1948 deletions

View File

@@ -31,7 +31,6 @@
#include "diffeditor.h"
#include "diffeditorconstants.h"
#include "diffeditordocument.h"
#include "diffeditorguicontroller.h"
#include "diffview.h"
#include <coreplugin/icore.h>
@@ -62,7 +61,13 @@
#include <QTextBlock>
static const char settingsGroupC[] = "DiffEditor";
static const char diffEditorTypeKeyC[] = "DiffEditorType";
static const char descriptionVisibleKeyC[] = "DescriptionVisible";
static const char horizontalScrollBarSynchronizationKeyC[] =
"HorizontalScrollBarSynchronization";
static const char contextLineCountKeyC[] = "ContextLineNumbers";
static const char ignoreWhitespaceKeyC[] = "IgnoreWhitespace";
static const char diffViewKeyC[] = "DiffEditorType";
static const char legacySettingsGroupC[] = "Git";
static const char useDiffEditorKeyC[] = "UseDiffEditor";
@@ -187,7 +192,6 @@ void DescriptionEditorWidget::highlightCurrentContents()
sel.format.setFontUnderline(true);
setExtraSelections(TextEditorWidget::OtherSelection,
QList<QTextEdit::ExtraSelection>() << sel);
}
void DescriptionEditorWidget::handleCurrentContents()
@@ -204,15 +208,23 @@ DiffEditor::DiffEditor(const QSharedPointer<DiffEditorDocument> &doc)
: m_document(doc)
, m_descriptionWidget(0)
, m_stackedWidget(0)
, m_currentViewIndex(-1)
, m_guiController(0)
, m_toolBar(0)
, m_entriesComboBox(0)
, m_toggleSyncAction(0)
, m_whitespaceButtonAction(0)
, m_contextLabelAction(0)
, m_contextSpinBoxAction(0)
, m_toggleDescriptionAction(0)
, m_reloadAction(0)
, m_diffEditorSwitcher(0)
, m_currentViewIndex(-1)
, m_currentDiffFileIndex(-1)
, m_sync(false)
, m_showDescription(true)
, m_ignoreChanges(true)
{
QTC_ASSERT(m_document, return);
setDuplicateSupported(true);
QSplitter *splitter = new Core::MiniSplitter(Qt::Vertical);
@@ -228,29 +240,23 @@ DiffEditor::DiffEditor(const QSharedPointer<DiffEditorDocument> &doc)
setWidget(splitter);
DiffEditorController *control = controller();
m_guiController = new DiffEditorGuiController(control, this);
connect(m_descriptionWidget, &DescriptionEditorWidget::requestBranchList,
control, &DiffEditorController::expandBranchesRequested);
connect(control, &DiffEditorController::cleared, this, &DiffEditor::slotCleared);
connect(control, &DiffEditorController::diffFilesChanged,
this, &DiffEditor::slotDiffFilesChanged);
connect(control, &DiffEditorController::descriptionChanged,
this, &DiffEditor::slotDescriptionChanged);
connect(control, &DiffEditorController::descriptionEnablementChanged,
this, &DiffEditor::slotDescriptionVisibilityChanged);
connect(m_guiController, &DiffEditorGuiController::descriptionVisibilityChanged,
this, &DiffEditor::slotDescriptionVisibilityChanged);
connect(m_guiController, &DiffEditorGuiController::currentDiffFileIndexChanged,
this, &DiffEditor::activateEntry);
slotDescriptionChanged(control->description());
slotDescriptionVisibilityChanged();
showDiffView(readCurrentDiffEditorSetting());
m_document.data(), &DiffEditorDocument::requestMoreInformation);
connect(m_document.data(), &DiffEditorDocument::documentChanged,
this, &DiffEditor::documentHasChanged);
connect(m_document.data(), &DiffEditorDocument::descriptionChanged,
this, &DiffEditor::updateDescription);
connect(m_document.data(), &DiffEditorDocument::aboutToReload,
this, &DiffEditor::prepareForReload);
connect(m_document.data(), &DiffEditorDocument::reloadFinished,
this, &DiffEditor::reloadHasFinished);
toolBar();
loadSettings();
updateDescription();
m_ignoreChanges = false;
}
DiffEditor::~DiffEditor()
@@ -295,8 +301,6 @@ QWidget *DiffEditor::toolBar()
if (m_toolBar)
return m_toolBar;
DiffEditorController *control = controller();
// Create
m_toolBar = createToolBar(m_views.at(0));
@@ -306,109 +310,77 @@ QWidget *DiffEditor::toolBar()
QSizePolicy policy = m_entriesComboBox->sizePolicy();
policy.setHorizontalPolicy(QSizePolicy::Expanding);
m_entriesComboBox->setSizePolicy(policy);
connect(m_entriesComboBox, static_cast<void (QComboBox::*)(int)>(&QComboBox::activated),
this, &DiffEditor::entryActivated);
connect(m_entriesComboBox, static_cast<void (QComboBox::*)(int)>(&QComboBox::currentIndexChanged),
this, &DiffEditor::setCurrentDiffFileIndex);
m_toolBar->addWidget(m_entriesComboBox);
QToolButton *whitespaceButton = new QToolButton(m_toolBar);
whitespaceButton->setText(tr("Ignore Whitespace"));
whitespaceButton->setCheckable(true);
whitespaceButton->setChecked(control->isIgnoreWhitespace());
m_whitespaceButtonAction = m_toolBar->addWidget(whitespaceButton);
m_whitespaceButton = new QToolButton(m_toolBar);
m_whitespaceButton->setText(tr("Ignore Whitespace"));
m_whitespaceButton->setCheckable(true);
m_whitespaceButton->setChecked(m_document->ignoreWhitespace());
m_whitespaceButtonAction = m_toolBar->addWidget(m_whitespaceButton);
QLabel *contextLabel = new QLabel(m_toolBar);
contextLabel->setText(tr("Context Lines:"));
contextLabel->setContentsMargins(6, 0, 6, 0);
m_contextLabelAction = m_toolBar->addWidget(contextLabel);
QSpinBox *contextSpinBox = new QSpinBox(m_toolBar);
contextSpinBox->setRange(1, 100);
contextSpinBox->setValue(control->contextLinesNumber());
contextSpinBox->setFrame(false);
contextSpinBox->setSizePolicy(QSizePolicy::Minimum,
QSizePolicy::Expanding); // Mac Qt5
m_contextSpinBoxAction = m_toolBar->addWidget(contextSpinBox);
m_contextSpinBox = new QSpinBox(m_toolBar);
m_contextSpinBox->setRange(1, 100);
m_contextSpinBox->setValue(m_document->contextLineCount());
m_contextSpinBox->setFrame(false);
m_contextSpinBox->setSizePolicy(QSizePolicy::Minimum,
QSizePolicy::Expanding); // Mac Qt5
m_contextSpinBoxAction = m_toolBar->addWidget(m_contextSpinBox);
QToolButton *toggleDescription = new QToolButton(m_toolBar);
toggleDescription->setIcon(QIcon(QLatin1String(Constants::ICON_TOP_BAR)));
toggleDescription->setCheckable(true);
toggleDescription->setChecked(m_guiController->isDescriptionVisible());
toggleDescription->setChecked(m_showDescription);
m_toggleDescriptionAction = m_toolBar->addWidget(toggleDescription);
slotDescriptionVisibilityChanged();
updateDescription();
QToolButton *reloadButton = new QToolButton(m_toolBar);
reloadButton->setIcon(QIcon(QLatin1String(Core::Constants::ICON_RELOAD_GRAY)));
reloadButton->setToolTip(tr("Reload Editor"));
m_reloadAction = m_toolBar->addWidget(reloadButton);
slotReloaderChanged();
documentStateChanged();
QToolButton *toggleSync = new QToolButton(m_toolBar);
toggleSync->setIcon(QIcon(QLatin1String(Core::Constants::ICON_LINK)));
toggleSync->setCheckable(true);
toggleSync->setChecked(m_guiController->horizontalScrollBarSynchronization());
toggleSync->setToolTip(tr("Synchronize Horizontal Scroll Bars"));
m_toolBar->addWidget(toggleSync);
m_toggleSyncAction = m_toolBar->addWidget(toggleSync);
m_diffEditorSwitcher = new QToolButton(m_toolBar);
m_toolBar->addWidget(m_diffEditorSwitcher);
updateDiffEditorSwitcher();
connect(whitespaceButton, &QToolButton::clicked,
control, &DiffEditorController::setIgnoreWhitespace);
connect(control, &DiffEditorController::ignoreWhitespaceChanged,
whitespaceButton, &QToolButton::setChecked);
connect(contextSpinBox, static_cast<void (QSpinBox::*)(int)>(&QSpinBox::valueChanged),
control, &DiffEditorController::setContextLinesNumber);
connect(control, &DiffEditorController::contextLinesNumberChanged,
contextSpinBox, &QSpinBox::setValue);
connect(toggleSync, &QAbstractButton::clicked,
m_guiController, &DiffEditorGuiController::setHorizontalScrollBarSynchronization);
connect(m_whitespaceButton, &QToolButton::clicked,
this, &DiffEditor::ignoreWhitespaceHasChanged);
connect(m_contextSpinBox, static_cast<void (QSpinBox::*)(int)>(&QSpinBox::valueChanged),
this, &DiffEditor::contextLineCountHasChanged);
connect(toggleSync, &QAbstractButton::clicked, this, &DiffEditor::toggleSync);
connect(toggleDescription, &QAbstractButton::clicked,
m_guiController, &DiffEditorGuiController::setDescriptionVisible);
this, &DiffEditor::toggleDescription);
connect(m_diffEditorSwitcher, &QAbstractButton::clicked,
this, [this]() { showDiffView(nextView()); });
connect(reloadButton, &QAbstractButton::clicked,
control, &DiffEditorController::requestReload);
connect(control, &DiffEditorController::reloaderChanged,
this, &DiffEditor::slotReloaderChanged);
connect(control, &DiffEditorController::contextLinesNumberEnablementChanged,
this, &DiffEditor::slotReloaderChanged);
connect(reloadButton, &QAbstractButton::clicked, this, [this]() { m_document->reload(); });
connect(m_document.data(), &DiffEditorDocument::temporaryStateChanged,
this, &DiffEditor::documentStateChanged);
return m_toolBar;
}
DiffEditorController *DiffEditor::controller() const
void DiffEditor::documentHasChanged()
{
return m_document->controller();
}
m_ignoreChanges = true;
const QList<FileData> diffFileList = m_document->diffFiles();
void DiffEditor::updateEntryToolTip()
{
const QString &toolTip = m_entriesComboBox->itemData(
m_entriesComboBox->currentIndex(), Qt::ToolTipRole).toString();
m_entriesComboBox->setToolTip(toolTip);
}
void DiffEditor::entryActivated(int index)
{
updateEntryToolTip();
m_guiController->setCurrentDiffFileIndex(index);
}
void DiffEditor::slotCleared(const QString &message)
{
Q_UNUSED(message)
m_entriesComboBox->clear();
updateEntryToolTip();
}
void DiffEditor::slotDiffFilesChanged(const QList<FileData> &diffFileList,
const QString &workingDirectory)
{
Q_UNUSED(workingDirectory)
currentView()->setDiff(diffFileList, m_document->baseDirectory());
m_entriesComboBox->clear();
int index = 0;
const int count = diffFileList.count();
for (int i = 0; i < count; i++) {
const DiffFileInfo leftEntry = diffFileList.at(i).leftFileInfo;
@@ -449,64 +421,193 @@ void DiffEditor::slotDiffFilesChanged(const QList<FileData> &diffFileList,
rightEntry.fileName);
}
}
if (m_currentFileChunk.first == leftEntry.fileName
&& m_currentFileChunk.second == rightEntry.fileName)
index = i;
m_entriesComboBox->addItem(itemText);
m_entriesComboBox->setItemData(m_entriesComboBox->count() - 1,
leftEntry.fileName, Qt::UserRole);
m_entriesComboBox->setItemData(m_entriesComboBox->count() - 1,
rightEntry.fileName, Qt::UserRole + 1);
m_entriesComboBox->setItemData(m_entriesComboBox->count() - 1,
itemToolTip, Qt::ToolTipRole);
}
updateEntryToolTip();
m_ignoreChanges = false;
setCurrentDiffFileIndex(m_entriesComboBox->count() > 0 ? index : -1);
}
void DiffEditor::activateEntry(int index)
void DiffEditor::toggleDescription()
{
m_entriesComboBox->blockSignals(true);
m_entriesComboBox->setCurrentIndex(index);
m_entriesComboBox->blockSignals(false);
updateEntryToolTip();
m_showDescription = !m_showDescription;
saveSetting(QLatin1String(descriptionVisibleKeyC), m_showDescription);
updateDescription();
}
void DiffEditor::slotDescriptionChanged(const QString &description)
void DiffEditor::updateDescription()
{
QString description = m_document->description();
m_descriptionWidget->setPlainText(description);
}
m_descriptionWidget->setVisible(m_showDescription && !description.isEmpty());
void DiffEditor::slotDescriptionVisibilityChanged()
{
const bool enabled = controller()->isDescriptionEnabled();
const bool visible = m_guiController->isDescriptionVisible();
m_descriptionWidget->setVisible(visible && enabled);
if (!m_toggleDescriptionAction)
return;
QTC_ASSERT(m_toolBar, return);
QTC_ASSERT(m_toggleDescriptionAction, return);
QWidget *toggle = m_toolBar->widgetForAction(m_toggleDescriptionAction);
if (visible)
toggle->setToolTip(tr("Hide Change Description"));
else
toggle->setToolTip(tr("Show Change Description"));
m_toggleDescriptionAction->setVisible(enabled);
toggle->setToolTip(m_showDescription ? tr("Hide Change Description")
: tr("Show Change Description"));
m_toggleDescriptionAction->setVisible(!description.isEmpty());
}
void DiffEditor::slotReloaderChanged()
void DiffEditor::contextLineCountHasChanged(int lines)
{
DiffEditorController *control = controller();
const DiffEditorReloader *reloader = control->reloader();
const bool contextVisible = control->isContextLinesNumberEnabled();
QTC_ASSERT(!m_document->isContextLineCountForced(), return);
if (m_ignoreChanges || lines == m_document->contextLineCount())
return;
m_whitespaceButtonAction->setVisible(reloader);
m_contextLabelAction->setVisible(reloader && contextVisible);
m_contextSpinBoxAction->setVisible(reloader && contextVisible);
m_reloadAction->setVisible(reloader);
m_document->setContextLineCount(lines);
saveSetting(QLatin1String(contextLineCountKeyC), lines);
m_document->reload();
}
void DiffEditor::ignoreWhitespaceHasChanged(bool ignore)
{
if (m_ignoreChanges || ignore == m_document->ignoreWhitespace())
return;
m_document->setIgnoreWhitespace(ignore);
saveSetting(QLatin1String(ignoreWhitespaceKeyC), ignore);
m_document->reload();
}
void DiffEditor::prepareForReload()
{
documentStateChanged(); // To update actions...
QTC_ASSERT(currentView(), return);
if (m_entriesComboBox->count() > 0) {
m_currentFileChunk
= qMakePair(m_entriesComboBox->itemData(m_currentDiffFileIndex, Qt::UserRole).toString(),
m_entriesComboBox->itemData(m_currentDiffFileIndex, Qt::UserRole + 1).toString());
} else {
m_currentFileChunk = qMakePair(QString(), QString());
}
m_ignoreChanges = true;
m_contextSpinBox->setValue(m_document->contextLineCount());
m_whitespaceButton->setChecked(m_document->ignoreWhitespace());
m_ignoreChanges = false;
currentView()->beginOperation();
}
void DiffEditor::reloadHasFinished(bool success)
{
if (!currentView())
return;
m_currentFileChunk = qMakePair(QString(), QString());
currentView()->endOperation(success);
}
void DiffEditor::updateEntryToolTip()
{
const QString &toolTip = m_entriesComboBox->itemData(
m_entriesComboBox->currentIndex(), Qt::ToolTipRole).toString();
m_entriesComboBox->setToolTip(toolTip);
}
void DiffEditor::setCurrentDiffFileIndex(int index)
{
if (m_ignoreChanges)
return;
QTC_ASSERT((index < 0) != (m_entriesComboBox->count() > 0), return);
m_ignoreChanges = true;
m_currentDiffFileIndex = index;
currentView()->setCurrentDiffFileIndex(index);
m_entriesComboBox->setCurrentIndex(m_entriesComboBox->count() > 0 ? qMax(0, index) : -1);
updateEntryToolTip();
m_ignoreChanges = false;
}
void DiffEditor::documentStateChanged()
{
const bool canReload = m_document->isTemporary();
const bool contextVisible = !m_document->isContextLineCountForced();
m_whitespaceButtonAction->setVisible(canReload);
m_contextLabelAction->setVisible(canReload && contextVisible);
m_contextSpinBoxAction->setVisible(canReload && contextVisible);
m_reloadAction->setVisible(canReload);
}
void DiffEditor::updateDiffEditorSwitcher()
{
if (!m_diffEditorSwitcher)
return;
IDiffView *next = nextView();
m_diffEditorSwitcher->setIcon(next->icon());
m_diffEditorSwitcher->setToolTip(next->toolTip());
}
m_diffEditorSwitcher->setIcon(currentView()->icon());
m_diffEditorSwitcher->setToolTip(currentView()->toolTip());
void DiffEditor::toggleSync()
{
QTC_ASSERT(currentView(), return);
m_sync = !m_sync;
saveSetting(QLatin1String(horizontalScrollBarSynchronizationKeyC), m_sync);
currentView()->setSync(m_sync);
}
void DiffEditor::loadSettings()
{
QTC_ASSERT(currentView(), return);
QSettings *s = Core::ICore::settings();
// TODO: Remove in 3.6: Read legacy settings first:
s->beginGroup(QLatin1String(legacySettingsGroupC));
const bool legacyExists = s->contains(QLatin1String(useDiffEditorKeyC));
const bool legacyEditor = s->value(
QLatin1String(useDiffEditorKeyC), true).toBool();
s->remove(QLatin1String(useDiffEditorKeyC));
s->endGroup();
// Save legacy settings to current settings:
if (legacyExists) {
saveSetting(QLatin1String(diffViewKeyC), legacyEditor ? m_views.at(0)->id().toSetting() :
m_views.at(1)->id().toSetting());
}
// Read current settings:
s->beginGroup(QLatin1String(settingsGroupC));
m_showDescription = s->value(QLatin1String(descriptionVisibleKeyC),
true).toBool();
m_sync = s->value(QLatin1String(horizontalScrollBarSynchronizationKeyC),
true).toBool();
m_document->setIgnoreWhitespace(s->value(QLatin1String(ignoreWhitespaceKeyC), false).toBool());
m_document->setContextLineCount(s->value(QLatin1String(contextLineCountKeyC), 3).toInt());
Core::Id id = Core::Id::fromSetting(s->value(QLatin1String(diffViewKeyC)));
s->endGroup();
IDiffView *view = Utils::findOr(m_views, m_views.at(0), [id](IDiffView *v) { return v->id() == id; });
QTC_ASSERT(view, return);
setupView(view);
}
void DiffEditor::saveSetting(const QString &key, const QVariant &value) const
{
QSettings *s = Core::ICore::settings();
s->beginGroup(QLatin1String(settingsGroupC));
s->setValue(key, value);
s->endGroup();
}
void DiffEditor::addView(IDiffView *view)
@@ -514,6 +615,10 @@ void DiffEditor::addView(IDiffView *view)
QTC_ASSERT(!m_views.contains(view), return);
m_views.append(view);
m_stackedWidget->addWidget(view->widget());
if (m_views.count() == 1)
setCurrentView(view);
connect(view, &IDiffView::currentDiffFileIndexChanged, this, &DiffEditor::setCurrentDiffFileIndex);
}
IDiffView *DiffEditor::currentView() const
@@ -539,71 +644,42 @@ IDiffView *DiffEditor::nextView()
return m_views.at(pos);
}
void DiffEditor::showDiffView(IDiffView *newView)
void DiffEditor::setupView(IDiffView *view)
{
QTC_ASSERT(newView, return);
QTC_ASSERT(view, return);
setCurrentView(view);
if (currentView() == newView)
saveSetting(QLatin1String(diffViewKeyC), currentView()->id().toSetting());
m_toggleSyncAction->setVisible(currentView()->supportsSync());
m_toggleSyncAction->setToolTip(currentView()->syncToolTip());
m_toggleSyncAction->setChecked(m_sync);
view->setDocument(m_document.data());
view->setSync(m_sync);
view->beginOperation();
view->setDiff(m_document->diffFiles(), m_document->baseDirectory());
view->endOperation(true);
view->setCurrentDiffFileIndex(m_currentDiffFileIndex);
m_stackedWidget->setCurrentWidget(view->widget());
updateDiffEditorSwitcher();
if (widget())
widget()->setFocusProxy(view->widget());
}
void DiffEditor::showDiffView(IDiffView *view)
{
if (currentView() == view)
return;
if (currentView()) // during initialization
currentView()->setDiffEditorGuiController(0);
setCurrentView(newView);
currentView()->setDiffEditorGuiController(m_guiController);
currentView()->setDocument(0);
m_stackedWidget->setCurrentWidget(currentView()->widget());
writeCurrentDiffEditorSetting(currentView());
updateDiffEditorSwitcher();
widget()->setFocusProxy(currentView()->widget());
}
// TODO: Remove in 3.6:
IDiffView *DiffEditor::readLegacyCurrentDiffEditorSetting()
{
QTC_ASSERT(!m_views.isEmpty(), return 0);
QTC_ASSERT(m_views.count() == 2, return m_views.at(0));
QSettings *s = Core::ICore::settings();
s->beginGroup(QLatin1String(legacySettingsGroupC));
const bool legacyExists = s->contains(QLatin1String(useDiffEditorKeyC));
const bool legacyEditor = s->value(
QLatin1String(useDiffEditorKeyC), true).toBool();
if (legacyExists)
s->remove(QLatin1String(useDiffEditorKeyC));
s->endGroup();
IDiffView *currentEditor = m_views.at(0);
if (!legacyEditor)
currentEditor = m_views.at(1);
if (legacyExists)
writeCurrentDiffEditorSetting(currentEditor);
return currentEditor;
}
IDiffView *DiffEditor::readCurrentDiffEditorSetting()
{
// replace it with m_sideBySideEditor when dropping legacy stuff
IDiffView *view = readLegacyCurrentDiffEditorSetting();
QSettings *s = Core::ICore::settings();
s->beginGroup(QLatin1String(settingsGroupC));
const Core::Id id = Core::Id::fromSetting(s->value(QLatin1String(diffEditorTypeKeyC)));
s->endGroup();
return Utils::findOr(m_views, view, [id](IDiffView *v) { return v->id() == id; });
}
void DiffEditor::writeCurrentDiffEditorSetting(IDiffView *currentEditor)
{
QTC_ASSERT(currentEditor, return);
QSettings *s = Core::ICore::settings();
s->beginGroup(QLatin1String(settingsGroupC));
s->setValue(QLatin1String(diffEditorTypeKeyC), currentEditor->id().toSetting());
s->endGroup();
QTC_ASSERT(view, return);
setupView(view);
}
} // namespace Internal

View File

@@ -38,6 +38,7 @@
QT_BEGIN_NAMESPACE
class QComboBox;
class QSpinBox;
class QToolBar;
class QToolButton;
class QStackedWidget;
@@ -50,7 +51,6 @@ namespace DiffEditor {
namespace Internal {
class DescriptionEditorWidget;
class DiffEditorDocument;
class DiffEditorGuiController;
class IDiffView;
class DiffEditor : public Core::IEditor
@@ -62,8 +62,6 @@ public:
~DiffEditor();
public:
DiffEditorController *controller() const;
Core::IEditor *duplicate();
bool open(QString *errorString,
@@ -73,44 +71,52 @@ public:
QWidget *toolBar();
public slots:
void activateEntry(int index);
private slots:
void slotCleared(const QString &message);
void slotDiffFilesChanged(const QList<FileData> &diffFileList,
const QString &workingDirectory);
void entryActivated(int index);
void slotDescriptionChanged(const QString &description);
void slotDescriptionVisibilityChanged();
void slotReloaderChanged();
void documentHasChanged();
void toggleDescription();
void updateDescription();
void contextLineCountHasChanged(int lines);
void ignoreWhitespaceHasChanged(bool ignore);
void prepareForReload();
void reloadHasFinished(bool success);
void setCurrentDiffFileIndex(int index);
void documentStateChanged();
void toggleSync();
private:
void loadSettings();
void saveSetting(const QString &key, const QVariant &value) const;
void updateEntryToolTip();
void showDiffView(IDiffView *newEditor);
void showDiffView(IDiffView *view);
void updateDiffEditorSwitcher();
void addView(IDiffView *view);
IDiffView *currentView() const;
void setCurrentView(IDiffView *view);
IDiffView *nextView();
IDiffView *readLegacyCurrentDiffEditorSetting();
IDiffView *readCurrentDiffEditorSetting();
void writeCurrentDiffEditorSetting(IDiffView *currentEditor);
void setupView(IDiffView *view);
QSharedPointer<DiffEditorDocument> m_document;
DescriptionEditorWidget *m_descriptionWidget;
QStackedWidget *m_stackedWidget;
QVector<IDiffView *> m_views;
int m_currentViewIndex;
DiffEditorGuiController *m_guiController;
QToolBar *m_toolBar;
QComboBox *m_entriesComboBox;
QToolButton *m_whitespaceButton;
QSpinBox *m_contextSpinBox;
QAction *m_toggleSyncAction;
QAction *m_whitespaceButtonAction;
QAction *m_contextLabelAction;
QAction *m_contextSpinBoxAction;
QAction *m_toggleDescriptionAction;
QAction *m_reloadAction;
QToolButton *m_diffEditorSwitcher;
QPair<QString, QString> m_currentFileChunk;
int m_currentViewIndex;
int m_currentDiffFileIndex;
bool m_sync;
bool m_showDescription;
bool m_ignoreChanges;
};
} // namespace Internal

View File

@@ -7,10 +7,8 @@ HEADERS += diffeditor_global.h \
diffeditorcontroller.h \
diffeditordocument.h \
diffeditorfactory.h \
diffeditorguicontroller.h \
diffeditormanager.h \
diffeditorplugin.h \
diffeditorreloader.h \
differ.h \
diffutils.h \
diffview.h \
@@ -22,10 +20,8 @@ SOURCES += diffeditor.cpp \
diffeditorcontroller.cpp \
diffeditordocument.cpp \
diffeditorfactory.cpp \
diffeditorguicontroller.cpp \
diffeditormanager.cpp \
diffeditorplugin.cpp \
diffeditorreloader.cpp \
differ.cpp \
diffutils.cpp \
diffview.cpp \

View File

@@ -22,14 +22,10 @@ QtcPlugin {
"diffeditordocument.h",
"diffeditorfactory.cpp",
"diffeditorfactory.h",
"diffeditorguicontroller.cpp",
"diffeditorguicontroller.h",
"diffeditormanager.cpp",
"diffeditormanager.h",
"diffeditorplugin.cpp",
"diffeditorplugin.h",
"diffeditorreloader.cpp",
"diffeditorreloader.h",
"differ.cpp",
"differ.h",
"diffutils.cpp",

View File

@@ -30,227 +30,90 @@
#include "diffeditorconstants.h"
#include "diffeditorcontroller.h"
#include "diffeditorreloader.h"
#include "diffeditordocument.h"
#include <coreplugin/icore.h>
#include <QStringList>
#include <utils/qtcassert.h>
static const char settingsGroupC[] = "DiffEditor";
static const char contextLineNumbersKeyC[] = "ContextLineNumbers";
static const char ignoreWhitespaceKeyC[] = "IgnoreWhitespace";
#include <QStringList>
namespace DiffEditor {
DiffEditorController::DiffEditorController(QObject *parent)
: QObject(parent),
m_reloader(0),
m_contextLinesNumber(3),
m_diffFileIndex(-1),
m_chunkIndex(-1),
m_descriptionEnabled(false),
m_contextLinesNumberEnabled(true),
m_ignoreWhitespace(true)
DiffEditorController::DiffEditorController(Core::IDocument *document) :
QObject(document),
m_document(qobject_cast<Internal::DiffEditorDocument *>(document)),
m_isReloading(false),
m_diffFileIndex(-1),
m_chunkIndex(-1)
{
QSettings *s = Core::ICore::settings();
s->beginGroup(QLatin1String(settingsGroupC));
m_contextLinesNumber = s->value(QLatin1String(contextLineNumbersKeyC),
m_contextLinesNumber).toInt();
m_ignoreWhitespace = s->value(QLatin1String(ignoreWhitespaceKeyC),
m_ignoreWhitespace).toBool();
s->endGroup();
clear();
QTC_ASSERT(m_document, return);
QTC_CHECK(!m_document->controller());
m_document->setController(this);
}
DiffEditorController::~DiffEditorController()
bool DiffEditorController::isReloading() const
{
delete m_reloader;
return m_isReloading;
}
QString DiffEditorController::clearMessage() const
QString DiffEditorController::baseDirectory() const
{
return m_clearMessage;
return m_document->baseDirectory();
}
QList<FileData> DiffEditorController::diffFiles() const
int DiffEditorController::contextLineCount() const
{
return m_diffFiles;
return m_document->contextLineCount();
}
QString DiffEditorController::workingDirectory() const
bool DiffEditorController::ignoreWhitespace() const
{
return m_workingDirectory;
return m_document->ignoreWhitespace();
}
QString DiffEditorController::description() const
QString DiffEditorController::revisionFromDescription() const
{
return m_description;
}
bool DiffEditorController::isDescriptionEnabled() const
{
return m_descriptionEnabled;
}
int DiffEditorController::contextLinesNumber() const
{
return m_contextLinesNumber;
}
bool DiffEditorController::isContextLinesNumberEnabled() const
{
return m_contextLinesNumberEnabled;
}
bool DiffEditorController::isIgnoreWhitespace() const
{
return m_ignoreWhitespace;
}
// ### fixme: git-specific handling should be done in the git plugin:
// Remove unexpanded branches and follows-tag, clear indentation
// and create E-mail
static void formatGitDescription(QString *description)
{
QString result;
result.reserve(description->size());
foreach (QString line, description->split(QLatin1Char('\n'))) {
if (line.startsWith(QLatin1String("commit "))
|| line.startsWith(QLatin1String("Branches: <Expand>"))) {
continue;
}
if (line.startsWith(QLatin1String("Author: ")))
line.replace(0, 8, QStringLiteral("From: "));
else if (line.startsWith(QLatin1String(" ")))
line.remove(0, 4);
result.append(line);
result.append(QLatin1Char('\n'));
}
*description = result;
}
QString DiffEditorController::contents() const
{
QString result = m_description;
const int formattingOptions = DiffUtils::GitFormat;
if (formattingOptions & DiffUtils::GitFormat)
formatGitDescription(&result);
const QString diff = DiffUtils::makePatch(diffFiles(), formattingOptions);
if (!diff.isEmpty()) {
if (!result.isEmpty())
result += QLatin1Char('\n');
result += diff;
}
return result;
// TODO: This is specific for git and does not belong here at all!
return m_document->description().mid(7, 12);
}
QString DiffEditorController::makePatch(bool revert, bool addPrefix) const
{
if (m_diffFileIndex < 0 || m_chunkIndex < 0)
return QString();
if (m_diffFileIndex >= m_diffFiles.count())
return QString();
const FileData fileData = m_diffFiles.at(m_diffFileIndex);
if (m_chunkIndex >= fileData.chunks.count())
return QString();
const ChunkData chunkData = fileData.chunks.at(m_chunkIndex);
const bool lastChunk = (m_chunkIndex == fileData.chunks.count() - 1);
const QString fileName = revert
? fileData.rightFileInfo.fileName
: fileData.leftFileInfo.fileName;
QString leftPrefix, rightPrefix;
if (addPrefix) {
leftPrefix = QLatin1String("a/");
rightPrefix = QLatin1String("b/");
}
return DiffUtils::makePatch(chunkData,
leftPrefix + fileName,
rightPrefix + fileName,
lastChunk && fileData.lastChunkAtTheEndOfFile);
}
DiffEditorReloader *DiffEditorController::reloader() const
{
return m_reloader;
}
// The ownership of reloader is passed to the controller
void DiffEditorController::setReloader(DiffEditorReloader *reloader)
{
if (m_reloader == reloader)
return; // nothing changes
delete m_reloader;
m_reloader = reloader;
if (m_reloader)
m_reloader->setController(this);
emit reloaderChanged();
}
void DiffEditorController::clear()
{
clear(tr("No difference"));
}
void DiffEditorController::clear(const QString &message)
{
setDescription(QString());
setDiffFiles(QList<FileData>());
m_clearMessage = message;
emit cleared(message);
return m_document->makePatch(m_diffFileIndex, m_chunkIndex, revert, addPrefix);
}
void DiffEditorController::setDiffFiles(const QList<FileData> &diffFileList,
const QString &workingDirectory)
{
m_diffFiles = diffFileList;
m_workingDirectory = workingDirectory;
emit diffFilesChanged(diffFileList, workingDirectory);
m_document->setDiffFiles(diffFileList, workingDirectory);
}
void DiffEditorController::setDescription(const QString &description)
{
if (m_description == description)
return;
m_description = description;
emit descriptionChanged(m_description);
m_document->setDescription(description);
}
void DiffEditorController::setDescriptionEnabled(bool on)
{
if (m_descriptionEnabled == on)
return;
m_descriptionEnabled = on;
emit descriptionEnablementChanged(on);
}
void DiffEditorController::branchesForCommitReceived(const QString &output)
void DiffEditorController::informationForCommitReceived(const QString &output)
{
// TODO: Git specific code...
const QString branches = prepareBranchesForCommit(output);
m_description.replace(QLatin1String(Constants::EXPAND_BRANCHES), branches);
emit descriptionChanged(m_description);
QString tmp = m_document->description();
tmp.replace(QLatin1String(Constants::EXPAND_BRANCHES), branches);
m_document->setDescription(tmp);
}
void DiffEditorController::expandBranchesRequested()
void DiffEditorController::requestMoreInformation()
{
emit requestBranchList(m_description.mid(7, 8));
const QString rev = revisionFromDescription();
if (!rev.isEmpty())
emit requestInformationForCommit(rev);
}
QString DiffEditorController::prepareBranchesForCommit(const QString &output)
{
// TODO: More git-specific code...
QString moreBranches;
QString branches;
QStringList res;
@@ -274,69 +137,40 @@ QString DiffEditorController::prepareBranchesForCommit(const QString &output)
return branches;
}
void DiffEditorController::setContextLinesNumber(int lines)
/**
* @brief Force the lines of context to the given number.
*
* The user will not be able to change the context lines anymore. This needs to be set before
* starting any operation or the flag will be ignored by the UI.
*
* @param lines Lines of context to display.
*/
void DiffEditorController::forceContextLineCount(int lines)
{
const int l = qMax(lines, 1);
if (m_contextLinesNumber == l)
return;
m_contextLinesNumber = l;
QSettings *s = Core::ICore::settings();
s->beginGroup(QLatin1String(settingsGroupC));
s->setValue(QLatin1String(contextLineNumbersKeyC), m_contextLinesNumber);
s->endGroup();
emit contextLinesNumberChanged(l);
}
void DiffEditorController::setContextLinesNumberEnabled(bool on)
{
if (m_contextLinesNumberEnabled == on)
return;
m_contextLinesNumberEnabled = on;
emit contextLinesNumberEnablementChanged(on);
}
void DiffEditorController::setIgnoreWhitespace(bool ignore)
{
if (m_ignoreWhitespace == ignore)
return;
m_ignoreWhitespace = ignore;
QSettings *s = Core::ICore::settings();
s->beginGroup(QLatin1String(settingsGroupC));
s->setValue(QLatin1String(ignoreWhitespaceKeyC), m_ignoreWhitespace);
s->endGroup();
emit ignoreWhitespaceChanged(ignore);
m_document->forceContextLineCount(lines);
}
/**
* @brief Request the diff data to be re-read.
*/
void DiffEditorController::requestReload()
{
if (m_reloader)
m_reloader->requestReload();
m_isReloading = true;
m_document->beginReload();
reload();
}
void DiffEditorController::requestChunkActions(QMenu *menu,
int diffFileIndex,
int chunkIndex)
void DiffEditorController::reloadFinished(bool success)
{
m_document->endReload(success);
m_isReloading = false;
}
void DiffEditorController::requestChunkActions(QMenu *menu, int diffFileIndex, int chunkIndex)
{
m_diffFileIndex = diffFileIndex;
m_chunkIndex = chunkIndex;
emit chunkActionsRequested(menu, diffFileIndex >= 0 && chunkIndex >= 0);
}
void DiffEditorController::requestSaveState()
{
emit saveStateRequested();
}
void DiffEditorController::requestRestoreState()
{
emit restoreStateRequested();
}
} // namespace DiffEditor

View File

@@ -36,81 +36,60 @@
#include <QObject>
namespace DiffEditor {
namespace Core { class IDocument; }
class DiffEditorReloader;
namespace DiffEditor {
namespace Internal { class DiffEditorDocument; }
class DIFFEDITOR_EXPORT DiffEditorController : public QObject
{
Q_OBJECT
public:
DiffEditorController(QObject *parent = 0);
~DiffEditorController();
explicit DiffEditorController(Core::IDocument *document);
QString clearMessage() const;
void requestReload();
bool isReloading() const;
QList<FileData> diffFiles() const;
QString workingDirectory() const;
QString description() const;
bool isDescriptionEnabled() const;
int contextLinesNumber() const;
bool isContextLinesNumberEnabled() const;
bool isIgnoreWhitespace() const;
QString baseDirectory() const;
int contextLineCount() const;
bool ignoreWhitespace() const;
QString revisionFromDescription() const;
QString makePatch(bool revert, bool addPrefix = false) const;
QString contents() const;
DiffEditorReloader *reloader() const;
void setReloader(DiffEditorReloader *reloader);
public slots:
void clear();
void clear(const QString &message);
void setDiffFiles(const QList<FileData> &diffFileList,
const QString &workingDirectory = QString());
void setDescription(const QString &description);
void setDescriptionEnabled(bool on);
void setContextLinesNumber(int lines);
void setContextLinesNumberEnabled(bool on);
void setIgnoreWhitespace(bool ignore);
void requestReload();
void requestChunkActions(QMenu *menu,
int diffFileIndex,
int chunkIndex);
void requestSaveState();
void requestRestoreState();
void branchesForCommitReceived(const QString &output);
void expandBranchesRequested();
void informationForCommitReceived(const QString &output);
signals:
void cleared(const QString &message);
void diffFilesChanged(const QList<FileData> &diffFileList,
const QString &workingDirectory);
void descriptionChanged(const QString &description);
void descriptionEnablementChanged(bool on);
void contextLinesNumberChanged(int lines);
void contextLinesNumberEnablementChanged(bool on);
void ignoreWhitespaceChanged(bool ignore);
void chunkActionsRequested(QMenu *menu, bool isValid);
void saveStateRequested();
void restoreStateRequested();
void requestBranchList(const QString &revision);
void reloaderChanged();
void requestInformationForCommit(const QString &revision);
protected:
// reloadFinished() should be called
// inside reload() (for synchronous reload)
// or later (for asynchronous reload)
virtual void reload() = 0;
void reloadFinished(bool success);
void setDiffFiles(const QList<FileData> &diffFileList,
const QString &baseDirectory = QString());
void setDescription(const QString &description);
void forceContextLineCount(int lines);
private:
QString prepareBranchesForCommit(const QString &output);
QString m_clearMessage;
void requestMoreInformation();
void requestChunkActions(QMenu *menu, int diffFileIndex, int chunkIndex);
QList<FileData> m_diffFiles;
QString m_workingDirectory;
QString m_description;
DiffEditorReloader *m_reloader;
int m_contextLinesNumber;
QString prepareBranchesForCommit(const QString &output);
Internal::DiffEditorDocument *const m_document;
bool m_isReloading;
int m_diffFileIndex;
int m_chunkIndex;
bool m_descriptionEnabled;
bool m_contextLinesNumberEnabled;
bool m_ignoreWhitespace;
friend class Internal::DiffEditorDocument;
};
} // namespace DiffEditor

View File

@@ -32,33 +32,165 @@
#include "diffeditorconstants.h"
#include "diffeditorcontroller.h"
#include "diffeditormanager.h"
#include "diffeditorreloader.h"
#include "diffutils.h"
#include <utils/fileutils.h>
#include <utils/qtcassert.h>
#include <coreplugin/editormanager/editormanager.h>
#include <QCoreApplication>
#include <QFile>
#include <QDir>
#include <QMenu>
#include <QTextCodec>
#include <QUuid>
using namespace Utils;
namespace DiffEditor {
namespace Internal {
DiffEditorDocument::DiffEditorDocument() :
Core::BaseTextDocument(),
m_controller(new DiffEditorController(this))
m_controller(0),
m_contextLineCount(3),
m_isContextLineCountForced(false),
m_ignoreWhitespace(false)
{
setId(Constants::DIFF_EDITOR_ID);
setMimeType(QLatin1String(Constants::DIFF_EDITOR_MIMETYPE));
setTemporary(true);
}
DiffEditorDocument::~DiffEditorDocument()
{
DiffEditorManager::removeDocument(this);
}
/**
* @brief Set a controller for a document
* @param controller The controller to set.
*
* This method takes ownership of the controller and will delete it after it is done with it.
*/
void DiffEditorDocument::setController(DiffEditorController *controller)
{
QTC_ASSERT(isTemporary(), return);
if (m_controller == controller)
return;
if (m_controller)
m_controller->deleteLater();
m_controller = controller;
if (m_controller) {
connect(this, &DiffEditorDocument::chunkActionsRequested,
m_controller, &DiffEditorController::requestChunkActions);
connect(this, &DiffEditorDocument::requestMoreInformation,
m_controller, &DiffEditorController::requestMoreInformation);
}
}
DiffEditorController *DiffEditorDocument::controller() const
{
return m_controller;
}
QString DiffEditorDocument::makePatch(int fileIndex, int chunkIndex, bool revert, bool addPrefix) const
{
if (fileIndex < 0 || chunkIndex < 0)
return QString();
if (fileIndex >= m_diffFiles.count())
return QString();
const FileData &fileData = m_diffFiles.at(fileIndex);
if (chunkIndex >= fileData.chunks.count())
return QString();
const ChunkData &chunkData = fileData.chunks.at(chunkIndex);
const bool lastChunk = (chunkIndex == fileData.chunks.count() - 1);
const QString fileName = revert
? fileData.rightFileInfo.fileName
: fileData.leftFileInfo.fileName;
QString leftPrefix, rightPrefix;
if (addPrefix) {
leftPrefix = QLatin1String("a/");
rightPrefix = QLatin1String("b/");
}
return DiffUtils::makePatch(chunkData,
leftPrefix + fileName,
rightPrefix + fileName,
lastChunk && fileData.lastChunkAtTheEndOfFile);
}
void DiffEditorDocument::setDiffFiles(const QList<FileData> &data, const QString &directory)
{
m_diffFiles = data;
m_baseDirectory = directory;
emit documentChanged();
}
QList<FileData> DiffEditorDocument::diffFiles() const
{
return m_diffFiles;
}
QString DiffEditorDocument::baseDirectory() const
{
return m_baseDirectory;
}
void DiffEditorDocument::setDescription(const QString &description)
{
if (m_description == description)
return;
m_description = description;
emit descriptionChanged();
}
QString DiffEditorDocument::description() const
{
return m_description;
}
void DiffEditorDocument::setContextLineCount(int lines)
{
m_contextLineCount = lines;
}
int DiffEditorDocument::contextLineCount() const
{
return m_contextLineCount;
}
void DiffEditorDocument::forceContextLineCount(int lines)
{
m_contextLineCount = lines;
m_isContextLineCountForced = true;
}
bool DiffEditorDocument::isContextLineCountForced() const
{
return m_isContextLineCountForced;
}
void DiffEditorDocument::setIgnoreWhitespace(bool ignore)
{
if (m_isContextLineCountForced)
return;
m_ignoreWhitespace = ignore;
}
bool DiffEditorDocument::ignoreWhitespace() const
{
return m_ignoreWhitespace;
}
bool DiffEditorDocument::setContents(const QByteArray &contents)
{
Q_UNUSED(contents);
@@ -67,7 +199,9 @@ bool DiffEditorDocument::setContents(const QByteArray &contents)
QString DiffEditorDocument::defaultPath() const
{
return m_controller->workingDirectory();
if (!m_baseDirectory.isEmpty())
return m_baseDirectory;
return QDir::homePath();
}
bool DiffEditorDocument::save(QString *errorString, const QString &fileName, bool autoSave)
@@ -75,23 +209,35 @@ bool DiffEditorDocument::save(QString *errorString, const QString &fileName, boo
Q_UNUSED(errorString)
Q_UNUSED(autoSave)
const bool ok = write(fileName, format(), m_controller->contents(), errorString);
const bool ok = write(fileName, format(), plainText(), errorString);
if (!ok)
return false;
m_controller->setReloader(0);
m_controller->setDescription(QString());
m_controller->setDescriptionEnabled(false);
DiffEditorManager::removeDocument(this);
setController(0);
setDescription(QString());
const QFileInfo fi(fileName);
setTemporary(false);
setFilePath(Utils::FileName::fromString(fi.absoluteFilePath()));
setFilePath(FileName::fromString(fi.absoluteFilePath()));
setPreferredDisplayName(QString());
emit temporaryStateChanged();
return true;
}
void DiffEditorDocument::reload()
{
if (m_controller) {
m_controller->requestReload();
} else {
QString errorMessage;
reload(&errorMessage, Core::IDocument::FlagReload, Core::IDocument::TypeContents);
}
}
bool DiffEditorDocument::reload(QString *errorString, ReloadFlag flag, ChangeType type)
{
Q_UNUSED(type)
@@ -102,8 +248,10 @@ bool DiffEditorDocument::reload(QString *errorString, ReloadFlag flag, ChangeTyp
bool DiffEditorDocument::open(QString *errorString, const QString &fileName)
{
QTC_ASSERT(errorString, return false);
beginReload();
QString patch;
if (read(fileName, &patch, errorString) != Utils::TextFileFormat::ReadSuccess)
if (read(fileName, &patch, errorString) != TextFileFormat::ReadSuccess)
return false;
bool ok = false;
@@ -112,49 +260,82 @@ bool DiffEditorDocument::open(QString *errorString, const QString &fileName)
*errorString = tr("Could not parse patch file \"%1\". "
"The content is not of unified diff format.")
.arg(fileName);
return false;
} else {
const QFileInfo fi(fileName);
setTemporary(false);
emit temporaryStateChanged();
setFilePath(FileName::fromString(fi.absoluteFilePath()));
setDiffFiles(fileDataList, fi.absolutePath());
}
const QFileInfo fi(fileName);
setTemporary(false);
setFilePath(Utils::FileName::fromString(fi.absoluteFilePath()));
m_controller->setDiffFiles(fileDataList, fi.absolutePath());
return true;
endReload(ok);
return ok;
}
QString DiffEditorDocument::suggestedFileName() const
{
enum { maxSubjectLength = 50 };
QString result = QStringLiteral("0001");
const QString description = m_controller->description();
if (!description.isEmpty()) {
// Derive "git format-patch-type" file name from subject.
const int pos = description.indexOf(QLatin1String("\n\n "));
const int endPos = pos >= 0 ? description.indexOf(QLatin1Char('\n'), pos + 6) : -1;
if (endPos > pos) {
const QChar space(QLatin1Char(' '));
const QChar dash(QLatin1Char('-'));
QString subject = description.mid(pos, endPos - pos);
for (int i = 0; i < subject.size(); ++i) {
if (!subject.at(i).isLetterOrNumber())
subject[i] = space;
}
subject = subject.simplified();
if (subject.size() > maxSubjectLength) {
const int lastSpace = subject.lastIndexOf(space, maxSubjectLength);
subject.truncate(lastSpace > 0 ? lastSpace : maxSubjectLength);
}
subject.replace(space, dash);
result += dash;
result += subject;
}
const int maxSubjectLength = 50;
const QString desc = description();
if (!desc.isEmpty()) {
QString name = QString::fromLatin1("0001-%1").arg(desc.left(desc.indexOf(QLatin1Char('\n'))));
name = FileUtils::fileSystemFriendlyName(name);
name.truncate(maxSubjectLength);
name.append(QLatin1String(".patch"));
return name;
}
return result + QStringLiteral(".patch");
return QStringLiteral("0001.patch");
}
// ### fixme: git-specific handling should be done in the git plugin:
// Remove unexpanded branches and follows-tag, clear indentation
// and create E-mail
static void formatGitDescription(QString *description)
{
QString result;
result.reserve(description->size());
foreach (QString line, description->split(QLatin1Char('\n'))) {
if (line.startsWith(QLatin1String("commit "))
|| line.startsWith(QLatin1String("Branches: <Expand>"))) {
continue;
}
if (line.startsWith(QLatin1String("Author: ")))
line.replace(0, 8, QStringLiteral("From: "));
else if (line.startsWith(QLatin1String(" ")))
line.remove(0, 4);
result.append(line);
result.append(QLatin1Char('\n'));
}
*description = result;
}
QString DiffEditorDocument::plainText() const
{
return m_controller->contents();
QString result = description();
const int formattingOptions = DiffUtils::GitFormat;
if (formattingOptions & DiffUtils::GitFormat)
formatGitDescription(&result);
const QString diff = DiffUtils::makePatch(diffFiles(), formattingOptions);
if (!diff.isEmpty()) {
if (!result.isEmpty())
result += QLatin1Char('\n');
result += diff;
}
return result;
}
void DiffEditorDocument::beginReload()
{
emit aboutToReload();
const bool blocked = blockSignals(true);
setDiffFiles(QList<FileData>(), QString());
setDescription(QString());
blockSignals(blocked);
}
void DiffEditorDocument::endReload(bool success)
{
emit reloadFinished(success);
}
} // namespace Internal

View File

@@ -31,6 +31,8 @@
#ifndef DIFFEDITORDOCUMENT_H
#define DIFFEDITORDOCUMENT_H
#include "diffutils.h"
#include <coreplugin/textdocument.h>
namespace DiffEditor {
@@ -45,9 +47,26 @@ class DiffEditorDocument : public Core::BaseTextDocument
Q_PROPERTY(QString plainText READ plainText STORED false) // For access by code pasters
public:
DiffEditorDocument();
~DiffEditorDocument();
DiffEditorController *controller() const;
QString makePatch(int fileIndex, int chunkIndex, bool revert, bool addPrefix = false) const;
void setDiffFiles(const QList<FileData> &data, const QString &directory);
QList<FileData> diffFiles() const;
QString baseDirectory() const;
void setDescription(const QString &description);
QString description() const;
void setContextLineCount(int lines);
int contextLineCount() const;
void forceContextLineCount(int lines);
bool isContextLineCountForced() const;
void setIgnoreWhitespace(bool ignore);
bool ignoreWhitespace() const;
bool setContents(const QByteArray &contents);
QString defaultPath() const;
QString suggestedFileName() const Q_DECL_OVERRIDE;
@@ -55,13 +74,35 @@ public:
bool isModified() const { return false; }
bool isSaveAsAllowed() const { return true; }
bool save(QString *errorString, const QString &fileName, bool autoSave);
void reload();
bool reload(QString *errorString, ReloadFlag flag, ChangeType type);
bool open(QString *errorString, const QString &fileName);
QString plainText() const;
signals:
void temporaryStateChanged();
void documentChanged();
void descriptionChanged();
void chunkActionsRequested(QMenu *menu, int diffFileIndex, int chunkIndex);
void requestMoreInformation();
public slots:
void beginReload();
void endReload(bool success);
private:
DiffEditorController *const m_controller;
void setController(DiffEditorController *controller);
DiffEditorController *m_controller;
QList<FileData> m_diffFiles;
QString m_baseDirectory;
QString m_description;
int m_contextLineCount;
bool m_isContextLineCountForced;
bool m_ignoreWhitespace;
friend class ::DiffEditor::DiffEditorController;
};
} // namespace Internal

View File

@@ -1,143 +0,0 @@
/****************************************************************************
**
** Copyright (C) 2015 The Qt Company Ltd.
** Contact: http://www.qt.io/licensing
**
** This file is part of Qt Creator.
**
** 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 The Qt Company. For licensing terms and
** conditions see http://www.qt.io/terms-conditions. For further information
** use the contact form at http://www.qt.io/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 or version 3 as published by the Free
** Software Foundation and appearing in the file LICENSE.LGPLv21 and
** LICENSE.LGPLv3 included in the packaging of this file. Please review the
** following information to ensure the GNU Lesser General Public License
** requirements will be met: https://www.gnu.org/licenses/lgpl.html and
** http://www.gnu.org/licenses/old-licenses/lgpl-2.1.html.
**
** In addition, as a special exception, The Qt Company gives you certain additional
** rights. These rights are described in The Qt Company LGPL Exception
** version 1.1, included in the file LGPL_EXCEPTION.txt in this package.
**
****************************************************************************/
#include "diffeditorguicontroller.h"
#include "diffeditorcontroller.h"
#include <coreplugin/icore.h>
#include <utils/qtcassert.h>
static const char settingsGroupC[] = "DiffEditor";
static const char descriptionVisibleKeyC[] = "DescriptionVisible";
static const char horizontalScrollBarSynchronizationKeyC[] =
"HorizontalScrollBarSynchronization";
namespace DiffEditor {
namespace Internal {
DiffEditorGuiController::DiffEditorGuiController(
DiffEditorController *controller,
QObject *parent)
: QObject(parent),
m_controller(controller),
m_descriptionVisible(true),
m_syncScrollBars(true),
m_currentDiffFileIndex(-1)
{
QTC_ASSERT(m_controller, return);
QSettings *s = Core::ICore::settings();
s->beginGroup(QLatin1String(settingsGroupC));
m_descriptionVisible = s->value(QLatin1String(descriptionVisibleKeyC),
m_descriptionVisible).toBool();
m_syncScrollBars = s->value(QLatin1String(horizontalScrollBarSynchronizationKeyC),
m_syncScrollBars).toBool();
s->endGroup();
connect(m_controller, &DiffEditorController::cleared, this,
&DiffEditorGuiController::slotUpdateDiffFileIndex);
connect(m_controller, &DiffEditorController::diffFilesChanged, this,
&DiffEditorGuiController::slotUpdateDiffFileIndex);
slotUpdateDiffFileIndex();
}
DiffEditorController *DiffEditorGuiController::controller() const
{
return m_controller;
}
bool DiffEditorGuiController::isDescriptionVisible() const
{
return m_descriptionVisible;
}
bool DiffEditorGuiController::horizontalScrollBarSynchronization() const
{
return m_syncScrollBars;
}
int DiffEditorGuiController::currentDiffFileIndex() const
{
return m_currentDiffFileIndex;
}
void DiffEditorGuiController::slotUpdateDiffFileIndex()
{
m_currentDiffFileIndex = (m_controller->diffFiles().isEmpty() ? -1 : 0);
}
void DiffEditorGuiController::setDescriptionVisible(bool on)
{
if (m_descriptionVisible == on)
return;
m_descriptionVisible = on;
QSettings *s = Core::ICore::settings();
s->beginGroup(QLatin1String(settingsGroupC));
s->setValue(QLatin1String(descriptionVisibleKeyC), m_descriptionVisible);
s->endGroup();
emit descriptionVisibilityChanged(on);
}
void DiffEditorGuiController::setHorizontalScrollBarSynchronization(bool on)
{
if (m_syncScrollBars == on)
return;
m_syncScrollBars = on;
QSettings *s = Core::ICore::settings();
s->beginGroup(QLatin1String(settingsGroupC));
s->setValue(QLatin1String(horizontalScrollBarSynchronizationKeyC),
m_syncScrollBars);
s->endGroup();
emit horizontalScrollBarSynchronizationChanged(on);
}
void DiffEditorGuiController::setCurrentDiffFileIndex(int diffFileIndex)
{
if (m_controller->diffFiles().isEmpty())
return; // -1 is the only valid value in this case
const int newIndex = qBound(0, diffFileIndex,
m_controller->diffFiles().count() - 1);
if (m_currentDiffFileIndex == newIndex)
return;
m_currentDiffFileIndex = newIndex;
emit currentDiffFileIndexChanged(newIndex);
}
} // namespace Internal
} // namespace DiffEditor

View File

@@ -1,78 +0,0 @@
/****************************************************************************
**
** Copyright (C) 2015 The Qt Company Ltd.
** Contact: http://www.qt.io/licensing
**
** This file is part of Qt Creator.
**
** 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 The Qt Company. For licensing terms and
** conditions see http://www.qt.io/terms-conditions. For further information
** use the contact form at http://www.qt.io/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 or version 3 as published by the Free
** Software Foundation and appearing in the file LICENSE.LGPLv21 and
** LICENSE.LGPLv3 included in the packaging of this file. Please review the
** following information to ensure the GNU Lesser General Public License
** requirements will be met: https://www.gnu.org/licenses/lgpl.html and
** http://www.gnu.org/licenses/old-licenses/lgpl-2.1.html.
**
** In addition, as a special exception, The Qt Company gives you certain additional
** rights. These rights are described in The Qt Company LGPL Exception
** version 1.1, included in the file LGPL_EXCEPTION.txt in this package.
**
****************************************************************************/
#ifndef DIFFEDITORGUICONTROLLER_H
#define DIFFEDITORGUICONTROLLER_H
#include <QObject>
namespace DiffEditor {
class DiffEditorController;
namespace Internal {
class DiffEditorGuiController : public QObject
{
Q_OBJECT
public:
DiffEditorGuiController(DiffEditorController *controller,
QObject *parent = 0);
DiffEditorController *controller() const;
bool isDescriptionVisible() const;
bool horizontalScrollBarSynchronization() const;
int currentDiffFileIndex() const;
public slots:
void setDescriptionVisible(bool on);
void setHorizontalScrollBarSynchronization(bool on);
void setCurrentDiffFileIndex(int diffFileIndex);
signals:
void descriptionVisibilityChanged(bool on);
void horizontalScrollBarSynchronizationChanged(bool on);
void currentDiffFileIndexChanged(int diffFileIndex);
private slots:
void slotUpdateDiffFileIndex();
private:
DiffEditorController *const m_controller;
bool m_descriptionVisible;
bool m_syncScrollBars;
int m_currentDiffFileIndex;
};
} // namespace Internal
} // namespace DiffEditor
#endif // DIFFEDITORGUICONTROLLER_H

View File

@@ -49,10 +49,6 @@ DiffEditorManager::DiffEditorManager(QObject *parent)
{
QTC_ASSERT(!m_instance, return);
m_instance = this;
Core::EditorManager *editorManager = Core::EditorManager::instance();
connect(editorManager, &Core::EditorManager::editorsClosed,
this, &DiffEditorManager::slotEditorsClosed);
}
DiffEditorManager::~DiffEditorManager()
@@ -60,27 +56,11 @@ DiffEditorManager::~DiffEditorManager()
m_instance = 0;
}
void DiffEditorManager::slotEditorsClosed(const QList<Core::IEditor *> &editors)
{
QMap<Core::IDocument *, int> editorsForDocument;
for (int i = 0; i < editors.count(); i++) {
DiffEditor *diffEditor = qobject_cast<DiffEditor *>(editors.at(i));
if (diffEditor) {
Core::IDocument *document = diffEditor->document();
editorsForDocument[document]++;
}
}
QMapIterator<Core::IDocument *, int> it(editorsForDocument);
while (it.hasNext()) {
it.next();
if (Core::DocumentModel::editorsForDocument(it.key()).count() == 0) // no other editors use that document
removeDocument(it.key());
}
}
Core::IDocument *DiffEditorManager::find(const QString &vcsId)
{
return m_instance->m_idToDocument.value(vcsId);
Core::IDocument *document = m_instance->m_idToDocument.value(vcsId);
QTC_ASSERT(!document || document->isTemporary(), return 0);
return document;
}
Core::IDocument *DiffEditorManager::findOrCreate(const QString &vcsId, const QString &displayName)
@@ -89,10 +69,8 @@ Core::IDocument *DiffEditorManager::findOrCreate(const QString &vcsId, const QSt
if (document)
return document;
const QString msgWait = tr("Waiting for data...");
DiffEditor *diffEditor = qobject_cast<DiffEditor *>(
Core::EditorManager::openEditorWithContents(Constants::DIFF_EDITOR_ID,
0, msgWait.toUtf8()));
Core::EditorManager::openEditorWithContents(Constants::DIFF_EDITOR_ID, 0));
QTC_ASSERT(diffEditor, return 0);
document = qobject_cast<Internal::DiffEditorDocument *>(diffEditor->document());

View File

@@ -53,17 +53,16 @@ public:
explicit DiffEditorManager(QObject *parent);
virtual ~DiffEditorManager();
static Core::IDocument *find(const QString &vcsId);
static Core::IDocument *findOrCreate(const QString &vcsId, const QString &displayName);
static DiffEditorController *controller(Core::IDocument *document);
private:
static Core::IDocument *find(const QString &vcsId);
static void removeDocument(Core::IDocument *document);
private slots:
void slotEditorsClosed(const QList<Core::IEditor *> &editors);
private:
QMap<QString, Internal::DiffEditorDocument *> m_idToDocument;
friend class Internal::DiffEditorDocument;
};
} // namespace DiffEditor

View File

@@ -31,10 +31,10 @@
#include "diffeditorplugin.h"
#include "diffeditor.h"
#include "diffeditorconstants.h"
#include "diffeditorcontroller.h"
#include "diffeditordocument.h"
#include "diffeditorfactory.h"
#include "diffeditormanager.h"
#include "diffeditorreloader.h"
#include "differ.h"
#include <QAction>
@@ -53,12 +53,12 @@
namespace DiffEditor {
namespace Internal {
class SimpleDiffEditorReloader : public DiffEditorReloader
class FileDiffController : public DiffEditorController
{
Q_OBJECT
public:
SimpleDiffEditorReloader(const QString &leftFileName,
const QString &rightFileName);
FileDiffController(Core::IDocument *document, const QString &leftFileName,
const QString &rightFileName);
protected:
void reload();
@@ -68,14 +68,12 @@ private:
QString m_rightFileName;
};
SimpleDiffEditorReloader::SimpleDiffEditorReloader(const QString &leftFileName,
const QString &rightFileName)
: m_leftFileName(leftFileName),
m_rightFileName(rightFileName)
{
}
FileDiffController::FileDiffController(Core::IDocument *document, const QString &leftFileName,
const QString &rightFileName) :
DiffEditorController(document), m_leftFileName(leftFileName), m_rightFileName(rightFileName)
{ }
void SimpleDiffEditorReloader::reload()
void FileDiffController::reload()
{
QString errorString;
Utils::TextFileFormat format;
@@ -86,7 +84,6 @@ void SimpleDiffEditorReloader::reload()
format.codec,
&leftText, &format, &errorString)
!= Utils::TextFileFormat::ReadSuccess) {
return;
}
@@ -95,13 +92,11 @@ void SimpleDiffEditorReloader::reload()
format.codec,
&rightText, &format, &errorString)
!= Utils::TextFileFormat::ReadSuccess) {
return;
}
Differ differ;
QList<Diff> diffList = differ.cleanupSemantics(
differ.diff(leftText, rightText));
QList<Diff> diffList = differ.cleanupSemantics(differ.diff(leftText, rightText));
QList<Diff> leftDiffList;
QList<Diff> rightDiffList;
@@ -109,15 +104,13 @@ void SimpleDiffEditorReloader::reload()
QList<Diff> outputLeftDiffList;
QList<Diff> outputRightDiffList;
if (controller()->isIgnoreWhitespace()) {
const QList<Diff> leftIntermediate =
Differ::moveWhitespaceIntoEqualities(leftDiffList);
const QList<Diff> rightIntermediate =
Differ::moveWhitespaceIntoEqualities(rightDiffList);
Differ::ignoreWhitespaceBetweenEqualities(leftIntermediate,
rightIntermediate,
&outputLeftDiffList,
&outputRightDiffList);
if (ignoreWhitespace()) {
const QList<Diff> leftIntermediate
= Differ::moveWhitespaceIntoEqualities(leftDiffList);
const QList<Diff> rightIntermediate
= Differ::moveWhitespaceIntoEqualities(rightDiffList);
Differ::ignoreWhitespaceBetweenEqualities(leftIntermediate, rightIntermediate,
&outputLeftDiffList, &outputRightDiffList);
} else {
outputLeftDiffList = leftDiffList;
outputRightDiffList = rightDiffList;
@@ -125,45 +118,31 @@ void SimpleDiffEditorReloader::reload()
const ChunkData chunkData = DiffUtils::calculateOriginalData(
outputLeftDiffList, outputRightDiffList);
FileData fileData = DiffUtils::calculateContextData(
chunkData, controller()->contextLinesNumber(), 0);
FileData fileData = DiffUtils::calculateContextData(chunkData, contextLineCount(), 0);
fileData.leftFileInfo.fileName = m_leftFileName;
fileData.rightFileInfo.fileName = m_rightFileName;
QList<FileData> fileDataList;
fileDataList << fileData;
controller()->requestSaveState();
controller()->setDiffFiles(fileDataList);
controller()->requestRestoreState();
reloadFinished();
setDiffFiles(fileDataList);
reloadFinished(true);
}
/////////////////
DiffEditorPlugin::DiffEditorPlugin()
{
}
DiffEditorPlugin::~DiffEditorPlugin()
{
}
bool DiffEditorPlugin::initialize(const QStringList &arguments, QString *errorMessage)
{
Q_UNUSED(arguments)
Q_UNUSED(errorMessage)
//register actions
Core::ActionContainer *toolsContainer =
Core::ActionManager::actionContainer(Core::Constants::M_TOOLS);
toolsContainer->insertGroup(Core::Constants::G_TOOLS_OPTIONS,
Constants::G_TOOLS_DIFF);
Core::ActionContainer *toolsContainer
= Core::ActionManager::actionContainer(Core::Constants::M_TOOLS);
toolsContainer->insertGroup(Core::Constants::G_TOOLS_OPTIONS, Constants::G_TOOLS_DIFF);
QAction *diffAction = new QAction(tr("Diff..."), this);
Core::Command *diffCommand = Core::ActionManager::registerAction(diffAction,
"DiffEditor.Diff");
Core::Command *diffCommand = Core::ActionManager::registerAction(diffAction, "DiffEditor.Diff");
connect(diffAction, &QAction::triggered, this, &DiffEditorPlugin::diff);
toolsContainer->addAction(diffCommand, Constants::G_TOOLS_DIFF);
@@ -175,8 +154,7 @@ bool DiffEditorPlugin::initialize(const QStringList &arguments, QString *errorMe
}
void DiffEditorPlugin::extensionsInitialized()
{
}
{ }
void DiffEditorPlugin::diff()
{
@@ -193,24 +171,19 @@ void DiffEditorPlugin::diff()
return;
const QString documentId = QLatin1String("Diff ") + fileName1
+ QLatin1String(", ") + fileName2;
const QString documentId = QLatin1String("Diff ") + fileName1 + QLatin1String(", ") + fileName2;
QString title = tr("Diff \"%1\", \"%2\"").arg(fileName1).arg(fileName2);
Core::IDocument *const document = DiffEditorManager::findOrCreate(documentId, title);
auto const document
= qobject_cast<DiffEditorDocument *>(DiffEditorManager::findOrCreate(documentId, title));
if (!document)
return;
DiffEditorController *controller = DiffEditorManager::controller(document);
if (!controller)
controller = new FileDiffController(document, fileName1, fileName2);
QTC_ASSERT(controller, return);
if (!controller->reloader()) {
SimpleDiffEditorReloader *reloader =
new SimpleDiffEditorReloader(fileName1, fileName2);
controller->setReloader(reloader);
}
Core::EditorManager::activateEditorForDocument(document);
controller->requestReload();
document->reload();
}
} // namespace Internal

View File

@@ -44,9 +44,6 @@ class DiffEditorPlugin : public ExtensionSystem::IPlugin
Q_PLUGIN_METADATA(IID "org.qt-project.Qt.QtCreatorPlugin" FILE "DiffEditor.json")
public:
DiffEditorPlugin();
~DiffEditorPlugin();
bool initialize(const QStringList &arguments, QString *errorMessage = 0);
void extensionsInitialized();

View File

@@ -1,97 +0,0 @@
/****************************************************************************
**
** Copyright (C) 2015 The Qt Company Ltd.
** Contact: http://www.qt.io/licensing
**
** This file is part of Qt Creator.
**
** 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 The Qt Company. For licensing terms and
** conditions see http://www.qt.io/terms-conditions. For further information
** use the contact form at http://www.qt.io/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 or version 3 as published by the Free
** Software Foundation and appearing in the file LICENSE.LGPLv21 and
** LICENSE.LGPLv3 included in the packaging of this file. Please review the
** following information to ensure the GNU Lesser General Public License
** requirements will be met: https://www.gnu.org/licenses/lgpl.html and
** http://www.gnu.org/licenses/old-licenses/lgpl-2.1.html.
**
** In addition, as a special exception, The Qt Company gives you certain additional
** rights. These rights are described in The Qt Company LGPL Exception
** version 1.1, included in the file LGPL_EXCEPTION.txt in this package.
**
****************************************************************************/
#include "diffeditorreloader.h"
#include "diffeditorcontroller.h"
namespace DiffEditor {
DiffEditorReloader::DiffEditorReloader()
: m_controller(0),
m_reloading(false)
{
}
DiffEditorReloader::~DiffEditorReloader()
{
}
DiffEditorController *DiffEditorReloader::controller() const
{
return m_controller;
}
void DiffEditorReloader::setController(DiffEditorController *controller)
{
if (m_controller == controller)
return; // nothing changes
if (m_controller) {
disconnect(m_controller, SIGNAL(ignoreWhitespaceChanged(bool)),
this, SLOT(requestReload()));
disconnect(m_controller, SIGNAL(contextLinesNumberChanged(int)),
this, SLOT(requestReload()));
}
m_controller = controller;
if (m_controller) {
connect(m_controller, &DiffEditorController::ignoreWhitespaceChanged,
this, &DiffEditorReloader::requestReload);
connect(m_controller, &DiffEditorController::contextLinesNumberChanged,
this, &DiffEditorReloader::requestReload);
}
}
void DiffEditorReloader::requestReload()
{
if (m_reloading)
return;
if (!m_controller)
return;
m_reloading = true;
reload();
}
bool DiffEditorReloader::isReloading() const
{
return m_reloading;
}
void DiffEditorReloader::reloadFinished()
{
m_reloading = false;
}
} // namespace DiffEditor

View File

@@ -1,74 +0,0 @@
/****************************************************************************
**
** Copyright (C) 2015 The Qt Company Ltd.
** Contact: http://www.qt.io/licensing
**
** This file is part of Qt Creator.
**
** 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 The Qt Company. For licensing terms and
** conditions see http://www.qt.io/terms-conditions. For further information
** use the contact form at http://www.qt.io/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 or version 3 as published by the Free
** Software Foundation and appearing in the file LICENSE.LGPLv21 and
** LICENSE.LGPLv3 included in the packaging of this file. Please review the
** following information to ensure the GNU Lesser General Public License
** requirements will be met: https://www.gnu.org/licenses/lgpl.html and
** http://www.gnu.org/licenses/old-licenses/lgpl-2.1.html.
**
** In addition, as a special exception, The Qt Company gives you certain additional
** rights. These rights are described in The Qt Company LGPL Exception
** version 1.1, included in the file LGPL_EXCEPTION.txt in this package.
**
****************************************************************************/
#ifndef DIFFEDITORRELOADER_H
#define DIFFEDITORRELOADER_H
#include "diffeditor_global.h"
#include <QObject>
namespace DiffEditor {
class DiffEditorController;
class DIFFEDITOR_EXPORT DiffEditorReloader : public QObject
{
Q_OBJECT
public:
DiffEditorReloader();
~DiffEditorReloader();
bool isReloading() const;
DiffEditorController *controller() const;
public slots:
void requestReload();
protected:
// reloadFinished() should be called
// inside reload() (for synchronous reload)
// or later (for asynchronous reload)
virtual void reload() = 0;
void setController(DiffEditorController *controller);
protected slots:
void reloadFinished();
private:
DiffEditorController *m_controller;
bool m_reloading;
friend class DiffEditorController;
};
} // namespace DiffEditor
#endif // DIFFEDITORRELOADER_H

View File

@@ -263,11 +263,10 @@ ChunkData DiffUtils::calculateOriginalData(const QList<Diff> &leftDiffList,
return chunkData;
}
FileData DiffUtils::calculateContextData(const ChunkData &originalData,
int contextLinesNumber,
FileData DiffUtils::calculateContextData(const ChunkData &originalData, int contextLineCount,
int joinChunkThreshold)
{
if (contextLinesNumber < 0)
if (contextLineCount < 0)
return FileData(originalData);
FileData fileData;
@@ -292,9 +291,9 @@ FileData DiffUtils::calculateContextData(const ChunkData &originalData,
const bool last = i == originalData.rows.count(); // includes last line?
const int firstLine = first
? 0 : equalRowStart + contextLinesNumber;
? 0 : equalRowStart + contextLineCount;
const int lastLine = last
? originalData.rows.count() : i - contextLinesNumber;
? originalData.rows.count() : i - contextLineCount;
if (firstLine < lastLine - joinChunkThreshold) {
for (int j = firstLine; j < lastLine; j++) {

View File

@@ -138,7 +138,7 @@ public:
static ChunkData calculateOriginalData(const QList<Diff> &leftDiffList,
const QList<Diff> &rightDiffList);
static FileData calculateContextData(const ChunkData &originalData,
int contextLinesNumber,
int contextLineCount,
int joinChunkThreshold = 1);
static QString makePatchLine(const QChar &startLineCharacter,
const QString &textLine,

View File

@@ -40,6 +40,9 @@
namespace DiffEditor {
namespace Internal {
IDiffView::IDiffView(QObject *parent) : QObject(parent), m_supportsSync(false)
{ }
QIcon IDiffView::icon() const
{
return m_icon;
@@ -50,6 +53,16 @@ QString IDiffView::toolTip() const
return m_toolTip;
}
bool IDiffView::supportsSync() const
{
return m_supportsSync;
}
QString IDiffView::syncToolTip() const
{
return m_syncToolTip;
}
Core::Id IDiffView::id() const
{
return m_id;
@@ -70,6 +83,16 @@ void IDiffView::setId(const Core::Id &id)
m_id = id;
}
void IDiffView::setSupportsSync(bool sync)
{
m_supportsSync = sync;
}
void IDiffView::setSyncToolTip(const QString &text)
{
m_syncToolTip = text;
}
UnifiedView::UnifiedView() : m_widget(0)
{
setId(UNIFIED_VIEW_ID);
@@ -79,15 +102,49 @@ UnifiedView::UnifiedView() : m_widget(0)
QWidget *UnifiedView::widget()
{
if (!m_widget)
if (!m_widget) {
m_widget = new UnifiedDiffEditorWidget;
connect(m_widget, &UnifiedDiffEditorWidget::currentDiffFileIndexChanged,
this, &UnifiedView::currentDiffFileIndexChanged);
}
return m_widget;
}
void UnifiedView::setDiffEditorGuiController(DiffEditorGuiController *controller)
void UnifiedView::setDocument(DiffEditorDocument *document)
{
QTC_ASSERT(m_widget, return);
m_widget->setDiffEditorGuiController(controller);
m_widget->setDocument(document);
}
void UnifiedView::beginOperation()
{
QTC_ASSERT(m_widget, return);
m_widget->saveState();
m_widget->clear(tr("Waiting for data..."));
}
void UnifiedView::setDiff(const QList<FileData> &diffFileList, const QString &workingDirectory)
{
QTC_ASSERT(m_widget, return);
m_widget->setDiff(diffFileList, workingDirectory);
}
void UnifiedView::endOperation(bool success)
{
Q_UNUSED(success);
QTC_ASSERT(m_widget, return);
m_widget->restoreState();
}
void UnifiedView::setCurrentDiffFileIndex(int index)
{
QTC_ASSERT(m_widget, return);
m_widget->setCurrentDiffFileIndex(index);
}
void UnifiedView::setSync(bool sync)
{
Q_UNUSED(sync);
}
SideBySideView::SideBySideView() : m_widget(0)
@@ -96,19 +153,56 @@ SideBySideView::SideBySideView() : m_widget(0)
setIcon(QIcon(QLatin1String(":/diffeditor/images/sidebysidediff.png")));
setToolTip(QCoreApplication::translate("DiffEditor::SideBySideView",
"Switch to Side By Side Diff Editor"));
setSupportsSync(true);
setSyncToolTip(tr("Synchronize Horizontal Scroll Bars"));
}
QWidget *SideBySideView::widget()
{
if (!m_widget)
if (!m_widget) {
m_widget = new SideBySideDiffEditorWidget;
connect(m_widget, &SideBySideDiffEditorWidget::currentDiffFileIndexChanged,
this, &SideBySideView::currentDiffFileIndexChanged);
}
return m_widget;
}
void SideBySideView::setDiffEditorGuiController(DiffEditorGuiController *controller)
void SideBySideView::setDocument(DiffEditorDocument *document)
{
QTC_ASSERT(m_widget, return);
m_widget->setDiffEditorGuiController(controller);
m_widget->setDocument(document);
}
void SideBySideView::beginOperation()
{
QTC_ASSERT(m_widget, return);
m_widget->saveState();
m_widget->clear(tr("Waiting for data..."));
}
void SideBySideView::setCurrentDiffFileIndex(int index)
{
QTC_ASSERT(m_widget, return);
m_widget->setCurrentDiffFileIndex(index);
}
void SideBySideView::setDiff(const QList<FileData> &diffFileList, const QString &workingDirectory)
{
QTC_ASSERT(m_widget, return);
m_widget->setDiff(diffFileList, workingDirectory);
}
void SideBySideView::endOperation(bool success)
{
Q_UNUSED(success);
QTC_ASSERT(m_widget, return);
m_widget->restoreState();
}
void SideBySideView::setSync(bool sync)
{
QTC_ASSERT(m_widget, return);
m_widget->setHorizontalSync(sync);
}
} // namespace Internal

View File

@@ -35,59 +35,101 @@
#include <QIcon>
#include <QString>
#include <QObject>
#include <QWidget>
namespace DiffEditor {
class DiffEditorController;
class FileData;
namespace Internal {
class DiffEditorGuiController;
class DiffEditorDocument;
class SideBySideDiffEditorWidget;
class UnifiedDiffEditorWidget;
const char SIDE_BY_SIDE_VIEW_ID[] = "SideBySide";
const char UNIFIED_VIEW_ID[] = "Unified";
class IDiffView
class IDiffView : public QObject
{
Q_OBJECT
public:
IDiffView() { }
virtual ~IDiffView() { }
explicit IDiffView(QObject *parent = 0);
QIcon icon() const;
QString toolTip() const;
bool supportsSync() const;
QString syncToolTip() const;
Core::Id id() const;
virtual QWidget *widget() = 0;
virtual void setDiffEditorGuiController(DiffEditorGuiController *controller) = 0;
virtual void setDocument(DiffEditorDocument *document) = 0;
virtual void beginOperation() = 0;
virtual void setCurrentDiffFileIndex(int index) = 0;
virtual void setDiff(const QList<FileData> &diffFileList, const QString &workingDirectory) = 0;
virtual void endOperation(bool success) = 0;
virtual void setSync(bool) = 0;
signals:
void currentDiffFileIndexChanged(int index);
protected:
void setIcon(const QIcon &icon);
void setToolTip(const QString &toolTip);
void setId(const Core::Id &id);
void setSupportsSync(bool sync);
void setSyncToolTip(const QString &text);
private:
QIcon m_icon;
QString m_toolTip;
Core::Id m_id;
bool m_supportsSync;
QString m_syncToolTip;
};
class UnifiedView : public IDiffView {
class UnifiedView : public IDiffView
{
Q_OBJECT
public:
UnifiedView();
QWidget *widget();
void setDiffEditorGuiController(DiffEditorGuiController *controller);
void setDocument(DiffEditorDocument *document);
void beginOperation();
void setCurrentDiffFileIndex(int index);
void setDiff(const QList<FileData> &diffFileList, const QString &workingDirectory);
void endOperation(bool success);
void setSync(bool sync);
private:
UnifiedDiffEditorWidget *m_widget;
};
class SideBySideView : public IDiffView {
class SideBySideView : public IDiffView
{
Q_OBJECT
public:
SideBySideView();
QWidget *widget();
void setDiffEditorGuiController(DiffEditorGuiController *controller);
void setDocument(DiffEditorDocument *document);
void beginOperation();
void setCurrentDiffFileIndex(int index);
void setDiff(const QList<FileData> &diffFileList, const QString &workingDirectory);
void endOperation(bool success);
void setSync(bool sync);
private:
SideBySideDiffEditorWidget *m_widget;

View File

@@ -30,8 +30,8 @@
#include "sidebysidediffeditorwidget.h"
#include "selectabletexteditorwidget.h"
#include "diffeditorguicontroller.h"
#include "diffutils.h"
#include "diffeditorcontroller.h"
#include "diffeditorconstants.h"
#include <coreplugin/editormanager/editormanager.h>
@@ -133,11 +133,11 @@ public:
return TextEditorWidget::firstVisibleBlock();
}
// void setDocuments(const QList<QPair<DiffFileInfo, QString> > &documents);
void saveState();
void restoreState();
public slots:
void setDisplaySettings(const DisplaySettings &ds);
void saveStateRequested();
void restoreStateRequested();
signals:
void jumpToOriginalFileRequested(int diffFileIndex,
@@ -311,20 +311,20 @@ SideDiffEditorWidget::SideDiffEditorWidget(QWidget *parent)
// baseTextDocument()->setSyntaxHighlighter(m_highlighter);
}
void SideDiffEditorWidget::saveStateRequested()
void SideDiffEditorWidget::saveState()
{
if (!m_state.isNull())
return;
m_state = saveState();
m_state = SelectableTextEditorWidget::saveState();
}
void SideDiffEditorWidget::restoreStateRequested()
void SideDiffEditorWidget::restoreState()
{
if (m_state.isNull())
return;
restoreState(m_state);
SelectableTextEditorWidget::restoreState(m_state);
m_state.clear();
}
@@ -443,10 +443,8 @@ int SideDiffEditorWidget::blockNumberForFileIndex(int fileIndex) const
int SideDiffEditorWidget::fileIndexForBlockNumber(int blockNumber) const
{
QMap<int, DiffFileInfo>::const_iterator it
= m_fileInfo.constBegin();
QMap<int, DiffFileInfo>::const_iterator itEnd
= m_fileInfo.constEnd();
QMap<int, DiffFileInfo>::const_iterator it = m_fileInfo.constBegin();
QMap<int, DiffFileInfo>::const_iterator itEnd = m_fileInfo.constEnd();
int i = -1;
while (it != itEnd) {
@@ -484,7 +482,6 @@ void SideDiffEditorWidget::clearAll(const QString &message)
setExtraSelections(TextEditorWidget::OtherSelection,
QList<QTextEdit::ExtraSelection>());
setPlainText(message);
// m_highlighter->setDocuments(QList<QPair<DiffFileInfo, QString> >());
}
void SideDiffEditorWidget::clearAllData()
@@ -497,12 +494,7 @@ void SideDiffEditorWidget::clearAllData()
m_separators.clear();
setSelections(QMap<int, QList<DiffSelection> >());
}
/*
void SideDiffEditorWidget::setDocuments(const QList<QPair<DiffFileInfo, QString> > &documents)
{
m_highlighter->setDocuments(documents);
}
*/
void SideDiffEditorWidget::scrollContentsBy(int dx, int dy)
{
SelectableTextEditorWidget::scrollContentsBy(dx, dy);
@@ -751,10 +743,10 @@ void SideDiffEditorWidget::drawCollapsedBlockPopup(QPainter &painter,
SideBySideDiffEditorWidget::SideBySideDiffEditorWidget(QWidget *parent)
: QWidget(parent)
, m_guiController(0)
, m_controller(0)
, m_document(0)
, m_ignoreCurrentIndexChange(false)
, m_foldingBlocker(false)
, m_horizontalSync(false)
, m_contextMenuFileIndex(-1)
, m_contextMenuChunkIndex(-1)
{
@@ -815,8 +807,6 @@ SideBySideDiffEditorWidget::SideBySideDiffEditorWidget(QWidget *parent)
connect(m_rightEditor, &QPlainTextEdit::cursorPositionChanged,
this, &SideBySideDiffEditorWidget::rightCursorPositionChanged);
// connect(m_rightEditor->document()->documentLayout(), SIGNAL(documentSizeChanged(QSizeF)),
// this, SLOT(rightDocumentSizeChanged()));
m_splitter = new MiniSplitter(this);
m_splitter->addWidget(m_leftEditor);
@@ -825,83 +815,42 @@ SideBySideDiffEditorWidget::SideBySideDiffEditorWidget(QWidget *parent)
l->setMargin(0);
l->addWidget(m_splitter);
setFocusProxy(m_rightEditor);
clear(tr("No controller"));
}
void SideBySideDiffEditorWidget::setDiffEditorGuiController(
DiffEditorGuiController *controller)
void SideBySideDiffEditorWidget::setDocument(DiffEditorDocument *document)
{
if (m_guiController == controller)
return;
if (m_guiController) {
disconnect(m_controller, &DiffEditorController::cleared,
this, &SideBySideDiffEditorWidget::clearAll);
disconnect(m_controller, &DiffEditorController::diffFilesChanged,
this, &SideBySideDiffEditorWidget::setDiff);
disconnect(m_controller, &DiffEditorController::saveStateRequested,
m_leftEditor, &SideDiffEditorWidget::saveStateRequested);
disconnect(m_controller, &DiffEditorController::saveStateRequested,
m_rightEditor, &SideDiffEditorWidget::saveStateRequested);
disconnect(m_controller, &DiffEditorController::restoreStateRequested,
m_leftEditor, &SideDiffEditorWidget::restoreStateRequested);
disconnect(m_controller, &DiffEditorController::restoreStateRequested,
m_rightEditor, &SideDiffEditorWidget::restoreStateRequested);
disconnect(m_guiController, &DiffEditorGuiController::currentDiffFileIndexChanged,
this, &SideBySideDiffEditorWidget::setCurrentDiffFileIndex);
clearAll(tr("No controller"));
}
m_guiController = controller;
m_controller = 0;
if (m_guiController) {
m_controller = m_guiController->controller();
connect(m_controller, &DiffEditorController::cleared,
this, &SideBySideDiffEditorWidget::clearAll);
connect(m_controller, &DiffEditorController::diffFilesChanged,
this, &SideBySideDiffEditorWidget::setDiff);
connect(m_controller, &DiffEditorController::saveStateRequested,
m_leftEditor, &SideDiffEditorWidget::saveStateRequested);
connect(m_controller, &DiffEditorController::saveStateRequested,
m_rightEditor, &SideDiffEditorWidget::saveStateRequested);
connect(m_controller, &DiffEditorController::restoreStateRequested,
m_leftEditor, &SideDiffEditorWidget::restoreStateRequested);
connect(m_controller, &DiffEditorController::restoreStateRequested,
m_rightEditor, &SideDiffEditorWidget::restoreStateRequested);
connect(m_guiController, &DiffEditorGuiController::currentDiffFileIndexChanged,
this, &SideBySideDiffEditorWidget::setCurrentDiffFileIndex);
setDiff(m_controller->diffFiles(), m_controller->workingDirectory());
setCurrentDiffFileIndex(m_guiController->currentDiffFileIndex());
}
m_document = document;
}
void SideBySideDiffEditorWidget::clear(const QString &message)
{
const bool oldIgnore = m_ignoreCurrentIndexChange;
m_ignoreCurrentIndexChange = true;
setDiff(QList<FileData>(), QString());
m_leftEditor->clearAll(message);
m_rightEditor->clearAll(message);
m_ignoreCurrentIndexChange = oldIgnore;
}
void SideBySideDiffEditorWidget::clearAll(const QString &message)
{
setDiff(QList<FileData>(), QString());
clear(message);
}
void SideBySideDiffEditorWidget::setDiff(const QList<FileData> &diffFileList,
const QString &workingDirectory)
{
Q_UNUSED(workingDirectory)
const bool oldIgnore = m_ignoreCurrentIndexChange;
m_ignoreCurrentIndexChange = true;
m_leftEditor->clear();
m_rightEditor->clear();
m_contextFileData = diffFileList;
showDiff();
if (m_contextFileData.isEmpty()) {
const QString msg = tr("No difference");
m_leftEditor->setPlainText(msg);
m_rightEditor->setPlainText(msg);
} else {
showDiff();
}
m_ignoreCurrentIndexChange = oldIgnore;
}
void SideBySideDiffEditorWidget::setCurrentDiffFileIndex(int diffFileIndex)
@@ -928,14 +877,29 @@ void SideBySideDiffEditorWidget::setCurrentDiffFileIndex(int diffFileIndex)
m_ignoreCurrentIndexChange = oldIgnore;
}
void SideBySideDiffEditorWidget::setHorizontalSync(bool sync)
{
m_horizontalSync = sync;
rightHSliderChanged();
}
void SideBySideDiffEditorWidget::saveState()
{
m_leftEditor->saveState();
m_rightEditor->saveState();
}
void SideBySideDiffEditorWidget::restoreState()
{
m_leftEditor->restoreState();
m_rightEditor->restoreState();
}
void SideBySideDiffEditorWidget::showDiff()
{
clear(tr("No difference"));
QMap<int, QList<DiffSelection> > leftFormats;
QMap<int, QList<DiffSelection> > rightFormats;
// QList<QPair<DiffFileInfo, QString> > leftDocs, rightDocs;
QString leftTexts, rightTexts;
int blockNumber = 0;
QChar separator = QLatin1Char('\n');
@@ -1065,16 +1029,11 @@ void SideBySideDiffEditorWidget::showDiff()
rightText.replace(QLatin1Char('\r'), QLatin1Char(' '));
leftTexts += leftText;
rightTexts += rightText;
// leftDocs.append(qMakePair(contextFileData.leftFileInfo, leftText));
// rightDocs.append(qMakePair(contextFileData.rightFileInfo, rightText));
}
if (leftTexts.isEmpty() && rightTexts.isEmpty())
return;
// m_leftEditor->setDocuments(leftDocs);
// m_rightEditor->setDocuments(rightDocs);
const bool oldIgnore = m_ignoreCurrentIndexChange;
m_ignoreCurrentIndexChange = true;
m_leftEditor->clear();
@@ -1085,63 +1044,6 @@ void SideBySideDiffEditorWidget::showDiff()
m_leftEditor->setSelections(leftFormats);
m_rightEditor->setSelections(rightFormats);
/*
QTextBlock leftBlock = m_leftEditor->document()->firstBlock();
QTextBlock rightBlock = m_rightEditor->document()->firstBlock();
for (int i = 0; i < m_contextFileData.count(); i++) {
const FileData &contextFileData = m_contextFileData.at(i);
leftBlock = leftBlock.next();
rightBlock = rightBlock.next();
for (int j = 0; j < contextFileData.chunks.count(); j++) {
ChunkData chunkData = contextFileData.chunks.at(j);
if (chunkData.contextChunk) {
BaseTextDocumentLayout::setFoldingIndent(leftBlock, FILE_LEVEL);
BaseTextDocumentLayout::setFoldingIndent(rightBlock, FILE_LEVEL);
leftBlock = leftBlock.next();
rightBlock = rightBlock.next();
}
const int indent = chunkData.contextChunk ? CHUNK_LEVEL : FILE_LEVEL;
for (int k = 0; k < chunkData.rows.count(); k++) {
BaseTextDocumentLayout::setFoldingIndent(leftBlock, indent);
BaseTextDocumentLayout::setFoldingIndent(rightBlock, indent);
leftBlock = leftBlock.next();
rightBlock = rightBlock.next();
}
}
}
blockNumber = 0;
for (int i = 0; i < m_contextFileData.count(); i++) {
const FileData &contextFileData = m_contextFileData.at(i);
blockNumber++;
for (int j = 0; j < contextFileData.chunks.count(); j++) {
ChunkData chunkData = contextFileData.chunks.at(j);
if (chunkData.contextChunk) {
QTextBlock leftBlock = m_leftEditor->document()->findBlockByNumber(blockNumber);
BaseTextDocumentLayout::doFoldOrUnfold(leftBlock, false);
QTextBlock rightBlock = m_rightEditor->document()->findBlockByNumber(blockNumber);
BaseTextDocumentLayout::doFoldOrUnfold(rightBlock, false);
blockNumber++;
}
blockNumber += chunkData.rows.count();
}
}
m_foldingBlocker = true;
BaseTextDocumentLayout *leftLayout = qobject_cast<BaseTextDocumentLayout *>(m_leftEditor->document()->documentLayout());
if (leftLayout) {
leftLayout->requestUpdate();
leftLayout->emitDocumentSizeChanged();
}
BaseTextDocumentLayout *rightLayout = qobject_cast<BaseTextDocumentLayout *>(m_rightEditor->document()->documentLayout());
if (rightLayout) {
rightLayout->requestUpdate();
rightLayout->emitDocumentSizeChanged();
}
m_foldingBlocker = false;
*/
// m_leftEditor->updateFoldingHighlight(QPoint(-1, -1));
// m_rightEditor->updateFoldingHighlight(QPoint(-1, -1));
}
void SideBySideDiffEditorWidget::setFontSettings(
@@ -1212,10 +1114,10 @@ void SideBySideDiffEditorWidget::slotRightJumpToOriginalFileRequested(
void SideBySideDiffEditorWidget::jumpToOriginalFile(const QString &fileName,
int lineNumber, int columnNumber)
{
if (!m_controller)
if (!m_document)
return;
const QDir dir(m_controller->workingDirectory());
const QDir dir(m_document->baseDirectory());
const QString absoluteFileName = dir.absoluteFilePath(fileName);
QFileInfo fi(absoluteFileName);
if (fi.exists() && !fi.isDir())
@@ -1249,7 +1151,7 @@ void SideBySideDiffEditorWidget::slotLeftContextMenuRequested(QMenu *menu,
if (m_contextMenuChunkIndex >= fileData.chunks.count())
return;
m_controller->requestChunkActions(menu, diffFileIndex, chunkIndex);
m_document->chunkActionsRequested(menu, diffFileIndex, chunkIndex);
if (fileData.leftFileInfo.fileName == fileData.rightFileInfo.fileName)
return;
@@ -1284,33 +1186,22 @@ void SideBySideDiffEditorWidget::slotRightContextMenuRequested(QMenu *menu,
if (m_contextMenuChunkIndex >= fileData.chunks.count())
return;
m_controller->requestChunkActions(menu, diffFileIndex, chunkIndex);
m_document->chunkActionsRequested(menu, diffFileIndex, chunkIndex);
revertAction->setEnabled(true);
}
void SideBySideDiffEditorWidget::slotSendChunkToCodePaster()
{
if (!m_controller)
if (!m_document)
return;
if (m_contextMenuFileIndex < 0 || m_contextMenuChunkIndex < 0)
return;
if (m_contextMenuFileIndex >= m_contextFileData.count())
return;
const FileData fileData = m_contextFileData.at(m_contextMenuFileIndex);
if (m_contextMenuChunkIndex >= fileData.chunks.count())
return;
const QString patch = m_controller->makePatch(false);
const QString patch = m_document->makePatch(m_contextMenuFileIndex, m_contextMenuChunkIndex, false);
if (patch.isEmpty())
return;
// Retrieve service by soft dependency.
QObject *pasteService =
ExtensionSystem::PluginManager::getObjectByClassName(
QObject *pasteService= ExtensionSystem::PluginManager::getObjectByClassName(
QLatin1String("CodePaster::CodePasterService"));
if (pasteService) {
QMetaObject::invokeMethod(pasteService, "postText",
@@ -1334,18 +1225,10 @@ void SideBySideDiffEditorWidget::slotRevertChunk()
void SideBySideDiffEditorWidget::patch(bool revert)
{
if (!m_controller)
return;
if (m_contextMenuFileIndex < 0 || m_contextMenuChunkIndex < 0)
return;
if (m_contextMenuFileIndex >= m_contextFileData.count())
if (!m_document)
return;
const FileData fileData = m_contextFileData.at(m_contextMenuFileIndex);
if (m_contextMenuChunkIndex >= fileData.chunks.count())
return;
const QString title = revert ? tr("Revert Chunk") : tr("Apply Chunk");
const QString question = revert
@@ -1358,50 +1241,46 @@ void SideBySideDiffEditorWidget::patch(bool revert)
return;
}
const int strip = m_controller->workingDirectory().isEmpty() ? -1 : 0;
const int strip = m_document->baseDirectory().isEmpty() ? -1 : 0;
const QString fileName = revert
? fileData.rightFileInfo.fileName
: fileData.leftFileInfo.fileName;
const QString workingDirectory = m_controller->workingDirectory().isEmpty()
const QString workingDirectory = m_document->baseDirectory().isEmpty()
? QFileInfo(fileName).absolutePath()
: m_controller->workingDirectory();
: m_document->baseDirectory();
const QString patch = m_controller->makePatch(revert);
const QString patch = m_document->makePatch(m_contextMenuFileIndex, m_contextMenuChunkIndex, revert);
if (patch.isEmpty())
return;
if (PatchTool::runPatch(EditorManager::defaultTextCodec()->fromUnicode(patch),
workingDirectory, strip, revert))
m_controller->requestReload();
workingDirectory, strip, revert))
m_document->reload();
}
void SideBySideDiffEditorWidget::leftVSliderChanged()
{
m_rightEditor->verticalScrollBar()->setValue(
m_leftEditor->verticalScrollBar()->value());
m_rightEditor->verticalScrollBar()->setValue(m_leftEditor->verticalScrollBar()->value());
}
void SideBySideDiffEditorWidget::rightVSliderChanged()
{
m_leftEditor->verticalScrollBar()->setValue(
m_rightEditor->verticalScrollBar()->value());
m_leftEditor->verticalScrollBar()->setValue(m_rightEditor->verticalScrollBar()->value());
}
void SideBySideDiffEditorWidget::leftHSliderChanged()
{
if (!m_guiController || m_guiController->horizontalScrollBarSynchronization())
m_rightEditor->horizontalScrollBar()->setValue(
m_leftEditor->horizontalScrollBar()->value());
if (m_horizontalSync)
m_rightEditor->horizontalScrollBar()->setValue(m_leftEditor->horizontalScrollBar()->value());
}
void SideBySideDiffEditorWidget::rightHSliderChanged()
{
if (!m_guiController || m_guiController->horizontalScrollBarSynchronization())
m_leftEditor->horizontalScrollBar()->setValue(
m_rightEditor->horizontalScrollBar()->value());
if (m_horizontalSync)
m_leftEditor->horizontalScrollBar()->setValue(m_rightEditor->horizontalScrollBar()->value());
}
void SideBySideDiffEditorWidget::leftCursorPositionChanged()
@@ -1409,17 +1288,13 @@ void SideBySideDiffEditorWidget::leftCursorPositionChanged()
leftVSliderChanged();
leftHSliderChanged();
if (!m_guiController)
return;
if (m_ignoreCurrentIndexChange)
return;
const bool oldIgnore = m_ignoreCurrentIndexChange;
m_ignoreCurrentIndexChange = true;
m_guiController->setCurrentDiffFileIndex(
m_leftEditor->fileIndexForBlockNumber(
m_leftEditor->textCursor().blockNumber()));
emit currentDiffFileIndexChanged(
m_leftEditor->fileIndexForBlockNumber(m_leftEditor->textCursor().blockNumber()));
m_ignoreCurrentIndexChange = oldIgnore;
}
@@ -1428,161 +1303,16 @@ void SideBySideDiffEditorWidget::rightCursorPositionChanged()
rightVSliderChanged();
rightHSliderChanged();
if (!m_guiController)
return;
if (m_ignoreCurrentIndexChange)
return;
const bool oldIgnore = m_ignoreCurrentIndexChange;
m_ignoreCurrentIndexChange = true;
m_guiController->setCurrentDiffFileIndex(
m_rightEditor->fileIndexForBlockNumber(
m_rightEditor->textCursor().blockNumber()));
emit currentDiffFileIndexChanged(
m_rightEditor->fileIndexForBlockNumber(m_rightEditor->textCursor().blockNumber()));
m_ignoreCurrentIndexChange = oldIgnore;
}
#if 0
void SideBySideDiffEditorWidget::leftDocumentSizeChanged()
{
synchronizeFoldings(m_leftEditor, m_rightEditor);
}
void SideBySideDiffEditorWidget::rightDocumentSizeChanged()
{
synchronizeFoldings(m_rightEditor, m_leftEditor);
}
/* Special version of that method (original: BaseTextDocumentLayout::doFoldOrUnfold())
The hack lies in fact, that when unfolding all direct sub-blocks are made visible,
while some of them need to stay invisible (i.e. unfolded chunk lines)
*/
static void doFoldOrUnfold(SideDiffEditorWidget *editor, const QTextBlock &block, bool unfold)
{
if (!BaseTextDocumentLayout::canFold(block))
return;
QTextBlock b = block.next();
int indent = BaseTextDocumentLayout::foldingIndent(block);
while (b.isValid() && BaseTextDocumentLayout::foldingIndent(b) > indent && (unfold || b.next().isValid())) {
if (unfold && editor->isChunkLine(b.blockNumber()) && !BaseTextDocumentLayout::isFolded(b)) {
b.setVisible(false);
b.setLineCount(0);
} else {
b.setVisible(unfold);
b.setLineCount(unfold ? qMax(1, b.layout()->lineCount()) : 0);
}
if (unfold) { // do not unfold folded sub-blocks
if (BaseTextDocumentLayout::isFolded(b) && b.next().isValid()) {
int jndent = BaseTextDocumentLayout::foldingIndent(b);
b = b.next();
while (b.isValid() && BaseTextDocumentLayout::foldingIndent(b) > jndent)
b = b.next();
continue;
}
}
b = b.next();
}
BaseTextDocumentLayout::setFolded(block, !unfold);
}
void SideBySideDiffEditorWidget::synchronizeFoldings(SideDiffEditorWidget *source, SideDiffEditorWidget *destination)
{
if (m_foldingBlocker)
return;
m_foldingBlocker = true;
QTextBlock sourceBlock = source->document()->firstBlock();
QTextBlock destinationBlock = destination->document()->firstBlock();
while (sourceBlock.isValid() && destinationBlock.isValid()) {
if (BaseTextDocumentLayout::canFold(sourceBlock)) {
const bool isSourceFolded = BaseTextDocumentLayout::isFolded(sourceBlock);
const bool isDestinationFolded = BaseTextDocumentLayout::isFolded(destinationBlock);
if (isSourceFolded != isDestinationFolded) {
if (source->isFileLine(sourceBlock.blockNumber())) {
doFoldOrUnfold(source, sourceBlock, !isSourceFolded);
doFoldOrUnfold(destination, destinationBlock, !isSourceFolded);
} else {
if (isSourceFolded) { // we fold the destination (shrinking)
QTextBlock previousSource = sourceBlock.previous(); // skippedLines
QTextBlock previousDestination = destinationBlock.previous(); // skippedLines
if (source->isChunkLine(previousSource.blockNumber())) {
QTextBlock firstVisibleDestinationBlock = destination->firstVisibleBlock();
QTextBlock firstDestinationBlock = destination->document()->firstBlock();
BaseTextDocumentLayout::doFoldOrUnfold(destinationBlock, !isSourceFolded);
BaseTextDocumentLayout::setFoldingIndent(sourceBlock, CHUNK_LEVEL);
BaseTextDocumentLayout::setFoldingIndent(destinationBlock, CHUNK_LEVEL);
previousSource.setVisible(true);
previousSource.setLineCount(1);
previousDestination.setVisible(true);
previousDestination.setLineCount(1);
sourceBlock.setVisible(false);
sourceBlock.setLineCount(0);
destinationBlock.setVisible(false);
destinationBlock.setLineCount(0);
BaseTextDocumentLayout::setFolded(previousSource, true);
BaseTextDocumentLayout::setFolded(previousDestination, true);
if (firstVisibleDestinationBlock == destinationBlock) {
/*
The following hack is completely crazy. That's the only way to scroll 1 line up
in case destinationBlock was the top visible block.
There is no need to scroll the source since this is in sync anyway
(leftSliderChanged(), rightSliderChanged())
*/
destination->verticalScrollBar()->setValue(destination->verticalScrollBar()->value() - 1);
destination->verticalScrollBar()->setValue(destination->verticalScrollBar()->value() + 1);
if (firstVisibleDestinationBlock.previous() == firstDestinationBlock) {
/*
Even more crazy case: the destinationBlock was the first top visible block.
*/
destination->verticalScrollBar()->setValue(0);
}
}
}
} else { // we unfold the destination (expanding)
if (source->isChunkLine(sourceBlock.blockNumber())) {
QTextBlock nextSource = sourceBlock.next();
QTextBlock nextDestination = destinationBlock.next();
BaseTextDocumentLayout::doFoldOrUnfold(destinationBlock, !isSourceFolded);
BaseTextDocumentLayout::setFoldingIndent(nextSource, FILE_LEVEL);
BaseTextDocumentLayout::setFoldingIndent(nextDestination, FILE_LEVEL);
sourceBlock.setVisible(false);
sourceBlock.setLineCount(0);
destinationBlock.setVisible(false);
destinationBlock.setLineCount(0);
BaseTextDocumentLayout::setFolded(nextSource, false);
BaseTextDocumentLayout::setFolded(nextDestination, false);
}
}
}
break; // only one should be synchronized
}
}
sourceBlock = sourceBlock.next();
destinationBlock = destinationBlock.next();
}
BaseTextDocumentLayout *sourceLayout = qobject_cast<BaseTextDocumentLayout *>(source->document()->documentLayout());
if (sourceLayout) {
sourceLayout->requestUpdate();
sourceLayout->emitDocumentSizeChanged();
}
QWidget *ea = source->extraArea();
if (ea->contentsRect().contains(ea->mapFromGlobal(QCursor::pos())))
source->updateFoldingHighlight(source->mapFromGlobal(QCursor::pos()));
BaseTextDocumentLayout *destinationLayout = qobject_cast<BaseTextDocumentLayout *>(destination->document()->documentLayout());
if (destinationLayout) {
destinationLayout->requestUpdate();
destinationLayout->emitDocumentSizeChanged();
}
m_foldingBlocker = false;
}
#endif
} // namespace Internal
} // namespace DiffEditor

View File

@@ -32,7 +32,7 @@
#define SIDEBYSIDEDIFFEDITORWIDGET_H
#include "differ.h"
#include "diffeditorcontroller.h"
#include "diffeditordocument.h"
#include <QWidget>
#include <QTextCharFormat>
@@ -60,16 +60,23 @@ class SideBySideDiffEditorWidget : public QWidget
public:
explicit SideBySideDiffEditorWidget(QWidget *parent = 0);
void setDiffEditorGuiController(Internal::DiffEditorGuiController *controller);
void setDocument(DiffEditorDocument *document);
private slots:
void clear(const QString &message = QString());
void clearAll(const QString &message = QString());
void setDiff(const QList<FileData> &diffFileList,
const QString &workingDirectory);
void setCurrentDiffFileIndex(int diffFileIndex);
void setHorizontalSync(bool sync);
void saveState();
void restoreState();
void clear(const QString &message = QString());
signals:
void currentDiffFileIndexChanged(int index);
private slots:
void setFontSettings(const TextEditor::FontSettings &fontSettings);
void slotLeftJumpToOriginalFileRequested(int diffFileIndex,
int lineNumber, int columnNumber);
@@ -98,16 +105,16 @@ private:
int lineNumber, int columnNumber);
void patch(bool revert);
DiffEditorGuiController *m_guiController;
DiffEditorController *m_controller;
DiffEditorDocument *m_document;
SideDiffEditorWidget *m_leftEditor;
SideDiffEditorWidget *m_rightEditor;
QSplitter *m_splitter;
QList<FileData> m_contextFileData; // ultimate data to be shown, contextLinesNumber taken into account
QList<FileData> m_contextFileData; // ultimate data to be shown, contextLineCount taken into account
bool m_ignoreCurrentIndexChange;
bool m_foldingBlocker;
bool m_horizontalSync;
int m_contextMenuFileIndex;
int m_contextMenuChunkIndex;

View File

@@ -29,9 +29,10 @@
****************************************************************************/
#include "unifieddiffeditorwidget.h"
#include "diffeditorguicontroller.h"
#include "diffutils.h"
#include "diffeditorconstants.h"
#include "diffeditordocument.h"
#include "diffutils.h"
#include <QPlainTextEdit>
#include <QVBoxLayout>
@@ -75,8 +76,7 @@ namespace Internal {
UnifiedDiffEditorWidget::UnifiedDiffEditorWidget(QWidget *parent)
: SelectableTextEditorWidget("DiffEditor.UnifiedDiffEditor", parent)
, m_guiController(0)
, m_controller(0)
, m_document(0)
, m_ignoreCurrentIndexChange(false)
, m_contextMenuFileIndex(-1)
, m_contextMenuChunkIndex(-1)
@@ -102,70 +102,35 @@ UnifiedDiffEditorWidget::UnifiedDiffEditorWidget(QWidget *parent)
this, &UnifiedDiffEditorWidget::setFontSettings);
setFontSettings(TextEditorSettings::fontSettings());
clear(tr("No controller"));
clear(tr("No document"));
connect(this, &QPlainTextEdit::cursorPositionChanged,
this, &UnifiedDiffEditorWidget::slotCursorPositionChangedInEditor);
}
void UnifiedDiffEditorWidget::setDiffEditorGuiController(
DiffEditorGuiController *controller)
void UnifiedDiffEditorWidget::setDocument(DiffEditorDocument *document)
{
if (m_guiController == controller)
return;
if (m_guiController) {
disconnect(m_controller, &DiffEditorController::cleared,
this, &UnifiedDiffEditorWidget::clearAll);
disconnect(m_controller, &DiffEditorController::diffFilesChanged,
this, &UnifiedDiffEditorWidget::setDiff);
disconnect(m_controller, &DiffEditorController::saveStateRequested,
this, &UnifiedDiffEditorWidget::saveStateRequested);
disconnect(m_controller, &DiffEditorController::restoreStateRequested,
this, &UnifiedDiffEditorWidget::restoreStateRequested);
disconnect(m_guiController, &DiffEditorGuiController::currentDiffFileIndexChanged,
this, &UnifiedDiffEditorWidget::setCurrentDiffFileIndex);
clear(tr("No controller"));
}
m_guiController = controller;
m_controller = 0;
if (m_guiController) {
m_controller = m_guiController->controller();
connect(m_controller, &DiffEditorController::cleared,
this, &UnifiedDiffEditorWidget::clearAll);
connect(m_controller, &DiffEditorController::diffFilesChanged,
this, &UnifiedDiffEditorWidget::setDiff);
connect(m_controller, &DiffEditorController::saveStateRequested,
this, &UnifiedDiffEditorWidget::saveStateRequested);
connect(m_controller, &DiffEditorController::restoreStateRequested,
this, &UnifiedDiffEditorWidget::restoreStateRequested);
connect(m_guiController, &DiffEditorGuiController::currentDiffFileIndexChanged,
this, &UnifiedDiffEditorWidget::setCurrentDiffFileIndex);
setDiff(m_controller->diffFiles(), m_controller->workingDirectory());
setCurrentDiffFileIndex(m_guiController->currentDiffFileIndex());
}
m_document = document;
}
void UnifiedDiffEditorWidget::saveStateRequested()
void UnifiedDiffEditorWidget::saveState()
{
if (!m_state.isNull())
return;
m_state = saveState();
m_state = SelectableTextEditorWidget::saveState();
}
void UnifiedDiffEditorWidget::restoreStateRequested()
void UnifiedDiffEditorWidget::restoreState()
{
if (m_state.isNull())
return;
restoreState(m_state);
const bool oldIgnore = m_ignoreCurrentIndexChange;
m_ignoreCurrentIndexChange = true;
SelectableTextEditorWidget::restoreState(m_state);
m_state.clear();
m_ignoreCurrentIndexChange = oldIgnore;
}
void UnifiedDiffEditorWidget::setDisplaySettings(const DisplaySettings &ds)
@@ -187,16 +152,12 @@ void UnifiedDiffEditorWidget::setFontSettings(const FontSettings &fontSettings)
void UnifiedDiffEditorWidget::slotCursorPositionChangedInEditor()
{
if (!m_guiController)
return;
if (m_ignoreCurrentIndexChange)
return;
const bool oldIgnore = m_ignoreCurrentIndexChange;
m_ignoreCurrentIndexChange = true;
m_guiController->setCurrentDiffFileIndex(fileIndexForBlockNumber(
textCursor().blockNumber()));
emit currentDiffFileIndexChanged(fileIndexForBlockNumber(textCursor().blockNumber()));
m_ignoreCurrentIndexChange = oldIgnore;
}
@@ -230,7 +191,7 @@ void UnifiedDiffEditorWidget::addContextMenuActions(QMenu *menu,
int diffFileIndex,
int chunkIndex)
{
if (!m_controller)
if (!m_document || !m_document->controller())
return;
menu->addSeparator();
@@ -260,7 +221,7 @@ void UnifiedDiffEditorWidget::addContextMenuActions(QMenu *menu,
if (m_contextMenuChunkIndex >= fileData.chunks.count())
return;
m_controller->requestChunkActions(menu, diffFileIndex, chunkIndex);
m_document->chunkActionsRequested(menu, diffFileIndex, chunkIndex);
revertAction->setEnabled(true);
@@ -272,20 +233,10 @@ void UnifiedDiffEditorWidget::addContextMenuActions(QMenu *menu,
void UnifiedDiffEditorWidget::slotSendChunkToCodePaster()
{
if (!m_controller)
if (!m_document)
return;
if (m_contextMenuFileIndex < 0 || m_contextMenuChunkIndex < 0)
return;
if (m_contextMenuFileIndex >= m_contextFileData.count())
return;
const FileData fileData = m_contextFileData.at(m_contextMenuFileIndex);
if (m_contextMenuChunkIndex >= fileData.chunks.count())
return;
const QString patch = m_controller->makePatch(false);
const QString patch = m_document->makePatch(m_contextMenuFileIndex, m_contextMenuChunkIndex, false);
if (patch.isEmpty())
return;
@@ -316,17 +267,7 @@ void UnifiedDiffEditorWidget::slotRevertChunk()
void UnifiedDiffEditorWidget::patch(bool revert)
{
if (!m_controller)
return;
if (m_contextMenuFileIndex < 0 || m_contextMenuChunkIndex < 0)
return;
if (m_contextMenuFileIndex >= m_contextFileData.count())
return;
const FileData fileData = m_contextFileData.at(m_contextMenuFileIndex);
if (m_contextMenuChunkIndex >= fileData.chunks.count())
if (!m_document)
return;
const QString title = revert ? tr("Revert Chunk") : tr("Apply Chunk");
@@ -339,24 +280,24 @@ void UnifiedDiffEditorWidget::patch(bool revert)
return;
}
const int strip = m_controller->workingDirectory().isEmpty() ? -1 : 0;
const int strip = m_document->baseDirectory().isEmpty() ? -1 : 0;
const FileData fileData = m_contextFileData.at(m_contextMenuFileIndex);
const QString fileName = revert
? fileData.rightFileInfo.fileName
: fileData.leftFileInfo.fileName;
const QString workingDirectory = m_controller->workingDirectory().isEmpty()
const QString workingDirectory = m_document->baseDirectory().isEmpty()
? QFileInfo(fileName).absolutePath()
: m_controller->workingDirectory();
: m_document->baseDirectory();
const QString patch = m_controller->makePatch(revert);
const QString patch = m_document->makePatch(m_contextMenuFileIndex, m_contextMenuChunkIndex, revert);
if (patch.isEmpty())
return;
if (PatchTool::runPatch(
EditorManager::defaultTextCodec()->fromUnicode(patch),
workingDirectory, strip, revert))
m_controller->requestReload();
if (PatchTool::runPatch(EditorManager::defaultTextCodec()->fromUnicode(patch),
workingDirectory, strip, revert))
m_document->reload();
}
void UnifiedDiffEditorWidget::clear(const QString &message)
@@ -372,16 +313,11 @@ void UnifiedDiffEditorWidget::clear(const QString &message)
const bool oldIgnore = m_ignoreCurrentIndexChange;
m_ignoreCurrentIndexChange = true;
SelectableTextEditorWidget::clear();
setDiff(QList<FileData>(), QString());
setPlainText(message);
m_ignoreCurrentIndexChange = oldIgnore;
}
void UnifiedDiffEditorWidget::clearAll(const QString &message)
{
setDiff(QList<FileData>(), QString());
clear(message);
}
QString UnifiedDiffEditorWidget::lineNumber(int blockNumber) const
{
QString lineNumberString;
@@ -618,8 +554,6 @@ QString UnifiedDiffEditorWidget::showChunk(const ChunkData &chunkData,
void UnifiedDiffEditorWidget::showDiff()
{
clear(tr("No difference"));
QString diffText;
int blockNumber = 0;
@@ -669,8 +603,10 @@ void UnifiedDiffEditorWidget::showDiff()
}
if (diffText.isEmpty())
if (diffText.isEmpty()) {
setPlainText(tr("No difference."));
return;
}
diffText.replace(QLatin1Char('\r'), QLatin1Char(' '));
const bool oldIgnore = m_ignoreCurrentIndexChange;
@@ -783,10 +719,10 @@ void UnifiedDiffEditorWidget::jumpToOriginalFile(const QString &fileName,
int lineNumber,
int columnNumber)
{
if (!m_controller)
if (!m_document)
return;
const QDir dir(m_controller->workingDirectory());
const QDir dir(m_document->baseDirectory());
const QString absoluteFileName = dir.absoluteFilePath(fileName);
QFileInfo fi(absoluteFileName);
if (fi.exists() && !fi.isDir())

View File

@@ -47,9 +47,8 @@ QT_END_NAMESPACE
namespace DiffEditor {
namespace Internal { class DiffEditorGuiController; }
class ChunkData;
class DiffEditorController;
class FileData;
namespace Internal {
@@ -60,7 +59,19 @@ class UnifiedDiffEditorWidget : public SelectableTextEditorWidget
public:
UnifiedDiffEditorWidget(QWidget *parent = 0);
void setDiffEditorGuiController(Internal::DiffEditorGuiController *controller);
void setDocument(DiffEditorDocument *document);
void setDiff(const QList<FileData> &diffFileList,
const QString &workingDirectory);
void setCurrentDiffFileIndex(int diffFileIndex);
void saveState();
void restoreState();
void clear(const QString &message = QString());
signals:
void currentDiffFileIndexChanged(int index);
public slots:
void setDisplaySettings(const TextEditor::DisplaySettings &ds);
@@ -72,13 +83,6 @@ protected:
int lineNumberDigits() const;
private slots:
void clear(const QString &message = QString());
void clearAll(const QString &message = QString());
void setDiff(const QList<FileData> &diffFileList,
const QString &workingDirectory);
void setCurrentDiffFileIndex(int diffFileIndex);
void setFontSettings(const TextEditor::FontSettings &fontSettings);
void slotCursorPositionChangedInEditor();
@@ -86,8 +90,6 @@ private slots:
void slotSendChunkToCodePaster();
void slotApplyChunk();
void slotRevertChunk();
void saveStateRequested();
void restoreStateRequested();
private:
void setLeftLineNumber(int blockNumber, int lineNumber);
@@ -114,8 +116,7 @@ private:
int chunkIndex);
void patch(bool revert);
Internal::DiffEditorGuiController *m_guiController;
DiffEditorController *m_controller;
DiffEditorDocument *m_document;
// block number, visual line number.
QMap<int, int> m_leftLineNumbers;
@@ -132,7 +133,7 @@ private:
QMap<int, QPair<int, int> > m_chunkInfo;
QList<FileData> m_contextFileData; // ultimate data to be shown
// contextLinesNumber taken into account
// contextLineCount taken into account
QTextCharFormat m_fileLineFormat;
QTextCharFormat m_chunkLineFormat;