]> Softwares of Agnibho - medscript.git/blob - window.py
Icon path
[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, real_dir, 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 year=datetime.datetime.now().year
185 if(year>2023):
186 copy="2023"+"-"+str(year)
187 else:
188 copy="2023"
189 txt="<h1>MedScript</h1>"
190 txt=txt+"<p>Version 0.2</p>"
191 txt=txt+"<p>The Prescription Writing Software</p>"
192 txt=txt+"<p><a href='https://code.agnibho.com/medscript/'>Website</a></p>"
193 txt=txt+"<p>Copyright © "+copy+" Dr. Agnibho Mondal</p>"
194 QMessageBox.about(self,"MedScript", txt)
195
196 def cmd_help(self):
197 self.viewbox.md(os.path.join(real_dir, "README"))
198 self.viewbox.show()
199
200 def insert_preset_extra(self):
201 try:
202 self.input_extra.insertPlainText(self.preset_extra.data[self.input_extra_preset.currentText()])
203 except KeyError:
204 self.input_extra.insertPlainText(self.input_extra_preset.currentText())
205 finally:
206 self.input_extra_preset.setCurrentIndex(-1)
207 if config["preset_newline"]:
208 self.input_extra.insertPlainText("\n")
209
210 def insert_preset_note(self):
211 try:
212 self.input_note.insertPlainText(self.preset_note.data[self.input_note_preset.currentText()])
213 except KeyError:
214 self.input_note.insertPlainText(self.input_note_preset.currentText())
215 finally:
216 self.input_note_preset.setCurrentIndex(-1)
217 if config["preset_newline"]:
218 self.input_note.insertPlainText("\n")
219
220 def insert_preset_report(self):
221 try:
222 self.input_report.insertPlainText(self.preset_report.data[self.input_report_preset.currentText()])
223 except KeyError:
224 self.input_report.insertPlainText(self.input_report_preset.currentText())
225 finally:
226 self.input_report_preset.setCurrentIndex(-1)
227 if config["preset_newline"]:
228 self.input_report.insertPlainText("\n")
229 def insert_preset_advice(self):
230 try:
231 self.input_advice.insertPlainText(self.preset_advice.data[self.input_advice_preset.currentText()])
232 except KeyError:
233 self.input_advice.insertPlainText(self.input_advice_preset.currentText())
234 finally:
235 self.input_advice_preset.setCurrentIndex(-1)
236 if config["preset_newline"]:
237 self.input_advice.insertPlainText("\n")
238
239
240 def insert_preset_investigation(self):
241 try:
242 self.input_investigation.insertPlainText(self.preset_investigation.data[self.input_investigation_preset.currentText()])
243 except KeyError:
244 self.input_investigation.insertPlainText(self.input_investigation_preset.currentText())
245 finally:
246 self.input_investigation_preset.setCurrentIndex(-1)
247 if config["preset_newline"]:
248 self.input_investigation.insertPlainText("\n")
249
250 def insert_preset_medication(self):
251 try:
252 self.input_medication.insertPlainText(self.preset_medication.data[self.input_medication_preset.currentText()])
253 except KeyError:
254 self.input_medication.insertPlainText(self.input_medication_preset.currentText())
255 finally:
256 self.input_medication_preset.setCurrentIndex(-1)
257 if config["preset_newline"]:
258 self.input_medication.insertPlainText("\n")
259
260 def insert_preset_additional(self):
261 try:
262 self.input_additional.insertPlainText(self.preset_additional.data[self.input_additional_preset.currentText()])
263 except KeyError:
264 self.input_additional.insertPlainText(self.input_additional_preset.currentText())
265 finally:
266 self.input_additional_preset.setCurrentIndex(-1)
267 if config["preset_newline"]:
268 self.input_additional.insertPlainText("\n")
269
270 def load_interface(self, file="", date=None, id="", name="", age="", sex="", address="", contact="", extra="", mode="", daw="", diagnosis="", note="", report="", advice="", investigation="", medication="", additional=""):
271 try:
272 file_msg=self.current_file.file if self.current_file.file else "New file"
273 sign_msg="(signed)" if sign_available and config["smime"] and self.current_file.is_signed() else ""
274 self.statusbar.showMessage(file_msg+" "+sign_msg)
275 if date is None:
276 d=QDateTime.currentDateTime()
277 else:
278 try:
279 pdate=dateutil.parser.parse(date)
280 d=QDateTime.fromString(pdate.strftime("%Y-%m-%d %H:%M:%S"), "yyyy-MM-dd hh:mm:ss")
281 except Exception as e:
282 QMessageBox.warning(self,"Failed to load", str(e))
283 print(e)
284 self.input_date.setDateTime(d)
285 self.input_id.setText(id)
286 self.input_name.setText(name)
287 self.input_age.setText(age)
288 self.input_sex.setCurrentText(sex)
289 self.input_address.setText(address)
290 self.input_contact.setText(contact)
291 self.input_extra.setText(extra)
292 self.input_mode.setCurrentText(mode)
293 self.input_daw.setChecked(bool(daw))
294 self.input_diagnosis.setText(diagnosis)
295 self.input_note.setText(note)
296 self.input_report.setText(report)
297 self.input_advice.setText(advice)
298 self.input_investigation.setText(investigation)
299 self.input_medication.setText(medication)
300 self.input_additional.setText(additional)
301 self.label_prescriber.setText(self.prescription.prescriber.name)
302 except Exception as e:
303 QMessageBox.warning(self,"Failed to load", "Failed to load the data into the application.")
304 print(e)
305
306 def load_interface_from_instance(self):
307 self.load_interface(
308 file=self.prescription.file,
309 date=self.prescription.date,
310 id=self.prescription.id,
311 name=self.prescription.name,
312 age=self.prescription.age,
313 sex=self.prescription.sex,
314 address=self.prescription.address,
315 contact=self.prescription.contact,
316 extra=self.prescription.extra,
317 mode=self.prescription.mode,
318 daw=self.prescription.daw,
319 diagnosis=self.prescription.diagnosis,
320 note=self.prescription.note,
321 report=self.prescription.report,
322 advice=self.prescription.advice,
323 investigation=self.prescription.investigation,
324 medication=self.prescription.medication,
325 additional=self.prescription.additional
326 )
327
328 def update_instance(self):
329 try:
330 self.prescription.set_data(
331 date=self.input_date.dateTime().toString("yyyy-MM-dd hh:mm:ss"),
332 id=self.input_id.text(),
333 name=self.input_name.text(),
334 age=self.input_age.text(),
335 sex=self.input_sex.currentText(),
336 address=self.input_address.text(),
337 contact=self.input_contact.text(),
338 extra=self.input_extra.toPlainText(),
339 mode=self.input_mode.currentText(),
340 daw=self.input_daw.isChecked(),
341 diagnosis=self.input_diagnosis.text(),
342 note=self.input_note.toPlainText(),
343 report=self.input_report.toPlainText(),
344 advice=self.input_advice.toPlainText(),
345 investigation=self.input_investigation.toPlainText(),
346 medication=self.input_medication.toPlainText(),
347 additional=self.input_additional.toPlainText()
348 )
349 except Exception as e:
350 QMessageBox.critical(self,"Failed", "Critical failure happned. Please check console for more info.")
351 print(e)
352
353 def new_doc(self):
354 self.current_file.reset()
355 self.prescription.set_data()
356 self.input_attachment.clear()
357 self.load_interface()
358 self.update_instance()
359 self.save_state=md5(self.prescription.get_json().encode()).hexdigest()
360
361 def refresh(self):
362 self.update_instance()
363 self.load_interface_from_instance()
364
365 def add_attachment(self):
366 try:
367 new=QFileDialog.getOpenFileName(self, "Open File", config["document_directory"], "PDF (*.pdf);; Images (*.jpg, *.jpeg, *.png, *.gif);; All Files (*)")[0]
368 if new:
369 self.input_attachment.addItem(new)
370 except Exception as e:
371 QMessageBox.warning(self,"Attach failed", "Failed to attach file.")
372 print(e)
373
374 def remove_attachment(self):
375 index=self.input_attachment.currentRow()
376 if(index>=0):
377 self.current_file.delete_attachment(self.input_attachment.item(index).text())
378 self.input_attachment.takeItem(index)
379 else:
380 QMessageBox.warning(self, "Select item", "Please select an attachment to remove.")
381
382 def save_attachment(self):
383 try:
384 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])
385 except Exception as e:
386 print(e)
387
388 def load_attachment(self, attachments):
389 for attach in attachments:
390 self.input_attachment.addItem(attach)
391
392 def confirm_close(self):
393 self.refresh()
394 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?"))
395 return flag
396
397 def closeEvent(self, event):
398 if(self.confirm_close()):
399 event.accept()
400 else:
401 event.ignore()
402
403 def __init__(self, *args, **kwargs):
404 super().__init__(*args, **kwargs)
405
406 global sign_available
407
408 self.setWindowTitle("MedScript")
409 self.setGeometry(100, 100, 600, 400)
410 self.setWindowIcon(QIcon(os.path.join(config["resource"], "icon_medscript.ico")))
411
412 icon_open=QIcon(os.path.join(config["resource"], "icon_open.svg"))
413 icon_save=QIcon(os.path.join(config["resource"], "icon_save.svg"))
414 icon_render=QIcon(os.path.join(config["resource"], "icon_render.svg"))
415 icon_refresh=QIcon(os.path.join(config["resource"], "icon_refresh.svg"))
416
417 self.preset_extra=Preset(os.path.join(config["preset_directory"], "certify.csv"))
418 self.preset_note=Preset(os.path.join(config["preset_directory"], "note.csv"))
419 self.preset_report=Preset(os.path.join(config["preset_directory"], "report.csv"))
420 self.preset_advice=Preset(os.path.join(config["preset_directory"], "advice.csv"))
421 self.preset_investigation=Preset(os.path.join(config["preset_directory"], "investigation.csv"))
422 self.preset_medication=Preset(os.path.join(config["preset_directory"], "medication.csv"), text_as_key=True)
423 self.preset_additional=Preset(os.path.join(config["preset_directory"], "additional.csv"))
424
425 action_new=QAction("New", self)
426 action_new.setShortcut("Ctrl+N")
427 action_new.triggered.connect(self.cmd_new)
428 action_open=QAction("Open", self)
429 action_open2=QAction(icon_open, "Open", self)
430 action_open.setShortcut("Ctrl+O")
431 action_open.triggered.connect(self.cmd_open)
432 action_open2.triggered.connect(self.cmd_open)
433 action_save=QAction("Save", self)
434 action_save2=QAction(icon_save, "Save", self)
435 action_save.setShortcut("Ctrl+S")
436 action_save.triggered.connect(self.cmd_save)
437 action_save2.triggered.connect(self.cmd_save)
438 action_save_as=QAction("Save As", self)
439 action_save_as.setShortcut("Ctrl+Shift+S")
440 action_save_as.triggered.connect(self.cmd_save_as)
441 action_refresh=QAction("Refresh", self)
442 action_refresh.setShortcut("F5")
443 action_refresh2=QAction(icon_refresh, "Refresh", self)
444 action_refresh.triggered.connect(self.cmd_refresh)
445 action_refresh2.triggered.connect(self.cmd_refresh)
446 action_quit=QAction("Quit", self)
447 action_quit.setShortcut("Ctrl+Q")
448 action_quit.triggered.connect(self.cmd_quit)
449 action_render=QAction("Render", self)
450 action_render.setShortcut("Ctrl+R")
451 action_render2=QAction(icon_render, "Render", self)
452 action_render.triggered.connect(self.cmd_render)
453 action_render2.triggered.connect(self.cmd_render)
454 action_sign=QAction("Sign", self)
455 action_sign.triggered.connect(self.cmd_sign)
456 action_unsign=QAction("Unsign", self)
457 action_unsign.triggered.connect(self.cmd_unsign)
458 action_verify=QAction("Verify", self)
459 action_verify.triggered.connect(self.cmd_verify)
460 action_configuration=QAction("Configuration", self)
461 action_configuration.triggered.connect(self.cmd_configuration)
462 action_prescriber=QAction("Prescriber", self)
463 action_prescriber.triggered.connect(self.cmd_prescriber)
464 action_switch=QAction("Switch", self)
465 action_switch.triggered.connect(self.cmd_switch)
466 action_about=QAction("About", self)
467 action_about.triggered.connect(self.cmd_about)
468 action_help=QAction("Help", self)
469 action_help.setShortcut("F1")
470 action_help.triggered.connect(self.cmd_help)
471
472 menubar=self.menuBar()
473 menu_file=menubar.addMenu("File")
474 menu_file.addAction(action_new)
475 menu_file.addAction(action_open)
476 menu_file.addAction(action_save)
477 menu_file.addAction(action_save_as)
478 menu_file.addAction(action_quit)
479 menu_prepare=menubar.addMenu("Prepare")
480 menu_prepare.addAction(action_render)
481 menu_prepare.addAction(action_refresh)
482 if(sign_available and config["smime"]):
483 menu_prepare.addAction(action_sign)
484 menu_prepare.addAction(action_unsign)
485 menu_prepare.addAction(action_verify)
486 menu_settings=menubar.addMenu("Settings")
487 menu_settings.addAction(action_configuration)
488 menu_settings.addAction(action_prescriber)
489 menu_settings.addAction(action_switch)
490 menu_help=menubar.addMenu("Help")
491 menu_help.addAction(action_about)
492 menu_help.addAction(action_help)
493
494 toolbar=QToolBar("Main Toolbar", floatable=False, movable=False)
495 toolbar.setIconSize(QSize(16, 16))
496 toolbar.addAction(action_open2)
497 toolbar.addAction(action_save2)
498 toolbar.addAction(action_refresh2)
499 toolbar.addAction(action_render2)
500 toolbar.addSeparator()
501 self.input_template=QComboBox(self)
502 templates=os.listdir(config["template_directory"])
503 try:
504 templates.remove(os.path.basename(config["template"]))
505 templates.insert(0, os.path.basename(config["template"]))
506 except Exception as e:
507 print(e)
508 self.input_template.addItems(templates)
509 toolbar.addWidget(self.input_template)
510 spacer=QWidget(self)
511 spacer.setSizePolicy(QSizePolicy.Policy.Expanding, QSizePolicy.Policy.Expanding)
512 toolbar.addWidget(spacer)
513 self.label_prescriber=QLabel(self)
514 toolbar.addWidget(self.label_prescriber)
515 self.addToolBar(toolbar)
516
517 tab_info=QWidget(self)
518 layout_info=QFormLayout(tab_info)
519 layout_info2=QHBoxLayout()
520 self.input_date=QDateTimeEdit(self)
521 self.input_date.setDisplayFormat("MMMM dd, yyyy hh:mm a")
522 layout_info.addRow("Date", self.input_date)
523 self.input_id=QLineEdit(self)
524 layout_info.addRow("ID", self.input_id)
525 self.input_name=QLineEdit(self)
526 layout_info.addRow("Name", self.input_name)
527 self.input_age=QLineEdit(self)
528 layout_info.addRow("Age", self.input_age)
529 self.input_sex=QComboBox(self)
530 self.input_sex.addItems(["Male", "Female", "Other"])
531 self.input_sex.setEditable(True)
532 layout_info.addRow("Sex", self.input_sex)
533 self.input_address=QLineEdit(self)
534 layout_info.addRow("Address", self.input_address)
535 self.input_contact=QLineEdit(self)
536 layout_info.addRow("Contact", self.input_contact)
537 self.input_diagnosis=QLineEdit(self)
538 layout_info.addRow("Diagnosis", self.input_diagnosis)
539 self.input_extra=QTextEdit(self)
540 self.input_extra_preset=QComboBox(self)
541 self.input_extra_preset.addItems(self.preset_extra.data.keys())
542 self.input_extra_preset.setCurrentIndex(-1)
543 self.input_extra_preset.setEditable(True)
544 self.input_extra_preset.completer().setCompletionMode(QCompleter.CompletionMode.PopupCompletion)
545 self.input_extra_preset.completer().setFilterMode(Qt.MatchFlag.MatchContains)
546 self.input_extra_preset.setPlaceholderText("Select a preset")
547 input_extra_preset_btn=QPushButton("Insert")
548 input_extra_preset_btn.clicked.connect(self.insert_preset_extra)
549 layout_info2.addWidget(self.input_extra_preset, 5)
550 layout_info2.addWidget(input_extra_preset_btn, 1)
551 layout_info.addRow("Certify\nPreset", layout_info2)
552 layout_info.addRow("Certify /\nExtra", self.input_extra)
553 self.input_mode=QComboBox(self)
554 self.input_mode.addItems(["In-Person", "Tele-Consultation", "Other"])
555 self.input_mode.setEditable(True)
556 layout_info.addRow("Mode", self.input_mode)
557 self.input_daw=QCheckBox("Dispense as written", self)
558 layout_info.addRow("DAW", self.input_daw)
559
560 tab_note=QWidget(self)
561 layout_note=QVBoxLayout(tab_note)
562 layout_note2=QHBoxLayout()
563 label_note=QLabel("Clinical Notes")
564 label_note.setProperty("class", "info_head")
565 self.input_note_preset=QComboBox(self)
566 self.input_note_preset.addItems(self.preset_note.data.keys())
567 self.input_note_preset.setCurrentIndex(-1)
568 self.input_note_preset.setEditable(True)
569 self.input_note_preset.completer().setCompletionMode(QCompleter.CompletionMode.PopupCompletion)
570 self.input_note_preset.completer().setFilterMode(Qt.MatchFlag.MatchContains)
571 self.input_note_preset.setPlaceholderText("Select a preset")
572 input_note_preset_btn=QPushButton("Insert")
573 input_note_preset_btn.clicked.connect(self.insert_preset_note)
574 layout_note2.addWidget(self.input_note_preset, 5)
575 layout_note2.addWidget(input_note_preset_btn, 1)
576 self.input_note=QTextEdit(self)
577 layout_note.addWidget(label_note)
578 layout_note.addLayout(layout_note2)
579 layout_note.addWidget(self.input_note)
580
581 tab_report=QWidget(self)
582 layout_report=QVBoxLayout(tab_report)
583 layout_report2=QHBoxLayout()
584 label_report=QLabel("Available Reports")
585 label_report.setProperty("class", "info_head")
586 self.input_report_preset=QComboBox(self)
587 self.input_report_preset.addItems(self.preset_report.data.keys())
588 self.input_report_preset.setCurrentIndex(-1)
589 self.input_report_preset.setEditable(True)
590 self.input_report_preset.completer().setCompletionMode(QCompleter.CompletionMode.PopupCompletion)
591 self.input_report_preset.completer().setFilterMode(Qt.MatchFlag.MatchContains)
592 self.input_report_preset.setPlaceholderText("Select a preset")
593 input_report_preset_btn=QPushButton("Insert")
594 input_report_preset_btn.clicked.connect(self.insert_preset_report)
595 layout_report2.addWidget(self.input_report_preset, 5)
596 layout_report2.addWidget(input_report_preset_btn, 1)
597 self.input_report=QTextEdit(self)
598 layout_report.addWidget(label_report)
599 layout_report.addLayout(layout_report2)
600 layout_report.addWidget(self.input_report)
601
602 tab_advice=QWidget(self)
603 layout_advice=QVBoxLayout(tab_advice)
604 layout_advice2=QHBoxLayout()
605 label_advice=QLabel("Advice")
606 label_advice.setProperty("class", "info_head")
607 self.input_advice_preset=QComboBox(self)
608 self.input_advice_preset.addItems(self.preset_advice.data.keys())
609 self.input_advice_preset.setCurrentIndex(-1)
610 self.input_advice_preset.setEditable(True)
611 self.input_advice_preset.completer().setCompletionMode(QCompleter.CompletionMode.PopupCompletion)
612 self.input_advice_preset.completer().setFilterMode(Qt.MatchFlag.MatchContains)
613 self.input_advice_preset.setPlaceholderText("Select a preset")
614 input_advice_preset_btn=QPushButton("Insert")
615 input_advice_preset_btn.clicked.connect(self.insert_preset_advice)
616 layout_advice2.addWidget(self.input_advice_preset, 5)
617 layout_advice2.addWidget(input_advice_preset_btn, 1)
618 self.input_advice=QTextEdit(self)
619 layout_advice.addWidget(label_advice)
620 layout_advice.addLayout(layout_advice2)
621 layout_advice.addWidget(self.input_advice)
622
623 tab_investigation=QWidget(self)
624 layout_investigation=QVBoxLayout(tab_investigation)
625 layout_investigation2=QHBoxLayout()
626 label_investigation=QLabel("Recommended Investigations")
627 label_investigation.setProperty("class", "info_head")
628 self.input_investigation_preset=QComboBox(self)
629 self.input_investigation_preset.addItems(self.preset_investigation.data.keys())
630 self.input_investigation_preset.setCurrentIndex(-1)
631 self.input_investigation_preset.setEditable(True)
632 self.input_investigation_preset.completer().setCompletionMode(QCompleter.CompletionMode.PopupCompletion)
633 self.input_investigation_preset.completer().setFilterMode(Qt.MatchFlag.MatchContains)
634 self.input_investigation_preset.setPlaceholderText("Select a preset")
635 input_investigation_preset_btn=QPushButton("Insert")
636 input_investigation_preset_btn.clicked.connect(self.insert_preset_investigation)
637 layout_investigation2.addWidget(self.input_investigation_preset, 5)
638 layout_investigation2.addWidget(input_investigation_preset_btn, 1)
639 self.input_investigation=QTextEdit(self)
640 layout_investigation.addWidget(label_investigation)
641 layout_investigation.addLayout(layout_investigation2)
642 layout_investigation.addWidget(self.input_investigation)
643
644 tab_medication=QWidget(self)
645 layout_medication=QVBoxLayout(tab_medication)
646 layout_medication2=QHBoxLayout()
647 label_medication=QLabel("Medication Advice")
648 label_medication.setProperty("class", "info_head")
649 self.input_medication_preset=QComboBox(self)
650 self.input_medication_preset.addItems(self.preset_medication.data.keys())
651 self.input_medication_preset.setCurrentIndex(-1)
652 self.input_medication_preset.setEditable(True)
653 self.input_medication_preset.completer().setCompletionMode(QCompleter.CompletionMode.PopupCompletion)
654 self.input_medication_preset.completer().setFilterMode(Qt.MatchFlag.MatchContains)
655 self.input_medication_preset.setPlaceholderText("Select a preset")
656 input_medication_preset_btn=QPushButton("Insert")
657 input_medication_preset_btn.clicked.connect(self.insert_preset_medication)
658 layout_medication2.addWidget(self.input_medication_preset, 5)
659 layout_medication2.addWidget(input_medication_preset_btn, 1)
660 self.input_medication=QTextEdit(self)
661 layout_medication.addWidget(label_medication)
662 layout_medication.addLayout(layout_medication2)
663 layout_medication.addWidget(self.input_medication)
664
665 tab_additional=QWidget(self)
666 layout_additional=QVBoxLayout(tab_additional)
667 layout_additional2=QHBoxLayout()
668 label_additional=QLabel("Additional Advice")
669 label_additional.setProperty("class", "info_head")
670 self.input_additional_preset=QComboBox(self)
671 self.input_additional_preset.addItems(self.preset_additional.data.keys())
672 self.input_additional_preset.setCurrentIndex(-1)
673 self.input_additional_preset.setEditable(True)
674 self.input_additional_preset.completer().setCompletionMode(QCompleter.CompletionMode.PopupCompletion)
675 self.input_additional_preset.completer().setFilterMode(Qt.MatchFlag.MatchContains)
676 self.input_additional_preset.setPlaceholderText("Select a preset")
677 input_additional_preset_btn=QPushButton("Insert")
678 input_additional_preset_btn.clicked.connect(self.insert_preset_additional)
679 layout_additional2.addWidget(self.input_additional_preset, 5)
680 layout_additional2.addWidget(input_additional_preset_btn, 1)
681 self.input_additional=QTextEdit(self)
682 layout_additional.addWidget(label_additional)
683 layout_additional.addLayout(layout_additional2)
684 layout_additional.addWidget(self.input_additional)
685
686 tab_attachment=QWidget(self)
687 layout_attachment=QVBoxLayout(tab_attachment)
688 layout_attachment2=QHBoxLayout()
689 label_attachment=QLabel("Attached files")
690 label_attachment.setProperty("class", "info_head")
691 self.input_attachment=QListWidget(self)
692 button_add=QPushButton("Add")
693 button_add.clicked.connect(self.add_attachment)
694 button_remove=QPushButton("Remove")
695 button_remove.clicked.connect(self.remove_attachment)
696 button_save=QPushButton("Save")
697 button_save.clicked.connect(self.save_attachment)
698 layout_attachment.addWidget(label_attachment)
699 layout_attachment.addLayout(layout_attachment2)
700 layout_attachment.addWidget(self.input_attachment)
701 layout_attachment2.addWidget(button_add)
702 layout_attachment2.addWidget(button_remove)
703 layout_attachment2.addWidget(button_save)
704
705 tab=QTabWidget(self)
706 tab.addTab(tab_info, "Patient")
707 tab.addTab(tab_note, "Clinical")
708 tab.addTab(tab_report, "Report")
709 tab.addTab(tab_advice, "Advice")
710 tab.addTab(tab_investigation, "Investigation")
711 tab.addTab(tab_medication, "Medication")
712 tab.addTab(tab_additional, "Additional")
713 tab.addTab(tab_attachment, "Attachment")
714
715 self.setCentralWidget(tab)
716
717 self.statusbar=QStatusBar()
718 self.setStatusBar(self.statusbar)
719
720 self.renderbox=RenderBox()
721 self.signal_view.connect(self.renderbox.update)
722 self.edit_configuration=EditConfiguration()
723 self.edit_prescriber=EditPrescriber()
724 self.edit_prescriber.signal_save.connect(self.cmd_prescriber_reload)
725 self.viewbox=ViewBox()
726
727 self.new_doc()
728 if(config["filename"]):
729 self.cmd_open(config["filename"])
730
731 if(len(self.prescription.prescriber.name.strip())<1):
732 self.cmd_prescriber()
733
734 self.setWindowIcon(QIcon(os.path.join(config["resource"], "icon_medscript.ico")))
735 self.showMaximized()