Skip to content
Merged
Show file tree
Hide file tree
Changes from 5 commits
Commits
File filter

Filter by extension

Filter by extension


Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
20 changes: 10 additions & 10 deletions package-lock.json

Some generated files are not rendered by default. Learn more about how customized files appear on GitHub.

6 changes: 6 additions & 0 deletions package.json
Original file line number Diff line number Diff line change
Expand Up @@ -62,6 +62,12 @@
"type": "boolean",
"description": "Synchronize dependency viewer selection with folder explorer",
"default": true
},
"java.dependency.packagePresentation": {
"type": "string",
"enum":["flat","hierarchical"],
"description": "Set the presentation model of packages",

Copy link
Copy Markdown
Contributor

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Package presentation mode: flat or hierarchical

"default": "flat"
}
}
},
Expand Down
4 changes: 4 additions & 0 deletions src/settings.ts
Original file line number Diff line number Diff line change
Expand Up @@ -28,5 +28,9 @@ export class Settings {
return this._depdendencyConfig.get("syncWithFolderExplorer");
}

public static getPackagePresentation(): string {
return this._depdendencyConfig.get("packagePresentation");
}

private static _depdendencyConfig: WorkspaceConfiguration = workspace.getConfiguration("java.dependency");
}
12 changes: 9 additions & 3 deletions src/views/dependencyExplorer.ts
Original file line number Diff line number Diff line change
Expand Up @@ -9,6 +9,7 @@ import { Utility } from "../utility";
import { DataNode } from "./dataNode";
import { DependencyDataProvider } from "./dependencyDataProvider";
import { ExplorerNode } from "./explorerNode";
import { HierarchicalNode } from "./hierarchicalNode";

export class DependencyExplorer {

Expand Down Expand Up @@ -49,7 +50,6 @@ export class DependencyExplorer {
if (!current) {
return;
}

Copy link
Copy Markdown
Contributor

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Avoid the empty diff if possible. You can always provide another PR for format/coding convention to avoid distraction.

const res = current.getChildren();
if (Utility.isThenable(res)) {
res.then((children: DataNode[]) => {
Expand All @@ -71,8 +71,14 @@ export class DependencyExplorer {
this._selectionWhenHidden = c;
}
} else {
paths.shift();
this.revealPath(c, paths);
// Resove Hierarchical packages

Copy link
Copy Markdown
Contributor

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

typo: Resolve ==> Resolve

if (c instanceof HierarchicalNode && c.isHierarchicalView()) {
c.revealPath(paths)
.then((revealResult) => { this.revealPath(revealResult[0], revealResult[1]); });
} else {
paths.shift();
this.revealPath(c, paths);
}
}
break;
}
Expand Down
66 changes: 66 additions & 0 deletions src/views/hierachicalPackageRootSubNode.ts
Original file line number Diff line number Diff line change
@@ -0,0 +1,66 @@
import { Jdtls } from "../java/jdtls";
import { INodeData, NodeKind } from "../java/nodeData";
import { DataNode } from "./dataNode";
import { ExplorerNode } from "./explorerNode";
import { FileNode } from "./fileNode";
import { FolderNode } from "./folderNode";
import { PackageTreeNode } from "./packageTreeNode";
import { ProjectNode } from "./projectNode";
import { TypeRootNode } from "./typeRootNode";

export class HierachicalPackageRootSubNode extends DataNode {

public packageTree: PackageTreeNode;

Copy link
Copy Markdown
Contributor

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

This class code is duplicate with the HierarchicalPackageRootNode, could we model these two types in one class?


constructor(nodeData: INodeData, parent: DataNode, private _project: ProjectNode, packageTree: PackageTreeNode = null) {

Copy link
Copy Markdown
Contributor

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

= null should be removed

super(nodeData, parent);
this.packageTree = packageTree;
}

protected loadData(): Thenable<any[]> {
return Jdtls.getPackageData({
kind: NodeKind.Package,
projectUri: this._project.nodeData.uri,
path: this.packageTree.fullName,
rootPath: this.nodeData.path,
});
}

protected get iconPath(): { light: string; dark: string } {
return ExplorerNode.resolveIconPath("package");
}

protected createChildNodeList(): ExplorerNode[] {
const result = [];
if (this.nodeData.children && this.nodeData.children.length) {
this.nodeData.children.forEach((data) => {
if (data.kind === NodeKind.File) {
result.push(new FileNode(data, this));
} else if (data.kind === NodeKind.Folder) {
result.push(new FolderNode(data, this, this._project, this));
} else if (data.kind === NodeKind.TypeRoot) {
result.push(new TypeRootNode(data, this));
}
});
}
this.getHierarchicalPackageNodes().forEach((node) => result.push(node));
result.sort();
return result;
}

protected getHierarchicalPackageNodes(): ExplorerNode[] {
const result = [];
this.packageTree.childs.forEach((childNode) => {
Comment thread
Flanker32 marked this conversation as resolved.
Outdated
const childNodeData: INodeData = {
name: childNode.name,
moduleName: this.nodeData.moduleName,
path: this.nodeData.path,
uri: null,
kind: NodeKind.PackageRoot,
children: null,
};
result.push(new HierachicalPackageRootSubNode(childNodeData, this, this._project, childNode));
});
return result;
}
}
14 changes: 14 additions & 0 deletions src/views/hierarchicalNode.ts
Original file line number Diff line number Diff line change
@@ -0,0 +1,14 @@
import { INodeData } from "../java/nodeData";
import { DataNode } from "./dataNode";
import { ExplorerNode } from "./explorerNode";

export abstract class HierarchicalNode extends DataNode {
public abstract createFlatChildNodeList(): ExplorerNode[];
public abstract createHierarchicalChildNodeList(): ExplorerNode[];
public abstract isHierarchicalView(): boolean;
public abstract revealPath(paths: INodeData[]): Promise<[ExplorerNode, INodeData[]]>;

protected createChildNodeList(): ExplorerNode[] {
return this.isHierarchicalView() ? this.createHierarchicalChildNodeList() : this.createFlatChildNodeList();
}
}
75 changes: 70 additions & 5 deletions src/views/packageRootNode.ts
Original file line number Diff line number Diff line change
Expand Up @@ -4,25 +4,29 @@
import { Jdtls } from "../java/jdtls";
import { INodeData, NodeKind } from "../java/nodeData";
import { IPackageRootNodeData, PackageRootKind } from "../java/packageRootNodeData";
import { Settings } from "../settings";
import { DataNode } from "./dataNode";
import { ExplorerNode } from "./explorerNode";
import { FileNode } from "./fileNode";
import { FolderNode } from "./folderNode";
import { HierachicalPackageRootSubNode } from "./hierachicalPackageRootSubNode";
import { HierarchicalNode } from "./hierarchicalNode";
import { PackageNode } from "./packageNode";
import { PackageTreeNode } from "./packageTreeNode";
import { ProjectNode } from "./projectNode";
import { TypeRootNode } from "./typeRootNode";

export class PackageRootNode extends DataNode {
export class PackageRootNode extends HierarchicalNode {

constructor(nodeData: INodeData, parent: DataNode, private _project: ProjectNode) {
constructor(nodeData: INodeData, parent: DataNode, protected _project: ProjectNode) {
super(nodeData, parent);

Copy link
Copy Markdown
Contributor

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

You should NOT mixed the flat package node and hierarchy package node in the same class. It violate SRP and will make the code hard to main in the future.

You can create two class/types for different purpose.

Copy link
Copy Markdown
Member Author

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

I made an abstract class named HierarchicalNode , which includes createFlatChildNodeList , createHierarchicalChildNodeList and revealPath, and PackageRootNode extends it, i didn't split packagenode into two parts for there are still some common methods like loadData and getIconPath, other methods for Hierarchical was moved to HierachicalPackageRootSubNode

}

protected loadData(): Thenable<INodeData[]> {
return Jdtls.getPackageData({ kind: NodeKind.PackageRoot, projectUri: this._project.nodeData.uri, rootPath: this.nodeData.path });
public isHierarchicalView(): boolean {
return Settings.getPackagePresentation() === "hierarchical";
}

protected createChildNodeList(): ExplorerNode[] {
public createFlatChildNodeList(): ExplorerNode[] {
const result = [];
if (this.nodeData.children && this.nodeData.children.length) {
this.sort();
Expand All @@ -40,6 +44,41 @@ export class PackageRootNode extends DataNode {
}
return result;
}
public createHierarchicalChildNodeList(): ExplorerNode[] {
const result = [];
if (this.nodeData.children && this.nodeData.children.length) {
this.nodeData.children.forEach((data) => {
if (data.kind === NodeKind.File) {
result.push(new FileNode(data, this));
} else if (data.kind === NodeKind.Folder) {
result.push(new FolderNode(data, this, this._project, this));
} else if (data.kind === NodeKind.TypeRoot) {
result.push(new TypeRootNode(data, this));
}
});
}
this.getHierarchicalPackageNodes().forEach((node) => result.push(node));
result.sort();
return result;
}

public async revealPath(paths: INodeData[]): Promise<[ExplorerNode, INodeData[]]> {
await this.getChildren();
const packageRootNodeData = paths.shift();
const packageNodeData = paths.shift();
let packageTreeNode: PackageTreeNode = this.getPackageTree();
// tslint:disable-next-line:no-this-assignment
let result: DataNode = this;
while (packageTreeNode.childs.length && packageTreeNode.fullName !== packageNodeData.name) {
packageTreeNode.childs.forEach((child) => {
if (packageNodeData.name.startsWith(child.fullName)) {
result = new HierachicalPackageRootSubNode(child.getNodeDataFromPackageTreeNode(this.nodeData), result, this._project, child);
packageTreeNode = child;
}
});
}
return [result, paths];
}

protected get iconPath(): { light: string; dark: string } {
const data = <IPackageRootNodeData>this.nodeData;
Expand All @@ -49,4 +88,30 @@ export class PackageRootNode extends DataNode {
return ExplorerNode.resolveIconPath("packagefolder");
}
}

protected getHierarchicalPackageNodes(): ExplorerNode[] {
const result = [];
const packageTree = this.getPackageTree();
packageTree.childs.forEach((childNode) => {
result.push(new HierachicalPackageRootSubNode(childNode.getNodeDataFromPackageTreeNode(this.nodeData), this, this._project, childNode));
});
return result;
}

protected loadData(): Thenable<INodeData[]> {
return Jdtls.getPackageData({ kind: NodeKind.PackageRoot, projectUri: this._project.nodeData.uri, rootPath: this.nodeData.path });
}

private getPackageTree(): PackageTreeNode {
const result: PackageTreeNode = new PackageTreeNode("", "");
if (this.nodeData.children && this.nodeData.children.length) {
this.nodeData.children.forEach((child) => {
if (child.kind === NodeKind.Package) {
result.addPackage(child.name);
}
});
}
result.compressTree();
return result;
}
}
63 changes: 63 additions & 0 deletions src/views/packageTreeNode.ts
Original file line number Diff line number Diff line change
@@ -0,0 +1,63 @@
import { INodeData, NodeKind } from "../java/nodeData";

export class PackageTreeNode {
public name: string;
public fullName: string;
public childs: PackageTreeNode[] = [];
public isPackage: boolean = false;

constructor(packageName: string, parentName: string) {
const splitPackageName = packageName.split(".");
this.name = splitPackageName[0];
this.fullName = parentName === "" ? this.name : parentName + "." + this.name;
if (splitPackageName.length > 1) {
this.childs.push(new PackageTreeNode(packageName.substring(this.name.length + 1), this.fullName));
} else {
this.isPackage = true;
}
}

public addPackage(packageName: string): void {
const splitPackageName = packageName.split(".");
const firstSubName = splitPackageName[0];
const restname = packageName.substring(firstSubName.length + 1);

let contains: boolean = false;
this.childs.forEach((child) => {
if (child.name === firstSubName) {
if (restname === "") {
child.isPackage = true;
} else {
child.addPackage(restname);
}
contains = true;
}
});
if (!contains) {
this.childs.push(new PackageTreeNode(packageName, this.fullName));
}
}

public compressTree(): void {
// Don't compress the root node
while (this.name !== "" && this.childs.length === 1 && !this.isPackage) {
const child = this.childs[0];
this.fullName = this.fullName + "." + child.name;
this.name = this.name + "." + child.name;
this.childs = child.childs;
this.isPackage = child.isPackage;
}
this.childs.forEach((child) => child.compressTree());
}

public getNodeDataFromPackageTreeNode(nodeData: INodeData): INodeData {
return {
name: this.name,
moduleName: nodeData.moduleName,
path: nodeData.path,
uri: null,
kind: NodeKind.PackageRoot,
children: null,
};
}
}