]> Softwares of Agnibho - medscript.git/blob - window.py
Added shortcuts
[medscript.git] / window.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 os, sys, datetime, dateutil.parser, shutil
9 from PyQt6.QtCore import Qt, QDateTime, QSize, pyqtSignal
10 from PyQt6.QtWidgets import QWidget, QMainWindow, QMessageBox, QLabel, QPushButton, QLineEdit, QTextEdit, QDateTimeEdit, QListWidget, QComboBox, QCheckBox, QVBoxLayout, QHBoxLayout, QFormLayout, QToolBar, QTabWidget, QStatusBar, QFileDialog, QInputDialog, QCompleter, QSizePolicy
11 from PyQt6.QtGui import QAction, QIcon
12 from pathlib import Path
13 from hashlib import md5
14
15 from config import config, sign_available
16 from prescription import Prescription
17 from renderer import Renderer
18 from filehandler import FileHandler
19 from renderbox import RenderBox
20 from setting import EditConfiguration, EditPrescriber
21 from viewbox import ViewBox
22 from preset import Preset
23 try:
24 from M2Crypto.EVP import EVPError
25 from M2Crypto.BIO import BIOError
26 from M2Crypto.SMIME import SMIME_Error
27 except Exception as e:
28 print(e)
29 sign_available=False
30
31 class MainWindow(QMainWindow):
32
33 signal_view=pyqtSignal(str)
34
35 current_file=FileHandler()
36 prescription=Prescription()
37 renderer=Renderer()
38 save_state=md5("".encode()).hexdigest()
39 unchanged_state=False
40
41 def cmd_new(self):
42 if(self.confirm_close()):
43 self.new_doc()
44
45 def cmd_open(self, file=None):
46 if(self.confirm_close()):
47 try:
48 self.current_file.reset()
49 if(file):
50 self.current_file.set_file(file)
51 else:
52 self.current_file.set_file(QFileDialog.getOpenFileName(self, "Open File", config["document_directory"], "Prescriptions (*.mpaz);; All Files (*)")[0])
53 self.current_file.open()
54 self.prescription.read_from(os.path.join(self.current_file.directory.name,"prescription.json"))
55 self.load_interface_from_instance()
56 self.save_state=md5(self.prescription.get_json().encode()).hexdigest()
57 self.load_attachment(self.current_file.list())
58 self.unchanged_state=True
59 except Exception as e:
60 QMessageBox.warning(self,"Open failed", "Failed to open file.")
61 print(e)
62
63 def cmd_save(self, save_as=False):
64 self.update_instance()
65 suggest=self.prescription.id if(self.prescription.id) else self.prescription.name
66 suggest=os.path.abspath(os.path.join(config["document_directory"], suggest)+".mpaz")
67 if(save_as or not self.unchanged_state or QMessageBox.StandardButton.Yes==QMessageBox.question(self,"Confirm change", "Modify the original file?")):
68 try:
69 if not os.path.exists(self.current_file.file):
70 filename=QFileDialog.getSaveFileName(self, "Save File", suggest, "Prescriptions (*.mpaz);; All Files (*)")[0]
71 self.current_file.set_file(filename)
72 for i in range(self.input_attachment.count()):
73 self.current_file.copy(self.input_attachment.item(i).text())
74 self.prescription.write_to(os.path.join(self.current_file.directory.name, "prescription.json"))
75 config["template"]=os.path.join(config["template_directory"], self.input_template.currentText())
76 self.current_file.save()
77 self.unchanged_state=False
78 self.load_interface_from_instance()
79 self.save_state=md5(self.prescription.get_json().encode()).hexdigest()
80 except Exception as e:
81 QMessageBox.warning(self,"Save failed", "Failed to save file.")
82 print(e)
83
84 def cmd_save_as(self):
85 suggest=self.prescription.id if(self.prescription.id) else self.prescription.name
86 suggest=os.path.abspath(os.path.join(config["document_directory"], suggest)+".mpaz")
87 self.current_file.set_file(QFileDialog.getSaveFileName(self, "Save File", suggest, "Prescriptions (*.mpaz);; All Files (*)")[0])
88 Path(self.current_file.file).touch()
89 self.cmd_save(save_as=True)
90
91 def cmd_refresh(self):
92 self.refresh()
93
94 def cmd_quit(self):
95 if(self.confirm_close()):
96 sys.exit()
97
98 def cmd_render(self):
99 self.refresh()
100 if(self.save_state==md5(self.prescription.get_json().encode()).hexdigest()):
101 try:
102 target=self.renderer.render(self.current_file.directory.name)
103 self.signal_view.emit(target)
104 self.renderbox.showMaximized()
105 except FileNotFoundError as e:
106 print(e)
107 QMessageBox.information(self, "Save first", "Please save the file before rendering.")
108
109 else:
110 QMessageBox.information(self, "Save first", "Please save the file before rendering.")
111
112 def cmd_sign(self):
113 self.refresh()
114 if(self.save_state==md5(self.prescription.get_json().encode()).hexdigest()):
115 password, ok=QInputDialog.getText(self, "Enter password", "Private key password", QLineEdit.EchoMode.Password)
116 if(ok):
117 try:
118 try:
119 self.current_file.sign(password)
120 self.cmd_save()
121 except FileNotFoundError as e:
122 print(e)
123 QMessageBox.information(self, "Save first", "Please save the file before signing.")
124 except TypeError as e:
125 print(e)
126 QMessageBox.information(self, "Configure", "Please add valid key and certificate to the config file.")
127 except EVPError as e:
128 print(e)
129 QMessageBox.information(self, "Check password", "Failed to load key. Please check if password is correct.")
130 except BIOError as e:
131 print(e)
132 QMessageBox.information(self, "Not found", "Certifcate and/or key not found.")
133 except SMIME_Error as e:
134 print(e)
135 QMessageBox.information(self, "Failed to load", "Failed to sign. Please check if certificate and key match.")
136 except Exception as e:
137 print(e)
138 QMessageBox.information(self, "Failed", "Failed to sign.")
139 except Exception as e:
140 print(e)
141 else:
142 QMessageBox.information(self, "Save first", "Please save the file before signing.")
143
144 def cmd_unsign(self):
145 self.current_file.delete_sign()
146 self.cmd_save()
147 self.refresh()
148
149 def cmd_verify(self):
150 try:
151 result=self.current_file.verify()
152 if result is False:
153 QMessageBox.critical(self, "Verification failed", "Signature is invalid.")
154 elif result is None:
155 QMessageBox.warning(self, "No Siganture", "No signature was found.")
156 else:
157 print(result)
158 QMessageBox.information(self, "Valid signature", "Valid signature found with the following information:\n"+result)
159 except FileNotFoundError as e:
160 print(e)
161 QMessageBox.warning(self, "No Siganture", "No signature was found.")
162 except Exception as e:
163 print(e)
164 QMessageBox.warning(self, "Failed", "Failed to verify.")
165
166 def cmd_configuration(self):
167 self.edit_configuration.show()
168
169 def cmd_prescriber(self):
170 self.edit_prescriber.show()
171
172 def cmd_prescriber_reload(self, file=None):
173 self.prescription.reload_prescriber(file=None)
174 self.refresh()
175
176 def cmd_switch(self):
177 try:
178 self.prescription.reload_prescriber(QFileDialog.getOpenFileName(self, "Open File", config["prescriber_directory"], "JSON (*.json);; All Files (*)")[0])
179 self.refresh()
180 except FileNotFoundError as e:
181 print(e)
182
183 def cmd_about(self):
184 self.viewbox.open(os.path.join(config["resource"], "about.html"))
185 self.viewbox.show()
186
187 def cmd_help(self):
188 self.viewbox.open(os.path.join(config["resource"], "help.html"))
189 self.viewbox.show()
190
191 def insert_preset_extra(self):
192 try:
193 self.input_extra.insertPlainText(self.preset_extra.data[self.input_extra_preset.currentText()])
194 except KeyError:
195 self.input_extra.insertPlainText(self.input_extra_preset.currentText())
196 finally:
197 self.input_extra_preset.setCurrentIndex(-1)
198 if config["preset_newline"]:
199 self.input_extra.insertPlainText("\n")
200
201 def insert_preset_note(self):
202 try:
203 self.input_note.insertPlainText(self.preset_note.data[self.input_note_preset.currentText()])
204 except KeyError:
205 self.input_note.insertPlainText(self.input_note_preset.currentText())
206 finally:
207 self.input_note_preset.setCurrentIndex(-1)
208 if config["preset_newline"]:
209 self.input_note.insertPlainText("\n")
210
211 def insert_preset_report(self):
212 try:
213 self.input_report.insertPlainText(self.preset_report.data[self.input_report_preset.currentText()])
214 except KeyError:
215 self.input_report.insertPlainText(self.input_report_preset.currentText())
216 finally:
217 self.input_report_preset.setCurrentIndex(-1)
218 if config["preset_newline"]:
219 self.input_report.insertPlainText("\n")
220 def insert_preset_advice(self):
221 try:
222 self.input_advice.insertPlainText(self.preset_advice.data[self.input_advice_preset.currentText()])
223 except KeyError:
224 self.input_advice.insertPlainText(self.input_advice_preset.currentText())
225 finally:
226 self.input_advice_preset.setCurrentIndex(-1)
227 if config["preset_newline"]:
228 self.input_advice.insertPlainText("\n")
229
230
231 def insert_preset_investigation(self):
232 try:
233 self.input_investigation.insertPlainText(self.preset_investigation.data[self.input_investigation_preset.currentText()])
234 except KeyError:
235 self.input_investigation.insertPlainText(self.input_investigation_preset.currentText())
236 finally:
237 self.input_investigation_preset.setCurrentIndex(-1)
238 if config["preset_newline"]:
239 self.input_investigation.insertPlainText("\n")
240
241 def insert_preset_medication(self):
242 try:
243 self.input_medication.insertPlainText(self.preset_medication.data[self.input_medication_preset.currentText()])
244 except KeyError:
245 self.input_medication.insertPlainText(self.input_medication_preset.currentText())
246 finally:
247 self.input_medication_preset.setCurrentIndex(-1)
248 if config["preset_newline"]:
249 self.input_medication.insertPlainText("\n")
250
251 def insert_preset_additional(self):
252 try:
253 self.input_additional.insertPlainText(self.preset_additional.data[self.input_additional_preset.currentText()])
254 except KeyError:
255 self.input_additional.insertPlainText(self.input_additional_preset.currentText())
256 finally:
257 self.input_additional_preset.setCurrentIndex(-1)
258 if config["preset_newline"]:
259 self.input_additional.insertPlainText("\n")
260
261 def load_interface(self, file="", date=None, id="", name="", age="", sex="", address="", contact="", extra="", mode="", daw="", diagnosis="", note="", report="", advice="", investigation="", medication="", additional=""):
262 try:
263 file_msg=self.current_file.file if self.current_file.file else "New file"
264 sign_msg="(signed)" if sign_available and config["smime"] and self.current_file.is_signed() else ""
265 self.statusbar.showMessage(file_msg+" "+sign_msg)
266 if date is None:
267 d=QDateTime.currentDateTime()
268 else:
269 try:
270 pdate=dateutil.parser.parse(date)
271 d=QDateTime.fromString(pdate.strftime("%Y-%m-%d %H:%M:%S"), "yyyy-MM-dd hh:mm:ss")
272 except Exception as e:
273 QMessageBox.warning(self,"Failed to load", str(e))
274 print(e)
275 self.input_date.setDateTime(d)
276 self.input_id.setText(id)
277 self.input_name.setText(name)
278 self.input_age.setText(age)
279 self.input_sex.setCurrentText(sex)
280 self.input_address.setText(address)
281 self.input_contact.setText(contact)
282 self.input_extra.setText(extra)
283 self.input_mode.setCurrentText(mode)
284 self.input_daw.setChecked(bool(daw))
285 self.input_diagnosis.setText(diagnosis)
286 self.input_note.setText(note)
287 self.input_report.setText(report)
288 self.input_advice.setText(advice)
289 self.input_investigation.setText(investigation)
290 self.input_medication.setText(medication)
291 self.input_additional.setText(additional)
292 self.label_prescriber.setText(self.prescription.prescriber.name)
293 except Exception as e:
294 QMessageBox.warning(self,"Failed to load", "Failed to load the data into the application.")
295 print(e)
296
297 def load_interface_from_instance(self):
298 self.load_interface(
299 file=self.prescription.file,
300 date=self.prescription.date,
301 id=self.prescription.id,
302 name=self.prescription.name,
303 age=self.prescription.age,
304 sex=self.prescription.sex,
305 address=self.prescription.address,
306 contact=self.prescription.contact,
307 extra=self.prescription.extra,
308 mode=self.prescription.mode,
309 daw=self.prescription.daw,
310 diagnosis=self.prescription.diagnosis,
311 note=self.prescription.note,
312 report=self.prescription.report,
313 advice=self.prescription.advice,
314 investigation=self.prescription.investigation,
315 medication=self.prescription.medication,
316 additional=self.prescription.additional
317 )
318
319 def update_instance(self):
320 try:
321 self.prescription.set_data(
322 date=self.input_date.dateTime().toString("yyyy-MM-dd hh:mm:ss"),
323 id=self.input_id.text(),
324 name=self.input_name.text(),
325 age=self.input_age.text(),
326 sex=self.input_sex.currentText(),
327 address=self.input_address.text(),
328 contact=self.input_contact.text(),
329 extra=self.input_extra.toPlainText(),
330 mode=self.input_mode.currentText(),
331 daw=self.input_daw.isChecked(),
332 diagnosis=self.input_diagnosis.text(),
333 note=self.input_note.toPlainText(),
334 report=self.input_report.toPlainText(),
335 advice=self.input_advice.toPlainText(),
336 investigation=self.input_investigation.toPlainText(),
337 medication=self.input_medication.toPlainText(),
338 additional=self.input_additional.toPlainText()
339 )
340 except Exception as e:
341 QMessageBox.critical(self,"Failed", "Critical failure happned. Please check console for more info.")
342 print(e)
343
344 def new_doc(self):
345 self.current_file.reset()
346 self.prescription.set_data()
347 self.input_attachment.clear()
348 self.load_interface()
349 self.update_instance()
350 self.save_state=md5(self.prescription.get_json().encode()).hexdigest()
351
352 def refresh(self):
353 self.update_instance()
354 self.load_interface_from_instance()
355
356 def add_attachment(self):
357 try:
358 new=QFileDialog.getOpenFileName(self, "Open File", config["document_directory"], "PDF (*.pdf);; Images (*.jpg, *.jpeg, *.png, *.gif);; All Files (*)")[0]
359 if new:
360 self.input_attachment.addItem(new)
361 except Exception as e:
362 QMessageBox.warning(self,"Attach failed", "Failed to attach file.")
363 print(e)
364
365 def remove_attachment(self):
366 index=self.input_attachment.currentRow()
367 if(index>=0):
368 self.current_file.delete_attachment(self.input_attachment.item(index).text())
369 self.input_attachment.takeItem(index)
370 else:
371 QMessageBox.warning(self, "Select item", "Please select an attachment to remove.")
372
373 def save_attachment(self):
374 try:
375 shutil.copyfile(self.input_attachment.currentItem().text(), QFileDialog.getSaveFileName(self, "Save Attachment", os.path.join(config["document_directory"], os.path.basename(self.input_attachment.currentItem().text())))[0])
376 except Exception as e:
377 print(e)
378
379 def load_attachment(self, attachments):
380 for attach in attachments:
381 self.input_attachment.addItem(attach)
382
383 def confirm_close(self):
384 self.refresh()
385 flag=(self.save_state==md5(self.prescription.get_json().encode()).hexdigest() or QMessageBox.StandardButton.Yes==QMessageBox.question(self,"Confirm action", "Unsaved changes may be lost. Continue?"))
386 return flag
387
388 def closeEvent(self, event):
389 if(self.confirm_close()):
390 event.accept()
391 else:
392 event.ignore()
393
394 def __init__(self, *args, **kwargs):
395 super().__init__(*args, **kwargs)
396
397 global sign_available
398
399 self.setWindowTitle("MedScript")
400 self.setGeometry(100, 100, 600, 400)
401 self.setWindowIcon(QIcon(os.path.join(config["resource"], "icon_medscript.ico")))
402
403 icon_open=QIcon(os.path.join(config["resource"], "icon_open.svg"))
404 icon_save=QIcon(os.path.join(config["resource"], "icon_save.svg"))
405 icon_render=QIcon(os.path.join(config["resource"], "icon_render.svg"))
406 icon_refresh=QIcon(os.path.join(config["resource"], "icon_refresh.svg"))
407
408 self.preset_extra=Preset(os.path.join(config["preset_directory"], "certify.csv"))
409 self.preset_note=Preset(os.path.join(config["preset_directory"], "note.csv"))
410 self.preset_report=Preset(os.path.join(config["preset_directory"], "report.csv"))
411 self.preset_advice=Preset(os.path.join(config["preset_directory"], "advice.csv"))
412 self.preset_investigation=Preset(os.path.join(config["preset_directory"], "investigation.csv"))
413 self.preset_medication=Preset(os.path.join(config["preset_directory"], "medication.csv"), text_as_key=True)
414 self.preset_additional=Preset(os.path.join(config["preset_directory"], "additional.csv"))
415
416 action_new=QAction("New", self)
417 action_new.setShortcut("Ctrl+N")
418 action_new.triggered.connect(self.cmd_new)
419 action_open=QAction("Open", self)
420 action_open2=QAction(icon_open, "Open", self)
421 action_open.setShortcut("Ctrl+O")
422 action_open.triggered.connect(self.cmd_open)
423 action_open2.triggered.connect(self.cmd_open)
424 action_save=QAction("Save", self)
425 action_save2=QAction(icon_save, "Save", self)
426 action_save.setShortcut("Ctrl+S")
427 action_save.triggered.connect(self.cmd_save)
428 action_save2.triggered.connect(self.cmd_save)
429 action_save_as=QAction("Save As", self)
430 action_save_as.setShortcut("Ctrl+Shift+S")
431 action_save_as.triggered.connect(self.cmd_save_as)
432 action_refresh=QAction("Refresh", self)
433 action_refresh.setShortcut("F5")
434 action_refresh2=QAction(icon_refresh, "Refresh", self)
435 action_refresh.triggered.connect(self.cmd_refresh)
436 action_refresh2.triggered.connect(self.cmd_refresh)
437 action_quit=QAction("Quit", self)
438 action_quit.setShortcut("Ctrl+Q")
439 action_quit.triggered.connect(self.cmd_quit)
440 action_render=QAction("Render", self)
441 action_render.setShortcut("Ctrl+R")
442 action_render2=QAction(icon_render, "Render", self)
443 action_render.triggered.connect(self.cmd_render)
444 action_render2.triggered.connect(self.cmd_render)
445 action_sign=QAction("Sign", self)
446 action_sign.triggered.connect(self.cmd_sign)
447 action_unsign=QAction("Unsign", self)
448 action_unsign.triggered.connect(self.cmd_unsign)
449 action_verify=QAction("Verify", self)
450 action_verify.triggered.connect(self.cmd_verify)
451 action_configuration=QAction("Configuration", self)
452 action_configuration.triggered.connect(self.cmd_configuration)
453 action_prescriber=QAction("Prescriber", self)
454 action_prescriber.triggered.connect(self.cmd_prescriber)
455 action_switch=QAction("Switch", self)
456 action_switch.triggered.connect(self.cmd_switch)
457 action_about=QAction("About", self)
458 action_about.triggered.connect(self.cmd_about)
459 action_help=QAction("Help", self)
460 action_help.setShortcut("F1")
461 action_help.triggered.connect(self.cmd_help)
462
463 menubar=self.menuBar()
464 menu_file=menubar.addMenu("File")
465 menu_file.addAction(action_new)
466 menu_file.addAction(action_open)
467 menu_file.addAction(action_save)
468 menu_file.addAction(action_save_as)
469 menu_file.addAction(action_quit)
470 menu_prepare=menubar.addMenu("Prepare")
471 menu_prepare.addAction(action_render)
472 menu_prepare.addAction(action_refresh)
473 if(sign_available and config["smime"]):
474 menu_prepare.addAction(action_sign)
475 menu_prepare.addAction(action_unsign)
476 menu_prepare.addAction(action_verify)
477 menu_settings=menubar.addMenu("Settings")
478 menu_settings.addAction(action_configuration)
479 menu_settings.addAction(action_prescriber)
480 menu_settings.addAction(action_switch)
481 menu_help=menubar.addMenu("Help")
482 menu_help.addAction(action_about)
483 menu_help.addAction(action_help)
484
485 toolbar=QToolBar("Main Toolbar", floatable=False, movable=False)
486 toolbar.setIconSize(QSize(16, 16))
487 toolbar.addAction(action_open2)
488 toolbar.addAction(action_save2)
489 toolbar.addAction(action_refresh2)
490 toolbar.addAction(action_render2)
491 toolbar.addSeparator()
492 self.input_template=QComboBox(self)
493 templates=os.listdir(config["template_directory"])
494 try:
495 templates.remove(os.path.basename(config["template"]))
496 templates.insert(0, os.path.basename(config["template"]))
497 except Exception as e:
498 print(e)
499 self.input_template.addItems(templates)
500 toolbar.addWidget(self.input_template)
501 spacer=QWidget(self)
502 spacer.setSizePolicy(QSizePolicy.Policy.Expanding, QSizePolicy.Policy.Expanding)
503 toolbar.addWidget(spacer)
504 self.label_prescriber=QLabel(self)
505 toolbar.addWidget(self.label_prescriber)
506 self.addToolBar(toolbar)
507
508 tab_info=QWidget(self)
509 layout_info=QFormLayout(tab_info)
510 layout_info2=QHBoxLayout()
511 self.input_date=QDateTimeEdit(self)
512 self.input_date.setDisplayFormat("MMMM dd, yyyy hh:mm a")
513 layout_info.addRow("Date", self.input_date)
514 self.input_id=QLineEdit(self)
515 layout_info.addRow("ID", self.input_id)
516 self.input_name=QLineEdit(self)
517 layout_info.addRow("Name", self.input_name)
518 self.input_age=QLineEdit(self)
519 layout_info.addRow("Age", self.input_age)
520 self.input_sex=QComboBox(self)
521 self.input_sex.addItems(["Male", "Female", "Other"])
522 self.input_sex.setEditable(True)
523 layout_info.addRow("Sex", self.input_sex)
524 self.input_address=QLineEdit(self)
525 layout_info.addRow("Address", self.input_address)
526 self.input_contact=QLineEdit(self)
527 layout_info.addRow("Contact", self.input_contact)
528 self.input_diagnosis=QLineEdit(self)
529 layout_info.addRow("Diagnosis", self.input_diagnosis)
530 self.input_extra=QTextEdit(self)
531 self.input_extra_preset=QComboBox(self)
532 self.input_extra_preset.addItems(self.preset_extra.data.keys())
533 self.input_extra_preset.setCurrentIndex(-1)
534 self.input_extra_preset.setEditable(True)
535 self.input_extra_preset.completer().setCompletionMode(QCompleter.CompletionMode.PopupCompletion)
536 self.input_extra_preset.completer().setFilterMode(Qt.MatchFlag.MatchContains)
537 self.input_extra_preset.setPlaceholderText("Select a preset")
538 input_extra_preset_btn=QPushButton("Insert")
539 input_extra_preset_btn.clicked.connect(self.insert_preset_extra)
540 layout_info2.addWidget(self.input_extra_preset, 5)
541 layout_info2.addWidget(input_extra_preset_btn, 1)
542 layout_info.addRow("Certify\nPreset", layout_info2)
543 layout_info.addRow("Certify /\nExtra", self.input_extra)
544 self.input_mode=QComboBox(self)
545 self.input_mode.addItems(["In-Person", "Tele-Consultation", "Other"])
546 self.input_mode.setEditable(True)
547 layout_info.addRow("Mode", self.input_mode)
548 self.input_daw=QCheckBox("Dispense as written", self)
549 layout_info.addRow("DAW", self.input_daw)
550
551 tab_note=QWidget(self)
552 layout_note=QVBoxLayout(tab_note)
553 layout_note2=QHBoxLayout()
554 label_note=QLabel("Clinical Notes")
555 self.input_note_preset=QComboBox(self)
556 self.input_note_preset.addItems(self.preset_note.data.keys())
557 self.input_note_preset.setCurrentIndex(-1)
558 self.input_note_preset.setEditable(True)
559 self.input_note_preset.completer().setCompletionMode(QCompleter.CompletionMode.PopupCompletion)
560 self.input_note_preset.completer().setFilterMode(Qt.MatchFlag.MatchContains)
561 self.input_note_preset.setPlaceholderText("Select a preset")
562 input_note_preset_btn=QPushButton("Insert")
563 input_note_preset_btn.clicked.connect(self.insert_preset_note)
564 layout_note2.addWidget(self.input_note_preset, 5)
565 layout_note2.addWidget(input_note_preset_btn, 1)
566 self.input_note=QTextEdit(self)
567 layout_note.addWidget(label_note)
568 layout_note.addLayout(layout_note2)
569 layout_note.addWidget(self.input_note)
570
571 tab_report=QWidget(self)
572 layout_report=QVBoxLayout(tab_report)
573 layout_report2=QHBoxLayout()
574 label_report=QLabel("Available Reports")
575 self.input_report_preset=QComboBox(self)
576 self.input_report_preset.addItems(self.preset_report.data.keys())
577 self.input_report_preset.setCurrentIndex(-1)
578 self.input_report_preset.setEditable(True)
579 self.input_report_preset.completer().setCompletionMode(QCompleter.CompletionMode.PopupCompletion)
580 self.input_report_preset.completer().setFilterMode(Qt.MatchFlag.MatchContains)
581 self.input_report_preset.setPlaceholderText("Select a preset")
582 input_report_preset_btn=QPushButton("Insert")
583 input_report_preset_btn.clicked.connect(self.insert_preset_report)
584 layout_report2.addWidget(self.input_report_preset, 5)
585 layout_report2.addWidget(input_report_preset_btn, 1)
586 self.input_report=QTextEdit(self)
587 layout_report.addWidget(label_report)
588 layout_report.addLayout(layout_report2)
589 layout_report.addWidget(self.input_report)
590
591 tab_advice=QWidget(self)
592 layout_advice=QVBoxLayout(tab_advice)
593 layout_advice2=QHBoxLayout()
594 label_advice=QLabel("Advice")
595 self.input_advice_preset=QComboBox(self)
596 self.input_advice_preset.addItems(self.preset_advice.data.keys())
597 self.input_advice_preset.setCurrentIndex(-1)
598 self.input_advice_preset.setEditable(True)
599 self.input_advice_preset.completer().setCompletionMode(QCompleter.CompletionMode.PopupCompletion)
600 self.input_advice_preset.completer().setFilterMode(Qt.MatchFlag.MatchContains)
601 self.input_advice_preset.setPlaceholderText("Select a preset")
602 input_advice_preset_btn=QPushButton("Insert")
603 input_advice_preset_btn.clicked.connect(self.insert_preset_advice)
604 layout_advice2.addWidget(self.input_advice_preset, 5)
605 layout_advice2.addWidget(input_advice_preset_btn, 1)
606 self.input_advice=QTextEdit(self)
607 layout_advice.addWidget(label_advice)
608 layout_advice.addLayout(layout_advice2)
609 layout_advice.addWidget(self.input_advice)
610
611 tab_investigation=QWidget(self)
612 layout_investigation=QVBoxLayout(tab_investigation)
613 layout_investigation2=QHBoxLayout()
614 label_investigation=QLabel("Recommended Investigations")
615 self.input_investigation_preset=QComboBox(self)
616 self.input_investigation_preset.addItems(self.preset_investigation.data.keys())
617 self.input_investigation_preset.setCurrentIndex(-1)
618 self.input_investigation_preset.setEditable(True)
619 self.input_investigation_preset.completer().setCompletionMode(QCompleter.CompletionMode.PopupCompletion)
620 self.input_investigation_preset.completer().setFilterMode(Qt.MatchFlag.MatchContains)
621 self.input_investigation_preset.setPlaceholderText("Select a preset")
622 input_investigation_preset_btn=QPushButton("Insert")
623 input_investigation_preset_btn.clicked.connect(self.insert_preset_investigation)
624 layout_investigation2.addWidget(self.input_investigation_preset, 5)
625 layout_investigation2.addWidget(input_investigation_preset_btn, 1)
626 self.input_investigation=QTextEdit(self)
627 layout_investigation.addWidget(label_investigation)
628 layout_investigation.addLayout(layout_investigation2)
629 layout_investigation.addWidget(self.input_investigation)
630
631 tab_medication=QWidget(self)
632 layout_medication=QVBoxLayout(tab_medication)
633 layout_medication2=QHBoxLayout()
634 label_medication=QLabel("Medication Advice")
635 self.input_medication_preset=QComboBox(self)
636 self.input_medication_preset.addItems(self.preset_medication.data.keys())
637 self.input_medication_preset.setCurrentIndex(-1)
638 self.input_medication_preset.setEditable(True)
639 self.input_medication_preset.completer().setCompletionMode(QCompleter.CompletionMode.PopupCompletion)
640 self.input_medication_preset.completer().setFilterMode(Qt.MatchFlag.MatchContains)
641 self.input_medication_preset.setPlaceholderText("Select a preset")
642 input_medication_preset_btn=QPushButton("Insert")
643 input_medication_preset_btn.clicked.connect(self.insert_preset_medication)
644 layout_medication2.addWidget(self.input_medication_preset, 5)
645 layout_medication2.addWidget(input_medication_preset_btn, 1)
646 self.input_medication=QTextEdit(self)
647 layout_medication.addWidget(label_medication)
648 layout_medication.addLayout(layout_medication2)
649 layout_medication.addWidget(self.input_medication)
650
651 tab_additional=QWidget(self)
652 layout_additional=QVBoxLayout(tab_additional)
653 layout_additional2=QHBoxLayout()
654 label_additional=QLabel("Additional Advice")
655 self.input_additional_preset=QComboBox(self)
656 self.input_additional_preset.addItems(self.preset_additional.data.keys())
657 self.input_additional_preset.setCurrentIndex(-1)
658 self.input_additional_preset.setEditable(True)
659 self.input_additional_preset.completer().setCompletionMode(QCompleter.CompletionMode.PopupCompletion)
660 self.input_additional_preset.completer().setFilterMode(Qt.MatchFlag.MatchContains)
661 self.input_additional_preset.setPlaceholderText("Select a preset")
662 input_additional_preset_btn=QPushButton("Insert")
663 input_additional_preset_btn.clicked.connect(self.insert_preset_additional)
664 layout_additional2.addWidget(self.input_additional_preset, 5)
665 layout_additional2.addWidget(input_additional_preset_btn, 1)
666 self.input_additional=QTextEdit(self)
667 layout_additional.addWidget(label_additional)
668 layout_additional.addLayout(layout_additional2)
669 layout_additional.addWidget(self.input_additional)
670
671 tab_attachment=QWidget(self)
672 layout_attachment=QVBoxLayout(tab_attachment)
673 layout_attachment2=QHBoxLayout()
674 label_attachment=QLabel("Attached files")
675 self.input_attachment=QListWidget(self)
676 button_add=QPushButton("Add")
677 button_add.clicked.connect(self.add_attachment)
678 button_remove=QPushButton("Remove")
679 button_remove.clicked.connect(self.remove_attachment)
680 button_save=QPushButton("Save")
681 button_save.clicked.connect(self.save_attachment)
682 layout_attachment.addWidget(label_attachment)
683 layout_attachment.addLayout(layout_attachment2)
684 layout_attachment.addWidget(self.input_attachment)
685 layout_attachment2.addWidget(button_add)
686 layout_attachment2.addWidget(button_remove)
687 layout_attachment2.addWidget(button_save)
688
689 tab=QTabWidget(self)
690 tab.addTab(tab_info, "Patient")
691 tab.addTab(tab_note, "Clinical")
692 tab.addTab(tab_report, "Report")
693 tab.addTab(tab_advice, "Advice")
694 tab.addTab(tab_investigation, "Investigation")
695 tab.addTab(tab_medication, "Medication")
696 tab.addTab(tab_additional, "Additional")
697 tab.addTab(tab_attachment, "Attachment")
698
699 self.setCentralWidget(tab)
700
701 self.statusbar=QStatusBar()
702 self.setStatusBar(self.statusbar)
703
704 self.renderbox=RenderBox()
705 self.signal_view.connect(self.renderbox.update)
706 self.edit_configuration=EditConfiguration()
707 self.edit_prescriber=EditPrescriber()
708 self.edit_prescriber.signal_save.connect(self.cmd_prescriber_reload)
709 self.viewbox=ViewBox()
710
711 self.new_doc()
712 if(config["filename"]):
713 self.cmd_open(config["filename"])
714
715 if(len(self.prescription.prescriber.name.strip())<1):
716 self.cmd_prescriber()
717
718 self.setWindowIcon(QIcon(os.path.join("resource", "icon_medscript.ico")))
719 self.showMaximized()