Page MenuHomePhabricator (Chris)

FileDiffWidget.cpp
No OneTemporary

Authored By
Unknown
Size
27 KB
Referenced Files
None
Subscribers
None

FileDiffWidget.cpp

#include "FileDiffWidget.h"
#include "ui_FileDiffWidget.h"
#include "BigDiffWindow.h"
#include "GitDiff.h"
#include "common/joinpath.h"
#include "MainWindow.h"
#include "common/misc.h"
#include <QBuffer>
#include <QDebug>
#include <QKeyEvent>
#include <QPainter>
enum {
DiffIndexRole = Qt::UserRole,
};
struct FileDiffWidget::Private {
MainWindow *mainwindow = nullptr;
InitParam_ init_param_;
Git::CommitItemList commit_item_list;
// FileDiffWidget::DiffData diff_data;
// FileDiffWidget::DrawData draw_data;
std::vector<std::string> original_lines;
TextEditorEnginePtr engine_left;
TextEditorEnginePtr engine_right;
TextDiffLineList left_lines;
TextDiffLineList right_lines;
int max_line_length = 0;
int term_cursor_row = 0;
int term_cursor_col = 0;
};
FileDiffWidget::FileDiffWidget(QWidget *parent)
: QWidget(parent)
, ui(new Ui::FileDiffWidget)
, m(new Private)
{
ui->setupUi(this);
Qt::WindowFlags flags = windowFlags();
flags &= ~Qt::WindowContextHelpButtonHint;
setWindowFlags(flags);
ui->widget_diff_pixmap->bind(this);
setFocusAcceptable(true);
int n = style()->pixelMetric(QStyle::PM_ScrollBarExtent);
ui->toolButton_fullscreen->setFixedSize(n, n);
setMaximizeButtonEnabled(true);
// ui->widget_diff_left->installEventFilter(this);
// ui->widget_diff_right->installEventFilter(this);
// ui->widget_diff_pixmap->installEventFilter(this);
m->engine_left = TextEditorEnginePtr(new TextEditorEngine);
m->engine_right = TextEditorEnginePtr(new TextEditorEngine);
ui->widget_diff_left->setRenderingMode(TextEditorWidget::DecoratedMode);
ui->widget_diff_right->setRenderingMode(TextEditorWidget::DecoratedMode);
ui->widget_diff_left->setTheme(TextEditorTheme::Light());
ui->widget_diff_right->setTheme(TextEditorTheme::Light());
ui->widget_diff_left->setTextEditorEngine(m->engine_left);
ui->widget_diff_right->setTextEditorEngine(m->engine_right);
ui->widget_diff_left->showHeader(false);
ui->widget_diff_left->showFooter(false);
ui->widget_diff_right->showHeader(false);
ui->widget_diff_right->showFooter(false);
ui->widget_diff_left->setAutoLayout(true);
ui->widget_diff_right->setAutoLayout(true);
ui->widget_diff_left->bindScrollBar(ui->verticalScrollBar, ui->horizontalScrollBar);
ui->widget_diff_right->bindScrollBar(ui->verticalScrollBar, ui->horizontalScrollBar);
ui->widget_diff_left->setToggleSelectionAnchorEnabled(false);
ui->widget_diff_right->setToggleSelectionAnchorEnabled(false);
}
FileDiffWidget::~FileDiffWidget()
{
delete m;
delete ui;
}
void FileDiffWidget::setLeftBorderVisible(bool f)
{
// ui->widget_diff_left->setLeftBorderVisible(f);
}
void FileDiffWidget::setMaximizeButtonEnabled(bool f)
{
ui->toolButton_fullscreen->setVisible(f);
ui->toolButton_fullscreen->setEnabled(f);
}
//FileDiffWidget::DiffData *FileDiffWidget::diffdata()
//{
// return &m->diff_data;
//}
//const FileDiffWidget::DiffData *FileDiffWidget::diffdata() const
//{
// return &m->diff_data;
//}
//FileDiffWidget::DrawData *FileDiffWidget::drawdata()
//{
// return &m->draw_data;
//}
//const FileDiffWidget::DrawData *FileDiffWidget::drawdata() const
//{
// return &m->draw_data;
//}
FileDiffWidget::ViewStyle FileDiffWidget::viewstyle() const
{
return m->init_param_.view_style;
}
void FileDiffWidget::bindContent_()
{
// ui->widget_diff_pixmap->bind(m->mainwindow, this, diffdata(), drawdata());
// ui->widget_diff_left->bind(m->mainwindow, diffdata()->left, drawdata());
// ui->widget_diff_right->bind(m->mainwindow, diffdata()->right, drawdata());
}
void FileDiffWidget::bind(MainWindow *mw)
{
Q_ASSERT(mw);
m->mainwindow = mw;
bindContent_();
connect(ui->verticalScrollBar, SIGNAL(valueChanged(int)), this, SLOT(onVerticalScrollValueChanged(int)));
connect(ui->horizontalScrollBar, SIGNAL(valueChanged(int)), this, SLOT(onHorizontalScrollValueChanged(int)));
// connect(ui->widget_diff_pixmap, SIGNAL(scrollByWheel(int)), this, SLOT(onDiffWidgetWheelScroll(int)));
// connect(ui->widget_diff_pixmap, SIGNAL(valueChanged(int)), this, SLOT(onScrollValueChanged2(int)));
// connect(ui->widget_diff_left, SIGNAL(scrollByWheel(int)), this, SLOT(onDiffWidgetWheelScroll(int)));
// connect(ui->widget_diff_left, SIGNAL(resized()), this, SLOT(onDiffWidgetResized()));
// connect(ui->widget_diff_right, SIGNAL(scrollByWheel(int)), this, SLOT(onDiffWidgetWheelScroll(int)));
// connect(ui->widget_diff_right, SIGNAL(resized()), this, SLOT(onDiffWidgetResized()));
// connect(ui->widget_diff_left, SIGNAL(onBinaryMode()), this, SLOT(setBinaryMode()));
// connect(ui->widget_diff_right, SIGNAL(onBinaryMode()), this, SLOT(setBinaryMode()));
}
GitPtr FileDiffWidget::git()
{
return m->mainwindow->git();
}
Git::Object FileDiffWidget::cat_file(GitPtr /*g*/, QString const &id)
{
return m->mainwindow->cat_file(id);
}
int FileDiffWidget::totalTextLines() const
{
// return diffdata()->left->lines.size();
return m->engine_left->document.lines.size();
}
//int FileDiffWidget::fileviewScrollPos() const
//{
//// return drawdata()->v_scroll_pos;
//}
int FileDiffWidget::visibleLines() const
{
int n = 0;
// if (drawdata()->line_height > 0) {
// n = fileviewHeight() / drawdata()->line_height;
// if (n < 1) n = 1;
// }
return n;
}
void FileDiffWidget::clearDiffView()
{
// diffdata()->clear();
ui->widget_diff_pixmap->clear(false);
// ui->widget_diff_left->clear();
// ui->widget_diff_right->clear();
bindContent_();
}
int FileDiffWidget::fileviewHeight() const
{
return ui->widget_diff_left->height();
}
void FileDiffWidget::resetScrollBarValue()
{
ui->verticalScrollBar->setValue(0);
ui->horizontalScrollBar->setValue(0);
}
void FileDiffWidget::updateVerticalScrollBar()
{
// QScrollBar *sb = ui->verticalScrollBar;
// if (drawdata()->line_height > 0) {
// int lines_per_widget = fileviewHeight() / drawdata()->line_height;
// if (lines_per_widget < diffdata()->left->lines.size() + 1) {
// sb->setRange(0, diffdata()->left->lines.size() - lines_per_widget + 1);
// sb->setPageStep(lines_per_widget);
// return;
// }
// }
// sb->setRange(0, 0);
// sb->setPageStep(0);
}
void FileDiffWidget::updateHorizontalScrollBar()
{
// int headerchars = 0;
// if (viewstyle() == Terminal) {
// headerchars = 0;
// } else if (viewstyle() == SideBySideText) {
// headerchars = 10;
// } else {
// headerchars = 5;
// }
// QScrollBar *sb = ui->horizontalScrollBar;
// if (drawdata()->char_width) {
// int chars = ui->widget_diff_left->width() / drawdata()->char_width;
// sb->setRange(0, m->max_line_length + headerchars - chars);
// sb->setPageStep(chars);
// return;
// }
// sb->setRange(0, 0);
// sb->setPageStep(0);
}
void FileDiffWidget::scrollToBottom()
{
QScrollBar *sb = ui->verticalScrollBar;
sb->setValue(sb->maximum());
}
void FileDiffWidget::updateSliderCursor()
{
if (viewstyle() == SideBySideText) {
// int total = totalTextLines();
// int value = fileviewScrollPos();
// int size = visibleLines();
// ui->widget_diff_pixmap->setScrollPos(total, value, size);
}
}
void FileDiffWidget::updateControls()
{
updateVerticalScrollBar();
updateHorizontalScrollBar();
updateSliderCursor();
}
void FileDiffWidget::makeSideBySideDiffData(Git::Diff const &diff, std::vector<std::string> const &original_lines, TextDiffLineList *left_lines, TextDiffLineList *right_lines)
{
left_lines->clear();
right_lines->clear();
m->original_lines = original_lines;
size_t linenum = original_lines.size();
std::vector<HunkItem> hunks;
int number = 0;
for (auto it = diff.hunks.begin(); it != diff.hunks.end(); it++, number++) {
std::string at = it->at;
if (strncmp(at.c_str(), "@@ -", 4) == 0) {
size_t pos = 0;
size_t len = 0;
char const *p = at.c_str() + 4;
auto ParseNumber = [&](){
size_t v = 0;
while (isdigit(*p & 0xff)) {
v = v * 10 + (*p - '0');
p++;
}
return v;
};
pos = ParseNumber();
if (*p == ',') {
p++;
len = ParseNumber();
} else {
len = 1;
}
if (pos > 0) pos--;
HunkItem item;
item.hunk_number = number;
item.pos = pos;
item.len = len;
for (std::string const &line : it->lines) {
item.lines.push_back(line);
}
hunks.push_back(item);
}
}
std::sort(hunks.begin(), hunks.end(), [](HunkItem const &l, HunkItem const &r){
return l.pos + l.len < r.pos + r.len;
});
size_t h = hunks.size();
while (linenum > 0 || h > 0) {
while (h > 0) {
int hunk_number = h - 1;
HunkItem const &hi = hunks[hunk_number];
if (hi.pos + hi.len < linenum) {
break;
}
std::vector<TextDiffLine> tmp_left;
std::vector<TextDiffLine> tmp_right;
int minus = 0;
int plus = 0;
auto FlushBlank = [&](){
while (minus < plus) {
tmp_left.push_back(TextDiffLine());
minus++;
}
while (minus > plus) {
tmp_right.push_back(TextDiffLine());
plus++;
}
minus = plus = 0;
};
for (auto it = hi.lines.begin(); it != hi.lines.end(); it++) {
std::string line = *it;
int c = line[0] & 0xff;
line = line.substr(1);
if (c == '-') {
minus++;
TextDiffLine l(line, TextDiffLine::Del);
l.hunk_number = hunk_number;
tmp_left.push_back(l);
} else if (c == '+') {
plus++;
TextDiffLine l(line, TextDiffLine::Add);
l.hunk_number = hunk_number;
tmp_right.push_back(l);
} else {
FlushBlank();
TextDiffLine l(line, TextDiffLine::Normal);
l.hunk_number = hunk_number;
tmp_left.push_back(l);
tmp_right.push_back(l);
}
}
FlushBlank();
for (auto it = tmp_left.rbegin(); it != tmp_left.rend(); it++) left_lines->push_back(*it);
for (auto it = tmp_right.rbegin(); it != tmp_right.rend(); it++) right_lines->push_back(*it);
linenum = hi.pos;
h--;
}
if (linenum > 0) {
linenum--;
if (linenum < (size_t)original_lines.size()) {
std::string line = original_lines[linenum];
left_lines->push_back(TextDiffLine(line, TextDiffLine::Normal));
right_lines->push_back(TextDiffLine(line, TextDiffLine::Normal));
}
}
}
std::reverse(left_lines->begin(), left_lines->end());
std::reverse(right_lines->begin(), right_lines->end());
}
void FileDiffWidget::setDiffText(Git::Diff const &diff, std::vector<std::string> const &original_lines, TextDiffLineList const &left, TextDiffLineList const &right)
{
// QPixmap pm(1, 1);
// QPainter pr(&pm);
// pr.setFont(ui->widget_diff_left->font());
// QFontMetrics fm = pr.fontMetrics();
m->max_line_length = 0;
// parseDiff(s, &diff, &diff);
TextDiffLineList left_lines;
TextDiffLineList right_lines;
makeSideBySideDiffData(diff, original_lines, &left_lines, &right_lines);
enum Pane {
Left,
Right,
};
auto MakeDiffLines = [&](TextDiffLineList const &lines, Pane pane, TextDiffLineList *out){
out->clear();
int linenum = 1;
for (TextDiffLine const &line : lines) {
TextDiffLine item = line;
switch (item.type) {
case TextDiffLine::Normal:
item.line_number = linenum++;
break;
case TextDiffLine::Add:
if (pane == Pane::Right) {
item.line_number = linenum++;
}
break;
case TextDiffLine::Del:
if (pane == Pane::Left) {
item.line_number = linenum++;
}
break;
default:
item.line_number = linenum; // 行番号は設定するが、インクリメントはしない
break;
}
out->push_back(item);
}
};
MakeDiffLines(left_lines, Pane::Left, &m->left_lines);
MakeDiffLines(right_lines, Pane::Right, &m->right_lines);
ui->widget_diff_left->setDocument(&m->left_lines);
ui->widget_diff_right->setDocument(&m->right_lines);
ui->widget_diff_left->scrollToTop();
ui->widget_diff_right->scrollToTop();
ui->widget_diff_pixmap->updatePixmap();
ui->widget_diff_pixmap->update();
}
FilePreviewType FileDiffWidget::setupPreviewWidget()
{
clearDiffView();
// object data
// {
// Git::Diff const &diff = m->init_param_.diff;
// diffdata()->left->path = diff.path;
// diffdata()->right->path = diff.path;
// diffdata()->left->id = diff.blob.a_id;
// diffdata()->right->id = diff.blob.b_id;
// diffdata()->left->bytes = m->init_param_.bytes_a;
// diffdata()->right->bytes = m->init_param_.bytes_b;
// }
// layout widgets
{
// 水平スクロールバーを取り外す
int i = ui->gridLayout->indexOf(ui->horizontalScrollBar);
if (i >= 0) delete ui->gridLayout->takeAt(i); // this will deleted QWidgetItem, it wrapped horizontalScrollBar.
ViewStyle vs = m->init_param_.view_style;
bool single = vs == ViewStyle::Terminal || vs == ViewStyle::SingleFile;
if (single) { // 1ファイル表示モード
ui->gridLayout->addWidget(ui->horizontalScrollBar, 1, 1, 1, 1); // 水平スクロールバーを colspan=1 で据え付ける
ui->widget_diff_right->setVisible(false); // 右ファイルビューを非表示
ui->widget_diff_pixmap->setVisible(false); // pixmap非表示
} else { // 2ファイル表示モード
ui->gridLayout->addWidget(ui->horizontalScrollBar, 1, 1, 1, 2); // 水平スクロールバーを colspan=2 で据え付ける
ui->widget_diff_right->setVisible(true); // 右ファイルビューを表示
ui->widget_diff_pixmap->setVisible(true); // pixmap表示
}
}
// init content
QString mimetype_l = m->mainwindow->determinFileType(m->init_param_.bytes_a, true);
QString mimetype_r = m->mainwindow->determinFileType(m->init_param_.bytes_b, true);
// ui->widget_diff_left->setFileType(mimetype_l);
// ui->widget_diff_right->setFileType(mimetype_r);
if (misc::isImage(mimetype_l) || misc::isImage(mimetype_r)) { // image
ui->verticalScrollBar->setVisible(false);
ui->horizontalScrollBar->setVisible(false);
if (m->init_param_.view_style == FileDiffWidget::ViewStyle::SideBySideImage) {
// FilePreviewWidget *w_left = ui->widget_diff_left;
// FilePreviewWidget *w_right = ui->widget_diff_right;
// w_left->setImage(mimetype_l, diffdata()->left->bytes);
// w_right->setImage(mimetype_r, diffdata()->right->bytes);
// return w_left->filetype();
return FilePreviewType::Text;
} else {
// FilePreviewType type = (m->init_param_.view_style == FileDiffWidget::ViewStyle::RightOnly
// ? ui->widget_diff_right
// : ui->widget_diff_left
// )->filetype();
// ui->widget_diff_left->setImage(mimetype_l, diffdata()->left->bytes);
// ui->widget_diff_right->setImage(mimetype_r, diffdata()->right->bytes);
// return type;
return FilePreviewType::Text;
}
} else { // text
ui->verticalScrollBar->setVisible(true);
ui->horizontalScrollBar->setVisible(true);
std::vector<std::string> lines;
{
QByteArray const *p = nullptr;
if (m->init_param_.view_style == FileDiffWidget::ViewStyle::LeftOnly || m->init_param_.view_style == FileDiffWidget::ViewStyle::SideBySideText) {
p = &m->init_param_.bytes_a;
} else if (m->init_param_.view_style == FileDiffWidget::ViewStyle::RightOnly) {
p = &m->init_param_.bytes_b;
}
if (p && !p->isEmpty()) {
// lines = misc::splitLines(*p, [](char const *ptr, size_t len){
// return QString::fromUtf8(ptr, len);
// });
misc::splitLines(p->data(), p->data() + p->size(), &lines);
}
}
// diffdata()->original_lines = lines;
return FilePreviewType::Text;
}
}
void FileDiffWidget::setBinaryMode(bool f)
{
// diffdata()->original_lines.clear();
// ui->widget_diff_left->setBinaryMode(f);
// ui->widget_diff_right->setBinaryMode(f);
ui->widget_diff_left->update();
ui->widget_diff_right->update();
}
void FileDiffWidget::setBinaryMode()
{
setBinaryMode(true);
}
void FileDiffWidget::setSingleFile(QByteArray const &ba, QString const &id, QString const &path)
{
m->init_param_ = InitParam_();
m->init_param_.view_style = FileDiffWidget::ViewStyle::SingleFile;
m->init_param_.bytes_a = ba;
m->init_param_.diff.path = path;
m->init_param_.diff.blob.a_id = id;
if (setupPreviewWidget() == FilePreviewType::Text) {
TextDiffLineList left_lines;
TextDiffLineList right_lines;
// for (std::string const &line : diffdata()->original_lines) {
// left_lines.push_back(TextDiffLine(line, TextDiffLine::Normal));
// }
// setDiffText(left_lines, right_lines);
}
}
void FileDiffWidget::setLeftOnly(QByteArray const &ba, Git::Diff const &diff)
{
m->init_param_ = InitParam_();
m->init_param_.view_style = FileDiffWidget::ViewStyle::LeftOnly;
m->init_param_.bytes_a = ba;
m->init_param_.diff = diff;
if (setupPreviewWidget() == FilePreviewType::Text) {
TextDiffLineList left_lines;
TextDiffLineList right_lines;
for (std::string const &line : m->original_lines) {
left_lines.push_back(TextDiffLine(line, TextDiffLine::Del));
right_lines.push_back(TextDiffLine());
}
setDiffText(diff, m->original_lines, left_lines, right_lines);
}
}
void FileDiffWidget::setRightOnly(QByteArray const &ba, Git::Diff const &diff)
{
m->init_param_ = InitParam_();
m->init_param_.view_style = FileDiffWidget::ViewStyle::RightOnly;
m->init_param_.bytes_b = ba;
m->init_param_.diff = diff;
if (setupPreviewWidget() == FilePreviewType::Text) {
TextDiffLineList left_lines;
TextDiffLineList right_lines;
for (std::string const &line : m->original_lines) {
left_lines.push_back(TextDiffLine());
right_lines.push_back(TextDiffLine(line, TextDiffLine::Add));
}
setDiffText(diff, m->original_lines, left_lines, right_lines);
}
}
void FileDiffWidget::setSideBySide(QByteArray const &ba, Git::Diff const &diff, bool uncommited, QString const &workingdir)
{
m->init_param_ = InitParam_();
m->init_param_.view_style = FileDiffWidget::ViewStyle::SideBySideText;
m->init_param_.bytes_a = ba;
m->init_param_.diff = diff;
m->init_param_.uncommited = uncommited;
m->init_param_.workingdir = workingdir;
if (setupPreviewWidget() == FilePreviewType::Text) {
if (uncommited) {
QString path = workingdir / diff.path;
// diffdata()->right->id = GitDiff::prependPathPrefix(path);
}
TextDiffLineList left_lines;
TextDiffLineList right_lines;
makeSideBySideDiffData(diff, m->original_lines, &left_lines, &right_lines);
setDiffText(diff, m->original_lines, left_lines, right_lines);
}
}
void FileDiffWidget::setSideBySide(QByteArray const &ba_a, QByteArray const &ba_b, QString const &workingdir)
{
m->init_param_ = InitParam_();
m->init_param_.view_style = FileDiffWidget::ViewStyle::SideBySideImage;
m->init_param_.bytes_a = ba_a;
m->init_param_.bytes_b = ba_b;
m->init_param_.workingdir = workingdir;
if (setupPreviewWidget() == FilePreviewType::Text) {
TextDiffLineList left_lines;
TextDiffLineList right_lines;
makeSideBySideDiffData(m->init_param_.diff, m->original_lines, &left_lines, &right_lines);
setDiffText(m->init_param_.diff, m->original_lines, left_lines, right_lines);
}
}
bool FileDiffWidget::isValidID_(QString const &id)
{
if (id.startsWith(PATH_PREFIX)) {
return true;
}
return Git::isValidID(id);
}
void FileDiffWidget::updateDiffView(Git::Diff const &info, bool uncommited)
{
GitPtr g = git();
if (!g) return;
if (!g->isValidWorkingCopy()) return;
if (isValidID_(info.blob.a_id) && isValidID_(info.blob.b_id)) {
Git::Object obj_a = cat_file(g, info.blob.a_id);
Git::Object obj_b = cat_file(g, info.blob.b_id);
QString mime_a = m->mainwindow->determinFileType(obj_a.content, true);
QString mime_b = m->mainwindow->determinFileType(obj_b.content, true);
if (misc::isImage(mime_a) && misc::isImage(mime_b)) {
setSideBySide(obj_a.content, obj_b.content, g->workingRepositoryDir());
goto L1;
}
}
{
Git::Diff diff;
if (isValidID_(info.blob.a_id) && isValidID_(info.blob.b_id)) {
std::string text = GitDiff::diffFile(g, info.blob.a_id, info.blob.b_id).toStdString();
GitDiff::parseDiff(text, &info, &diff);
} else {
diff = info;
}
Git::Object obj;
if (isValidID_(diff.blob.a_id)) { // 左が有効
obj = cat_file(g, diff.blob.a_id);
if (isValidID_(diff.blob.b_id)) { // 右が有効
setSideBySide(obj.content, diff, uncommited, g->workingRepositoryDir()); // 通常のdiff表示
} else {
setLeftOnly(obj.content, diff); // 右が無効の時は、削除されたファイル
}
} else if (isValidID_(diff.blob.b_id)) { // 左が無効で右が有効の時は、追加されたファイル
obj = cat_file(g, diff.blob.b_id);
setRightOnly(obj.content, diff);
}
}
L1:;
ui->widget_diff_pixmap->clear(false);
resetScrollBarValue();
updateControls();
ui->widget_diff_pixmap->update();
}
void FileDiffWidget::updateDiffView(QString id_left, QString id_right)
{
GitPtr g = git();
if (!g) return;
if (!g->isValidWorkingCopy()) return;
Git::Diff diff;
diff.blob.a_id = id_left;
diff.blob.b_id = id_right;
diff.mode = "0";
std::string text = GitDiff::diffFile(g, diff.blob.a_id, diff.blob.b_id).toStdString();
GitDiff::parseDiff(text, &diff, &diff);
Git::Object obj = cat_file(g, diff.blob.a_id);
setSideBySide(obj.content, diff, false, g->workingRepositoryDir());
ui->widget_diff_pixmap->clear(false);
resetScrollBarValue();
updateControls();
ui->widget_diff_pixmap->update();
}
bool FileDiffWidget::eventFilter(QObject *watched, QEvent *event)
{
#if 0
if (event->type() == QEvent::KeyPress) {
QKeyEvent *e = dynamic_cast<QKeyEvent *>(event);
Q_ASSERT(e);
int k = e->key();
if (watched == ui->widget_diff_left || watched == ui->widget_diff_right || watched == ui->widget_diff_pixmap) {
if (e->modifiers() & Qt::AltModifier) {
switch (k) {
case Qt::Key_Up:
emit movePreviousItem();
return true;
case Qt::Key_Down:
emit moveNextItem();
return true;
}
} else {
QScrollBar::SliderAction act = QScrollBar::SliderNoAction;
switch (k) {
case Qt::Key_Up: act = QScrollBar::SliderSingleStepSub; break;
case Qt::Key_Down: act = QScrollBar::SliderSingleStepAdd; break;
case Qt::Key_PageUp: act = QScrollBar::SliderPageStepSub; break;
case Qt::Key_PageDown: act = QScrollBar::SliderPageStepAdd; break;
case Qt::Key_Home: act = QScrollBar::SliderToMinimum; break;
case Qt::Key_End: act = QScrollBar::SliderToMaximum; break;
}
if (act != QScrollBar::SliderNoAction) {
ui->verticalScrollBar->triggerAction(act);
return true;
}
}
}
}
#endif
return false;
}
void FileDiffWidget::scrollTo(int value)
{
// drawdata()->v_scroll_pos = value;
// ui->widget_diff_left->update();
// ui->widget_diff_right->update();
ui->verticalScrollBar->setValue(value);
}
void FileDiffWidget::onVerticalScrollValueChanged(int value)
{
// scrollTo(value);
// updateSliderCursor();
refrectScrollBar();
}
void FileDiffWidget::onHorizontalScrollValueChanged(int value)
{
// m->draw_data.h_scroll_pos = value;
// ui->widget_diff_left->update();
// ui->widget_diff_right->update();
refrectScrollBar();
}
void FileDiffWidget::onDiffWidgetWheelScroll(int lines)
{
while (lines > 0) {
ui->verticalScrollBar->triggerAction(QScrollBar::SliderSingleStepAdd);
lines--;
}
while (lines < 0) {
ui->verticalScrollBar->triggerAction(QScrollBar::SliderSingleStepSub);
lines++;
}
}
void FileDiffWidget::onScrollValueChanged2(int value)
{
ui->verticalScrollBar->setValue(value);
}
void FileDiffWidget::onDiffWidgetResized()
{
updateControls();
}
QPixmap FileDiffWidget::makeDiffPixmap(ViewType side, int width, int height, FileDiffWidget::DiffData const *diffdata, FileDiffWidget::DrawData const *drawdata)
{
auto MakePixmap = [&](TextDiffLineList const &lines, int w, int h){
const int scale = 1;
QPixmap pixmap = QPixmap(w, h * scale);
pixmap.fill(Qt::white);
QPainter pr(&pixmap);
auto Loop = [&](std::function<QColor(TextDiffLine::Type)> getcolor){
int i = 0;
while (i < lines.size()) {
TextDiffLine::Type type = (TextDiffLine::Type)lines[i].type;
int j = i + 1;
if (type != TextDiffLine::Normal) {
while (j < lines.size()) {
if (lines[j].type != type) break;
j++;
}
int y = i * pixmap.height() / lines.size();
int z = j * pixmap.height() / lines.size();
if (z == y) z = y + 1;
QColor color = getcolor(type);
if (color.isValid()) pr.fillRect(0, y, w, z - y, color);
}
i = j;
}
};
Loop([&](TextDiffLine::Type t)->QColor{
switch (t) {
case TextDiffLine::Unknown: return drawdata->bgcolor_gray;
}
return QColor();
});
Loop([&](TextDiffLine::Type t)->QColor{
switch (t) {
case TextDiffLine::Add: return drawdata->bgcolor_add_dark;
case TextDiffLine::Del: return drawdata->bgcolor_del_dark;
}
return QColor();
});
if (scale == 1) return pixmap;
return pixmap.scaled(w, h, Qt::IgnoreAspectRatio, Qt::SmoothTransformation);
};
if (side == ViewType::Left) return MakePixmap(diffdata->left->lines, width, height);
if (side == ViewType::Right) return MakePixmap(diffdata->right->lines, width, height);
return QPixmap();
}
void FileDiffWidget::on_toolButton_fullscreen_clicked()
{
BigDiffWindow win(m->mainwindow);
win.setWindowState(Qt::WindowMaximized);
win.init(m->mainwindow, m->init_param_);
win.exec();
}
void FileDiffWidget::setTerminalMode()
{
setSingleFile(QByteArray(), QString(), QString());
m->init_param_.view_style = ViewStyle::Terminal;
// ui->widget_diff_left->setTerminalMode();
ui->horizontalScrollBar->setVisible(false);
}
bool FileDiffWidget::isTerminalMode() const
{
return m->init_param_.view_style == ViewStyle::Terminal;
}
void FileDiffWidget::termWrite(ushort c)
{
#if 0
if (!isTerminalMode()) return;
if (c == '\r') {
m->term_cursor_col = 0;
return;
}
if (c == '\n') {
m->term_cursor_col = 0;
m->term_cursor_row++;
return;
}
TextDiffLineList *lines = &m->diff_data.left->lines;
while (lines->size() <= m->term_cursor_row) {
lines->push_back(TextDiffLine(TextDiffLine::Normal, 100));
}
TextDiffLine *line = &(*lines)[m->term_cursor_row];
while ((int)line->text.size() <= m->term_cursor_col) {
line->text.push_back(' ');
}
line->text[m->term_cursor_col] = c;
m->term_cursor_col++;
#endif
}
void FileDiffWidget::termWrite(ushort const *begin, ushort const *end)
{
ushort const *p = begin;
while (p < end) {
termWrite(*p);
p++;
}
}
void FileDiffWidget::termWrite(QString const &text)
{
ushort const *begin = text.utf16();
ushort const *end = begin + text.size();
termWrite(begin, end);
}
void FileDiffWidget::setFocusAcceptable(bool f)
{
Qt::FocusPolicy focuspolicy = f ? Qt::StrongFocus : Qt::NoFocus;
ui->widget_diff_left->setFocusPolicy(focuspolicy);
ui->widget_diff_right->setFocusPolicy(focuspolicy);
}
void FileDiffWidget::refrectScrollBar()
{
ui->widget_diff_left->refrectScrollBar();
ui->widget_diff_right->refrectScrollBar();
ui->widget_diff_pixmap->setScrollPos(m->engine_left->document.lines.size(), ui->verticalScrollBar->value(), ui->verticalScrollBar->pageStep());
}
QPixmap FileDiffWidget::makeDiffPixmap(Pane pane, int width, int height)
{
auto MakePixmap = [&](TextDiffLineList const &lines, int w, int h){
const int scale = 1;
QPixmap pixmap = QPixmap(w, h * scale);
pixmap.fill(Qt::white);
QPainter pr(&pixmap);
auto Loop = [&](std::function<QColor(TextDiffLine::Type)> getcolor){
int i = 0;
while (i < lines.size()) {
TextDiffLine::Type type = (TextDiffLine::Type)lines[i].type;
int j = i + 1;
if (type != TextDiffLine::Normal) {
while (j < lines.size()) {
if (lines[j].type != type) break;
j++;
}
int y = i * pixmap.height() / lines.size();
int z = j * pixmap.height() / lines.size();
if (z == y) z = y + 1;
QColor color = getcolor(type);
if (color.isValid()) pr.fillRect(0, y, w, z - y, color);
}
i = j;
}
};
Loop([&](TextDiffLine::Type t)->QColor{
switch (t) {
case TextDiffLine::Unknown: return ui->widget_diff_left->theme()->bgDiffUnknown();
}
return QColor();
});
Loop([&](TextDiffLine::Type t)->QColor{
switch (t) {
case TextDiffLine::Add: return ui->widget_diff_left->theme()->bgDiffAddDark();
case TextDiffLine::Del: return ui->widget_diff_left->theme()->bgDiffDelDark();
}
return QColor();
});
if (scale == 1) return pixmap;
return pixmap.scaled(w, h, Qt::IgnoreAspectRatio, Qt::SmoothTransformation);
};
if (pane == Pane::Left) return MakePixmap(m->left_lines, width, height);
if (pane == Pane::Right) return MakePixmap(m->right_lines, width, height);
return QPixmap();
}

File Metadata

Mime Type
text/x-c
Expires
Sun, Nov 15, 2:44 PM (1 d, 18 h)
Storage Engine
blob
Storage Format
Raw Data
Storage Handle
152407
Default Alt Text
FileDiffWidget.cpp (27 KB)

Event Timeline