diff --git a/src/plugins/perforce/perforceplugin.cpp b/src/plugins/perforce/perforceplugin.cpp index d3fcc1d17dec20a86b0b8655b332d801a23d5ebb..65efbc977f3fb7a5e05516eaced425ac3a5ea638 100644 --- a/src/plugins/perforce/perforceplugin.cpp +++ b/src/plugins/perforce/perforceplugin.cpp @@ -106,6 +106,27 @@ static inline QString debugCodec(const QTextCodec *c) return c ? QString::fromAscii(c->name()) : QString::fromAscii("Null codec"); } +// Return the project files relevant for VCS +static const QStringList currentProjectFiles(QString *name) +{ + QStringList files = VCSBase::VCSBaseSubmitEditor::currentProjectFiles(true, name); + if (!files.empty()) { + // Filter out mkspecs/qconfig.pri + QString exclusion = QLatin1String("mkspecs"); + exclusion += QDir::separator(); + exclusion += QLatin1String("qconfig.pri"); + for (QStringList::iterator it = files.begin(); it != files.end(); ) { + if (it->endsWith(exclusion)) { + it = files.erase(it); + break; + } else { + ++it; + } + } + } + return files; +} + const char * const PerforcePlugin::PERFORCE_MENU = "Perforce.Menu"; const char * const PerforcePlugin::EDIT = "Perforce.Edit"; const char * const PerforcePlugin::ADD = "Perforce.Add"; @@ -450,7 +471,7 @@ void PerforcePlugin::diffCurrentFile() void PerforcePlugin::diffCurrentProject() { QString name; - const QStringList nativeFiles = VCSBase::VCSBaseSubmitEditor::currentProjectFiles(true, &name); + const QStringList nativeFiles = currentProjectFiles(&name); p4Diff(nativeFiles, name); } @@ -509,7 +530,7 @@ void PerforcePlugin::submit() // Assemble file list of project QString name; - const QStringList nativeFiles = VCSBase::VCSBaseSubmitEditor::currentProjectFiles(true, &name); + const QStringList nativeFiles = currentProjectFiles(&name); PerforceResponse result2 = runP4Cmd(QStringList(QLatin1String("fstat")), nativeFiles, CommandToWindow|StdErrToWindow|ErrorToWindow); if (result2.error) { @@ -846,7 +867,9 @@ Core::IEditor * PerforcePlugin::showOutputInEditor(const QString& title, const Q e->setSuggestedFileName(s); if (codec) e->setCodec(codec); - return e->editableInterface(); + Core::IEditor *ie = e->editableInterface(); + Core::EditorManager::instance()->activateEditor(ie); + return ie; } QStringList PerforcePlugin::environment() const diff --git a/src/plugins/subversion/subversionplugin.cpp b/src/plugins/subversion/subversionplugin.cpp index 5645031eb484681251eeb2912e2de8c0a35f5112..67e56eacf65d1c65996c40408e8f39cf01a40401 100644 --- a/src/plugins/subversion/subversionplugin.cpp +++ b/src/plugins/subversion/subversionplugin.cpp @@ -1039,7 +1039,9 @@ Core::IEditor * SubversionPlugin::showOutputInEditor(const QString& title, const e->setSource(source); if (codec) e->setCodec(codec); - return e->editableInterface(); + Core::IEditor *ie = e->editableInterface(); + Core::EditorManager::instance()->activateEditor(ie); + return ie; } SubversionSettings SubversionPlugin::settings() const diff --git a/src/plugins/vcsbase/diffhighlighter.cpp b/src/plugins/vcsbase/diffhighlighter.cpp index 57c8cd4b25e376ce19e7ff9c4d087b47d9ec70bd..e4f434c28d0260ccc201eb2f801429b3dd51c24c 100644 --- a/src/plugins/vcsbase/diffhighlighter.cpp +++ b/src/plugins/vcsbase/diffhighlighter.cpp @@ -115,4 +115,9 @@ void DiffHighlighter::setFormats(const QVector<QTextCharFormat> &s) } } +QRegExp DiffHighlighter::filePattern() const +{ + return m_d->m_filePattern; +} + } // namespace VCSBase diff --git a/src/plugins/vcsbase/diffhighlighter.h b/src/plugins/vcsbase/diffhighlighter.h index 93da9b1daddbcf81a92645ae0f8d508cf1845ba7..83a4a36d4daa5e8f289b422844b7d928ea16aa4c 100644 --- a/src/plugins/vcsbase/diffhighlighter.h +++ b/src/plugins/vcsbase/diffhighlighter.h @@ -79,6 +79,8 @@ public: // Set formats from a sequence of type QTextCharFormat void setFormats(const QVector<QTextCharFormat> &s); + QRegExp filePattern() const; + private: DiffHighlighterPrivate *m_d; }; diff --git a/src/plugins/vcsbase/vcsbaseeditor.cpp b/src/plugins/vcsbase/vcsbaseeditor.cpp index 21442b3144c08a1a25a3bb7425d963a2695164af..2376f3b83e3dae74bc18841ef6b652317a3750e9 100644 --- a/src/plugins/vcsbase/vcsbaseeditor.cpp +++ b/src/plugins/vcsbase/vcsbaseeditor.cpp @@ -35,12 +35,14 @@ #include <coreplugin/editormanager/editormanager.h> #include <coreplugin/uniqueidmanager.h> +#include <coreplugin/editormanager/editormanager.h> #include <extensionsystem/pluginmanager.h> #include <projectexplorer/editorconfiguration.h> #include <projectexplorer/projectexplorer.h> #include <projectexplorer/session.h> #include <texteditor/fontsettings.h> #include <texteditor/texteditorconstants.h> +#include <utils/qtcassert.h> #include <QtCore/QDebug> #include <QtCore/QFileInfo> @@ -55,10 +57,13 @@ #include <QtGui/QMenu> #include <QtGui/QTextCursor> #include <QtGui/QTextEdit> +#include <QtGui/QComboBox> +#include <QtGui/QToolBar> namespace VCSBase { // VCSBaseEditorEditable: An editable with no support for duplicates +// Creates a browse combo in the toolbar for diff output. class VCSBaseEditorEditable : public TextEditor::BaseTextEditorEditable { public: @@ -73,12 +78,12 @@ public: private: const char *m_kind; QList<int> m_context; - }; VCSBaseEditorEditable::VCSBaseEditorEditable(VCSBaseEditor *editor, - const VCSBaseEditorParameters *type) - : BaseTextEditorEditable(editor), m_kind(type->kind) + const VCSBaseEditorParameters *type) : + BaseTextEditorEditable(editor), + m_kind(type->kind) { Core::UniqueIDManager *uidm = Core::UniqueIDManager::instance(); m_context << uidm->uniqueIdentifier(QLatin1String(type->context)) @@ -90,6 +95,34 @@ QList<int> VCSBaseEditorEditable::context() const return m_context; } +// Diff editable: creates a browse combo in the toolbar for diff output. +class VCSBaseDiffEditorEditable : public VCSBaseEditorEditable +{ +public: + VCSBaseDiffEditorEditable(VCSBaseEditor *, const VCSBaseEditorParameters *type); + + virtual QToolBar *toolBar() { return m_toolBar; } + QComboBox *diffFileBrowseComboBox() const { return m_diffFileBrowseComboBox; } + +private: + QComboBox *m_diffFileBrowseComboBox; + QToolBar *m_toolBar; +}; + +VCSBaseDiffEditorEditable::VCSBaseDiffEditorEditable(VCSBaseEditor *e, const VCSBaseEditorParameters *type) : + VCSBaseEditorEditable(e, type), + m_diffFileBrowseComboBox(new QComboBox), + m_toolBar(new QToolBar) +{ + m_diffFileBrowseComboBox->setMinimumContentsLength(20); + m_diffFileBrowseComboBox->setSizeAdjustPolicy(QComboBox::AdjustToContents); + // Make the combo box prefer to expand + QSizePolicy policy = m_diffFileBrowseComboBox->sizePolicy(); + policy.setHorizontalPolicy(QSizePolicy::Expanding); + m_diffFileBrowseComboBox->setSizePolicy(policy); + m_toolBar->addWidget(m_diffFileBrowseComboBox); +} + // ----------- VCSBaseEditorPrivate struct VCSBaseEditorPrivate @@ -97,13 +130,20 @@ struct VCSBaseEditorPrivate VCSBaseEditorPrivate(const VCSBaseEditorParameters *type, QObject *parent); const VCSBaseEditorParameters *m_parameters; + QAction *m_describeAction; QString m_currentChange; QString m_source; + + QRegExp m_diffFilePattern; + QList<int> m_diffSections; // line number where this section starts + int m_cursorLine; }; -VCSBaseEditorPrivate::VCSBaseEditorPrivate(const VCSBaseEditorParameters *type, QObject *parent) - : m_parameters(type), m_describeAction(new QAction(parent)) +VCSBaseEditorPrivate::VCSBaseEditorPrivate(const VCSBaseEditorParameters *type, QObject *parent) : + m_parameters(type), + m_describeAction(new QAction(parent)), + m_cursorLine(-1) { } @@ -131,8 +171,13 @@ void VCSBaseEditor::init() // Annotation highlighting depends on contents, which is set later on connect(this, SIGNAL(textChanged()), this, SLOT(slotActivateAnnotation())); break; - case DiffOutput: - baseTextDocument()->setSyntaxHighlighter(createDiffHighlighter()); + case DiffOutput: { + DiffHighlighter *dh = createDiffHighlighter(); + baseTextDocument()->setSyntaxHighlighter(dh); + d->m_diffFilePattern = dh->filePattern(); + connect(this, SIGNAL(textChanged()), this, SLOT(slotPopulateDiffBrowser())); + connect(this, SIGNAL(cursorPositionChanged()), this, SLOT(slotDiffCursorPositionChanged())); + } break; } } @@ -178,7 +223,87 @@ bool VCSBaseEditor::isModified() const TextEditor::BaseTextEditorEditable *VCSBaseEditor::createEditableInterface() { - return new VCSBaseEditorEditable(this, d->m_parameters); + if (d->m_parameters->type != DiffOutput) + return new VCSBaseEditorEditable(this, d->m_parameters); + // Diff: set up diff file browsing + VCSBaseDiffEditorEditable *de = new VCSBaseDiffEditorEditable(this, d->m_parameters); + QComboBox *diffBrowseComboBox = de->diffFileBrowseComboBox(); + connect(diffBrowseComboBox, SIGNAL(currentIndexChanged(int)), this, SLOT(slotDiffBrowse(int))); + return de; +} + +void VCSBaseEditor::slotPopulateDiffBrowser() +{ + VCSBaseDiffEditorEditable *de = static_cast<VCSBaseDiffEditorEditable*>(editableInterface()); + QComboBox *diffBrowseComboBox = de->diffFileBrowseComboBox(); + diffBrowseComboBox->clear(); + d->m_diffSections.clear(); + // Create a list of section line numbers (diffed files) + // and populate combo with filenames. + const QTextBlock cend = document()->end(); + int lineNumber = 0; + QString lastFileName; + for (QTextBlock it = document()->begin(); it != cend; it = it.next(), lineNumber++) { + const QString text = it.text(); + // Check for a new diff section (not repeating the last filename) + if (d->m_diffFilePattern.exactMatch(text)) { + const QString file = fileNameFromDiffSpecification(it); + if (!file.isEmpty() && lastFileName != file) { + lastFileName = file; + // ignore any headers + d->m_diffSections.push_back(d->m_diffSections.empty() ? 0 : lineNumber); + diffBrowseComboBox->addItem(QFileInfo(file).fileName()); + } + } + } +} + +void VCSBaseEditor::slotDiffBrowse(int index) +{ + // goto diffed file as indicated by index/line number + if (index < 0 || index >= d->m_diffSections.size()) + return; + const int lineNumber = d->m_diffSections.at(index); + Core::EditorManager *editorManager = Core::EditorManager::instance(); + editorManager->addCurrentPositionToNavigationHistory(true); + gotoLine(lineNumber + 1, 0); // TextEdit uses 1..n convention + editorManager->addCurrentPositionToNavigationHistory(); +} + +// Locate a line number in the list of diff sections. +static int sectionOfLine(int line, const QList<int> §ions) +{ + const int sectionCount = sections.size(); + if (!sectionCount) + return -1; + // The section at s indicates where the section begins. + for (int s = 0; s < sectionCount; s++) { + if (line < sections.at(s)) + return s - 1; + } + return sectionCount - 1; +} + +void VCSBaseEditor::slotDiffCursorPositionChanged() +{ + // Adapt diff file browse combo to new position + // if the cursor goes across a file line. + QTC_ASSERT(d->m_parameters->type == DiffOutput, return) + const int newCursorLine = textCursor().blockNumber(); + if (newCursorLine == d->m_cursorLine) + return; + // Which section does it belong to? + d->m_cursorLine = newCursorLine; + const int section = sectionOfLine(d->m_cursorLine, d->m_diffSections); + if (section != -1) { + VCSBaseDiffEditorEditable *de = static_cast<VCSBaseDiffEditorEditable*>(editableInterface()); + QComboBox *diffBrowseComboBox = de->diffFileBrowseComboBox(); + if (diffBrowseComboBox->currentIndex() != section) { + const bool blocked = diffBrowseComboBox->blockSignals(true); + diffBrowseComboBox->setCurrentIndex(section); + diffBrowseComboBox->blockSignals(blocked); + } + } } void VCSBaseEditor::contextMenuEvent(QContextMenuEvent *e) diff --git a/src/plugins/vcsbase/vcsbaseeditor.h b/src/plugins/vcsbase/vcsbaseeditor.h index fc1ce94b73dfd5e78ed84a98ced0f62fa635fe3a..29dcb03bf3779c9d1b90777aaa0f2df672eeb208 100644 --- a/src/plugins/vcsbase/vcsbaseeditor.h +++ b/src/plugins/vcsbase/vcsbaseeditor.h @@ -142,6 +142,9 @@ public slots: private slots: void describe(); void slotActivateAnnotation(); + void slotPopulateDiffBrowser(); + void slotDiffBrowse(int); + void slotDiffCursorPositionChanged(); private: // Implement to return a set of change identifiers in