Skip to content
体验新版
项目
组织
正在加载...
登录
切换导航
打开侧边栏
掘金者说
vscode
提交
60ba9db9
V
vscode
项目概览
掘金者说
/
vscode
与 Fork 源项目一致
从无法访问的项目Fork
通知
1
Star
0
Fork
0
代码
文件
提交
分支
Tags
贡献者
分支图
Diff
Issue
0
列表
看板
标记
里程碑
合并请求
0
DevOps
流水线
流水线任务
计划
Wiki
0
Wiki
分析
仓库
DevOps
项目成员
Pages
V
vscode
项目概览
项目概览
详情
发布
仓库
仓库
文件
提交
分支
标签
贡献者
分支图
比较
Issue
0
Issue
0
列表
看板
标记
里程碑
合并请求
0
合并请求
0
Pages
DevOps
DevOps
流水线
流水线任务
计划
分析
分析
仓库分析
DevOps
Wiki
0
Wiki
成员
成员
收起侧边栏
关闭侧边栏
动态
分支图
创建新Issue
流水线任务
提交
Issue看板
体验新版 GitCode,发现更多精彩内容 >>
提交
60ba9db9
编写于
10月 02, 2018
作者:
J
Joao Moreno
浏览文件
操作
浏览文件
下载
电子邮件补丁
差异文件
tree: fix filter & collapse
上级
321df035
变更
3
隐藏空白更改
内联
并排
Showing
3 changed file
with
164 addition
and
98 deletion
+164
-98
src/vs/base/browser/ui/tree/tree.ts
src/vs/base/browser/ui/tree/tree.ts
+2
-2
src/vs/base/browser/ui/tree/treeModel.ts
src/vs/base/browser/ui/tree/treeModel.ts
+77
-65
src/vs/base/test/browser/ui/tree/treeModel.test.ts
src/vs/base/test/browser/ui/tree/treeModel.test.ts
+85
-31
未找到文件。
src/vs/base/browser/ui/tree/tree.ts
浏览文件 @
60ba9db9
...
...
@@ -178,8 +178,8 @@ export class Tree<T, TFilterData = void> implements IDisposable {
this
.
model
.
setCollapsedAll
(
true
);
}
refilter
(
location
?:
number
[]
):
void
{
this
.
model
.
refilter
(
location
);
refilter
():
void
{
this
.
model
.
refilter
();
}
private
onMouseClick
(
e
:
IListMouseEvent
<
ITreeNode
<
T
,
TFilterData
>>
):
void
{
...
...
src/vs/base/browser/ui/tree/treeModel.ts
浏览文件 @
60ba9db9
...
...
@@ -187,28 +187,10 @@ export class TreeModel<T, TFilterData = void> {
return
this
.
findNode
(
location
).
node
.
collapsed
;
}
refilter
(
location
?:
number
[]):
void
{
let
node
:
ITreeNode
<
T
,
TFilterData
>
;
if
(
!
location
||
location
.
length
===
0
)
{
node
=
this
.
root
;
const
previousRevealedCount
=
node
.
revealedCount
;
const
toInsert
=
this
.
updateSubtreeViewState
(
this
.
root
);
this
.
list
.
splice
(
0
,
previousRevealedCount
,
toInsert
.
slice
(
1
));
}
else
{
const
findResult
=
this
.
findNode
(
location
);
if
(
!
findResult
.
revealed
)
{
return
;
}
node
=
findResult
.
node
;
const
previousRevealedCount
=
node
.
revealedCount
;
const
toInsert
=
this
.
updateSubtreeViewState
(
this
.
root
);
this
.
list
.
splice
(
findResult
.
listIndex
,
previousRevealedCount
,
toInsert
);
}
refilter
(
/* location?: number[] */
):
void
{
const
previousRevealedCount
=
this
.
root
.
revealedCount
;
const
toInsert
=
this
.
updateNodeAfterFilterChange
(
this
.
root
);
this
.
list
.
splice
(
0
,
previousRevealedCount
,
toInsert
);
}
private
_setCollapsed
(
node
:
IMutableTreeNode
<
T
,
TFilterData
>
,
listIndex
:
number
,
revealed
:
boolean
,
collapsed
?:
boolean
|
undefined
):
boolean
{
...
...
@@ -228,7 +210,7 @@ export class TreeModel<T, TFilterData = void> {
if
(
revealed
)
{
const
previousRevealedCount
=
node
.
revealedCount
;
const
toInsert
=
this
.
update
SubtreeViewStat
e
(
node
);
const
toInsert
=
this
.
update
NodeAfterCollapseChang
e
(
node
);
this
.
list
.
splice
(
listIndex
+
1
,
previousRevealedCount
-
1
,
toInsert
.
slice
(
1
));
this
.
_onDidChangeCollapseState
.
fire
(
node
);
...
...
@@ -244,7 +226,7 @@ export class TreeModel<T, TFilterData = void> {
this
.
updateNodeFilterState
(
node
);
if
(
revealed
&&
node
.
visible
)
{
if
(
revealed
)
{
treeListElements
.
push
(
node
);
}
...
...
@@ -252,14 +234,17 @@ export class TreeModel<T, TFilterData = void> {
node
.
children
=
Iterator
.
collect
(
Iterator
.
map
(
children
,
el
=>
this
.
createTreeNode
(
el
,
node
,
revealed
&&
!
treeElement
.
collapsed
,
treeListElements
)));
node
.
collapsible
=
node
.
collapsible
||
node
.
children
.
length
>
0
;
if
(
typeof
node
.
visible
===
'
undefined
'
&&
node
.
children
.
length
===
0
)
{
node
.
visible
=
false
;
treeListElements
.
pop
();
}
else
{
node
.
visible
=
true
;
if
(
typeof
node
.
visible
===
'
undefined
'
)
{
node
.
visible
=
node
.
children
.
length
>
0
;
}
if
(
node
.
visible
&&
!
collapsed
)
{
if
(
!
node
.
visible
)
{
node
.
revealedCount
=
0
;
if
(
revealed
)
{
treeListElements
.
pop
();
}
}
else
if
(
!
collapsed
)
{
node
.
revealedCount
+=
getRevealedCount
(
node
.
children
);
}
...
...
@@ -270,65 +255,92 @@ export class TreeModel<T, TFilterData = void> {
* Recursively updates the view state of a subtree, while collecting
* all the visible nodes in an array. Used in expanding/collapsing.
*/
private
update
SubtreeViewState
(
node
:
IMutableTreeNode
<
T
,
TFilterData
>
,
filterFirst
=
false
):
ITreeNode
<
T
,
TFilterData
>
[]
{
private
update
NodeAfterCollapseChange
(
node
:
IMutableTreeNode
<
T
,
TFilterData
>
):
ITreeNode
<
T
,
TFilterData
>
[]
{
const
previousRevealedCount
=
node
.
revealedCount
;
const
result
:
ITreeNode
<
T
,
TFilterData
>
[]
=
[];
let
first
=
true
;
const
recurse
=
(
node
:
IMutableTreeNode
<
T
,
TFilterData
>
,
revealed
=
true
):
number
=>
{
if
(
!
first
||
filterFirst
)
{
this
.
updateNodeFilterState
(
node
);
this
.
_updateNodeAfterCollapseChange
(
node
,
result
);
this
.
_updateParentRevealedCount
(
node
.
parent
,
result
.
length
-
previousRevealedCount
);
return
result
;
}
private
_updateNodeAfterCollapseChange
(
node
:
IMutableTreeNode
<
T
,
TFilterData
>
,
result
:
ITreeNode
<
T
,
TFilterData
>
[]):
number
{
if
(
node
.
visible
===
false
)
{
return
0
;
}
result
.
push
(
node
);
node
.
revealedCount
=
1
;
if
(
!
node
.
collapsed
)
{
for
(
const
child
of
node
.
children
)
{
node
.
revealedCount
+=
this
.
_updateNodeAfterCollapseChange
(
child
,
result
);
}
}
return
node
.
revealedCount
;
}
private
updateNodeAfterFilterChange
(
node
:
IMutableTreeNode
<
T
,
TFilterData
>
):
ITreeNode
<
T
,
TFilterData
>
[]
{
const
previousRevealedCount
=
node
.
revealedCount
;
const
result
:
ITreeNode
<
T
,
TFilterData
>
[]
=
[];
this
.
_updateNodeAfterFilterChange
(
node
,
result
);
this
.
_updateParentRevealedCount
(
node
.
parent
,
result
.
length
-
previousRevealedCount
);
return
result
;
}
private
_updateNodeAfterFilterChange
(
node
:
IMutableTreeNode
<
T
,
TFilterData
>
,
result
:
ITreeNode
<
T
,
TFilterData
>
[],
revealed
=
true
):
boolean
{
if
(
node
!==
this
.
root
)
{
this
.
updateNodeFilterState
(
node
);
if
(
node
.
visible
===
false
)
{
return
0
;
return
false
;
}
first
=
false
;
if
(
revealed
)
{
result
.
push
(
node
);
}
}
node
.
revealedCount
=
1
;
let
childrenRevealedCount
=
0
;
if
(
!
node
.
collapsed
||
typeof
node
.
visible
===
'
undefined
'
)
{
for
(
const
child
of
node
.
children
)
{
childrenRevealedCount
+=
recurse
(
child
,
revealed
&&
!
node
.
collapsed
);
}
}
const
resultStartLength
=
result
.
length
;
node
.
revealedCount
=
node
===
this
.
root
?
0
:
1
;
if
(
typeof
node
.
visible
===
'
undefined
'
&&
childrenRevealedCount
===
0
)
{
node
.
visible
=
false
;
node
.
revealedCount
=
0
;
result
.
pop
();
return
0
;
let
hasVisibleDescendants
=
false
;
if
(
typeof
node
.
visible
===
'
undefined
'
||
!
node
.
collapsed
)
{
for
(
const
child
of
node
.
children
)
{
hasVisibleDescendants
=
this
.
_updateNodeAfterFilterChange
(
child
,
result
,
revealed
&&
!
node
.
collapsed
)
||
hasVisibleDescendants
;
}
}
if
(
!
node
.
collapsed
)
{
node
.
revealedCount
+=
childrenRevealedCount
;
}
if
(
typeof
node
.
visible
===
'
undefined
'
)
{
node
.
visible
=
hasVisibleDescendants
;
}
return
node
.
revealedCount
;
}
;
if
(
!
node
.
visible
)
{
node
.
revealedCount
=
0
;
recurse
(
node
);
if
(
revealed
)
{
result
.
pop
();
}
}
else
if
(
!
node
.
collapsed
)
{
node
.
revealedCount
+=
result
.
length
-
resultStartLength
;
}
const
revealedCountDiff
=
result
.
length
-
previousRevealedCount
;
return
node
.
visible
;
}
if
(
revealedCountDiff
===
0
)
{
return
result
;
private
_updateParentRevealedCount
(
node
:
IMutableTreeNode
<
T
,
TFilterData
>
,
diff
:
number
):
void
{
if
(
diff
===
0
)
{
return
;
}
node
=
node
.
parent
;
while
(
node
)
{
node
.
revealedCount
+=
revealedCountD
iff
;
node
.
revealedCount
+=
d
iff
;
node
=
node
.
parent
;
}
return
result
;
}
private
updateNodeFilterState
(
node
:
IMutableTreeNode
<
T
,
TFilterData
>
):
void
{
...
...
src/vs/base/test/browser/ui/tree/treeModel.test.ts
浏览文件 @
60ba9db9
...
...
@@ -366,7 +366,7 @@ suite('TreeModel2', function () {
assert
.
deepEqual
(
toArray
(
list
),
[
0
,
2
,
4
,
6
]);
});
test
(
'
collapse & expand should
refilter
'
,
function
()
{
test
(
'
refilter
'
,
function
()
{
const
list
=
[]
as
ITreeNode
<
number
>
[];
let
shouldFilter
=
false
;
const
filter
=
new
class
implements
ITreeFilter
<
number
>
{
...
...
@@ -393,54 +393,65 @@ suite('TreeModel2', function () {
assert
.
deepEqual
(
toArray
(
list
),
[
0
,
1
,
2
,
3
,
4
,
5
,
6
,
7
]);
model
.
setCollapsed
([
0
],
true
);
assert
.
deepEqual
(
toArray
(
list
),
[
0
]);
model
.
refilter
(
);
assert
.
deepEqual
(
toArray
(
list
),
[
0
,
1
,
2
,
3
,
4
,
5
,
6
,
7
]);
shouldFilter
=
true
;
model
.
setCollapsed
([
0
],
false
);
model
.
refilter
(
);
assert
.
deepEqual
(
toArray
(
list
),
[
0
,
2
,
4
,
6
]);
shouldFilter
=
false
;
model
.
refilter
();
assert
.
deepEqual
(
toArray
(
list
),
[
0
,
1
,
2
,
3
,
4
,
5
,
6
,
7
]);
});
test
(
'
refilter
'
,
function
()
{
const
list
=
[]
as
ITreeNode
<
number
>
[];
let
shouldFilter
=
false
;
const
filter
=
new
class
implements
ITreeFilter
<
number
>
{
filter
(
element
:
number
):
Visibility
{
return
(
!
shouldFilter
||
element
%
2
===
0
)
?
Visibility
.
Visible
:
Visibility
.
Hidden
;
test
(
'
re
cursive
filter
'
,
function
()
{
const
list
=
[]
as
ITreeNode
<
string
>
[];
let
query
=
new
RegExp
(
''
)
;
const
filter
=
new
class
implements
ITreeFilter
<
string
>
{
filter
(
element
:
string
):
Visibility
{
return
query
.
test
(
element
)
?
Visibility
.
Visible
:
Visibility
.
Recurse
;
}
};
const
model
=
new
TreeModel
<
number
>
(
toSpliceable
(
list
),
{
filter
});
const
model
=
new
TreeModel
<
string
>
(
toSpliceable
(
list
),
{
filter
});
model
.
splice
([
0
],
0
,
Iterator
.
fromArray
([
{
element
:
0
,
children
:
[
{
element
:
1
},
{
element
:
2
},
{
element
:
3
},
{
element
:
4
},
{
element
:
5
},
{
element
:
6
},
{
element
:
7
}
element
:
'
vscode
'
,
children
:
[
{
element
:
'
.build
'
},
{
element
:
'
git
'
},
{
element
:
'
github
'
,
children
:
[
{
element
:
'
calendar.yml
'
},
{
element
:
'
endgame
'
},
{
element
:
'
build.js
'
},
]
},
{
element
:
'
build
'
,
children
:
[
{
element
:
'
lib
'
},
{
element
:
'
gulpfile.js
'
}
]
}
]
},
]));
assert
.
deepEqual
(
toArray
(
list
),
[
0
,
1
,
2
,
3
,
4
,
5
,
6
,
7
]
);
assert
.
deepEqual
(
list
.
length
,
10
);
query
=
/build/
;
model
.
refilter
();
assert
.
deepEqual
(
toArray
(
list
),
[
0
,
1
,
2
,
3
,
4
,
5
,
6
,
7
]);
assert
.
deepEqual
(
toArray
(
list
),
[
'
vscode
'
,
'
.build
'
,
'
github
'
,
'
build.js
'
,
'
build
'
]);
shouldFilter
=
true
;
model
.
refilter
();
assert
.
deepEqual
(
toArray
(
list
),
[
0
,
2
,
4
,
6
]);
model
.
setCollapsed
([
0
],
true
);
assert
.
deepEqual
(
toArray
(
list
),
[
'
vscode
'
]);
shouldFilter
=
false
;
model
.
refilter
();
assert
.
deepEqual
(
toArray
(
list
),
[
0
,
1
,
2
,
3
,
4
,
5
,
6
,
7
]);
model
.
setCollapsed
([
0
],
false
);
assert
.
deepEqual
(
toArray
(
list
),
[
'
vscode
'
,
'
.build
'
,
'
github
'
,
'
build.js
'
,
'
build
'
]);
});
test
(
'
recursive filter
'
,
function
()
{
test
(
'
recursive filter
with collapse
'
,
function
()
{
const
list
=
[]
as
ITreeNode
<
string
>
[];
let
query
=
new
RegExp
(
''
);
const
filter
=
new
class
implements
ITreeFilter
<
string
>
{
...
...
@@ -475,15 +486,58 @@ suite('TreeModel2', function () {
assert
.
deepEqual
(
list
.
length
,
10
);
query
=
/
build
/
;
query
=
/
gulp
/
;
model
.
refilter
();
assert
.
deepEqual
(
toArray
(
list
),
[
'
vscode
'
,
'
.build
'
,
'
github
'
,
'
build.js
'
,
'
build
'
]);
assert
.
deepEqual
(
toArray
(
list
),
[
'
vscode
'
,
'
build
'
,
'
gulpfile.js
'
]);
model
.
setCollapsed
([
0
,
3
],
true
);
assert
.
deepEqual
(
toArray
(
list
),
[
'
vscode
'
,
'
build
'
]);
model
.
setCollapsed
([
0
],
true
);
assert
.
deepEqual
(
toArray
(
list
),
[
'
vscode
'
]);
});
test
(
'
recursive filter while collapsed
'
,
function
()
{
const
list
=
[]
as
ITreeNode
<
string
>
[];
let
query
=
new
RegExp
(
''
);
const
filter
=
new
class
implements
ITreeFilter
<
string
>
{
filter
(
element
:
string
):
Visibility
{
return
query
.
test
(
element
)
?
Visibility
.
Visible
:
Visibility
.
Recurse
;
}
};
const
model
=
new
TreeModel
<
string
>
(
toSpliceable
(
list
),
{
filter
});
model
.
splice
([
0
],
0
,
Iterator
.
fromArray
([
{
element
:
'
vscode
'
,
collapsed
:
true
,
children
:
[
{
element
:
'
.build
'
},
{
element
:
'
git
'
},
{
element
:
'
github
'
,
children
:
[
{
element
:
'
calendar.yml
'
},
{
element
:
'
endgame
'
},
{
element
:
'
build.js
'
},
]
},
{
element
:
'
build
'
,
children
:
[
{
element
:
'
lib
'
},
{
element
:
'
gulpfile.js
'
}
]
}
]
},
]));
assert
.
deepEqual
(
toArray
(
list
),
[
'
vscode
'
]);
query
=
/gulp/
;
model
.
refilter
();
assert
.
deepEqual
(
toArray
(
list
),
[
'
vscode
'
]);
model
.
setCollapsed
([
0
],
false
);
assert
.
deepEqual
(
toArray
(
list
),
[
'
vscode
'
,
'
.build
'
,
'
github
'
,
'
build.js
'
,
'
build
'
]);
assert
.
deepEqual
(
toArray
(
list
),
[
'
vscode
'
,
'
build
'
,
'
gulpfile.js
'
]);
});
suite
(
'
getNodeLocation
'
,
function
()
{
...
...
编辑
预览
Markdown
is supported
0%
请重试
或
添加新附件
.
添加附件
取消
You are about to add
0
people
to the discussion. Proceed with caution.
先完成此消息的编辑!
取消
想要评论请
注册
或
登录