Skip to content
GitLab
Projects
Groups
Snippets
/
Help
Help
Support
Community forum
Keyboard shortcuts
?
Submit feedback
Contribute to GitLab
Sign in
Toggle navigation
Menu
Open sidebar
Utilities
Kate
Commits
26473a97
Commit
26473a97
authored
Dec 25, 2021
by
Waqar Ahmed
Committed by
Christoph Cullmann
Dec 28, 2021
Browse files
Add fuzzy filtering to GitWidget
parent
833e815c
Pipeline
#115390
passed with stage
in 5 minutes and 25 seconds
Changes
4
Pipelines
3
Hide whitespace changes
Inline
Side-by-side
addons/project/gitstatusmodel.cpp
View file @
26473a97
...
...
@@ -155,6 +155,8 @@ QVariant GitStatusModel::data(const QModelIndex &index, int role) const
}
else
if
(
index
.
column
()
==
1
&&
rootIndex
==
0
)
{
return
KColorScheme
().
foreground
(
KColorScheme
::
PositiveText
).
color
();
}
}
else
if
(
role
==
Role
::
GitItemType
)
{
return
(
ItemType
)
rootIndex
;
}
}
...
...
@@ -170,14 +172,3 @@ void GitStatusModel::setStatusItems(GitUtils::GitParsedStatus status, bool numSt
m_showNumStat
=
numStat
;
endResetModel
();
}
QVector
<
int
>
GitStatusModel
::
emptyRows
()
{
QVector
<
int
>
empty
;
for
(
int
i
=
0
;
i
<
4
;
++
i
)
{
if
(
m_nodes
[
i
].
isEmpty
())
{
empty
.
append
(
i
);
}
}
return
empty
;
}
addons/project/gitstatusmodel.h
View file @
26473a97
...
...
@@ -15,8 +15,16 @@ class GitStatusModel : public QAbstractItemModel
public:
explicit
GitStatusModel
(
QObject
*
parent
);
enum
ItemType
{
NodeStage
=
0
,
NodeChanges
,
NodeConflict
,
NodeUntrack
,
NodeFile
};
enum
Role
{
TreeItemType
=
Qt
::
UserRole
+
1
,
FileNameRole
};
enum
ItemType
{
NodeStage
=
0
,
NodeChanges
,
NodeConflict
,
NodeUntrack
,
NodeFile
,
};
Q_ENUM
(
ItemType
)
enum
Role
{
TreeItemType
=
Qt
::
UserRole
+
1
,
FileNameRole
,
GitItemType
};
public:
QModelIndex
index
(
int
row
,
int
column
,
const
QModelIndex
&
parent
)
const
override
;
...
...
@@ -26,7 +34,6 @@ public:
QVariant
data
(
const
QModelIndex
&
index
,
int
role
)
const
override
;
void
setStatusItems
(
GitUtils
::
GitParsedStatus
status
,
bool
numStat
);
QVector
<
int
>
emptyRows
();
const
QVector
<
GitUtils
::
StatusItem
>
&
untrackedFiles
()
const
{
...
...
addons/project/gitwidget.cpp
View file @
26473a97
...
...
@@ -54,6 +54,8 @@
#include
<KTextEditor/Message>
#include
<KTextEditor/View>
#include
<kfts_fuzzy_match.h>
class
NumStatStyle
final
:
public
QStyledItemDelegate
{
public:
...
...
@@ -122,6 +124,54 @@ private:
KateProjectPlugin
*
m_plugin
;
};
class
StatusProxyModel
:
public
QSortFilterProxyModel
{
public:
using
QSortFilterProxyModel
::
QSortFilterProxyModel
;
bool
isTopLevel
(
const
QModelIndex
&
idx
)
const
{
return
!
idx
.
isValid
();
}
bool
filterAcceptsRow
(
int
sourceRow
,
const
QModelIndex
&
parent
)
const
override
{
// top level node
auto
index
=
sourceModel
()
->
index
(
sourceRow
,
0
,
parent
);
if
(
isTopLevel
(
parent
))
{
// Staged are always visible
if
(
index
.
row
()
==
GitStatusModel
::
ItemType
::
NodeStage
)
return
true
;
// otherwise visible only if rowCount > 0
return
sourceModel
()
->
rowCount
(
index
)
>
0
;
}
if
(
!
index
.
isValid
())
{
return
false
;
}
// no pattern => everything visible
if
(
m_text
.
isEmpty
())
{
return
true
;
}
const
QString
file
=
index
.
data
().
toString
();
int
s
=
0
;
// not using score atm
return
kfts
::
fuzzy_match
(
m_text
,
file
,
s
);
}
void
setFilterText
(
const
QString
&
text
)
{
beginResetModel
();
m_text
=
text
;
endResetModel
();
}
private:
QString
m_text
;
};
class
GitWidgetTreeView
:
public
QTreeView
{
public:
...
...
@@ -212,12 +262,21 @@ GitWidget::GitWidget(KateProject *project, KTextEditor::MainWindow *mainWindow,
layout
->
addLayout
(
btnsLayout
);
layout
->
addWidget
(
m_treeView
);
m_filterLineEdit
=
new
QLineEdit
(
this
);
m_filterLineEdit
->
setPlaceholderText
(
i18n
(
"Type to filter..."
));
layout
->
addWidget
(
m_filterLineEdit
);
m_model
=
new
GitStatusModel
(
this
);
auto
proxy
=
new
StatusProxyModel
(
this
);
proxy
->
setSourceModel
(
m_model
);
connect
(
m_filterLineEdit
,
&
QLineEdit
::
textChanged
,
proxy
,
&
StatusProxyModel
::
setFilterText
);
connect
(
m_filterLineEdit
,
&
QLineEdit
::
textChanged
,
m_treeView
,
&
QTreeView
::
expandAll
);
m_treeView
->
setUniformRowHeights
(
true
);
m_treeView
->
setHeaderHidden
(
true
);
m_treeView
->
setSelectionMode
(
QTreeView
::
ExtendedSelection
);
m_treeView
->
setModel
(
m_model
);
m_treeView
->
setModel
(
proxy
);
m_treeView
->
installEventFilter
(
this
);
m_treeView
->
setRootIsDecorated
(
false
);
...
...
@@ -648,7 +707,7 @@ void GitWidget::openCommitChangesDialog(bool amend)
void
GitWidget
::
handleClick
(
const
QModelIndex
&
idx
,
ClickAction
clickAction
)
{
auto
type
=
idx
.
data
(
GitStatusModel
::
TreeItemType
);
const
auto
type
=
idx
.
data
(
GitStatusModel
::
TreeItemType
);
if
(
type
!=
GitStatusModel
::
NodeFile
)
{
return
;
}
...
...
@@ -658,7 +717,8 @@ void GitWidget::handleClick(const QModelIndex &idx, ClickAction clickAction)
}
const
QString
file
=
m_gitPath
+
idx
.
data
(
GitStatusModel
::
FileNameRole
).
toString
();
bool
staged
=
idx
.
internalId
()
==
GitStatusModel
::
NodeStage
;
const
auto
statusItemType
=
idx
.
data
(
GitStatusModel
::
GitItemType
).
value
<
GitStatusModel
::
ItemType
>
();
const
bool
staged
=
statusItemType
==
GitStatusModel
::
NodeStage
;
if
(
clickAction
==
ClickAction
::
StageUnstage
)
{
if
(
staged
)
{
...
...
@@ -688,19 +748,20 @@ void GitWidget::treeViewDoubleClicked(const QModelIndex &idx)
void
GitWidget
::
hideEmptyTreeNodes
()
{
const
auto
emptyRows
=
m_model
->
emptyRows
();
m_treeView
->
expand
(
m_model
->
getModelIndex
((
GitStatusModel
::
NodeStage
)));
// 1 because "Staged" will always be visible
for
(
int
i
=
1
;
i
<
4
;
++
i
)
{
if
(
emptyRows
.
contains
(
i
))
{
m_treeView
->
setRowHidden
(
i
,
QModelIndex
(),
true
);
}
else
{
m_treeView
->
setRowHidden
(
i
,
QModelIndex
(),
false
);
if
(
i
!=
GitStatusModel
::
NodeUntrack
)
{
m_treeView
->
expand
(
m_model
->
getModelIndex
((
GitStatusModel
::
ItemType
)
i
));
}
auto
expand
=
[
this
](
GitStatusModel
::
ItemType
t
)
{
auto
*
model
=
m_treeView
->
model
();
auto
index
=
model
->
index
(
t
,
0
);
if
(
!
index
.
isValid
()
||
index
.
data
(
GitStatusModel
::
TreeItemType
).
toInt
()
==
GitStatusModel
::
NodeUntrack
)
{
return
;
}
}
if
(
model
->
rowCount
(
index
)
>
0
&&
!
m_treeView
->
isExpanded
(
index
))
{
m_treeView
->
expand
(
index
);
}
};
expand
(
GitStatusModel
::
NodeStage
);
expand
(
GitStatusModel
::
NodeChanges
);
expand
(
GitStatusModel
::
NodeConflict
);
m_treeView
->
resizeColumnToContents
(
0
);
m_treeView
->
resizeColumnToContents
(
1
);
...
...
@@ -907,12 +968,12 @@ void GitWidget::treeViewContextMenuEvent(QContextMenuEvent *e)
}
}
auto
idx
=
m_model
->
index
(
m_treeView
->
currentIndex
()
.
row
(),
0
,
m_treeView
->
currentIndex
().
parent
())
;
auto
t
ype
=
idx
.
data
(
GitStatusModel
::
TreeItemType
);
const
auto
idx
=
m_treeView
->
currentIndex
();
auto
t
reeItem
=
idx
.
data
(
GitStatusModel
::
TreeItemType
);
if
(
t
ype
==
GitStatusModel
::
NodeChanges
||
t
ype
==
GitStatusModel
::
NodeUntrack
)
{
if
(
t
reeItem
==
GitStatusModel
::
NodeChanges
||
t
reeItem
==
GitStatusModel
::
NodeUntrack
)
{
QMenu
menu
;
bool
untracked
=
t
ype
==
GitStatusModel
::
NodeUntrack
;
bool
untracked
=
t
reeItem
==
GitStatusModel
::
NodeUntrack
;
auto
stageAct
=
menu
.
addAction
(
i18n
(
"Stage All"
));
...
...
@@ -935,7 +996,7 @@ void GitWidget::treeViewContextMenuEvent(QContextMenuEvent *e)
});
if
(
act
==
stageAct
)
{
stage
(
files
,
t
ype
==
GitStatusModel
::
NodeUntrack
);
stage
(
files
,
t
reeItem
==
GitStatusModel
::
NodeUntrack
);
}
else
if
(
act
==
discardAct
&&
!
untracked
)
{
auto
ret
=
confirm
(
this
,
i18n
(
"Are you sure you want to remove these files?"
));
if
(
ret
==
KMessageBox
::
Yes
)
{
...
...
@@ -960,10 +1021,11 @@ void GitWidget::treeViewContextMenuEvent(QContextMenuEvent *e)
}
else
if
(
!
untracked
&&
act
==
diff
)
{
showDiff
(
QString
(),
false
);
}
}
else
if
(
t
ype
==
GitStatusModel
::
NodeFile
)
{
}
else
if
(
t
reeItem
==
GitStatusModel
::
NodeFile
)
{
QMenu
menu
;
bool
staged
=
idx
.
internalId
()
==
GitStatusModel
::
NodeStage
;
bool
untracked
=
idx
.
internalId
()
==
GitStatusModel
::
NodeUntrack
;
const
auto
statusItemType
=
idx
.
data
(
GitStatusModel
::
GitItemType
).
value
<
GitStatusModel
::
ItemType
>
();
const
bool
staged
=
statusItemType
==
GitStatusModel
::
NodeStage
;
const
bool
untracked
=
statusItemType
==
GitStatusModel
::
NodeUntrack
;
auto
openFile
=
menu
.
addAction
(
i18n
(
"Open file"
));
auto
showDiffAct
=
untracked
?
nullptr
:
menu
.
addAction
(
QIcon
::
fromTheme
(
QStringLiteral
(
"vcs-diff"
)),
i18n
(
"Show raw diff"
));
...
...
@@ -1005,7 +1067,7 @@ void GitWidget::treeViewContextMenuEvent(QContextMenuEvent *e)
}
else
if
(
act
==
openFile
)
{
m_mainWin
->
openUrl
(
QUrl
::
fromLocalFile
(
file
));
}
}
else
if
(
t
ype
==
GitStatusModel
::
NodeStage
)
{
}
else
if
(
t
reeItem
==
GitStatusModel
::
NodeStage
)
{
QMenu
menu
;
auto
stage
=
menu
.
addAction
(
i18n
(
"Unstage All"
));
auto
diff
=
menu
.
addAction
(
i18n
(
"Show diff"
));
...
...
@@ -1040,16 +1102,23 @@ void GitWidget::selectedContextMenu(QContextMenuEvent *e)
if
(
auto
selModel
=
m_treeView
->
selectionModel
())
{
const
auto
idxList
=
selModel
->
selectedIndexes
();
for
(
const
auto
&
idx
:
idxList
)
{
if
(
idx
.
internalId
()
==
GitStatusModel
::
NodeStage
)
{
selectionHasStagedItems
=
true
;
}
else
if
(
!
idx
.
parent
().
isValid
())
{
// can't allow main nodes to be selected
// no context menu for multi selection of top level nodes
const
bool
isTopLevel
=
idx
.
data
(
GitStatusModel
::
TreeItemType
).
value
<
GitStatusModel
::
ItemType
>
()
!=
GitStatusModel
::
NodeFile
;
if
(
isTopLevel
)
{
return
;
}
else
if
(
idx
.
internalId
()
==
GitStatusModel
::
NodeUntrack
)
{
}
// what type of status item is this?
auto
type
=
idx
.
data
(
GitStatusModel
::
GitItemType
).
value
<
GitStatusModel
::
ItemType
>
();
if
(
type
==
GitStatusModel
::
NodeStage
)
{
selectionHasStagedItems
=
true
;
}
else
if
(
type
==
GitStatusModel
::
NodeUntrack
)
{
selectionHasUntrackedItems
=
true
;
}
else
if
(
idx
.
internalId
()
==
GitStatusModel
::
NodeChanges
)
{
}
else
if
(
type
==
GitStatusModel
::
NodeChanges
)
{
selectionHasChangedItems
=
true
;
}
files
.
append
(
idx
.
data
(
GitStatusModel
::
FileNameRole
).
toString
());
}
}
...
...
addons/project/gitwidget.h
View file @
26473a97
...
...
@@ -24,6 +24,7 @@ class QTemporaryFile;
class
KateProjectPluginView
;
class
GitWidgetTreeView
;
class
QStackedWidget
;
class
QLineEdit
;
namespace
KTextEditor
{
...
...
@@ -63,6 +64,7 @@ private:
GitWidgetTreeView
*
m_treeView
;
GitStatusModel
*
m_model
;
KateProject
*
m_project
;
QLineEdit
*
m_filterLineEdit
;
/** This ends with "/", always remember this */
QString
m_gitPath
;
QFutureWatcher
<
GitUtils
::
GitParsedStatus
>
m_gitStatusWatcher
;
...
...
Write
Preview
Supports
Markdown
0%
Try again
or
attach a new file
.
Cancel
You are about to add
0
people
to the discussion. Proceed with caution.
Finish editing this message first!
Cancel
Please
register
or
sign in
to comment