Page Menu
Home
Phabricator (Chris)
Search
Configure Global Search
Log In
Files
F632595
FileDiffWidget.cpp
No One
Temporary
Actions
Download File
Edit File
Delete File
View Transforms
Subscribe
Mute Notifications
Flag For Later
Award Token
Authored By
Unknown
Size
27 KB
Referenced Files
None
Subscribers
None
FileDiffWidget.cpp
View Options
#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
Details
Attached
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)
Attached To
Mode
R77 Guitar
Attached
Detach File
Event Timeline