from __future__ import annotations import datetime import os import pathlib import re from pathlib import Path from numpy import geomspace, linspace from pyqtgraph import ViewBox from nmreval.configs import * from nmreval.io.sessionwriter import NMRWriter from .management import UpperManagement from ..Qt import QtGui, QtPrintSupport from ..data.shift_graphs import QShift from ..data.signaledit import QApodDialog, QBaselineDialog, QPhasedialog from ..fit.result import FitExtension, QFitResult from ..graphs.graphwindow import QGraphWindow from ..graphs.movedialog import QMover from ..io.fcbatchreader import QFCReader from ..io.filedialog import * from ..lib import get_icon, make_action_icons from ..lib.pg_objects import RegionItem from ..math.evaluation import QEvalDialog from ..math.interpol import InterpolDialog from ..math.mean_dialog import QMeanTimes from ..math.smooth import QSmooth from ..nmr.coupling_calc import QCoupCalcDialog from ..nmr.t1_from_tau import QRelaxCalc from .._py.basewindow import Ui_BaseWindow from ..lib.utils import UpdateDialog, open_bug_report, Updater class NMRMainWindow(QtWidgets.QMainWindow, Ui_BaseWindow): closeSignal = QtCore.pyqtSignal() openpoints = QtCore.pyqtSignal(dict) save_ses_sig = QtCore.pyqtSignal(str) rest_ses_sig = QtCore.pyqtSignal(str) def __init__(self, parents=None, path=None): super().__init__(parent=parents) if path is None: self.path = Path.home() else: self.path = Path(path) self.read_state() self.management = UpperManagement(self) self.fitlimitvalues = [None, None] self.fitpreview = [] self._fit_plot_id = None self.savefitdialog = None self.eval = None self.editor = None self.movedialog = QMover(self) self.current_graph_widget = None self.current_plotitem = None self._block_window_change = False self.fname = None self.tim = QtCore.QTimer() self.settings = QtCore.QSettings('NMREVal', 'settings') self._init_gui() self._init_signals() if os.getenv('APPIMAGE') is not None: if Updater.get_update_information(os.getenv('APPIMAGE'))[0]: self.look_for_update() self.__timer = QtCore.QTimer() self.__backup_path = config_paths() / f'{datetime.datetime.now().strftime("%Y-%m-%d_%H%M%S")}.nmr' self.__timer.start(3*60*1000) # every three minutese self.__timer.timeout.connect(self._autosave) def _init_gui(self): self.setupUi(self) make_action_icons(self) self.setWindowIcon(get_icon('logo')) self.norm_toolbutton = QtWidgets.QToolButton(self) self.norm_toolbutton.setMenu(self.menuNormalize) self.norm_toolbutton.setPopupMode(self.norm_toolbutton.InstantPopup) self.norm_toolbutton.setIcon(get_icon('normal')) self.toolbar_edit.addWidget(self.norm_toolbutton) self.fitlim_button = QtWidgets.QToolButton(self) self.fitlim_button.setMenu(self.menuLimits) self.fitlim_button.setPopupMode(self.fitlim_button.InstantPopup) self.fitlim_button.setIcon(get_icon('fit_region')) self.toolBar_fit.addWidget(self.fitlim_button) self.area.dragEnterEvent = self.dragEnterEvent while self.tabWidget.count() > 2: self.tabWidget.removeTab(self.tabWidget.count()-1) # Prevent closing "data" and "values" for i in [0, 1]: self.tabWidget.tabBar().tabButton(i, QtWidgets.QTabBar.ButtonPosition.RightSide).resize(0, 0) self.setAcceptDrops(True) self.mousepos = QtWidgets.QLabel('') self.status = QtWidgets.QLabel('') self.statusBar.addWidget(self.status) self.statusBar.addWidget(self.mousepos) self.fitregion = RegionItem() self._fit_plot_id = None self.setGeometry(QtWidgets.QStyle.alignedRect(QtCore.Qt.LeftToRight, QtCore.Qt.AlignCenter, self.size(), QtWidgets.qApp.desktop().availableGeometry())) self.datawidget.management = self.management self.integralwidget.management = self.management self.drawingswidget.graphs = self.management.graphs self.ac_group = QtWidgets.QActionGroup(self) self.ac_group.addAction(self.action_lm_fit) self.ac_group.addAction(self.action_nm_fit) self.ac_group.addAction(self.action_odr_fit) self.ac_group2 = QtWidgets.QActionGroup(self) self.ac_group2.addAction(self.action_no_range) self.ac_group2.addAction(self.action_x_range) self.ac_group2.addAction(self.action_custom_range) def _init_signals(self): self.actionRedo = self.management.undostack.createRedoAction(self) icon = QtGui.QIcon.fromTheme("edit-redo") self.actionRedo.setIcon(icon) self.actionRedo.setShortcuts(QtGui.QKeySequence.Redo) self.menuData.insertAction(self.action_new_set, self.actionRedo) self.actionUndo = self.management.undostack.createUndoAction(self) self.actionUndo.setShortcuts(QtGui.QKeySequence.Undo) icon = QtGui.QIcon.fromTheme("edit-undo") self.actionUndo.setIcon(icon) self.menuData.insertAction(self.actionRedo, self.actionUndo) # self.actionSave.triggered.connect(lambda: self.management.save('/autohome/dominik/nmreval/testdata/test.nmr', '')) # self.actionSave.triggered.connect(self.save) self.action_save_fit_parameter.triggered.connect(self.save_fit_parameter) self.ac_group2.triggered.connect(self.change_fit_limits) self.t1action.triggered.connect(lambda: self._show_tab('t1_temp')) self.action_edit.triggered.connect(lambda: self._show_tab('signal')) self.actionPick_position.triggered.connect(lambda: self._show_tab('pick')) self.actionIntegration.triggered.connect(lambda: self._show_tab('integrate')) self.action_FitWidget.triggered.connect(lambda: self._show_tab('fit')) self.action_draw_object.triggered.connect(lambda: self._show_tab('drawing')) self.action_new_set.triggered.connect(self.management.create_empty) self.datawidget.keyChanged.connect(self.management.change_keys) self.datawidget.tree.deleteItem.connect(self.management.delete_sets) self.datawidget.tree.moveItem.connect(self.management.move_sets) self.datawidget.tree.copyItem.connect(self.management.copy_sets) self.datawidget.graph_toolButton.clicked.connect(self.new_graph) self.datawidget.empty_toolButton.clicked.connect(self.management.create_empty) self.datawidget.func_toolButton.clicked.connect(self.make_data_from_function) self.datawidget.tree.stateChanged.connect(self.management.change_visibility) self.datawidget.startShowProperty.connect(self.management.get_properties) self.datawidget.propertyChanged.connect(self.management.update_property) self.datawidget.tree.saveFits.connect(self.save_fit_parameter) self.datawidget.tree.extendFits.connect(self.extend_fit) self.management.newData.connect(self.show_new_data) self.management.newGraph.connect(self.new_graph) self.management.dataChanged.connect(self.update_data) self.management.deleteData.connect(self.delete_data) self.management.deleteGraph.connect(self.remove_graph) self.management.restoreGraph.connect(self.set_graph) self.management.properties_collected.connect(self.datawidget.set_properties) self.management.unset_state.connect(lambda x: self.datawidget.uncheck_sets(x)) self.management.fitFinished.connect(self.show_fit_results) self.fit_dialog._management = self.management self.fit_dialog.preview_emit.connect(self.show_fit_preview) self.fit_dialog.fitStartSig.connect(self.start_fit) self.fit_dialog.abortFit.connect(lambda : self.management.stopFit.emit()) self.movedialog.moveData.connect(self.move_sets) self.movedialog.copyData.connect(self.management.copy_sets) self.ptsselectwidget.points_selected.connect(self.management.extract_points) self.t1tauwidget.newData.connect(self.management.add_new_data) self.editsignalwidget.do_something.connect(self.management.apply) self.editsignalwidget.preview_triggered.connect(self.do_preview) self.action_sort_pts.triggered.connect(lambda: self.management.apply('sort', ())) self.action_calc_eps_derivative.triggered.connect(self.management.bds_deriv) self.action_magnitude.triggered.connect(self.management.calc_magn) self.actionCenterMax.triggered.connect(lambda: self.management.apply('center', ())) self.valuewidget.requestData.connect(self.show_data_values) self.valuewidget.itemChanged.connect(self.management.set_values) self.valuewidget.itemDeleted.connect(self.management.remove_values) self.valuewidget.itemAdded.connect(self.management.append) self.valuewidget.maskSignal.connect(self.management.mask_value) self.valuewidget.values_selected.connect(self.plot_selected_values) self.valuewidget.split_signal.connect(self.management.split_set) self.actionMaximize.triggered.connect(lambda: self.current_graph_widget.showMaximized()) self.actionNext_window.triggered.connect(lambda: self.area.activateNextSubWindow()) self.actionPrevious.triggered.connect(lambda: self.area.activatePreviousSubWindow()) self.closeSignal.connect(self.close) self.action_norm_max.triggered.connect(lambda: self.management.apply('norm', ('max',))) self.action_norm_max_abs.triggered.connect(lambda: self.management.apply('norm', ('maxabs',))) self.action_norm_first.triggered.connect(lambda: self.management.apply('norm', ('first',))) self.action_norm_last.triggered.connect(lambda: self.management.apply('norm', ('last',))) self.action_norm_area.triggered.connect(lambda: self.management.apply('norm', ('area',))) self.action_cut.triggered.connect(lambda: self.management.cut()) self.actionConcatenate_sets.triggered.connect(lambda : self.management.cat()) @QtCore.pyqtSlot(name='on_action_open_triggered') def open(self): filedialog = OpenFileDialog(directory=self.path, caption='Open files', filter='All files (*.*);;' 'Program session (*.nmr);;' 'HDF files (*.h5);;' 'Text files (*.txt *.dat);;' 'Novocontrol Alpha (*.EPS);;' 'TecMag files (*.tnt);;' 'Grace files (*.agr)') filedialog.set_graphs(self.management.graphs.list()) filedialog.exec() fname = filedialog.selectedFiles() if fname: self.path = Path(fname[0]).parent self.management.load_files(fname, new_plot=filedialog.add_to_graph) @QtCore.pyqtSlot(name='on_actionOpen_FC_triggered') def read_fc(self): reader = QFCReader(path=self.path, parent=self) reader.data_read.connect(self.management.add_new_data) reader.exec() del reader @QtCore.pyqtSlot(name='on_actionPrint_triggered') def print(self): QtPrintSupport.QPrintDialog().exec() @QtCore.pyqtSlot(name='on_actionExportData_triggered') @QtCore.pyqtSlot(name='on_actionSave_triggered') def save(self): save_dialog = SaveDirectoryDialog(directory=str(self.path), parent=self) mode = save_dialog.exec() if mode == QtWidgets.QDialog.Accepted: savefile = save_dialog.save_file() selected_filter = save_dialog.selectedNameFilter() if savefile is not None: self.path = savefile.parent use_underscore = save_dialog.checkBox.isChecked() self.management.save(savefile, selected_filter, strip_spaces=use_underscore) param_outfile = re.sub('[_\s-]?