diff --git a/src/plugins/diffeditor/diffeditor.cpp b/src/plugins/diffeditor/diffeditor.cpp index 2d0405666fcebe1098358a1fd10bcc9229c8c629..d18e7bbfb28d9d1e1fa76d1171a1d97073835332 100644 --- a/src/plugins/diffeditor/diffeditor.cpp +++ b/src/plugins/diffeditor/diffeditor.cpp @@ -52,6 +52,7 @@ #include <QComboBox> #include <QFileInfo> #include <QTextCodec> +#include <QTextBlock> static const char settingsGroupC[] = "DiffEditor"; static const char diffEditorTypeKeyC[] = "DiffEditorType"; @@ -74,6 +75,9 @@ public: DescriptionEditorWidget(QWidget *parent = 0); virtual QSize sizeHint() const; +signals: + void expandBranchesRequested(); + public slots: void setDisplaySettings(const DisplaySettings &ds); @@ -84,6 +88,15 @@ protected: editor->document()->setId("DiffEditor.DescriptionEditor"); return editor; } + void mouseMoveEvent(QMouseEvent *e); + void mouseReleaseEvent(QMouseEvent *e); + + bool findContentsUnderCursor(const QTextCursor &cursor); + void highlightCurrentContents(); + void handleCurrentContents(); + +private: + QTextCursor m_currentCursor; }; DescriptionEditorWidget::DescriptionEditorWidget(QWidget *parent) @@ -118,6 +131,67 @@ void DescriptionEditorWidget::setDisplaySettings(const DisplaySettings &ds) BaseTextEditorWidget::setDisplaySettings(settings); } +void DescriptionEditorWidget::mouseMoveEvent(QMouseEvent *e) +{ + if (e->buttons()) { + TextEditor::BaseTextEditorWidget::mouseMoveEvent(e); + return; + } + + Qt::CursorShape cursorShape; + + const QTextCursor cursor = cursorForPosition(e->pos()); + if (findContentsUnderCursor(cursor)) { + highlightCurrentContents(); + cursorShape = Qt::PointingHandCursor; + } else { + setExtraSelections(OtherSelection, QList<QTextEdit::ExtraSelection>()); + cursorShape = Qt::IBeamCursor; + } + + TextEditor::BaseTextEditorWidget::mouseMoveEvent(e); + viewport()->setCursor(cursorShape); +} + +void DescriptionEditorWidget::mouseReleaseEvent(QMouseEvent *e) +{ + if (e->button() == Qt::LeftButton && !(e->modifiers() & Qt::ShiftModifier)) { + const QTextCursor cursor = cursorForPosition(e->pos()); + if (findContentsUnderCursor(cursor)) { + handleCurrentContents(); + e->accept(); + return; + } + } + + TextEditor::BaseTextEditorWidget::mouseReleaseEvent(e); +} + +bool DescriptionEditorWidget::findContentsUnderCursor(const QTextCursor &cursor) +{ + m_currentCursor = cursor; + return cursor.block().text() == QLatin1String(Constants::EXPAND_BRANCHES); +} + +void DescriptionEditorWidget::highlightCurrentContents() +{ + QTextEdit::ExtraSelection sel; + sel.cursor = m_currentCursor; + sel.cursor.select(QTextCursor::LineUnderCursor); + sel.format.setFontUnderline(true); + setExtraSelections(BaseTextEditorWidget::OtherSelection, + QList<QTextEdit::ExtraSelection>() << sel); + +} + +void DescriptionEditorWidget::handleCurrentContents() +{ + m_currentCursor.select(QTextCursor::LineUnderCursor); + m_currentCursor.removeSelectedText(); + m_currentCursor.insertText(QLatin1String("Branches: Expanding...")); + emit expandBranchesRequested(); +} + } // namespace Internal ///////////////////////////////// DiffEditor ////////////////////////////////// @@ -179,6 +253,8 @@ void DiffEditor::ctor() setWidget(splitter); + connect(m_descriptionWidget, SIGNAL(expandBranchesRequested()), + m_document->controller(), SLOT(expandBranchesRequested())); connect(TextEditorSettings::instance(), SIGNAL(displaySettingsChanged(TextEditor::DisplaySettings)), m_descriptionWidget, diff --git a/src/plugins/diffeditor/diffeditorconstants.h b/src/plugins/diffeditor/diffeditorconstants.h index a59336eb0665b50d62b1f77797a5a20973026e83..c988415abe0a32d37d1adcbd6f40bdd23226d0a1 100644 --- a/src/plugins/diffeditor/diffeditorconstants.h +++ b/src/plugins/diffeditor/diffeditorconstants.h @@ -44,6 +44,8 @@ const char ICON_SIDE_BY_SIDE_DIFF[] = ":/diffeditor/images/sidebysidediff.png"; const char ICON_UNIFIED_DIFF[] = ":/diffeditor/images/unifieddiff.png"; const char ICON_TOP_BAR[] = ":/diffeditor/images/topbar.png"; +const char EXPAND_BRANCHES[] = "Branches: <Expand>"; + } // namespace Constants } // namespace DiffEditor diff --git a/src/plugins/diffeditor/diffeditorcontroller.cpp b/src/plugins/diffeditor/diffeditorcontroller.cpp index e826cf1e7df3f2372445f70fd7b10fef1c60254f..1d9d76448fa261763fd2d2a7e1fd9839eeb72cda 100644 --- a/src/plugins/diffeditor/diffeditorcontroller.cpp +++ b/src/plugins/diffeditor/diffeditorcontroller.cpp @@ -27,10 +27,13 @@ ** ****************************************************************************/ +#include "diffeditorconstants.h" #include "diffeditorcontroller.h" #include <coreplugin/icore.h> +#include <QStringList> + static const char settingsGroupC[] = "DiffEditor"; static const char contextLineNumbersKeyC[] = "ContextLineNumbers"; static const char ignoreWhitespaceKeyC[] = "IgnoreWhitespace"; @@ -148,7 +151,11 @@ void DiffEditorController::setDescription(const QString &description) return; m_description = description; - emit descriptionChanged(description); + // Empty line before headers and commit message + const int emptyLine = m_description.indexOf(QLatin1String("\n\n")); + if (emptyLine != -1) + m_description.insert(emptyLine, QLatin1Char('\n') + QLatin1String(Constants::EXPAND_BRANCHES)); + emit descriptionChanged(m_description); } void DiffEditorController::setDescriptionEnabled(bool on) @@ -160,6 +167,44 @@ void DiffEditorController::setDescriptionEnabled(bool on) emit descriptionEnablementChanged(on); } +void DiffEditorController::branchesForCommitReceived(const QString &output) +{ + const QString branches = prepareBranchesForCommit(output); + + m_description.replace(QLatin1String(Constants::EXPAND_BRANCHES), branches); + emit descriptionChanged(m_description); +} + +void DiffEditorController::expandBranchesRequested() +{ + emit expandBranchesRequested(m_description.mid(7, 8)); +} + +QString DiffEditorController::prepareBranchesForCommit(const QString &output) +{ + QString moreBranches; + QString branches; + QStringList res; + foreach (const QString &branch, output.split(QLatin1Char('\n'))) { + const QString b = branch.mid(2).trimmed(); + if (!b.isEmpty()) + res << b; + } + const int branchCount = res.count(); + // If there are more than 20 branches, list first 10 followed by a hint + if (branchCount > 20) { + const int leave = 10; + //: Displayed after the untranslated message "Branches: branch1, branch2 'and %n more'" + // in git show. + moreBranches = QLatin1Char(' ') + tr("and %n more", 0, branchCount - leave); + res.erase(res.begin() + leave, res.end()); + } + if (!res.isEmpty()) + branches = (QLatin1String("Branches: ") + res.join(QLatin1String(", ")) + moreBranches); + + return branches; +} + void DiffEditorController::setContextLinesNumber(int lines) { const int l = qMax(lines, 1); diff --git a/src/plugins/diffeditor/diffeditorcontroller.h b/src/plugins/diffeditor/diffeditorcontroller.h index 5bdfbd1cc4215565e10e9f294e3df00964362cad..82c150435ffad6fced3a1366acb253b6dce22475 100644 --- a/src/plugins/diffeditor/diffeditorcontroller.h +++ b/src/plugins/diffeditor/diffeditorcontroller.h @@ -68,6 +68,8 @@ public slots: void requestChunkActions(QMenu *menu, int diffFileIndex, int chunkIndex); + void branchesForCommitReceived(const QString &output); + void expandBranchesRequested(); signals: void cleared(const QString &message); @@ -81,9 +83,10 @@ signals: void chunkActionsRequested(QMenu *menu, int diffFileIndex, int chunkIndex); - + void expandBranchesRequested(const QString &revision); private: + QString prepareBranchesForCommit(const QString &output); QString m_clearMessage; QList<FileData> m_diffFiles; diff --git a/src/plugins/git/gitclient.cpp b/src/plugins/git/gitclient.cpp index 1e47d1aa63c33a0509447cce814a8fe41cbb0b82..7bec91dce36f6fa494760d19775dcf977f4322cd 100644 --- a/src/plugins/git/gitclient.cpp +++ b/src/plugins/git/gitclient.cpp @@ -1139,6 +1139,10 @@ void GitClient::show(const QString &source, const QString &id, const QString &na DiffEditor::DiffEditorManager::find(documentId); if (!diffEditorDocument) { diffEditorDocument = createDiffEditor(documentId, source, title); + + connect(diffEditorDocument->controller(), SIGNAL(expandBranchesRequested(QString)), + this, SLOT(branchesForCommit(QString))); + diffEditorDocument->controller()->setDescriptionEnabled(true); GitDiffEditorReloader *reloader = @@ -1738,23 +1742,25 @@ void GitClient::synchronousTagsForCommit(const QString &workingDirectory, const } } -QStringList GitClient::synchronousBranchesForCommit(const QString &workingDirectory, const QString &revision) +void GitClient::branchesForCommit(const QString &revision) { - QByteArray outputData; - QString output; QStringList arguments; arguments << QLatin1String("branch") << QLatin1String(noColorOption) << QLatin1String("-a") << QLatin1String("--contains") << revision; - fullySynchronousGit(workingDirectory, arguments, &outputData, 0, - VcsBasePlugin::SuppressCommandLogging); - output = commandOutputFromLocal8Bit(outputData); - QStringList res; - foreach (const QString &branch, output.split(QLatin1Char('\n'))) { - const QString b = branch.mid(2).trimmed(); - if (!b.isEmpty()) - res << b; - } - return res; + + DiffEditor::DiffEditorController *editorController + = qobject_cast<DiffEditor::DiffEditorController *>(sender()); + QString workingDirectory = editorController->workingDirectory(); + VcsBase::Command *command = new VcsBase::Command(gitBinaryPath(), workingDirectory, + processEnvironment()); + command->setCodec(getSourceCodec(currentDocumentPath())); + + connect(command, SIGNAL(output(QString)), editorController, + SLOT(branchesForCommitReceived(QString))); + + command->addJob(arguments, -1); + command->execute(); + command->setCookie(workingDirectory); } bool GitClient::isRemoteCommit(const QString &workingDirectory, const QString &commit) diff --git a/src/plugins/git/gitclient.h b/src/plugins/git/gitclient.h index 5602d175e56087def18dda5f784cdb27221c9891..1b20d75e2a71c71b50f834c04364ecf23e843b9b 100644 --- a/src/plugins/git/gitclient.h +++ b/src/plugins/git/gitclient.h @@ -241,8 +241,6 @@ public: QString synchronousTopRevision(const QString &workingDirectory, QString *errorMessage = 0); void synchronousTagsForCommit(const QString &workingDirectory, const QString &revision, QString &precedes, QString &follows); - QStringList synchronousBranchesForCommit(const QString &workingDirectory, - const QString &revision); bool isRemoteCommit(const QString &workingDirectory, const QString &commit); bool isFastForwardMerge(const QString &workingDirectory, const QString &branch); @@ -349,6 +347,7 @@ private slots: void slotChunkActionsRequested(QMenu *menu, int diffFileIndex, int chunkIndex); void slotStageChunk(); void slotUnstageChunk(); + void branchesForCommit(const QString &revision); private: QString makePatch(int diffFileIndex, int chunkIndex, bool revert) const;