From b2b8b867d68e95e9421a15549c1a7bb83949186d Mon Sep 17 00:00:00 2001 From: Tobias Hunger Date: Fri, 30 Jan 2015 16:59:25 +0100 Subject: [PATCH] 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 Reviewed-by: Jarek Kobus --- src/plugins/diffeditor/diffeditor.cpp | 444 +++++++----- src/plugins/diffeditor/diffeditor.h | 44 +- src/plugins/diffeditor/diffeditor.pro | 4 - src/plugins/diffeditor/diffeditor.qbs | 4 - .../diffeditor/diffeditorcontroller.cpp | 284 ++------ src/plugins/diffeditor/diffeditorcontroller.h | 89 +-- src/plugins/diffeditor/diffeditordocument.cpp | 267 ++++++-- src/plugins/diffeditor/diffeditordocument.h | 43 +- .../diffeditor/diffeditorguicontroller.cpp | 143 ---- .../diffeditor/diffeditorguicontroller.h | 78 --- src/plugins/diffeditor/diffeditormanager.cpp | 30 +- src/plugins/diffeditor/diffeditormanager.h | 9 +- src/plugins/diffeditor/diffeditorplugin.cpp | 89 +-- src/plugins/diffeditor/diffeditorplugin.h | 3 - src/plugins/diffeditor/diffeditorreloader.cpp | 97 --- src/plugins/diffeditor/diffeditorreloader.h | 74 -- src/plugins/diffeditor/diffutils.cpp | 9 +- src/plugins/diffeditor/diffutils.h | 2 +- src/plugins/diffeditor/diffview.cpp | 106 ++- src/plugins/diffeditor/diffview.h | 60 +- .../diffeditor/sidebysidediffeditorwidget.cpp | 410 ++--------- .../diffeditor/sidebysidediffeditorwidget.h | 25 +- .../diffeditor/unifieddiffeditorwidget.cpp | 132 +--- .../diffeditor/unifieddiffeditorwidget.h | 31 +- src/plugins/git/gitclient.cpp | 641 ++++++++---------- src/plugins/git/gitclient.h | 7 +- src/plugins/subversion/subversionclient.cpp | 121 ++-- src/plugins/subversion/subversionclient.h | 8 +- 28 files changed, 1306 insertions(+), 1948 deletions(-) delete mode 100644 src/plugins/diffeditor/diffeditorguicontroller.cpp delete mode 100644 src/plugins/diffeditor/diffeditorguicontroller.h delete mode 100644 src/plugins/diffeditor/diffeditorreloader.cpp delete mode 100644 src/plugins/diffeditor/diffeditorreloader.h diff --git a/src/plugins/diffeditor/diffeditor.cpp b/src/plugins/diffeditor/diffeditor.cpp index 1b63b8f5a60..8e2a0739490 100644 --- a/src/plugins/diffeditor/diffeditor.cpp +++ b/src/plugins/diffeditor/diffeditor.cpp @@ -31,7 +31,6 @@ #include "diffeditor.h" #include "diffeditorconstants.h" #include "diffeditordocument.h" -#include "diffeditorguicontroller.h" #include "diffview.h" #include @@ -62,7 +61,13 @@ #include 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() << sel); - } void DescriptionEditorWidget::handleCurrentContents() @@ -204,15 +208,23 @@ DiffEditor::DiffEditor(const QSharedPointer &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 &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(&QComboBox::activated), - this, &DiffEditor::entryActivated); + connect(m_entriesComboBox, static_cast(&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(&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(&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 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 &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 &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 diff --git a/src/plugins/diffeditor/diffeditor.h b/src/plugins/diffeditor/diffeditor.h index 3a10abdbab3..78134cc24ce 100644 --- a/src/plugins/diffeditor/diffeditor.h +++ b/src/plugins/diffeditor/diffeditor.h @@ -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 &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 m_document; DescriptionEditorWidget *m_descriptionWidget; QStackedWidget *m_stackedWidget; QVector 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 m_currentFileChunk; + int m_currentViewIndex; + int m_currentDiffFileIndex; + bool m_sync; + bool m_showDescription; + bool m_ignoreChanges; }; } // namespace Internal diff --git a/src/plugins/diffeditor/diffeditor.pro b/src/plugins/diffeditor/diffeditor.pro index dd591992fc3..b93d6ae9366 100644 --- a/src/plugins/diffeditor/diffeditor.pro +++ b/src/plugins/diffeditor/diffeditor.pro @@ -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 \ diff --git a/src/plugins/diffeditor/diffeditor.qbs b/src/plugins/diffeditor/diffeditor.qbs index 21a4600a485..7b2090c4de5 100644 --- a/src/plugins/diffeditor/diffeditor.qbs +++ b/src/plugins/diffeditor/diffeditor.qbs @@ -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", diff --git a/src/plugins/diffeditor/diffeditorcontroller.cpp b/src/plugins/diffeditor/diffeditorcontroller.cpp index e4bab7fc74a..6380dee25b2 100644 --- a/src/plugins/diffeditor/diffeditorcontroller.cpp +++ b/src/plugins/diffeditor/diffeditorcontroller.cpp @@ -30,227 +30,90 @@ #include "diffeditorconstants.h" #include "diffeditorcontroller.h" -#include "diffeditorreloader.h" +#include "diffeditordocument.h" #include -#include +#include -static const char settingsGroupC[] = "DiffEditor"; -static const char contextLineNumbersKeyC[] = "ContextLineNumbers"; -static const char ignoreWhitespaceKeyC[] = "IgnoreWhitespace"; +#include 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(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 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: "))) { - 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()); - m_clearMessage = message; - emit cleared(message); + return m_document->makePatch(m_diffFileIndex, m_chunkIndex, revert, addPrefix); } void DiffEditorController::setDiffFiles(const QList &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 diff --git a/src/plugins/diffeditor/diffeditorcontroller.h b/src/plugins/diffeditor/diffeditorcontroller.h index 08d4036ab4e..e54016eefbe 100644 --- a/src/plugins/diffeditor/diffeditorcontroller.h +++ b/src/plugins/diffeditor/diffeditorcontroller.h @@ -36,81 +36,60 @@ #include -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 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 &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 &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 &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 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 diff --git a/src/plugins/diffeditor/diffeditordocument.cpp b/src/plugins/diffeditor/diffeditordocument.cpp index 262e2e9c09a..0937a230e0d 100644 --- a/src/plugins/diffeditor/diffeditordocument.cpp +++ b/src/plugins/diffeditor/diffeditordocument.cpp @@ -32,33 +32,165 @@ #include "diffeditorconstants.h" #include "diffeditorcontroller.h" #include "diffeditormanager.h" -#include "diffeditorreloader.h" #include "diffutils.h" +#include +#include + #include #include #include #include +#include #include +#include + +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 &data, const QString &directory) +{ + m_diffFiles = data; + m_baseDirectory = directory; + emit documentChanged(); +} + +QList 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: "))) { + 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(), QString()); + setDescription(QString()); + blockSignals(blocked); +} + +void DiffEditorDocument::endReload(bool success) +{ + emit reloadFinished(success); } } // namespace Internal diff --git a/src/plugins/diffeditor/diffeditordocument.h b/src/plugins/diffeditor/diffeditordocument.h index bba9f635cf8..3efa024ddcc 100644 --- a/src/plugins/diffeditor/diffeditordocument.h +++ b/src/plugins/diffeditor/diffeditordocument.h @@ -31,6 +31,8 @@ #ifndef DIFFEDITORDOCUMENT_H #define DIFFEDITORDOCUMENT_H +#include "diffutils.h" + #include 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 &data, const QString &directory); + QList 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 m_diffFiles; + QString m_baseDirectory; + QString m_description; + int m_contextLineCount; + bool m_isContextLineCountForced; + bool m_ignoreWhitespace; + + friend class ::DiffEditor::DiffEditorController; }; } // namespace Internal diff --git a/src/plugins/diffeditor/diffeditorguicontroller.cpp b/src/plugins/diffeditor/diffeditorguicontroller.cpp deleted file mode 100644 index c2885fb83ee..00000000000 --- a/src/plugins/diffeditor/diffeditorguicontroller.cpp +++ /dev/null @@ -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 - -#include - -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 diff --git a/src/plugins/diffeditor/diffeditorguicontroller.h b/src/plugins/diffeditor/diffeditorguicontroller.h deleted file mode 100644 index 5c2eee87c0c..00000000000 --- a/src/plugins/diffeditor/diffeditorguicontroller.h +++ /dev/null @@ -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 - -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 diff --git a/src/plugins/diffeditor/diffeditormanager.cpp b/src/plugins/diffeditor/diffeditormanager.cpp index 06ec139e99e..41f6dc4ab0e 100644 --- a/src/plugins/diffeditor/diffeditormanager.cpp +++ b/src/plugins/diffeditor/diffeditormanager.cpp @@ -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 &editors) -{ - QMap editorsForDocument; - for (int i = 0; i < editors.count(); i++) { - DiffEditor *diffEditor = qobject_cast(editors.at(i)); - if (diffEditor) { - Core::IDocument *document = diffEditor->document(); - editorsForDocument[document]++; - } - } - QMapIterator 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( - 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(diffEditor->document()); diff --git a/src/plugins/diffeditor/diffeditormanager.h b/src/plugins/diffeditor/diffeditormanager.h index 2185da63033..30f7be03686 100644 --- a/src/plugins/diffeditor/diffeditormanager.h +++ b/src/plugins/diffeditor/diffeditormanager.h @@ -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 &editors); - -private: QMap m_idToDocument; + + friend class Internal::DiffEditorDocument; }; } // namespace DiffEditor diff --git a/src/plugins/diffeditor/diffeditorplugin.cpp b/src/plugins/diffeditor/diffeditorplugin.cpp index 4a980d99218..e87f8aaa900 100644 --- a/src/plugins/diffeditor/diffeditorplugin.cpp +++ b/src/plugins/diffeditor/diffeditorplugin.cpp @@ -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 @@ -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 diffList = differ.cleanupSemantics( - differ.diff(leftText, rightText)); + QList diffList = differ.cleanupSemantics(differ.diff(leftText, rightText)); QList leftDiffList; QList rightDiffList; @@ -109,15 +104,13 @@ void SimpleDiffEditorReloader::reload() QList outputLeftDiffList; QList outputRightDiffList; - if (controller()->isIgnoreWhitespace()) { - const QList leftIntermediate = - Differ::moveWhitespaceIntoEqualities(leftDiffList); - const QList rightIntermediate = - Differ::moveWhitespaceIntoEqualities(rightDiffList); - Differ::ignoreWhitespaceBetweenEqualities(leftIntermediate, - rightIntermediate, - &outputLeftDiffList, - &outputRightDiffList); + if (ignoreWhitespace()) { + const QList leftIntermediate + = Differ::moveWhitespaceIntoEqualities(leftDiffList); + const QList 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 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(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 diff --git a/src/plugins/diffeditor/diffeditorplugin.h b/src/plugins/diffeditor/diffeditorplugin.h index 6e2caa196ed..52a96e536d9 100644 --- a/src/plugins/diffeditor/diffeditorplugin.h +++ b/src/plugins/diffeditor/diffeditorplugin.h @@ -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(); diff --git a/src/plugins/diffeditor/diffeditorreloader.cpp b/src/plugins/diffeditor/diffeditorreloader.cpp deleted file mode 100644 index 9ae58051dda..00000000000 --- a/src/plugins/diffeditor/diffeditorreloader.cpp +++ /dev/null @@ -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 diff --git a/src/plugins/diffeditor/diffeditorreloader.h b/src/plugins/diffeditor/diffeditorreloader.h deleted file mode 100644 index 2858868f50d..00000000000 --- a/src/plugins/diffeditor/diffeditorreloader.h +++ /dev/null @@ -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 - -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 diff --git a/src/plugins/diffeditor/diffutils.cpp b/src/plugins/diffeditor/diffutils.cpp index d464e230b09..0e16becbdf6 100644 --- a/src/plugins/diffeditor/diffutils.cpp +++ b/src/plugins/diffeditor/diffutils.cpp @@ -263,11 +263,10 @@ ChunkData DiffUtils::calculateOriginalData(const QList &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++) { diff --git a/src/plugins/diffeditor/diffutils.h b/src/plugins/diffeditor/diffutils.h index f902ba484c0..f5f969c6d2f 100644 --- a/src/plugins/diffeditor/diffutils.h +++ b/src/plugins/diffeditor/diffutils.h @@ -138,7 +138,7 @@ public: static ChunkData calculateOriginalData(const QList &leftDiffList, const QList &rightDiffList); static FileData calculateContextData(const ChunkData &originalData, - int contextLinesNumber, + int contextLineCount, int joinChunkThreshold = 1); static QString makePatchLine(const QChar &startLineCharacter, const QString &textLine, diff --git a/src/plugins/diffeditor/diffview.cpp b/src/plugins/diffeditor/diffview.cpp index cc2478f9c1c..457fa5e2d12 100644 --- a/src/plugins/diffeditor/diffview.cpp +++ b/src/plugins/diffeditor/diffview.cpp @@ -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 &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 &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 diff --git a/src/plugins/diffeditor/diffview.h b/src/plugins/diffeditor/diffview.h index cf46b0f433f..1a972f3e406 100644 --- a/src/plugins/diffeditor/diffview.h +++ b/src/plugins/diffeditor/diffview.h @@ -35,59 +35,101 @@ #include #include +#include #include 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 &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 &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 &diffFileList, const QString &workingDirectory); + void endOperation(bool success); + + void setSync(bool sync); private: SideBySideDiffEditorWidget *m_widget; diff --git a/src/plugins/diffeditor/sidebysidediffeditorwidget.cpp b/src/plugins/diffeditor/sidebysidediffeditorwidget.cpp index b1a3b4d0bf4..9cac1f63040 100644 --- a/src/plugins/diffeditor/sidebysidediffeditorwidget.cpp +++ b/src/plugins/diffeditor/sidebysidediffeditorwidget.cpp @@ -30,8 +30,8 @@ #include "sidebysidediffeditorwidget.h" #include "selectabletexteditorwidget.h" -#include "diffeditorguicontroller.h" #include "diffutils.h" +#include "diffeditorcontroller.h" #include "diffeditorconstants.h" #include @@ -133,11 +133,11 @@ public: return TextEditorWidget::firstVisibleBlock(); } // void setDocuments(const QList > &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::const_iterator it - = m_fileInfo.constBegin(); - QMap::const_iterator itEnd - = m_fileInfo.constEnd(); + QMap::const_iterator it = m_fileInfo.constBegin(); + QMap::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()); setPlainText(message); -// m_highlighter->setDocuments(QList >()); } void SideDiffEditorWidget::clearAllData() @@ -497,12 +494,7 @@ void SideDiffEditorWidget::clearAllData() m_separators.clear(); setSelections(QMap >()); } -/* -void SideDiffEditorWidget::setDocuments(const QList > &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(), QString()); m_leftEditor->clearAll(message); m_rightEditor->clearAll(message); m_ignoreCurrentIndexChange = oldIgnore; } -void SideBySideDiffEditorWidget::clearAll(const QString &message) -{ - setDiff(QList(), QString()); - clear(message); -} - void SideBySideDiffEditorWidget::setDiff(const QList &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 > leftFormats; QMap > rightFormats; -// QList > 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(m_leftEditor->document()->documentLayout()); - if (leftLayout) { - leftLayout->requestUpdate(); - leftLayout->emitDocumentSizeChanged(); - } - BaseTextDocumentLayout *rightLayout = qobject_cast(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(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(destination->document()->documentLayout()); - if (destinationLayout) { - destinationLayout->requestUpdate(); - destinationLayout->emitDocumentSizeChanged(); - } - m_foldingBlocker = false; -} -#endif - } // namespace Internal } // namespace DiffEditor diff --git a/src/plugins/diffeditor/sidebysidediffeditorwidget.h b/src/plugins/diffeditor/sidebysidediffeditorwidget.h index bbf47ed8354..abfd25b9b2b 100644 --- a/src/plugins/diffeditor/sidebysidediffeditorwidget.h +++ b/src/plugins/diffeditor/sidebysidediffeditorwidget.h @@ -32,7 +32,7 @@ #define SIDEBYSIDEDIFFEDITORWIDGET_H #include "differ.h" -#include "diffeditorcontroller.h" +#include "diffeditordocument.h" #include #include @@ -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 &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 m_contextFileData; // ultimate data to be shown, contextLinesNumber taken into account + QList 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; diff --git a/src/plugins/diffeditor/unifieddiffeditorwidget.cpp b/src/plugins/diffeditor/unifieddiffeditorwidget.cpp index 31bd0961f87..458fb162863 100644 --- a/src/plugins/diffeditor/unifieddiffeditorwidget.cpp +++ b/src/plugins/diffeditor/unifieddiffeditorwidget.cpp @@ -29,9 +29,10 @@ ****************************************************************************/ #include "unifieddiffeditorwidget.h" -#include "diffeditorguicontroller.h" -#include "diffutils.h" + #include "diffeditorconstants.h" +#include "diffeditordocument.h" +#include "diffutils.h" #include #include @@ -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(), QString()); setPlainText(message); m_ignoreCurrentIndexChange = oldIgnore; } -void UnifiedDiffEditorWidget::clearAll(const QString &message) -{ - setDiff(QList(), 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()) diff --git a/src/plugins/diffeditor/unifieddiffeditorwidget.h b/src/plugins/diffeditor/unifieddiffeditorwidget.h index 6e50f354192..1366314930a 100644 --- a/src/plugins/diffeditor/unifieddiffeditorwidget.h +++ b/src/plugins/diffeditor/unifieddiffeditorwidget.h @@ -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 &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 &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 m_leftLineNumbers; @@ -132,7 +133,7 @@ private: QMap > m_chunkInfo; QList m_contextFileData; // ultimate data to be shown - // contextLinesNumber taken into account + // contextLineCount taken into account QTextCharFormat m_fileLineFormat; QTextCharFormat m_chunkLineFormat; diff --git a/src/plugins/git/gitclient.cpp b/src/plugins/git/gitclient.cpp index 42767f0d253..c59635bc47c 100644 --- a/src/plugins/git/gitclient.cpp +++ b/src/plugins/git/gitclient.cpp @@ -64,7 +64,6 @@ #include #include #include -#include #include #include @@ -103,341 +102,288 @@ static unsigned diffExecutionFlags() return HostOsInfo::isWindowsHost() ? unsigned(VcsBasePlugin::SuppressStdErrInLogWindow) : 0u; } -class GitDiffHandler : public QObject +///////////////////////////////////// + +class BaseController : public DiffEditorController { Q_OBJECT public: - GitDiffHandler(DiffEditorController *controller, const QString &workingDirectory); - - // index -> working tree - void diffFile(const QString &fileName); - // stagedFileNames: HEAD -> index - // unstagedFileNames: index -> working tree - void diffFiles(const QStringList &stagedFileNames, - const QStringList &unstagedFileNames); - // index -> working tree - void diffProjects(const QStringList &projectPaths); - // index -> working tree - void diffRepository(); - // branch HEAD -> working tree - void diffBranch(const QString &branchName); - // id^ -> id - void show(const QString &id); + BaseController(IDocument *document, const QString &dir); + ~BaseController(); + void runCommand(const QList &args, QTextCodec *codec = 0); private slots: - void slotShowDescriptionReceived(const QString &data); - void slotTextualDiffOutputReceived(const QString &contents); + virtual void processOutput(const QString &output); + +protected: + void processDiff(const QString &output); + QStringList addConfigurationArguments(const QStringList &args) const; + GitClient *gitClient() const; + QStringList addHeadWhenCommandInProgress() const; + + const QString m_directory; private: - void postCollectShowDescription(const QString &id); - void postCollectTextualDiffOutputUsingDiffCommand(const QStringList &arguments); - void postCollectTextualDiffOutputUsingDiffCommand(const QList &argumentsList); - void postCollectTextualDiffOutputUsingShowCommand(const QStringList &arguments); - void postCollectTextualDiffOutput(const QString &gitCommand, - const QList &argumentsList); - void addJob(VcsCommand *command, - const QString &gitCommand, - const QStringList &arguments); - QStringList addHeadWhenCommandInProgress() const; - int timeout() const; - QProcessEnvironment processEnvironment() const; - FileName gitPath() const; - - QPointer m_controller; - const QString m_workingDirectory; - GitClient *m_gitClient; - const QString m_waitMessage; - - QString m_id; + VcsCommand *m_command; }; -GitDiffHandler::GitDiffHandler(DiffEditorController *controller, - const QString &workingDirectory) - : m_controller(controller), - m_workingDirectory(workingDirectory), - m_gitClient(GitPlugin::instance()->gitClient()), - m_waitMessage(tr("Waiting for data...")) +BaseController::BaseController(IDocument *document, const QString &dir) : + DiffEditorController(document), + m_directory(dir), + m_command(0) +{ } + +BaseController::~BaseController() { + if (m_command) + m_command->cancel(); } -void GitDiffHandler::diffFile(const QString &fileName) +void BaseController::runCommand(const QList &args, QTextCodec *codec) { - postCollectTextualDiffOutputUsingDiffCommand(addHeadWhenCommandInProgress() - << QLatin1String("--") - << fileName); -} - -void GitDiffHandler::diffFiles(const QStringList &stagedFileNames, - const QStringList &unstagedFileNames) -{ - QList arguments; - - if (!stagedFileNames.isEmpty()) { - QStringList stagedArguments; - stagedArguments << QLatin1String("--cached"); - stagedArguments << QLatin1String("--"); - stagedArguments << stagedFileNames; - arguments << stagedArguments; + if (m_command) { + m_command->disconnect(); + m_command->cancel(); } - if (!unstagedFileNames.isEmpty()) { - QStringList unstagedArguments = addHeadWhenCommandInProgress(); - unstagedArguments << QLatin1String("--"); - unstagedArguments << unstagedFileNames; - arguments << unstagedArguments; + m_command = new VcsCommand(gitClient()->gitExecutable(), m_directory, gitClient()->processEnvironment()); + m_command->setCodec(codec ? codec : EditorManager::defaultTextCodec()); + connect(m_command, &VcsCommand::output, this, &BaseController::processOutput); + connect(m_command, &VcsCommand::finished, this, &BaseController::reloadFinished); + m_command->addFlags(diffExecutionFlags()); + + foreach (const QStringList &arg, args) { + QTC_ASSERT(!arg.isEmpty(), continue); + + m_command->addJob(arg, GitPlugin::instance()->settings().intValue(GitSettings::timeoutKey)); } - postCollectTextualDiffOutputUsingDiffCommand(arguments); + m_command->execute(); } -void GitDiffHandler::diffProjects(const QStringList &projectPaths) +void BaseController::processDiff(const QString &output) { - postCollectTextualDiffOutputUsingDiffCommand(addHeadWhenCommandInProgress() - << QLatin1String("--") - << projectPaths); + m_command = 0; + + bool ok; + QList fileDataList = DiffUtils::readPatch(output, &ok); + setDiffFiles(fileDataList, m_directory); } -void GitDiffHandler::diffRepository() +QStringList BaseController::addConfigurationArguments(const QStringList &args) const { - postCollectTextualDiffOutputUsingDiffCommand(addHeadWhenCommandInProgress()); + QTC_ASSERT(!args.isEmpty(), return args); + + QStringList realArgs; + realArgs << args.at(0); + realArgs << QLatin1String("-m"); // show diff agains parents instead of merge commits + realArgs << QLatin1String("--first-parent"); // show only first parent + if (ignoreWhitespace()) + realArgs << QLatin1String("--ignore-space-change"); + realArgs << QLatin1String("--unified=") + QString::number(contextLineCount()); + realArgs << QLatin1String("--src-prefix=a/") << QLatin1String("--dst-prefix=b/"); + realArgs << args.mid(1); + + return realArgs; } -void GitDiffHandler::diffBranch(const QString &branchName) +void BaseController::processOutput(const QString &output) { - postCollectTextualDiffOutputUsingDiffCommand(addHeadWhenCommandInProgress() - << branchName); + processDiff(output); } -void GitDiffHandler::show(const QString &id) +GitClient *BaseController::gitClient() const { - m_id = id; - postCollectShowDescription(id); + return GitPlugin::instance()->gitClient(); } -void GitDiffHandler::postCollectShowDescription(const QString &id) -{ - if (m_controller.isNull()) { - deleteLater(); - return; - } - - m_controller->requestSaveState(); - m_controller->clear(m_waitMessage); - auto command = new VcsCommand(gitPath(), m_workingDirectory, processEnvironment()); - command->setCodec(m_gitClient->encoding(m_workingDirectory, - "i18n.commitEncoding")); - connect(command, &VcsCommand::output, this, &GitDiffHandler::slotShowDescriptionReceived); - QStringList arguments; - arguments << QLatin1String("show") - << QLatin1String("-s") - << QLatin1String(noColorOption) - << QLatin1String(decorateOption) - << id; - command->addJob(arguments, timeout()); - command->execute(); -} - -void GitDiffHandler::slotShowDescriptionReceived(const QString &description) -{ - if (m_controller.isNull()) { - deleteLater(); - return; - } - - postCollectTextualDiffOutputUsingShowCommand(QStringList() - << QLatin1String("--format=format:") // omit header, already generated - << QLatin1String("-M") - << QLatin1String("-C") - << QLatin1String(noColorOption) - << QLatin1String(decorateOption) - << m_id); - - // need to be called after postCollectDiffOutput(), since it clears the description - m_controller->setDescription( - m_gitClient->extendedShowDescription(m_workingDirectory, - description)); -} - -void GitDiffHandler::addJob(VcsCommand *command, - const QString &gitCommand, - const QStringList &arguments) -{ - QStringList args; - args << gitCommand; - args << QLatin1String("-m"); // show diff agains parents instead of merge commits - args << QLatin1String("--first-parent"); // show only first parent - if (m_controller->isIgnoreWhitespace()) - args << QLatin1String("--ignore-space-change"); - args << QLatin1String("--unified=") + QString::number( - m_controller->contextLinesNumber()); - args << QLatin1String("--src-prefix=a/") << QLatin1String("--dst-prefix=b/"); - args << arguments; - command->addJob(args, timeout()); -} - -QStringList GitDiffHandler::addHeadWhenCommandInProgress() const +QStringList BaseController::addHeadWhenCommandInProgress() const { QStringList args; // This is workaround for lack of support for merge commits and resolving conflicts, // we compare the current state of working tree to the HEAD of current branch // instead of showing unsupported combined diff format. - GitClient::CommandInProgress commandInProgress = m_gitClient->checkCommandInProgress(m_workingDirectory); + GitClient::CommandInProgress commandInProgress = gitClient()->checkCommandInProgress(m_directory); if (commandInProgress != GitClient::NoCommand) args << QLatin1String(HEAD); return args; } -void GitDiffHandler::postCollectTextualDiffOutputUsingDiffCommand(const QStringList &arguments) -{ - postCollectTextualDiffOutputUsingDiffCommand(QList() << arguments); -} - -void GitDiffHandler::postCollectTextualDiffOutputUsingDiffCommand(const QList &argumentsList) -{ - postCollectTextualDiffOutput(QLatin1String("diff"), argumentsList); -} - -void GitDiffHandler::postCollectTextualDiffOutputUsingShowCommand(const QStringList &arguments) -{ - postCollectTextualDiffOutput(QLatin1String("show"), QList() << arguments); -} - -void GitDiffHandler::postCollectTextualDiffOutput(const QString &gitCommand, const QList &argumentsList) -{ - if (m_controller.isNull()) { - deleteLater(); - return; - } - - m_controller->requestSaveState(); - m_controller->clear(m_waitMessage); - auto command = new VcsCommand(gitPath(), m_workingDirectory, processEnvironment()); - command->setCodec(EditorManager::defaultTextCodec()); - connect(command, &VcsCommand::output, this, &GitDiffHandler::slotTextualDiffOutputReceived); - command->addFlags(diffExecutionFlags()); - - for (int i = 0; i < argumentsList.count(); i++) - addJob(command, gitCommand, argumentsList.at(i)); - - command->execute(); -} - -void GitDiffHandler::slotTextualDiffOutputReceived(const QString &contents) -{ - if (m_controller.isNull()) { - deleteLater(); - return; - } - - bool ok; - QList fileDataList = DiffUtils::readPatch(contents, &ok); - m_controller->setDiffFiles(fileDataList, m_workingDirectory); - m_controller->requestRestoreState(); - deleteLater(); -} - -int GitDiffHandler::timeout() const -{ - return m_gitClient->settings()->intValue(GitSettings::timeoutKey); -} - -QProcessEnvironment GitDiffHandler::processEnvironment() const -{ - return m_gitClient->processEnvironment(); -} - -FileName GitDiffHandler::gitPath() const -{ - return m_gitClient->gitExecutable(); -} - -///////////////////////////////////// - -class GitDiffEditorReloader : public DiffEditorReloader +class RepositoryDiffController : public BaseController { Q_OBJECT public: - enum DiffType { - DiffRepository, - DiffFile, - DiffFileList, - DiffProjectList, - DiffBranch, - DiffShow - }; + RepositoryDiffController(IDocument *document, const QString &dir) : + BaseController(document, dir) + { } - GitDiffEditorReloader(); - void setWorkingDirectory(const QString &workingDir) { - m_workingDirectory = workingDir; - } - void setDiffType(DiffType type) { m_diffType = type; } - void setFileName(const QString &fileName) { m_fileName = fileName; } - void setFileList(const QStringList &stagedFiles, - const QStringList &unstagedFiles) { - m_stagedFiles = stagedFiles; - m_unstagedFiles = unstagedFiles; - } - void setProjectList(const QStringList &projectFiles) { - m_projectFiles = projectFiles; - } - void setBranchName(const QString &branchName) { - m_branchName = branchName; - } - void setId(const QString &id) { m_id = id; } - void setDisplayName(const QString &displayName) { - m_displayName = displayName; - } + void reload(); +}; +void RepositoryDiffController::reload() +{ + QStringList args; + args << QLatin1String("diff"); + args.append(addHeadWhenCommandInProgress()); + runCommand(QList() << addConfigurationArguments(args)); +} + +class FileDiffController : public BaseController +{ + Q_OBJECT +public: + FileDiffController(IDocument *document, const QString &dir, const QString &fileName) : + BaseController(document, dir), + m_fileName(fileName) + { } -protected: void reload(); private: - GitClient *m_gitClient; - - QString m_workingDirectory; - DiffType m_diffType; - QString m_fileName; - QStringList m_stagedFiles; - QStringList m_unstagedFiles; - QStringList m_projectFiles; - QString m_branchName; - QString m_id; - QString m_displayName; + const QString m_fileName; }; -GitDiffEditorReloader::GitDiffEditorReloader() - : m_gitClient(GitPlugin::instance()->gitClient()) +void FileDiffController::reload() { + QStringList args; + args << QLatin1String("diff"); + args.append(addHeadWhenCommandInProgress()); + args << QLatin1String("--") << m_fileName; + runCommand(QList() << addConfigurationArguments(args)); } -void GitDiffEditorReloader::reload() +class FileListDiffController : public BaseController { - auto handler = new GitDiffHandler(controller(), m_workingDirectory); - connect(handler, &GitDiffHandler::destroyed, this, &GitDiffEditorReloader::reloadFinished); + Q_OBJECT +public: + FileListDiffController(IDocument *document, const QString &dir, + const QStringList &stagedFiles, const QStringList &unstagedFiles) : + BaseController(document, dir), + m_stagedFiles(stagedFiles), + m_unstagedFiles(unstagedFiles) + { } - switch (m_diffType) { - case DiffRepository: - handler->diffRepository(); - break; - case DiffFile: - handler->diffFile(m_fileName); - break; - case DiffFileList: - handler->diffFiles(m_stagedFiles, m_unstagedFiles); - break; - case DiffProjectList: - handler->diffProjects(m_projectFiles); - break; - case DiffBranch: - handler->diffBranch(m_branchName); - break; - case DiffShow: - handler->show(m_id); - break; - default: - break; + void reload(); + +private: + const QStringList m_stagedFiles; + const QStringList m_unstagedFiles; +}; + +void FileListDiffController::reload() +{ + QList argLists; + if (!m_stagedFiles.isEmpty()) { + QStringList stagedArgs; + stagedArgs << QLatin1String("diff") << QLatin1String("--cached") << QLatin1String("--") + << m_stagedFiles; + argLists << addConfigurationArguments(stagedArgs); + } + + if (!m_unstagedFiles.isEmpty()) { + QStringList unstagedArgs; + unstagedArgs << QLatin1String("diff") << addHeadWhenCommandInProgress() + << QLatin1String("--") << m_unstagedFiles; + argLists << addConfigurationArguments(unstagedArgs); + } + + if (!argLists.isEmpty()) + runCommand(argLists); +} + +class ProjectDiffController : public BaseController +{ + Q_OBJECT +public: + ProjectDiffController(IDocument *document, const QString &dir, + const QStringList &projectPaths) : + BaseController(document, dir), + m_projectPaths(projectPaths) + { } + + void reload(); + +private: + const QStringList m_projectPaths; +}; + +void ProjectDiffController::reload() +{ + QStringList args; + args << QLatin1String("diff") << addHeadWhenCommandInProgress() + << QLatin1String("--") << m_projectPaths; + runCommand(QList() << addConfigurationArguments(args)); +} + +class BranchDiffController : public BaseController +{ + Q_OBJECT +public: + BranchDiffController(IDocument *document, const QString &dir, + const QString &branch) : + BaseController(document, dir), + m_branch(branch) + { } + + void reload(); + +private: + const QString m_branch; +}; + +void BranchDiffController::reload() +{ + QStringList args; + args << QLatin1String("diff") << addHeadWhenCommandInProgress() << m_branch; + runCommand(QList() << addConfigurationArguments(args)); +} + +class ShowController : public BaseController +{ + Q_OBJECT +public: + ShowController(IDocument *document, const QString &dir, const QString &id) : + BaseController(document, dir), + m_id(id), + m_state(Idle) + { } + + void reload(); + void processOutput(const QString &output); + +private: + const QString m_id; + enum State { Idle, GettingDescription, GettingDiff }; + State m_state; +}; + +void ShowController::reload() +{ + QTC_ASSERT(m_state == Idle, return); + + QStringList args; + args << QLatin1String("show") << QLatin1String("-s") << QLatin1String(noColorOption) + << QLatin1String(decorateOption) << m_id; + m_state = GettingDescription; + runCommand(QList() << args, gitClient()->encoding(m_directory, "i18n.commitEncoding")); +} + +void ShowController::processOutput(const QString &output) +{ + QTC_ASSERT(m_state != Idle, return); + if (m_state == GettingDescription) { + setDescription(gitClient()->extendedShowDescription(m_directory, output)); + + QStringList args; + args << QLatin1String("show") << QLatin1String("--format=format:") // omit header, already generated + << QLatin1String("-M") << QLatin1String("-C") << QLatin1String(noColorOption) + << QLatin1String(decorateOption) << m_id; + m_state = GettingDiff; + runCommand(QList() << addConfigurationArguments(args)); + } else if (m_state == GettingDiff) { + m_state = Idle; + processDiff(output); } } @@ -735,39 +681,6 @@ VcsBaseEditorWidget *GitClient::findExistingVCSEditor(const char *registerDynami return rc; } -GitDiffEditorReloader *GitClient::findOrCreateDiffEditor(const QString &documentId, - const QString &source, - const QString &title, - const QString &workingDirectory) const -{ - DiffEditorController *controller = 0; - GitDiffEditorReloader *reloader = 0; - Core::IDocument *document = DiffEditorManager::find(documentId); - if (document) { - controller = DiffEditorManager::controller(document); - reloader = static_cast(controller->reloader()); - } else { - document = DiffEditorManager::findOrCreate(documentId, title); - QTC_ASSERT(document, return 0); - controller = DiffEditorManager::controller(document); - - connect(controller, &DiffEditorController::chunkActionsRequested, - this, &GitClient::slotChunkActionsRequested, Qt::DirectConnection); - connect(controller, &DiffEditorController::requestBranchList, - this, &GitClient::branchesForCommit); - - reloader = new GitDiffEditorReloader(); - controller->setReloader(reloader); - - reloader->setWorkingDirectory(workingDirectory); - } - QTC_ASSERT(reloader, return 0); - - VcsBasePlugin::setSource(document, source); - EditorManager::activateEditorForDocument(document); - return reloader; -} - void GitClient::slotChunkActionsRequested(QMenu *menu, bool isValid) { menu->addSeparator(); @@ -814,7 +727,7 @@ void GitClient::stage(const QString &patch, bool revert) if (!patchFile.open()) return; - const QString baseDir = m_contextController->workingDirectory(); + const QString baseDir = m_contextController->baseDirectory(); QTextCodec *codec = EditorManager::defaultTextCodec(); const QByteArray patchData = codec ? codec->fromUnicode(patch) : patch.toLocal8Bit(); @@ -878,41 +791,60 @@ VcsBaseEditorWidget *GitClient::createVcsEditor( return rc; } +void GitClient::requestReload(const QString &documentId, const QString &source, + const QString &title, + std::function factory) const +{ + DiffEditorController *controller = 0; + IDocument *document = DiffEditorManager::findOrCreate(documentId, title); + QTC_ASSERT(document, return); + controller = DiffEditorManager::controller(document); + if (!controller) { + controller = factory(document); + QTC_ASSERT(controller, return); + + connect(controller, &DiffEditorController::chunkActionsRequested, + this, &GitClient::slotChunkActionsRequested, Qt::DirectConnection); + connect(controller, &DiffEditorController::requestInformationForCommit, + this, &GitClient::branchesForCommit); + } + + VcsBasePlugin::setSource(document, source); + EditorManager::activateEditorForDocument(document); + controller->requestReload(); +} + void GitClient::diffFiles(const QString &workingDirectory, const QStringList &unstagedFileNames, const QStringList &stagedFileNames) const { - GitDiffEditorReloader *reloader = findOrCreateDiffEditor(QLatin1String("Files:") + workingDirectory, - workingDirectory, - tr("Git Diff Files"), - workingDirectory); - QTC_ASSERT(reloader, return); - reloader->setDiffType(GitDiffEditorReloader::DiffFileList); - reloader->setFileList(stagedFileNames, unstagedFileNames); - reloader->requestReload(); + requestReload(QLatin1String("Files:") + workingDirectory, + workingDirectory, tr("Git Diff Files"), + [this, workingDirectory, stagedFileNames, unstagedFileNames] + (IDocument *doc) -> DiffEditorController* { + return new FileListDiffController(doc, workingDirectory, + stagedFileNames, unstagedFileNames); + }); } void GitClient::diffProject(const QString &workingDirectory, const QString &projectDirectory) const { - GitDiffEditorReloader *reloader = findOrCreateDiffEditor(QLatin1String("Project:") + workingDirectory, - workingDirectory, - tr("Git Diff Project"), - workingDirectory); - QTC_ASSERT(reloader, return); - reloader->setDiffType(GitDiffEditorReloader::DiffProjectList); - reloader->setProjectList(QStringList(projectDirectory)); - reloader->requestReload(); + requestReload(QLatin1String("Project:") + workingDirectory, + workingDirectory, tr("Git Diff Project"), + [this, workingDirectory, projectDirectory] + (IDocument *doc) -> DiffEditorController* { + return new ProjectDiffController(doc, workingDirectory, + QStringList(projectDirectory)); + }); } void GitClient::diffRepository(const QString &workingDirectory) const { - GitDiffEditorReloader *reloader = findOrCreateDiffEditor(QLatin1String("Repository:") + workingDirectory, - workingDirectory, - tr("Git Diff Repository"), - workingDirectory); - QTC_ASSERT(reloader, return); - reloader->setDiffType(GitDiffEditorReloader::DiffRepository); - reloader->requestReload(); + requestReload(QLatin1String("Repository:") + workingDirectory, + workingDirectory, tr("Git Diff Repository"), + [this, workingDirectory](IDocument *doc) -> DiffEditorController* { + return new RepositoryDiffController(doc, workingDirectory); + }); } void GitClient::diffFile(const QString &workingDirectory, const QString &fileName) const @@ -920,12 +852,11 @@ void GitClient::diffFile(const QString &workingDirectory, const QString &fileNam const QString title = tr("Git Diff \"%1\"").arg(fileName); const QString sourceFile = VcsBaseEditor::getSource(workingDirectory, fileName); const QString documentId = QLatin1String("File:") + sourceFile; - GitDiffEditorReloader *reloader = findOrCreateDiffEditor(documentId, sourceFile, - title, workingDirectory); - QTC_ASSERT(reloader, return); - reloader->setDiffType(GitDiffEditorReloader::DiffFile); - reloader->setFileName(fileName); - reloader->requestReload(); + requestReload(documentId, sourceFile, title, + [this, workingDirectory, fileName] + (IDocument *doc) -> DiffEditorController* { + return new FileDiffController(doc, workingDirectory, fileName); + }); } void GitClient::diffBranch(const QString &workingDirectory, @@ -933,12 +864,11 @@ void GitClient::diffBranch(const QString &workingDirectory, { const QString title = tr("Git Diff Branch \"%1\"").arg(branchName); const QString documentId = QLatin1String("Branch:") + branchName; - GitDiffEditorReloader *reloader = findOrCreateDiffEditor(documentId, workingDirectory, - title, workingDirectory); - QTC_ASSERT(reloader, return); - reloader->setDiffType(GitDiffEditorReloader::DiffBranch); - reloader->setBranchName(branchName); - reloader->requestReload(); + requestReload(documentId, workingDirectory, title, + [this, workingDirectory, branchName] + (IDocument *doc) -> DiffEditorController* { + return new BranchDiffController(doc, workingDirectory, branchName); + }); } void GitClient::merge(const QString &workingDirectory, @@ -1049,13 +979,11 @@ void GitClient::show(const QString &source, const QString &id, const QString &na if (!repoDirectory.isEmpty()) workingDirectory = repoDirectory; const QString documentId = QLatin1String("Show:") + id; - GitDiffEditorReloader *reloader = findOrCreateDiffEditor(documentId, source, title, workingDirectory); - QTC_ASSERT(reloader, return); - reloader->setDiffType(GitDiffEditorReloader::DiffShow); - reloader->setFileName(source); - reloader->setId(id); - reloader->controller()->setDescriptionEnabled(true); - reloader->requestReload(); + requestReload(documentId, source, title, + [this, workingDirectory, id] + (IDocument *doc) -> DiffEditorController* { + return new ShowController(doc, workingDirectory, id); + }); } void GitClient::saveSettings() @@ -1650,12 +1578,12 @@ void GitClient::branchesForCommit(const QString &revision) << QLatin1String("-a") << QLatin1String("--contains") << revision; auto controller = qobject_cast(sender()); - QString workingDirectory = controller->workingDirectory(); + QString workingDirectory = controller->baseDirectory(); auto command = new VcsCommand(gitExecutable(), workingDirectory, processEnvironment()); command->setCodec(getSourceCodec(currentDocumentPath())); connect(command, &VcsCommand::output, controller, - &DiffEditorController::branchesForCommitReceived); + &DiffEditorController::informationForCommitReceived); command->addJob(arguments, -1); command->setCookie(workingDirectory); @@ -3578,6 +3506,7 @@ void GitClient::StashInfo::end() m_pushAction = NoPush; m_stashResult = NotStashed; } + } // namespace Internal } // namespace Git diff --git a/src/plugins/git/gitclient.h b/src/plugins/git/gitclient.h index 6cb337fe61c..870e2e25903 100644 --- a/src/plugins/git/gitclient.h +++ b/src/plugins/git/gitclient.h @@ -72,7 +72,6 @@ namespace Git { namespace Internal { class CommitData; -class GitDiffEditorReloader; struct GitSubmitEditorPanelData; class Stash; @@ -375,10 +374,8 @@ private: const QString &dynamicPropertyValue, VcsBase::VcsBaseEditorParameterWidget *configWidget) const; - GitDiffEditorReloader *findOrCreateDiffEditor(const QString &documentId, - const QString &source, - const QString &title, - const QString &workingDirectory) const; + void requestReload(const QString &documentId, const QString &source, const QString &title, + std::function factory) const; VcsBase::VcsCommand *createCommand(const QString &workingDirectory, VcsBase::VcsBaseEditorWidget* editor = 0, diff --git a/src/plugins/subversion/subversionclient.cpp b/src/plugins/subversion/subversionclient.cpp index 0c5ca6ef773..bce6f4016bb 100644 --- a/src/plugins/subversion/subversionclient.cpp +++ b/src/plugins/subversion/subversionclient.cpp @@ -42,7 +42,6 @@ #include #include #include -#include #include #include @@ -51,9 +50,10 @@ #include #include +using namespace Core; +using namespace DiffEditor; using namespace Utils; using namespace VcsBase; -using namespace Core; namespace Subversion { namespace Internal { @@ -164,13 +164,12 @@ QString SubversionClient::synchronousTopic(const QString &repository) return QString(); } -class SubversionDiffEditorReloader : public DiffEditor::DiffEditorReloader +class DiffController : public DiffEditorController { Q_OBJECT public: - SubversionDiffEditorReloader(const SubversionClient *client); + DiffController(IDocument *document, const SubversionClient *client, const QString &directory); - void setWorkingDirectory(const QString &workingDirectory); void setFilesList(const QStringList &filesList); void setChangeNumber(int changeNumber); @@ -191,41 +190,33 @@ private: QString m_workingDirectory; QStringList m_filesList; int m_changeNumber; - const QString m_waitMessage; }; -SubversionDiffEditorReloader::SubversionDiffEditorReloader(const SubversionClient *client) - : DiffEditor::DiffEditorReloader(), - m_client(client), - m_changeNumber(0), - m_waitMessage(tr("Waiting for data...")) +DiffController::DiffController(IDocument *document, const SubversionClient *client, const QString &directory) : + DiffEditorController(document), + m_client(client), + m_workingDirectory(directory), + m_changeNumber(0) { + forceContextLineCount(3); // SVN can not change that when using internal diff } -int SubversionDiffEditorReloader::timeout() const +int DiffController::timeout() const { return m_client->settings()->intValue(VcsBaseClientSettings::timeoutKey); } -FileName SubversionDiffEditorReloader::subversionPath() const +FileName DiffController::subversionPath() const { return m_client->settings()->binaryPath(); } -QProcessEnvironment SubversionDiffEditorReloader::processEnvironment() const +QProcessEnvironment DiffController::processEnvironment() const { return m_client->processEnvironment(); } -void SubversionDiffEditorReloader::setWorkingDirectory(const QString &workingDirectory) -{ - if (isReloading()) - return; - - m_workingDirectory = workingDirectory; -} - -void SubversionDiffEditorReloader::setFilesList(const QStringList &filesList) +void DiffController::setFilesList(const QStringList &filesList) { if (isReloading()) return; @@ -233,7 +224,7 @@ void SubversionDiffEditorReloader::setFilesList(const QStringList &filesList) m_filesList = filesList; } -void SubversionDiffEditorReloader::setChangeNumber(int changeNumber) +void DiffController::setChangeNumber(int changeNumber) { if (isReloading()) return; @@ -241,7 +232,7 @@ void SubversionDiffEditorReloader::setChangeNumber(int changeNumber) m_changeNumber = qMax(changeNumber, 0); } -QString SubversionDiffEditorReloader::getDescription() const +QString DiffController::getDescription() const { QStringList args(QLatin1String("log")); args << SubversionClient::addAuthenticationOptions(*m_client->settings()); @@ -258,13 +249,8 @@ QString SubversionDiffEditorReloader::getDescription() const return logResponse.stdOut; } -void SubversionDiffEditorReloader::postCollectTextualDiffOutput() +void DiffController::postCollectTextualDiffOutput() { - if (!controller()) - return; - - controller()->requestSaveState(); - controller()->clear(m_waitMessage); auto command = new VcsCommand(subversionPath(), m_workingDirectory, processEnvironment()); command->setCodec(EditorManager::defaultTextCodec()); connect(command, SIGNAL(output(QString)), @@ -275,7 +261,7 @@ void SubversionDiffEditorReloader::postCollectTextualDiffOutput() args << QLatin1String("diff"); args << m_client->addAuthenticationOptions(*m_client->settings()); args << QLatin1String("--internal-diff"); - if (controller()->isIgnoreWhitespace()) + if (ignoreWhitespace()) args << QLatin1String("-x") << QLatin1String("-uw"); if (m_changeNumber) { args << QLatin1String("-r") << QString::number(m_changeNumber - 1) @@ -288,58 +274,35 @@ void SubversionDiffEditorReloader::postCollectTextualDiffOutput() command->execute(); } -void SubversionDiffEditorReloader::slotTextualDiffOutputReceived(const QString &contents) +void DiffController::slotTextualDiffOutputReceived(const QString &contents) { - if (!controller()) - return; - bool ok; - QList fileDataList - = DiffEditor::DiffUtils::readPatch(contents, &ok); - controller()->setDiffFiles(fileDataList, m_workingDirectory); - controller()->requestRestoreState(); + QList fileDataList + = DiffUtils::readPatch(contents, &ok); + setDiffFiles(fileDataList, m_workingDirectory); - reloadFinished(); + reloadFinished(true); } -void SubversionDiffEditorReloader::reload() +void DiffController::reload() { - if (!controller()) - return; - const QString description = m_changeNumber ? getDescription() : QString(); postCollectTextualDiffOutput(); - controller()->setDescription(description); + setDescription(description); } -SubversionDiffEditorReloader *SubversionClient::findOrCreateDiffEditor(const QString &documentId, - const QString &source, - const QString &title, - const QString &workingDirectory) const +DiffController *SubversionClient::findOrCreateDiffEditor(const QString &documentId, + const QString &source, + const QString &title, + const QString &workingDirectory) const { - DiffEditor::DiffEditorController *controller = 0; - SubversionDiffEditorReloader *reloader = 0; - Core::IDocument *document = DiffEditor::DiffEditorManager::find(documentId); - if (document) { - controller = DiffEditor::DiffEditorManager::controller(document); - reloader = static_cast(controller->reloader()); - } else { - document = DiffEditor::DiffEditorManager::findOrCreate(documentId, title); - QTC_ASSERT(document, return 0); - controller = DiffEditor::DiffEditorManager::controller(document); - QTC_ASSERT(controller, return 0); - - reloader = new SubversionDiffEditorReloader(this); - controller->setReloader(reloader); - controller->setContextLinesNumberEnabled(false); - } - QTC_ASSERT(reloader, return 0); - - reloader->setWorkingDirectory(workingDirectory); + IDocument *document = DiffEditorManager::findOrCreate(documentId, title); + DiffController *controller = qobject_cast(DiffEditorManager::controller(document)); + if (!controller) + controller = new DiffController(document, this, workingDirectory); VcsBasePlugin::setSource(document, source); - - return reloader; + return controller; } void SubversionClient::diff(const QString &workingDirectory, const QStringList &files, const QStringList &extraOptions) @@ -350,10 +313,10 @@ void SubversionClient::diff(const QString &workingDirectory, const QStringList & const QString documentId = VcsBaseEditor::getTitleId(workingDirectory, files); const QString title = vcsEditorTitle(vcsCmdString, documentId); - SubversionDiffEditorReloader *reloader = findOrCreateDiffEditor(documentId, workingDirectory, title, workingDirectory); - QTC_ASSERT(reloader, return); - reloader->setFilesList(files); - reloader->requestReload(); + DiffController *controller = findOrCreateDiffEditor(documentId, workingDirectory, title, + workingDirectory); + controller->setFilesList(files); + controller->requestReload(); } void SubversionClient::log(const QString &workingDir, @@ -384,11 +347,9 @@ void SubversionClient::describe(const QString &workingDirectory, int changeNumbe QStringList(), QString::number(changeNumber)); - SubversionDiffEditorReloader *reloader = findOrCreateDiffEditor(documentId, workingDirectory, title, workingDirectory); - QTC_ASSERT(reloader, return); - reloader->setChangeNumber(changeNumber); - reloader->controller()->setDescriptionEnabled(true); - reloader->requestReload(); + DiffController *controller = findOrCreateDiffEditor(documentId, workingDirectory, title, workingDirectory); + controller->setChangeNumber(changeNumber); + controller->requestReload(); } QString SubversionClient::findTopLevelForFile(const QFileInfo &file) const diff --git a/src/plugins/subversion/subversionclient.h b/src/plugins/subversion/subversionclient.h index ee283cfca6b..5db0327b169 100644 --- a/src/plugins/subversion/subversionclient.h +++ b/src/plugins/subversion/subversionclient.h @@ -41,7 +41,7 @@ namespace Subversion { namespace Internal { class SubversionSettings; -class SubversionDiffEditorReloader; +class DiffController; class SubversionClient : public VcsBase::VcsBaseClient { @@ -83,10 +83,8 @@ protected: Core::Id vcsEditorKind(VcsCommandTag cmd) const; private: - SubversionDiffEditorReloader *findOrCreateDiffEditor(const QString &documentId, - const QString &source, - const QString &title, - const QString &workingDirectory) const; + DiffController *findOrCreateDiffEditor(const QString &documentId, const QString &source, + const QString &title, const QString &workingDirectory) const; mutable Utils::FileName m_svnVersionBinary; mutable QString m_svnVersion;