Skip to content
Open
Show file tree
Hide file tree
Changes from all commits
Commits
File filter

Filter by extension

Filter by extension

Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
494 changes: 361 additions & 133 deletions src/ui/CommitList.cpp

Large diffs are not rendered by default.

31 changes: 31 additions & 0 deletions src/ui/CommitList.h
Original file line number Diff line number Diff line change
Expand Up @@ -12,6 +12,7 @@

#include "git/Reference.h"
#include <QListView>
#include <QTimer>

class Index;

Expand Down Expand Up @@ -63,22 +64,36 @@ class CommitList : public QListView {

void setModel(QAbstractItemModel *model) override;

// Whether a status check and/or walker/row rebuild is currently in
// flight. See the loadingChanged() signal for a way to wait on this
// instead of polling it.
bool isLoading() const { return mLoading; }

signals:
void statusChanged(bool dirty);
void diffSelected(const git::Diff diff, const QString &file = QString(),
bool spontaneous = false);

// Emitted just before a (potentially slow) diff is being computation. This
// can be used to clear GUI and enable loading indicators whilst waiting
void diffLoading();

// Emitted whenever isLoading() changes.
void loadingChanged(bool loading);

protected:
void contextMenuEvent(QContextMenuEvent *event) override;
void mouseMoveEvent(QMouseEvent *event) override;
void mousePressEvent(QMouseEvent *event) override;
void mouseReleaseEvent(QMouseEvent *event) override;
void leaveEvent(QEvent *) override;
void paintEvent(QPaintEvent *event) override;

private:
void storeSelection();
void restoreSelection();
void updateModel();
void setLoading(bool loading);

QModelIndexList sortedIndexes() const;

Expand All @@ -87,6 +102,7 @@ class CommitList : public QListView {
const QString &file = QString(), bool spontaneous = false);

void notifySelectionChanged();
void dispatchSelectedDiff(const QString &file, bool spontaneous);

bool isDecoration(const QModelIndex &index, const QPoint &pos);
bool isStar(const QModelIndex &index, const QPoint &pos);
Expand All @@ -105,6 +121,21 @@ class CommitList : public QListView {
bool mRestoreSelection{true};

QString mSelectedRange;

// Whether the current selection is just the automatic fallback rather
// than a deliberate user pick
bool mSelectionIsDefault{false};

// Whether the loading indicator should be shown
bool mLoading{false};
float mLoadingFadein = 0;
int mProgress{0};
QTimer mTimer;

// Incremented on every selection-driven diff request. This is a hack used to
// discard diffs that arrive before the last one
// (Yes, we should have a proper cancel pathway here)
int mDiffRequest = 0;
};

#endif
17 changes: 17 additions & 0 deletions src/ui/DetailView.cpp
Original file line number Diff line number Diff line change
Expand Up @@ -618,6 +618,23 @@ void DetailView::setDiff(const git::Diff &diff, const QString &file,
MenuBar::instance(this)->updateRepository();
}

void DetailView::setLoading() {
// Commit metadata (author, date, message, parents, refs, ...) comes from
// the selected commit(s), not the diff, so this can easily be shown
// immediatly.
RepoView *view = RepoView::parentView(this);
QList<git::Commit> commits = view->commits();
if (!commits.isEmpty()) {
mDetail->setCurrentIndex(CommitIndex);
mDetail->setVisible(true);
static_cast<CommitDetail *>(mDetail->currentWidget())->setCommits(commits);
}

// Incidate data loading while we wait for data to arrive
ContentWidget *cw = static_cast<ContentWidget *>(mContent->currentWidget());
cw->setLoading();
}

void DetailView::cancelBackgroundTasks() {
CommitDetail *cd = static_cast<CommitDetail *>(mDetail->widget(CommitIndex));
cd->cancelBackgroundTasks();
Expand Down
8 changes: 8 additions & 0 deletions src/ui/DetailView.h
Original file line number Diff line number Diff line change
Expand Up @@ -34,6 +34,13 @@ class ContentWidget : public QWidget {
virtual void setDiff(const git::Diff &diff, const QString &file = QString(),
const QString &pathspec = QString()) = 0;

/*!
* \brief Set whether or not to show a spinner. This is useful to indicate
* waiting for slow-content to arrive
* \param loading Indicator whether we wait for something to load
*/
virtual void setLoading() {}

virtual void cancelBackgroundTasks() {}

virtual void find() {}
Expand Down Expand Up @@ -72,6 +79,7 @@ class DetailView : public QWidget {
void setCommitMessage(const QString &message);
void setDiff(const git::Diff &diff, const QString &file = QString(),
const QString &pathspec = QString());
void setLoading();

void cancelBackgroundTasks();

Expand Down
12 changes: 7 additions & 5 deletions src/ui/DiffTreeModel.cpp
Original file line number Diff line number Diff line change
Expand Up @@ -60,12 +60,14 @@ void DiffTreeModel::createDiffTree() {
void DiffTreeModel::setDiff(const git::Diff &diff) {
beginResetModel();

if (diff) {
delete mRoot;
mDiff = diff;
mRoot = new Node(mRepo.workdir().path(), -1);
// Always rebuild the tree, even for an invalid diff, so callers that
// clear the diff (e.g. while a new one is loading) actually see an empty
// tree instead of the previous diff's stale rows.
delete mRoot;
mDiff = diff;
mRoot = new Node(mRepo.workdir().path(), -1);
if (diff)
createDiffTree();
}

endResetModel();
}
Expand Down
37 changes: 35 additions & 2 deletions src/ui/DiffView/DiffView.cpp
Original file line number Diff line number Diff line change
Expand Up @@ -16,7 +16,9 @@
#include "ui/DiffTreeModel.h"
#include "ui/DoubleTreeWidget.h"
#include "ui/HotkeyManager.h"
#include "ui/ProgressIndicator.h"
#include "git/Tree.h"
#include <QPainter>
#include <QScrollBar>
#include <QPushButton>
#include <QMimeData>
Expand Down Expand Up @@ -100,10 +102,42 @@ DiffView::DiffView(const git::Repository &repo, QWidget *parent)
shortcut = new QShortcut(this);
moveHalfPageUpHotKey.use(shortcut);
connect(shortcut, &QShortcut::activated, [this] { moveHalfPageUp(); });

connect(&mTimer, &QTimer::timeout, this, [this] {
++mProgress;
if (mLoadingFadein < 1.0f)
mLoadingFadein += 0.1;
viewport()->update();
});
}

DiffView::~DiffView() {}

void DiffView::setLoading(bool loading) {
if (loading) {
mProgress = 0;
mLoadingFadein = 0;
mTimer.start(50);
} else {
mTimer.stop();
}

viewport()->update();
}

void DiffView::paintEvent(QPaintEvent *event) {
QScrollArea::paintEvent(event);

if (!mDiff.isValid()) {
QPainter painter(viewport());
QRect indicator(QPoint(0, 0), ProgressIndicator::size());
indicator.moveCenter(viewport()->rect().center());
ProgressIndicator::paint(&painter, indicator,
palette().color(QPalette::WindowText),
mLoadingFadein, mProgress);
}
}

QWidget *DiffView::file(int index) {
fetchAll(index);
return mFiles.at(index);
Expand Down Expand Up @@ -429,8 +463,7 @@ void DiffView::fetchMore(int fetchWidgets) {
}
int count = indices.count();

for (int i = mFiles.count(); i < count && addedWidgets < fetchWidgets;
++i) {
for (int i = mFiles.count(); i < count && addedWidgets < fetchWidgets; ++i) {

int pidx = indices[i].data(DiffTreeModel::PatchIndexRole).toInt();
git::Patch patch = mDiff.patch(pidx);
Expand Down
14 changes: 14 additions & 0 deletions src/ui/DiffView/DiffView.h
Original file line number Diff line number Diff line change
Expand Up @@ -21,6 +21,7 @@
#include "app/Theme.h"
#include <QMap>
#include <QScrollArea>
#include <QTimer>

class QCheckBox;
class QVBoxLayout;
Expand Down Expand Up @@ -99,6 +100,14 @@ class DiffView : public QScrollArea, public EditorProvider {
* \param enable
*/
void enable(bool enable);

/*!
* \brief Set whether or not to show a spinner. This is useful to indicate
* waiting for slow-content to arrive
* \param loading Indicator whether we wait for something to load
*/
void setLoading(bool loading);

void setModel(DiffTreeModel *model);
void diffTreeModelDataChanged(const QModelIndex &topLeft,
const QModelIndex &bottomRight,
Expand All @@ -119,6 +128,7 @@ class DiffView : public QScrollArea, public EditorProvider {
protected:
void dropEvent(QDropEvent *event) override;
void dragEnterEvent(QDragEnterEvent *event) override;
void paintEvent(QPaintEvent *event) override;

private:
bool canFetchMore();
Expand All @@ -142,6 +152,10 @@ class DiffView : public QScrollArea, public EditorProvider {
DiffTreeModel *mDiffTreeModel{nullptr};
QWidget *mParent{nullptr};
QVBoxLayout *mFileWidgetLayout{nullptr};

float mLoadingFadein = 0;
int mProgress{0};
QTimer mTimer;
};

#endif
19 changes: 19 additions & 0 deletions src/ui/DoubleTreeWidget.cpp
Original file line number Diff line number Diff line change
Expand Up @@ -403,6 +403,20 @@ QString DoubleTreeWidget::selectedFile() const {
return "";
}

void DoubleTreeWidget::setLoading() {
// Clear the file list's rows, the diff view, and the blame editor, then
// let the file list and the diff view paint their own spinner over the
// now-empty content while we wait.
mDiffTreeModel->setDiff(git::Diff());

mEditor->clear();
mDiffView->setDiff(git::Diff());

stagedFiles->setLoading(true);
unstagedFiles->setLoading(true);
mDiffView->setLoading(true);
}

/*!
* \brief DoubleTreeWidget::setDiff
* \param diff
Expand All @@ -414,6 +428,11 @@ void DoubleTreeWidget::setDiff(const git::Diff &diff, const QString &file,
Q_UNUSED(file)
Q_UNUSED(pathspec)

// Diff is being set, so lets not indicate we're loading anything
stagedFiles->setLoading(false);
unstagedFiles->setLoading(false);
mDiffView->setLoading(false);

mSetDiffCounter++;

DebugRefresh("time: " << QDateTime::currentDateTime()
Expand Down
1 change: 1 addition & 0 deletions src/ui/DoubleTreeWidget.h
Original file line number Diff line number Diff line change
Expand Up @@ -41,6 +41,7 @@ class DoubleTreeWidget : public ContentWidget {

void setDiff(const git::Diff &diff, const QString &file = QString(),
const QString &pathspec = QString()) override;
void setLoading() override;

void cancelBackgroundTasks() override;

Expand Down
6 changes: 3 additions & 3 deletions src/ui/ProgressIndicator.cpp
Original file line number Diff line number Diff line change
Expand Up @@ -22,7 +22,7 @@ const int kSize = 26;
QSize ProgressIndicator::size() { return QSize(kSize, kSize); }

void ProgressIndicator::paint(QPainter *painter, const QRect &rect,
const QColor &c, int progress,
const QColor &c, float fadein, int progress,
const QWidget *widget) {
painter->save();
painter->setRenderHints(QPainter::Antialiasing);
Expand Down Expand Up @@ -51,11 +51,11 @@ void ProgressIndicator::paint(QPainter *painter, const QRect &rect,
const qreal in = 7;
const qreal out = 12;

int alpha = 32;
int alpha = 32 * fadein;
QColor color = c;
for (int i = 0; i < 12; ++i) {
color.setAlpha(alpha);
alpha += 16;
alpha += 16 * fadein;

painter->setPen(QPen(color, 2.5, Qt::SolidLine, Qt::RoundCap));

Expand Down
8 changes: 7 additions & 1 deletion src/ui/ProgressIndicator.h
Original file line number Diff line number Diff line change
Expand Up @@ -17,8 +17,14 @@ class ProgressIndicator : public QWidget {
public:
static QSize size();

static void paint(QPainter *painter, const QRect &rect, const QColor &c,
float fadein, int progress,
const QWidget *widget = nullptr);

static void paint(QPainter *painter, const QRect &rect, const QColor &color,
int progress, const QWidget *widget = nullptr);
int progress, const QWidget *widget = nullptr) {
paint(painter, rect, color, 1.0f, progress, widget);
}
};

#endif
6 changes: 6 additions & 0 deletions src/ui/RepoView.cpp
Original file line number Diff line number Diff line change
Expand Up @@ -273,6 +273,8 @@ RepoView::RepoView(const git::Repository &repo, MainWindow *parent)
connect(mRefs, &ReferenceWidget::referenceSelected, mCommits,
&CommitList::selectReference);
connect(mCommits, &CommitList::statusChanged, this, &RepoView::statusChanged);
connect(mCommits, &CommitList::loadingChanged, this,
&RepoView::loadingChanged);

// Respond to pathspec change.
connect(mPathspec, &PathspecWidget::pathspecChanged, this,
Expand Down Expand Up @@ -306,6 +308,8 @@ RepoView::RepoView(const git::Repository &repo, MainWindow *parent)
// Respond to commit list selection change.
connect(mCommits, &CommitList::diffSelected, this, &RepoView::diffSelected,
Qt::ConnectionType::DirectConnection);
connect(mCommits, &CommitList::diffLoading, mDetails,
&DetailView::setLoading);

// Refresh the diff when a whole directory is added to the index.
// FIXME: This is a workaround.
Expand Down Expand Up @@ -505,6 +509,8 @@ RepoView::ViewMode RepoView::viewMode() const { return mDetails->viewMode(); }

void RepoView::setViewMode(ViewMode mode) { mDetails->setViewMode(mode, true); }

bool RepoView::isLoading() const { return mCommits->isLoading(); }

bool RepoView::isWorkingDirectoryDirty() const {
git::Diff status = mCommits->status();
if (!status.isValid())
Expand Down
5 changes: 5 additions & 0 deletions src/ui/RepoView.h
Original file line number Diff line number Diff line change
Expand Up @@ -107,6 +107,10 @@ class RepoView : public QSplitter {
// workdir
bool isWorkingDirectoryDirty() const;

// Whether a status check and/or walker/row rebuild is currently in
// flight for the commit list.
bool isLoading() const;

// current reference
git::Reference reference() const;
void selectReference(const git::Reference &ref);
Expand Down Expand Up @@ -360,6 +364,7 @@ private slots:

signals:
void statusChanged(bool dirty);
void loadingChanged(bool loading);

protected:
void showEvent(QShowEvent *event) override;
Expand Down
Loading
Loading