Compare commits
13 Commits
| Author | SHA1 | Date | |
|---|---|---|---|
| bdad077350 | |||
| 051e361c9f | |||
| 7cac3da421 | |||
| cb7a74d189 | |||
| 9c2c5d7d37 | |||
| 3640082b59 | |||
| 71bcf8c7df | |||
| 6994394da4 | |||
| 64ce267c84 | |||
| cd289303a6 | |||
| 87def4961c | |||
| a332aecd87 | |||
| fcf37b60c8 |
145
base.py
145
base.py
@@ -5,10 +5,11 @@ from collections import OrderedDict
|
|||||||
from datetime import datetime
|
from datetime import datetime
|
||||||
import getpass
|
import getpass
|
||||||
import h5py
|
import h5py
|
||||||
|
import logging
|
||||||
import inspect
|
import inspect
|
||||||
import platform
|
import platform
|
||||||
import re
|
|
||||||
import os
|
import os
|
||||||
|
import re
|
||||||
import sys
|
import sys
|
||||||
import time
|
import time
|
||||||
|
|
||||||
@@ -30,6 +31,8 @@ from pyqtacc.bdbase.readjson import ReadJSON
|
|||||||
from pyqtacc.bdbase.savehdf import QSaveHDF
|
from pyqtacc.bdbase.savehdf import QSaveHDF
|
||||||
from pyqtacc.bdbase.hdf5filemenu import HDF5GroupBox
|
from pyqtacc.bdbase.hdf5filemenu import HDF5GroupBox
|
||||||
from pyqtacc.bdbase.sendelog import QSendToELOG
|
from pyqtacc.bdbase.sendelog import QSendToELOG
|
||||||
|
|
||||||
|
|
||||||
from pyqtacc.bdbase.screenshot import QScreenshot
|
from pyqtacc.bdbase.screenshot import QScreenshot
|
||||||
from pyqtacc.bdbase.guiframe import GUIFrame
|
from pyqtacc.bdbase.guiframe import GUIFrame
|
||||||
|
|
||||||
@@ -101,32 +104,53 @@ class BaseWindow(QMainWindow):
|
|||||||
time_in_seconds=self.time_in_seconds,
|
time_in_seconds=self.time_in_seconds,
|
||||||
reanalysis_time_in_seconds=self.reanalysis_time)
|
reanalysis_time_in_seconds=self.reanalysis_time)
|
||||||
|
|
||||||
print("date_str", date_str, flush=True)
|
#print("date_str", date_str, flush=True)
|
||||||
|
|
||||||
|
write_message_fired = False
|
||||||
for i, (nfig, name) in enumerate(
|
for i, (nfig, name) in enumerate(
|
||||||
zip(self.settings.data["GUI"]["resultsSeq"],
|
zip(self.settings.data["GUI"]["resultsSeq"],
|
||||||
self.settings.data["GUI"]["subResultsTabTitle"])):
|
self.settings.data["GUI"]["subResultsTabTitle"])):
|
||||||
canvas = 'Canvas {0}'.format(i+1)
|
canvas = 'Canvas {0}'.format(i+1)
|
||||||
name_base = name.replace(' ', '_').lower()
|
name_base = name.replace(' ', '_').lower()
|
||||||
|
|
||||||
for idx in range(0, nfig):
|
if self.all_data['Figure data'][canvas] is not None:
|
||||||
|
nfig_canvas = len(self.all_data['Figure data'][canvas])
|
||||||
|
nfig_canvas = min(nfig_canvas, nfig)
|
||||||
|
else:
|
||||||
|
nfig_canvas = nfig
|
||||||
|
|
||||||
|
|
||||||
|
for idx in range(0, nfig_canvas):
|
||||||
if self.all_data['Figure data'][canvas] is not None:
|
if self.all_data['Figure data'][canvas] is not None:
|
||||||
|
|
||||||
name = name_base + "_{0}".format(
|
name = name_base + "_{0}".format(
|
||||||
idx) if idx > 0 else name_base
|
idx) if idx > 0 else name_base
|
||||||
save_dest = (folder_name + date_str + '_' + name +
|
save_dest = (folder_name + date_str + '_' + name +
|
||||||
'.png')
|
'.png')
|
||||||
print("idx", i, save_dest, flush=True)
|
|
||||||
if not os.path.exists(save_dest):
|
if not os.path.exists(save_dest):
|
||||||
if self.all_data['Figure data'][canvas][
|
if self.all_data['Figure data'][canvas][
|
||||||
idx] is not None:
|
idx] is not None:
|
||||||
self.all_data['Figure data'][canvas][
|
_dirname = os.path.dirname(save_dest)
|
||||||
idx].savefig(save_dest)
|
if os.access(_dirname, os.W_OK):
|
||||||
|
self.all_data['Figure data'][canvas][
|
||||||
|
idx].savefig(save_dest)
|
||||||
|
elif not write_message_fired:
|
||||||
|
_mess = ("Do not have write permission " +
|
||||||
|
"for directory {0} from this " +
|
||||||
|
"host {1}. Images not saved and " +
|
||||||
|
"cannot be sent to elog").format(
|
||||||
|
_dirname, os.uname()[1])
|
||||||
|
self.parent.trigger_log_message.emit(
|
||||||
|
MsgSeverity.WARN.name, _pymodule,
|
||||||
|
_line(), _mess, {})
|
||||||
|
write_message_fired = True
|
||||||
|
|
||||||
attach_files.append(save_dest)
|
attach_files.append(save_dest)
|
||||||
|
|
||||||
if attach_files:
|
if attach_files:
|
||||||
self.parent.attach_files = attach_files
|
self.parent.attach_files = attach_files
|
||||||
print("All files attached")
|
print("All files attached", flush=True)
|
||||||
else:
|
else:
|
||||||
print("No files to attach", flush=True)
|
print("No files to attach", flush=True)
|
||||||
time.sleep(0.2) #avoid race condition
|
time.sleep(0.2) #avoid race condition
|
||||||
@@ -276,12 +300,15 @@ class BaseWindow(QMainWindow):
|
|||||||
def run(self):
|
def run(self):
|
||||||
"""Run thread
|
"""Run thread
|
||||||
"""
|
"""
|
||||||
|
|
||||||
|
|
||||||
all_dict = self.analysis_procedure.measure_and_analyze(
|
all_dict = self.analysis_procedure.measure_and_analyze(
|
||||||
self.input_parameters)
|
self.input_parameters)
|
||||||
|
|
||||||
# Emit results
|
# Emit results
|
||||||
if all_dict is not None:
|
if all_dict:
|
||||||
self.trigger_thread_event.emit(all_dict)
|
self.trigger_thread_event.emit(all_dict)
|
||||||
|
|
||||||
mess = "Analysis completed"
|
mess = "Analysis completed"
|
||||||
self.parent.trigger_log_message.emit(
|
self.parent.trigger_log_message.emit(
|
||||||
MsgSeverity.INFO.name, _pymodule, _line(), mess, {})
|
MsgSeverity.INFO.name, _pymodule, _line(), mess, {})
|
||||||
@@ -293,7 +320,7 @@ class BaseWindow(QMainWindow):
|
|||||||
|
|
||||||
def __init__(self, parent=None, pymodule=None, appversion=None, title="",
|
def __init__(self, parent=None, pymodule=None, appversion=None, title="",
|
||||||
user_mode=UserMode.OPERATION, facility=Facility.SwissFEL,
|
user_mode=UserMode.OPERATION, facility=Facility.SwissFEL,
|
||||||
extended=True, has_optics=True):
|
extended=True, has_optics=True, has_procedure=True):
|
||||||
super(BaseWindow, self).__init__(parent)
|
super(BaseWindow, self).__init__(parent)
|
||||||
|
|
||||||
self.parent = parent
|
self.parent = parent
|
||||||
@@ -307,12 +334,18 @@ class BaseWindow(QMainWindow):
|
|||||||
self.facility = facility
|
self.facility = facility
|
||||||
self.user_mode = user_mode
|
self.user_mode = user_mode
|
||||||
self.appname, self.appext = self.pymodule.split(".")
|
self.appname, self.appext = self.pymodule.split(".")
|
||||||
|
|
||||||
|
|
||||||
print("=============================================")
|
print("=============================================")
|
||||||
print("Starting {0} at: {1}".format(self.appname, datetime.now()))
|
print("Starting {0} at: {1}".format(self.appname, datetime.now()))
|
||||||
print("User: {0} Host: {1}".format(os.getlogin(), os.uname()[1]))
|
print("User: {0} Host: {1}".format(os.getlogin(), os.uname()[1]))
|
||||||
print("=============================================", flush=True)
|
print("=============================================", flush=True)
|
||||||
|
|
||||||
|
self.settings = ReadJSON(self.appname)
|
||||||
|
|
||||||
|
|
||||||
|
#Read out current_logbook
|
||||||
|
|
||||||
self.cafe = PyCafe.CyCafe()
|
self.cafe = PyCafe.CyCafe()
|
||||||
self.cyca = PyCafe.CyCa()
|
self.cyca = PyCafe.CyCa()
|
||||||
self.cafe_exception = PyCafe.CafeException
|
self.cafe_exception = PyCafe.CafeException
|
||||||
@@ -332,7 +365,7 @@ class BaseWindow(QMainWindow):
|
|||||||
self.hdf_dialog = None
|
self.hdf_dialog = None
|
||||||
|
|
||||||
self.daq_analysis_completed = False
|
self.daq_analysis_completed = False
|
||||||
self.hdf_save_completed = False
|
|
||||||
|
|
||||||
self.setObjectName("MainWindow")
|
self.setObjectName("MainWindow")
|
||||||
self.setWindowTitle(self.appname)
|
self.setWindowTitle(self.appname)
|
||||||
@@ -343,8 +376,7 @@ class BaseWindow(QMainWindow):
|
|||||||
|
|
||||||
self.menu = self.menuBar()
|
self.menu = self.menuBar()
|
||||||
|
|
||||||
self.settings = ReadJSON(self.appname)
|
|
||||||
|
|
||||||
'''
|
'''
|
||||||
try:
|
try:
|
||||||
dirname = self.settings.data["stdout"]["destination"]
|
dirname = self.settings.data["stdout"]["destination"]
|
||||||
@@ -364,6 +396,12 @@ class BaseWindow(QMainWindow):
|
|||||||
self.stdlog_dest = (self.settings.data["stdlog"]["destination"] +
|
self.stdlog_dest = (self.settings.data["stdlog"]["destination"] +
|
||||||
self.appname + "-" + os.getlogin() + ".log")
|
self.appname + "-" + os.getlogin() + ".log")
|
||||||
|
|
||||||
|
self.logging = logging
|
||||||
|
#self.logging.basicConfig(filename=self.stdlog_dest, level=logging.DEBUG)
|
||||||
|
self.logging.basicConfig(level=logging.NOTSET)
|
||||||
|
self.logger = self.logging.getLogger(__name__)
|
||||||
|
self.logger.info("Logging activated")
|
||||||
|
|
||||||
self.date_str = None
|
self.date_str = None
|
||||||
self.autopost_elog = True
|
self.autopost_elog = True
|
||||||
|
|
||||||
@@ -382,13 +420,16 @@ class BaseWindow(QMainWindow):
|
|||||||
self.autopost_epics = self.settings.data["menuFlags"]["hasEpics"]
|
self.autopost_epics = self.settings.data["menuFlags"]["hasEpics"]
|
||||||
except KeyError as error:
|
except KeyError as error:
|
||||||
print("KeyError in base.py, init:", error)
|
print("KeyError in base.py, init:", error)
|
||||||
self.autopost_epics = True
|
self.autopost_epics = False
|
||||||
|
|
||||||
try:
|
try:
|
||||||
self.autopost_hdf = self.settings.data["menuFlags"]["hasH5"]
|
self.autopost_hdf = self.settings.data["menuFlags"]["hasH5"]
|
||||||
except KeyError as error:
|
except KeyError as error:
|
||||||
print("KeyError in base.py, init:", error)
|
print("KeyError in base.py, init:", error)
|
||||||
self.autopost_hdf = True
|
self.autopost_hdf = False
|
||||||
|
|
||||||
|
self.hdf_save_completed = False if self.autopost_hdf else True
|
||||||
|
|
||||||
|
|
||||||
self.all_input_parameters = {} #gui
|
self.all_input_parameters = {} #gui
|
||||||
self.all_input_labels = {} #gui
|
self.all_input_labels = {} #gui
|
||||||
@@ -412,7 +453,8 @@ class BaseWindow(QMainWindow):
|
|||||||
from src.analysis import AnalysisProcedure
|
from src.analysis import AnalysisProcedure
|
||||||
self.analysis_procedure = AnalysisProcedure(self)
|
self.analysis_procedure = AnalysisProcedure(self)
|
||||||
except ImportError as e:
|
except ImportError as e:
|
||||||
print("Import Error:", e)
|
print(("Base class without user supplied AnalysisProcedure class."
|
||||||
|
+ " mport Error:"), e)
|
||||||
|
|
||||||
##self.trigger_elog_entry.connect(self.receive_elog_notification)
|
##self.trigger_elog_entry.connect(self.receive_elog_notification)
|
||||||
##self.trigger_hdf_save.connect(self.save_to_hdf)
|
##self.trigger_hdf_save.connect(self.save_to_hdf)
|
||||||
@@ -463,18 +505,25 @@ class BaseWindow(QMainWindow):
|
|||||||
|
|
||||||
if self.facility == Facility.SwissFEL:
|
if self.facility == Facility.SwissFEL:
|
||||||
from pyqtacc.sf.guiheader import GUIHeader
|
from pyqtacc.sf.guiheader import GUIHeader
|
||||||
|
from pyqtacc.bdbase.sendelog import QSendToELOG
|
||||||
elif self.facility == Facility.SLS:
|
elif self.facility == Facility.SLS:
|
||||||
from pyqtacc.sls.guiheader import GUIHeader
|
from pyqtacc.sls.guiheader import GUIHeader
|
||||||
|
from pyqtacc.sls.sendelogsls import QSendToELOG
|
||||||
|
elif self.facility == Facility.HIPA:
|
||||||
|
from pyqtacc.hipa.guiheader import GUIHeader
|
||||||
|
from pyqtacc.hipa.sendeloghipa import QSendToELOG
|
||||||
|
|
||||||
self.gui_header = GUIHeader(self, user_mode=self.user_mode,
|
self.gui_header = GUIHeader(self, user_mode=self.user_mode,
|
||||||
extended=extended)
|
extended=extended)
|
||||||
self.mainwindow_layout.addWidget(self.gui_header.header_wgt)
|
self.mainwindow_layout.addWidget(self.gui_header.header_wgt)
|
||||||
|
|
||||||
self.gui_frame = GUIFrame(self, has_optics=self.has_optics)
|
self.gui_frame = GUIFrame(self, has_optics=self.has_optics,
|
||||||
|
has_procedure=has_procedure)
|
||||||
self.show_log_message = self.gui_frame.show_log_message
|
self.show_log_message = self.gui_frame.show_log_message
|
||||||
|
|
||||||
self.hdf_dock_widget = QNoDockWidget(" HDF5", self)
|
if self.autopost_hdf:
|
||||||
self.init_hdf_analysis_wgt()
|
self.hdf_dock_widget = QNoDockWidget(" HDF5", self)
|
||||||
|
self.init_hdf_analysis_wgt()
|
||||||
|
|
||||||
self.mainwindow_layout.addWidget(self.gui_frame.central_tab_widget)
|
self.mainwindow_layout.addWidget(self.gui_frame.central_tab_widget)
|
||||||
self.mainwindow.setLayout(self.mainwindow_layout)
|
self.mainwindow.setLayout(self.mainwindow_layout)
|
||||||
@@ -487,7 +536,7 @@ class BaseWindow(QMainWindow):
|
|||||||
self.mainwindow.setMinimumWidth(SLS_CENTRAL_WIDGET_MINIMUM_WIDTH)
|
self.mainwindow.setMinimumWidth(SLS_CENTRAL_WIDGET_MINIMUM_WIDTH)
|
||||||
|
|
||||||
self.setCentralWidget(self.mainwindow)
|
self.setCentralWidget(self.mainwindow)
|
||||||
self.show_log_message(MsgSeverity.INFO, _pymodule, _line(),
|
self.show_log_message(MsgSeverity.INFO.name, _pymodule, _line(),
|
||||||
"Application configured")
|
"Application configured")
|
||||||
|
|
||||||
|
|
||||||
@@ -523,7 +572,7 @@ class BaseWindow(QMainWindow):
|
|||||||
|
|
||||||
if self.settings.data["Parameters"][key]["flag"]:
|
if self.settings.data["Parameters"][key]["flag"]:
|
||||||
self.input_parameters[key] = val
|
self.input_parameters[key] = val
|
||||||
self.all_input_parameters[key] = val
|
self.all_input_parameters[key] = val
|
||||||
#print("val=",val, key)
|
#print("val=",val, key)
|
||||||
|
|
||||||
except KeyError as e:
|
except KeyError as e:
|
||||||
@@ -569,8 +618,8 @@ class BaseWindow(QMainWindow):
|
|||||||
|
|
||||||
if self.settings.data["Expert"][key]["flag"]:
|
if self.settings.data["Expert"][key]["flag"]:
|
||||||
self.expert_parameters[key] = val
|
self.expert_parameters[key] = val
|
||||||
self.all_expert_parameters[key] = val
|
self.all_expert_parameters[key] = val
|
||||||
#print("val=",val, key)
|
#print("val=",val, key)
|
||||||
|
|
||||||
except KeyError as e:
|
except KeyError as e:
|
||||||
print("Key Error in base.py initialization:", e)
|
print("Key Error in base.py initialization:", e)
|
||||||
@@ -811,7 +860,7 @@ class BaseWindow(QMainWindow):
|
|||||||
"""
|
"""
|
||||||
#Close all dock widgets
|
#Close all dock widgets
|
||||||
#self.removeDockWidget(self.hdf_dock_widget)
|
#self.removeDockWidget(self.hdf_dock_widget)
|
||||||
|
self.logger.info("Closing Application")
|
||||||
self.save_application_settings()
|
self.save_application_settings()
|
||||||
QApplication.processEvents()
|
QApplication.processEvents()
|
||||||
self.cafe.monitorStopAll()
|
self.cafe.monitorStopAll()
|
||||||
@@ -1147,6 +1196,7 @@ class BaseWindow(QMainWindow):
|
|||||||
#print("filename", self.hdf_filename)
|
#print("filename", self.hdf_filename)
|
||||||
|
|
||||||
def verify_send_to_elog(self):
|
def verify_send_to_elog(self):
|
||||||
|
|
||||||
if self.analysis_thread is not None:
|
if self.analysis_thread is not None:
|
||||||
if self.analysis_thread.isRunning():
|
if self.analysis_thread.isRunning():
|
||||||
_mess = ("Measurement in progress. " +
|
_mess = ("Measurement in progress. " +
|
||||||
@@ -1180,6 +1230,9 @@ class BaseWindow(QMainWindow):
|
|||||||
def send_to_elog(self):
|
def send_to_elog(self):
|
||||||
""" Response to elog_action; normally overwritten
|
""" Response to elog_action; normally overwritten
|
||||||
"""
|
"""
|
||||||
|
if not self.verify_send_to_elog():
|
||||||
|
return
|
||||||
|
'''
|
||||||
if self.analysis_thread is not None:
|
if self.analysis_thread is not None:
|
||||||
if self.analysis_thread.isRunning():
|
if self.analysis_thread.isRunning():
|
||||||
_mess = ("Measurement in progress. " +
|
_mess = ("Measurement in progress. " +
|
||||||
@@ -1188,6 +1241,7 @@ class BaseWindow(QMainWindow):
|
|||||||
QMessageBox.Ok)
|
QMessageBox.Ok)
|
||||||
|
|
||||||
return
|
return
|
||||||
|
'''
|
||||||
|
|
||||||
#_elog_sf = ElogSwissFEL()
|
#_elog_sf = ElogSwissFEL()
|
||||||
_logbook = None
|
_logbook = None
|
||||||
@@ -1197,6 +1251,7 @@ class BaseWindow(QMainWindow):
|
|||||||
_attach_files = []
|
_attach_files = []
|
||||||
_message = ""
|
_message = ""
|
||||||
|
|
||||||
|
|
||||||
QSendToELOG(self, logbook=_logbook, categoryIdx=_category_idx,
|
QSendToELOG(self, logbook=_logbook, categoryIdx=_category_idx,
|
||||||
domainIdx=_domain_idx, sectionIdx=_section_idx,
|
domainIdx=_domain_idx, sectionIdx=_section_idx,
|
||||||
title=self.title, message=_message,
|
title=self.title, message=_message,
|
||||||
@@ -1613,7 +1668,7 @@ class BaseWindow(QMainWindow):
|
|||||||
|
|
||||||
@Slot()
|
@Slot()
|
||||||
def start_analysis_thread(self):
|
def start_analysis_thread(self):
|
||||||
|
|
||||||
if not self.analysis_procedure:
|
if not self.analysis_procedure:
|
||||||
mess = "Analysis thread not configured for this application"
|
mess = "Analysis thread not configured for this application"
|
||||||
self.show_log_message(MsgSeverity.ERROR, _pymodule, _line(), mess)
|
self.show_log_message(MsgSeverity.ERROR, _pymodule, _line(), mess)
|
||||||
@@ -1636,17 +1691,17 @@ class BaseWindow(QMainWindow):
|
|||||||
|
|
||||||
if not self.verify_analysis_preconditions():
|
if not self.verify_analysis_preconditions():
|
||||||
return
|
return
|
||||||
|
|
||||||
|
|
||||||
self.analysis_thread = self.AnalysisThread(
|
self.analysis_thread = self.AnalysisThread(
|
||||||
self, self.analysis_procedure, self.input_parameters)
|
self, self.analysis_procedure, self.input_parameters)
|
||||||
|
|
||||||
self.analysis_thread.trigger_thread_event.connect(
|
self.analysis_thread.trigger_thread_event.connect(
|
||||||
self.receive_analysis_results)
|
self.receive_analysis_results)
|
||||||
|
|
||||||
self.analysis_thread.started.connect(self.analysis_thread_started)
|
self.analysis_thread.started.connect(self.analysis_thread_started)
|
||||||
self.analysis_thread.finished.connect(self.analysis_thread_finished)
|
self.analysis_thread.finished.connect(self.analysis_thread_finished)
|
||||||
|
|
||||||
#getMachineDatafor hdf
|
|
||||||
|
|
||||||
|
|
||||||
self.analysis_thread.start()
|
self.analysis_thread.start()
|
||||||
QApplication.processEvents()
|
QApplication.processEvents()
|
||||||
@@ -1686,17 +1741,26 @@ class BaseWindow(QMainWindow):
|
|||||||
|
|
||||||
@Slot(dict)
|
@Slot(dict)
|
||||||
def receive_analysis_results(self, all_dict):
|
def receive_analysis_results(self, all_dict):
|
||||||
#print("receive analysis results", all_dict)
|
|
||||||
self.all_data = all_dict
|
self.all_data = all_dict
|
||||||
self.gui_frame.canvas_update(all_dict['Figure data'])
|
self.gui_frame.canvas_update(all_dict['Figure data'])
|
||||||
|
|
||||||
|
if self.gui_frame.results_output_wgt_dict:
|
||||||
|
#all_dict['Processed data']['Results']={}
|
||||||
|
#all_dict['Processed data']['Results']['mean'] = 123.23
|
||||||
|
#all_dict['Processed data']['Results']['SD'] = 0.23
|
||||||
|
try:
|
||||||
|
results_data = all_dict['Processed data']['Results']
|
||||||
|
self.gui_frame.send_to_results_output_wgt(results_data)
|
||||||
|
except:
|
||||||
|
pass
|
||||||
|
|
||||||
self.gui_frame.central_tab_widget.setCurrentIndex(1)
|
self.gui_frame.central_tab_widget.setCurrentIndex(1)
|
||||||
self.gui_frame.results_tab_wgt.setCurrentIndex(0)
|
self.gui_frame.results_tab_wgt.setCurrentIndex(0)
|
||||||
|
|
||||||
@Slot()
|
@Slot()
|
||||||
def receive_abort_analysis(self):
|
def receive_abort_analysis(self):
|
||||||
"""Instantiate action on abort
|
"""Instantiate action on abort
|
||||||
"""
|
"""
|
||||||
print("Aborting")
|
|
||||||
if self.analysis_procedure.abort:
|
if self.analysis_procedure.abort:
|
||||||
return
|
return
|
||||||
self.gui_frame.in_abort_procedure()
|
self.gui_frame.in_abort_procedure()
|
||||||
@@ -1719,6 +1783,12 @@ class BaseWindow(QMainWindow):
|
|||||||
message="Measurement in progress..."):
|
message="Measurement in progress..."):
|
||||||
'''Receives update of message'''
|
'''Receives update of message'''
|
||||||
self.progressbar.setVisible(True)
|
self.progressbar.setVisible(True)
|
||||||
|
try:
|
||||||
|
if self.input_parameters["simulation"] :
|
||||||
|
self.progressbar_color = self.progressbar_simulation
|
||||||
|
except KeyError:
|
||||||
|
pass
|
||||||
|
|
||||||
if value == PROGRESS_BAR_THREAD_INIT:
|
if value == PROGRESS_BAR_THREAD_INIT:
|
||||||
self.progressbar.setVisible(False)
|
self.progressbar.setVisible(False)
|
||||||
self.progressbar.setFormat("")
|
self.progressbar.setFormat("")
|
||||||
@@ -1738,6 +1808,8 @@ class BaseWindow(QMainWindow):
|
|||||||
prog_val = re.findall(r'\d+', message)
|
prog_val = re.findall(r'\d+', message)
|
||||||
if prog_val:
|
if prog_val:
|
||||||
self.progressbar.setValue(int(prog_val[0]))
|
self.progressbar.setValue(int(prog_val[0]))
|
||||||
|
else:
|
||||||
|
self.progressbar.setValue(int(10))
|
||||||
mess = "Aborting measurement procedure"
|
mess = "Aborting measurement procedure"
|
||||||
self.show_log_message(
|
self.show_log_message(
|
||||||
MsgSeverity.WARN.name, _pymodule, _line(), mess)
|
MsgSeverity.WARN.name, _pymodule, _line(), mess)
|
||||||
@@ -1764,7 +1836,8 @@ class BaseWindow(QMainWindow):
|
|||||||
self.progressbar.setValue(value)
|
self.progressbar.setValue(value)
|
||||||
self.progressbar.setObjectName(self.progressbar_color)
|
self.progressbar.setObjectName(self.progressbar_color)
|
||||||
self.daq_analysis_completed = True
|
self.daq_analysis_completed = True
|
||||||
self.hdf_save_completed = False
|
if self.autopost_hdf:
|
||||||
|
self.hdf_save_completed = False
|
||||||
QTimer.singleShot(2000, lambda: self.progressbar.setVisible(False))
|
QTimer.singleShot(2000, lambda: self.progressbar.setVisible(False))
|
||||||
else:
|
else:
|
||||||
self.progressbar.setFormat(message)
|
self.progressbar.setFormat(message)
|
||||||
@@ -1774,7 +1847,7 @@ class BaseWindow(QMainWindow):
|
|||||||
self.progressbar.style().polish(self.progressbar)
|
self.progressbar.style().polish(self.progressbar)
|
||||||
QApplication.processEvents()
|
QApplication.processEvents()
|
||||||
time.sleep(0.0001)
|
time.sleep(0.0001)
|
||||||
|
|
||||||
|
|
||||||
def initialize_application(self, appname=_appname, delay=None,
|
def initialize_application(self, appname=_appname, delay=None,
|
||||||
facility=Facility.SwissFEL):
|
facility=Facility.SwissFEL):
|
||||||
@@ -1794,6 +1867,9 @@ class BaseWindow(QMainWindow):
|
|||||||
elif facility == Facility.SLS:
|
elif facility == Facility.SLS:
|
||||||
from pyqtacc.qrc_resources.facility.sls.pyrcc5 import qrc_resources
|
from pyqtacc.qrc_resources.facility.sls.pyrcc5 import qrc_resources
|
||||||
print("FACILITY SLS")
|
print("FACILITY SLS")
|
||||||
|
elif facility == Facility.HIPA:
|
||||||
|
from pyqtacc.qrc_resources.facility.hipa.pyrcc5 import qrc_resources
|
||||||
|
print("FACILITY HIPA")
|
||||||
else:
|
else:
|
||||||
print("Unknown Facility; assuming SLS")
|
print("Unknown Facility; assuming SLS")
|
||||||
from pyqtacc.qrc_resources.facility.sls.pyrcc5 import qrc_resources
|
from pyqtacc.qrc_resources.facility.sls.pyrcc5 import qrc_resources
|
||||||
@@ -1880,7 +1956,8 @@ class BaseWindow(QMainWindow):
|
|||||||
int_seconds_remaining = int(delay - (now-start1))
|
int_seconds_remaining = int(delay - (now-start1))
|
||||||
seconds_remaining = '{:2d}'.format(int_seconds_remaining)
|
seconds_remaining = '{:2d}'.format(int_seconds_remaining)
|
||||||
self.splash_progressbar.setValue(val)
|
self.splash_progressbar.setValue(val)
|
||||||
self.processEvents()
|
#self.processEvents()
|
||||||
|
self.flush()
|
||||||
sec_str = "s" if abs(int_seconds_remaining) != 1 else ""
|
sec_str = "s" if abs(int_seconds_remaining) != 1 else ""
|
||||||
mess = """
|
mess = """
|
||||||
<br><p style='color:black; font-weight:bold;
|
<br><p style='color:black; font-weight:bold;
|
||||||
|
|||||||
@@ -18,6 +18,7 @@ class Facility(IntEnum):
|
|||||||
PSI = 0
|
PSI = 0
|
||||||
SwissFEL = 1
|
SwissFEL = 1
|
||||||
SLS = 2
|
SLS = 2
|
||||||
|
HIPA = 3
|
||||||
|
|
||||||
class MsgSeverity(IntEnum):
|
class MsgSeverity(IntEnum):
|
||||||
""" For use with message logger
|
""" For use with message logger
|
||||||
@@ -35,6 +36,7 @@ class UserMode(IntEnum):
|
|||||||
OPERATION = 1
|
OPERATION = 1
|
||||||
EXPERT = 2
|
EXPERT = 2
|
||||||
SIMULATION = 3
|
SIMULATION = 3
|
||||||
|
|
||||||
|
|
||||||
|
|
||||||
|
|
||||||
|
|||||||
1531
guiframe.py
1531
guiframe.py
File diff suppressed because it is too large
Load Diff
10
sendelog.py
10
sendelog.py
@@ -34,6 +34,7 @@ class QSendToELOG(QDialog):
|
|||||||
attachFile=None, destination_folder=None):
|
attachFile=None, destination_folder=None):
|
||||||
#super(QSendToELOG, self).__init__(parent)
|
#super(QSendToELOG, self).__init__(parent)
|
||||||
super().__init__()
|
super().__init__()
|
||||||
|
|
||||||
self.files_text = ''
|
self.files_text = ''
|
||||||
self.fflag = False
|
self.fflag = False
|
||||||
self.parent = parent
|
self.parent = parent
|
||||||
@@ -43,7 +44,7 @@ class QSendToELOG(QDialog):
|
|||||||
self.destination = destination_folder
|
self.destination = destination_folder
|
||||||
self.window_title = self.parent.appname + ": " + _appname
|
self.window_title = self.parent.appname + ": " + _appname
|
||||||
self.pymodule = _pymodule
|
self.pymodule = _pymodule
|
||||||
|
|
||||||
self.setWindowTitle(self.window_title)
|
self.setWindowTitle(self.window_title)
|
||||||
|
|
||||||
elog_books = list(self.parent.settings.data["ElogBooks"])
|
elog_books = list(self.parent.settings.data["ElogBooks"])
|
||||||
@@ -51,6 +52,7 @@ class QSendToELOG(QDialog):
|
|||||||
self.elog_items.addItems(elog_books)
|
self.elog_items.addItems(elog_books)
|
||||||
self.elog_items.currentIndexChanged.connect(self.on_elog_change)
|
self.elog_items.currentIndexChanged.connect(self.on_elog_change)
|
||||||
idx = 0
|
idx = 0
|
||||||
|
|
||||||
if logbook is not None:
|
if logbook is not None:
|
||||||
try:
|
try:
|
||||||
idx = elog_books.index(logbook)
|
idx = elog_books.index(logbook)
|
||||||
@@ -144,7 +146,7 @@ class QSendToELOG(QDialog):
|
|||||||
|
|
||||||
self.files = []
|
self.files = []
|
||||||
self.attributes = {}
|
self.attributes = {}
|
||||||
|
|
||||||
self.layout = QVBoxLayout(self)
|
self.layout = QVBoxLayout(self)
|
||||||
self.layout.addLayout(logbook)
|
self.layout.addLayout(logbook)
|
||||||
self.layout.addLayout(self.applicationbox)
|
self.layout.addLayout(self.applicationbox)
|
||||||
@@ -187,7 +189,7 @@ class QSendToELOG(QDialog):
|
|||||||
self.fflag = True
|
self.fflag = True
|
||||||
|
|
||||||
filebox.addWidget(self.filesE)
|
filebox.addWidget(self.filesE)
|
||||||
|
|
||||||
openCloseVBox = QVBoxLayout()
|
openCloseVBox = QVBoxLayout()
|
||||||
self.openBtn = QPushButton('Add')
|
self.openBtn = QPushButton('Add')
|
||||||
self.openBtn.setAutoDefault(False)
|
self.openBtn.setAutoDefault(False)
|
||||||
@@ -216,7 +218,7 @@ class QSendToELOG(QDialog):
|
|||||||
self.messagelbl.setStyleSheet("QLabel { color : red; }")
|
self.messagelbl.setStyleSheet("QLabel { color : red; }")
|
||||||
self.layout.addWidget(self.messagelbl)
|
self.layout.addWidget(self.messagelbl)
|
||||||
self.layout.addLayout(btnLayout)
|
self.layout.addLayout(btnLayout)
|
||||||
|
|
||||||
self.setMinimumWidth(440)
|
self.setMinimumWidth(440)
|
||||||
self.exec()
|
self.exec()
|
||||||
|
|
||||||
|
|||||||
324
sendelogframe.py
Normal file
324
sendelogframe.py
Normal file
@@ -0,0 +1,324 @@
|
|||||||
|
import getpass
|
||||||
|
import inspect
|
||||||
|
import os
|
||||||
|
import time
|
||||||
|
|
||||||
|
from qtpy.QtCore import Qt
|
||||||
|
from qtpy.QtWidgets import (QComboBox, QDialog, QFileDialog, QHBoxLayout,
|
||||||
|
QLabel, QLineEdit, QPushButton, QTextEdit,
|
||||||
|
QVBoxLayout)
|
||||||
|
|
||||||
|
import elog # https://github.com/paulscherrerinstitute/py_elog
|
||||||
|
from pyqtacc.bdbase.enumkind import MsgSeverity
|
||||||
|
|
||||||
|
_version = "1.0.0"
|
||||||
|
_pymodule = os.path.basename(__file__)
|
||||||
|
_appname, _appext = _pymodule.split(".")
|
||||||
|
|
||||||
|
def _line():
|
||||||
|
"""Macro to return the current line number.
|
||||||
|
|
||||||
|
The current line number within the file is used when
|
||||||
|
reporting messages to the message logging window.
|
||||||
|
|
||||||
|
Returns:
|
||||||
|
int: Current line number.
|
||||||
|
"""
|
||||||
|
return inspect.currentframe().f_back.f_lineno
|
||||||
|
|
||||||
|
class QSendToELOGFrame(QDialog):
|
||||||
|
""" Graphical interface to elog
|
||||||
|
"""
|
||||||
|
def __init__(self, parent, logbook=None, title=None, message=None,
|
||||||
|
attachFile=None, destination_folder=None):
|
||||||
|
super().__init__()
|
||||||
|
|
||||||
|
self.files_text = ''
|
||||||
|
self.fflag = False
|
||||||
|
self.parent = parent
|
||||||
|
|
||||||
|
if destination_folder is None:
|
||||||
|
self.destination = self.parent.elog_dest + " / " + self.parent.appname
|
||||||
|
else:
|
||||||
|
self.destination = destination_folder
|
||||||
|
self.window_title = self.parent.appname + ": " + _appname
|
||||||
|
self.pymodule = _pymodule
|
||||||
|
|
||||||
|
self.setWindowTitle(self.window_title)
|
||||||
|
|
||||||
|
elog_books = list(self.parent.settings.data["ElogBooks"])
|
||||||
|
self.elog_items = QComboBox()
|
||||||
|
self.elog_items.addItems(elog_books)
|
||||||
|
self.elog_items.currentIndexChanged.connect(self.on_elog_change)
|
||||||
|
idx = 0
|
||||||
|
|
||||||
|
if logbook is not None:
|
||||||
|
try:
|
||||||
|
idx = elog_books.index(logbook)
|
||||||
|
except Exception:
|
||||||
|
mess = "Index not found for logbook {0}".format(logbook)
|
||||||
|
self.parent.show_log_message(MsgSeverity.WARN, self.pymodule,
|
||||||
|
_line(), mess)
|
||||||
|
|
||||||
|
|
||||||
|
else:
|
||||||
|
logbook = self.parent.settings.data["Elog"]["book"]
|
||||||
|
try:
|
||||||
|
idx = elog_books.index(logbook)
|
||||||
|
except Exception:
|
||||||
|
mess = "Index not found for logbook {0}".format(logbook)
|
||||||
|
self.parent.show_log_message(MsgSeverity.WARN, self.pymodule,
|
||||||
|
_line(), mess)
|
||||||
|
|
||||||
|
self.logbook = logbook
|
||||||
|
|
||||||
|
self.elog_items.setCurrentIndex(idx)
|
||||||
|
self.elog_items.currentIndexChanged.emit(idx)
|
||||||
|
self.elog_items.setObjectName("Elog")
|
||||||
|
|
||||||
|
self.title_items = QHBoxLayout()
|
||||||
|
self.title_items.addWidget(QLabel('Title: '))
|
||||||
|
self.titleline = QLineEdit()
|
||||||
|
self.titleline.setObjectName('Elog')
|
||||||
|
#self.titleline.setStatusTip('elog')
|
||||||
|
if title is None:
|
||||||
|
title = self.parent.appname
|
||||||
|
self.titleline.setText(str(title))
|
||||||
|
self.titleline.setFixedWidth(300)
|
||||||
|
self.titleline.setAlignment(Qt.AlignCenter)
|
||||||
|
self.title_items.addWidget(self.titleline)
|
||||||
|
|
||||||
|
self.applicationbox = QHBoxLayout()
|
||||||
|
self.applicationbox.addWidget(QLabel('Application:'))
|
||||||
|
self.applicationlabel = QLabel(self.parent.pymodule)
|
||||||
|
self.applicationlabel.setObjectName("Elog")
|
||||||
|
# self.applicationbox.addStretch()
|
||||||
|
self.applicationbox.addWidget(self.applicationlabel)
|
||||||
|
|
||||||
|
logbook = QHBoxLayout()
|
||||||
|
logbook.addWidget(QLabel('Logbook: '))
|
||||||
|
logbook.addWidget(self.elog_items)
|
||||||
|
|
||||||
|
|
||||||
|
authorbox = QHBoxLayout()
|
||||||
|
authorbox.addWidget(QLabel('Author: '))
|
||||||
|
self.author = QLineEdit()
|
||||||
|
self.author.setObjectName('Elog')
|
||||||
|
self.author.setFixedWidth(195)
|
||||||
|
self.author.setStatusTip('elog')
|
||||||
|
self.author.setText(getpass.getuser())
|
||||||
|
authorbox.addWidget(self.author)
|
||||||
|
|
||||||
|
self.files = []
|
||||||
|
self.attributes = {}
|
||||||
|
|
||||||
|
self.layout = QVBoxLayout(self)
|
||||||
|
self.layout.addLayout(logbook)
|
||||||
|
self.layout.addLayout(self.applicationbox)
|
||||||
|
|
||||||
|
self.layout.addLayout(authorbox)
|
||||||
|
self.layout.addLayout(self.title_items)
|
||||||
|
|
||||||
|
report = QLabel('Report: ')
|
||||||
|
self.layout.addWidget(report)
|
||||||
|
self.message = QTextEdit(message)
|
||||||
|
self.layout.addWidget(self.message)
|
||||||
|
|
||||||
|
filebox = QHBoxLayout()
|
||||||
|
qlfile = QLabel('Attach:')
|
||||||
|
qlfile.setAlignment(Qt.AlignTop)
|
||||||
|
filebox.addWidget(qlfile)
|
||||||
|
|
||||||
|
self.filesE = QTextEdit()
|
||||||
|
self.filesE.setAlignment(Qt.AlignTop)
|
||||||
|
self.filesE.setFixedHeight(80)
|
||||||
|
self.filesE.setReadOnly(True)
|
||||||
|
|
||||||
|
self.attachFile = attachFile
|
||||||
|
|
||||||
|
if self.attachFile is not None:
|
||||||
|
_attachFile = []
|
||||||
|
if isinstance(self.attachFile, str):
|
||||||
|
_attachFile.append(self.attachFile)
|
||||||
|
elif isinstance(self.attachFile, list):
|
||||||
|
_attachFile = self.attachFile
|
||||||
|
for i, file in enumerate(_attachFile):
|
||||||
|
_attach_base = os.path.basename(file)
|
||||||
|
if i > 0:
|
||||||
|
self.files_text += "\n"
|
||||||
|
self.files_text += str(_attach_base)
|
||||||
|
self.filesE.setText(self.files_text)
|
||||||
|
self.fflag = True
|
||||||
|
|
||||||
|
filebox.addWidget(self.filesE)
|
||||||
|
|
||||||
|
openCloseVBox = QVBoxLayout()
|
||||||
|
self.openBtn = QPushButton('Add')
|
||||||
|
self.openBtn.setAutoDefault(False)
|
||||||
|
self.openBtn.clicked.connect(self.openFiles)
|
||||||
|
openCloseVBox.addWidget(self.openBtn)
|
||||||
|
|
||||||
|
closeBtn = QPushButton('Clear')
|
||||||
|
closeBtn.setAutoDefault(False)
|
||||||
|
closeBtn.clicked.connect(self.clearFiles)
|
||||||
|
openCloseVBox.addWidget(closeBtn)
|
||||||
|
|
||||||
|
filebox.addLayout(openCloseVBox)
|
||||||
|
self.layout.addLayout(filebox)
|
||||||
|
|
||||||
|
btnLayout = QHBoxLayout()
|
||||||
|
self.okBtn = QPushButton('Send')
|
||||||
|
self.okBtn.setAutoDefault(False)
|
||||||
|
self.okBtn.clicked.connect(self.ok)
|
||||||
|
|
||||||
|
self.cancelBtn = QPushButton('Cancel')
|
||||||
|
self.cancelBtn.setAutoDefault(False)
|
||||||
|
self.cancelBtn.clicked.connect(self.close)
|
||||||
|
btnLayout.addWidget(self.okBtn)
|
||||||
|
btnLayout.addWidget(self.cancelBtn)
|
||||||
|
self.messagelbl = QLabel('')
|
||||||
|
self.messagelbl.setStyleSheet("QLabel { color : red; }")
|
||||||
|
self.layout.addWidget(self.messagelbl)
|
||||||
|
self.layout.addLayout(btnLayout)
|
||||||
|
|
||||||
|
self.setMinimumWidth(440)
|
||||||
|
#self.exec()
|
||||||
|
|
||||||
|
def on_elog_change(self, elog_change_val):
|
||||||
|
if "test" in self.elog_items.currentText():
|
||||||
|
_bgcolor = "QComboBox {background: plum; color : black;}"
|
||||||
|
else:
|
||||||
|
_bgcolor = "QComboBox {background: lightblue; color : black;}"
|
||||||
|
self.elog_items.setStyleSheet(_bgcolor)
|
||||||
|
|
||||||
|
|
||||||
|
def ok(self):
|
||||||
|
message = self.message.document().toPlainText()
|
||||||
|
if not message:
|
||||||
|
self.messagelbl.setText('Please enter a brief Report')
|
||||||
|
return
|
||||||
|
title = self.titleline.text()
|
||||||
|
if not title:
|
||||||
|
self.messagelbl.setText('Titel attribute is required')
|
||||||
|
return
|
||||||
|
|
||||||
|
author = self.author.text()
|
||||||
|
application = self.applicationlabel.text()
|
||||||
|
self.attributes['Autor'] = author
|
||||||
|
self.attributes['Author'] = author
|
||||||
|
self.attributes['Application'] = application
|
||||||
|
self.attributes['Titel'] = title
|
||||||
|
self.attributes['Title'] = title
|
||||||
|
self.attributes['When'] = str(time.time())
|
||||||
|
self.attributes['Wann'] = str(time.time())
|
||||||
|
|
||||||
|
|
||||||
|
|
||||||
|
if self.attachFile is not None:
|
||||||
|
_attachFile = []
|
||||||
|
if isinstance(self.attachFile, str):
|
||||||
|
_attachFile.append(self.attachFile)
|
||||||
|
elif isinstance(self.attachFile, list):
|
||||||
|
_attachFile = self.attachFile
|
||||||
|
for i in range(0, len(_attachFile)):
|
||||||
|
if "/tmp" in _attachFile[i]:
|
||||||
|
self.files.append(str(_attachFile[i]))
|
||||||
|
elif "/afs/psi.ch" in _attachFile[i]:
|
||||||
|
self.files.append(str(_attachFile[i]))
|
||||||
|
elif "/sls/bd/data/" in _attachFile[i]:
|
||||||
|
self.files.append(str(_attachFile[i]))
|
||||||
|
else:
|
||||||
|
self.files.append(self.destination + str(_attachFile[i]))
|
||||||
|
|
||||||
|
el = self.elog_items.currentText()
|
||||||
|
|
||||||
|
url = self.parent.settings.data["ElogBooks"][el]["url"]
|
||||||
|
|
||||||
|
self.logbook = elog.open(url, user='robot', password='robot')
|
||||||
|
|
||||||
|
|
||||||
|
try:
|
||||||
|
if self.files:
|
||||||
|
self.logbook.post(message, attributes=self.attributes,
|
||||||
|
attachments=self.files)
|
||||||
|
else:
|
||||||
|
self.logbook.post(message, attributes=self.attributes)
|
||||||
|
|
||||||
|
#self.trigger_elog_entry.emit(True, url, "OK")
|
||||||
|
self.receive_elog_notification(True, url, "OK")
|
||||||
|
except Exception as ex:
|
||||||
|
#self.trigger_elog_entry.emit(False, url, str(ex))
|
||||||
|
print("Exception in sendelog.py", str(ex))
|
||||||
|
self.receive_elog_notification(False, url, str(ex))
|
||||||
|
|
||||||
|
#for file in self.files:
|
||||||
|
# if os.path.exists(file):
|
||||||
|
# os.remove(file)
|
||||||
|
|
||||||
|
self.close()
|
||||||
|
|
||||||
|
|
||||||
|
def clearFiles(self):
|
||||||
|
self.attachFile = []
|
||||||
|
self.filesE.clear()
|
||||||
|
self.files = []
|
||||||
|
self.files_text = ''
|
||||||
|
self.fflag = False
|
||||||
|
|
||||||
|
def openFiles(self):
|
||||||
|
# Notethat openFiles also gets called when qDialog cacnel is clicked!
|
||||||
|
qFileDialog = QFileDialog()
|
||||||
|
extensions = ("Images (*.bmp *.eps *.gif *.jpeg *.jpg *.pdf *.png " +
|
||||||
|
"*.ps *.tiff *.xpm);;Text files (*.txt *.text);;" +
|
||||||
|
"JSON/XML files (*.json *.xml)")
|
||||||
|
|
||||||
|
flocal = qFileDialog.getOpenFileNames(
|
||||||
|
self, 'Open File', self.destination, extensions)[0]
|
||||||
|
|
||||||
|
if not flocal:
|
||||||
|
return
|
||||||
|
self.files.append(flocal[0])
|
||||||
|
if self.fflag:
|
||||||
|
self.files_text += '\n'
|
||||||
|
self.files_text += str(flocal[0].split('/')[-1])
|
||||||
|
self.fflag = True
|
||||||
|
self.filesE.setText(self.files_text)
|
||||||
|
|
||||||
|
|
||||||
|
def receive_elog_notification(self, is_accepted, logbook_url, elog_message):
|
||||||
|
'''Receive notification from ELOG, and report to log window'''
|
||||||
|
|
||||||
|
yes_no = "made" if is_accepted else "failed"
|
||||||
|
mess = "Entry into ELOG: {0} {1}".format(logbook_url, yes_no)
|
||||||
|
|
||||||
|
if is_accepted:
|
||||||
|
self.parent.show_log_message(MsgSeverity.INFO, self.pymodule,
|
||||||
|
_line(), mess)
|
||||||
|
else:
|
||||||
|
mess += ".\n" + elog_message
|
||||||
|
self.parent.show_log_message(MsgSeverity.WARN, self.pymodule,
|
||||||
|
_line(), mess)
|
||||||
|
self.parent.statusbar.showMessage(mess)
|
||||||
|
|
||||||
|
|
||||||
|
def get_logbook_specific_items(self, logbook):
|
||||||
|
'''Retrieve logbook specific options'''
|
||||||
|
#First check what is the logbook being requested?
|
||||||
|
#find layout items
|
||||||
|
layout_items = []
|
||||||
|
layout_items_optional = []
|
||||||
|
try:
|
||||||
|
layout_items = list(self.parent.settings.data[
|
||||||
|
"ElogBooks"][logbook]['Required'].keys())
|
||||||
|
except KeyError:
|
||||||
|
pass
|
||||||
|
try:
|
||||||
|
layout_items_optional = list(self.parent.settings.data[
|
||||||
|
"ElogBooks"][logbook]['Optional'].keys())
|
||||||
|
except KeyError:
|
||||||
|
pass
|
||||||
|
|
||||||
|
layout_items.extend(layout_items_optional)
|
||||||
|
|
||||||
|
return layout_items
|
||||||
|
|
||||||
Reference in New Issue
Block a user