diff --git a/app/main.ts b/app/main.ts index 7f9f75d..0668026 100644 --- a/app/main.ts +++ b/app/main.ts @@ -57,7 +57,7 @@ function createWindow(): BrowserWindow { { label: "Gamesystem", click: () => { - win!.webContents.send('context-menu', "new-location"); + win!.webContents.send('context-menu', "new-gamesystem"); } }, { diff --git a/e2e/game-model/gamesystems/CreateGamesystem.spec.ts b/e2e/game-model/gamesystems/CreateGamesystem.spec.ts new file mode 100644 index 0000000..84e01c5 --- /dev/null +++ b/e2e/game-model/gamesystems/CreateGamesystem.spec.ts @@ -0,0 +1,53 @@ +import { BrowserContext, ElectronApplication, Page, _electron as electron } from 'playwright'; +import { test, expect } from '@playwright/test'; +import * as PATH from 'path'; +import {GameModel} from "../../../src/app/game-model/GameModel"; +import {Gamesystem} from "../../src/app/game-model/gamesystems/Gamesystem"; +import {ScriptAccount} from "../../../src/app/game-model/scriptAccounts/ScriptAccount"; +import {ModelComponentType} from "../../../src/app/game-model/ModelComponentType"; +import {SimpleGamesystem} from "../../../src/app/game-model/gamesystems/SimpleGamesystem"; +import exp = require("node:constants"); +import {end} from "electron-debug"; +import {GamesystemTrainer} from "./GamesystemTrainer"; +import {ProductGamesystem} from "../../../src/app/game-model/gamesystems/ProductGamesystem"; +test.describe('Test Create Gamesystems', () => { + + test('Test creating gamesystem with invalid name', async => { + const gameModel = GamesystemTrainer.givenEmptyGameModel(); + let result = gameModel.createGamesystem(undefined, undefined); + expect(result).toBeUndefined(); + + result = gameModel.createGamesystem(null, undefined); + expect(result).toBeUndefined(); + }) + + test("Test creating gamesystem with valid name but without parent", async => { + const gameModel = GamesystemTrainer.givenEmptyGameModel(); + let result = gameModel.createGamesystem(GamesystemTrainer.SIMPLEGAMESYSTEMNAME, undefined); + expect(result).toBeDefined(); + expect(gameModel.gamesystems.length).toEqual(1); + expect(gameModel.findGamesystem(GamesystemTrainer.SIMPLEGAMESYSTEMNAME)).toBeDefined(); + }) + + test("Test creating Gamesystem with valid name but with Product Parent", async => { + const gameModel = GamesystemTrainer.givenGameModelWithProductGamesytemOnTopLayer(); + let result = gameModel.createGamesystem(GamesystemTrainer.SIMPLEGAMESYSTEM_LEAF_LEFT, GamesystemTrainer.TOP_PRODUCT_GAMESYSTEM_NAME); + expect(result).toBeDefined(); + expect(result.parentGamesystem!.componentName).toEqual(GamesystemTrainer.TOP_PRODUCT_GAMESYSTEM_NAME); + expect(result.parentGamesystem!.innerGamesystems.length).toEqual(3); + expect(result.parentGamesystem!.innerGamesystems.includes(result)).toBeTruthy(); + }) + + test("Test creating Gamesystem with valid name but with Simple Parent", async() => { + const gameModel = GamesystemTrainer.givenGameModelWithSimpleGamesystemOnTopLayer(); + let result = gameModel.createGamesystem(GamesystemTrainer.SIMPLEGAMESYSTEM_LEAF_LEFT, GamesystemTrainer.SIMPLEGAMESYSTEMNAME); + expect(result).toBeDefined(); + expect(gameModel.gamesystems.length).toEqual(1); + expect(gameModel.gamesystems[0]).toBeInstanceOf(ProductGamesystem); + expect(gameModel.gamesystems[0]).toEqual(result.parentGamesystem); + expect((gameModel.gamesystems[0] as ProductGamesystem).innerGamesystems.length).toEqual(1); + expect((gameModel.gamesystems[0] as ProductGamesystem).innerGamesystems.includes(result)).toBeTruthy(); + }) + + +}); diff --git a/e2e/game-model/gamesystems/GamesystemTrainer.ts b/e2e/game-model/gamesystems/GamesystemTrainer.ts index 8b2055f..515882e 100644 --- a/e2e/game-model/gamesystems/GamesystemTrainer.ts +++ b/e2e/game-model/gamesystems/GamesystemTrainer.ts @@ -9,6 +9,9 @@ export class GamesystemTrainer { static TOP_PRODUCT_GAMESYSTEM_NAME: string = "Top Product Gamesystem" static SIMPLEGAMESYSTEM2: string = "Simple Gamesystem Leaf 2"; + static SIMPLEGAMESYSTEM_LEAF_LEFT: string = "Leaf Gamesystem Left" + static SIMPLEGAMESYSTEM_LEAF_RIGHT: string = "Leaf Gamesystem Right"; + static givenEmptyGameModel() { return new GameModel(GamesystemTrainer.GAMEMODELNAME); } @@ -33,5 +36,20 @@ export class GamesystemTrainer { return gameModel; } + static givenGameModelWithProductGamesystemOnLowerLayer() { + const gameModel = new GameModel(GamesystemTrainer.GAMEMODELNAME); + const top_productGamesystem = new ProductGamesystem(this.TOP_PRODUCT_GAMESYSTEM_NAME); + const leaf1 = new ProductGamesystem(this.SIMPLEGAMESYSTEMNAME); + const leaf2 = new SimpleGamesystem(this.SIMPLEGAMESYSTEM2); + top_productGamesystem.innerGamesystems.push(leaf1); + top_productGamesystem.innerGamesystems.push(leaf2); + gameModel.addGamesystem(top_productGamesystem); + + const leaf_1_1 = new SimpleGamesystem(this.SIMPLEGAMESYSTEM_LEAF_LEFT); + leaf1.addChildGamesystem(leaf_1_1); + const leaf_1_2 = new SimpleGamesystem(this.SIMPLEGAMESYSTEM_LEAF_RIGHT); + leaf1.addChildGamesystem(leaf_1_2); + } + } diff --git a/e2e/game-model/scriptAccounts/ScriptAccountTest.spec.ts b/e2e/game-model/scriptAccounts/ScriptAccountTest.spec.ts index c7eb65b..00688ac 100644 --- a/e2e/game-model/scriptAccounts/ScriptAccountTest.spec.ts +++ b/e2e/game-model/scriptAccounts/ScriptAccountTest.spec.ts @@ -21,24 +21,24 @@ test.describe('Test ScriptAccounts', () => { test("Test Adding ScriptAccounts", async () => { const gameModel: GameModel = new GameModel("GameModel"); - let scriptAccount =gameModel.addScriptAccount("ScriptAccount"); + let scriptAccount =gameModel.createScriptAccount("ScriptAccount"); expect(scriptAccount).toBeDefined(); expect(gameModel.scriptAccounts.length).toEqual(1); expect(gameModel.scriptAccounts.includes(scriptAccount)).toBeTruthy(); //Test adding scriptAccount with already existing name - const scriptAccount2 = gameModel.addScriptAccount("ScriptAccount") + const scriptAccount2 = gameModel.createScriptAccount("ScriptAccount") expect(scriptAccount2).toBeUndefined(); expect(gameModel.scriptAccounts.length).toEqual(1); //Test for adding invalid names as scriptaccount names (null/undefined/empty) - let result = gameModel.addScriptAccount(null); + let result = gameModel.createScriptAccount(null); expect(result).toBeUndefined(); expect(gameModel.scriptAccounts.length).toEqual(1); - result = gameModel.addScriptAccount(undefined); + result = gameModel.createScriptAccount(undefined); expect(result).toBeUndefined(); expect(gameModel.scriptAccounts.length).toEqual(1); - result = gameModel.addScriptAccount(""); + result = gameModel.createScriptAccount(""); expect(result).toBeUndefined(); expect(gameModel.scriptAccounts.length).toEqual(1); }) @@ -50,7 +50,7 @@ test.describe('Test ScriptAccounts', () => { gameModel.removeScriptAccount(scriptAccount); expect(gameModel.scriptAccounts.length).toEqual(0); - scriptAccount = gameModel.addScriptAccount("ScriptAccount"); + scriptAccount = gameModel.createScriptAccount("ScriptAccount"); gameModel.removeScriptAccount(scriptAccount); expect(gameModel.scriptAccounts.length).toEqual(0); @@ -60,8 +60,8 @@ test.describe('Test ScriptAccounts', () => { gameModel.removeScriptAccount(null); expect(gameModel.scriptAccounts.length).toEqual(0); - scriptAccount = gameModel.addScriptAccount(scriptAccount); - let scriptAccount2 = gameModel.addScriptAccount("ScriptAccount 2"); + scriptAccount = gameModel.createScriptAccount(scriptAccount); + let scriptAccount2 = gameModel.createScriptAccount("ScriptAccount 2"); gameModel.removeScriptAccount(scriptAccount); expect(gameModel.scriptAccounts.length).toEqual(1); diff --git a/src/app/app.component.ts b/src/app/app.component.ts index 3cbfe90..fd4ad28 100644 --- a/src/app/app.component.ts +++ b/src/app/app.component.ts @@ -45,29 +45,78 @@ export class AppComponent implements OnInit{ electronService.ipcRenderer.on('context-menu', (event: any, message: string) => { this.zone.run(() => { - if(message == "edit") { - if(this.openContent == ModelComponentType.SCRIPTACCOUNT && this.scriptAccountOverview != undefined && this.scriptAccountOverview.selectedScriptAccount != undefined) { - this.editor!.openGameModelComponent(this.scriptAccountOverview.selectedScriptAccount!); - } - } else if(message == "delete") { - const affectedModelComponent = this.getSelectedModelComponent(); - const dialogRef = this.dialog.open(DeleteConfirmationDialogComponent, {data: affectedModelComponent, minWidth: "400px"}); - - dialogRef.afterClosed().subscribe(res => { - if(res != undefined && res) { - if(affectedModelComponent instanceof ScriptAccount) { - this.gameModel!.removeScriptAccount(affectedModelComponent); - } - } - }) - } - }) + this.onContextMenuMessageRecieved(message); + }); }) } else { console.log('Run in browser'); } } + onContextMenuMessageRecieved(message: string) { + if(message == "edit") { + this.onEditModelComponent(); + } else if(message == "delete") { + this.onDeleteModelComponent(); + } else if(message.startsWith("new")) { + const splittedMessage = message.split("-"); + const modelComponentType = ModelComponentTypeUtillities.fromString(splittedMessage[1]); + if(modelComponentType != undefined) { + this.onCreateModelComponent(modelComponentType); + } else { + console.log("[ERROR] [App-Component] Unknown Context-Menu Command!") + } + } + } + + private onEditModelComponent() { + if(this.openContent == ModelComponentType.SCRIPTACCOUNT && this.scriptAccountOverview != undefined && this.scriptAccountOverview.selectedScriptAccount != undefined) { + this.editor!.openGameModelComponent(this.scriptAccountOverview.selectedScriptAccount!); + } else { + //Erweitere to Gamesystems + } + } + + private onDeleteModelComponent() { + const affectedModelComponent = this.getSelectedModelComponent(); + const dialogRef = this.dialog.open(DeleteConfirmationDialogComponent, {data: affectedModelComponent, minWidth: "400px"}); + + dialogRef.afterClosed().subscribe(res => { + if(res != undefined && res) { + if(affectedModelComponent instanceof ScriptAccount) { + this.gameModel!.removeScriptAccount(affectedModelComponent); + } + } + }) + } + + private onCreateModelComponent(modelComponentType: ModelComponentType) { + switch (modelComponentType) { + case ModelComponentType.SCRIPTACCOUNT: this.onCreateNewScriptAccount(); break + case ModelComponentType.GAMESYTEM: this.onCreateNewGamesystem(); break + } + } + + private onCreateNewScriptAccount() { + const createdScriptAccount = this.gameModel!.createScriptAccount("New ScriptAccount"); + if(createdScriptAccount != undefined) { + this.editor?.openGameModelComponent(createdScriptAccount); + } else { + console.log("[DEBUG] [App-Component] ScriptAccount could not be created (Name not unique)"); + } + } + + private onCreateNewGamesystem() { + let parentGamesystemName = undefined + if(this.openContent != ModelComponentType.GAMESYTEM) { + this.openGamesystemsOverview(); + } else { + parentGamesystemName = this.gamesystemOverview!.selectedGamesystemName; + } + this.gameModel!.createGamesystem("New Gamesystem", parentGamesystemName); + this.gamesystemOverview!.refresh(); + } + private getSelectedModelComponent(): ModelComponent | undefined { if(this.openContent == ModelComponentType.SCRIPTACCOUNT) { if(this.scriptAccountOverview != undefined) { @@ -81,8 +130,8 @@ export class AppComponent implements OnInit{ ngOnInit() { this.gameModel = new GameModel("No More"); - this.gameModel.addScriptAccount("Temperature"); - this.gameModel.addScriptAccount("Luftfeuchtigkeit"); + this.gameModel.createScriptAccount("Temperature"); + this.gameModel.createScriptAccount("Luftfeuchtigkeit"); const weather = new SimpleGamesystem("Weather"); const season = new SimpleGamesystem("Season"); @@ -120,7 +169,7 @@ export class AppComponent implements OnInit{ onModelNameUpdate() { if(this.openContent == ModelComponentType.GAMESYTEM) { - this.gamesystemOverview!.onUpdateModelName(); + this.gamesystemOverview!.refresh(); } } } diff --git a/src/app/game-model/GameModel.ts b/src/app/game-model/GameModel.ts index 207fd0a..9e2a514 100644 --- a/src/app/game-model/GameModel.ts +++ b/src/app/game-model/GameModel.ts @@ -3,6 +3,7 @@ import {ScriptAccount} from "./scriptAccounts/ScriptAccount"; import {Transition} from "./gamesystems/Transition"; import {State} from "./gamesystems/State"; import {ProductGamesystem} from "./gamesystems/ProductGamesystem"; +import {SimpleGamesystem} from "./gamesystems/SimpleGamesystem"; export class GameModel { private readonly _gameModelName: string @@ -24,16 +25,14 @@ export class GameModel { } addGamesystem(gamesystem: Gamesystem) { - if(!this.gamesystems.includes(gamesystem)) { - this._gamesystems.push(gamesystem); - } + this._gamesystems.push(gamesystem); } removeGamesystem(gamesystem : Gamesystem) { this._gamesystems = this._gamesystems.filter(g => g !== gamesystem); } - addScriptAccount(scriptAccountName: string) { + createScriptAccount(scriptAccountName: string) { if(scriptAccountName != undefined && scriptAccountName.length > 0) { const scriptAccount = new ScriptAccount(scriptAccountName, ""); const searchedScriptAccount = this.scriptAccounts.find(s => s.componentName === scriptAccount.componentName); @@ -45,6 +44,28 @@ export class GameModel { return undefined; } + createGamesystem(gamesystemName: string, parentGamesystemName: string | undefined) { + if(gamesystemName != undefined && this.findGamesystem(gamesystemName) == undefined) { + const simpleGamesystem = new SimpleGamesystem(gamesystemName); + if(parentGamesystemName != undefined) { + const parentGamesystem = this.findGamesystem(parentGamesystemName); + if(parentGamesystem instanceof SimpleGamesystem) { + const parentProductGamesystem = ProductGamesystem.constructFromSimpleGamesystem(parentGamesystem, this); + parentProductGamesystem.addChildGamesystem(simpleGamesystem); + simpleGamesystem.parentGamesystem = parentProductGamesystem; + } else { + const productParentGamesystem = parentGamesystem as ProductGamesystem; + productParentGamesystem.addChildGamesystem(simpleGamesystem); + simpleGamesystem.parentGamesystem = productParentGamesystem; + } + } else { + this.gamesystems.push(simpleGamesystem); + + } + return simpleGamesystem; + } + } + removeScriptAccount(scriptAccount: ScriptAccount) { if(scriptAccount != undefined) { this._scriptAccounts = this.scriptAccounts.filter(s => s != scriptAccount); diff --git a/src/app/game-model/ModelComponentTypeUtillities.ts b/src/app/game-model/ModelComponentTypeUtillities.ts index c267736..236cc96 100644 --- a/src/app/game-model/ModelComponentTypeUtillities.ts +++ b/src/app/game-model/ModelComponentTypeUtillities.ts @@ -16,4 +16,12 @@ export class ModelComponentTypeUtillities { default: return "Undefined"; } } + + static fromString(string: string) : ModelComponentType | undefined { + console.log(string) + switch (string) { + case "gamesystem": return ModelComponentType.GAMESYTEM; + case "scriptaccount": return ModelComponentType.SCRIPTACCOUNT; + } + } } diff --git a/src/app/game-model/gamesystems/ProductGamesystem.ts b/src/app/game-model/gamesystems/ProductGamesystem.ts index d97f39e..84a135d 100644 --- a/src/app/game-model/gamesystems/ProductGamesystem.ts +++ b/src/app/game-model/gamesystems/ProductGamesystem.ts @@ -5,12 +5,34 @@ import {State} from "./State"; import {Transition} from "./Transition"; import {SimpleState} from "./SimpleState"; import {SimpleGamesystem} from "./SimpleGamesystem"; +import {GameModel} from "../GameModel"; export class ProductGamesystem extends Gamesystem { - innerGamesystems: SimpleGamesystem[] = []; + innerGamesystems: Gamesystem, Transition>[] = []; parentGamesystem: ProductGamesystem | undefined + static constructFromSimpleGamesystem(simpleGamesystem: SimpleGamesystem, gameModel: GameModel) { + const productGamesystem = new ProductGamesystem(simpleGamesystem.componentName); + const parentGamesystem = simpleGamesystem.parentGamesystem; + + if(simpleGamesystem.states.length > 0) { + simpleGamesystem.componentName += "(Child)"; + productGamesystem.addChildGamesystem(simpleGamesystem); + } + + + if(parentGamesystem != undefined) { + parentGamesystem.removeChildGamesystem(simpleGamesystem); + parentGamesystem.addChildGamesystem(productGamesystem); + } else { + gameModel.removeGamesystem(simpleGamesystem); + gameModel.addGamesystem(productGamesystem); + } + + return productGamesystem; + } + createState(label: string, description: string): ProductState | undefined { return undefined; } @@ -28,5 +50,11 @@ export class ProductGamesystem extends Gamesystem, Transition>) { + this.innerGamesystems.push(gamesystem); + } + private removeChildGamesystem(gamesystem: Gamesystem, Transition>) { + this.innerGamesystems = this.innerGamesystems.filter(childSystem => childSystem != gamesystem); + } } diff --git a/src/app/side-overviews/gamescript-overview/gamescript-overview.component.ts b/src/app/side-overviews/gamescript-overview/gamescript-overview.component.ts index 87129b9..4c07292 100644 --- a/src/app/side-overviews/gamescript-overview/gamescript-overview.component.ts +++ b/src/app/side-overviews/gamescript-overview/gamescript-overview.component.ts @@ -92,7 +92,15 @@ export class GamescriptOverviewComponent implements OnInit { } } - onUpdateModelName() { + get selectedGamesystemName() { + if(this.selectedGamesystem == undefined) { + return undefined + } else { + return this.selectedGamesystem!.name + } + } + + refresh() { this.dataSource.data = this.gameModel!.gamesystems; } } diff --git a/src/app/side-overviews/script-account-overview/script-account-overview.component.ts b/src/app/side-overviews/script-account-overview/script-account-overview.component.ts index f8621ee..f0d15da 100644 --- a/src/app/side-overviews/script-account-overview/script-account-overview.component.ts +++ b/src/app/side-overviews/script-account-overview/script-account-overview.component.ts @@ -14,17 +14,7 @@ export class ScriptAccountOverviewComponent { selectedScriptAccount: ScriptAccount | undefined - constructor(private electronService: ElectronService, - private zone: NgZone) { - if(electronService.isElectron) { - this.electronService.ipcRenderer.on('context-menu', (event: any, message: string) => { - this.zone.run(() => { - if(message == "new-scriptaccount") { - this.onCreateNewScriptAccount() - } - }) - }) - } + constructor() { } onOpenScriptAccount(scriptAccount: ScriptAccount) { @@ -32,12 +22,6 @@ export class ScriptAccountOverviewComponent { this.openScriptAccountEmitter.emit(scriptAccount); } - onCreateNewScriptAccount() { - const scriptAccount = this.gameModel!.addScriptAccount("New ScriptAccount"); - if(scriptAccount != undefined) { - this.openScriptAccountEmitter.emit(scriptAccount); - } - } selectScriptAccount(scriptAccount: ScriptAccount) {