diff --git a/common/src/module/canvas.mjs b/common/src/module/canvas.mjs
index 5d42f5e..c46c9a1 100644
--- a/common/src/module/canvas.mjs
+++ b/common/src/module/canvas.mjs
@@ -522,8 +522,9 @@ class CanvasAPI extends Module {
const onRendered = (imgData) => {
if(!this.#canvas.isImageLoaded(imgData.source) && !this.#canvas.isImageLoading(imgData.source)) {
// Wait until the image is loaded to callback.
- this.#canvas.loadImage(imgData.source)
- this.#canvas.imageLoaders[imgData.source] = [callback, imgData]
+ this.#canvas.loadImageAsync(imgData.source).then(() => {
+ callback(imgData)
+ })
} else {
// Callback directly
callback(imgData)
diff --git a/common/src/module/common.mjs b/common/src/module/common.mjs
index bdca62f..243fed2 100644
--- a/common/src/module/common.mjs
+++ b/common/src/module/common.mjs
@@ -57,7 +57,7 @@ export class Module extends BaseEventEmitter {
if(!options.hasOwnProperty(name))
throw new Error(`Option '${name}' of initialize of module ${this.#name} does not exist.`)
if(typeof value === "function" && value.prototype instanceof Interface)
- Interface.check_implementation(value, options[name])
+ Interface.checkImplementation(value, options[name])
else if(typeof value !== typeof options[name])
throw new Error(`Option '${name}' of initialize of module ${this.#name} is not a '${value}' (${typeof options[name]}).`)
}
diff --git a/common/src/module/interface.mjs b/common/src/module/interface.mjs
index 2886f73..27fb7eb 100644
--- a/common/src/module/interface.mjs
+++ b/common/src/module/interface.mjs
@@ -35,9 +35,8 @@ export class Interface {
* Throws an error if the implementation does not conform to the interface.
* @param {typeof Interface} interface_
* @param {object} classToCheck
- * @return {boolean}
*/
- static check_implementation(interface_, classToCheck) {
+ static checkImplementation(interface_, classToCheck) {
const properties = new interface_()
const interfaceName = interface_.name
const toCheckName = classToCheck.constructor.name
@@ -52,7 +51,7 @@ export class Interface {
else if((typeof value) === "object")
// Test type of object.
if(value instanceof Interface)
- Interface.check_implementation(value, classToCheck[property])
+ Interface.checkImplementation(value, classToCheck[property])
else if(value.prototype && !(classToCheck[property] instanceof value))
throw new Error(`Property '${property}' of ${interfaceName} implementation ${toCheckName} is not '${value.constructor.name}'.`)
}
@@ -61,13 +60,12 @@ export class Interface {
export class CanvasInterface extends Interface {
- imageLoaders = OBJECT
/** @type {function(string): CanvasRenderingContext2D} */
getContext = FUNCTION
/** @type {function(rect)} */
markDirty = FUNCTION
- /** @type {function(string)} */
- loadImage = FUNCTION
+ /** @type {function(string): Promise} */
+ loadImageAsync = FUNCTION
/** @type {function(string)} */
isImageLoading = FUNCTION
/** @type {function(string)} */
diff --git a/common/test/general/events.mjs b/common/test/basics/events.mjs
similarity index 100%
rename from common/test/general/events.mjs
rename to common/test/basics/events.mjs
diff --git a/common/test/basics/interface.mjs b/common/test/basics/interface.mjs
new file mode 100644
index 0000000..a8d8d32
--- /dev/null
+++ b/common/test/basics/interface.mjs
@@ -0,0 +1,51 @@
+/**
+ * LogarithmPlotter - 2D plotter software to make BODE plots, sequences and distribution functions.
+ * Copyright (C) 2021-2024 Ad5001
+ *
+ * This program is free software: you can redistribute it and/or modify
+ * it under the terms of the GNU General Public License as published by
+ * the Free Software Foundation, either version 3 of the License, or
+ * (at your option) any later version.
+ *
+ * This program is distributed in the hope that it will be useful,
+ * but WITHOUT ANY WARRANTY; without even the implied warranty of
+ * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
+ * GNU General Public License for more details.
+ *
+ * You should have received a copy of the GNU General Public License
+ * along with this program. If not, see .
+ */
+
+import { describe, it } from "mocha"
+import { expect } from "chai"
+
+import { MockLatex } from "../mock/latex.mjs"
+import { MockHelper } from "../mock/helper.mjs"
+import {
+ CanvasInterface,
+ DialogInterface,
+ HelperInterface,
+ Interface,
+ LatexInterface,
+ RootInterface
+} from "../../src/module/interface.mjs"
+import { MockDialog } from "../mock/dialog.mjs"
+import { MockRootElement } from "../mock/root.mjs"
+import { MockCanvas } from "../mock/canvas.mjs"
+
+describe("Interface", function() {
+ describe("#checkImplementation", function() {
+ it("should validate the implementation of mocks", function() {
+ const checkMockLatex = () => Interface.checkImplementation(LatexInterface, new MockLatex())
+ const checkMockHelper = () => Interface.checkImplementation(HelperInterface, new MockHelper())
+ const checkMockDialog = () => Interface.checkImplementation(DialogInterface, new MockDialog())
+ const checkMockRoot = () => Interface.checkImplementation(RootInterface, new MockRootElement())
+ const checkMockCanvas = () => Interface.checkImplementation(CanvasInterface, new MockCanvas())
+ expect(checkMockLatex).to.not.throw()
+ expect(checkMockHelper).to.not.throw()
+ expect(checkMockDialog).to.not.throw()
+ expect(checkMockRoot).to.not.throw()
+ expect(checkMockCanvas).to.not.throw()
+ })
+ })
+})
\ No newline at end of file
diff --git a/common/test/general/utils.mjs b/common/test/basics/utils.mjs
similarity index 100%
rename from common/test/general/utils.mjs
rename to common/test/basics/utils.mjs
diff --git a/common/test/mock/canvas.mjs b/common/test/mock/canvas.mjs
new file mode 100644
index 0000000..e770e10
--- /dev/null
+++ b/common/test/mock/canvas.mjs
@@ -0,0 +1,59 @@
+/**
+ * LogarithmPlotter - 2D plotter software to make BODE plots, sequences and distribution functions.
+ * Copyright (C) 2021-2024 Ad5001
+ *
+ * This program is free software: you can redistribute it and/or modify
+ * it under the terms of the GNU General Public License as published by
+ * the Free Software Foundation, either version 3 of the License, or
+ * (at your option) any later version.
+ *
+ * This program is distributed in the hope that it will be useful,
+ * but WITHOUT ANY WARRANTY; without even the implied warranty of
+ * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
+ * GNU General Public License for more details.
+ *
+ * You should have received a copy of the GNU General Public License
+ * along with this program. If not, see .
+ */
+
+
+export class MockCanvas {
+ constructor(mockLoading = false) {
+ this.mockLoading = mockLoading
+ }
+
+ getContext(context) {
+ throw new Error("MockCanvas.getContext not implemented")
+ }
+
+ markDirty(rect) {
+ this.requestPaint()
+ }
+
+ loadImageAsync(image) {
+ return new Promise((resolve, reject) => {
+ resolve()
+ })
+ }
+
+ /**
+ * Image loading is instantaneous.
+ * @param {string} image
+ * @return {boolean}
+ */
+ isImageLoading(image) {
+ return this.mockLoading
+ }
+
+ /**
+ * Image loading is instantaneous.
+ * @param {string} image
+ * @return {boolean}
+ */
+ isImageLoaded(image) {
+ return !this.mockLoading
+ }
+
+ requestPaint() {
+ }
+}
\ No newline at end of file
diff --git a/common/test/mock/dialog.mjs b/common/test/mock/dialog.mjs
new file mode 100644
index 0000000..3ff118f
--- /dev/null
+++ b/common/test/mock/dialog.mjs
@@ -0,0 +1,23 @@
+/**
+ * LogarithmPlotter - 2D plotter software to make BODE plots, sequences and distribution functions.
+ * Copyright (C) 2021-2024 Ad5001
+ *
+ * This program is free software: you can redistribute it and/or modify
+ * it under the terms of the GNU General Public License as published by
+ * the Free Software Foundation, either version 3 of the License, or
+ * (at your option) any later version.
+ *
+ * This program is distributed in the hope that it will be useful,
+ * but WITHOUT ANY WARRANTY; without even the implied warranty of
+ * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
+ * GNU General Public License for more details.
+ *
+ * You should have received a copy of the GNU General Public License
+ * along with this program. If not, see .
+ */
+
+export class MockDialog {
+ constructor() {}
+
+ show() {}
+}
\ No newline at end of file
diff --git a/common/test/mock/root.mjs b/common/test/mock/root.mjs
new file mode 100644
index 0000000..51807e2
--- /dev/null
+++ b/common/test/mock/root.mjs
@@ -0,0 +1,61 @@
+/**
+ * LogarithmPlotter - 2D plotter software to make BODE plots, sequences and distribution functions.
+ * Copyright (C) 2021-2024 Ad5001
+ *
+ * This program is free software: you can redistribute it and/or modify
+ * it under the terms of the GNU General Public License as published by
+ * the Free Software Foundation, either version 3 of the License, or
+ * (at your option) any later version.
+ *
+ * This program is distributed in the hope that it will be useful,
+ * but WITHOUT ANY WARRANTY; without even the implied warranty of
+ * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
+ * GNU General Public License for more details.
+ *
+ * You should have received a copy of the GNU General Public License
+ * along with this program. If not, see .
+ */
+
+/**
+ * Mock for root element with width and height property.
+ * setWidth, setHeight, getWidth, and getHeight methods can be spied on to check
+ * when the accessor is called.
+ */
+export class MockRootElement {
+ #width = 0
+ #height = 0
+
+ constructor() {}
+
+ setWidth(width) {
+ this.#width = width;
+ }
+
+ getWidth() {
+ return this.#width
+ }
+
+ setHeight(height) {
+ this.#height = height;
+ }
+
+ getHeight() {
+ return this.#height
+ }
+
+ get width() {
+ return this.getWidth()
+ }
+
+ set width(value) {
+ this.setWidth(value)
+ }
+
+ get height() {
+ return this.getHeight()
+ }
+
+ set height(value) {
+ this.setHeight(value)
+ }
+}
\ No newline at end of file
diff --git a/runtime-pyside6/LogarithmPlotter/qml/eu/ad5001/LogarithmPlotter/LogGraphCanvas.qml b/runtime-pyside6/LogarithmPlotter/qml/eu/ad5001/LogarithmPlotter/LogGraphCanvas.qml
index 07b6002..e1583f6 100644
--- a/runtime-pyside6/LogarithmPlotter/qml/eu/ad5001/LogarithmPlotter/LogGraphCanvas.qml
+++ b/runtime-pyside6/LogarithmPlotter/qml/eu/ad5001/LogarithmPlotter/LogGraphCanvas.qml
@@ -36,7 +36,7 @@ Canvas {
width: parent.width
/*!
\qmlproperty var LogGraphCanvas::imageLoaders
- Dictionary of format {image: [callback.image data]} containing data for defered image loading.
+ Dictionary of format {image: callback} containing data for deferred image loading.
*/
property var imageLoaders: {}
@@ -66,9 +66,21 @@ Canvas {
Object.keys(imageLoaders).forEach((key) => {
if(isImageLoaded(key)) {
// Calling callback
- imageLoaders[key][0](imageLoaders[key][1])
+ imageLoaders[key]()
delete imageLoaders[key]
}
})
}
+
+ /*!
+ \qmlmethod void LogGraphCanvas::loadImageAsync(string imageSource)
+ Loads an image data onto the canvas asynchronously.
+ Returns a Promise that is resolved when the image is loaded.
+ */
+ function loadImageAsync(imageSource) {
+ return new Promise((resolve) => {
+ this.loadImage(imageSource)
+ this.imageLoaders[imageSource] = resolve
+ })
+ }
}
diff --git a/runtime-pyside6/LogarithmPlotter/qml/eu/ad5001/LogarithmPlotter/LogarithmPlotter.qml b/runtime-pyside6/LogarithmPlotter/qml/eu/ad5001/LogarithmPlotter/LogarithmPlotter.qml
index e7cfc1a..d541a0c 100644
--- a/runtime-pyside6/LogarithmPlotter/qml/eu/ad5001/LogarithmPlotter/LogarithmPlotter.qml
+++ b/runtime-pyside6/LogarithmPlotter/qml/eu/ad5001/LogarithmPlotter/LogarithmPlotter.qml
@@ -257,13 +257,11 @@ ApplicationWindow {
})
Modules.IO.on("saved loaded", (evt) => {
// Refreshing sidebar
- console.log(evt.name)
updateObjectsLists()
if(title.endsWith("*"))
title = title.substring(0, title.length-1)
})
Modules.IO.on("modified", () => {
- console.log("modified")
if(!title.endsWith("*"))
title = title+"*"
})