]> Softwares of Agnibho - medscript.git/blob - plugin.py
Bugfix: Windows uninstall package permission error
[medscript.git] / plugin.py
1 # MedScript
2 # Copyright (C) 2023 Dr. Agnibho Mondal
3 # This file is part of MedScript.
4 # MedScript 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.
5 # MedScript 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.
6 # You should have received a copy of the GNU General Public License along with MedScript. If not, see <https://www.gnu.org/licenses/>.
7
8 import logging, os, importlib, copy, json
9 from PyQt6.QtWidgets import QMessageBox, QMainWindow, QInputDialog, QFileDialog, QVBoxLayout
10 from PyQt6.QtCore import QObject, QThread, QUrl, pyqtSignal, pyqtSlot
11 from PyQt6.QtWebChannel import QWebChannel
12 from PyQt6.QtGui import QIcon
13 from PyQt6.QtWebEngineWidgets import QWebEngineView
14 from glob import glob
15 from config import config
16
17 class Plugin(QObject):
18
19 update=pyqtSignal()
20
21 plugins=[]
22 names=[]
23 workers=[]
24
25 def __init__(self):
26 super().__init__()
27 if(config["enable_plugin"]):
28 self.load()
29
30 def load(self):
31 plugin_list=glob(os.path.join(config["plugin_directory"], "*"))
32 for i in plugin_list:
33 try:
34 if(os.path.isdir(i)):
35 spec=importlib.util.spec_from_file_location(os.path.basename(i), os.path.join(i, "main.py"))
36 mod=importlib.util.module_from_spec(spec)
37 spec.loader.exec_module(mod)
38 self.plugins.append(mod)
39 except Exception as e:
40 logging.warning(i+":"+str(e))
41
42 def get_name(self, mod):
43 try:
44 return(mod.name)
45 except Exception as e:
46 return(mod.__name__)
47
48 def commands(self):
49 cmds=[]
50 for i in self.plugins:
51 if(hasattr(i, "run") and callable(i.run)):
52 cmds.append([i, self.get_name(i)])
53 return(cmds)
54
55 def new(self, prescription):
56 for i in self.plugins:
57 try:
58 if(hasattr(i, "new") and callable(i.new)):
59 if(hasattr(i, "input") and callable(i.input)):
60 i.input(self.input())
61 prescription_copy=copy.deepcopy(prescription)
62 message=i.new(prescription_copy)
63 prescription.set_data_from_copy(prescription_copy)
64 if(message):
65 self.showMessage(message)
66 except Exception as e:
67 logging.exception(e)
68
69 def open(self, prescription):
70 for i in self.plugins:
71 try:
72 if(hasattr(i, "open") and callable(i.open)):
73 if(hasattr(i, "input") and callable(i.input)):
74 i.input(self.input())
75 prescription_copy=copy.deepcopy(prescription)
76 message=i.open(prescription_copy)
77 prescription.set_data_from_copy(prescription_copy)
78 if(message):
79 self.showMessage(message)
80 except Exception as e:
81 logging.exception(e)
82
83 def save(self, prescription):
84 for i in self.plugins:
85 try:
86 if(hasattr(i, "save") and callable(i.save)):
87 if(hasattr(i, "input") and callable(i.input)):
88 i.input(self.input())
89 prescription_copy=copy.deepcopy(prescription)
90 message=i.save(prescription_copy)
91 prescription.set_data_from_copy(prescription_copy)
92 if(message):
93 self.showMessage(message)
94 except Exception as e:
95 logging.exception(e)
96
97 def refresh(self, prescription):
98 for i in self.plugins:
99 try:
100 if(hasattr(i, "refresh") and callable(i.refresh)):
101 if(hasattr(i, "input") and callable(i.input)):
102 i.input(self.input())
103 prescription_copy=copy.deepcopy(prescription)
104 message=i.refresh(prescription_copy)
105 prescription.set_data_from_copy(prescription_copy)
106 if(message):
107 self.showMessage(message)
108 except Exception as e:
109 logging.exception(e)
110
111 def run(self, module, prescription):
112 try:
113 if(hasattr(module, "web") and callable(module.web)):
114 self.webapp=WebApp()
115 self.webapp.done.connect(lambda: prescription.set_data_from_copy(prescription_copy))
116 self.webapp.done.connect(lambda: self.update.emit())
117 prescription_copy=copy.deepcopy(prescription)
118 url, data=module.web(prescription_copy)
119 self.webapp.load(module, QUrl(url), prescription_copy, data)
120 self.webapp.show()
121 elif(hasattr(module, "run") and callable(module.run)):
122 if(hasattr(module, "confirm") and module.confirm):
123 if(QMessageBox.StandardButton.Yes!=QMessageBox.question(None,"Confirm", module.confirm)):
124 return
125 if(hasattr(module, "input") and callable(module.input)):
126 module.input(self.input())
127 if(hasattr(module, "fileopen") and callable(module.fileopen)):
128 module.fileopen(QFileDialog.getOpenFileName()[0])
129 if(hasattr(module, "filesave") and callable(module.filesave)):
130 module.filesave(QFileDialog.getSaveFileName()[0])
131 if(hasattr(module, "background") and module.background):
132 self.showMessage("Module "+module.__name__+" will run in background.")
133 self.workers.append(Worker(module.run, prescription))
134 index=len(self.workers)-1
135 self.workers[index].setIndex(index)
136 self.workers[index].pluginComplete.connect(self.showMessage)
137 self.workers[index].start()
138 else:
139 prescription_copy=copy.deepcopy(prescription)
140 message=module.run(prescription_copy)
141 prescription.set_data_from_copy(prescription_copy)
142 if(message):
143 self.showMessage(message)
144 except Exception as e:
145 logging.exception(e)
146
147 def input(self):
148 try:
149 text, ok=QInputDialog.getText(None, "User input", "Enter text:")
150 if text and ok:
151 return text
152 else:
153 return ""
154 except Exception as e:
155 logging.exception(e)
156
157 def showMessage(self, message, index=None):
158 QMessageBox.information(None, "Information", message)
159 if index is not None:
160 self.workers[index]=None
161
162 class WebApp(QMainWindow):
163
164 done=pyqtSignal()
165
166 def __init__(self, *args, **kwargs):
167 super().__init__(*args, **kwargs)
168
169 self.setWindowTitle("WebApp Plugin")
170 self.setGeometry(100, 100, 400, 400)
171 self.setWindowIcon(QIcon(os.path.join("resource", "icon_medscript.ico")))
172
173 self.webview=QWebEngineView()
174 self.setCentralWidget(self.webview)
175
176 def load(self, module, url, prescription, data):
177 self.module=module
178 self.webview.load(url)
179 self.channel=QWebChannel()
180 self.js=JS(module, prescription, data)
181 self.channel.registerObject("js", self.js)
182 self.webview.page().setWebChannel(self.channel)
183 self.js.done.connect(lambda: self.done.emit())
184 self.js.hide.connect(lambda: self.close())
185
186 class JS(QObject):
187
188 done=pyqtSignal()
189 hide=pyqtSignal()
190
191 def __init__(self, module, prescription, data):
192 super().__init__()
193 self.module=module
194 self.prescription=prescription
195 self.data=data
196
197 @pyqtSlot(str)
198 def run(self, result):
199 try:
200 prescription_copy=copy.deepcopy(self.prescription)
201 message=self.module.run(prescription_copy, result)
202 self.prescription.set_data_from_copy(prescription_copy)
203 if(message):
204 QMessageBox.information(None, "Information", message)
205 self.done.emit()
206 except Exception as e:
207 logging.error(self.module)
208 logging.exception(e)
209
210 @pyqtSlot(result=str)
211 def get(self):
212 return self.data
213
214 @pyqtSlot()
215 def close(self):
216 self.hide.emit()
217
218 class Worker(QThread):
219
220 pluginComplete=pyqtSignal(str, int)
221 function=None
222 prescription=None
223 index=None
224
225 def __init__(self, function, prescription):
226 super().__init__()
227 self.function=function
228 self.prescription=prescription
229
230 def setIndex(self, index):
231 self.index=index
232
233 def run(self):
234 try:
235 prescription_copy=copy.deepcopy(self.prescription)
236 message=self.function(prescription_copy)
237 self.pluginComplete.emit(message, self.index)
238 except Exception as e:
239 logging.exception(e)