From e61774f1f10834be230b09c71d4b9e0d0d5bb52c Mon Sep 17 00:00:00 2001 From: xiange Date: Thu, 17 Aug 2023 18:12:05 +0800 Subject: [PATCH] =?UTF-8?q?=F0=9F=A6=84=20refactor:=20add=20IApplication?= MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit Add the IApplication interface and refactor the Application --- package-lock.json | 58 ++-------- package.json | 2 - packages/chili-core/src/application.ts | 18 +++ packages/chili-core/src/base/pubsub.ts | 1 - packages/chili-core/src/command/command.ts | 4 +- packages/chili-core/src/command/commands.ts | 10 -- packages/chili-core/src/decorators/command.ts | 14 ++- packages/chili-core/src/document.ts | 2 + packages/chili-core/src/index.ts | 3 +- packages/chili-core/src/ioc/container.ts | 44 -------- packages/chili-core/src/ioc/index.ts | 6 - packages/chili-core/src/ioc/inject.ts | 15 --- packages/chili-core/src/ioc/register.ts | 10 -- packages/chili-core/src/ioc/resolve.ts | 8 -- packages/chili-core/src/module.ts | 8 -- packages/chili-core/src/service.ts | 4 +- packages/chili-core/test/collection.test.ts | 3 +- packages/chili-core/test/converter.test.ts | 2 - packages/chili-core/test/history.test.ts | 4 +- packages/chili-core/test/ioc.test.ts | 21 ---- packages/chili-core/test/math.test.ts | 2 - packages/chili-core/test/matrix.test.ts | 2 - packages/chili-core/test/node.test.ts | 3 +- packages/chili-core/test/nodeList.test.ts | 2 - packages/chili-core/test/observer.test.ts | 2 - packages/chili-core/test/plane.test.ts | 2 - packages/chili-core/test/ray.test.ts | 2 - packages/chili-core/test/result.test.ts | 2 - packages/chili-core/test/serializer.test.ts | 2 - packages/chili-core/test/snapType.test.ts | 2 - packages/chili-core/test/task.test.ts | 2 - packages/chili-core/test/token.test.ts | 2 - packages/chili-core/test/transaction.test.ts | 4 +- packages/chili-core/test/visual.test.ts | 1 - packages/chili-core/test/xyz.test.ts | 2 - packages/chili-occ/src/index.ts | 3 +- packages/chili-occ/src/module.ts | 24 ---- packages/chili-occ/test/occ.test.ts | 2 - packages/chili-three/src/index.ts | 2 +- packages/chili-three/src/module.ts | 15 --- packages/chili-three/src/threeView.ts | 11 +- packages/chili-three/test/testDocument.ts | 3 + packages/chili-three/test/three.test.ts | 12 +- packages/chili-ui/src/mainWindow.ts | 14 +-- .../chili-ui/src/ribbon/commandContextTab.ts | 4 +- packages/chili-ui/src/ribbon/ribbonButton.ts | 4 +- .../chili-ui/src/ribbon/titlebar/quickbar.ts | 4 +- packages/chili-web/src/appBuilder.ts | 104 +++++++++--------- packages/chili-web/src/index.ts | 2 - packages/chili/src/application.ts | 71 +++++++----- packages/chili/src/bodys/box.ts | 3 +- packages/chili/src/bodys/circle.ts | 3 +- packages/chili/src/bodys/line.ts | 3 +- packages/chili/src/bodys/polygon.ts | 3 +- packages/chili/src/bodys/rect.ts | 3 +- .../src/commands/application/newDocument.ts | 12 +- .../src/commands/application/openDocument.ts | 32 +++--- .../src/commands/application/saveDocument.ts | 8 +- packages/chili/src/commands/create/box.ts | 17 +-- packages/chili/src/commands/create/circle.ts | 12 +- .../src/commands/create/createCommand.ts | 14 +-- packages/chili/src/commands/create/line.ts | 13 +-- packages/chili/src/commands/create/rect.ts | 9 +- packages/chili/src/commands/delete.ts | 5 +- packages/chili/src/commands/folder.ts | 5 +- packages/chili/src/commands/modify/array.ts | 14 ++- .../src/commands/modify/transformedCommand.ts | 16 +-- .../chili/src/commands/multistepCommand.ts | 41 ++++--- packages/chili/src/commands/redo.ts | 5 +- packages/chili/src/commands/undo.ts | 5 +- packages/chili/src/document.ts | 29 ++--- packages/chili/src/editors/circleEditor.ts | 3 +- packages/chili/src/editors/lineEditor.ts | 3 +- packages/chili/src/index.ts | 1 + packages/chili/src/services/commandService.ts | 34 +++--- packages/chili/src/services/editorService.ts | 5 +- packages/chili/src/services/hotkeyService.ts | 7 +- packages/chili/test/service.test.ts | 23 ---- 78 files changed, 313 insertions(+), 559 deletions(-) create mode 100644 packages/chili-core/src/application.ts delete mode 100644 packages/chili-core/src/ioc/container.ts delete mode 100644 packages/chili-core/src/ioc/index.ts delete mode 100644 packages/chili-core/src/ioc/inject.ts delete mode 100644 packages/chili-core/src/ioc/register.ts delete mode 100644 packages/chili-core/src/ioc/resolve.ts delete mode 100644 packages/chili-core/src/module.ts delete mode 100644 packages/chili-core/test/ioc.test.ts delete mode 100644 packages/chili-occ/src/module.ts delete mode 100644 packages/chili-three/src/module.ts delete mode 100644 packages/chili/test/service.test.ts diff --git a/package-lock.json b/package-lock.json index 511f328a..4912bb5b 100644 --- a/package-lock.json +++ b/package-lock.json @@ -19,10 +19,8 @@ "lint-staged": "^13.2.2", "nanoid": "^4.0.2", "prettier": "^2.8.8", - "reflect-metadata": "^0.1.13", "simple-git-hooks": "^2.8.1", "ts-jest": "^29.1.0", - "tsyringe": "^4.7.0", "typescript": "^5.1.3", "typescript-plugin-css-modules": "^5.0.1" } @@ -6853,12 +6851,6 @@ "node": ">=8.10.0" } }, - "node_modules/reflect-metadata": { - "version": "0.1.13", - "resolved": "https://registry.npmmirror.com/reflect-metadata/-/reflect-metadata-0.1.13.tgz", - "integrity": "sha512-Ts1Y/anZELhSsjMcU605fU9RE4Oi3p5ORujwbIKXfWa+0Zxs510Qrmrce5/Jowq3cHSZSJqBjypxmHarc+vEWg==", - "dev": true - }, "node_modules/require-directory": { "version": "2.1.1", "resolved": "https://registry.npmmirror.com/require-directory/-/require-directory-2.1.1.tgz", @@ -7901,24 +7893,6 @@ "integrity": "sha512-d6xOpEDfsi2CZVlPQzGeux8XMwLT9hssAsaPYExaQMuYskwb+x1x7J371tWlbBdWHroy99KnVB6qIkUbs5X3UQ==", "dev": true }, - "node_modules/tsyringe": { - "version": "4.7.0", - "resolved": "https://registry.npmmirror.com/tsyringe/-/tsyringe-4.7.0.tgz", - "integrity": "sha512-ncFDM1jTLsok4ejMvSW5jN1VGPQD48y2tfAR0pdptWRKYX4bkbqPt92k7KJ5RFJ1KV36JEs/+TMh7I6OUgj74g==", - "dev": true, - "dependencies": { - "tslib": "^1.9.3" - }, - "engines": { - "node": ">= 6.0.0" - } - }, - "node_modules/tsyringe/node_modules/tslib": { - "version": "1.14.1", - "resolved": "https://registry.npmmirror.com/tslib/-/tslib-1.14.1.tgz", - "integrity": "sha512-Xni35NKzjgMrwevysHTCArtLDpPvye8zV/0E4EyYn43P7/7qvQwPh9BGkHewbMulVntbigmcT7rdX3BNo9wRJg==", - "dev": true - }, "node_modules/type-check": { "version": "0.3.2", "resolved": "https://registry.npmmirror.com/type-check/-/type-check-0.3.2.tgz", @@ -8698,7 +8672,9 @@ }, "packages/chili-storage": { "version": "0.1.0", - "devDependencies": {} + "devDependencies": { + "chili-core": "*" + } }, "packages/chili-three": { "version": "0.1.0", @@ -11143,7 +11119,10 @@ } }, "chili-storage": { - "version": "file:packages/chili-storage" + "version": "file:packages/chili-storage", + "requires": { + "chili-core": "*" + } }, "chili-three": { "version": "file:packages/chili-three", @@ -14292,12 +14271,6 @@ "picomatch": "^2.2.1" } }, - "reflect-metadata": { - "version": "0.1.13", - "resolved": "https://registry.npmmirror.com/reflect-metadata/-/reflect-metadata-0.1.13.tgz", - "integrity": "sha512-Ts1Y/anZELhSsjMcU605fU9RE4Oi3p5ORujwbIKXfWa+0Zxs510Qrmrce5/Jowq3cHSZSJqBjypxmHarc+vEWg==", - "dev": true - }, "require-directory": { "version": "2.1.1", "resolved": "https://registry.npmmirror.com/require-directory/-/require-directory-2.1.1.tgz", @@ -15124,23 +15097,6 @@ "integrity": "sha512-d6xOpEDfsi2CZVlPQzGeux8XMwLT9hssAsaPYExaQMuYskwb+x1x7J371tWlbBdWHroy99KnVB6qIkUbs5X3UQ==", "dev": true }, - "tsyringe": { - "version": "4.7.0", - "resolved": "https://registry.npmmirror.com/tsyringe/-/tsyringe-4.7.0.tgz", - "integrity": "sha512-ncFDM1jTLsok4ejMvSW5jN1VGPQD48y2tfAR0pdptWRKYX4bkbqPt92k7KJ5RFJ1KV36JEs/+TMh7I6OUgj74g==", - "dev": true, - "requires": { - "tslib": "^1.9.3" - }, - "dependencies": { - "tslib": { - "version": "1.14.1", - "resolved": "https://registry.npmmirror.com/tslib/-/tslib-1.14.1.tgz", - "integrity": "sha512-Xni35NKzjgMrwevysHTCArtLDpPvye8zV/0E4EyYn43P7/7qvQwPh9BGkHewbMulVntbigmcT7rdX3BNo9wRJg==", - "dev": true - } - } - }, "type-check": { "version": "0.3.2", "resolved": "https://registry.npmmirror.com/type-check/-/type-check-0.3.2.tgz", diff --git a/package.json b/package.json index ff5a40aa..54173012 100644 --- a/package.json +++ b/package.json @@ -30,10 +30,8 @@ "lint-staged": "^13.2.2", "nanoid": "^4.0.2", "prettier": "^2.8.8", - "reflect-metadata": "^0.1.13", "simple-git-hooks": "^2.8.1", "ts-jest": "^29.1.0", - "tsyringe": "^4.7.0", "typescript": "^5.1.3", "typescript-plugin-css-modules": "^5.0.1" } diff --git a/packages/chili-core/src/application.ts b/packages/chili-core/src/application.ts new file mode 100644 index 00000000..836498a7 --- /dev/null +++ b/packages/chili-core/src/application.ts @@ -0,0 +1,18 @@ +// Copyright 2022-2023 the Chili authors. All rights reserved. MPL-2.0 license. + +import { IShapeFactory } from "chili-geo"; +import { IVisualFactory } from "chili-vis"; +import { IStorage, Serialized } from "./base"; +import { IDocument } from "./document"; +import { IService } from "./service"; + +export interface IApplication { + readonly visualFactory: IVisualFactory; + readonly shapeFactory: IShapeFactory; + readonly services: IService[]; + readonly storage: IStorage; + activeDocument: IDocument | undefined; + newDocument(name: string): Promise; + openDocument(id: string): Promise; + loadDocument(data: Serialized): Promise; +} diff --git a/packages/chili-core/src/base/pubsub.ts b/packages/chili-core/src/base/pubsub.ts index f8963e8c..54c370e8 100644 --- a/packages/chili-core/src/base/pubsub.ts +++ b/packages/chili-core/src/base/pubsub.ts @@ -16,7 +16,6 @@ export interface PubSubEventMap { executeCommand: (commandName: keyof Commands) => void; nodeLinkedListChanged: (records: NodeRecord[]) => void; activeDocumentChanged: (document: IDocument | undefined) => void; - openDocument: (id: string) => void; documentClosed: (document: IDocument) => void; modelUpdate: (model: IModel) => void; visibleChanged: (model: IModel) => void; diff --git a/packages/chili-core/src/command/command.ts b/packages/chili-core/src/command/command.ts index 9453630c..e4ba95e7 100644 --- a/packages/chili-core/src/command/command.ts +++ b/packages/chili-core/src/command/command.ts @@ -1,7 +1,7 @@ // Copyright 2022-2023 the Chili authors. All rights reserved. MPL-2.0 license. -import { Application } from "chili/src/application"; +import { IApplication } from "../application"; export interface ICommand { - execute(application: Application): Promise; + execute(application: IApplication): Promise; } diff --git a/packages/chili-core/src/command/commands.ts b/packages/chili-core/src/command/commands.ts index 01bf5c37..d02c48b2 100644 --- a/packages/chili-core/src/command/commands.ts +++ b/packages/chili-core/src/command/commands.ts @@ -21,14 +21,4 @@ export class Commands { Mirror = "Mirror"; Rotate = "Rotate"; Array = "Array"; - - private constructor() {} - - private static _instance: Commands | undefined; - static get instance() { - if (this._instance === undefined) { - this._instance = new Commands(); - } - return this._instance; - } } diff --git a/packages/chili-core/src/decorators/command.ts b/packages/chili-core/src/decorators/command.ts index cf71f8e9..06a43410 100644 --- a/packages/chili-core/src/decorators/command.ts +++ b/packages/chili-core/src/decorators/command.ts @@ -5,6 +5,8 @@ import { I18n } from "../i18n"; const CommandMap = new Map ICommand>(); +export type CommandConstructor = new (...args: any[]) => ICommand; + export interface CommandData { name: keyof Commands; display: keyof I18n; @@ -13,17 +15,15 @@ export interface CommandData { helpUrl?: string; } -export function command ICommand>(commandData: CommandData) { +export function command(commandData: CommandData) { return (ctor: T) => { CommandMap.set(commandData.name, ctor); ctor.prototype.data = commandData; }; } -export namespace CommandData { - export function get( - command: string | ICommand | (new (...args: any[]) => ICommand) - ): CommandData | undefined { +export namespace Command { + export function getData(command: string | ICommand | CommandConstructor): CommandData | undefined { if (typeof command === "string") { let c = CommandMap.get(command); return c?.prototype.data; @@ -33,4 +33,8 @@ export namespace CommandData { return Object.getPrototypeOf(command).data; } } + + export function get(name: keyof Commands): CommandConstructor | undefined { + return CommandMap.get(name); + } } diff --git a/packages/chili-core/src/document.ts b/packages/chili-core/src/document.ts index 547bfafc..4cf1be7b 100644 --- a/packages/chili-core/src/document.ts +++ b/packages/chili-core/src/document.ts @@ -1,5 +1,6 @@ // Copyright 2022-2023 the Chili authors. All rights reserved. MPL-2.0 license. +import { IApplication } from "./application"; import { History, IDisposable, IPropertyChanged } from "./base"; import { INode, INodeLinkedList } from "./model/node"; import { SelectionManager } from "./selectionManager"; @@ -13,6 +14,7 @@ export interface IDocument extends IPropertyChanged, IDisposable { readonly history: History; readonly visual: IVisual; readonly rootNode: INodeLinkedList; + readonly application: IApplication; addNode(...nodes: INode[]): void; save(): Promise; close(): Promise; diff --git a/packages/chili-core/src/index.ts b/packages/chili-core/src/index.ts index 9ff3beb6..4cb002e7 100644 --- a/packages/chili-core/src/index.ts +++ b/packages/chili-core/src/index.ts @@ -1,5 +1,6 @@ // Copyright 2022-2023 the Chili authors. All rights reserved. MPL-2.0 license. +export * from "./application"; export * from "./base"; export * from "./command"; export * from "./config"; @@ -12,10 +13,8 @@ export * from "./editor"; export * from "./geometry"; export * from "./i18n"; export * from "./id"; -export * from "./ioc"; export * from "./math"; export * from "./model"; -export * from "./module"; export * from "./selectionManager"; export * from "./service"; export * from "./snapType"; diff --git a/packages/chili-core/src/ioc/container.ts b/packages/chili-core/src/ioc/container.ts deleted file mode 100644 index f3e5fa3b..00000000 --- a/packages/chili-core/src/ioc/container.ts +++ /dev/null @@ -1,44 +0,0 @@ -// Copyright 2022-2023 the Chili authors. All rights reserved. MPL-2.0 license. - -import { container as tsContainer, DependencyContainer as TsDependencyContainer, Lifecycle } from "tsyringe"; - -import { Token } from "../decorators/token"; -import { IRegister, IResolve } from "./"; - -export class Container implements IRegister, IResolve { - private container: TsDependencyContainer; - - constructor() { - this.container = tsContainer.createChildContainer(); - } - - has(token: Token): boolean { - return this.container.isRegistered(token.token); - } - - createResolve(): IResolve { - return this; - } - - register(token: Token, ctor: new (...args: any[]) => T): void { - this.container.register(token.token, { - useClass: ctor, - }); - } - - registerSingleton(token: Token, ctor: new (...args: any[]) => T): void { - this.container.register( - token.token, - { - useClass: ctor, - }, - { - lifecycle: Lifecycle.Singleton, - } - ); - } - - resolve(token: Token): T | undefined { - return this.container.resolve(token.token); - } -} diff --git a/packages/chili-core/src/ioc/index.ts b/packages/chili-core/src/ioc/index.ts deleted file mode 100644 index 648b1370..00000000 --- a/packages/chili-core/src/ioc/index.ts +++ /dev/null @@ -1,6 +0,0 @@ -// Copyright 2022-2023 the Chili authors. All rights reserved. MPL-2.0 license. - -export * from "./container"; -export * from "./resolve"; -export * from "./register"; -export * from "./inject"; diff --git a/packages/chili-core/src/ioc/inject.ts b/packages/chili-core/src/ioc/inject.ts deleted file mode 100644 index 72cc4343..00000000 --- a/packages/chili-core/src/ioc/inject.ts +++ /dev/null @@ -1,15 +0,0 @@ -// Copyright 2022-2023 the Chili authors. All rights reserved. MPL-2.0 license. - -import { inject as tsyringeInject, injectable as tsyringeInjectable } from "tsyringe"; - -import { Token } from "../decorators/token"; - -export function injectable(): (target: new (...args: any[]) => T) => void { - return tsyringeInjectable(); -} - -export function inject( - token: Token -): (target: any, propertyKey: string | symbol, parameterIndex: number) => any { - return tsyringeInject(token.token); -} diff --git a/packages/chili-core/src/ioc/register.ts b/packages/chili-core/src/ioc/register.ts deleted file mode 100644 index 49907e47..00000000 --- a/packages/chili-core/src/ioc/register.ts +++ /dev/null @@ -1,10 +0,0 @@ -// Copyright 2022-2023 the Chili authors. All rights reserved. MPL-2.0 license. - -import { Token } from "../decorators/token"; -import { IResolve } from "./resolve"; - -export interface IRegister { - createResolve(): IResolve; - register(token: Token, ctor: new (...args: any[]) => T): void; - registerSingleton(token: Token, ctor: new (...args: any[]) => T): void; -} diff --git a/packages/chili-core/src/ioc/resolve.ts b/packages/chili-core/src/ioc/resolve.ts deleted file mode 100644 index 50aa34fa..00000000 --- a/packages/chili-core/src/ioc/resolve.ts +++ /dev/null @@ -1,8 +0,0 @@ -// Copyright 2022-2023 the Chili authors. All rights reserved. MPL-2.0 license. - -import { Token } from "../decorators/token"; - -export interface IResolve { - has(token: Token): boolean; - resolve(token: Token): T | undefined; -} diff --git a/packages/chili-core/src/module.ts b/packages/chili-core/src/module.ts deleted file mode 100644 index 69384f78..00000000 --- a/packages/chili-core/src/module.ts +++ /dev/null @@ -1,8 +0,0 @@ -// Copyright 2022-2023 the Chili authors. All rights reserved. MPL-2.0 license. - -import { IRegister } from "./ioc"; - -export interface IModule { - type(): string; - init(container: IRegister): void | Promise; -} diff --git a/packages/chili-core/src/service.ts b/packages/chili-core/src/service.ts index 8273678f..c75b198b 100644 --- a/packages/chili-core/src/service.ts +++ b/packages/chili-core/src/service.ts @@ -1,9 +1,9 @@ // Copyright 2022-2023 the Chili authors. All rights reserved. MPL-2.0 license. -import { Application } from "chili/src/application"; +import { IApplication } from "./application"; export interface IService { - register(app: Application): void; + register(app: IApplication): void; start(): void; stop(): void; } diff --git a/packages/chili-core/test/collection.test.ts b/packages/chili-core/test/collection.test.ts index 6ea06f42..c1f30831 100644 --- a/packages/chili-core/test/collection.test.ts +++ b/packages/chili-core/test/collection.test.ts @@ -1,5 +1,4 @@ // Copyright 2022-2023 the Chili authors. All rights reserved. MPL-2.0 license. -import "reflect-metadata"; import { CollectionAction, CollectionChangedArgs, ObservableCollection } from "../src"; describe("ObservableCollection test", () => { @@ -44,7 +43,7 @@ describe("ObservableCollection test", () => { expect(collection.items).toStrictEqual([1, 3, 2, 3]); expect(arg.items).toStrictEqual([3, 2]); expect(arg.items.length).toBe(2); - expect(arg.item).toBe(1); + expect(arg.item).toBe(2); } }); collection.replace(1, 3, 2); diff --git a/packages/chili-core/test/converter.test.ts b/packages/chili-core/test/converter.test.ts index 15733dba..5da060b1 100644 --- a/packages/chili-core/test/converter.test.ts +++ b/packages/chili-core/test/converter.test.ts @@ -1,7 +1,5 @@ // Copyright 2022-2023 the Chili authors. All rights reserved. MPL-2.0 license. -import "reflect-metadata"; - import { XYZ } from "../src"; import { IConverter, NumberConverter, StringConverter, XYZConverter } from "../src/converter"; diff --git a/packages/chili-core/test/history.test.ts b/packages/chili-core/test/history.test.ts index c01a5365..e258ccf2 100644 --- a/packages/chili-core/test/history.test.ts +++ b/packages/chili-core/test/history.test.ts @@ -1,8 +1,6 @@ // Copyright 2022-2023 the Chili authors. All rights reserved. MPL-2.0 license. -import "reflect-metadata"; - -import { ArrayRecord, PropertyHistoryRecord, History } from "chili-core"; +import { ArrayRecord, History, PropertyHistoryRecord } from "chili-core"; describe("test history", () => { class TestClass { diff --git a/packages/chili-core/test/ioc.test.ts b/packages/chili-core/test/ioc.test.ts deleted file mode 100644 index 356beb14..00000000 --- a/packages/chili-core/test/ioc.test.ts +++ /dev/null @@ -1,21 +0,0 @@ -// Copyright 2022-2023 the Chili authors. All rights reserved. MPL-2.0 license. - -import "reflect-metadata"; - -import { Container, Token } from "../src"; - -test("test ioc", () => { - class TestClass { - constructor() {} - } - let container = new Container(); - container.register(new Token("t1"), TestClass); - container.registerSingleton(new Token("t2"), TestClass); - let t11 = container.resolve(new Token("t1")); - let t12 = container.resolve(new Token("t1")); - expect(t11 === t12).toBeFalsy(); - - let t21 = container.resolve(new Token("t2")); - let t22 = container.resolve(new Token("t2")); - expect(t21 === t22).toBeTruthy(); -}); diff --git a/packages/chili-core/test/math.test.ts b/packages/chili-core/test/math.test.ts index 358dd7ba..0b2b6e70 100644 --- a/packages/chili-core/test/math.test.ts +++ b/packages/chili-core/test/math.test.ts @@ -1,7 +1,5 @@ // Copyright 2022-2023 the Chili authors. All rights reserved. MPL-2.0 license. -import "reflect-metadata"; - import { MathUtils } from "../src"; describe("test math", () => { diff --git a/packages/chili-core/test/matrix.test.ts b/packages/chili-core/test/matrix.test.ts index c2c1e388..ecd8d8f0 100644 --- a/packages/chili-core/test/matrix.test.ts +++ b/packages/chili-core/test/matrix.test.ts @@ -1,7 +1,5 @@ // Copyright 2022-2023 the Chili authors. All rights reserved. MPL-2.0 license. -import "reflect-metadata"; - import { Matrix4, Plane, XYZ } from "../src"; describe("test Transform", () => { diff --git a/packages/chili-core/test/node.test.ts b/packages/chili-core/test/node.test.ts index f3e61b6a..efeb53ba 100644 --- a/packages/chili-core/test/node.test.ts +++ b/packages/chili-core/test/node.test.ts @@ -1,7 +1,6 @@ // Copyright 2022-2023 the Chili authors. All rights reserved. MPL-2.0 license. -import "reflect-metadata"; -import { IDocument, History, INode, NodeLinkedList } from "../src"; +import { History, IDocument, INode, NodeLinkedList } from "../src"; describe("test node", () => { let doc: IDocument = { history: new History() } as any; diff --git a/packages/chili-core/test/nodeList.test.ts b/packages/chili-core/test/nodeList.test.ts index 86fdf551..70b9b947 100644 --- a/packages/chili-core/test/nodeList.test.ts +++ b/packages/chili-core/test/nodeList.test.ts @@ -1,7 +1,5 @@ // Copyright 2022-2023 the Chili authors. All rights reserved. MPL-2.0 license. -import "reflect-metadata"; - import { History, IDocument, NodeLinkedList } from "../src"; describe("test NodeLinkedList", () => { diff --git a/packages/chili-core/test/observer.test.ts b/packages/chili-core/test/observer.test.ts index 2d741e98..ba93a7ce 100644 --- a/packages/chili-core/test/observer.test.ts +++ b/packages/chili-core/test/observer.test.ts @@ -1,7 +1,5 @@ // Copyright 2022-2023 the Chili authors. All rights reserved. MPL-2.0 license. -import "reflect-metadata"; - import { Observable } from "../src"; class TestClass extends Observable { diff --git a/packages/chili-core/test/plane.test.ts b/packages/chili-core/test/plane.test.ts index 7525e2a1..a0f66b46 100644 --- a/packages/chili-core/test/plane.test.ts +++ b/packages/chili-core/test/plane.test.ts @@ -1,7 +1,5 @@ // Copyright 2022-2023 the Chili authors. All rights reserved. MPL-2.0 license. -import "reflect-metadata"; - import { Plane, Ray, XYZ } from "../src"; describe("test plane", () => { diff --git a/packages/chili-core/test/ray.test.ts b/packages/chili-core/test/ray.test.ts index c7889a8e..ce8d2c4c 100644 --- a/packages/chili-core/test/ray.test.ts +++ b/packages/chili-core/test/ray.test.ts @@ -1,7 +1,5 @@ // Copyright 2022-2023 the Chili authors. All rights reserved. MPL-2.0 license. -import "reflect-metadata"; - import { Ray, XYZ } from "../src"; describe("test ray", () => { diff --git a/packages/chili-core/test/result.test.ts b/packages/chili-core/test/result.test.ts index 700af256..c0e79f93 100644 --- a/packages/chili-core/test/result.test.ts +++ b/packages/chili-core/test/result.test.ts @@ -1,7 +1,5 @@ // Copyright 2022-2023 the Chili authors. All rights reserved. MPL-2.0 license. -import "reflect-metadata"; - import { Result } from "../src"; test("test result", () => { diff --git a/packages/chili-core/test/serializer.test.ts b/packages/chili-core/test/serializer.test.ts index 74277dec..aaa051db 100644 --- a/packages/chili-core/test/serializer.test.ts +++ b/packages/chili-core/test/serializer.test.ts @@ -1,7 +1,5 @@ // Copyright 2022-2023 the Chili authors. All rights reserved. MPL-2.0 license. -import "reflect-metadata"; - import { History, IDocument, ISerialize, NodeLinkedList, Serialized, Serializer } from "../src"; class TestObject implements ISerialize { diff --git a/packages/chili-core/test/snapType.test.ts b/packages/chili-core/test/snapType.test.ts index 166b539a..35d2e1b4 100644 --- a/packages/chili-core/test/snapType.test.ts +++ b/packages/chili-core/test/snapType.test.ts @@ -1,7 +1,5 @@ // Copyright 2022-2023 the Chili authors. All rights reserved. MPL-2.0 license. -import "reflect-metadata"; - import { ObjectSnapType } from "../src"; test("test SnapType", () => { diff --git a/packages/chili-core/test/task.test.ts b/packages/chili-core/test/task.test.ts index 774b2a77..b9035ef0 100644 --- a/packages/chili-core/test/task.test.ts +++ b/packages/chili-core/test/task.test.ts @@ -1,7 +1,5 @@ // Copyright 2022-2023 the Chili authors. All rights reserved. MPL-2.0 license. -import "reflect-metadata"; - import { AsyncState } from "../src"; test("test cancel", async () => { diff --git a/packages/chili-core/test/token.test.ts b/packages/chili-core/test/token.test.ts index bb1c451f..fd9ee56e 100644 --- a/packages/chili-core/test/token.test.ts +++ b/packages/chili-core/test/token.test.ts @@ -1,7 +1,5 @@ // Copyright 2022-2023 the Chili authors. All rights reserved. MPL-2.0 license. -import "reflect-metadata"; - import { Token } from "../src"; test("test token", () => { diff --git a/packages/chili-core/test/transaction.test.ts b/packages/chili-core/test/transaction.test.ts index 322bc360..6abdf6cc 100644 --- a/packages/chili-core/test/transaction.test.ts +++ b/packages/chili-core/test/transaction.test.ts @@ -1,8 +1,6 @@ // Copyright 2022-2023 the Chili authors. All rights reserved. MPL-2.0 license. -import "reflect-metadata"; - -import { IDocument, History, PropertyHistoryRecord, Transaction } from "../src"; +import { History, IDocument, PropertyHistoryRecord, Transaction } from "../src"; describe("test Transaction", () => { test("test static methods", () => { diff --git a/packages/chili-core/test/visual.test.ts b/packages/chili-core/test/visual.test.ts index 12d885be..a9a26dbc 100644 --- a/packages/chili-core/test/visual.test.ts +++ b/packages/chili-core/test/visual.test.ts @@ -1,6 +1,5 @@ // Copyright 2022-2023 the Chili authors. All rights reserved. MPL-2.0 license. -import "reflect-metadata"; import { VisualState } from "../src"; describe("visual test", () => { diff --git a/packages/chili-core/test/xyz.test.ts b/packages/chili-core/test/xyz.test.ts index 577d09ff..15282f5a 100644 --- a/packages/chili-core/test/xyz.test.ts +++ b/packages/chili-core/test/xyz.test.ts @@ -1,7 +1,5 @@ // Copyright 2022-2023 the Chili authors. All rights reserved. MPL-2.0 license. -import "reflect-metadata"; - import { XY, XYZ } from "../src"; describe("test xyz", () => { diff --git a/packages/chili-occ/src/index.ts b/packages/chili-occ/src/index.ts index 65b42252..2607e842 100644 --- a/packages/chili-occ/src/index.ts +++ b/packages/chili-occ/src/index.ts @@ -1,3 +1,4 @@ // Copyright 2022-2023 the Chili authors. All rights reserved. MPL-2.0 license. -export * from "./module"; +export * from "./shapeFactory"; +export * from "./occ"; diff --git a/packages/chili-occ/src/module.ts b/packages/chili-occ/src/module.ts deleted file mode 100644 index f218fe21..00000000 --- a/packages/chili-occ/src/module.ts +++ /dev/null @@ -1,24 +0,0 @@ -// Copyright 2022-2023 the Chili authors. All rights reserved. MPL-2.0 license. - -import { IModule, IRegister, Token } from "chili-core"; - -export class OccModule implements IModule { - type(): string { - return "occ module"; - } - - async init(container: IRegister): Promise { - const m = await import("./occ"); - await m.initMyOcc(); - - let factorys: any = await import("./shapeFactory"); - let keys = Object.keys(factorys); - keys.forEach((key) => { - let factory = factorys[key]; - let token = Token.get(factory); - if (token !== undefined) { - container.registerSingleton(token, factory); - } - }); - } -} diff --git a/packages/chili-occ/test/occ.test.ts b/packages/chili-occ/test/occ.test.ts index 02300ef9..b7ba083d 100644 --- a/packages/chili-occ/test/occ.test.ts +++ b/packages/chili-occ/test/occ.test.ts @@ -1,7 +1,5 @@ // Copyright 2022-2023 the Chili authors. All rights reserved. MPL-2.0 license. -import "reflect-metadata"; - import { expect, jest, test } from "@jest/globals"; import { CurveType, Id, Matrix4, Ray, ShapeType, XYZ } from "chili-core"; import initOpenCascade, { OpenCascadeInstance } from "opencascade.js/dist/node.js"; diff --git a/packages/chili-three/src/index.ts b/packages/chili-three/src/index.ts index 65b42252..acf54eef 100644 --- a/packages/chili-three/src/index.ts +++ b/packages/chili-three/src/index.ts @@ -1,3 +1,3 @@ // Copyright 2022-2023 the Chili authors. All rights reserved. MPL-2.0 license. -export * from "./module"; +export * from "./threeVisualFactory"; diff --git a/packages/chili-three/src/module.ts b/packages/chili-three/src/module.ts deleted file mode 100644 index 84f31d2c..00000000 --- a/packages/chili-three/src/module.ts +++ /dev/null @@ -1,15 +0,0 @@ -// Copyright 2022-2023 the Chili authors. All rights reserved. MPL-2.0 license. - -import { IModule, IRegister, Token } from "chili-core"; - -import { ThreeVisulFactory } from "./threeVisualFactory"; - -export class ThreeModule implements IModule { - type(): string { - return "three module"; - } - - init(container: IRegister): void | Promise { - container.registerSingleton(Token.VisulizationFactory, ThreeVisulFactory); - } -} diff --git a/packages/chili-three/src/threeView.ts b/packages/chili-three/src/threeView.ts index ef2c565b..4f573d83 100644 --- a/packages/chili-three/src/threeView.ts +++ b/packages/chili-three/src/threeView.ts @@ -340,8 +340,8 @@ export class ThreeView extends Observable implements IView, IDisposable { return detecteds; } - detected(shapeType: ShapeType, mx: number, my: number, firstHitOnly: boolean): VisualShapeData[] { - let intersections = this.findIntersections(shapeType, mx, my, firstHitOnly); + detected(shapeType: ShapeType, mx: number, my: number): VisualShapeData[] { + let intersections = this.findIntersections(shapeType, mx, my); return shapeType === ShapeType.Shape ? this.detectThreeShapes(intersections) : this.detectSubShapes(shapeType, intersections); @@ -393,8 +393,8 @@ export class ThreeView extends Observable implements IView, IDisposable { return { groupIndex, groups }; } - private findIntersections(shapeType: ShapeType, mx: number, my: number, firstHitOnly: boolean) { - let raycaster = this.initRaycaster(mx, my, firstHitOnly); + private findIntersections(shapeType: ShapeType, mx: number, my: number) { + let raycaster = this.initRaycaster(mx, my); let shapes = this.initIntersectableObjects(shapeType); return raycaster.intersectObjects(shapes, false); } @@ -416,13 +416,12 @@ export class ThreeView extends Observable implements IView, IDisposable { return shapes; } - private initRaycaster(mx: number, my: number, firstHitOnly: boolean) { + private initRaycaster(mx: number, my: number) { let threshold = Constants.RaycasterThreshold * this.scale; let raycaster = new Raycaster(); raycaster.params = { Line: { threshold }, Points: { threshold } }; let ray = this.rayAt(mx, my); raycaster.set(ThreeHelper.fromXYZ(ray.location), ThreeHelper.fromXYZ(ray.direction)); - raycaster.firstHitOnly = firstHitOnly; return raycaster; } } diff --git a/packages/chili-three/test/testDocument.ts b/packages/chili-three/test/testDocument.ts index feb6d4ac..bbe98f2e 100644 --- a/packages/chili-three/test/testDocument.ts +++ b/packages/chili-three/test/testDocument.ts @@ -2,6 +2,7 @@ import { History, + IApplication, IDocument, INode, INodeLinkedList, @@ -12,6 +13,7 @@ import { import { ThreeVisual } from "../src/threeVisual"; export class TestDocument implements IDocument { + application: IApplication; name: string; currentNode: INodeLinkedList | undefined; id: string; @@ -41,6 +43,7 @@ export class TestDocument implements IDocument { this.history = {} as any; this.selection = {} as any; this.rootNode = {} as any; + this.application = {} as any; } addNode(...nodes: INode[]): void { throw new Error("Method not implemented."); diff --git a/packages/chili-three/test/three.test.ts b/packages/chili-three/test/three.test.ts index 564c6c06..1b81dbd4 100644 --- a/packages/chili-three/test/three.test.ts +++ b/packages/chili-three/test/three.test.ts @@ -1,12 +1,10 @@ // Copyright 2022-2023 the Chili authors. All rights reserved. MPL-2.0 license. -import "reflect-metadata"; -import { expect, jest, test } from "@jest/globals"; -import { GeometryModel, Model, Plane, ShapeType, XY, XYZ } from "chili-core"; +import { expect, test } from "@jest/globals"; +import { GeometryModel, ShapeType, XY, XYZ } from "chili-core"; import { TestDocument } from "./testDocument"; +import { TestBody } from "./testEdge"; import { TestView } from "./testView"; -import { TestBody, TestEdge } from "./testEdge"; -import { shaderFunctions } from "three-mesh-bvh"; describe("three test", () => { let doc = new TestDocument(); @@ -27,7 +25,7 @@ describe("three test", () => { context.addModel([model]); expect(context.getShape(model)).not.toBeNull(); let mouse = view.worldToScreen(new XYZ(100, 0, 0)); - let shapes = view.detected(ShapeType.Shape, mouse.x, mouse.y, false); + let shapes = view.detected(ShapeType.Shape, mouse.x, mouse.y); expect(shapes.length).toEqual(1); expect(shapes[0].shape.shapeType).toBe(ShapeType.Edge); @@ -36,6 +34,6 @@ describe("three test", () => { expect(context.getModel(shape!)).toEqual(model); context.removeModel([model]); - expect(view.detected(ShapeType.Shape, mouse.x, mouse.y, false).length).toEqual(0); + expect(view.detected(ShapeType.Shape, mouse.x, mouse.y).length).toEqual(0); }); }); diff --git a/packages/chili-ui/src/mainWindow.ts b/packages/chili-ui/src/mainWindow.ts index 134045f7..2f4a3081 100644 --- a/packages/chili-ui/src/mainWindow.ts +++ b/packages/chili-ui/src/mainWindow.ts @@ -2,7 +2,7 @@ import { Constants, - IStorage, + IApplication, Lazy, Observable, ObservableCollection, @@ -34,7 +34,7 @@ export class MainWindow { return this.#lazy.value; } - #storage?: IStorage; + #app?: IApplication; #home: HTMLElement; #editor: HTMLElement; readonly #vm: MainWindowViewModel = new MainWindowViewModel(); @@ -45,8 +45,8 @@ export class MainWindow { this.#editor = new Editor(); } - async init(storage: IStorage, root: HTMLElement) { - this.#storage = storage; + async init(app: IApplication, root: HTMLElement) { + this.#app = app; this.setTheme("light"); root.append(this.#home, this.#editor); @@ -55,7 +55,7 @@ export class MainWindow { } private onDocumentClick = (document: RecentDocumentDTO) => { - PubSub.default.pub("openDocument", document.id); + this.#app?.openDocument(document.id); }; private onPropertyChanged = (p: keyof MainWindowViewModel) => { @@ -66,9 +66,9 @@ export class MainWindow { private async setHomeDisplay() { this.#home.style.display = this.#vm.displayHome ? "" : "none"; - if (this.#vm.displayHome && this.#storage) { + if (this.#vm.displayHome && this.#app) { this.#documents.clear(); - let datas = await this.#storage.page(Constants.DBName, Constants.RecentTable, 0); + let datas = await this.#app.storage.page(Constants.DBName, Constants.RecentTable, 0); this.#documents.add(...datas); } } diff --git a/packages/chili-ui/src/ribbon/commandContextTab.ts b/packages/chili-ui/src/ribbon/commandContextTab.ts index db21af72..d9a33937 100644 --- a/packages/chili-ui/src/ribbon/commandContextTab.ts +++ b/packages/chili-ui/src/ribbon/commandContextTab.ts @@ -1,6 +1,6 @@ // Copyright 2022-2023 the Chili authors. All rights reserved. MPL-2.0 license. -import { CommandData, I18n, ICommand, Observable, Property } from "chili-core"; +import { Command, I18n, ICommand, Observable, Property } from "chili-core"; import { Control } from "../components"; import { RibbonButton } from "./ribbonButton"; import { RibbonButtonSize } from "./ribbonButtonSize"; @@ -12,7 +12,7 @@ export class CommandContextTab extends RibbonTab { private readonly propMap: Map = new Map(); constructor(readonly command: ICommand) { - super(CommandData.get(command)!.display); + super(Command.getData(command)!.display); this.initContext(); if (command instanceof Observable) { this.addConnectedCallback(() => { diff --git a/packages/chili-ui/src/ribbon/ribbonButton.ts b/packages/chili-ui/src/ribbon/ribbonButton.ts index 943e6eb4..dfcd9a39 100644 --- a/packages/chili-ui/src/ribbon/ribbonButton.ts +++ b/packages/chili-ui/src/ribbon/ribbonButton.ts @@ -1,6 +1,6 @@ // Copyright 2022-2023 the Chili authors. All rights reserved. MPL-2.0 license. -import { CommandData, Commands, I18n, Logger, PubSub } from "chili-core"; +import { Command, Commands, I18n, Logger, PubSub } from "chili-core"; import { Control, Label, Svg } from "../components"; import style from "./ribbonButton.module.css"; import { RibbonButtonSize } from "./ribbonButtonSize"; @@ -13,7 +13,7 @@ export class RibbonButton extends Control { } static fromCommandName(commandName: keyof Commands, size: RibbonButtonSize) { - let data = CommandData.get(commandName); + let data = Command.getData(commandName); if (data === undefined) { Logger.warn(`commandData of ${commandName} is undefined`); return undefined; diff --git a/packages/chili-ui/src/ribbon/titlebar/quickbar.ts b/packages/chili-ui/src/ribbon/titlebar/quickbar.ts index fc430fba..6ed60905 100644 --- a/packages/chili-ui/src/ribbon/titlebar/quickbar.ts +++ b/packages/chili-ui/src/ribbon/titlebar/quickbar.ts @@ -1,6 +1,6 @@ // Copyright 2022-2023 the Chili authors. All rights reserved. MPL-2.0 license. -import { CommandData, Logger, PubSub } from "chili-core"; +import { Command, Logger, PubSub } from "chili-core"; import { Control, Svg } from "../../components"; import style from "./quickbar.module.css"; @@ -13,7 +13,7 @@ export class QuickToolbar extends Control { addButton(...commands: string[]) { let buttons: Svg[] = []; for (const command of commands) { - let data = CommandData.get(command); + let data = Command.getData(command); if (data === undefined) { Logger.warn("commandData is undefined"); continue; diff --git a/packages/chili-web/src/appBuilder.ts b/packages/chili-web/src/appBuilder.ts index 35f9a4de..df1dcfe3 100644 --- a/packages/chili-web/src/appBuilder.ts +++ b/packages/chili-web/src/appBuilder.ts @@ -1,95 +1,91 @@ // Copyright 2022-2023 the Chili authors. All rights reserved. MPL-2.0 license. -import { CommandService, EditorService, HotkeyService } from "chili"; -import { CommandData, Container, IRegister, IService, IStorage, Logger, Token } from "chili-core"; -import { Application } from "chili/src/application"; +import { Application, CommandService, EditorService, HotkeyService } from "chili"; +import { IService, IStorage, Logger } from "chili-core"; +import { IShapeFactory } from "chili-geo"; +import { IVisualFactory } from "chili-vis"; export class AppBuilder { - private _inits: (() => Promise)[]; - private _register: IRegister = new Container(); - private _storage?: IStorage; - - private storage() { - if (this._storage === undefined) { - throw new Error("storage has not been initialized"); - } - return this._storage; - } - - constructor() { - this._inits = []; - this.registerCommands(); - } + #useUI: boolean = false; + #inits: (() => Promise)[] = []; + #storage?: IStorage; + #visualFactory?: IVisualFactory; + #shapeFactory?: IShapeFactory; useIndexedDB() { - this._inits.push(async () => { + this.#inits.push(async () => { Logger.info("initializing IndexedDBStorage"); let db = await import("chili-storage"); - this._storage = new db.IndexedDBStorage(); + this.#storage = new db.IndexedDBStorage(); }); return this; } useOcc(): this { - this._inits.push(async () => { + this.#inits.push(async () => { Logger.info("initializing occ"); let occ = await import("chili-occ"); - await new occ.OccModule().init(this._register); + await occ.initMyOcc(); + this.#shapeFactory = new occ.ShapeFactory(); }); return this; } useThree(): this { - this._inits.push(async () => { + this.#inits.push(async () => { Logger.info("initializing three"); let three = await import("chili-three"); - await new three.ThreeModule().init(this._register); + this.#visualFactory = new three.ThreeVisulFactory(); }); return this; } useUI(): this { - this._inits.push(async () => { - Logger.info("initializing UI"); - - const root = document.getElementById("root"); - if (root === null) { - throw new Error("root element not found"); - } - - let ui = await import("chili-ui"); - ui.MainWindow.instance.init(this.storage(), root); - }); + this.#useUI = true; return this; } - private registerCommands() { - this._inits.push(async () => { - Logger.info("initializing commands"); + async build(): Promise { + for (const init of this.#inits) { + await init(); + } + this.ensureNecessary(); + + let app = Application.build( + this.#visualFactory!, + this.#shapeFactory!, + this.getServices(), + this.#storage! + ); + await this.loadUI(app); - let commands: any = await import("chili"); - let keys = Object.keys(commands); - for (const element of keys) { - let command = commands[element]; - let data = CommandData.get(command); - if (command.prototype?.execute !== undefined && data !== undefined) { - this._register.register(new Token(data.name), command); - } - } - }); + Logger.info("Application build completed"); } - async build(): Promise { - for (const element of this._inits) { - await element(); + private ensureNecessary() { + if (this.#shapeFactory === undefined) { + throw new Error("ShapeFactory not set"); + } + if (this.#visualFactory === undefined) { + throw new Error("VisualFactory not set"); + } + if (this.#storage === undefined) { + throw new Error("storage has not been initialized"); } - let services = this.getServices(); - Application.build(this._register.createResolve(), services, this.storage()); + } - Logger.info("Application build completed"); + private async loadUI(app: Application) { + if (this.#useUI) { + const root = document.getElementById("root"); + if (root === null) { + throw new Error("root element not found"); + } + let ui = await import("chili-ui"); + ui.MainWindow.instance.init(app, root); + } } private getServices(): IService[] { diff --git a/packages/chili-web/src/index.ts b/packages/chili-web/src/index.ts index d5d8fda6..b7948b2c 100644 --- a/packages/chili-web/src/index.ts +++ b/packages/chili-web/src/index.ts @@ -1,7 +1,5 @@ // Copyright 2022-2023 the Chili authors. All rights reserved. MPL-2.0 license. -import "reflect-metadata"; // 使用依赖注入时,必须导入 - import { Logger } from "chili-core"; import { AppBuilder } from "./appBuilder"; import { Loading } from "./loading"; diff --git a/packages/chili/src/application.ts b/packages/chili/src/application.ts index c51bc4de..d6524c21 100644 --- a/packages/chili/src/application.ts +++ b/packages/chili/src/application.ts @@ -1,61 +1,72 @@ // Copyright 2022-2023 the Chili authors. All rights reserved. MPL-2.0 license. -import { IDocument, IResolve, IService, IStorage, Logger, PubSub, Token } from "chili-core"; +import { Document } from "chili"; +import { IApplication, IDocument, IService, IStorage, Logger, PubSub, Serialized } from "chili-core"; import { IShapeFactory } from "chili-geo"; import { IVisualFactory } from "chili-vis"; -import { Document } from "chili"; - -export class Application { - private static _instance: Application | undefined; +export class Application implements IApplication { + static #instance: Application | undefined; static get instance() { - if (Application._instance === undefined) { + if (Application.#instance === undefined) { throw new Error("Application is not build"); } - return Application._instance; + return Application.#instance; } - static build(resolve: IResolve, services: IService[], storage: IStorage): Application { - if (this._instance) { + static build( + visualFactory: IVisualFactory, + shapeFactory: IShapeFactory, + services: IService[], + storage: IStorage + ): Application { + if (this.#instance) { Logger.warn("Application has been built"); } else { - this._instance = new Application(resolve, services, storage); + this.#instance = new Application(visualFactory, shapeFactory, services, storage); } - return this._instance; + return this.#instance; } - readonly visualFactory: IVisualFactory; - readonly shapeFactory: IShapeFactory; + private _activeDocument: IDocument | undefined; + get activeDocument(): IDocument | undefined { + return this._activeDocument; + } + set activeDocument(document: IDocument | undefined) { + if (this._activeDocument === document) return; + this._activeDocument = document; + PubSub.default.pub("activeDocumentChanged", document); + } private constructor( - readonly resolve: IResolve, + readonly visualFactory: IVisualFactory, + readonly shapeFactory: IShapeFactory, readonly services: IService[], readonly storage: IStorage ) { - this.visualFactory = this.resolveOrThrow(Token.VisulizationFactory); - this.shapeFactory = this.resolveOrThrow(Token.ShapeFactory); services.forEach((x) => x.register(this)); services.forEach((x) => x.start()); - - PubSub.default.sub("openDocument", async (id) => { - this.activeDocument = await Document.open(id); - }); } - private resolveOrThrow(token: Token): T { - let v = this.resolve.resolve(token); - if (v === undefined) throw new Error(`can not resolve ${token.token}`); - return v; + async openDocument(id: string): Promise { + await this.saveAndCloseActiveDocument(); + return (this.activeDocument = await Document.open(this, id)); } - private _activeDocument: IDocument | undefined; + async newDocument(name: string): Promise { + await this.saveAndCloseActiveDocument(); + return (this.activeDocument = new Document(this, name)); + } - get activeDocument(): IDocument | undefined { - return this._activeDocument; + async loadDocument(data: Serialized): Promise { + await this.saveAndCloseActiveDocument(); + return (this.activeDocument = Document.load(this, data)); } - set activeDocument(document: IDocument | undefined) { - this._activeDocument = document; - PubSub.default.pub("activeDocumentChanged", document); + private async saveAndCloseActiveDocument() { + if (this.activeDocument) { + await this.activeDocument.save(); + await this.activeDocument.close(); + } } } diff --git a/packages/chili/src/bodys/box.ts b/packages/chili/src/bodys/box.ts index 1cb81983..834a92e3 100644 --- a/packages/chili/src/bodys/box.ts +++ b/packages/chili/src/bodys/box.ts @@ -1,7 +1,6 @@ // Copyright 2022-2023 the Chili authors. All rights reserved. MPL-2.0 license. import { Body, I18n, IDocument, IShape, Plane, Property, Result, Serializer } from "chili-core"; -import { Application } from "../application"; export class BoxBody extends Body { readonly name: keyof I18n = "body.box"; @@ -72,6 +71,6 @@ export class BoxBody extends Body { } protected generateShape(): Result { - return Application.instance.shapeFactory.box(this.plane, this._dx, this._dy, this._dz); + return this.document.application.shapeFactory.box(this.plane, this._dx, this._dy, this._dz); } } diff --git a/packages/chili/src/bodys/circle.ts b/packages/chili/src/bodys/circle.ts index 55da352d..6a57a8cf 100644 --- a/packages/chili/src/bodys/circle.ts +++ b/packages/chili/src/bodys/circle.ts @@ -1,7 +1,6 @@ // Copyright 2022-2023 the Chili authors. All rights reserved. MPL-2.0 license. import { Body, I18n, IDocument, IShape, Property, Result, Serializer, XYZ } from "chili-core"; -import { Application } from "../application"; export class CircleBody extends Body { readonly name: keyof I18n = "body.circle"; @@ -58,6 +57,6 @@ export class CircleBody extends Body { } protected generateShape(): Result { - return Application.instance.shapeFactory.circle(this.normal, this._center, this._radius); + return this.document.application.shapeFactory.circle(this.normal, this._center, this._radius); } } diff --git a/packages/chili/src/bodys/line.ts b/packages/chili/src/bodys/line.ts index 367795eb..9bb28d3f 100644 --- a/packages/chili/src/bodys/line.ts +++ b/packages/chili/src/bodys/line.ts @@ -1,7 +1,6 @@ // Copyright 2022-2023 the Chili authors. All rights reserved. MPL-2.0 license. import { Body, I18n, IDocument, IShape, Property, Result, Serializer, XYZ } from "chili-core"; -import { Application } from "../application"; export class LineBody extends Body { readonly name: keyof I18n = "body.line"; @@ -40,6 +39,6 @@ export class LineBody extends Body { } protected generateShape(): Result { - return Application.instance.shapeFactory.line(this._start, this._end); + return this.document.application.shapeFactory.line(this._start, this._end); } } diff --git a/packages/chili/src/bodys/polygon.ts b/packages/chili/src/bodys/polygon.ts index e34f2b7d..27ab7a20 100644 --- a/packages/chili/src/bodys/polygon.ts +++ b/packages/chili/src/bodys/polygon.ts @@ -1,7 +1,6 @@ // Copyright 2022-2023 the Chili authors. All rights reserved. MPL-2.0 license. import { Entity, I18n, IDocument, IShape, Result, XYZ } from "chili-core"; -import { Application } from "../application"; export class PolygonBody extends Entity { private _points: XYZ[]; @@ -13,6 +12,6 @@ export class PolygonBody extends Entity { } protected generateShape(): Result { - return Application.instance.shapeFactory.polygon(...this._points); + return this.document.application.shapeFactory.polygon(...this._points); } } diff --git a/packages/chili/src/bodys/rect.ts b/packages/chili/src/bodys/rect.ts index ee5db464..18e76ffa 100644 --- a/packages/chili/src/bodys/rect.ts +++ b/packages/chili/src/bodys/rect.ts @@ -1,7 +1,6 @@ // Copyright 2022-2023 the Chili authors. All rights reserved. MPL-2.0 license. import { Body, I18n, IDocument, IShape, Plane, Property, Result, Serializer } from "chili-core"; -import { Application } from "../application"; export class RectBody extends Body { readonly name: keyof I18n = "body.rect"; @@ -45,6 +44,6 @@ export class RectBody extends Body { } protected generateShape(): Result { - return Application.instance.shapeFactory.rect(this.plane, this._dx, this._dy); + return this.document.application.shapeFactory.rect(this.plane, this._dx, this._dy); } } diff --git a/packages/chili/src/commands/application/newDocument.ts b/packages/chili/src/commands/application/newDocument.ts index 283e7e87..e9986955 100644 --- a/packages/chili/src/commands/application/newDocument.ts +++ b/packages/chili/src/commands/application/newDocument.ts @@ -1,8 +1,6 @@ // Copyright 2022-2023 the Chili authors. All rights reserved. MPL-2.0 license. -import { ICommand, command } from "chili-core"; -import { Document } from "../../document"; -import { Application } from "../../application"; +import { IApplication, ICommand, command } from "chili-core"; let count = 1; @@ -12,11 +10,7 @@ let count = 1; icon: "icon-new", }) export class NewDocument implements ICommand { - async execute(app: Application): Promise { - if (app.activeDocument) { - await app.activeDocument.close(); - } - let document = new Document(`undefined ${count}`); - app.activeDocument = document; + async execute(app: IApplication): Promise { + app.newDocument(`undefined ${count}`); } } diff --git a/packages/chili/src/commands/application/openDocument.ts b/packages/chili/src/commands/application/openDocument.ts index d5ed2a69..c0b5edf4 100644 --- a/packages/chili/src/commands/application/openDocument.ts +++ b/packages/chili/src/commands/application/openDocument.ts @@ -1,8 +1,6 @@ // Copyright 2022-2023 the Chili authors. All rights reserved. MPL-2.0 license. -import { ICommand, Serialized, command } from "chili-core"; -import { Document } from "../../document"; -import { Application } from "../../application"; +import { IApplication, ICommand, Serialized, command } from "chili-core"; @command({ name: "OpenDocument", @@ -10,25 +8,21 @@ import { Application } from "../../application"; icon: "icon-open", }) export class OpenDocument implements ICommand { - async execute(app: Application): Promise { + async execute(app: IApplication): Promise { let input = document.createElement("input"); - input.setAttribute("type", "file"); - input.setAttribute("style", "visibility:hidden"); - input.setAttribute("accept", ".cd"); + input.type = "file"; + input.style.visibility = "hidden"; + input.accept = ".cd"; input.onchange = () => { let file = input.files?.item(0); - if (file) { - let reader = new FileReader(); - reader.onload = async (e) => { - let data = e.target?.result as string; - let json: Serialized = JSON.parse(data); - if (app.activeDocument) { - await app.activeDocument.close(); - } - app.activeDocument = Document.load(json); - }; - reader.readAsText(file); - } + if (!file) return; + let reader = new FileReader(); + reader.onload = async (e) => { + let data = e.target?.result as string; + let json: Serialized = JSON.parse(data); + await app.loadDocument(json); + }; + reader.readAsText(file); }; document.body.appendChild(input); input.click(); diff --git a/packages/chili/src/commands/application/saveDocument.ts b/packages/chili/src/commands/application/saveDocument.ts index 52ecbaba..ba5668c9 100644 --- a/packages/chili/src/commands/application/saveDocument.ts +++ b/packages/chili/src/commands/application/saveDocument.ts @@ -1,7 +1,6 @@ // Copyright 2022-2023 the Chili authors. All rights reserved. MPL-2.0 license. -import { command, ICommand } from "chili-core"; -import { Application } from "../../application"; +import { command, IApplication, ICommand } from "chili-core"; @command({ name: "SaveDocument", @@ -9,8 +8,7 @@ import { Application } from "../../application"; icon: "icon-save", }) export class SaveDocument implements ICommand { - async execute(app: Application): Promise { - let document = app.activeDocument!; - await document.save(); + async execute(app: IApplication): Promise { + await app.activeDocument?.save(); } } diff --git a/packages/chili/src/commands/create/box.ts b/packages/chili/src/commands/create/box.ts index 4d08a4e1..357d8523 100644 --- a/packages/chili/src/commands/create/box.ts +++ b/packages/chili/src/commands/create/box.ts @@ -1,11 +1,10 @@ // Copyright 2022-2023 the Chili authors. All rights reserved. MPL-2.0 license. -import { command, IDocument, GeometryModel, Plane, XYZ } from "chili-core"; +import { GeometryModel, Plane, XYZ, command } from "chili-core"; import { BoxBody } from "../../bodys"; import { SnapLengthAtAxisData } from "../../snap"; import { IStep, LengthAtAxisStep } from "../../step"; import { RectCommandBase } from "./rect"; -import { Application } from "../../application"; @command({ name: "Box", @@ -32,20 +31,16 @@ export class Box extends RectCommandBase { private previewBox = (end: XYZ) => { let data = this.getRectData(end); return [ - Application.instance.shapeFactory.box( - data.plane, - data.dx, - data.dy, - this.getHeight(data.plane, end) - ).value?.mesh.edges!, + this.application.shapeFactory.box(data.plane, data.dx, data.dy, this.getHeight(data.plane, end)) + .value?.mesh.edges!, ]; }; - protected create(document: IDocument): GeometryModel { + protected create(): GeometryModel { let rect = this.getRectData(this.stepDatas[1].point); let dz = this.getHeight(rect.plane, this.stepDatas[2].point); - let body = new BoxBody(document, rect.plane, rect.dx, rect.dy, dz); - return new GeometryModel(document, `Box ${Box.count++}`, body); + let body = new BoxBody(this.document, rect.plane, rect.dx, rect.dy, dz); + return new GeometryModel(this.document, `Box ${Box.count++}`, body); } private getHeight(plane: Plane, point: XYZ): number { diff --git a/packages/chili/src/commands/create/circle.ts b/packages/chili/src/commands/create/circle.ts index d952c95e..9a9b4edc 100644 --- a/packages/chili/src/commands/create/circle.ts +++ b/packages/chili/src/commands/create/circle.ts @@ -1,13 +1,11 @@ // Copyright 2022-2023 the Chili authors. All rights reserved. MPL-2.0 license. -import { GeometryModel, IDocument, Plane, XYZ, command, injectable } from "chili-core"; +import { GeometryModel, Plane, XYZ, command } from "chili-core"; import { CircleBody } from "../../bodys"; import { SnapLengthAtPlaneData } from "../../snap"; import { IStep, LengthAtPlaneStep, PointStep } from "../../step"; import { CreateCommand } from "./createCommand"; -import { Application } from "../../application"; -@injectable() @command({ name: "Circle", display: "command.circle", @@ -34,18 +32,18 @@ export class Circle extends CreateCommand { }; }; - create(document: IDocument): GeometryModel { + create(): GeometryModel { let [p1, p2] = [this.stepDatas[0].point, this.stepDatas[1].point]; let plane = this.stepDatas[0].view.workplane; - let body = new CircleBody(document, plane.normal, p1, this.getDistanceAtPlane(plane, p1, p2)); - return new GeometryModel(document, `Circle ${Circle.count++}`, body); + let body = new CircleBody(this.document, plane.normal, p1, this.getDistanceAtPlane(plane, p1, p2)); + return new GeometryModel(this.document, `Circle ${Circle.count++}`, body); } private circlePreview = (point: XYZ) => { let start = this.stepDatas[0].point; let plane = this.stepDatas[0].view.workplane; return [ - Application.instance.shapeFactory.circle( + this.application.shapeFactory.circle( plane.normal, start, this.getDistanceAtPlane(plane, start, point) diff --git a/packages/chili/src/commands/create/createCommand.ts b/packages/chili/src/commands/create/createCommand.ts index b2548e6a..82aa0ea2 100644 --- a/packages/chili/src/commands/create/createCommand.ts +++ b/packages/chili/src/commands/create/createCommand.ts @@ -1,16 +1,16 @@ // Copyright 2022-2023 the Chili authors. All rights reserved. MPL-2.0 license. -import { GeometryModel, IDocument, Transaction } from "chili-core"; +import { GeometryModel, Transaction } from "chili-core"; import { MultistepCommand } from "../multistepCommand"; export abstract class CreateCommand extends MultistepCommand { - protected override executeMainTask(document: IDocument) { - Transaction.excute(document, `excute ${Object.getPrototypeOf(this).data.name}`, () => { - let model = this.create(document); - document.addNode(model); - document.visual.viewer.redraw(); + protected override executeMainTask() { + Transaction.excute(this.document, `excute ${Object.getPrototypeOf(this).data.name}`, () => { + let model = this.create(); + this.document.addNode(model); + this.document.visual.viewer.redraw(); }); } - protected abstract create(document: IDocument): GeometryModel; + protected abstract create(): GeometryModel; } diff --git a/packages/chili/src/commands/create/line.ts b/packages/chili/src/commands/create/line.ts index c224b190..1331500a 100644 --- a/packages/chili/src/commands/create/line.ts +++ b/packages/chili/src/commands/create/line.ts @@ -1,11 +1,10 @@ // Copyright 2022-2023 the Chili authors. All rights reserved. MPL-2.0 license. -import { GeometryModel, IDocument, Precision, Property, XYZ, command } from "chili-core"; +import { GeometryModel, Precision, Property, XYZ, command } from "chili-core"; import { LineBody } from "../../bodys"; import { Dimension, SnapPointData } from "../../snap"; import { IStep, PointStep } from "../../step"; import { CreateCommand } from "./createCommand"; -import { Application } from "../../application"; @command({ name: "Line", @@ -52,9 +51,9 @@ export class Line extends CreateCommand { this.setProperty("isContinue", value); } - create(document: IDocument): GeometryModel { - let body = new LineBody(document, this.stepDatas[0].point, this.stepDatas[1].point); - return new GeometryModel(document, `Line ${Line.count++}`, body); + create(): GeometryModel { + let body = new LineBody(this.document, this.stepDatas[0].point, this.stepDatas[1].point); + return new GeometryModel(this.document, `Line ${Line.count++}`, body); } getSteps(): IStep[] { @@ -76,7 +75,7 @@ export class Line extends CreateCommand { }; private linePreview = (point: XYZ) => { - return [Application.instance.shapeFactory.line(this.stepDatas[0].point, point).value?.mesh.edges!]; + return [this.application.shapeFactory.line(this.stepDatas[0].point, point).value?.mesh.edges!]; }; private xlinePreview = (point: XYZ) => { @@ -88,6 +87,6 @@ export class Line extends CreateCommand { let vector = point.sub(this.stepDatas[0].point).normalize()!.multiply(1e6); let start = this.stepDatas[0].point.sub(vector); let end = this.stepDatas[0].point.add(vector); - return Application.instance.shapeFactory.line(start, end).value; + return this.application.shapeFactory.line(start, end).value; } } diff --git a/packages/chili/src/commands/create/rect.ts b/packages/chili/src/commands/create/rect.ts index feba5cff..1601cd43 100644 --- a/packages/chili/src/commands/create/rect.ts +++ b/packages/chili/src/commands/create/rect.ts @@ -5,7 +5,6 @@ import { RectBody } from "../../bodys"; import { SnapLengthAtPlaneData } from "../../snap"; import { IStep, LengthAtPlaneStep, PointStep } from "../../step"; import { CreateCommand } from "./createCommand"; -import { Application } from "../../application"; export interface RectData { plane: Plane; @@ -50,7 +49,7 @@ export abstract class RectCommandBase extends CreateCommand { private previewRect = (end: XYZ) => { let data = this.getRectData(end); - return [Application.instance.shapeFactory.rect(data.plane, data.dx, data.dy).value?.mesh.edges!]; + return [this.application.shapeFactory.rect(data.plane, data.dx, data.dy).value?.mesh.edges!]; }; protected getRectData(point: XYZ): RectData { @@ -67,10 +66,10 @@ export abstract class RectCommandBase extends CreateCommand { export class Rect extends RectCommandBase { private static count: number = 1; - protected create(document: IDocument): GeometryModel { + protected create(): GeometryModel { let rect = this.getRectData(this.stepDatas[1].point); - let body = new RectBody(document, rect.plane, rect.dx, rect.dy); - return new GeometryModel(document, `Rect ${Rect.count++}`, body); + let body = new RectBody(this.document, rect.plane, rect.dx, rect.dy); + return new GeometryModel(this.document, `Rect ${Rect.count++}`, body); } constructor() { diff --git a/packages/chili/src/commands/delete.ts b/packages/chili/src/commands/delete.ts index 08137cae..57ff3b06 100644 --- a/packages/chili/src/commands/delete.ts +++ b/packages/chili/src/commands/delete.ts @@ -1,7 +1,6 @@ // Copyright 2022-2023 the Chili authors. All rights reserved. MPL-2.0 license. -import { command, ICommand, Transaction } from "chili-core"; -import { Application } from "../application"; +import { command, IApplication, ICommand, Transaction } from "chili-core"; @command({ name: "Delete", @@ -9,7 +8,7 @@ import { Application } from "../application"; icon: "icon-redo", }) export class Delete implements ICommand { - async execute(app: Application): Promise { + async execute(app: IApplication): Promise { let document = app.activeDocument; if (document === undefined) return; Transaction.excute(document, "delete", () => { diff --git a/packages/chili/src/commands/folder.ts b/packages/chili/src/commands/folder.ts index 17187f66..e7f22b60 100644 --- a/packages/chili/src/commands/folder.ts +++ b/packages/chili/src/commands/folder.ts @@ -1,7 +1,6 @@ // Copyright 2022-2023 the Chili authors. All rights reserved. MPL-2.0 license. -import { command, ICommand, NodeLinkedList } from "chili-core"; -import { Application } from "../application"; +import { command, IApplication, ICommand, NodeLinkedList } from "chili-core"; let index: number = 1; @@ -11,7 +10,7 @@ let index: number = 1; icon: "icon-folder-plus", }) export class NewFolder implements ICommand { - async execute(app: Application): Promise { + async execute(app: IApplication): Promise { let document = app.activeDocument!; let folder = new NodeLinkedList(document, `Folder${index++}`); document.addNode(folder); diff --git a/packages/chili/src/commands/modify/array.ts b/packages/chili/src/commands/modify/array.ts index 66ce0cc2..62cea8f8 100644 --- a/packages/chili/src/commands/modify/array.ts +++ b/packages/chili/src/commands/modify/array.ts @@ -60,11 +60,13 @@ export class Array extends MultistepCommand { ]; }; - protected override async beforeExecute(document: IDocument): Promise { - this.models = document.selection.getSelectedNodes().filter((x) => INode.isModelNode(x)) as IModel[]; + protected override async beforeExecute(): Promise { + this.models = this.document.selection + .getSelectedNodes() + .filter((x) => INode.isModelNode(x)) as IModel[]; if (this.models.length === 0) { this.token = new AsyncState(); - this.models = await Selection.pickModel(document, "axis.x", this.token); + this.models = await Selection.pickModel(this.document, "axis.x", this.token); if (this.restarting || this.models.length === 0) return false; } this.positions = []; @@ -75,14 +77,14 @@ export class Array extends MultistepCommand { return true; } - protected executeMainTask(document: IDocument): void { - Transaction.excute(document, `excute ${Object.getPrototypeOf(this).data.name}`, () => { + protected executeMainTask(): void { + Transaction.excute(this.document, `excute ${Object.getPrototypeOf(this).data.name}`, () => { let vec = this.stepDatas[1].point.sub(this.stepDatas[0].point); let transform = Matrix4.createTranslation(vec.x, vec.y, vec.z); this.models?.forEach((x) => { x.matrix = x.matrix.multiply(transform); }); - document.visual.viewer.redraw(); + this.document.visual.viewer.redraw(); }); } } diff --git a/packages/chili/src/commands/modify/transformedCommand.ts b/packages/chili/src/commands/modify/transformedCommand.ts index 7aa91f65..626593c2 100644 --- a/packages/chili/src/commands/modify/transformedCommand.ts +++ b/packages/chili/src/commands/modify/transformedCommand.ts @@ -48,12 +48,14 @@ export abstract class TransformedCommand extends MultistepCommand { return EdgeMeshData.from(start, end, Config.instance.visual.temporaryEdgeColor, LineType.Solid); } - protected override async beforeExecute(document: IDocument): Promise { - await super.beforeExecute(document); - this.models = document.selection.getSelectedNodes().filter((x) => INode.isModelNode(x)) as IModel[]; + protected override async beforeExecute(): Promise { + await super.beforeExecute(); + this.models = this.document.selection + .getSelectedNodes() + .filter((x) => INode.isModelNode(x)) as IModel[]; if (this.models.length === 0) { this.token = new AsyncState(); - this.models = await Selection.pickModel(document, "prompt.select.models", this.token); + this.models = await Selection.pickModel(this.document, "prompt.select.models", this.token); if (this.restarting || this.models.length === 0) { alert(i18n["prompt.select.noModelSelected"]); return false; @@ -68,8 +70,8 @@ export abstract class TransformedCommand extends MultistepCommand { return true; } - protected executeMainTask(document: IDocument): void { - Transaction.excute(document, `excute ${Object.getPrototypeOf(this).data.name}`, () => { + protected executeMainTask(): void { + Transaction.excute(this.document, `excute ${Object.getPrototypeOf(this).data.name}`, () => { let transform = this.transfrom(this.stepDatas.at(-1)!.point); let models = this.models; if (this.isClone) { @@ -78,7 +80,7 @@ export abstract class TransformedCommand extends MultistepCommand { models?.forEach((x) => { x.matrix = x.matrix.multiply(transform); }); - document.visual.viewer.redraw(); + this.document.visual.viewer.redraw(); }); } } diff --git a/packages/chili/src/commands/multistepCommand.ts b/packages/chili/src/commands/multistepCommand.ts index 82026c12..9d3832a2 100644 --- a/packages/chili/src/commands/multistepCommand.ts +++ b/packages/chili/src/commands/multistepCommand.ts @@ -1,15 +1,26 @@ // Copyright 2022-2023 the Chili authors. All rights reserved. MPL-2.0 license. -import { AsyncState, ICommand, IDocument, Observable, Property, PubSub } from "chili-core"; +import { AsyncState, IApplication, ICommand, Observable, Property, PubSub } from "chili-core"; import { SnapedData } from "../snap"; import { IStep } from "../step"; -import { Application } from "../application"; const PropertiesCache: Map = new Map(); // 所有命令共享 export abstract class MultistepCommand extends Observable implements ICommand { protected stepDatas: SnapedData[] = []; + #application: IApplication | undefined; + get application() { + if (!this.#application) { + throw new Error("application is not set"); + } + return this.#application; + } + + get document() { + return this.#application!.activeDocument!; + } + private _restarting: boolean = false; protected get restarting() { return this._restarting; @@ -45,35 +56,37 @@ export abstract class MultistepCommand extends Observable implements ICommand { this.setProperty("repeatOperation", value); } - async execute(application: Application): Promise { - await this.executeFromStep(application.activeDocument!, 0); + async execute(application: IApplication): Promise { + if (!application.activeDocument) return; + this.#application = application; + await this.executeFromStep(0); } - protected async executeFromStep(document: IDocument, stepIndex: number): Promise { + protected async executeFromStep(stepIndex: number): Promise { if (this._restarting) { this._restarting = false; } let isCancel = false; try { - if ((await this.beforeExecute(document)) && (await this.executeSteps(document, stepIndex))) { - this.executeMainTask(document); + if ((await this.beforeExecute()) && (await this.executeSteps(stepIndex))) { + this.executeMainTask(); } else { isCancel = true; } } finally { - await this.afterExecute(document); + await this.afterExecute(); } if (this._restarting || (this.repeatOperation && !isCancel)) { - await this.executeFromStep(document, 0); + await this.executeFromStep(0); } } - private async executeSteps(document: IDocument, startIndex: number): Promise { + private async executeSteps(startIndex: number): Promise { this.stepDatas.length = startIndex; let steps = this.getSteps(); for (let i = startIndex; i < steps.length; i++) { this.token = new AsyncState(); - let data = await steps[i].execute(document, this.token); + let data = await steps[i].execute(this.document, this.token); if (this._restarting || data === undefined) { return false; } @@ -84,15 +97,15 @@ export abstract class MultistepCommand extends Observable implements ICommand { protected abstract getSteps(): IStep[]; - protected abstract executeMainTask(document: IDocument): void; + protected abstract executeMainTask(): void; - protected beforeExecute(document: IDocument): Promise { + protected beforeExecute(): Promise { this.readProperties(); PubSub.default.pub("openContextTab", this); return Promise.resolve(true); } - protected afterExecute(document: IDocument): Promise { + protected afterExecute(): Promise { this.saveProperties(); PubSub.default.pub("closeContextTab"); this.token?.dispose(); diff --git a/packages/chili/src/commands/redo.ts b/packages/chili/src/commands/redo.ts index f9b68d4b..49aabcec 100644 --- a/packages/chili/src/commands/redo.ts +++ b/packages/chili/src/commands/redo.ts @@ -1,7 +1,6 @@ // Copyright 2022-2023 the Chili authors. All rights reserved. MPL-2.0 license. -import { command, ICommand } from "chili-core"; -import { Application } from "../application"; +import { command, IApplication, ICommand } from "chili-core"; @command({ name: "Redo", @@ -9,7 +8,7 @@ import { Application } from "../application"; icon: "icon-redo", }) export class Redo implements ICommand { - async execute(app: Application): Promise { + async execute(app: IApplication): Promise { let document = app.activeDocument!; document.selection.clearSelected(); document.history.redo(); diff --git a/packages/chili/src/commands/undo.ts b/packages/chili/src/commands/undo.ts index fb19b861..37f8291a 100644 --- a/packages/chili/src/commands/undo.ts +++ b/packages/chili/src/commands/undo.ts @@ -1,7 +1,6 @@ // Copyright 2022-2023 the Chili authors. All rights reserved. MPL-2.0 license. -import { command, ICommand } from "chili-core"; -import { Application } from "../application"; +import { command, IApplication, ICommand } from "chili-core"; @command({ name: "Undo", @@ -9,7 +8,7 @@ import { Application } from "../application"; icon: "icon-undo", }) export class Undo implements ICommand { - async execute(application: Application): Promise { + async execute(application: IApplication): Promise { let document = application.activeDocument!; document.selection.clearSelected(); document.history.undo(); diff --git a/packages/chili/src/document.ts b/packages/chili/src/document.ts index fa3435b2..d7cef828 100644 --- a/packages/chili/src/document.ts +++ b/packages/chili/src/document.ts @@ -3,6 +3,7 @@ import { Constants, History, + IApplication, IDocument, IModel, INode, @@ -20,7 +21,6 @@ import { Serialized, Serializer, } from "chili-core"; -import { Application } from "./application"; export class Document extends Observable implements IDocument, ISerialize { readonly visual: IVisual; @@ -28,7 +28,6 @@ export class Document extends Observable implements IDocument, ISerialize { readonly selection: SelectionManager; private _name: string; - get name(): string { return this._name; } @@ -37,7 +36,6 @@ export class Document extends Observable implements IDocument, ISerialize { } private _rootNode: INodeLinkedList | undefined; - get rootNode(): INodeLinkedList { if (this._rootNode === undefined) { this._rootNode = new NodeLinkedList(this, this._name); @@ -46,20 +44,18 @@ export class Document extends Observable implements IDocument, ISerialize { } private _currentNode?: INodeLinkedList; - get currentNode(): INodeLinkedList | undefined { return this._currentNode; } - set currentNode(value: INodeLinkedList | undefined) { this.setProperty("currentNode", value); } - constructor(name: string, readonly id: string = Id.new()) { + constructor(readonly application: IApplication, name: string, readonly id: string = Id.new()) { super(); this._name = name; this.history = new History(); - this.visual = Application.instance.visualFactory.create(this); + this.visual = application.visualFactory.create(this); this.selection = new SelectionManager(this); PubSub.default.sub("nodeLinkedListChanged", this.handleModelChanged); Logger.info(`new document: ${name}`); @@ -90,9 +86,9 @@ export class Document extends Observable implements IDocument, ISerialize { async save() { let data = this.serialize(); - await Application.instance.storage.put(Constants.DBName, Constants.DocumentTable, this.id, data); + await this.application.storage.put(Constants.DBName, Constants.DocumentTable, this.id, data); let image = await this.visual.viewer.activeView?.toImage(); - await Application.instance.storage.put(Constants.DBName, Constants.RecentTable, this.id, { + await this.application.storage.put(Constants.DBName, Constants.RecentTable, this.id, { id: this.id, name: this.name, date: Date.now(), @@ -105,10 +101,11 @@ export class Document extends Observable implements IDocument, ISerialize { this.dispose(); Logger.info(`document: ${this._name} closed`); PubSub.default.pub("documentClosed", this); + this.application.activeDocument = undefined; } - static async open(id: string) { - let data = (await Application.instance.storage.get( + static async open(application: IApplication, id: string) { + let data = (await application.storage.get( Constants.DBName, Constants.DocumentTable, id @@ -117,13 +114,17 @@ export class Document extends Observable implements IDocument, ISerialize { Logger.warn(`document: ${id} not find`); return; } - let document = this.load(data); + let document = this.load(application, data); Logger.info(`document: ${document.name} opened`); return document; } - static load(data: Serialized) { - let document = new Document(data.constructorParameters["name"], data.constructorParameters["id"]); + static load(app: IApplication, data: Serialized) { + let document = new Document( + app, + data.constructorParameters["name"], + data.constructorParameters["id"] + ); document.history.disabled = true; document._rootNode = Serializer.deserialize(document, data.properties["rootNode"]); document.history.disabled = false; diff --git a/packages/chili/src/editors/circleEditor.ts b/packages/chili/src/editors/circleEditor.ts index 856651c7..3f1da68b 100644 --- a/packages/chili/src/editors/circleEditor.ts +++ b/packages/chili/src/editors/circleEditor.ts @@ -4,7 +4,6 @@ import { IDocument, Plane, XYZ } from "chili-core"; import { CircleBody } from "../bodys"; import { Dimension, LengthAtPlaneSnapper, PointSnapper, Snapper } from "../snap"; import { EditorEventHandler, FeaturePoint } from "./eventHandler"; -import { Application } from "../application"; export class CircleEditorEventHandler extends EditorEventHandler { private xVector: XYZ; @@ -62,7 +61,7 @@ export class CircleEditorEventHandler extends EditorEventHandler { }; private circlePreview = (c: XYZ, r: number) => { - return [Application.instance.shapeFactory.circle(this.circle.normal, c, r).value!.mesh.edges!]; + return [this.document.application.shapeFactory.circle(this.circle.normal, c, r).value!.mesh.edges!]; }; private getRadiusPoint() { diff --git a/packages/chili/src/editors/lineEditor.ts b/packages/chili/src/editors/lineEditor.ts index 076d465c..cd651436 100644 --- a/packages/chili/src/editors/lineEditor.ts +++ b/packages/chili/src/editors/lineEditor.ts @@ -4,7 +4,6 @@ import { IDocument, XYZ } from "chili-core"; import { LineBody } from "../bodys"; import { Dimension, PointSnapper, Snapper } from "../snap"; import { EditorEventHandler, FeaturePoint } from "./eventHandler"; -import { Application } from "../application"; export class LineEditorEventHandler extends EditorEventHandler { protected points: FeaturePoint[]; @@ -42,6 +41,6 @@ export class LineEditorEventHandler extends EditorEventHandler { } private linePreview = (s: XYZ, e: XYZ) => { - return [Application.instance.shapeFactory.line(s, e).value!.mesh.edges!]; + return [this.document.application.shapeFactory.line(s, e).value!.mesh.edges!]; }; } diff --git a/packages/chili/src/index.ts b/packages/chili/src/index.ts index 23c2f470..3d973be0 100644 --- a/packages/chili/src/index.ts +++ b/packages/chili/src/index.ts @@ -1,5 +1,6 @@ // Copyright 2022-2023 the Chili authors. All rights reserved. MPL-2.0 license. +export * from "./application"; export * from "./bodys"; export * from "./commands"; export * from "./comparers"; diff --git a/packages/chili/src/services/commandService.ts b/packages/chili/src/services/commandService.ts index b56c42eb..393d0845 100644 --- a/packages/chili/src/services/commandService.ts +++ b/packages/chili/src/services/commandService.ts @@ -1,8 +1,17 @@ // Copyright 2022-2023 the Chili authors. All rights reserved. MPL-2.0 license. -import { Commands, ICommand, IService, Lazy, Logger, PubSub, Token } from "chili-core"; +import { + Command, + Commands, + IApplication, + ICommand, + IService, + Lazy, + Logger, + PubSub, + Token, +} from "chili-core"; import { NewDocument, OpenDocument } from "../commands"; -import { Application } from "../application"; export class CommandService implements IService { private static readonly _lazy = new Lazy(() => new CommandService()); @@ -14,9 +23,9 @@ export class CommandService implements IService { private _lastCommand: keyof Commands | undefined; private _executingCommand: keyof Commands | undefined; - private _app: Application | undefined; + private _app: IApplication | undefined; - private get app(): Application { + private get app(): IApplication { if (this._app === undefined) { throw new Error("Executor is not initialized"); } @@ -35,7 +44,7 @@ export class CommandService implements IService { Logger.info(`${CommandService.name} stoped`); } - register(app: Application) { + register(app: IApplication) { this._app = app; Logger.info(`${CommandService.name} registed`); } @@ -53,7 +62,8 @@ export class CommandService implements IService { }; private async executeAsync(commandName: keyof Commands) { - let command = this.app.resolve.resolve(new Token(commandName))!; + let commandCtor = Command.get(commandName)!; + let command = new commandCtor(); this._executingCommand = commandName; await command .execute(this.app) @@ -66,20 +76,18 @@ export class CommandService implements IService { }); } - private canExecute(commandName: string) { + private canExecute(commandName: keyof Commands) { if (this._executingCommand) { Logger.warn(`command ${this._executingCommand} is executing`); return false; } - if ( - ![OpenDocument.name, NewDocument.name].includes(commandName) && - this.app.activeDocument === undefined - ) { + let appCommands: (keyof Commands)[] = ["OpenDocument", "NewDocument"]; + if (!appCommands.includes(commandName) && this.app.activeDocument === undefined) { Logger.error("No active document"); return false; } - if (!this.app.resolve.has(new Token(commandName))) { - Logger.error(`Unregistered dependency token: ${commandName}`); + if (!Command.get(commandName)) { + Logger.error(`Can not find ${commandName} command`); return false; } return true; diff --git a/packages/chili/src/services/editorService.ts b/packages/chili/src/services/editorService.ts index eea1301e..8f23d50e 100644 --- a/packages/chili/src/services/editorService.ts +++ b/packages/chili/src/services/editorService.ts @@ -1,10 +1,9 @@ // Copyright 2022-2023 the Chili authors. All rights reserved. MPL-2.0 license. -import { IDocument, PubSub, IService, Logger, Lazy, INode } from "chili-core"; +import { IApplication, IDocument, INode, IService, Lazy, Logger, PubSub } from "chili-core"; import { CircleBody, LineBody } from "../bodys"; import { EditorEventHandler, LineEditorEventHandler } from "../editors"; import { CircleEditorEventHandler } from "../editors/circleEditor"; -import { Application } from "../application"; export class EditorService implements IService { private static readonly _lazy = new Lazy(() => new EditorService()); @@ -15,7 +14,7 @@ export class EditorService implements IService { private handler?: EditorEventHandler; - register(_app: Application): void { + register(_app: IApplication): void { Logger.info(`${EditorService.name} registed`); } diff --git a/packages/chili/src/services/hotkeyService.ts b/packages/chili/src/services/hotkeyService.ts index d41667f8..970fe79b 100644 --- a/packages/chili/src/services/hotkeyService.ts +++ b/packages/chili/src/services/hotkeyService.ts @@ -1,7 +1,6 @@ // Copyright 2022-2023 the Chili authors. All rights reserved. MPL-2.0 license. -import { Commands, Lazy, Logger, PubSub, IService } from "chili-core"; -import { Application } from "../application"; +import { IApplication, Commands, IService, Lazy, Logger, PubSub } from "chili-core"; export interface Keys { key: string; @@ -29,7 +28,7 @@ export class HotkeyService implements IService { return this._lazy.value; } - private app?: Application; + private app?: IApplication; private readonly _keyMap = new Map(); private constructor() { @@ -38,7 +37,7 @@ export class HotkeyService implements IService { this.addMap(DefaultKeyMap); } - register(app: Application): void { + register(app: IApplication): void { this.app = app; Logger.info(`${HotkeyService.name} registed`); } diff --git a/packages/chili/test/service.test.ts b/packages/chili/test/service.test.ts deleted file mode 100644 index f01224be..00000000 --- a/packages/chili/test/service.test.ts +++ /dev/null @@ -1,23 +0,0 @@ -// Copyright 2022-2023 the Chili authors. All rights reserved. MPL-2.0 license. - -import "reflect-metadata"; - -import { Container, Token } from "chili-core"; - -class TestClass { - constructor() {} -} - -test("test service", () => { - let collection = new Container(); - let t1 = new Token("t1"); - let t2 = new Token("t2"); - collection.register(t1, TestClass); - collection.registerSingleton(t2, TestClass); - let c11 = collection.resolve(t1); - let c12 = collection.resolve(t1); - expect(c11 === c12).toBeFalsy(); - let c21 = collection.resolve(t2); - let c22 = collection.resolve(t2); - expect(c21 === c22).toBeTruthy(); -});