Skip to content
体验新版
项目
组织
正在加载...
登录
切换导航
打开侧边栏
掘金者说
vscode
提交
4f399951
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,发现更多精彩内容 >>
未验证
提交
4f399951
编写于
9月 13, 2019
作者:
J
João Moreno
提交者:
GitHub
9月 13, 2019
浏览文件
操作
浏览文件
下载
差异文件
Introduce `CompressibleObjectTree` (#77876)
Introduce `CompressibleObjectTree`
上级
c05a0af7
3d93cacb
变更
18
隐藏空白更改
内联
并排
Showing
18 changed file
with
747 addition
and
344 deletion
+747
-344
src/vs/base/browser/ui/list/listWidget.ts
src/vs/base/browser/ui/list/listWidget.ts
+1
-1
src/vs/base/browser/ui/tree/abstractTree.ts
src/vs/base/browser/ui/tree/abstractTree.ts
+35
-28
src/vs/base/browser/ui/tree/asyncDataTree.ts
src/vs/base/browser/ui/tree/asyncDataTree.ts
+163
-34
src/vs/base/browser/ui/tree/compressedObjectTree.ts
src/vs/base/browser/ui/tree/compressedObjectTree.ts
+0
-57
src/vs/base/browser/ui/tree/compressedObjectTreeModel.ts
src/vs/base/browser/ui/tree/compressedObjectTreeModel.ts
+151
-99
src/vs/base/browser/ui/tree/indexTree.ts
src/vs/base/browser/ui/tree/indexTree.ts
+2
-2
src/vs/base/browser/ui/tree/indexTreeModel.ts
src/vs/base/browser/ui/tree/indexTreeModel.ts
+31
-42
src/vs/base/browser/ui/tree/objectTree.ts
src/vs/base/browser/ui/tree/objectTree.ts
+114
-6
src/vs/base/browser/ui/tree/objectTreeModel.ts
src/vs/base/browser/ui/tree/objectTreeModel.ts
+10
-18
src/vs/base/browser/ui/tree/tree.ts
src/vs/base/browser/ui/tree/tree.ts
+19
-4
src/vs/base/test/browser/ui/tree/compressedObjectTreeModel.test.ts
...se/test/browser/ui/tree/compressedObjectTreeModel.test.ts
+5
-5
src/vs/base/test/browser/ui/tree/indexTreeModel.test.ts
src/vs/base/test/browser/ui/tree/indexTreeModel.test.ts
+3
-3
src/vs/base/test/browser/ui/tree/objectTree.test.ts
src/vs/base/test/browser/ui/tree/objectTree.test.ts
+159
-8
src/vs/platform/list/browser/listService.ts
src/vs/platform/list/browser/listService.ts
+33
-4
src/vs/workbench/browser/actions/listCommands.ts
src/vs/workbench/browser/actions/listCommands.ts
+1
-8
src/vs/workbench/contrib/search/browser/searchActions.ts
src/vs/workbench/contrib/search/browser/searchActions.ts
+4
-4
src/vs/workbench/contrib/search/test/browser/mockSearchTree.ts
...s/workbench/contrib/search/test/browser/mockSearchTree.ts
+0
-4
test/tree/public/index.html
test/tree/public/index.html
+16
-17
未找到文件。
src/vs/base/browser/ui/list/listWidget.ts
浏览文件 @
4f399951
...
...
@@ -862,7 +862,7 @@ export interface IListStyles {
}
const
defaultStyles
:
IListStyles
=
{
listFocusBackground
:
Color
.
fromHex
(
'
#
073655
'
),
listFocusBackground
:
Color
.
fromHex
(
'
#
7FB0D0
'
),
listActiveSelectionBackground
:
Color
.
fromHex
(
'
#0E639C
'
),
listActiveSelectionForeground
:
Color
.
fromHex
(
'
#FFFFFF
'
),
listFocusAndSelectionBackground
:
Color
.
fromHex
(
'
#094771
'
),
...
...
src/vs/base/browser/ui/tree/abstractTree.ts
浏览文件 @
4f399951
...
...
@@ -98,9 +98,11 @@ class TreeNodeListDragAndDrop<T, TFilterData, TRef> implements IListDragAndDrop<
}
if
(
result
.
bubble
===
TreeDragOverBubble
.
Up
)
{
const
parentNode
=
targetNode
.
parent
;
const
model
=
this
.
modelProvider
();
const
parentIndex
=
parentNode
&&
model
.
getListIndex
(
model
.
getNodeLocation
(
parentNode
));
const
ref
=
model
.
getNodeLocation
(
targetNode
);
const
parentRef
=
model
.
getParentNodeLocation
(
ref
);
const
parentNode
=
model
.
getNode
(
parentRef
);
const
parentIndex
=
parentRef
&&
model
.
getListIndex
(
parentRef
);
return
this
.
onDragOver
(
data
,
parentNode
,
parentIndex
,
originalEvent
,
false
);
}
...
...
@@ -155,7 +157,12 @@ function asListOptions<T, TFilterData, TRef>(modelProvider: () => ITreeModel<T,
enableKeyboardNavigation
:
options
.
simpleKeyboardNavigation
,
ariaProvider
:
{
getSetSize
(
node
)
{
return
node
.
parent
!
.
visibleChildrenCount
;
const
model
=
modelProvider
();
const
ref
=
model
.
getNodeLocation
(
node
);
const
parentRef
=
model
.
getParentNodeLocation
(
ref
);
const
parentNode
=
model
.
getNode
(
parentRef
);
return
parentNode
.
visibleChildrenCount
;
},
getPosInSet
(
node
)
{
return
node
.
visibleChildIndex
+
1
;
...
...
@@ -233,7 +240,7 @@ class EventCollection<T> implements Collection<T> {
}
}
class
TreeRenderer
<
T
,
TFilterData
,
TTemplateData
>
implements
IListRenderer
<
ITreeNode
<
T
,
TFilterData
>
,
ITreeListTemplateData
<
TTemplateData
>>
{
class
TreeRenderer
<
T
,
TFilterData
,
T
Ref
,
T
TemplateData
>
implements
IListRenderer
<
ITreeNode
<
T
,
TFilterData
>
,
ITreeListTemplateData
<
TTemplateData
>>
{
private
static
DefaultIndent
=
8
;
...
...
@@ -251,6 +258,7 @@ class TreeRenderer<T, TFilterData, TTemplateData> implements IListRenderer<ITree
constructor
(
private
renderer
:
ITreeRenderer
<
T
,
TFilterData
,
TTemplateData
>
,
private
modelProvider
:
()
=>
ITreeModel
<
T
,
TFilterData
,
TRef
>
,
onDidChangeCollapseState
:
Event
<
ICollapseStateChangeEvent
<
T
,
TFilterData
>>
,
private
activeNodes
:
Collection
<
ITreeNode
<
T
,
TFilterData
>>
,
options
:
ITreeRendererOptions
=
{}
...
...
@@ -381,10 +389,19 @@ class TreeRenderer<T, TFilterData, TTemplateData> implements IListRenderer<ITree
}
const
disposableStore
=
new
DisposableStore
();
const
model
=
this
.
modelProvider
();
let
node
=
target
;
while
(
node
.
parent
&&
node
.
parent
.
parent
)
{
const
parent
=
node
.
parent
;
while
(
true
)
{
const
ref
=
model
.
getNodeLocation
(
node
);
const
parentRef
=
model
.
getParentNodeLocation
(
ref
);
if
(
!
parentRef
)
{
break
;
}
const
parent
=
model
.
getNode
(
parentRef
);
const
guide
=
$
<
HTMLDivElement
>
(
'
.indent-guide
'
,
{
style
:
`width:
${
this
.
indent
}
px`
});
if
(
this
.
activeIndentNodes
.
has
(
parent
))
{
...
...
@@ -412,12 +429,16 @@ class TreeRenderer<T, TFilterData, TTemplateData> implements IListRenderer<ITree
}
const
set
=
new
Set
<
ITreeNode
<
T
,
TFilterData
>>
();
const
model
=
this
.
modelProvider
();
nodes
.
forEach
(
node
=>
{
const
ref
=
model
.
getNodeLocation
(
node
);
const
parentRef
=
model
.
getParentNodeLocation
(
ref
);
if
(
node
.
collapsible
&&
node
.
children
.
length
>
0
&&
!
node
.
collapsed
)
{
set
.
add
(
node
);
}
else
if
(
node
.
parent
)
{
set
.
add
(
node
.
parent
);
}
else
if
(
parentRef
)
{
set
.
add
(
model
.
getNode
(
parentRef
)
);
}
});
...
...
@@ -1153,7 +1174,7 @@ class TreeNodeList<T, TFilterData, TRef> extends List<ITreeNode<T, TFilterData>>
export
abstract
class
AbstractTree
<
T
,
TFilterData
,
TRef
>
implements
IDisposable
{
protected
view
:
TreeNodeList
<
T
,
TFilterData
,
TRef
>
;
private
renderers
:
TreeRenderer
<
T
,
TFilterData
,
any
>
[];
private
renderers
:
TreeRenderer
<
T
,
TFilterData
,
TRef
,
any
>
[];
protected
model
:
ITreeModel
<
T
,
TFilterData
,
TRef
>
;
private
focus
:
Trait
<
T
>
;
private
selection
:
Trait
<
T
>
;
...
...
@@ -1211,7 +1232,7 @@ export abstract class AbstractTree<T, TFilterData, TRef> implements IDisposable
const
activeNodes
=
new
EventCollection
(
onDidChangeActiveNodes
.
event
);
this
.
disposables
.
push
(
activeNodes
);
this
.
renderers
=
renderers
.
map
(
r
=>
new
TreeRenderer
<
T
,
TFilterData
,
any
>
(
r
,
onDidChangeCollapseStateRelay
.
event
,
activeNodes
,
_options
));
this
.
renderers
=
renderers
.
map
(
r
=>
new
TreeRenderer
<
T
,
TFilterData
,
TRef
,
any
>
(
r
,
()
=>
this
.
model
,
onDidChangeCollapseStateRelay
.
event
,
activeNodes
,
_options
));
this
.
disposables
.
push
(...
this
.
renderers
);
let
filter
:
TypeFilter
<
T
>
|
undefined
;
...
...
@@ -1383,7 +1404,9 @@ export abstract class AbstractTree<T, TFilterData, TRef> implements IDisposable
// Tree navigation
getParentElement
(
location
:
TRef
):
T
{
return
this
.
model
.
getParentElement
(
location
);
const
parentRef
=
this
.
model
.
getParentNodeLocation
(
location
);
const
parentNode
=
this
.
model
.
getNode
(
parentRef
);
return
parentNode
.
element
;
}
getFirstElementChild
(
location
:
TRef
):
T
|
undefined
{
...
...
@@ -1539,7 +1562,7 @@ export abstract class AbstractTree<T, TFilterData, TRef> implements IDisposable
if
(
!
didChange
)
{
const
parentLocation
=
this
.
model
.
getParentNodeLocation
(
location
);
if
(
parentLocation
===
null
)
{
if
(
!
parentLocation
)
{
return
;
}
...
...
@@ -1641,22 +1664,6 @@ class TreeNavigator<T extends NonNullable<any>, TFilterData, TRef> implements IT
return
this
.
current
();
}
parent
():
T
|
null
{
if
(
this
.
index
<
0
||
this
.
index
>=
this
.
view
.
length
)
{
return
null
;
}
const
node
=
this
.
view
.
element
(
this
.
index
);
if
(
!
node
.
parent
)
{
this
.
index
=
-
1
;
return
this
.
current
();
}
this
.
index
=
this
.
model
.
getListIndex
(
this
.
model
.
getNodeLocation
(
node
.
parent
));
return
this
.
current
();
}
first
():
T
|
null
{
this
.
index
=
0
;
return
this
.
current
();
...
...
src/vs/base/browser/ui/tree/asyncDataTree.ts
浏览文件 @
4f399951
...
...
@@ -4,9 +4,9 @@
*--------------------------------------------------------------------------------------------*/
import
{
ComposedTreeDelegate
,
IAbstractTreeOptions
,
IAbstractTreeOptionsUpdate
}
from
'
vs/base/browser/ui/tree/abstractTree
'
;
import
{
ObjectTree
,
IObjectTreeOptions
}
from
'
vs/base/browser/ui/tree/objectTree
'
;
import
{
ObjectTree
,
IObjectTreeOptions
,
CompressibleObjectTree
,
ICompressibleTreeRenderer
}
from
'
vs/base/browser/ui/tree/objectTree
'
;
import
{
IListVirtualDelegate
,
IIdentityProvider
,
IListDragAndDrop
,
IListDragOverReaction
}
from
'
vs/base/browser/ui/list/list
'
;
import
{
ITreeElement
,
ITreeNode
,
ITreeRenderer
,
ITreeEvent
,
ITreeMouseEvent
,
ITreeContextMenuEvent
,
ITreeSorter
,
ICollapseStateChangeEvent
,
IAsyncDataSource
,
ITreeDragAndDrop
,
TreeError
}
from
'
vs/base/browser/ui/tree/tree
'
;
import
{
ITreeElement
,
ITreeNode
,
ITreeRenderer
,
ITreeEvent
,
ITreeMouseEvent
,
ITreeContextMenuEvent
,
ITreeSorter
,
ICollapseStateChangeEvent
,
IAsyncDataSource
,
ITreeDragAndDrop
,
TreeError
,
WeakMapper
}
from
'
vs/base/browser/ui/tree/tree
'
;
import
{
IDisposable
,
dispose
}
from
'
vs/base/common/lifecycle
'
;
import
{
Emitter
,
Event
}
from
'
vs/base/common/event
'
;
import
{
timeout
,
CancelablePromise
,
createCancelablePromise
}
from
'
vs/base/common/async
'
;
...
...
@@ -18,6 +18,7 @@ import { isPromiseCanceledError, onUnexpectedError } from 'vs/base/common/errors
import
{
toggleClass
}
from
'
vs/base/browser/dom
'
;
import
{
values
}
from
'
vs/base/common/map
'
;
import
{
ScrollEvent
}
from
'
vs/base/common/scrollable
'
;
import
{
ICompressedTreeNode
,
ICompressedTreeElement
}
from
'
vs/base/browser/ui/tree/compressedObjectTreeModel
'
;
interface
IAsyncDataTreeNode
<
TInput
,
T
>
{
element
:
TInput
|
T
;
...
...
@@ -66,10 +67,11 @@ interface IDataTreeListTemplateData<T> {
templateData
:
T
;
}
type
AsyncDataTreeNodeMapper
<
TInput
,
T
,
TFilterData
>
=
WeakMapper
<
ITreeNode
<
IAsyncDataTreeNode
<
TInput
,
T
>
|
null
,
TFilterData
>
,
ITreeNode
<
TInput
|
T
,
TFilterData
>>
;
class
AsyncDataTreeNodeWrapper
<
TInput
,
T
,
TFilterData
>
implements
ITreeNode
<
TInput
|
T
,
TFilterData
>
{
get
element
():
T
{
return
this
.
node
.
element
!
.
element
as
T
;
}
get
parent
():
ITreeNode
<
T
,
TFilterData
>
|
undefined
{
return
this
.
node
.
parent
&&
new
AsyncDataTreeNodeWrapper
(
this
.
node
.
parent
);
}
get
children
():
ITreeNode
<
T
,
TFilterData
>
[]
{
return
this
.
node
.
children
.
map
(
node
=>
new
AsyncDataTreeNodeWrapper
(
node
));
}
get
depth
():
number
{
return
this
.
node
.
depth
;
}
get
visibleChildrenCount
():
number
{
return
this
.
node
.
visibleChildrenCount
;
}
...
...
@@ -82,14 +84,15 @@ class AsyncDataTreeNodeWrapper<TInput, T, TFilterData> implements ITreeNode<TInp
constructor
(
private
node
:
ITreeNode
<
IAsyncDataTreeNode
<
TInput
,
T
>
|
null
,
TFilterData
>
)
{
}
}
class
DataTreeRenderer
<
TInput
,
T
,
TFilterData
,
TTemplateData
>
implements
ITreeRenderer
<
IAsyncDataTreeNode
<
TInput
,
T
>
,
TFilterData
,
IDataTreeListTemplateData
<
TTemplateData
>>
{
class
Async
DataTreeRenderer
<
TInput
,
T
,
TFilterData
,
TTemplateData
>
implements
ITreeRenderer
<
IAsyncDataTreeNode
<
TInput
,
T
>
,
TFilterData
,
IDataTreeListTemplateData
<
TTemplateData
>>
{
readonly
templateId
:
string
;
private
renderedNodes
=
new
Map
<
IAsyncDataTreeNode
<
TInput
,
T
>
,
IDataTreeListTemplateData
<
TTemplateData
>>
();
private
disposables
:
IDisposable
[]
=
[];
constructor
(
private
renderer
:
ITreeRenderer
<
T
,
TFilterData
,
TTemplateData
>
,
protected
renderer
:
ITreeRenderer
<
T
,
TFilterData
,
TTemplateData
>
,
protected
nodeMapper
:
AsyncDataTreeNodeMapper
<
TInput
,
T
,
TFilterData
>
,
readonly
onDidChangeTwistieState
:
Event
<
IAsyncDataTreeNode
<
TInput
,
T
>>
)
{
this
.
templateId
=
renderer
.
templateId
;
...
...
@@ -101,7 +104,7 @@ class DataTreeRenderer<TInput, T, TFilterData, TTemplateData> implements ITreeRe
}
renderElement
(
node
:
ITreeNode
<
IAsyncDataTreeNode
<
TInput
,
T
>
,
TFilterData
>
,
index
:
number
,
templateData
:
IDataTreeListTemplateData
<
TTemplateData
>
,
height
:
number
|
undefined
):
void
{
this
.
renderer
.
renderElement
(
new
AsyncDataTreeNodeWrapper
(
node
)
,
index
,
templateData
.
templateData
,
height
);
this
.
renderer
.
renderElement
(
this
.
nodeMapper
.
map
(
node
)
as
ITreeNode
<
T
,
TFilterData
>
,
index
,
templateData
.
templateData
,
height
);
}
renderTwistie
(
element
:
IAsyncDataTreeNode
<
TInput
,
T
>
,
twistieElement
:
HTMLElement
):
boolean
{
...
...
@@ -111,7 +114,7 @@ class DataTreeRenderer<TInput, T, TFilterData, TTemplateData> implements ITreeRe
disposeElement
(
node
:
ITreeNode
<
IAsyncDataTreeNode
<
TInput
,
T
>
,
TFilterData
>
,
index
:
number
,
templateData
:
IDataTreeListTemplateData
<
TTemplateData
>
,
height
:
number
|
undefined
):
void
{
if
(
this
.
renderer
.
disposeElement
)
{
this
.
renderer
.
disposeElement
(
new
AsyncDataTreeNodeWrapper
(
node
)
,
index
,
templateData
.
templateData
,
height
);
this
.
renderer
.
disposeElement
(
this
.
nodeMapper
.
map
(
node
)
as
ITreeNode
<
T
,
TFilterData
>
,
index
,
templateData
.
templateData
,
height
);
}
}
...
...
@@ -243,25 +246,6 @@ function asObjectTreeOptions<TInput, T, TFilterData>(options?: IAsyncDataTreeOpt
};
}
function
asTreeElement
<
TInput
,
T
>
(
node
:
IAsyncDataTreeNode
<
TInput
,
T
>
,
viewStateContext
?:
IAsyncDataTreeViewStateContext
<
TInput
,
T
>
):
ITreeElement
<
IAsyncDataTreeNode
<
TInput
,
T
>>
{
let
collapsed
:
boolean
|
undefined
;
if
(
viewStateContext
&&
viewStateContext
.
viewState
.
expanded
&&
node
.
id
&&
viewStateContext
.
viewState
.
expanded
.
indexOf
(
node
.
id
)
>
-
1
)
{
collapsed
=
false
;
}
else
{
collapsed
=
node
.
collapsedByDefault
;
}
node
.
collapsedByDefault
=
undefined
;
return
{
element
:
node
,
children
:
node
.
hasChildren
?
Iterator
.
map
(
Iterator
.
fromArray
(
node
.
children
),
child
=>
asTreeElement
(
child
,
viewStateContext
))
:
[],
collapsible
:
node
.
hasChildren
,
collapsed
};
}
export
interface
IAsyncDataTreeOptionsUpdate
extends
IAbstractTreeOptionsUpdate
{
}
export
interface
IAsyncDataTreeOptions
<
T
,
TFilterData
=
void
>
extends
IAsyncDataTreeOptionsUpdate
,
Pick
<
IAbstractTreeOptions
<
T
,
TFilterData
>
,
Exclude
<
keyof
IAbstractTreeOptions
<
T
,
TFilterData
>
,
'
collapseByDefault
'
>>
{
...
...
@@ -304,7 +288,9 @@ export class AsyncDataTree<TInput, T, TFilterData = void> implements IDisposable
private
readonly
autoExpandSingleChildren
:
boolean
;
private
readonly
_onDidRender
=
new
Emitter
<
void
>
();
private
readonly
_onDidChangeNodeSlowState
=
new
Emitter
<
IAsyncDataTreeNode
<
TInput
,
T
>>
();
protected
readonly
_onDidChangeNodeSlowState
=
new
Emitter
<
IAsyncDataTreeNode
<
TInput
,
T
>>
();
protected
readonly
nodeMapper
:
AsyncDataTreeNodeMapper
<
TInput
,
T
,
TFilterData
>
=
new
WeakMapper
(
node
=>
new
AsyncDataTreeNodeWrapper
(
node
));
protected
readonly
disposables
:
IDisposable
[]
=
[];
...
...
@@ -351,11 +337,7 @@ export class AsyncDataTree<TInput, T, TFilterData = void> implements IDisposable
this
.
sorter
=
options
.
sorter
;
this
.
collapseByDefault
=
options
.
collapseByDefault
;
const
objectTreeDelegate
=
new
ComposedTreeDelegate
<
TInput
|
T
,
IAsyncDataTreeNode
<
TInput
,
T
>>
(
delegate
);
const
objectTreeRenderers
=
renderers
.
map
(
r
=>
new
DataTreeRenderer
(
r
,
this
.
_onDidChangeNodeSlowState
.
event
));
const
objectTreeOptions
=
asObjectTreeOptions
<
TInput
,
T
,
TFilterData
>
(
options
)
||
{};
this
.
tree
=
new
ObjectTree
(
user
,
container
,
objectTreeDelegate
,
objectTreeRenderers
,
objectTreeOptions
);
this
.
tree
=
this
.
createTree
(
user
,
container
,
delegate
,
renderers
,
options
);
this
.
root
=
createAsyncDataTreeNode
({
element
:
undefined
!
,
...
...
@@ -375,6 +357,20 @@ export class AsyncDataTree<TInput, T, TFilterData = void> implements IDisposable
this
.
tree
.
onDidChangeCollapseState
(
this
.
_onDidChangeCollapseState
,
this
,
this
.
disposables
);
}
protected
createTree
(
user
:
string
,
container
:
HTMLElement
,
delegate
:
IListVirtualDelegate
<
T
>
,
renderers
:
ITreeRenderer
<
T
,
TFilterData
,
any
>
[],
options
:
IAsyncDataTreeOptions
<
T
,
TFilterData
>
):
ObjectTree
<
IAsyncDataTreeNode
<
TInput
,
T
>
,
TFilterData
>
{
const
objectTreeDelegate
=
new
ComposedTreeDelegate
<
TInput
|
T
,
IAsyncDataTreeNode
<
TInput
,
T
>>
(
delegate
);
const
objectTreeRenderers
=
renderers
.
map
(
r
=>
new
AsyncDataTreeRenderer
(
r
,
this
.
nodeMapper
,
this
.
_onDidChangeNodeSlowState
.
event
));
const
objectTreeOptions
=
asObjectTreeOptions
<
TInput
,
T
,
TFilterData
>
(
options
)
||
{};
return
new
ObjectTree
(
user
,
container
,
objectTreeDelegate
,
objectTreeRenderers
,
objectTreeOptions
);
}
updateOptions
(
options
:
IAsyncDataTreeOptionsUpdate
=
{}):
void
{
this
.
tree
.
updateOptions
(
options
);
}
...
...
@@ -510,7 +506,7 @@ export class AsyncDataTree<TInput, T, TFilterData = void> implements IDisposable
getNode
(
element
:
TInput
|
T
=
this
.
root
.
element
):
ITreeNode
<
TInput
|
T
,
TFilterData
>
{
const
dataNode
=
this
.
getDataNode
(
element
);
const
node
=
this
.
tree
.
getNode
(
dataNode
===
this
.
root
?
null
:
dataNode
);
return
new
AsyncDataTreeNodeWrapper
<
TInput
,
T
,
TFilterData
>
(
node
);
return
this
.
nodeMapper
.
map
(
node
);
}
collapse
(
element
:
T
,
recursive
:
boolean
=
false
):
boolean
{
...
...
@@ -876,7 +872,7 @@ export class AsyncDataTree<TInput, T, TFilterData = void> implements IDisposable
}
private
render
(
node
:
IAsyncDataTreeNode
<
TInput
,
T
>
,
viewStateContext
?:
IAsyncDataTreeViewStateContext
<
TInput
,
T
>
):
void
{
const
children
=
node
.
children
.
map
(
c
=>
asTreeElement
(
c
,
viewStateContext
));
const
children
=
node
.
children
.
map
(
node
=>
this
.
asTreeElement
(
node
,
viewStateContext
));
this
.
tree
.
setChildren
(
node
===
this
.
root
?
null
:
node
,
children
);
if
(
node
!==
this
.
root
)
{
...
...
@@ -886,6 +882,25 @@ export class AsyncDataTree<TInput, T, TFilterData = void> implements IDisposable
this
.
_onDidRender
.
fire
();
}
protected
asTreeElement
(
node
:
IAsyncDataTreeNode
<
TInput
,
T
>
,
viewStateContext
?:
IAsyncDataTreeViewStateContext
<
TInput
,
T
>
):
ITreeElement
<
IAsyncDataTreeNode
<
TInput
,
T
>>
{
let
collapsed
:
boolean
|
undefined
;
if
(
viewStateContext
&&
viewStateContext
.
viewState
.
expanded
&&
node
.
id
&&
viewStateContext
.
viewState
.
expanded
.
indexOf
(
node
.
id
)
>
-
1
)
{
collapsed
=
false
;
}
else
{
collapsed
=
node
.
collapsedByDefault
;
}
node
.
collapsedByDefault
=
undefined
;
return
{
element
:
node
,
children
:
node
.
hasChildren
?
Iterator
.
map
(
Iterator
.
fromArray
(
node
.
children
),
child
=>
this
.
asTreeElement
(
child
,
viewStateContext
))
:
[],
collapsible
:
node
.
hasChildren
,
collapsed
};
}
// view state
getViewState
():
IAsyncDataTreeViewState
{
...
...
@@ -918,3 +933,117 @@ export class AsyncDataTree<TInput, T, TFilterData = void> implements IDisposable
dispose
(
this
.
disposables
);
}
}
type
CompressibleAsyncDataTreeNodeMapper
<
TInput
,
T
,
TFilterData
>
=
WeakMapper
<
ITreeNode
<
ICompressedTreeNode
<
IAsyncDataTreeNode
<
TInput
,
T
>>
,
TFilterData
>
,
ITreeNode
<
ICompressedTreeNode
<
TInput
|
T
>
,
TFilterData
>>
;
class
CompressibleAsyncDataTreeNodeWrapper
<
TInput
,
T
,
TFilterData
>
implements
ITreeNode
<
ICompressedTreeNode
<
TInput
|
T
>
,
TFilterData
>
{
get
element
():
ICompressedTreeNode
<
TInput
|
T
>
{
return
{
elements
:
this
.
node
.
element
.
elements
.
map
(
e
=>
e
.
element
),
incompressible
:
this
.
node
.
element
.
incompressible
};
}
get
children
():
ITreeNode
<
ICompressedTreeNode
<
TInput
|
T
>
,
TFilterData
>
[]
{
return
this
.
node
.
children
.
map
(
node
=>
new
CompressibleAsyncDataTreeNodeWrapper
(
node
));
}
get
depth
():
number
{
return
this
.
node
.
depth
;
}
get
visibleChildrenCount
():
number
{
return
this
.
node
.
visibleChildrenCount
;
}
get
visibleChildIndex
():
number
{
return
this
.
node
.
visibleChildIndex
;
}
get
collapsible
():
boolean
{
return
this
.
node
.
collapsible
;
}
get
collapsed
():
boolean
{
return
this
.
node
.
collapsed
;
}
get
visible
():
boolean
{
return
this
.
node
.
visible
;
}
get
filterData
():
TFilterData
|
undefined
{
return
this
.
node
.
filterData
;
}
constructor
(
private
node
:
ITreeNode
<
ICompressedTreeNode
<
IAsyncDataTreeNode
<
TInput
,
T
>>
,
TFilterData
>
)
{
}
}
class
CompressibleAsyncDataTreeRenderer
<
TInput
,
T
,
TFilterData
,
TTemplateData
>
implements
ICompressibleTreeRenderer
<
IAsyncDataTreeNode
<
TInput
,
T
>
,
TFilterData
,
IDataTreeListTemplateData
<
TTemplateData
>>
{
readonly
templateId
:
string
;
private
renderedNodes
=
new
Map
<
IAsyncDataTreeNode
<
TInput
,
T
>
,
IDataTreeListTemplateData
<
TTemplateData
>>
();
private
disposables
:
IDisposable
[]
=
[];
constructor
(
protected
renderer
:
ICompressibleTreeRenderer
<
T
,
TFilterData
,
TTemplateData
>
,
protected
nodeMapper
:
AsyncDataTreeNodeMapper
<
TInput
,
T
,
TFilterData
>
,
private
compressibleNodeMapperProvider
:
()
=>
CompressibleAsyncDataTreeNodeMapper
<
TInput
,
T
,
TFilterData
>
,
readonly
onDidChangeTwistieState
:
Event
<
IAsyncDataTreeNode
<
TInput
,
T
>>
)
{
this
.
templateId
=
renderer
.
templateId
;
}
renderTemplate
(
container
:
HTMLElement
):
IDataTreeListTemplateData
<
TTemplateData
>
{
const
templateData
=
this
.
renderer
.
renderTemplate
(
container
);
return
{
templateData
};
}
renderElement
(
node
:
ITreeNode
<
IAsyncDataTreeNode
<
TInput
,
T
>
,
TFilterData
>
,
index
:
number
,
templateData
:
IDataTreeListTemplateData
<
TTemplateData
>
,
height
:
number
|
undefined
):
void
{
this
.
renderer
.
renderElement
(
this
.
nodeMapper
.
map
(
node
)
as
ITreeNode
<
T
,
TFilterData
>
,
index
,
templateData
.
templateData
,
height
);
}
renderCompressedElements
(
node
:
ITreeNode
<
ICompressedTreeNode
<
IAsyncDataTreeNode
<
TInput
,
T
>>
,
TFilterData
>
,
index
:
number
,
templateData
:
IDataTreeListTemplateData
<
TTemplateData
>
,
height
:
number
|
undefined
):
void
{
this
.
renderer
.
renderCompressedElements
(
this
.
compressibleNodeMapperProvider
().
map
(
node
)
as
ITreeNode
<
ICompressedTreeNode
<
T
>
,
TFilterData
>
,
index
,
templateData
.
templateData
,
height
);
}
renderTwistie
(
element
:
IAsyncDataTreeNode
<
TInput
,
T
>
,
twistieElement
:
HTMLElement
):
boolean
{
toggleClass
(
twistieElement
,
'
loading
'
,
element
.
slow
);
return
false
;
}
disposeElement
(
node
:
ITreeNode
<
IAsyncDataTreeNode
<
TInput
,
T
>
,
TFilterData
>
,
index
:
number
,
templateData
:
IDataTreeListTemplateData
<
TTemplateData
>
,
height
:
number
|
undefined
):
void
{
if
(
this
.
renderer
.
disposeElement
)
{
this
.
renderer
.
disposeElement
(
this
.
nodeMapper
.
map
(
node
)
as
ITreeNode
<
T
,
TFilterData
>
,
index
,
templateData
.
templateData
,
height
);
}
}
disposeTemplate
(
templateData
:
IDataTreeListTemplateData
<
TTemplateData
>
):
void
{
this
.
renderer
.
disposeTemplate
(
templateData
.
templateData
);
}
dispose
():
void
{
this
.
renderedNodes
.
clear
();
this
.
disposables
=
dispose
(
this
.
disposables
);
}
}
export
interface
ITreeCompressionDelegate
<
T
>
{
isIncompressible
(
element
:
T
):
boolean
;
}
export
class
CompressibleAsyncDataTree
<
TInput
,
T
,
TFilterData
=
void
>
extends
AsyncDataTree
<
TInput
,
T
,
TFilterData
>
{
protected
readonly
compressibleNodeMapper
:
CompressibleAsyncDataTreeNodeMapper
<
TInput
,
T
,
TFilterData
>
=
new
WeakMapper
(
node
=>
new
CompressibleAsyncDataTreeNodeWrapper
(
node
));
constructor
(
user
:
string
,
container
:
HTMLElement
,
virtualDelegate
:
IListVirtualDelegate
<
T
>
,
private
compressionDelegate
:
ITreeCompressionDelegate
<
T
>
,
renderers
:
ICompressibleTreeRenderer
<
T
,
TFilterData
,
any
>
[],
dataSource
:
IAsyncDataSource
<
TInput
,
T
>
,
options
:
IAsyncDataTreeOptions
<
T
,
TFilterData
>
=
{}
)
{
super
(
user
,
container
,
virtualDelegate
,
renderers
,
dataSource
,
options
);
}
protected
createTree
(
user
:
string
,
container
:
HTMLElement
,
delegate
:
IListVirtualDelegate
<
T
>
,
renderers
:
ICompressibleTreeRenderer
<
T
,
TFilterData
,
any
>
[],
options
:
IAsyncDataTreeOptions
<
T
,
TFilterData
>
):
ObjectTree
<
IAsyncDataTreeNode
<
TInput
,
T
>
,
TFilterData
>
{
const
objectTreeDelegate
=
new
ComposedTreeDelegate
<
TInput
|
T
,
IAsyncDataTreeNode
<
TInput
,
T
>>
(
delegate
);
const
objectTreeRenderers
=
renderers
.
map
(
r
=>
new
CompressibleAsyncDataTreeRenderer
(
r
,
this
.
nodeMapper
,
()
=>
this
.
compressibleNodeMapper
,
this
.
_onDidChangeNodeSlowState
.
event
));
const
objectTreeOptions
=
asObjectTreeOptions
<
TInput
,
T
,
TFilterData
>
(
options
)
||
{};
return
new
CompressibleObjectTree
(
user
,
container
,
objectTreeDelegate
,
objectTreeRenderers
,
objectTreeOptions
);
}
protected
asTreeElement
(
node
:
IAsyncDataTreeNode
<
TInput
,
T
>
,
viewStateContext
?:
IAsyncDataTreeViewStateContext
<
TInput
,
T
>
):
ICompressedTreeElement
<
IAsyncDataTreeNode
<
TInput
,
T
>>
{
return
{
incompressible
:
this
.
compressionDelegate
.
isIncompressible
(
node
.
element
as
T
),
...
super
.
asTreeElement
(
node
,
viewStateContext
)
};
}
}
src/vs/base/browser/ui/tree/compressedObjectTree.ts
已删除
100644 → 0
浏览文件 @
c05a0af7
/*---------------------------------------------------------------------------------------------
* Copyright (c) Microsoft Corporation. All rights reserved.
* Licensed under the MIT License. See License.txt in the project root for license information.
*--------------------------------------------------------------------------------------------*/
import
{
Iterator
,
ISequence
}
from
'
vs/base/common/iterator
'
;
import
{
AbstractTree
,
IAbstractTreeOptions
}
from
'
vs/base/browser/ui/tree/abstractTree
'
;
import
{
ISpliceable
}
from
'
vs/base/common/sequence
'
;
import
{
ITreeNode
,
ITreeModel
,
ITreeElement
,
ITreeRenderer
,
ITreeSorter
,
ICollapseStateChangeEvent
}
from
'
vs/base/browser/ui/tree/tree
'
;
import
{
IListVirtualDelegate
}
from
'
vs/base/browser/ui/list/list
'
;
import
{
Event
}
from
'
vs/base/common/event
'
;
import
{
CompressedTreeModel
,
ICompressedTreeNode
}
from
'
vs/base/browser/ui/tree/compressedObjectTreeModel
'
;
export
interface
IObjectTreeOptions
<
T
,
TFilterData
=
void
>
extends
IAbstractTreeOptions
<
T
,
TFilterData
>
{
sorter
?:
ITreeSorter
<
T
>
;
}
export
class
CompressedObjectTree
<
T
extends
NonNullable
<
any
>
,
TFilterData
=
void
>
extends
AbstractTree
<
ICompressedTreeNode
<
T
>
|
null
,
TFilterData
,
T
|
null
>
{
protected
model
!
:
CompressedTreeModel
<
T
,
TFilterData
>
;
get
onDidChangeCollapseState
():
Event
<
ICollapseStateChangeEvent
<
ICompressedTreeNode
<
T
>
|
null
,
TFilterData
>>
{
return
this
.
model
.
onDidChangeCollapseState
;
}
constructor
(
user
:
string
,
container
:
HTMLElement
,
delegate
:
IListVirtualDelegate
<
ICompressedTreeNode
<
T
>>
,
renderers
:
ITreeRenderer
<
ICompressedTreeNode
<
T
>
,
TFilterData
,
any
>
[],
options
:
IObjectTreeOptions
<
ICompressedTreeNode
<
T
>
,
TFilterData
>
=
{}
)
{
super
(
user
,
container
,
delegate
,
renderers
,
options
);
}
setChildren
(
element
:
T
|
null
,
children
?:
ISequence
<
ITreeElement
<
T
>>
):
Iterator
<
ITreeElement
<
T
|
null
>>
{
return
this
.
model
.
setChildren
(
element
,
children
);
}
rerender
(
element
?:
T
):
void
{
if
(
element
===
undefined
)
{
this
.
view
.
rerender
();
return
;
}
this
.
model
.
rerender
(
element
);
}
resort
(
element
:
T
,
recursive
=
true
):
void
{
this
.
model
.
resort
(
element
,
recursive
);
}
protected
createModel
(
user
:
string
,
view
:
ISpliceable
<
ITreeNode
<
ICompressedTreeNode
<
T
>
,
TFilterData
>>
,
options
:
IObjectTreeOptions
<
ICompressedTreeNode
<
T
>
,
TFilterData
>
):
ITreeModel
<
ICompressedTreeNode
<
T
>
|
null
,
TFilterData
,
T
|
null
>
{
return
new
CompressedTreeModel
(
user
,
view
,
options
);
}
}
src/vs/base/browser/ui/tree/compressedObjectTreeModel.ts
浏览文件 @
4f399951
...
...
@@ -6,19 +6,32 @@
import
{
ISpliceable
}
from
'
vs/base/common/sequence
'
;
import
{
Iterator
,
ISequence
}
from
'
vs/base/common/iterator
'
;
import
{
Event
}
from
'
vs/base/common/event
'
;
import
{
ITreeModel
,
ITreeNode
,
ITreeElement
,
ICollapseStateChangeEvent
,
ITreeModelSpliceEvent
,
TreeError
}
from
'
vs/base/browser/ui/tree/tree
'
;
import
{
ITreeModel
,
ITreeNode
,
ITreeElement
,
ICollapseStateChangeEvent
,
ITreeModelSpliceEvent
,
TreeError
,
TreeFilterResult
,
TreeVisibility
,
WeakMapper
}
from
'
vs/base/browser/ui/tree/tree
'
;
import
{
IObjectTreeModelOptions
,
ObjectTreeModel
,
IObjectTreeModel
}
from
'
vs/base/browser/ui/tree/objectTreeModel
'
;
// Exported only for test reasons, do not use directly
export
interface
ICompressedTreeElement
<
T
>
extends
ITreeElement
<
T
>
{
readonly
children
?:
Iterator
<
ICompressedTreeElement
<
T
>>
|
ICompressedTreeElement
<
T
>
[];
readonly
incompressible
?:
boolean
;
}
// Exported only for test reasons, do not use directly
export
interface
ICompressedTreeNode
<
T
>
{
readonly
elements
:
T
[];
readonly
incompressible
:
boolean
;
}
function
noCompress
<
T
>
(
element
:
ICompressedTreeElement
<
T
>
):
ITreeElement
<
ICompressedTreeNode
<
T
>>
{
const
elements
=
[
element
.
element
];
const
incompressible
=
element
.
incompressible
||
false
;
return
{
element
:
{
elements
,
incompressible
},
children
:
Iterator
.
map
(
Iterator
.
from
(
element
.
children
),
noCompress
)
};
}
// Exported only for test reasons, do not use directly
export
function
compress
<
T
>
(
element
:
ICompressedTreeElement
<
T
>
):
ITreeElement
<
ICompressedTreeNode
<
T
>>
{
const
elements
=
[
element
.
element
];
const
incompressible
=
element
.
incompressible
||
false
;
...
...
@@ -49,7 +62,7 @@ export function compress<T>(element: ICompressedTreeElement<T>): ITreeElement<IC
};
}
export
function
_decompress
<
T
>
(
element
:
ITreeElement
<
ICompressedTreeNode
<
T
>>
,
index
=
0
):
ICompressedTreeElement
<
T
>
{
function
_decompress
<
T
>
(
element
:
ITreeElement
<
ICompressedTreeNode
<
T
>>
,
index
=
0
):
ICompressedTreeElement
<
T
>
{
let
children
:
Iterator
<
ICompressedTreeElement
<
T
>>
;
if
(
index
<
element
.
element
.
elements
.
length
-
1
)
{
...
...
@@ -65,11 +78,12 @@ export function _decompress<T>(element: ITreeElement<ICompressedTreeNode<T>>, in
return
{
element
:
element
.
element
.
elements
[
index
],
children
};
}
// Exported only for test reasons, do not use directly
export
function
decompress
<
T
>
(
element
:
ITreeElement
<
ICompressedTreeNode
<
T
>>
):
ICompressedTreeElement
<
T
>
{
return
_decompress
(
element
,
0
);
}
export
function
splice
<
T
>
(
treeElement
:
ICompressedTreeElement
<
T
>
,
element
:
T
,
children
:
Iterator
<
ICompressedTreeElement
<
T
>>
):
ICompressedTreeElement
<
T
>
{
function
splice
<
T
>
(
treeElement
:
ICompressedTreeElement
<
T
>
,
element
:
T
,
children
:
Iterator
<
ICompressedTreeElement
<
T
>>
):
ICompressedTreeElement
<
T
>
{
if
(
treeElement
.
element
===
element
)
{
return
{
element
,
children
};
}
...
...
@@ -80,9 +94,10 @@ export function splice<T>(treeElement: ICompressedTreeElement<T>, element: T, ch
};
}
export
interface
ICompressed
TreeModelOptions
<
T
,
TFilterData
>
extends
IObjectTreeModelOptions
<
ICompressedTreeNode
<
T
>
,
TFilterData
>
{
}
interface
ICompressedObject
TreeModelOptions
<
T
,
TFilterData
>
extends
IObjectTreeModelOptions
<
ICompressedTreeNode
<
T
>
,
TFilterData
>
{
}
export
class
CompressedTreeModel
<
T
extends
NonNullable
<
any
>
,
TFilterData
extends
NonNullable
<
any
>
=
void
>
implements
ITreeModel
<
ICompressedTreeNode
<
T
>
|
null
,
TFilterData
,
T
|
null
>
{
// Exported only for test reasons, do not use directly
export
class
CompressedObjectTreeModel
<
T
extends
NonNullable
<
any
>
,
TFilterData
extends
NonNullable
<
any
>
=
void
>
implements
ITreeModel
<
ICompressedTreeNode
<
T
>
|
null
,
TFilterData
,
T
|
null
>
{
readonly
rootRef
=
null
;
...
...
@@ -92,39 +107,77 @@ export class CompressedTreeModel<T extends NonNullable<any>, TFilterData extends
private
model
:
ObjectTreeModel
<
ICompressedTreeNode
<
T
>
,
TFilterData
>
;
private
nodes
=
new
Map
<
T
|
null
,
ICompressedTreeNode
<
T
>>
();
private
enabled
:
boolean
=
true
;
get
size
():
number
{
return
this
.
nodes
.
size
;
}
constructor
(
private
user
:
string
,
list
:
ISpliceable
<
ITreeNode
<
ICompressedTreeNode
<
T
>
,
TFilterData
>>
,
options
:
ICompressedTreeModelOptions
<
T
,
TFilterData
>
=
{}
options
:
ICompressed
Object
TreeModelOptions
<
T
,
TFilterData
>
=
{}
)
{
this
.
model
=
new
ObjectTreeModel
(
user
,
list
,
options
);
}
setChildren
(
element
:
T
|
null
,
children
:
ISequence
<
ICompressedTreeElement
<
T
>>
|
undefined
,
onDidCreateNode
?:
(
node
:
ITreeNode
<
ICompressedTreeNode
<
T
>
,
TFilterData
>
)
=>
void
,
onDidDeleteNode
?:
(
node
:
ITreeNode
<
ICompressedTreeNode
<
T
>
,
TFilterData
>
)
=>
void
):
Iterator
<
ITreeElement
<
T
|
null
>>
{
children
:
ISequence
<
ICompressedTreeElement
<
T
>>
|
undefined
):
void
{
if
(
element
===
null
)
{
const
compressedChildren
=
Iterator
.
map
(
Iterator
.
from
(
children
),
this
.
enabled
?
compress
:
noCompress
);
this
.
_setChildren
(
null
,
compressedChildren
);
return
;
}
const
compressedNode
=
this
.
nodes
.
get
(
element
);
if
(
!
compressedNode
)
{
throw
new
Error
(
'
Unknown compressed tree node
'
);
}
const
node
=
this
.
model
.
getNode
(
compressedNode
)
as
ITreeNode
<
ICompressedTreeNode
<
T
>
,
TFilterData
>
;
const
compressedParentNode
=
this
.
model
.
getParentNodeLocation
(
compressedNode
);
const
parent
=
this
.
model
.
getNode
(
compressedParentNode
)
as
ITreeNode
<
ICompressedTreeNode
<
T
>
,
TFilterData
>
;
const
decompressedElement
=
decompress
(
node
);
const
splicedElement
=
splice
(
decompressedElement
,
element
,
Iterator
.
from
(
children
));
const
recompressedElement
=
(
this
.
enabled
?
compress
:
noCompress
)(
splicedElement
);
const
parentChildren
=
parent
.
children
.
map
(
child
=>
child
===
node
?
recompressedElement
:
child
);
this
.
_setChildren
(
parent
.
element
,
parentChildren
);
}
isCompressionEnabled
():
boolean
{
return
this
.
enabled
;
}
setCompressionEnabled
(
enabled
:
boolean
):
void
{
if
(
enabled
===
this
.
enabled
)
{
return
;
}
this
.
enabled
=
enabled
;
const
root
=
this
.
model
.
getNode
();
const
rootChildren
=
Iterator
.
from
(
root
.
children
as
ITreeNode
<
ICompressedTreeNode
<
T
>>
[]);
const
decompressedRootChildren
=
Iterator
.
map
(
rootChildren
,
decompress
);
const
recompressedRootChildren
=
Iterator
.
map
(
decompressedRootChildren
,
enabled
?
compress
:
noCompress
);
this
.
_setChildren
(
null
,
recompressedRootChildren
);
}
private
_setChildren
(
node
:
ICompressedTreeNode
<
T
>
|
null
,
children
:
ISequence
<
ITreeElement
<
ICompressedTreeNode
<
T
>>>
|
undefined
):
void
{
const
insertedElements
=
new
Set
<
T
|
null
>
();
const
_onDidCreateNode
=
(
node
:
ITreeNode
<
ICompressedTreeNode
<
T
>
,
TFilterData
>
)
=>
{
for
(
const
element
of
node
.
element
.
elements
)
{
insertedElements
.
add
(
element
);
this
.
nodes
.
set
(
element
,
node
.
element
);
}
// if (this.identityProvider) {
// const id = this.identityProvider.getId(node.element).toString();
// insertedElementIds.add(id);
// this.nodesByIdentity.set(id, node);
// }
if
(
onDidCreateNode
)
{
onDidCreateNode
(
node
);
}
};
const
_onDidDeleteNode
=
(
node
:
ITreeNode
<
ICompressedTreeNode
<
T
>
,
TFilterData
>
)
=>
{
...
...
@@ -133,40 +186,9 @@ export class CompressedTreeModel<T extends NonNullable<any>, TFilterData extends
this
.
nodes
.
delete
(
element
);
}
}
// if (this.identityProvider) {
// const id = this.identityProvider.getId(node.element).toString();
// if (!insertedElementIds.has(id)) {
// this.nodesByIdentity.delete(id);
// }
// }
if
(
onDidDeleteNode
)
{
onDidDeleteNode
(
node
);
}
};
if
(
element
===
null
)
{
const
compressedChildren
=
Iterator
.
map
(
Iterator
.
from
(
children
),
compress
);
const
result
=
this
.
model
.
setChildren
(
null
,
compressedChildren
,
_onDidCreateNode
,
_onDidDeleteNode
);
return
Iterator
.
map
(
result
,
decompress
);
}
const
compressedNode
=
this
.
nodes
.
get
(
element
);
const
node
=
this
.
model
.
getNode
(
compressedNode
)
as
ITreeNode
<
ICompressedTreeNode
<
T
>
,
TFilterData
>
;
const
parent
=
node
.
parent
!
;
const
decompressedElement
=
decompress
(
node
);
const
splicedElement
=
splice
(
decompressedElement
,
element
,
Iterator
.
from
(
children
));
const
recompressedElement
=
compress
(
splicedElement
);
const
parentChildren
=
parent
.
children
.
map
(
child
=>
child
===
node
?
recompressedElement
:
child
);
this
.
model
.
setChildren
(
parent
.
element
,
parentChildren
,
_onDidCreateNode
,
_onDidDeleteNode
);
// TODO
return
Iterator
.
empty
();
this
.
model
.
setChildren
(
node
,
children
,
_onDidCreateNode
,
_onDidDeleteNode
);
}
getListIndex
(
location
:
T
|
null
):
number
{
...
...
@@ -211,11 +233,6 @@ export class CompressedTreeModel<T extends NonNullable<any>, TFilterData extends
return
parentNode
.
elements
[
parentNode
.
elements
.
length
-
1
];
}
getParentElement
(
location
:
T
|
null
):
ICompressedTreeNode
<
T
>
|
null
{
const
compressedNode
=
this
.
getCompressedNode
(
location
);
return
this
.
model
.
getParentElement
(
compressedNode
);
}
getFirstElementChild
(
location
:
T
|
null
):
ICompressedTreeNode
<
T
>
|
null
|
undefined
{
const
compressedNode
=
this
.
getCompressedNode
(
location
);
return
this
.
model
.
getFirstElementChild
(
compressedNode
);
...
...
@@ -265,7 +282,7 @@ export class CompressedTreeModel<T extends NonNullable<any>, TFilterData extends
this
.
model
.
resort
(
compressedNode
,
recursive
);
}
private
getCompressedNode
(
element
:
T
|
null
):
ICompressedTreeNode
<
T
>
|
null
{
getCompressedNode
(
element
:
T
|
null
):
ICompressedTreeNode
<
T
>
|
null
{
if
(
element
===
null
)
{
return
null
;
}
...
...
@@ -280,72 +297,113 @@ export class CompressedTreeModel<T extends NonNullable<any>, TFilterData extends
}
}
// Compressible Object Tree
export
type
ElementMapper
<
T
>
=
(
elements
:
T
[])
=>
T
;
export
const
DefaultElementMapper
:
ElementMapper
<
any
>
=
elements
=>
elements
[
elements
.
length
-
1
];
export
type
NodeMapper
<
T
,
TFilterData
>
=
(
node
:
ITreeNode
<
ICompressedTreeNode
<
T
>
|
null
,
TFilterData
>
)
=>
ITreeNode
<
T
|
null
,
TFilterData
>
;
export
type
CompressedNodeUnwrapper
<
T
>
=
(
node
:
ICompressedTreeNode
<
T
>
)
=>
T
;
type
CompressedNodeWeakMapper
<
T
,
TFilterData
>
=
WeakMapper
<
ITreeNode
<
ICompressedTreeNode
<
T
>
|
null
,
TFilterData
>
,
ITreeNode
<
T
|
null
,
TFilterData
>>
;
class
CompressedTreeNodeWrapper
<
T
,
TFilterData
>
implements
ITreeNode
<
T
|
null
,
TFilterData
>
{
get
element
():
T
|
null
{
return
this
.
node
.
element
===
null
?
null
:
this
.
unwrapper
(
this
.
node
.
element
);
}
get
children
():
ITreeNode
<
T
|
null
,
TFilterData
>
[]
{
return
this
.
node
.
children
.
map
(
node
=>
new
CompressedTreeNodeWrapper
(
this
.
unwrapper
,
node
));
}
get
depth
():
number
{
return
this
.
node
.
depth
;
}
get
visibleChildrenCount
():
number
{
return
this
.
node
.
visibleChildrenCount
;
}
get
visibleChildIndex
():
number
{
return
this
.
node
.
visibleChildIndex
;
}
get
collapsible
():
boolean
{
return
this
.
node
.
collapsible
;
}
get
collapsed
():
boolean
{
return
this
.
node
.
collapsed
;
}
get
visible
():
boolean
{
return
this
.
node
.
visible
;
}
get
filterData
():
TFilterData
|
undefined
{
return
this
.
node
.
filterData
;
}
function
mapNode
<
T
,
TFilterData
>
(
elementMapper
:
ElementMapper
<
T
>
,
node
:
ITreeNode
<
ICompressedTreeNode
<
T
>
|
null
,
TFilterData
>
):
ITreeNode
<
T
|
null
,
TFilterData
>
{
constructor
(
private
unwrapper
:
CompressedNodeUnwrapper
<
T
>
,
private
node
:
ITreeNode
<
ICompressedTreeNode
<
T
>
|
null
,
TFilterData
>
)
{
}
}
function
mapList
<
T
,
TFilterData
>
(
nodeMapper
:
CompressedNodeWeakMapper
<
T
,
TFilterData
>
,
list
:
ISpliceable
<
ITreeNode
<
T
,
TFilterData
>>
):
ISpliceable
<
ITreeNode
<
ICompressedTreeNode
<
T
>
,
TFilterData
>>
{
return
{
...
node
,
element
:
node
.
element
===
null
?
null
:
elementMapper
(
node
.
element
.
elements
),
children
:
node
.
children
.
map
(
child
=>
mapNode
(
elementMapper
,
child
)),
parent
:
typeof
node
.
parent
===
'
undefined
'
?
node
.
parent
:
mapNode
(
elementMapper
,
node
.
parent
)
splice
(
start
:
number
,
deleteCount
:
number
,
toInsert
:
ITreeNode
<
ICompressedTreeNode
<
T
>
,
TFilterData
>
[]):
void
{
list
.
splice
(
start
,
deleteCount
,
toInsert
.
map
(
node
=>
nodeMapper
.
map
(
node
))
as
ITreeNode
<
T
,
TFilterData
>
[]);
}
};
}
function
createNodeMapper
<
T
,
TFilterData
>
(
elementMapper
:
ElementMapper
<
T
>
):
NodeMapper
<
T
,
TFilterData
>
{
return
node
=>
mapNode
(
elementMapper
,
node
);
function
mapOptions
<
T
,
TFilterData
>
(
compressedNodeUnwrapper
:
CompressedNodeUnwrapper
<
T
>
,
options
:
ICompressibleObjectTreeModelOptions
<
T
,
TFilterData
>
):
ICompressedObjectTreeModelOptions
<
T
,
TFilterData
>
{
return
{
...
options
,
sorter
:
options
.
sorter
&&
{
compare
(
node
:
ICompressedTreeNode
<
T
>
,
otherNode
:
ICompressedTreeNode
<
T
>
):
number
{
return
options
.
sorter
!
.
compare
(
compressedNodeUnwrapper
(
node
),
compressedNodeUnwrapper
(
otherNode
));
}
},
identityProvider
:
options
.
identityProvider
&&
{
getId
(
node
:
ICompressedTreeNode
<
T
>
):
{
toString
():
string
;
}
{
return
options
.
identityProvider
!
.
getId
(
compressedNodeUnwrapper
(
node
));
}
},
filter
:
options
.
filter
&&
{
filter
(
node
:
ICompressedTreeNode
<
T
>
,
parentVisibility
:
TreeVisibility
):
TreeFilterResult
<
TFilterData
>
{
return
options
.
filter
!
.
filter
(
compressedNodeUnwrapper
(
node
),
parentVisibility
);
}
}
};
}
export
interface
ICompress
edObjectTreeModelOptions
<
T
,
TFilterData
>
extends
ICompressed
TreeModelOptions
<
T
,
TFilterData
>
{
export
interface
ICompress
ibleObjectTreeModelOptions
<
T
,
TFilterData
>
extends
IObject
TreeModelOptions
<
T
,
TFilterData
>
{
readonly
elementMapper
?:
ElementMapper
<
T
>
;
}
export
class
Compress
ed
ObjectTreeModel
<
T
extends
NonNullable
<
any
>
,
TFilterData
extends
NonNullable
<
any
>
=
void
>
implements
IObjectTreeModel
<
T
,
TFilterData
>
{
export
class
Compress
ible
ObjectTreeModel
<
T
extends
NonNullable
<
any
>
,
TFilterData
extends
NonNullable
<
any
>
=
void
>
implements
IObjectTreeModel
<
T
,
TFilterData
>
{
readonly
rootRef
=
null
;
get
onDidSplice
():
Event
<
ITreeModelSpliceEvent
<
T
|
null
,
TFilterData
>>
{
return
Event
.
map
(
this
.
model
.
onDidSplice
,
({
insertedNodes
,
deletedNodes
})
=>
({
insertedNodes
:
insertedNodes
.
map
(
this
.
mapNode
),
deletedNodes
:
deletedNodes
.
map
(
this
.
mapNode
),
insertedNodes
:
insertedNodes
.
map
(
node
=>
this
.
nodeMapper
.
map
(
node
)
),
deletedNodes
:
deletedNodes
.
map
(
node
=>
this
.
nodeMapper
.
map
(
node
)
),
}));
}
get
onDidChangeCollapseState
():
Event
<
ICollapseStateChangeEvent
<
T
|
null
,
TFilterData
>>
{
return
Event
.
map
(
this
.
model
.
onDidChangeCollapseState
,
({
node
,
deep
})
=>
({
node
:
this
.
mapNode
(
node
),
node
:
this
.
nodeMapper
.
map
(
node
),
deep
}));
}
get
onDidChangeRenderNodeCount
():
Event
<
ITreeNode
<
T
|
null
,
TFilterData
>>
{
return
Event
.
map
(
this
.
model
.
onDidChangeRenderNodeCount
,
this
.
mapNode
);
return
Event
.
map
(
this
.
model
.
onDidChangeRenderNodeCount
,
node
=>
this
.
nodeMapper
.
map
(
node
)
);
}
private
mapElement
:
ElementMapper
<
T
|
null
>
;
private
mapNode
:
NodeMapper
<
T
|
null
,
TFilterData
>
;
private
model
:
CompressedTreeModel
<
T
,
TFilterData
>
;
private
elementMapper
:
ElementMapper
<
T
>
;
private
nodeMapper
:
CompressedNodeWeakMapper
<
T
,
TFilterData
>
;
private
model
:
Compressed
Object
TreeModel
<
T
,
TFilterData
>
;
constructor
(
user
:
string
,
list
:
ISpliceable
<
ITreeNode
<
ICompressedTreeNode
<
T
>
,
TFilterData
>>
,
options
:
ICompress
ed
ObjectTreeModelOptions
<
T
,
TFilterData
>
=
{}
list
:
ISpliceable
<
ITreeNode
<
T
,
TFilterData
>>
,
options
:
ICompress
ible
ObjectTreeModelOptions
<
T
,
TFilterData
>
=
{}
)
{
this
.
mapElement
=
options
.
elementMapper
||
DefaultElementMapper
;
this
.
mapNode
=
createNodeMapper
(
this
.
mapElement
);
this
.
model
=
new
CompressedTreeModel
(
user
,
list
,
options
);
this
.
elementMapper
=
options
.
elementMapper
||
DefaultElementMapper
;
const
compressedNodeUnwrapper
:
CompressedNodeUnwrapper
<
T
>
=
node
=>
this
.
elementMapper
(
node
.
elements
);
this
.
nodeMapper
=
new
WeakMapper
(
node
=>
new
CompressedTreeNodeWrapper
(
compressedNodeUnwrapper
,
node
));
this
.
model
=
new
CompressedObjectTreeModel
(
user
,
mapList
(
this
.
nodeMapper
,
list
),
mapOptions
(
compressedNodeUnwrapper
,
options
));
}
setChildren
(
element
:
T
|
null
,
children
:
ISequence
<
ITreeElement
<
T
>>
|
undefined
):
Iterator
<
ITreeElement
<
T
>>
{
setChildren
(
element
:
T
|
null
,
children
?:
ISequence
<
ICompressedTreeElement
<
T
>>
):
void
{
this
.
model
.
setChildren
(
element
,
children
);
}
// TODO
return
Iterator
.
empty
();
isCompressionEnabled
():
boolean
{
return
this
.
model
.
isCompressionEnabled
();
}
setCompressionEnabled
(
enabled
:
boolean
):
void
{
this
.
model
.
setCompressionEnabled
(
enabled
);
}
getListIndex
(
location
:
T
|
null
):
number
{
...
...
@@ -357,7 +415,7 @@ export class CompressedObjectTreeModel<T extends NonNullable<any>, TFilterData e
}
getNode
(
location
?:
T
|
null
|
undefined
):
ITreeNode
<
T
|
null
,
any
>
{
return
this
.
mapNode
(
this
.
model
.
getNode
(
location
));
return
this
.
nodeMapper
.
map
(
this
.
model
.
getNode
(
location
));
}
getNodeLocation
(
node
:
ITreeNode
<
T
|
null
,
any
>
):
T
|
null
{
...
...
@@ -368,16 +426,6 @@ export class CompressedObjectTreeModel<T extends NonNullable<any>, TFilterData e
return
this
.
model
.
getParentNodeLocation
(
location
);
}
getParentElement
(
location
:
T
|
null
):
T
|
null
{
const
result
=
this
.
model
.
getParentElement
(
location
);
if
(
result
===
null
)
{
return
result
;
}
return
this
.
mapElement
(
result
.
elements
);
}
getFirstElementChild
(
location
:
T
|
null
):
T
|
null
|
undefined
{
const
result
=
this
.
model
.
getFirstElementChild
(
location
);
...
...
@@ -385,7 +433,7 @@ export class CompressedObjectTreeModel<T extends NonNullable<any>, TFilterData e
return
result
;
}
return
this
.
mapElement
(
result
.
elements
);
return
this
.
elementMapper
(
result
.
elements
);
}
getLastElementAncestor
(
location
?:
T
|
null
|
undefined
):
T
|
null
|
undefined
{
...
...
@@ -395,7 +443,7 @@ export class CompressedObjectTreeModel<T extends NonNullable<any>, TFilterData e
return
result
;
}
return
this
.
mapElement
(
result
.
elements
);
return
this
.
elementMapper
(
result
.
elements
);
}
isCollapsible
(
location
:
T
|
null
):
boolean
{
...
...
@@ -429,4 +477,8 @@ export class CompressedObjectTreeModel<T extends NonNullable<any>, TFilterData e
resort
(
element
:
T
|
null
=
null
,
recursive
=
true
):
void
{
return
this
.
model
.
resort
(
element
,
recursive
);
}
getCompressedTreeNode
(
element
:
T
):
ITreeNode
<
ICompressedTreeNode
<
T
>
,
TFilterData
>
{
return
this
.
model
.
getNode
(
element
)
as
ITreeNode
<
ICompressedTreeNode
<
T
>
,
TFilterData
>
;
}
}
src/vs/base/browser/ui/tree/indexTree.ts
浏览文件 @
4f399951
...
...
@@ -28,8 +28,8 @@ export class IndexTree<T, TFilterData = void> extends AbstractTree<T, TFilterDat
super
(
user
,
container
,
delegate
,
renderers
,
options
);
}
splice
(
location
:
number
[],
deleteCount
:
number
,
toInsert
:
ISequence
<
ITreeElement
<
T
>>
=
Iterator
.
empty
()):
Iterator
<
ITreeElement
<
T
>>
{
return
this
.
model
.
splice
(
location
,
deleteCount
,
toInsert
);
splice
(
location
:
number
[],
deleteCount
:
number
,
toInsert
:
ISequence
<
ITreeElement
<
T
>>
=
Iterator
.
empty
()):
void
{
this
.
model
.
splice
(
location
,
deleteCount
,
toInsert
);
}
rerender
(
location
?:
number
[]):
void
{
...
...
src/vs/base/browser/ui/tree/indexTreeModel.ts
浏览文件 @
4f399951
...
...
@@ -9,9 +9,10 @@ import { Emitter, Event, EventBufferer } from 'vs/base/common/event';
import
{
ISequence
,
Iterator
}
from
'
vs/base/common/iterator
'
;
import
{
ISpliceable
}
from
'
vs/base/common/sequence
'
;
interface
IMutableTreeNode
<
T
,
TFilterData
>
extends
ITreeNode
<
T
,
TFilterData
>
{
readonly
parent
:
IMutableTreeNode
<
T
,
TFilterData
>
|
undefined
;
readonly
children
:
IMutableTreeNode
<
T
,
TFilterData
>
[];
// Exported for tests
export
interface
IIndexTreeNode
<
T
,
TFilterData
=
void
>
extends
ITreeNode
<
T
,
TFilterData
>
{
readonly
parent
:
IIndexTreeNode
<
T
,
TFilterData
>
|
undefined
;
readonly
children
:
IIndexTreeNode
<
T
,
TFilterData
>
[];
visibleChildrenCount
:
number
;
visibleChildIndex
:
number
;
collapsible
:
boolean
;
...
...
@@ -33,13 +34,6 @@ export function getVisibleState(visibility: boolean | TreeVisibility): TreeVisib
}
}
function
treeNodeToElement
<
T
>
(
node
:
IMutableTreeNode
<
T
,
any
>
):
ITreeElement
<
T
>
{
const
{
element
,
collapsed
}
=
node
;
const
children
=
Iterator
.
map
(
Iterator
.
fromArray
(
node
.
children
),
treeNodeToElement
);
return
{
element
,
children
,
collapsed
};
}
export
interface
IIndexTreeModelOptions
<
T
,
TFilterData
>
{
readonly
collapseByDefault
?:
boolean
;
// defaults to false
readonly
filter
?:
ITreeFilter
<
T
,
TFilterData
>
;
...
...
@@ -65,7 +59,7 @@ export class IndexTreeModel<T extends Exclude<any, undefined>, TFilterData = voi
readonly
rootRef
=
[];
private
root
:
I
Mutable
TreeNode
<
T
,
TFilterData
>
;
private
root
:
I
Index
TreeNode
<
T
,
TFilterData
>
;
private
eventBufferer
=
new
EventBufferer
();
private
_onDidChangeCollapseState
=
new
Emitter
<
ICollapseStateChangeEvent
<
T
,
TFilterData
>>
();
...
...
@@ -112,7 +106,7 @@ export class IndexTreeModel<T extends Exclude<any, undefined>, TFilterData = voi
toInsert
?:
ISequence
<
ITreeElement
<
T
>>
,
onDidCreateNode
?:
(
node
:
ITreeNode
<
T
,
TFilterData
>
)
=>
void
,
onDidDeleteNode
?:
(
node
:
ITreeNode
<
T
,
TFilterData
>
)
=>
void
):
Iterator
<
ITreeElement
<
T
>>
{
):
void
{
if
(
location
.
length
===
0
)
{
throw
new
TreeError
(
this
.
user
,
'
Invalid tree location
'
);
}
...
...
@@ -136,7 +130,7 @@ export class IndexTreeModel<T extends Exclude<any, undefined>, TFilterData = voi
}
}
const
nodesToInsert
:
I
Mutable
TreeNode
<
T
,
TFilterData
>
[]
=
[];
const
nodesToInsert
:
I
Index
TreeNode
<
T
,
TFilterData
>
[]
=
[];
let
insertedVisibleChildrenCount
=
0
;
let
renderNodeCount
=
0
;
...
...
@@ -190,9 +184,7 @@ export class IndexTreeModel<T extends Exclude<any, undefined>, TFilterData = voi
deletedNodes
.
forEach
(
visit
);
}
const
result
=
Iterator
.
map
(
Iterator
.
fromArray
(
deletedNodes
),
treeNodeToElement
);
this
.
_onDidSplice
.
fire
({
insertedNodes
:
nodesToInsert
,
deletedNodes
});
return
result
;
}
rerender
(
location
:
number
[]):
void
{
...
...
@@ -275,7 +267,7 @@ export class IndexTreeModel<T extends Exclude<any, undefined>, TFilterData = voi
return
result
;
}
private
_setListNodeCollapseState
(
node
:
I
Mutable
TreeNode
<
T
,
TFilterData
>
,
listIndex
:
number
,
revealed
:
boolean
,
update
:
CollapseStateUpdate
):
boolean
{
private
_setListNodeCollapseState
(
node
:
I
Index
TreeNode
<
T
,
TFilterData
>
,
listIndex
:
number
,
revealed
:
boolean
,
update
:
CollapseStateUpdate
):
boolean
{
const
result
=
this
.
_setNodeCollapseState
(
node
,
update
,
false
);
if
(
!
revealed
||
!
node
.
visible
||
!
result
)
{
...
...
@@ -290,7 +282,7 @@ export class IndexTreeModel<T extends Exclude<any, undefined>, TFilterData = voi
return
result
;
}
private
_setNodeCollapseState
(
node
:
I
Mutable
TreeNode
<
T
,
TFilterData
>
,
update
:
CollapseStateUpdate
,
deep
:
boolean
):
boolean
{
private
_setNodeCollapseState
(
node
:
I
Index
TreeNode
<
T
,
TFilterData
>
,
update
:
CollapseStateUpdate
,
deep
:
boolean
):
boolean
{
let
result
:
boolean
;
if
(
node
===
this
.
root
)
{
...
...
@@ -341,13 +333,13 @@ export class IndexTreeModel<T extends Exclude<any, undefined>, TFilterData = voi
private
createTreeNode
(
treeElement
:
ITreeElement
<
T
>
,
parent
:
I
Mutable
TreeNode
<
T
,
TFilterData
>
,
parent
:
I
Index
TreeNode
<
T
,
TFilterData
>
,
parentVisibility
:
TreeVisibility
,
revealed
:
boolean
,
treeListElements
:
ITreeNode
<
T
,
TFilterData
>
[],
onDidCreateNode
?:
(
node
:
ITreeNode
<
T
,
TFilterData
>
)
=>
void
):
I
Mutable
TreeNode
<
T
,
TFilterData
>
{
const
node
:
I
Mutable
TreeNode
<
T
,
TFilterData
>
=
{
):
I
Index
TreeNode
<
T
,
TFilterData
>
{
const
node
:
I
Index
TreeNode
<
T
,
TFilterData
>
=
{
parent
,
element
:
treeElement
.
element
,
children
:
[],
...
...
@@ -404,7 +396,7 @@ export class IndexTreeModel<T extends Exclude<any, undefined>, TFilterData = voi
return
node
;
}
private
updateNodeAfterCollapseChange
(
node
:
I
Mutable
TreeNode
<
T
,
TFilterData
>
):
ITreeNode
<
T
,
TFilterData
>
[]
{
private
updateNodeAfterCollapseChange
(
node
:
I
Index
TreeNode
<
T
,
TFilterData
>
):
ITreeNode
<
T
,
TFilterData
>
[]
{
const
previousRenderNodeCount
=
node
.
renderNodeCount
;
const
result
:
ITreeNode
<
T
,
TFilterData
>
[]
=
[];
...
...
@@ -414,7 +406,7 @@ export class IndexTreeModel<T extends Exclude<any, undefined>, TFilterData = voi
return
result
;
}
private
_updateNodeAfterCollapseChange
(
node
:
I
Mutable
TreeNode
<
T
,
TFilterData
>
,
result
:
ITreeNode
<
T
,
TFilterData
>
[]):
number
{
private
_updateNodeAfterCollapseChange
(
node
:
I
Index
TreeNode
<
T
,
TFilterData
>
,
result
:
ITreeNode
<
T
,
TFilterData
>
[]):
number
{
if
(
node
.
visible
===
false
)
{
return
0
;
}
...
...
@@ -432,7 +424,7 @@ export class IndexTreeModel<T extends Exclude<any, undefined>, TFilterData = voi
return
node
.
renderNodeCount
;
}
private
updateNodeAfterFilterChange
(
node
:
I
Mutable
TreeNode
<
T
,
TFilterData
>
):
ITreeNode
<
T
,
TFilterData
>
[]
{
private
updateNodeAfterFilterChange
(
node
:
I
Index
TreeNode
<
T
,
TFilterData
>
):
ITreeNode
<
T
,
TFilterData
>
[]
{
const
previousRenderNodeCount
=
node
.
renderNodeCount
;
const
result
:
ITreeNode
<
T
,
TFilterData
>
[]
=
[];
...
...
@@ -442,7 +434,7 @@ export class IndexTreeModel<T extends Exclude<any, undefined>, TFilterData = voi
return
result
;
}
private
_updateNodeAfterFilterChange
(
node
:
I
Mutable
TreeNode
<
T
,
TFilterData
>
,
parentVisibility
:
TreeVisibility
,
result
:
ITreeNode
<
T
,
TFilterData
>
[],
revealed
=
true
):
boolean
{
private
_updateNodeAfterFilterChange
(
node
:
I
Index
TreeNode
<
T
,
TFilterData
>
,
parentVisibility
:
TreeVisibility
,
result
:
ITreeNode
<
T
,
TFilterData
>
[],
revealed
=
true
):
boolean
{
let
visibility
:
TreeVisibility
;
if
(
node
!==
this
.
root
)
{
...
...
@@ -496,7 +488,7 @@ export class IndexTreeModel<T extends Exclude<any, undefined>, TFilterData = voi
return
node
.
visible
;
}
private
_updateAncestorsRenderNodeCount
(
node
:
I
Mutable
TreeNode
<
T
,
TFilterData
>
|
undefined
,
diff
:
number
):
void
{
private
_updateAncestorsRenderNodeCount
(
node
:
I
Index
TreeNode
<
T
,
TFilterData
>
|
undefined
,
diff
:
number
):
void
{
if
(
diff
===
0
)
{
return
;
}
...
...
@@ -508,7 +500,7 @@ export class IndexTreeModel<T extends Exclude<any, undefined>, TFilterData = voi
}
}
private
_filterNode
(
node
:
I
Mutable
TreeNode
<
T
,
TFilterData
>
,
parentVisibility
:
TreeVisibility
):
TreeVisibility
{
private
_filterNode
(
node
:
I
Index
TreeNode
<
T
,
TFilterData
>
,
parentVisibility
:
TreeVisibility
):
TreeVisibility
{
const
result
=
this
.
filter
?
this
.
filter
.
filter
(
node
.
element
,
parentVisibility
)
:
TreeVisibility
.
Visible
;
if
(
typeof
result
===
'
boolean
'
)
{
...
...
@@ -524,7 +516,7 @@ export class IndexTreeModel<T extends Exclude<any, undefined>, TFilterData = voi
}
// cheap
private
getTreeNode
(
location
:
number
[],
node
:
I
MutableTreeNode
<
T
,
TFilterData
>
=
this
.
root
):
IMutable
TreeNode
<
T
,
TFilterData
>
{
private
getTreeNode
(
location
:
number
[],
node
:
I
IndexTreeNode
<
T
,
TFilterData
>
=
this
.
root
):
IIndex
TreeNode
<
T
,
TFilterData
>
{
if
(
!
location
||
location
.
length
===
0
)
{
return
node
;
}
...
...
@@ -539,7 +531,7 @@ export class IndexTreeModel<T extends Exclude<any, undefined>, TFilterData = voi
}
// expensive
private
getTreeNodeWithListIndex
(
location
:
number
[]):
{
node
:
I
Mutable
TreeNode
<
T
,
TFilterData
>
,
listIndex
:
number
,
revealed
:
boolean
,
visible
:
boolean
}
{
private
getTreeNodeWithListIndex
(
location
:
number
[]):
{
node
:
I
Index
TreeNode
<
T
,
TFilterData
>
,
listIndex
:
number
,
revealed
:
boolean
,
visible
:
boolean
}
{
if
(
location
.
length
===
0
)
{
return
{
node
:
this
.
root
,
listIndex
:
-
1
,
revealed
:
true
,
visible
:
false
};
}
...
...
@@ -556,7 +548,7 @@ export class IndexTreeModel<T extends Exclude<any, undefined>, TFilterData = voi
return
{
node
,
listIndex
,
revealed
,
visible
:
visible
&&
node
.
visible
};
}
private
getParentNodeWithListIndex
(
location
:
number
[],
node
:
I
MutableTreeNode
<
T
,
TFilterData
>
=
this
.
root
,
listIndex
:
number
=
0
,
revealed
=
true
,
visible
=
true
):
{
parentNode
:
IMutable
TreeNode
<
T
,
TFilterData
>
;
listIndex
:
number
;
revealed
:
boolean
;
visible
:
boolean
;
}
{
private
getParentNodeWithListIndex
(
location
:
number
[],
node
:
I
IndexTreeNode
<
T
,
TFilterData
>
=
this
.
root
,
listIndex
:
number
=
0
,
revealed
=
true
,
visible
=
true
):
{
parentNode
:
IIndex
TreeNode
<
T
,
TFilterData
>
;
listIndex
:
number
;
revealed
:
boolean
;
visible
:
boolean
;
}
{
const
[
index
,
...
rest
]
=
location
;
if
(
index
<
0
||
index
>
node
.
children
.
length
)
{
...
...
@@ -585,27 +577,24 @@ export class IndexTreeModel<T extends Exclude<any, undefined>, TFilterData = voi
// TODO@joao perf!
getNodeLocation
(
node
:
ITreeNode
<
T
,
TFilterData
>
):
number
[]
{
const
location
:
number
[]
=
[];
let
indexTreeNode
=
node
as
IIndexTreeNode
<
T
,
TFilterData
>
;
// typing woes
while
(
n
ode
.
parent
)
{
location
.
push
(
node
.
parent
.
children
.
indexOf
(
n
ode
));
node
=
n
ode
.
parent
;
while
(
indexTreeN
ode
.
parent
)
{
location
.
push
(
indexTreeNode
.
parent
.
children
.
indexOf
(
indexTreeN
ode
));
indexTreeNode
=
indexTreeN
ode
.
parent
;
}
return
location
.
reverse
();
}
getParentNodeLocation
(
location
:
number
[]):
number
[]
{
if
(
location
.
length
<=
1
)
{
getParentNodeLocation
(
location
:
number
[]):
number
[]
|
undefined
{
if
(
location
.
length
===
0
)
{
return
undefined
;
}
else
if
(
location
.
length
===
1
)
{
return
[];
}
else
{
return
tail2
(
location
)[
0
];
}
return
tail2
(
location
)[
0
];
}
getParentElement
(
location
:
number
[]):
T
{
const
parentLocation
=
this
.
getParentNodeLocation
(
location
);
const
node
=
this
.
getTreeNode
(
parentLocation
);
return
node
.
element
;
}
getFirstElementChild
(
location
:
number
[]):
T
|
undefined
{
...
...
src/vs/base/browser/ui/tree/objectTree.ts
浏览文件 @
4f399951
...
...
@@ -3,13 +3,14 @@
* Licensed under the MIT License. See License.txt in the project root for license information.
*--------------------------------------------------------------------------------------------*/
import
{
I
terator
,
I
Sequence
}
from
'
vs/base/common/iterator
'
;
import
{
ISequence
}
from
'
vs/base/common/iterator
'
;
import
{
AbstractTree
,
IAbstractTreeOptions
}
from
'
vs/base/browser/ui/tree/abstractTree
'
;
import
{
ISpliceable
}
from
'
vs/base/common/sequence
'
;
import
{
ITreeNode
,
ITreeModel
,
ITreeElement
,
ITreeRenderer
,
ITreeSorter
,
ICollapseStateChangeEvent
}
from
'
vs/base/browser/ui/tree/tree
'
;
import
{
ObjectTreeModel
,
IObjectTreeModel
}
from
'
vs/base/browser/ui/tree/objectTreeModel
'
;
import
{
IListVirtualDelegate
}
from
'
vs/base/browser/ui/list/list
'
;
import
{
Event
}
from
'
vs/base/common/event
'
;
import
{
CompressibleObjectTreeModel
,
ElementMapper
,
ICompressedTreeNode
,
ICompressedTreeElement
}
from
'
vs/base/browser/ui/tree/compressedObjectTreeModel
'
;
export
interface
IObjectTreeOptions
<
T
,
TFilterData
=
void
>
extends
IAbstractTreeOptions
<
T
,
TFilterData
>
{
sorter
?:
ITreeSorter
<
T
>
;
...
...
@@ -31,11 +32,8 @@ export class ObjectTree<T extends NonNullable<any>, TFilterData = void> extends
super
(
user
,
container
,
delegate
,
renderers
,
options
);
}
setChildren
(
element
:
T
|
null
,
children
?:
ISequence
<
ITreeElement
<
T
>>
):
Iterator
<
ITreeElement
<
T
|
null
>>
{
return
this
.
model
.
setChildren
(
element
,
children
);
setChildren
(
element
:
T
|
null
,
children
?:
ISequence
<
ITreeElement
<
T
>>
):
void
{
this
.
model
.
setChildren
(
element
,
children
);
}
rerender
(
element
?:
T
):
void
{
...
...
@@ -55,3 +53,113 @@ export class ObjectTree<T extends NonNullable<any>, TFilterData = void> extends
return
new
ObjectTreeModel
(
user
,
view
,
options
);
}
}
interface
ICompressedTreeNodeProvider
<
T
,
TFilterData
>
{
getCompressedTreeNode
(
element
:
T
):
ITreeNode
<
ICompressedTreeNode
<
T
>
,
TFilterData
>
;
}
export
interface
ICompressibleObjectTreeOptions
<
T
,
TFilterData
=
void
>
extends
IObjectTreeOptions
<
T
,
TFilterData
>
{
readonly
elementMapper
?:
ElementMapper
<
T
>
;
}
export
interface
ICompressibleTreeRenderer
<
T
,
TFilterData
=
void
,
TTemplateData
=
void
>
extends
ITreeRenderer
<
T
,
TFilterData
,
TTemplateData
>
{
renderCompressedElements
(
node
:
ITreeNode
<
ICompressedTreeNode
<
T
>
,
TFilterData
>
,
index
:
number
,
templateData
:
TTemplateData
,
height
:
number
|
undefined
):
void
;
disposeCompressedElements
?(
node
:
ITreeNode
<
ICompressedTreeNode
<
T
>
,
TFilterData
>
,
index
:
number
,
templateData
:
TTemplateData
,
height
:
number
|
undefined
):
void
;
}
interface
CompressibleTemplateData
<
T
,
TFilterData
,
TTemplateData
>
{
compressedTreeNode
:
ITreeNode
<
ICompressedTreeNode
<
T
>
,
TFilterData
>
|
undefined
;
readonly
data
:
TTemplateData
;
}
class
CompressibleRenderer
<
T
,
TFilterData
,
TTemplateData
>
implements
ITreeRenderer
<
T
,
TFilterData
,
CompressibleTemplateData
<
T
,
TFilterData
,
TTemplateData
>>
{
readonly
templateId
:
string
;
readonly
onDidChangeTwistieState
:
Event
<
T
>
|
undefined
;
compressedTreeNodeProvider
:
ICompressedTreeNodeProvider
<
T
,
TFilterData
>
;
constructor
(
private
renderer
:
ICompressibleTreeRenderer
<
T
,
TFilterData
,
TTemplateData
>
)
{
this
.
templateId
=
renderer
.
templateId
;
if
(
renderer
.
onDidChangeTwistieState
)
{
this
.
onDidChangeTwistieState
=
renderer
.
onDidChangeTwistieState
;
}
}
renderTemplate
(
container
:
HTMLElement
):
CompressibleTemplateData
<
T
,
TFilterData
,
TTemplateData
>
{
const
data
=
this
.
renderer
.
renderTemplate
(
container
);
return
{
compressedTreeNode
:
undefined
,
data
};
}
renderElement
(
node
:
ITreeNode
<
T
,
TFilterData
>
,
index
:
number
,
templateData
:
CompressibleTemplateData
<
T
,
TFilterData
,
TTemplateData
>
,
height
:
number
|
undefined
):
void
{
const
compressedTreeNode
=
this
.
compressedTreeNodeProvider
.
getCompressedTreeNode
(
node
.
element
);
if
(
compressedTreeNode
.
element
.
elements
.
length
===
1
)
{
templateData
.
compressedTreeNode
=
undefined
;
this
.
renderer
.
renderElement
(
node
,
index
,
templateData
.
data
,
height
);
}
else
{
templateData
.
compressedTreeNode
=
compressedTreeNode
;
this
.
renderer
.
renderCompressedElements
(
compressedTreeNode
,
index
,
templateData
.
data
,
height
);
}
}
disposeElement
(
node
:
ITreeNode
<
T
,
TFilterData
>
,
index
:
number
,
templateData
:
CompressibleTemplateData
<
T
,
TFilterData
,
TTemplateData
>
,
height
:
number
|
undefined
):
void
{
if
(
templateData
.
compressedTreeNode
)
{
if
(
this
.
renderer
.
disposeCompressedElements
)
{
this
.
renderer
.
disposeCompressedElements
(
templateData
.
compressedTreeNode
,
index
,
templateData
.
data
,
height
);
}
}
else
{
if
(
this
.
renderer
.
disposeElement
)
{
this
.
renderer
.
disposeElement
(
node
,
index
,
templateData
.
data
,
height
);
}
}
}
disposeTemplate
(
templateData
:
CompressibleTemplateData
<
T
,
TFilterData
,
TTemplateData
>
):
void
{
this
.
renderer
.
disposeTemplate
(
templateData
.
data
);
}
renderTwistie
?(
element
:
T
,
twistieElement
:
HTMLElement
):
void
{
if
(
this
.
renderer
.
renderTwistie
)
{
this
.
renderer
.
renderTwistie
(
element
,
twistieElement
);
}
}
}
export
class
CompressibleObjectTree
<
T
extends
NonNullable
<
any
>
,
TFilterData
=
void
>
extends
ObjectTree
<
T
,
TFilterData
>
{
protected
model
:
CompressibleObjectTreeModel
<
T
,
TFilterData
>
;
constructor
(
user
:
string
,
container
:
HTMLElement
,
delegate
:
IListVirtualDelegate
<
T
>
,
renderers
:
ICompressibleTreeRenderer
<
T
,
TFilterData
,
any
>
[],
options
:
IObjectTreeOptions
<
T
,
TFilterData
>
=
{}
)
{
const
compressibleRenderers
=
renderers
.
map
(
r
=>
new
CompressibleRenderer
(
r
));
super
(
user
,
container
,
delegate
,
compressibleRenderers
,
options
);
compressibleRenderers
.
forEach
(
r
=>
r
.
compressedTreeNodeProvider
=
this
);
}
setChildren
(
element
:
T
|
null
,
children
?:
ISequence
<
ICompressedTreeElement
<
T
>>
):
void
{
this
.
model
.
setChildren
(
element
,
children
);
}
protected
createModel
(
user
:
string
,
view
:
ISpliceable
<
ITreeNode
<
T
,
TFilterData
>>
,
options
:
ICompressibleObjectTreeOptions
<
T
,
TFilterData
>
):
ITreeModel
<
T
|
null
,
TFilterData
,
T
|
null
>
{
return
new
CompressibleObjectTreeModel
(
user
,
view
,
options
);
}
isCompressionEnabled
():
boolean
{
return
this
.
model
.
isCompressionEnabled
();
}
setCompressionEnabled
(
enabled
:
boolean
):
void
{
this
.
model
.
setCompressionEnabled
(
enabled
);
}
getCompressedTreeNode
(
element
:
T
):
ITreeNode
<
ICompressedTreeNode
<
T
>
,
TFilterData
>
{
return
this
.
model
.
getCompressedTreeNode
(
element
)
!
;
}
}
src/vs/base/browser/ui/tree/objectTreeModel.ts
浏览文件 @
4f399951
...
...
@@ -13,7 +13,7 @@ import { IIdentityProvider } from 'vs/base/browser/ui/list/list';
export
type
ITreeNodeCallback
<
T
,
TFilterData
>
=
(
node
:
ITreeNode
<
T
,
TFilterData
>
)
=>
void
;
export
interface
IObjectTreeModel
<
T
extends
NonNullable
<
any
>
,
TFilterData
extends
NonNullable
<
any
>
=
void
>
extends
ITreeModel
<
T
|
null
,
TFilterData
,
T
|
null
>
{
setChildren
(
element
:
T
|
null
,
children
:
ISequence
<
ITreeElement
<
T
>>
|
undefined
):
Iterator
<
ITreeElement
<
T
>>
;
setChildren
(
element
:
T
|
null
,
children
:
ISequence
<
ITreeElement
<
T
>>
|
undefined
):
void
;
resort
(
element
?:
T
|
null
,
recursive
?:
boolean
):
void
;
}
...
...
@@ -64,9 +64,9 @@ export class ObjectTreeModel<T extends NonNullable<any>, TFilterData extends Non
children
:
ISequence
<
ITreeElement
<
T
>>
|
undefined
,
onDidCreateNode
?:
ITreeNodeCallback
<
T
,
TFilterData
>
,
onDidDeleteNode
?:
ITreeNodeCallback
<
T
,
TFilterData
>
):
Iterator
<
ITreeElement
<
T
>>
{
):
void
{
const
location
=
this
.
getElementLocation
(
element
);
return
this
.
_setChildren
(
location
,
this
.
preserveCollapseState
(
children
),
onDidCreateNode
,
onDidDeleteNode
);
this
.
_setChildren
(
location
,
this
.
preserveCollapseState
(
children
),
onDidCreateNode
,
onDidDeleteNode
);
}
private
_setChildren
(
...
...
@@ -74,7 +74,7 @@ export class ObjectTreeModel<T extends NonNullable<any>, TFilterData extends Non
children
:
ISequence
<
ITreeElement
<
T
>>
|
undefined
,
onDidCreateNode
?:
ITreeNodeCallback
<
T
,
TFilterData
>
,
onDidDeleteNode
?:
ITreeNodeCallback
<
T
,
TFilterData
>
):
Iterator
<
ITreeElement
<
T
>>
{
):
void
{
const
insertedElements
=
new
Set
<
T
|
null
>
();
const
insertedElementIds
=
new
Set
<
string
>
();
...
...
@@ -110,15 +110,13 @@ export class ObjectTreeModel<T extends NonNullable<any>, TFilterData extends Non
}
};
const
result
=
this
.
model
.
splice
(
this
.
model
.
splice
(
[...
location
,
0
],
Number
.
MAX_VALUE
,
children
,
_onDidCreateNode
,
_onDidDeleteNode
);
return
result
as
Iterator
<
ITreeElement
<
T
>>
;
}
private
preserveCollapseState
(
elements
:
ISequence
<
ITreeElement
<
T
>>
|
undefined
):
ISequence
<
ITreeElement
<
T
>>
{
...
...
@@ -186,11 +184,6 @@ export class ObjectTreeModel<T extends NonNullable<any>, TFilterData extends Non
}));
}
getParentElement
(
ref
:
T
|
null
=
null
):
T
|
null
{
const
location
=
this
.
getElementLocation
(
ref
);
return
this
.
model
.
getParentElement
(
location
);
}
getFirstElementChild
(
ref
:
T
|
null
=
null
):
T
|
null
|
undefined
{
const
location
=
this
.
getElementLocation
(
ref
);
return
this
.
model
.
getFirstElementChild
(
location
);
...
...
@@ -263,13 +256,12 @@ export class ObjectTreeModel<T extends NonNullable<any>, TFilterData extends Non
throw
new
TreeError
(
this
.
user
,
`Invalid getParentNodeLocation call`
);
}
const
node
=
this
.
nodes
.
get
(
element
);
if
(
!
node
)
{
throw
new
TreeError
(
this
.
user
,
`Tree element not found:
${
element
}
`
);
}
const
node
=
this
.
nodes
.
get
(
element
)
!
;
const
location
=
this
.
model
.
getNodeLocation
(
node
);
const
parentLocation
=
this
.
model
.
getParentNodeLocation
(
location
);
const
parent
=
this
.
model
.
getNode
(
parentLocation
);
return
node
.
parent
!
.
element
;
return
parent
.
element
;
}
private
getElementLocation
(
element
:
T
|
null
):
number
[]
{
...
...
src/vs/base/browser/ui/tree/tree.ts
浏览文件 @
4f399951
...
...
@@ -81,7 +81,6 @@ export interface ITreeElement<T> {
export
interface
ITreeNode
<
T
,
TFilterData
=
void
>
{
readonly
element
:
T
;
readonly
parent
:
ITreeNode
<
T
,
TFilterData
>
|
undefined
;
readonly
children
:
ITreeNode
<
T
,
TFilterData
>
[];
readonly
depth
:
number
;
readonly
visibleChildrenCount
:
number
;
...
...
@@ -113,9 +112,8 @@ export interface ITreeModel<T, TFilterData, TRef> {
getListRenderCount
(
location
:
TRef
):
number
;
getNode
(
location
?:
TRef
):
ITreeNode
<
T
,
any
>
;
getNodeLocation
(
node
:
ITreeNode
<
T
,
any
>
):
TRef
;
getParentNodeLocation
(
location
:
TRef
):
TRef
;
getParentNodeLocation
(
location
:
TRef
):
TRef
|
undefined
;
getParentElement
(
location
:
TRef
):
T
;
getFirstElementChild
(
location
:
TRef
):
T
|
undefined
;
getLastElementAncestor
(
location
?:
TRef
):
T
|
undefined
;
...
...
@@ -160,7 +158,6 @@ export interface ITreeContextMenuEvent<T> {
export
interface
ITreeNavigator
<
T
>
{
current
():
T
|
null
;
previous
():
T
|
null
;
parent
():
T
|
null
;
first
():
T
|
null
;
last
():
T
|
null
;
next
():
T
|
null
;
...
...
@@ -202,3 +199,21 @@ export class TreeError extends Error {
super
(
`TreeError [
${
user
}
]
${
message
}
`
);
}
}
export
class
WeakMapper
<
K
extends
object
,
V
>
{
constructor
(
private
fn
:
(
k
:
K
)
=>
V
)
{
}
private
_map
=
new
WeakMap
<
K
,
V
>
();
map
(
key
:
K
):
V
{
let
result
=
this
.
_map
.
get
(
key
);
if
(
!
result
)
{
result
=
this
.
fn
(
key
);
this
.
_map
.
set
(
key
,
result
);
}
return
result
;
}
}
src/vs/base/test/browser/ui/tree/compressedObjectTreeModel.test.ts
浏览文件 @
4f399951
...
...
@@ -4,7 +4,7 @@
*--------------------------------------------------------------------------------------------*/
import
*
as
assert
from
'
assert
'
;
import
{
compress
,
ICompressedTreeElement
,
ICompressedTreeNode
,
decompress
,
CompressedTreeModel
}
from
'
vs/base/browser/ui/tree/compressedObjectTreeModel
'
;
import
{
compress
,
ICompressedTreeElement
,
ICompressedTreeNode
,
decompress
,
Compressed
Object
TreeModel
}
from
'
vs/base/browser/ui/tree/compressedObjectTreeModel
'
;
import
{
Iterator
}
from
'
vs/base/common/iterator
'
;
import
{
ITreeNode
}
from
'
vs/base/browser/ui/tree/tree
'
;
import
{
ISpliceable
}
from
'
vs/base/common/sequence
'
;
...
...
@@ -305,7 +305,7 @@ suite('CompressedObjectTree', function () {
test
(
'
ctor
'
,
()
=>
{
const
list
:
ITreeNode
<
ICompressedTreeNode
<
number
>>
[]
=
[];
const
model
=
new
CompressedTreeModel
<
number
>
(
'
test
'
,
toSpliceable
(
list
));
const
model
=
new
Compressed
Object
TreeModel
<
number
>
(
'
test
'
,
toSpliceable
(
list
));
assert
(
model
);
assert
.
equal
(
list
.
length
,
0
);
assert
.
equal
(
model
.
size
,
0
);
...
...
@@ -313,7 +313,7 @@ suite('CompressedObjectTree', function () {
test
(
'
flat
'
,
()
=>
{
const
list
:
ITreeNode
<
ICompressedTreeNode
<
number
>>
[]
=
[];
const
model
=
new
CompressedTreeModel
<
number
>
(
'
test
'
,
toSpliceable
(
list
));
const
model
=
new
Compressed
Object
TreeModel
<
number
>
(
'
test
'
,
toSpliceable
(
list
));
model
.
setChildren
(
null
,
Iterator
.
fromArray
([
{
element
:
0
},
...
...
@@ -340,7 +340,7 @@ suite('CompressedObjectTree', function () {
test
(
'
nested
'
,
()
=>
{
const
list
:
ITreeNode
<
ICompressedTreeNode
<
number
>>
[]
=
[];
const
model
=
new
CompressedTreeModel
<
number
>
(
'
test
'
,
toSpliceable
(
list
));
const
model
=
new
Compressed
Object
TreeModel
<
number
>
(
'
test
'
,
toSpliceable
(
list
));
model
.
setChildren
(
null
,
Iterator
.
fromArray
([
{
...
...
@@ -376,7 +376,7 @@ suite('CompressedObjectTree', function () {
test
(
'
compressed
'
,
()
=>
{
const
list
:
ITreeNode
<
ICompressedTreeNode
<
number
>>
[]
=
[];
const
model
=
new
CompressedTreeModel
<
number
>
(
'
test
'
,
toSpliceable
(
list
));
const
model
=
new
Compressed
Object
TreeModel
<
number
>
(
'
test
'
,
toSpliceable
(
list
));
model
.
setChildren
(
null
,
Iterator
.
fromArray
([
{
...
...
src/vs/base/test/browser/ui/tree/indexTreeModel.test.ts
浏览文件 @
4f399951
...
...
@@ -7,7 +7,7 @@ import * as assert from 'assert';
import
{
ITreeNode
,
ITreeFilter
,
TreeVisibility
}
from
'
vs/base/browser/ui/tree/tree
'
;
import
{
ISpliceable
}
from
'
vs/base/common/sequence
'
;
import
{
Iterator
}
from
'
vs/base/common/iterator
'
;
import
{
IndexTreeModel
}
from
'
vs/base/browser/ui/tree/indexTreeModel
'
;
import
{
IndexTreeModel
,
IIndexTreeNode
}
from
'
vs/base/browser/ui/tree/indexTreeModel
'
;
function
toSpliceable
<
T
>
(
arr
:
T
[]):
ISpliceable
<
T
>
{
return
{
...
...
@@ -637,7 +637,7 @@ suite('IndexTreeModel', function () {
suite
(
'
getNodeLocation
'
,
function
()
{
test
(
'
simple
'
,
function
()
{
const
list
:
ITreeNode
<
number
>
[]
=
[];
const
list
:
I
Index
TreeNode
<
number
>
[]
=
[];
const
model
=
new
IndexTreeModel
<
number
>
(
'
test
'
,
toSpliceable
(
list
),
-
1
);
model
.
splice
([
0
],
0
,
Iterator
.
fromArray
([
...
...
@@ -661,7 +661,7 @@ suite('IndexTreeModel', function () {
});
test
(
'
with filter
'
,
function
()
{
const
list
:
ITreeNode
<
number
>
[]
=
[];
const
list
:
I
Index
TreeNode
<
number
>
[]
=
[];
const
filter
=
new
class
implements
ITreeFilter
<
number
>
{
filter
(
element
:
number
):
TreeVisibility
{
return
element
%
2
===
0
?
TreeVisibility
.
Visible
:
TreeVisibility
.
Hidden
;
...
...
src/vs/base/test/browser/ui/tree/objectTree.test.ts
浏览文件 @
4f399951
...
...
@@ -6,8 +6,9 @@
import
*
as
assert
from
'
assert
'
;
import
{
ITreeNode
,
ITreeRenderer
}
from
'
vs/base/browser/ui/tree/tree
'
;
import
{
IListVirtualDelegate
,
IIdentityProvider
}
from
'
vs/base/browser/ui/list/list
'
;
import
{
ObjectTree
}
from
'
vs/base/browser/ui/tree/objectTree
'
;
import
{
ObjectTree
,
CompressibleObjectTree
,
ICompressibleTreeRenderer
}
from
'
vs/base/browser/ui/tree/objectTree
'
;
import
{
Iterator
}
from
'
vs/base/common/iterator
'
;
import
{
ICompressedTreeNode
}
from
'
vs/base/browser/ui/tree/compressedObjectTreeModel
'
;
suite
(
'
ObjectTree
'
,
function
()
{
suite
(
'
TreeNavigator
'
,
function
()
{
...
...
@@ -81,8 +82,6 @@ suite('ObjectTree', function () {
assert
.
equal
(
navigator
.
previous
(),
null
);
assert
.
equal
(
navigator
.
next
(),
0
);
assert
.
equal
(
navigator
.
next
(),
10
);
assert
.
equal
(
navigator
.
parent
(),
0
);
assert
.
equal
(
navigator
.
parent
(),
null
);
assert
.
equal
(
navigator
.
first
(),
0
);
assert
.
equal
(
navigator
.
last
(),
2
);
});
...
...
@@ -112,7 +111,6 @@ suite('ObjectTree', function () {
assert
.
equal
(
navigator
.
previous
(),
0
);
assert
.
equal
(
navigator
.
previous
(),
null
);
assert
.
equal
(
navigator
.
next
(),
0
);
assert
.
equal
(
navigator
.
parent
(),
null
);
assert
.
equal
(
navigator
.
first
(),
0
);
assert
.
equal
(
navigator
.
last
(),
2
);
});
...
...
@@ -147,8 +145,6 @@ suite('ObjectTree', function () {
assert
.
equal
(
navigator
.
previous
(),
null
);
assert
.
equal
(
navigator
.
next
(),
0
);
assert
.
equal
(
navigator
.
next
(),
10
);
assert
.
equal
(
navigator
.
parent
(),
0
);
assert
.
equal
(
navigator
.
parent
(),
null
);
assert
.
equal
(
navigator
.
first
(),
0
);
assert
.
equal
(
navigator
.
last
(),
2
);
});
...
...
@@ -180,8 +176,6 @@ suite('ObjectTree', function () {
assert
.
equal
(
navigator
.
previous
(),
null
);
assert
.
equal
(
navigator
.
next
(),
0
);
assert
.
equal
(
navigator
.
next
(),
10
);
assert
.
equal
(
navigator
.
parent
(),
0
);
assert
.
equal
(
navigator
.
parent
(),
null
);
assert
.
equal
(
navigator
.
first
(),
0
);
assert
.
equal
(
navigator
.
last
(),
2
);
});
...
...
@@ -225,3 +219,160 @@ suite('ObjectTree', function () {
assert
.
deepStrictEqual
(
tree
.
getFocus
(),
[
101
]);
});
});
function
toArray
(
list
:
NodeList
):
Node
[]
{
const
result
:
Node
[]
=
[];
list
.
forEach
(
node
=>
result
.
push
(
node
));
return
result
;
}
suite
(
'
CompressibleObjectTree
'
,
function
()
{
class
Delegate
implements
IListVirtualDelegate
<
number
>
{
getHeight
()
{
return
20
;
}
getTemplateId
():
string
{
return
'
default
'
;
}
}
class
Renderer
implements
ICompressibleTreeRenderer
<
number
,
void
,
HTMLElement
>
{
readonly
templateId
=
'
default
'
;
renderTemplate
(
container
:
HTMLElement
):
HTMLElement
{
return
container
;
}
renderElement
(
node
:
ITreeNode
<
number
,
void
>
,
_
:
number
,
templateData
:
HTMLElement
):
void
{
templateData
.
textContent
=
`
${
node
.
element
}
`
;
}
renderCompressedElements
(
node
:
ITreeNode
<
ICompressedTreeNode
<
number
>
,
void
>
,
_
:
number
,
templateData
:
HTMLElement
):
void
{
templateData
.
textContent
=
`
${
node
.
element
.
elements
.
join
(
'
/
'
)}
`
;
}
disposeTemplate
():
void
{
}
}
test
(
'
empty
'
,
function
()
{
const
container
=
document
.
createElement
(
'
div
'
);
container
.
style
.
width
=
'
200px
'
;
container
.
style
.
height
=
'
200px
'
;
const
tree
=
new
CompressibleObjectTree
<
number
>
(
'
test
'
,
container
,
new
Delegate
(),
[
new
Renderer
()]);
tree
.
layout
(
200
);
const
rows
=
toArray
(
container
.
querySelectorAll
(
'
.monaco-tl-contents
'
));
assert
.
equal
(
rows
.
length
,
0
);
});
test
(
'
simple
'
,
function
()
{
const
container
=
document
.
createElement
(
'
div
'
);
container
.
style
.
width
=
'
200px
'
;
container
.
style
.
height
=
'
200px
'
;
const
tree
=
new
CompressibleObjectTree
<
number
>
(
'
test
'
,
container
,
new
Delegate
(),
[
new
Renderer
()]);
tree
.
layout
(
200
);
tree
.
setChildren
(
null
,
[
{
element
:
0
,
children
:
[
{
element
:
10
},
{
element
:
11
},
{
element
:
12
},
]
},
{
element
:
1
},
{
element
:
2
}
]);
const
rows
=
toArray
(
container
.
querySelectorAll
(
'
.monaco-tl-contents
'
)).
map
(
row
=>
row
.
textContent
);
assert
.
deepEqual
(
rows
,
[
'
0
'
,
'
10
'
,
'
11
'
,
'
12
'
,
'
1
'
,
'
2
'
]);
});
test
(
'
compressed
'
,
()
=>
{
const
container
=
document
.
createElement
(
'
div
'
);
container
.
style
.
width
=
'
200px
'
;
container
.
style
.
height
=
'
200px
'
;
const
tree
=
new
CompressibleObjectTree
<
number
>
(
'
test
'
,
container
,
new
Delegate
(),
[
new
Renderer
()]);
tree
.
layout
(
200
);
tree
.
setChildren
(
null
,
Iterator
.
fromArray
([
{
element
:
1
,
children
:
Iterator
.
fromArray
([{
element
:
11
,
children
:
Iterator
.
fromArray
([{
element
:
111
,
children
:
Iterator
.
fromArray
([
{
element
:
1111
},
{
element
:
1112
},
{
element
:
1113
},
])
}])
}])
}
]));
let
rows
=
toArray
(
container
.
querySelectorAll
(
'
.monaco-tl-contents
'
)).
map
(
row
=>
row
.
textContent
);
assert
.
deepEqual
(
rows
,
[
'
1/11/111
'
,
'
1111
'
,
'
1112
'
,
'
1113
'
]);
tree
.
setChildren
(
11
,
Iterator
.
fromArray
([
{
element
:
111
},
{
element
:
112
},
{
element
:
113
},
]));
rows
=
toArray
(
container
.
querySelectorAll
(
'
.monaco-tl-contents
'
)).
map
(
row
=>
row
.
textContent
);
assert
.
deepEqual
(
rows
,
[
'
1/11
'
,
'
111
'
,
'
112
'
,
'
113
'
]);
tree
.
setChildren
(
113
,
Iterator
.
fromArray
([
{
element
:
1131
}
]));
rows
=
toArray
(
container
.
querySelectorAll
(
'
.monaco-tl-contents
'
)).
map
(
row
=>
row
.
textContent
);
assert
.
deepEqual
(
rows
,
[
'
1/11
'
,
'
111
'
,
'
112
'
,
'
113/1131
'
]);
tree
.
setChildren
(
1131
,
Iterator
.
fromArray
([
{
element
:
1132
}
]));
rows
=
toArray
(
container
.
querySelectorAll
(
'
.monaco-tl-contents
'
)).
map
(
row
=>
row
.
textContent
);
assert
.
deepEqual
(
rows
,
[
'
1/11
'
,
'
111
'
,
'
112
'
,
'
113/1131/1132
'
]);
tree
.
setChildren
(
1131
,
Iterator
.
fromArray
([
{
element
:
1132
},
{
element
:
1133
},
]));
rows
=
toArray
(
container
.
querySelectorAll
(
'
.monaco-tl-contents
'
)).
map
(
row
=>
row
.
textContent
);
assert
.
deepEqual
(
rows
,
[
'
1/11
'
,
'
111
'
,
'
112
'
,
'
113/1131
'
,
'
1132
'
,
'
1133
'
]);
});
test
(
'
enableCompression
'
,
()
=>
{
const
container
=
document
.
createElement
(
'
div
'
);
container
.
style
.
width
=
'
200px
'
;
container
.
style
.
height
=
'
200px
'
;
const
tree
=
new
CompressibleObjectTree
<
number
>
(
'
test
'
,
container
,
new
Delegate
(),
[
new
Renderer
()]);
tree
.
layout
(
200
);
assert
.
equal
(
tree
.
isCompressionEnabled
(),
true
);
tree
.
setChildren
(
null
,
Iterator
.
fromArray
([
{
element
:
1
,
children
:
Iterator
.
fromArray
([{
element
:
11
,
children
:
Iterator
.
fromArray
([{
element
:
111
,
children
:
Iterator
.
fromArray
([
{
element
:
1111
},
{
element
:
1112
},
{
element
:
1113
},
])
}])
}])
}
]));
let
rows
=
toArray
(
container
.
querySelectorAll
(
'
.monaco-tl-contents
'
)).
map
(
row
=>
row
.
textContent
);
assert
.
deepEqual
(
rows
,
[
'
1/11/111
'
,
'
1111
'
,
'
1112
'
,
'
1113
'
]);
tree
.
setCompressionEnabled
(
false
);
rows
=
toArray
(
container
.
querySelectorAll
(
'
.monaco-tl-contents
'
)).
map
(
row
=>
row
.
textContent
);
assert
.
deepEqual
(
rows
,
[
'
1
'
,
'
11
'
,
'
111
'
,
'
1111
'
,
'
1112
'
,
'
1113
'
]);
tree
.
setCompressionEnabled
(
true
);
rows
=
toArray
(
container
.
querySelectorAll
(
'
.monaco-tl-contents
'
)).
map
(
row
=>
row
.
textContent
);
assert
.
deepEqual
(
rows
,
[
'
1/11/111
'
,
'
1111
'
,
'
1112
'
,
'
1113
'
]);
});
});
src/vs/platform/list/browser/listService.ts
浏览文件 @
4f399951
...
...
@@ -25,9 +25,9 @@ import { Registry } from 'vs/platform/registry/common/platform';
import
{
attachListStyler
,
computeStyles
,
defaultListStyles
}
from
'
vs/platform/theme/common/styler
'
;
import
{
IThemeService
}
from
'
vs/platform/theme/common/themeService
'
;
import
{
InputFocusedContextKey
}
from
'
vs/platform/contextkey/common/contextkeys
'
;
import
{
ObjectTree
,
IObjectTreeOptions
}
from
'
vs/base/browser/ui/tree/objectTree
'
;
import
{
ObjectTree
,
IObjectTreeOptions
,
ICompressibleTreeRenderer
}
from
'
vs/base/browser/ui/tree/objectTree
'
;
import
{
ITreeEvent
,
ITreeRenderer
,
IAsyncDataSource
,
IDataSource
,
ITreeMouseEvent
}
from
'
vs/base/browser/ui/tree/tree
'
;
import
{
AsyncDataTree
,
IAsyncDataTreeOptions
}
from
'
vs/base/browser/ui/tree/asyncDataTree
'
;
import
{
AsyncDataTree
,
IAsyncDataTreeOptions
,
CompressibleAsyncDataTree
,
ITreeCompressionDelegate
}
from
'
vs/base/browser/ui/tree/asyncDataTree
'
;
import
{
DataTree
,
IDataTreeOptions
}
from
'
vs/base/browser/ui/tree/dataTree
'
;
import
{
IKeyboardNavigationEventFilter
,
IAbstractTreeOptions
,
RenderIndentGuides
}
from
'
vs/base/browser/ui/tree/abstractTree
'
;
import
{
IAccessibilityService
,
AccessibilitySupport
}
from
'
vs/platform/accessibility/common/accessibility
'
;
...
...
@@ -681,7 +681,7 @@ export class TreeResourceNavigator2<T, TFilterData> extends Disposable {
readonly
onDidOpenResource
:
Event
<
IOpenEvent
<
T
|
null
>>
=
this
.
_onDidOpenResource
.
event
;
constructor
(
private
tree
:
WorkbenchObjectTree
<
T
,
TFilterData
>
|
WorkbenchDataTree
<
any
,
T
,
TFilterData
>
|
WorkbenchAsyncDataTree
<
any
,
T
,
TFilterData
>
,
private
tree
:
WorkbenchObjectTree
<
T
,
TFilterData
>
|
WorkbenchDataTree
<
any
,
T
,
TFilterData
>
|
WorkbenchAsyncDataTree
<
any
,
T
,
TFilterData
>
|
WorkbenchCompressibleAsyncDataTree
<
any
,
T
,
TFilterData
>
,
options
?:
IResourceResultsNavigationOptions2
)
{
super
();
...
...
@@ -863,6 +863,35 @@ export class WorkbenchAsyncDataTree<TInput, T, TFilterData = void> extends Async
}
}
export
class
WorkbenchCompressibleAsyncDataTree
<
TInput
,
T
,
TFilterData
=
void
>
extends
CompressibleAsyncDataTree
<
TInput
,
T
,
TFilterData
>
{
private
internals
:
WorkbenchTreeInternals
<
TInput
,
T
,
TFilterData
>
;
get
contextKeyService
():
IContextKeyService
{
return
this
.
internals
.
contextKeyService
;
}
get
useAltAsMultipleSelectionModifier
():
boolean
{
return
this
.
internals
.
useAltAsMultipleSelectionModifier
;
}
constructor
(
user
:
string
,
container
:
HTMLElement
,
virtualDelegate
:
IListVirtualDelegate
<
T
>
,
compressionDelegate
:
ITreeCompressionDelegate
<
T
>
,
renderers
:
ICompressibleTreeRenderer
<
T
,
TFilterData
,
any
>
[],
dataSource
:
IAsyncDataSource
<
TInput
,
T
>
,
options
:
IAsyncDataTreeOptions
<
T
,
TFilterData
>
,
@
IContextKeyService
contextKeyService
:
IContextKeyService
,
@
IListService
listService
:
IListService
,
@
IThemeService
themeService
:
IThemeService
,
@
IConfigurationService
configurationService
:
IConfigurationService
,
@
IKeybindingService
keybindingService
:
IKeybindingService
,
@
IAccessibilityService
accessibilityService
:
IAccessibilityService
)
{
const
{
options
:
treeOptions
,
getAutomaticKeyboardNavigation
,
disposable
}
=
workbenchTreeDataPreamble
(
container
,
options
,
contextKeyService
,
themeService
,
configurationService
,
keybindingService
,
accessibilityService
);
super
(
user
,
container
,
virtualDelegate
,
compressionDelegate
,
renderers
,
dataSource
,
treeOptions
);
this
.
disposables
.
push
(
disposable
);
this
.
internals
=
new
WorkbenchTreeInternals
(
this
,
treeOptions
,
getAutomaticKeyboardNavigation
,
contextKeyService
,
listService
,
themeService
,
configurationService
,
accessibilityService
);
this
.
disposables
.
push
(
this
.
internals
);
}
}
function
workbenchTreeDataPreamble
<
T
,
TFilterData
,
TOptions
extends
IAbstractTreeOptions
<
T
,
TFilterData
>
|
IAsyncDataTreeOptions
<
T
,
TFilterData
>>
(
container
:
HTMLElement
,
options
:
TOptions
,
...
...
@@ -928,7 +957,7 @@ class WorkbenchTreeInternals<TInput, T, TFilterData> {
private
disposables
:
IDisposable
[]
=
[];
constructor
(
tree
:
WorkbenchObjectTree
<
T
,
TFilterData
>
|
WorkbenchDataTree
<
TInput
,
T
,
TFilterData
>
|
WorkbenchAsyncDataTree
<
TInput
,
T
,
TFilterData
>
,
tree
:
WorkbenchObjectTree
<
T
,
TFilterData
>
|
WorkbenchDataTree
<
TInput
,
T
,
TFilterData
>
|
WorkbenchAsyncDataTree
<
TInput
,
T
,
TFilterData
>
|
WorkbenchCompressibleAsyncDataTree
<
TInput
,
T
,
TFilterData
>
,
options
:
IAbstractTreeOptions
<
T
,
TFilterData
>
|
IAsyncDataTreeOptions
<
T
,
TFilterData
>
,
getAutomaticKeyboardNavigation
:
()
=>
boolean
|
undefined
,
@
IContextKeyService
contextKeyService
:
IContextKeyService
,
...
...
src/vs/workbench/browser/actions/listCommands.ts
浏览文件 @
4f399951
...
...
@@ -701,14 +701,7 @@ KeybindingsRegistry.registerCommandAndKeybindingRule({
if
(
!
start
)
{
scope
=
undefined
;
}
else
{
const
selectedNode
=
tree
.
getNode
(
start
);
const
parentNode
=
selectedNode
.
parent
;
if
(
!
parentNode
||
!
parentNode
.
parent
)
{
// root
scope
=
undefined
;
}
else
{
scope
=
parentNode
.
element
;
}
scope
=
tree
.
getParentElement
(
start
);
}
const
newSelection
:
unknown
[]
=
[];
...
...
src/vs/workbench/contrib/search/browser/searchActions.ts
浏览文件 @
4f399951
...
...
@@ -5,7 +5,6 @@
import
*
as
DOM
from
'
vs/base/browser/dom
'
;
import
{
Action
}
from
'
vs/base/common/actions
'
;
import
{
INavigator
}
from
'
vs/base/common/iterator
'
;
import
{
createKeybinding
,
ResolvedKeybinding
}
from
'
vs/base/common/keyCodes
'
;
import
{
isWindows
,
OS
}
from
'
vs/base/common/platform
'
;
import
{
repeat
}
from
'
vs/base/common/strings
'
;
...
...
@@ -29,6 +28,7 @@ import { ISearchHistoryService } from 'vs/workbench/contrib/search/common/search
import
{
IViewletService
}
from
'
vs/workbench/services/viewlet/browser/viewlet
'
;
import
{
SearchViewlet
}
from
'
vs/workbench/contrib/search/browser/searchViewlet
'
;
import
{
SearchPanel
}
from
'
vs/workbench/contrib/search/browser/searchPanel
'
;
import
{
ITreeNavigator
}
from
'
vs/base/browser/ui/tree/tree
'
;
export
function
isSearchViewFocused
(
viewletService
:
IViewletService
,
panelService
:
IPanelService
):
boolean
{
const
searchView
=
getSearchView
(
viewletService
,
panelService
);
...
...
@@ -447,7 +447,7 @@ export abstract class AbstractSearchAndReplaceAction extends Action {
}
getNextElementAfterRemoved
(
viewer
:
WorkbenchObjectTree
<
RenderableMatch
>
,
element
:
RenderableMatch
):
RenderableMatch
{
const
navigator
:
INavigator
<
any
>
=
viewer
.
navigate
(
element
);
const
navigator
:
I
Tree
Navigator
<
any
>
=
viewer
.
navigate
(
element
);
if
(
element
instanceof
FolderMatch
)
{
while
(
!!
navigator
.
next
()
&&
!
(
navigator
.
current
()
instanceof
FolderMatch
))
{
}
}
else
if
(
element
instanceof
FileMatch
)
{
...
...
@@ -461,7 +461,7 @@ export abstract class AbstractSearchAndReplaceAction extends Action {
}
getPreviousElementAfterRemoved
(
viewer
:
WorkbenchObjectTree
<
RenderableMatch
>
,
element
:
RenderableMatch
):
RenderableMatch
{
const
navigator
:
INavigator
<
any
>
=
viewer
.
navigate
(
element
);
const
navigator
:
I
Tree
Navigator
<
any
>
=
viewer
.
navigate
(
element
);
let
previousElement
=
navigator
.
previous
();
// Hence take the previous element.
...
...
@@ -613,7 +613,7 @@ export class ReplaceAction extends AbstractSearchAndReplaceAction {
}
private
getElementToFocusAfterReplace
():
Match
{
const
navigator
:
INavigator
<
any
>
=
this
.
viewer
.
navigate
();
const
navigator
:
I
Tree
Navigator
<
any
>
=
this
.
viewer
.
navigate
();
let
fileMatched
=
false
;
let
elementToFocus
:
any
=
null
;
do
{
...
...
src/vs/workbench/contrib/search/test/browser/mockSearchTree.ts
浏览文件 @
4f399951
...
...
@@ -68,10 +68,6 @@ class ArrayNavigator<T> implements ITreeNavigator<T> {
return
this
.
elements
[
--
this
.
index
];
}
parent
():
T
|
null
{
throw
new
Error
(
'
not implemented
'
);
}
first
():
T
|
null
{
this
.
index
=
0
;
return
this
.
elements
[
this
.
index
];
...
...
test/tree/public/index.html
浏览文件 @
4f399951
...
...
@@ -44,7 +44,7 @@
require
.
config
({
baseUrl
:
'
/static
'
});
require
([
'
vs/base/browser/ui/tree/indexTree
'
,
'
vs/base/browser/ui/tree/
compressedObjectTree
'
,
'
vs/base/browser/ui/tree/asyncDataTree
'
,
'
vs/base/browser/ui/tree/dataTree
'
,
'
vs/base/browser/ui/tree/tree
'
,
'
vs/base/common/iterator
'
],
({
IndexTree
},
{
Compressed
ObjectTree
},
{
AsyncDataTree
},
{
DataTree
},
{
TreeVisibility
},
{
iter
})
=>
{
require
([
'
vs/base/browser/ui/tree/indexTree
'
,
'
vs/base/browser/ui/tree/
objectTree
'
,
'
vs/base/browser/ui/tree/asyncDataTree
'
,
'
vs/base/browser/ui/tree/dataTree
'
,
'
vs/base/browser/ui/tree/tree
'
,
'
vs/base/common/iterator
'
],
({
IndexTree
},
{
Compressible
ObjectTree
},
{
AsyncDataTree
},
{
DataTree
},
{
TreeVisibility
},
{
iter
})
=>
{
function
createIndexTree
(
opts
)
{
opts
=
opts
||
{};
...
...
@@ -95,7 +95,7 @@
}
};
const
tree
=
new
IndexTree
(
container
,
delegate
,
[
renderer
],
null
,
{
...
opts
,
filter
:
treeFilter
,
setRowLineHeight
:
false
});
const
tree
=
new
IndexTree
(
'
test
'
,
container
,
delegate
,
[
renderer
],
null
,
{
...
opts
,
filter
:
treeFilter
,
setRowLineHeight
:
false
});
return
{
tree
,
treeFilter
};
}
...
...
@@ -113,11 +113,10 @@
templateId
:
'
template
'
,
renderTemplate
(
container
)
{
return
container
;
},
renderElement
(
element
,
index
,
container
)
{
if
(
element
.
element
.
elements
.
length
>
1
)
{
container
.
innerHTML
=
`🙈
${
element
.
element
.
elements
.
map
(
el
=>
el
.
name
).
join
(
'
/
'
)}
`
;
}
else
{
container
.
innerHTML
=
element
.
element
.
elements
[
0
].
name
;
}
container
.
innerHTML
=
element
.
element
.
name
;
},
renderCompressedElements
(
node
,
index
,
container
,
height
)
{
container
.
innerHTML
=
`🙈
${
node
.
element
.
elements
.
map
(
el
=>
el
.
name
).
join
(
'
/
'
)}
`
;
},
disposeElement
()
{
},
disposeTemplate
()
{
}
...
...
@@ -146,7 +145,7 @@
}
};
const
tree
=
new
Compress
edObjectTree
(
container
,
delegate
,
[
renderer
],
{
...
opts
,
filter
:
treeFilter
,
setRowLineHeight
:
false
,
collapseByDefault
:
true
,
setRowLineHeight
:
true
});
const
tree
=
new
Compress
ibleObjectTree
(
'
test
'
,
container
,
delegate
,
[
renderer
],
{
...
opts
,
filter
:
treeFilter
,
setRowLineHeight
:
false
,
collapseByDefault
:
true
,
setRowLineHeight
:
true
});
return
{
tree
,
treeFilter
};
}
...
...
@@ -206,7 +205,7 @@
getChildren
(
element
)
{
return
new
Promise
((
c
,
e
)
=>
{
const
xhr
=
new
XMLHttpRequest
();
xhr
.
open
(
'
GET
'
,
element
?
`/
api / readdir ? path =
${
element
.
element
.
path
}
`
:
'
/api/readdir
'
);
xhr
.
open
(
'
GET
'
,
element
?
`/
api/readdir?path=
${
element
.
element
.
path
}
`
:
'
/api/readdir
'
);
xhr
.
send
();
xhr
.
onreadystatechange
=
function
()
{
if
(
this
.
readyState
==
4
&&
this
.
status
==
200
)
{
...
...
@@ -228,7 +227,7 @@
}
};
const
tree
=
new
AsyncDataTree
(
container
,
delegate
,
[
renderer
],
dataSource
,
{
filter
:
treeFilter
,
sorter
,
identityProvider
});
const
tree
=
new
AsyncDataTree
(
'
test
'
,
container
,
delegate
,
[
renderer
],
dataSource
,
{
filter
:
treeFilter
,
sorter
,
identityProvider
});
return
{
tree
,
treeFilter
};
}
...
...
@@ -283,15 +282,15 @@
}
};
const
tree
=
new
DataTree
(
container
,
delegate
,
[
renderer
],
dataSource
,
{
filter
:
treeFilter
,
identityProvider
});
const
tree
=
new
DataTree
(
'
test
'
,
container
,
delegate
,
[
renderer
],
dataSource
,
{
filter
:
treeFilter
,
identityProvider
});
tree
.
input
=
{
tree
.
setInput
(
{
children
:
[
{
name
:
'
A
'
,
children
:
[{
name
:
'
AA
'
},
{
name
:
'
AB
'
}]
},
{
name
:
'
B
'
,
children
:
[{
name
:
'
BA
'
,
children
:
[{
name
:
'
BAA
'
}]
},
{
name
:
'
BB
'
}]
},
{
name
:
'
C
'
}
]
};
}
)
;
return
{
tree
,
treeFilter
};
}
...
...
@@ -324,9 +323,9 @@
expandall
.
onclick
=
()
=>
perf
(
'
expand all
'
,
()
=>
tree
.
expandAll
());
collapseall
.
onclick
=
()
=>
perf
(
'
collapse all
'
,
()
=>
tree
.
collapseAll
());
renderwidth
.
onclick
=
()
=>
perf
(
'
renderwidth
'
,
()
=>
tree
.
layoutWidth
(
Math
.
random
()));
refresh
.
onclick
=
()
=>
perf
(
'
refresh
'
,
()
=>
tree
.
refresh
(
null
,
true
));
refresh
.
onclick
=
()
=>
perf
(
'
refresh
'
,
()
=>
tree
.
updateChildren
(
));
tree
.
refresh
(
null
);
tree
.
setInput
(
null
);
break
;
}
...
...
@@ -336,7 +335,7 @@
expandall
.
onclick
=
()
=>
perf
(
'
expand all
'
,
()
=>
tree
.
expandAll
());
collapseall
.
onclick
=
()
=>
perf
(
'
collapse all
'
,
()
=>
tree
.
collapseAll
());
renderwidth
.
onclick
=
()
=>
perf
(
'
renderwidth
'
,
()
=>
tree
.
layoutWidth
(
Math
.
random
()));
refresh
.
onclick
=
()
=>
perf
(
'
refresh
'
,
()
=>
tree
.
refresh
(
null
,
true
));
refresh
.
onclick
=
()
=>
perf
(
'
refresh
'
,
()
=>
tree
.
updateChildren
(
));
break
;
}
...
...
@@ -401,4 +400,4 @@
</script>
</body>
</html>
\ No newline at end of file
</html>
编辑
预览
Markdown
is supported
0%
请重试
或
添加新附件
.
添加附件
取消
You are about to add
0
people
to the discussion. Proceed with caution.
先完成此消息的编辑!
取消
想要评论请
注册
或
登录