Exemple #1
0
def get_dir_(dlgtype='native', path='path'):
    if path is None:
        path = ''
    # print(f'get_dir processed in {int(QThread.currentThreadId())}')
    dialog = QFileDialog(None)
    dialog.setFileMode(QFileDialog.Directory)
    dialog.setOption(QFileDialog.ShowDirsOnly, True)
    if dlgtype == 'qt':  # default to native unless qt is explicitly requested
        dialog.setOption(QFileDialog.DontUseNativeDialog, True)
    dialog.setViewMode(QFileDialog.Detail)
    if len(path) > 0 and QDir(path).exists():
        dialog.setDirectory(path)

    directory = ''
    absolutepath = False
    if dialog.exec() == QFileDialog.Accepted:
        dlg_out = dialog.selectedFiles()
        directory = dlg_out[0]
        absolutepath = dialog.directory().absolutePath()

    output = {
        'directory': directory,
        'absolutePath': absolutepath,
    }

    return output
Exemple #2
0
 def _on_dir_select_clicked(self):
     d = QFileDialog()
     d.setFileMode(QFileDialog.DirectoryOnly)
     d.exec_()
     dirpath = d.directory().absolutePath()
     if isinstance(dirpath, bytes):
         dirpath = dirpath.decode(
             "utf-8")  # TODO: Use the native encoding on Windows
     self._repo_edit.setText(dirpath)
Exemple #3
0
 def load_released(self):
     """Action performed on load button released."""
     dialog = QFileDialog(parent=self)
     dialog.setAcceptMode(QFileDialog.AcceptOpen)
     dialog.setNameFilter("Images (*.png *.jpg *.jpeg)")
     if self.last_dir:
         dialog.setDirectory(self.last_dir)
     if dialog.exec_():
         self.image_lbl.load(dialog.selectedFiles()[0])
         self.last_dir = dialog.directory().absolutePath()
Exemple #4
0
 def PickDir(self, checked):
     hmdr = os.getenv('HOME')
     dirDlg = QFileDialog(self)
     dirDlg.setFileMode(QFileDialog.Directory)
     dirDlg.setDirectory(hmdr)
     dirDlg.setNameFilter("Select A Directory (*)")
     if dirDlg.exec_():
         selDir = dirDlg.directory()
         dirName = selDir.absolutePath()
         if dirName != "":
             self.ui.diskFName.setText(dirName)
Exemple #5
0
 def chooseExportDir(self, givenDir=None):
     state = settings.exportFileDialogState()
     dialog = QFileDialog(self)
     if state:
         dialog.restoreState(state)
     dialogDir = dialog.directory()
     if givenDir is not None:
         dialog.setDirectory(givenDir)
     elif dialogDir is None:
         dialog.setDirectory(
             QStandardPaths.standardLocations(QStandardPaths.DocumentsLocation)[0]
         )
     dialog.setAcceptMode(QFileDialog.AcceptOpen)
     dialog.setFileMode(QFileDialog.Directory)
     ok = dialog.exec_()
     exportDir = QDir.toNativeSeparators(dialog.directory().absolutePath())
     if givenDir is not None:
         dialog.setDirectory(dialogDir)
     settings.setExportFileDialogState(dialog.saveState())
     if ok:
         self.exportDirectory = exportDir
Exemple #6
0
    def addFilesAction(self):
        if not self.gui_config.lastUsedPath:
            self.gui_config.lastUsedPath = os.path.expanduser('~')

        fileDialog = QFileDialog(self, _translate('fb2mobi-gui', 'Select files'), self.gui_config.lastUsedPath)
        fileDialog.setFileMode(QFileDialog.ExistingFiles)
        fileDialog.setNameFilters([_translate('fb2mobi-gui', 'Ebook files (*.fb2 *.fb2.zip *.zip *.epub)'), 
                                  _translate('fb2mobi-gui', 'All files (*.*)')])

        if fileDialog.exec_():
            self.gui_config.lastUsedPath = os.path.normpath(fileDialog.directory().absolutePath())
            file_list = fileDialog.selectedFiles()
            self.addFiles(file_list)
class FileChooserButton(QPushButton):
    path_chosen_signal = pyqtSignal(Path)  # emits the selected path

    def __init__(self, text, file_mode=QFileDialog.AnyFile, name_filters=None):
        super().__init__()
        self.file_mode = file_mode
        self.name_filters = name_filters
        self.selection_made = False
        self.path = None
        self.setText(text)
        self.clicked.connect(self.open_dialog)

    def open_dialog(self):
        """
        Opens a file chooser dialog to the user.
        """
        # regarding #setFileMode and why we don't use it:
        # QFileDialog.ExistingFiles appears to override QFileDialog.Directory,
        # so I don't see a way to support selecting multiple files and selecting
        # directories in the same widget, unless we make our own QDialog class.
        self.dialog = QFileDialog(self)
        self.dialog.setFileMode(self.file_mode)
        if self.name_filters:
            self.dialog.setNameFilters(self.name_filters)
        self.start_dir = self.dialog.directory().absolutePath()

        # recommended over #exec by qt https://doc.qt.io/qt-5/qdialog.html#exec
        self.dialog.open()
        self.dialog.finished.connect(self.process_selection)

    def process_selection(self):
        """
        process whatever the user has chosen (either a folder, file, or
        multiple files).
        """
        files = self.dialog.selectedFiles()
        # will only be 1 file at most, but could be 0 (if the user canceled)
        if not files:
            self.selection_made = False
            return
        path = files[0]
        self.selection_made = path != self.start_dir

        # TODO truncate path, ideally with qt size policies but might not be
        # possible with those alone
        path = Path(path)
        self.path = path
        self.path_chosen_signal.emit(path)
Exemple #8
0
 def on_anonymize(self):
     '''
     Slot that will be called if the user clicks the Anonymize button.
     It will pop up a dialog to chose the destination folder for the anonymized
     files
     '''
     images = self.dicom_parser.get_image_data()
     if images.shape[0]:
         dialog = QFileDialog(self, 'Select destination folder')
         dialog.setFileMode(QFileDialog.DirectoryOnly)
         dialog.setOption(QFileDialog.ShowDirsOnly, False)
         if(dialog.exec()):
             folder_path = dialog.directory().absolutePath()
             self.dicom_parser.annonymize(folder_path)
     else:
         print("Before annonymize, open a file or folder")
Exemple #9
0
class KangarooSettings(QWidget):
    _icon_filename = "kangaroo.png"
    saved_settings = pyqtSignal(str, str, int)

    def __init__(self, path_root, folder, filename, batch_size):
        super().__init__()
        uic.loadUi(AssetPath.getQtAsset(path_root, 'KangarooSettings'), self)
        self._window_icon = AssetPath.getAsset(path_root, self._icon_filename)

        self.folder = folder
        self.absolute_path = Path(folder).resolve()
        self.filename = filename
        self.batch_size = batch_size
        self.initUI()

    def initUI(self):
        self.setWindowFlags(self.windowFlags()
                            | Qt.WindowContextHelpButtonHint)
        self.setWindowIcon(QIcon(self._window_icon))
        self.folder_button.setText(self.folder)
        self.absolute_folder.setText(str(self.absolute_path))
        self.filename_format.setPlainText(self.filename)
        self.batch_size_spin.setValue(self.batch_size)

        self.folder_button.clicked.connect(self.chooseLocation)

        save_button = self.button_box.button(QDialogButtonBox.Save)
        save_button.clicked.connect(self.saveSettings)

    def chooseLocation(self):
        self.file_chooser = QFileDialog()
        self.file_chooser.setFileMode(QFileDialog.Directory)

        if self.file_chooser.exec():
            new_location = self.file_chooser.directory()

            self.absolute_path = Path(new_location.path()).resolve()
            self.folder = self.absolute_path.name

            self.folder_button.setText(self.folder)
            self.absolute_folder.setText(str(self.absolute_path))

    def saveSettings(self):
        self.close()
        self.saved_settings.emit(str(self.absolute_path),
                                 self.filename_format.toPlainText(),
                                 self.batch_size_spin.value())
Exemple #10
0
 def saveAllCsv(self):
     """Save data for all currently plotted lines"""
     #Harsha: Plots were saved in GUI folder instead provided QFileDialog box to save to
     #user choose
     fileDialog2 = QFileDialog(self)
     fileDialog2.setFileMode(QFileDialog.Directory)
     fileDialog2.setWindowTitle('Select Directory to save plots')
     fileDialog2.setOptions(QFileDialog.ShowDirsOnly)
     fileDialog2.setLabelText(QFileDialog.Accept, self.tr("Save"))
     targetPanel = QFrame(fileDialog2)
     targetPanel.setLayout(QVBoxLayout())
     layout = fileDialog2.layout()
     layout.addWidget(targetPanel)
     if fileDialog2.exec_():
         directory = fileDialog2.directory().path()
         for line in list(self.lineToDataSource.keys()):
             self.saveCsv(line, directory)
Exemple #11
0
    def on_click_load_folder(self):
        '''
        Slot executed when the Open folder button is pressed.
        It will show a file dialog where the user has to choose a folder.
        If a valid string is provided, then the folder path is provided to the
        DICOM parser to try to search and open files on it.

        Inspired in https://forum.qt.io/topic/62138/qfiledialog-choose-directories-only-but-show-files-as-well/8
        '''
        dialog = QFileDialog();
        dialog.setFileMode(QFileDialog.DirectoryOnly)
        dialog.setOption(QFileDialog.ShowDirsOnly, False)
        if(dialog.exec()):
            folder_name = dialog.directory().absolutePath()
            self.on_click_close_image()
            self.dicom_parser.request_open_folder(folder_name)
        else:
            print("No path value entered.")
Exemple #12
0
def get_file(file_filter: str, base_path: str, read: bool) -> str:
    """
    Shows a file dialog and returns the first chosen file
    :param read: true if the file id for reading, false if for writing into
    :param file_filter: file type filter
    :param base_path: base path to show to the user
    :return: None if no file was selected, path to the file otherwise
    """
    dlg = QFileDialog()
    dlg.resize(800, 500)
    dlg.setFileMode(QFileDialog.ExistingFile if read else QFileDialog.AnyFile)
    dlg.setAcceptMode(
        QFileDialog.AcceptOpen if read else QFileDialog.AcceptSave)
    dlg.setNameFilters([file_filter])
    dlg.selectNameFilter(file_filter)
    dlg.setDirectory(base_path[:-3])
    dlg.exec_()
    return dlg.selectedFiles()[0] if len(dlg.selectedFiles(
    )) > 0 and dlg.selectedFiles()[0] != dlg.directory().path() else None
Exemple #13
0
def get_files_(dlgtype='native', path=''):
    if path is None:
        path = ''
    # print(f'get_files processed in {int(QThread.currentThreadId())}')
    dialog = QFileDialog(None)
    dialog.setFileMode(QFileDialog.ExistingFiles)
    dialog.setViewMode(QFileDialog.Detail)
    if dlgtype == 'qt':  # default to native unless qt is explicitly requested
        dialog.setOption(QFileDialog.DontUseNativeDialog, True)
    dialog.setNameFilters(['Aperio SVS or CSV (*.svs *.csv)'])
    if len(path) > 0 and QDir(path).exists():
        dialog.setDirectory(path)

    files = []
    absolutepath = False
    if dialog.exec() == QFileDialog.Accepted:
        dlg_out = dialog.selectedFiles()
        files = dlg_out
        absolutepath = dialog.directory().absolutePath()

    output = {'files': files, 'absolutePath': absolutepath}
    return output
Exemple #14
0
    def requestWrite(self,
                     nodes,
                     file_name=None,
                     limit_mimetypes=None,
                     file_handler=None,
                     **kwargs):
        """Request the specified nodes to be written to a file.

        :param nodes: A collection of scene nodes that should be written to the
        file.
        :param file_name: A suggestion for the file name to write
        to. Can be freely ignored if providing a file name makes no sense.
        :param limit_mimetypes: Should we limit the available MIME types to the
        MIME types available to the currently active machine?
        :param kwargs: Keyword arguments.
        """

        if self._writing:
            raise OutputDeviceError.DeviceBusyError()

        # Set up and display file dialog
        dialog = QFileDialog()

        dialog.setWindowTitle(catalog.i18nc("@title:window", "Save to Disk"))
        dialog.setFileMode(QFileDialog.AnyFile)
        dialog.setAcceptMode(QFileDialog.AcceptSave)

        # Ensure platform never ask for overwrite confirmation since we do this ourselves
        dialog.setOption(QFileDialog.DontConfirmOverwrite)

        if sys.platform == "linux" and "KDE_FULL_SESSION" in os.environ:
            dialog.setOption(QFileDialog.DontUseNativeDialog)

        filters = []
        mime_types = []
        selected_filter = None

        if "preferred_mimetypes" in kwargs and kwargs[
                "preferred_mimetypes"] is not None:
            preferred_mimetypes = kwargs["preferred_mimetypes"]
        else:
            preferred_mimetypes = Application.getInstance().getPreferences(
            ).getValue("local_file/last_used_type")
        preferred_mimetype_list = preferred_mimetypes.split(";")

        if not file_handler:
            file_handler = Application.getInstance().getMeshFileHandler()

        file_types = file_handler.getSupportedFileTypesWrite()

        file_types.sort(key=lambda k: k["description"])
        if limit_mimetypes:
            file_types = list(
                filter(lambda i: i["mime_type"] in limit_mimetypes,
                       file_types))

        file_types = [ft for ft in file_types if not ft["hide_in_file_dialog"]]

        if len(file_types) == 0:
            Logger.log("e", "There are no file types available to write with!")
            raise OutputDeviceError.WriteRequestFailedError(
                catalog.i18nc(
                    "@info:warning",
                    "There are no file types available to write with!"))

        # Find the first available preferred mime type
        preferred_mimetype = None
        for mime_type in preferred_mimetype_list:
            if any(ft["mime_type"] == mime_type for ft in file_types):
                preferred_mimetype = mime_type
                break

        extension_added = False
        for item in file_types:
            type_filter = "{0} (*.{1})".format(item["description"],
                                               item["extension"])
            filters.append(type_filter)
            mime_types.append(item["mime_type"])
            if preferred_mimetype == item["mime_type"]:
                selected_filter = type_filter
                if file_name and not extension_added:
                    extension_added = True
                    file_name += "." + item["extension"]

        # CURA-6411: This code needs to be before dialog.selectFile and the filters, because otherwise in macOS (for some reason) the setDirectory call doesn't work.
        stored_directory = Application.getInstance().getPreferences().getValue(
            "local_file/dialog_save_path")
        if stored_directory and stored_directory != "":
            dialog.setDirectory(stored_directory)

        # Add the file name before adding the extension to the dialog
        if file_name is not None:
            dialog.selectFile(file_name)

        dialog.setNameFilters(filters)
        if selected_filter is not None:
            dialog.selectNameFilter(selected_filter)

        if not dialog.exec_():
            raise OutputDeviceError.UserCanceledError()

        save_path = dialog.directory().absolutePath()
        Application.getInstance().getPreferences().setValue(
            "local_file/dialog_save_path", save_path)

        selected_type = file_types[filters.index(dialog.selectedNameFilter())]
        Application.getInstance().getPreferences().setValue(
            "local_file/last_used_type", selected_type["mime_type"])

        # Get file name from file dialog
        file_name = dialog.selectedFiles()[0]
        Logger.log("d", "Writing to [%s]..." % file_name)

        if os.path.exists(file_name):
            result = QMessageBox.question(
                None, catalog.i18nc("@title:window", "File Already Exists"),
                catalog.i18nc(
                    "@label Don't translate the XML tag <filename>!",
                    "The file <filename>{0}</filename> already exists. Are you sure you want to overwrite it?"
                ).format(file_name))
            if result == QMessageBox.No:
                raise OutputDeviceError.UserCanceledError()

        self.writeStarted.emit(self)

        # Actually writing file
        if file_handler:
            file_writer = file_handler.getWriter(selected_type["id"])
        else:
            file_writer = Application.getInstance().getMeshFileHandler(
            ).getWriter(selected_type["id"])

        try:
            mode = selected_type["mode"]
            if mode == MeshWriter.OutputMode.TextMode:
                Logger.log("d", "Writing to Local File %s in text mode",
                           file_name)
                stream = open(file_name, "wt", encoding="utf-8")
            elif mode == MeshWriter.OutputMode.BinaryMode:
                Logger.log("d", "Writing to Local File %s in binary mode",
                           file_name)
                stream = open(file_name, "wb")
            else:
                Logger.log("e", "Unrecognised OutputMode.")
                return None

            job = WriteFileJob(file_writer, stream, nodes, mode)
            job.setFileName(file_name)
            job.setAddToRecentFiles(
                True
            )  # The file will be added into the "recent files" list upon success
            job.progress.connect(self._onJobProgress)
            job.finished.connect(self._onWriteJobFinished)

            message = Message(
                catalog.i18nc(
                    "@info:progress Don't translate the XML tags <filename>!",
                    "Saving to <filename>{0}</filename>").format(file_name), 0,
                False, -1, catalog.i18nc("@info:title", "Saving"))
            message.show()

            job.setMessage(message)
            self._writing = True
            job.start()
        except PermissionError as e:
            Logger.log("e", "Permission denied when trying to write to %s: %s",
                       file_name, str(e))
            raise OutputDeviceError.PermissionDeniedError(
                catalog.i18nc(
                    "@info:status Don't translate the XML tags <filename>!",
                    "Permission denied when trying to save <filename>{0}</filename>"
                ).format(file_name)) from e
        except OSError as e:
            Logger.log("e",
                       "Operating system would not let us write to %s: %s",
                       file_name, str(e))
            raise OutputDeviceError.WriteRequestFailedError(
                catalog.i18nc(
                    "@info:status Don't translate the XML tags <filename> or <message>!",
                    "Could not save to <filename>{0}</filename>: <message>{1}</message>"
                ).format(file_name, str(e))) from e
Exemple #15
0
    def browse(self):
        """
        Open a file dialog and select a user specified file.
        """
        formats = [
            "Text - comma separated (*.csv, *)",
            "Text - tab separated (*.tsv, *)",
            "Text - all files (*)"
        ]

        dlg = QFileDialog(
            self, windowTitle="Open Data File",
            acceptMode=QFileDialog.AcceptOpen,
            fileMode=QFileDialog.ExistingFile
        )
        dlg.setNameFilters(formats)
        state = self.dialog_state
        lastdir = state.get("directory", "")
        lastfilter = state.get("filter", "")

        if lastdir and os.path.isdir(lastdir):
            dlg.setDirectory(lastdir)
        if lastfilter:
            dlg.selectNameFilter(lastfilter)

        status = dlg.exec_()
        dlg.deleteLater()
        if status == QFileDialog.Accepted:
            self.dialog_state["directory"] = dlg.directory().absolutePath()
            self.dialog_state["filter"] = dlg.selectedNameFilter()

            selected_filter = dlg.selectedNameFilter()
            path = dlg.selectedFiles()[0]
            # pre-flight check; try to determine the nature of the file
            mtype = _mime_type_for_path(path)
            if not mtype.inherits("text/plain"):
                mb = QMessageBox(
                    parent=self,
                    windowTitle="",
                    icon=QMessageBox.Question,
                    text="The '{basename}' may be a binary file.\n"
                         "Are you sure you want to continue?".format(
                             basename=os.path.basename(path)),
                    standardButtons=QMessageBox.Cancel | QMessageBox.Yes
                )
                mb.setWindowModality(Qt.WindowModal)
                if mb.exec() == QMessageBox.Cancel:
                    return

            # initialize dialect based on selected extension
            if selected_filter in formats[:-1]:
                filter_idx = formats.index(selected_filter)
                if filter_idx == 0:
                    dialect = csv.excel()
                elif filter_idx == 1:
                    dialect = csv.excel_tab()
                else:
                    dialect = csv.excel_tab()
                header = True
            else:
                try:
                    dialect, header = sniff_csv_with_path(path)
                except Exception:  # pylint: disable=broad-except
                    dialect, header = csv.excel(), True

            options = None
            # Search for path in history.
            # If found use the stored params to initialize the import dialog
            items = self.itemsFromSettings()
            idx = index_where(items, lambda t: samepath(t[0], path))
            if idx is not None:
                _, options_ = items[idx]
                if options_ is not None:
                    options = options_

            if options is None:
                if not header:
                    rowspec = []
                else:
                    rowspec = [(range(0, 1), RowSpec.Header)]
                options = Options(
                    encoding="utf-8", dialect=dialect, rowspec=rowspec)

            dlg = CSVImportDialog(
                self, windowTitle="Import Options", sizeGripEnabled=True)
            dlg.setWindowModality(Qt.WindowModal)
            dlg.setPath(path)
            dlg.setOptions(options)
            status = dlg.exec_()
            dlg.deleteLater()
            if status == QDialog.Accepted:
                self.set_selected_file(path, dlg.options())
    def requestWrite(self,
                     nodes,
                     file_name=None,
                     limit_mimetypes=None,
                     file_handler=None,
                     **kwargs):
        if self._writing:
            raise OutputDeviceError.DeviceBusyError()

            # Set up and display file dialog
        dialog = QFileDialog()

        dialog.setWindowTitle(catalog.i18nc("@title:window", "Save to File"))
        dialog.setFileMode(QFileDialog.AnyFile)
        dialog.setAcceptMode(QFileDialog.AcceptSave)

        # Ensure platform never ask for overwrite confirmation since we do this ourselves
        dialog.setOption(QFileDialog.DontConfirmOverwrite)

        if sys.platform == "linux" and "KDE_FULL_SESSION" in os.environ:
            dialog.setOption(QFileDialog.DontUseNativeDialog)

        filters = []
        mime_types = []
        selected_filter = None
        last_used_type = self._preferences.getValue(
            "local_file/last_used_type")

        if not file_handler:
            file_handler = Application.getInstance().getMeshFileHandler()

        file_types = file_handler.getSupportedFileTypesWrite()

        file_types.sort(key=lambda k: k["description"])
        if limit_mimetypes:
            file_types = list(
                filter(lambda i: i["mime_type"] in limit_mimetypes,
                       file_types))

        if len(file_types) == 0:
            Logger.log("e", "There are no file types available to write with!")
            raise OutputDeviceError.WriteRequestFailedError()

        for item in file_types:
            type_filter = "{0} (*.{1})".format(item["description"],
                                               item["extension"])
            filters.append(type_filter)
            mime_types.append(item["mime_type"])
            if last_used_type == item["mime_type"]:
                selected_filter = type_filter
                if file_name:
                    file_name += "." + item["extension"]

        dialog.setNameFilters(filters)
        if selected_filter is not None:
            dialog.selectNameFilter(selected_filter)

        if file_name is not None:
            dialog.selectFile(file_name)

        stored_directory = self._preferences.getValue(
            "local_file/dialog_save_path")
        dialog.setDirectory(stored_directory)

        if not dialog.exec_():
            raise OutputDeviceError.UserCanceledError()

        save_path = dialog.directory().absolutePath()
        self._preferences.setValue("local_file/dialog_save_path", save_path)

        selected_type = file_types[filters.index(dialog.selectedNameFilter())]
        self._preferences.setValue("local_file/last_used_type",
                                   selected_type["mime_type"])

        # Get file name from file dialog
        file_name = dialog.selectedFiles()[0]
        active_build_plate = Application.getInstance().getMultiBuildPlateModel(
        ).activeBuildPlate
        scene = Application.getInstance().getController().getScene()
        gcode_dict = getattr(scene, "gcode_dict", None)
        if not gcode_dict:
            return
        _gcode = gcode_dict.get(active_build_plate, None)
        self.save_gcode(file_name, _gcode)
    def browse(self):
        """
        Open a file dialog and select a user specified file.
        """
        formats = [
            "Text - comma separated (*.csv, *)",
            "Text - tab separated (*.tsv, *)",
            "Text - all files (*)"
        ]

        dlg = QFileDialog(
            self, windowTitle="Open Data File",
            acceptMode=QFileDialog.AcceptOpen,
            fileMode=QFileDialog.ExistingFile
        )
        dlg.setNameFilters(formats)
        state = self.dialog_state
        lastdir = state.get("directory", "")
        lastfilter = state.get("filter", "")

        if lastdir and os.path.isdir(lastdir):
            dlg.setDirectory(lastdir)
        if lastfilter:
            dlg.selectNameFilter(lastfilter)

        status = dlg.exec_()
        dlg.deleteLater()
        if status == QFileDialog.Accepted:
            self.dialog_state["directory"] = dlg.directory().absolutePath()
            self.dialog_state["filter"] = dlg.selectedNameFilter()

            selected_filter = dlg.selectedNameFilter()
            path = dlg.selectedFiles()[0]
            # pre-flight check; try to determine the nature of the file
            mtype = _mime_type_for_path(path)
            if not mtype.inherits("text/plain"):
                mb = QMessageBox(
                    parent=self,
                    windowTitle="",
                    icon=QMessageBox.Question,
                    text="The '{basename}' may be a binary file.\n"
                         "Are you sure you want to continue?".format(
                            basename=os.path.basename(path)),
                    standardButtons=QMessageBox.Cancel | QMessageBox.Yes
                )
                mb.setWindowModality(Qt.WindowModal)
                if mb.exec() == QMessageBox.Cancel:
                    return

            # initialize dialect based on selected extension
            if selected_filter in formats[:-1]:
                filter_idx = formats.index(selected_filter)
                if filter_idx == 0:
                    dialect = csv.excel()
                elif filter_idx == 1:
                    dialect = csv.excel_tab()
                else:
                    dialect = csv.excel_tab()
                header = True
            else:
                try:
                    dialect, header = sniff_csv_with_path(path)
                except Exception:
                    dialect, header = csv.excel(), True

            options = None
            # Search for path in history.
            # If found use the stored params to initialize the import dialog
            items = self.itemsFromSettings()
            idx = index_where(items, lambda t: samepath(t[0], path))
            if idx is not None:
                _, options_ = items[idx]
                if options_ is not None:
                    options = options_

            if options is None:
                if not header:
                    rowspec = []
                else:
                    rowspec = [(range(0, 1), RowSpec.Header)]
                options = Options(
                    encoding="utf-8", dialect=dialect, rowspec=rowspec)

            dlg = CSVImportDialog(
                self, windowTitle="Import Options",  sizeGripEnabled=True)
            dlg.setWindowModality(Qt.WindowModal)
            dlg.setPath(path)
            dlg.setOptions(options)
            status = dlg.exec_()
            dlg.deleteLater()
            if status == QDialog.Accepted:
                self.set_selected_file(path, dlg.options())
    def requestWrite(self, nodes, file_name = None, limit_mimetypes = None, file_handler = None, **kwargs):
        if self._writing:
            raise OutputDeviceError.DeviceBusyError()

        # Set up and display file dialog
        dialog = QFileDialog()

        dialog.setWindowTitle(catalog.i18nc("@title:window", "Save to File"))
        dialog.setFileMode(QFileDialog.AnyFile)
        dialog.setAcceptMode(QFileDialog.AcceptSave)

        # Ensure platform never ask for overwrite confirmation since we do this ourselves
        dialog.setOption(QFileDialog.DontConfirmOverwrite)

        if sys.platform == "linux" and "KDE_FULL_SESSION" in os.environ:
            dialog.setOption(QFileDialog.DontUseNativeDialog)

        filters = []
        mime_types = []
        selected_filter = None

        if "preferred_mimetype" in kwargs and kwargs["preferred_mimetype"] is not None:
            preferred_mimetype = kwargs["preferred_mimetype"]
        else:
            preferred_mimetype = Preferences.getInstance().getValue("local_file/last_used_type")

        if not file_handler:
            file_handler = Application.getInstance().getMeshFileHandler()

        file_types = file_handler.getSupportedFileTypesWrite()

        file_types.sort(key = lambda k: k["description"])
        if limit_mimetypes:
            file_types = list(filter(lambda i: i["mime_type"] in limit_mimetypes, file_types))

        if len(file_types) == 0:
            Logger.log("e", "There are no file types available to write with!")
            raise OutputDeviceError.WriteRequestFailedError()

        for item in file_types:
            type_filter = "{0} (*.{1})".format(item["description"], item["extension"])
            filters.append(type_filter)
            mime_types.append(item["mime_type"])
            if preferred_mimetype == item["mime_type"]:
                selected_filter = type_filter
                if file_name:
                    file_name += "." + item["extension"]

        dialog.setNameFilters(filters)
        if selected_filter is not None:
            dialog.selectNameFilter(selected_filter)

        if file_name is not None:
            dialog.selectFile(file_name)

        stored_directory = Preferences.getInstance().getValue("local_file/dialog_save_path")
        dialog.setDirectory(stored_directory)

        if not dialog.exec_():
            raise OutputDeviceError.UserCanceledError()

        save_path = dialog.directory().absolutePath()
        Preferences.getInstance().setValue("local_file/dialog_save_path", save_path)

        selected_type = file_types[filters.index(dialog.selectedNameFilter())]
        Preferences.getInstance().setValue("local_file/last_used_type", selected_type["mime_type"])

        # Get file name from file dialog
        file_name = dialog.selectedFiles()[0]
        Logger.log("d", "Writing to [%s]..." % file_name)
        
        if os.path.exists(file_name):
            result = QMessageBox.question(None, catalog.i18nc("@title:window", "File Already Exists"), catalog.i18nc("@label", "The file <filename>{0}</filename> already exists. Are you sure you want to overwrite it?").format(file_name))
            if result == QMessageBox.No:
                raise OutputDeviceError.UserCanceledError()

        self.writeStarted.emit(self)

        # Actually writing file
        if file_handler:
            file_writer = file_handler.getWriter(selected_type["id"])
        else:
            file_writer = Application.getInstance().getMeshFileHandler().getWriter(selected_type["id"])

        try:
            mode = selected_type["mode"]
            if mode == MeshWriter.OutputMode.TextMode:
                Logger.log("d", "Writing to Local File %s in text mode", file_name)
                stream = open(file_name, "wt", encoding = "utf-8")
            elif mode == MeshWriter.OutputMode.BinaryMode:
                Logger.log("d", "Writing to Local File %s in binary mode", file_name)
                stream = open(file_name, "wb")
            else:
                Logger.log("e", "Unrecognised OutputMode.")
                return None

            job = WriteFileJob(file_writer, stream, nodes, mode)
            job.setFileName(file_name)
            job.progress.connect(self._onJobProgress)
            job.finished.connect(self._onWriteJobFinished)

            message = Message(catalog.i18nc("@info:progress", "Saving to <filename>{0}</filename>").format(file_name), 0, False, -1)
            message.show()

            job.setMessage(message)
            self._writing = True
            job.start()
        except PermissionError as e:
            Logger.log("e", "Permission denied when trying to write to %s: %s", file_name, str(e))
            raise OutputDeviceError.PermissionDeniedError(catalog.i18nc("@info:status", "Permission denied when trying to save <filename>{0}</filename>").format(file_name)) from e
        except OSError as e:
            Logger.log("e", "Operating system would not let us write to %s: %s", file_name, str(e))
            raise OutputDeviceError.WriteRequestFailedError(catalog.i18nc("@info:status", "Could not save to <filename>{0}</filename>: <message>{1}</message>").format()) from e
class PhaseNetworkElements(QWidget):
    def __init__(self, camera=None, log=None, fps=10.):
        super().__init__()
        self.feedback = False
        # ---  --- #
        if log != None:
            self.log = log
        else:
            self.log = LogDisplay()
        #self.log.showLog()
        # --- default --- #
        self.fps       = fps
        self.cmap      = 'jet'
        self.sepration = ' '
        self.param_peak= [] # a N x 3 array where each line is [x0, a, b] the parameter of the fit, N being the number of peaks.
        self.dicspan   = {}
        self.postprocss_func = None
        self.procssfunc_default = True
        # --- main attriute --- #
        self.camera    = camera
        if not self.camera.isCameraInit:
            self.camera.__init__(cam_id=0, log=self.log)
        self.qlabl_max = QLabel()
        self.dataframe = np.zeros([10,10])
        # ---  --- #
        self.initUI()

    def initUI(self):
        self.splitter      = QSplitter(PyQt5.QtCore.Qt.Horizontal)
        self.fitting_frame = None
        # ---  --- #
        self.layout      = QVBoxLayout(self)
        # --- guassian fit init --- #
        self.gaussianfit     = GaussianFit(log=self.log)
        self.gaussian_plots  = {}
        self.fittingactivate = QCheckBox()
        self.fittingactivate.setTristate(False)
        self.fittingactivate.stateChanged.connect(self.acceptOrNot)
        # --- init frames --- #
        self.initView()
        self.initParameterZone()
        self.initVertHistogram()
        self.initMultiplotPeak()
        self.initLissajousPlot()
        # --- default --- #
        self.updatePtNbrLabel()
        # --- layout --- #
        vsplitter      = QSplitter(PyQt5.QtCore.Qt.Vertical)
        vsplitter.addWidget( self.camera_view )
        vsplitter.addWidget( self.paramFrame )
        self.splitter.addWidget( vsplitter )
        self.splitter.addWidget( self.histogFrame )
        self.splitter.addWidget( self.multiplotFrame )
        vsplitter      = QSplitter(PyQt5.QtCore.Qt.Vertical)
        vsplitter.addWidget( self.lissajousFrame )
        vsplitter.addWidget( QFrame() )
        self.splitter.addWidget( vsplitter )
        self.layout.addWidget( self.splitter )
        self.setLayout(self.layout)
        # ---  --- #

    def initView(self):
        self.camera_view     = CameraDisplay(camera=self.camera, log=self.log)
        # ---  --- #
        self.camera_view.image_view.setMinimumWidth(100)
        self.camera_view.image_view.setMinimumHeight(200)

    def initParameterZone(self):
        self.paramFrame = QFrame()
        self.paramFrame.setToolTip('Frame where we control the main parameter for the data sampling.')
        self.paramFrame.setFrameStyle(QFrame.StyledPanel | QFrame.Raised)
        self.paramFrame.setLineWidth(3)
        self.paramFrame.setMidLineWidth(1)
        # --- widgets --- #
        self.histogram_data = QComboBox()
        self.histogram_data.addItem('raw')
        self.histogram_data.addItem('remove backgrnd')
        self.histogram_data.addItem('normalise')
        self.histogram_data.setCurrentIndex(0)
        self.histrealtime   = QCheckBox()
        self.histrealtime.setTristate(False)
        self.histrealtime.setCheckState(2)
        self.setLinkToCameraTimer()
        self.button_save   = QPushButton('Save sampling data')
        self.button_save.setToolTip('Save the plots in the milti-plot window in a txt file such that each line corresponds to the y-data. Moreover we save the total intensity.')
        self.savefile      = QFileDialog(self)
        self.savefile_name = QLabel('Select a file')
        self.savefile_name.setWordWrap(True)
        self.choosedirectory  = QPushButton('&Change file')
        self.postprocss    = QComboBox()
        self.postprocss.addItem('Max peak')
        self.postprocss.addItem('Sum area span')
        # --- connections --- #
        self.choosedirectory.clicked.connect(self.setNewSaveFile)
        self.button_save.clicked.connect( self.saveDataFromMultiplot )
        self.histrealtime.stateChanged.connect( self.setLinkToCameraTimer )
        self.histogram_data.currentIndexChanged.connect( self.setHistgrmPlotRange )
        self.postprocss.currentIndexChanged.connect( self.setPostProcessFunction )
        # --- make layout --- #
        label_1 = QLabel('Histogram data: ')
        label_1.setWordWrap(True)
        label_1.setToolTip('Set what transformation we operate from the image data to the histogram data.\n"raw" means we integrate over the Y-axis and divide by the number of line.\n"normalise" like "raw" but we normalise to the maximum afterward.')
        label_2 = QLabel('Histogram in continuous mode: ')
        label_2.setWordWrap(True)
        label_2.setToolTip('When unchecked, stop the updating of the histogram. In other words, allow to stop the histogram without stopping the video image.')
        label_3 = QLabel('Sampling post-processing: ')
        label_3.setWordWrap(True)
        label_3.setToolTip('The post-processing refer to the data processing from the vertivcal histogram of the image.')
        grid    = QGridLayout()
        grid.addWidget(label_1               , 1,0)
        grid.addWidget( self.histogram_data  , 1,1)
        grid.addWidget(label_2               , 0,0)
        grid.addWidget( self.histrealtime    , 0,1)
        grid.addWidget(label_3               , 2,0)
        grid.addWidget(self.postprocss       , 2,1)
        grid.addWidget( QHLine()             , 3,0 , 1,2)
        grid.addWidget( self.button_save     , 4,0 , 1,2)
        grid.addWidget( self.choosedirectory , 5,0)
        grid.addWidget(self.savefile_name    , 5,1)
        self.paramFrame.setLayout( grid )

    def initVertHistogram(self):
        self.plot_hist    = pg.PlotWidget()
        self.plot_hist.setMinimumHeight(600)
        self.plot_hist.setMinimumWidth(100)
        plot_viewbox      = self.plot_hist.getViewBox()
        plot_viewbox.invertX(True)
        self.plot_hist.showAxis('right')
        self.plot_hist.hideAxis('left')
        self.plot_hist.showGrid(x=True)
        plot_viewbox.setAspectLocked(False)
        plot_viewbox.enableAutoRange(pg.ViewBox.YAxis, enable=True)
        # --- measured data --- #
        self.data_hist = pg.PlotDataItem()
        self.plot_hist.addItem(self.data_hist)
        # --- widgets --- #
        self.spanNumber     = QSpinBox()#QPushButton('add new span')
        self.spanNumber.setMaximum(20)
        self.spanNumber.setValue(0)
        self.spanNumber.valueChanged.connect( self.makeSpans )
        # --- make layout --- #
        self.histogFrame = QFrame()
        self.histogFrame.setToolTip('Vertical histogram of the image. We integrated over the Y-axis of the image.')
        layout = QGridLayout()
        layout.addWidget(QLabel('Span Number:') , 0,0)
        layout.addWidget( self.spanNumber       , 0,1)
        layout.addWidget(self.plot_hist   , 1,0 , 1,2)
        self.histogFrame.setLayout( layout )

    def initMultiplotPeak(self):
        self.multi_plot   = pg.GraphicsLayoutWidget()
        self.samplingtime = QSpinBox()
        self.samplingtime.setRange(1, 60)
        self.samplingtime.setValue(5)
        self.dicmultiplot = {}
        self.samplingPtNbr  = QLabel()
        # ---  --- #
        self.plot_max = PeakPlot(name='plot_max', span=None, log=self.log)
        #self.dicmultiplot[self.plot_max.name] = [self.plot_max]
        # ---  --- #
        self.spanNumber.valueChanged.connect( self.updateMultiplots )
        self.samplingtime.valueChanged.connect( self.updatePtNbrLabel )
        self.camera_view.fps_input.valueChanged.connect( self.updatePtNbrLabel )
        # --- make layout --- #
        label_1 = QLabel('Sampling time (s): ')
        label_1.setWordWrap(True)
        label_2 = QLabel('(s) --> pts nbr:')
        label_2.setWordWrap(True)
        self.multiplotFrame = QFrame()
        self.multiplotFrame.setToolTip('Multiplot frame. Each plot correspond to the post-processed data sampling of the corresponding span number.')
        layout = QGridLayout()
        layout.addWidget(label_1 , 0,0)
        layout.addWidget(self.samplingtime                 , 0,1)
        layout.addWidget(label_2     , 0,2)
        layout.addWidget(self.samplingPtNbr                , 0,3)
        layout.addWidget(self.multi_plot                   , 1,0 , 1,4)
        self.multiplotFrame.setLayout( layout )

    def initLissajousPlot(self):
        self.lissajousFrame = QFrame()
        self.lissajousFrame.setToolTip('Lissajous plot. We plot the post processed intensities as expressed below the graph.')
        self.lissajousFrame.setFrameStyle(QFrame.StyledPanel | QFrame.Raised)
        self.lissajousFrame.setLineWidth(3)
        self.lissajousFrame.setMidLineWidth(1)
        # ---  --- #
        self.plot_lissjs = pg.PlotWidget()
        self.plot_lissjs.setMinimumHeight(300)
        self.plot_lissjs.setMinimumWidth(300)
        self.plot_lissjs.showGrid(x=True, y=True)
        lissjs_viewbox   = self.plot_lissjs.getViewBox()
        self.data_lissjs = pg.ScatterPlotItem() #pg.PlotDataItem()
        #self.data_lissjs.setSymbol('o')
        self.plot_lissjs.addItem(self.data_lissjs)
        # ---  --- #
        lissjs_viewbox.setRange(xRange=(-1,+1), yRange=(-1,+1))
        self.plot_xaxis  = QComboBox()
        self.plot_yaxis  = QComboBox()
        self.makeLissajousAxisSelection()
        self.button_plot_lissajs = QPushButton('Plot')
        self.button_plot_lissajs.setCheckable(True)
        # --- make layout --- #
        label_equation = QLabel('-    i = (I/I_tot)\n- x,y = [i-(i_Max+i_min)/2]/(i_Max-i_min)/2')
        label_equation.setWordWrap(True)
        layout = QGridLayout()
        layout.addWidget( QLabel('X axis') , 0,1)
        layout.addWidget( QLabel('Y axis') , 0,2)
        layout.addWidget( QLabel('Plot : '), 1,0)
        layout.addWidget( self.plot_xaxis  , 1,1)
        layout.addWidget( self.plot_yaxis  , 1,2)
        layout.addWidget( self.button_plot_lissajs, 2,0 , 1,3)
        layout.addWidget( self.plot_lissjs , 3,0 , 1,3)
        layout.addWidget( QHLine()         , 4,0 , 1,3)
        layout.addWidget( label_equation   , 5,0 , 1,3)
        self.lissajousFrame.setLayout( layout )

    def setNewSaveFile(self):
        # --- stop timers to avoid over load --- #
        wasOn = self.camera_view.isOn
        self.camera_view.stop_continuous_view()
        # ---  --- #
        filename = self.savefile.getSaveFileName(None)
        if filename == '':
            # --- restart processes --- #
            if wasOn:
                self.camera_view.start_continuous_view()
            return False
        dir_path = self.savefile.directory().absolutePath()
        os.chdir(dir_path)
        self.savefile_name.setText( filename[0] )
        # --- restart processes --- #
        if wasOn:
            self.camera_view.start_continuous_view()
        # ---  --- #
        return True

    def saveDataFromMultiplot(self):
        # --- stop timers to avoid over load --- #  # we stop the process because it does not work while timer is running
        wasOn = self.camera_view.isOn
        self.camera_view.stop_continuous_view()
        # --- check if there are spans --- #
        if self.spanNumber.value() == 0:
            # --- restart processes --- #
            if wasOn:
                self.camera_view.start_continuous_view()
            return None
        # --- set file name --- #
        hasWorked = self.setNewSaveFile()
        if not hasWorked:
            # --- restart processes --- #
            if wasOn:
                self.camera_view.start_continuous_view()
            return None
        # ---  open file save --- #
        filename = self.savefile_name.text()
        try:
            f = open(filename, 'w+')
        except:
            err_msg  = 'Error: in saveDataFromMultiplot, not able to open file.'
            err_msg += '\nFilename is: {}'.format(filename)
            self.log.addText( err_msg )
        # --- make save --- #
        min_len   = np.inf
        data_list = []
        for key in self.dicmultiplot: # adding data from each plot in multiplot view
            data_list.append( self.dicmultiplot[key][0].plot.yData )
            min_len = np.min( [min_len, len(data_list[-1])] )
        # --- adding the data fot the total intensity --- #
        data_list.append( self.plot_max.plot.yData )
        min_len = np.min( [min_len, len(data_list[-1])] )
        # ---  --- #
        min_len = int(min_len)
        if len(data_list) == 0:
            return None
        # --- equalise the length of the data, from the end since it is the most recent one --- # 
        for i in range(len(data_list)):
            data_list[i] = data_list[i][-min_len:]
        data_list = np.array(data_list)
        # ---  --- #
        np.savetxt(filename, data_list)
        # --- restart processes --- #
        if wasOn:
            self.camera_view.start_continuous_view()

    def makeLissajousAxisSelection(self):
        nx = self.plot_xaxis.count()
        ny = self.plot_yaxis.count()
        if nx != ny:
            self.log.addText('Error in makeLissajousAxisSelection, the two axis combobox do not have the same item number.')
            return None
        for i in reversed(range(nx)):
            self.plot_xaxis.removeItem(i)
            self.plot_yaxis.removeItem(i)
        for i in range(self.spanNumber.value()):
            self.plot_xaxis.addItem(str(i+1))
            self.plot_yaxis.addItem(str(i+1))

    def toggleLissajousPlot(self):
        if   self.button_plot_lissajs.isChecked():
            self.doLissajous = True
        else:
            self.doLissajous = False

    def addSpan(self):
        N = len( list(self.dicspan.keys()) )
        newspan = SpanObject(name='span_{}'.format(N+1), pos_init=N*50 +1, log=self.log)
        self.dicspan[N+1] = newspan
        # ---  --- #
        self.plot_hist.addItem( newspan.span )
        # --- add label --- #
        #newspan.label.setParentItem(self.plot_hist.getViewBox())
        self.plot_hist.addItem( newspan.label )
        # ---  --- #
        self.addPlot(newspan)

    def removeSpan(self):
        N = len( list(self.dicspan.keys()) )
        if N == 0:
            return None
        # ---  --- #
        self.removePlot( self.dicspan[N] )
        # ---  --- #
        self.plot_hist.removeItem( self.dicspan[N].span )
        self.plot_hist.removeItem( self.dicspan[N].label )
        self.dicspan[N].setParent(None)
        del self.dicspan[N]

    def makeSpans(self):
        n = self.spanNumber.value()
        n_current = len(list(self.dicspan.keys()))
        if   n == n_current:
            pass
        elif n > n_current:
            for i in range(n-n_current):
                self.addSpan()
        elif n < n_current:
            for i in range(n_current-n):
                self.removeSpan()
        self.makeLissajousAxisSelection()
        self.setSameYAxisMultiplots()

    def addPlot(self, span):
        N = len( list(self.dicspan.keys()) )
        newplot = PeakPlot(name='plot_{}'.format(span.name), span=span, log=self.log)
        self.dicmultiplot[newplot.name] = [newplot]
        # ---  --- #
        span.span.sigRegionChangeFinished.connect( self.updateMultiplots )
        # ---  --- #
        self.multi_plot.nextRow()
        self.multi_plot.addItem( newplot )
        # ---  --- #
        label_item = self.multi_plot.addLabel(newplot.name[10:], angle = -90)
        self.dicmultiplot[newplot.name].append( label_item )

    def removePlot(self, span):
        '''
        In dictionary of plots, we retreive the plot list [plot_item, label_item], associated
        to the span region.
        '''
        N = len( list(self.dicspan.keys()) )
        plot_to_remove = self.dicmultiplot['plot_{}'.format(span.name)]
        # ---  remove plot --- #
        self.multi_plot.removeItem( plot_to_remove[0] )
        plot_to_remove[0].setParent(None)
        # --- remove label --- #
        self.multi_plot.removeItem( plot_to_remove[1] )
        # ---  --- #
        del self.dicmultiplot['plot_{}'.format(span.name)]
        span.setAssigned(False)

    def setSameYAxisMultiplots(self):
        key_init = list(self.dicmultiplot.keys())[0]
        common_viewBox = self.dicmultiplot[key_init][0].getViewBox()
        common_viewBox.enableAutoRange(pg.ViewBox.YAxis, enable=True)
        for key in self.dicmultiplot:
            plot = self.dicmultiplot[key][0]
            plot.setYLink(common_viewBox)

    def setLinkToCameraTimer(self):
        if   self.histrealtime.checkState() == 0:
            self.camera_view.timer.timeout.disconnect(self.updatePlotHistogram)
        elif self.histrealtime.checkState() == 2:
            self.camera_view.timer.timeout.connect(self.updatePlotHistogram)

    def addDataToFile(self):
        # --- stop timers to avoid over load --- #
        wasOn = self.isOn
        self.stop_continuous_view()
        self.fittingtimer.stop()
        # ---  --- #
        f = open(self.savefile_name.text(), 'a')
        coretxt  = ''
        coretxt += '\n'
        if   self.peakcount == 0:
            pass
        elif self.peakcount == 1:
            coretxt += self.sepration+str(self.param_peak[0][1])
        else:
            for i in range(self.peakcount):
                coretxt += self.sepration+str(self.param_peak[i,1])
        f.write(coretxt)
        f.close()
        # --- restart processes --- #
        if self.fittingactivate.checkState() != 0:
            self.fittingtimer.start()
        if wasOn:
            self.start_continuous_view()

    def acceptOrNot(self, i):
        if type(self.data_hist.xData)==type(None):
            self.fittingactivate.setCheckState(0)
        return None

    def changeMode(self):
        ind = self.modeselect.currentIndex()
        if   ind == 0:
            self.gaussianfit.setMode('all')
        elif ind == 1:
            self.gaussianfit.setMode('pbp')

    def setPostProcessFunction(self):
        ind = self.postprocss.currentIndex()
        if   ind == 0:
            func = eval("lambda x_data: np.max(x_data)")
            self.postprocss_func = func
        elif ind == 1:
            func = eval("lambda x_data: np.sum(x_data)")
            self.postprocss_func = func
        return None

    def setFittingRate(self):
        self.fittingtimer.setInterval(1e3/self.frqcyfitting.value())

    def setHistgrmPlotRange(self):
        ind = self.histogram_data.currentIndex()
        if   ind == 0 or ind == 1:
            self.plot_hist.getViewBox().enableAutoRange(pg.ViewBox.XAxis, enable=True)
        elif ind == 2:
            self.plot_hist.setXRange(0, 1.)

    def postProcessLissajous(self, xy_data):
        Max_ = np.max(xy_data)
        min_ = np.min(xy_data)
        A    = (Max_ + min_)*0.5
        B    = (Max_ - min_)*0.5
        return (xy_data-A)/B

    def updatePlotHistogram(self):
        frame = self.camera_view.frame
        if type(frame) == type(None):
            return None
        # --- mode data --- #
        ind = self.histogram_data.currentIndex()
        if   ind == 0: # raw
            ydata = np.sum(frame,axis=0)/frame.shape[0]
        elif ind == 1: # remove background
            frame = frame-np.mean(frame)
            ydata = np.sum(frame,axis=0)/frame.shape[0]
            ydata = ydata + np.abs(np.min([0, np.min(ydata)]))
        elif ind == 2: # normalise
            ydata = np.sum(frame,axis=0)/frame.shape[0]
            ydata = ydata/np.max(ydata)
        # --- plot data --- #
        self.data_hist.setData( ydata, np.arange(len(ydata)) )
        # ---  --- #
        self.updateMultiplots()

    def updateMultiplots(self):
        if type(self.postprocss_func) == type(None):
            self.setPostProcessFunction()
        # ---  --- #
        sum_max_peak = 0
        data = self.data_hist.xData
        for key in self.dicmultiplot:
            plot = self.dicmultiplot[key][0]
            plot.setLengthMax( int(self.samplingtime.value()*self.camera_view.fps) )
            # ---  --- #
            region = plot.span.span.getRegion()
            m , M  = int(np.min(region)), int(np.max(region))
            err_msg  = ''
            cond_1 = type(data) != type(None) and m != M
            cond_2 = len(data) >= m or len(data) >= M
            cond_3 = len(data[m:M]) != 0
            if cond_1 and cond_2 and cond_3:
                try:
                    new_val = self.postprocss_func(data[m:M])# np.max(data[m:M])
                    plot.addDataElement( new_val )
                except:
                    err_msg += 'Error: in updatePlot for object PeakPlot: '+plot.name
                    err_msg += '\nIssue with: self.addDataElement( np.max(self.data[m:M]) ),'
                    err_msg += '\nsample: {}'.format(self.data[m:M])
            else:
                err_msg += '\nOne of the following condition is unsatisfied:\n \
                type(data) != type(None) and m != M: {0}\n \
                len(data) >= m or len(data) >= M: {1}\n \
                len(data[m:M]) != 0: {2}'.format(cond_1,cond_2,cond_3)
                self.log.addText( err_msg )
            # ---  --- #
            sum_max_peak += plot.peakdata[-1]
        self.plot_max.setLengthMax( int(self.samplingtime.value()*self.camera_view.fps) )
        self.plot_max.addDataElement(sum_max_peak)
        # ---  --- #
        if self.button_plot_lissajs.isChecked():# if self.doLissajous:
            self.updateLissajousPlot()

    def updateLissajousPlot(self):
        xaxis_ind = self.plot_xaxis.currentText()
        yaxis_ind = self.plot_yaxis.currentText()
        try:
            xplot     = self.dicmultiplot['plot_span_{}'.format(xaxis_ind)][0]
            yplot     = self.dicmultiplot['plot_span_{}'.format(yaxis_ind)][0]
        except:
            if self.feedback:
                err_msg  = 'Error: in updateLissajousPlot. Wrong key for dicmultiplot.'
                self.log.addText( err_msg )
            return None
        xdata     = xplot.plot.yData
        ydata     = yplot.plot.yData
        max_data  = self.plot_max.plot.yData
        if type(xdata) != type(None) and type(ydata) != type(None):
            n = np.min( [len(xdata), len(ydata), len(max_data)] )
            xdata = xdata[-n:]/max_data[-n:]
            ydata = ydata[-n:]/max_data[-n:]
            xdata = self.postProcessLissajous(xdata)
            ydata = self.postProcessLissajous(ydata)
            self.data_lissjs.setData( xdata, ydata )

    def updatePtNbrLabel(self):
        self.samplingPtNbr.setText( str(self.samplingtime.value()*self.camera_view.fps) )
class DCMeasurement(QWidget):
    def __init__(self, camera=None, log=None, fps=10.):
        super().__init__()
        # ---  --- #
        if log != None:
            self.log = log
        else:
            self.log = LogDisplay()
        #self.log.showLog()
        # --- default --- #
        self.fps = fps
        self.cmap = 'jet'
        self.normalise = True
        self.sepration = ' '
        self.param_peak = [
        ]  # a N x 3 array where each line is [x0, a, b] the parameter of the fit, N being the number of peaks.
        self.measured_max = []
        self.power_peak = []
        self.fittingtimer = pg.QtCore.QTimer()
        # --- main attriute --- #
        self.camera = camera
        if not self.camera.isCameraInit:
            self.camera.__init__(cam_id=0, log=self.log)
        self.contview = ContinuousView(fps=self.fps)
        self.qlabl_max = QLabel()
        # ---  --- #
        self.initUI()

    def initUI(self):
        self.splitter = QSplitter(PyQt5.QtCore.Qt.Horizontal)
        self.fitting_frame = None
        # ---  --- #
        self.layout = QVBoxLayout(self)
        # --- guassian fit init --- #
        self.dic_spanfitting = {}
        self.gaussianfit = GaussianFit(log=self.log)
        self.gaussian_plots = {}
        self.fittingactivate = QCheckBox()
        self.fittingactivate.setTristate(False)
        self.fittingactivate.stateChanged.connect(self.acceptOrNot)
        self.fittingactivate.stateChanged.connect(
            self.fittingActivationDeactivation)
        # --- init frames --- #
        self.initView()
        self.initDisplayFittingFrame()
        self.initParameterFittingFrame()
        self.relativeHeightsLayout()
        # --- layout --- #
        self.splitter.addWidget(self.viewFrame)
        vsplitter = QSplitter(PyQt5.QtCore.Qt.Vertical)
        vsplitter.addWidget(self.fittingFrame)
        vsplitter.addWidget(self.paramfittingframe)
        vsplitter.addWidget(self.matrelatFrame)
        self.splitter.addWidget(vsplitter)
        self.layout.addWidget(self.splitter)
        self.setLayout(self.layout)
        # ---  --- #
        self.fittingtimer.start()
        self.setXdataPoints()
        self.setFittingMethod()

    def initView(self):
        self.camera_view = CameraDisplay(camera=self.camera, log=self.log)
        # ---  --- #
        self.camera_view.image_view.setMinimumWidth(600)
        self.camera_view.image_view.setMinimumHeight(200)
        # ---  --- #
        self.viewFrame = QFrame()
        self.viewFrame.setFrameStyle(QFrame.StyledPanel | QFrame.Raised)
        self.viewFrame.setLineWidth(3)
        self.viewFrame.setMidLineWidth(1)
        layout = QVBoxLayout()
        layout.addWidget(self.camera_view)
        self.viewFrame.setLayout(layout)

    def initDisplayFittingFrame(self):
        self.plot_hist = pg.PlotWidget()
        self.plot_hist.setMinimumWidth(800)
        plot_viewbox = self.plot_hist.getViewBox()
        plot_viewbox.setAspectLocked(False)
        plot_viewbox.enableAutoRange(pg.ViewBox.XAxis, enable=True)
        # --- measured data --- #
        self.data_hist = pg.PlotDataItem()
        self.plot_hist.addItem(self.data_hist)
        # --- threshold line object --- #
        self.threshold = pg.InfiniteLine(pos=1., angle=0, movable=True)
        self.plot_hist.addItem(self.threshold)
        # --- widgets --- #
        self.normalise_hist = QComboBox()
        self.normalise_hist.addItem('raw')
        self.normalise_hist.addItem('normalise')
        self.normalise_hist.setCurrentIndex(0)
        self.nbrpeak = QSpinBox()
        self.nbrpeak.setRange(1, 20)
        self.nbrpeak.setValue(2)
        self.histrealtime = QCheckBox()
        self.histrealtime.setTristate(False)
        self.histrealtime.setCheckState(2)
        self.setLinkToCameraTimer()
        # --- connections --- #
        self.threshold.sigPositionChangeFinished.connect(self.updatePlots)
        self.normalise_hist.currentIndexChanged.connect(self.setModeFitting)
        self.nbrpeak.valueChanged.connect(self.updatePlots)
        self.histrealtime.stateChanged.connect(self.setLinkToCameraTimer)
        # --- default --- #
        self.setModeFitting()
        plot_viewbox.enableAutoRange(pg.ViewBox.YAxis, enable=True)
        if self.normalise:
            self.plot_hist.setYRange(0, 1)
        # --- make layout --- #
        self.fittingFrame = QFrame()
        vlayout = QVBoxLayout()
        hlayout = QHBoxLayout()
        hlayout.addWidget(QLabel('mode fitting:'))
        hlayout.addWidget(self.normalise_hist)
        hlayout.addWidget(QLabel('Number maximum of peaks:'))
        hlayout.addWidget(self.nbrpeak)
        hlayout.addWidget(QLabel('Continuous mode:'))
        hlayout.addWidget(self.histrealtime)
        vlayout.addLayout(hlayout)
        vlayout.addWidget(self.plot_hist)
        self.fittingFrame.setLayout(vlayout)

    def initParameterFittingFrame(self):
        # --- widgets --- #
        self.peakcount_lab = QLabel('#')
        self.modeselect = QComboBox()
        self.modeselect.addItem('all')
        self.modeselect.addItem('peak by peak')
        self.choosedirectory = QPushButton('&New file')
        self.savefile_name = QLabel('Select a file')
        self.savefile_name.setWordWrap(True)
        self.savefile = QFileDialog()
        self.button_addData = QPushButton('Add data')
        self.button_addData.setStyleSheet("background-color: green")
        self.button_makefit = QPushButton('Make fit')
        self.frqcyfitting = QSpinBox()
        self.frqcyfitting.setRange(1, 12)
        self.frqcyfitting.setValue(10)
        self.fitting_xdataNbre = QSpinBox()
        self.fitting_xdataNbre.setRange(100, 5e3)
        self.fitting_xdataNbre.setValue(10**3)
        self.fitting_param_dspl = QTableWidget()
        self.fitting_param_dspl.setRowCount(5)
        self.saving_state = QLabel('###')
        self.saving_state.setWordWrap(True)
        self.save_count = QSpinBox()
        self.save_count.setRange(0, 1e4)
        self.save_count.setValue(0)
        self.button_test = QPushButton('TEST')
        # ---  --- #
        self.fittingtimer.setInterval(self.frqcyfitting.value())
        # --- connections --- #
        self.modeselect.currentIndexChanged.connect(self.setFittingMethod)
        self.choosedirectory.clicked.connect(self.setNewSaveFile)
        self.button_addData.clicked.connect(self.addDataToFile)
        self.frqcyfitting.valueChanged.connect(self.setFittingRate)
        self.fittingtimer.timeout.connect(self.updatePlots)
        self.fitting_xdataNbre.valueChanged.connect(self.setXdataPoints)
        self.button_makefit.clicked.connect(self.singleShotFittingPlot)
        self.nbrpeak.valueChanged.connect(self.initPeakByPeakFitting)
        # --- make layout --- #
        self.paramfittingframe = QFrame()
        self.param_grid = QGridLayout()
        self.param_grid.addWidget(QLabel('Activate fitting '), 0, 0)
        self.param_grid.addWidget(self.fittingactivate, 0, 1)
        self.param_grid.addWidget(QLabel('Fitting rate:'), 0, 2)
        self.param_grid.addWidget(self.frqcyfitting, 0, 3)
        self.param_grid.addWidget(QLabel('Fitting Sampling number'), 0, 4)
        self.param_grid.addWidget(self.fitting_xdataNbre, 0, 5)
        self.param_grid.addWidget(QLabel('Peak nbr:'), 1, 0)
        self.param_grid.addWidget(self.peakcount_lab, 1, 1)
        self.param_grid.addWidget(QLabel('Fitting method:'), 1, 2)
        self.param_grid.addWidget(self.modeselect, 1, 3)
        self.param_grid.addWidget(self.button_makefit, 1, 4, 1, 2)
        self.param_grid.addWidget(self.fitting_param_dspl, 2, 0, 4, 6)
        self.param_grid.setRowMinimumHeight(2, 35)
        self.param_grid.setRowMinimumHeight(3, 35)
        self.param_grid.setRowMinimumHeight(4, 35)
        self.param_grid.setRowMinimumHeight(5, 35)
        self.updateParamLayout()
        self.param_grid.addWidget(self.choosedirectory, 6, 0)
        self.param_grid.addWidget(self.savefile_name, 6, 1, 1, 6)
        self.param_grid.addWidget(self.button_addData, 7, 0, 1, 4)
        self.param_grid.addWidget(self.saving_state, 7, 4)
        self.param_grid.addWidget(self.save_count, 7, 5)
        for i in range(self.param_grid.rowCount() + 1):
            self.param_grid.setRowStretch(i, 1)
        # ---  --- #
        self.paramfittingframe.setLayout(self.param_grid)

    def initPeakByPeakFitting(self):
        if self.modeselect.currentIndex() != 1:
            return None
        # --- reset spans --- #
        self.removeAllSpans()
        # ---  --- #
        for i in range(self.nbrpeak.value()):
            newspan = SpanObject(name='span_{}'.format(i),
                                 orientation='vertical',
                                 log=self.log,
                                 pos_init=i * 50 + 1)
            newspan.span.sigRegionChangeFinished.connect(self.updatePowerPeak)
            self.dic_spanfitting[newspan.name] = newspan
            self.plot_hist.addItem(newspan.span)
            self.plot_hist.addItem(newspan.label)
        self.gaussianfit.setSpanDictionary(self.dic_spanfitting)
        # ---  --- #
        self.power_peak = np.zeros(self.nbrpeak.value())

    def initPowerEstimation(self):
        if self.modeselect.currentIndex() != 2:
            return None
        # --- reset spans --- #
        self.removeAllSpans()
        # ---  --- #
        for i in range(self.nbrpeak.value()):
            newspan = SpanObject(name='span_{}'.format(i),
                                 orientation='vertical',
                                 log=self.log,
                                 pos_init=i * 50 + 1)
            newspan.span.sigRegionChangeFinished.connect(self.updatePowerPeak)
            self.dic_spanfitting[newspan.name] = newspan
            self.plot_hist.addItem(newspan.span)
        # ---  --- #
        self.power_peak = np.zeros(self.nbrpeak.value())

    def removeAllSpans(self):
        KEYS = list(self.dic_spanfitting.keys())
        for key in KEYS:
            self.plot_hist.removeItem(self.dic_spanfitting[key].span)
            self.dic_spanfitting[key].setParent(None)
            del self.dic_spanfitting[key]

    def removeAllLabels(self):
        KEYS = list(self.dic_spanfitting.keys())
        for key in KEYS:
            self.plot_hist.removeItem(self.dic_spanfitting[key].label)

    def addDataToFile(self):
        # --- stop timers to avoid over load --- #
        wasOn = self.camera_view.isOn
        self.camera_view.stop_continuous_view()
        self.fittingtimer.stop()
        # ---  --- #
        self.saving_state.setText('Saving ...')
        self.button_addData.setStyleSheet("background-color: red")
        time.sleep(.5)
        self.img_count = self.save_count.value()
        # ---  --- #
        if len(self.param_peak) == 0:
            # --- restart processes --- #
            if self.fittingactivate.checkState() != 0:
                self.fittingtimer.start()
            if wasOn:
                self.camera_view.start_continuous_view()
            # ---  --- #
            self.saving_state.setText('Save unsuccessful: param of length 0.')
            return None
        elif len(self.power_peak) == 0:
            self.power_peak = np.zeros(self.nbrpeak.value())
        # ---  --- #
        N = self.param_peak.shape[0]
        try:
            open(self.savefile_name.text(), 'r')
        except:
            f = open(self.savefile_name.text(), 'a')
            header = ''
            for i in range(N):
                header += 'Peak_measured_{}'.format(i) + self.sepration
                header += 'Peak_power_{}'.format(i) + self.sepration
                header += 'Peak_fitted_{}'.format(i) + self.sepration
            f.write(header)
            f.close()
            self.log.addText('Creating new file')
        # ---  --- #
        f = open(self.savefile_name.text(), 'a')
        coretxt = ''
        coretxt += '\n'
        for i in range(N):
            coretxt += str(self.measured_max[i]) + self.sepration
            coretxt += str(self.power_peak[i]) + self.sepration
            coretxt += str(self.param_peak[i, 1]) + self.sepration
        f.write(coretxt)
        f.close()
        # --- save coresponding frame as tif --- #
        img_to_save = Image.fromarray(self.camera_view.frame)
        if self.savefile_name.text()[:-4] == '.':
            img_to_save.save(self.savefile_name.text()[:-4] +
                             '_{0:03d}.tif'.format(self.img_count))
        else:
            img_to_save.save(self.savefile_name.text() +
                             '_{0:03d}.tif'.format(self.img_count))
        self.img_count += 1
        # ---  --- #
        self.saving_state.setText('Saved No:')
        self.save_count.setValue(self.img_count)
        self.button_addData.setStyleSheet("background-color: green")
        time.sleep(0.5)
        # --- restart processes --- #
        if self.fittingactivate.checkState() != 0:
            self.fittingtimer.start()
        if wasOn:
            self.camera_view.start_continuous_view()

    def acceptOrNot(self, i):
        if type(self.data_hist.xData) == type(None):
            self.fittingactivate.setCheckState(0)
        # ---  --- #
        self.setXdataPoints()

    def clearGaussianFits(self):
        KEYS = list(self.gaussian_plots.keys())
        for i in reversed(range(len(KEYS))):
            key = KEYS[i]
            #self.plot_hist.removeItem(self.gaussian_plots[key])
            self.gaussian_plots[key].clear()
            del self.gaussian_plots[key]
            #self.log.addText('Deleting plot: {}'.format(key))
        self.gaussian_plots = {}

    def clearLayout(self, layout):
        for i in reversed(range(layout.count())):
            item = layout.itemAt(i)
            layout.removeItem(item)

    def fittingActivationDeactivation(self, i):
        if self.fittingactivate.checkState() == 0:
            self.fittingtimer.stop()
        elif self.fittingactivate.checkState() == 2:
            self.fittingtimer.start()

    def getParamFit(self):
        # --- fitting --- #
        self.gaussianfit.setXData(self.data_hist.xData)
        self.gaussianfit.setYData(self.data_hist.yData)
        self.gaussianfit.setPeakNumber(self.peakcount)
        self.gaussianfit.setCenters(self.param_peak[:, 0])
        self.gaussianfit.setAmplitudes(self.param_peak[:, 1])
        self.gaussianfit.setSTD(self.param_peak[:, 2])
        # ---  --- #
        self.gaussianfit.makeGaussianFit()
        # ---  --- #
        self.param_peak = self.gaussianfit.param
        if self.modeselect.currentIndex() == 1:
            self.measured_max = self.gaussianfit.maximums

    def quickPeakCount(self):
        xdata = self.data_hist.xData
        ydata = self.data_hist.yData
        if type(xdata) == type(None) or type(ydata) == type(None):
            self.peakcount = 0
            return None
        # --- threshold value --- #
        threshold = self.threshold.value()
        self.gaussianfit.setThreshold(self.threshold.value())
        truth_list = (np.abs(ydata - threshold) +
                      (ydata - threshold)).astype(bool)
        # ---  --- #
        block_list = [[i for i, value in it] for key, it in itertools.groupby(
            enumerate(truth_list), key=operator.itemgetter(1)) if key != 0]
        self.peakcount = len(block_list)
        self.param_peak = np.ones([self.peakcount, 3])
        self.measured_max = np.ones(self.peakcount)
        for i in range(self.peakcount):
            x0 = (block_list[i][-1] + block_list[i][0]) / 2.
            a = np.max(ydata[block_list[i]])
            b = (block_list[i][-1] - block_list[i][0]) / 2.
            if b != 0: b = b**-1
            self.param_peak[i] = [x0, a, b]
            self.measured_max[i] = a
        # ---  --- #
        self.peakcount_lab.setText(str(self.peakcount))
        self.updateParamLayout()

    def plotGaussianFit(self):
        # ---  remove old gaussian plots --- #
        self.clearGaussianFits()
        # ---  --- #
        for key in self.gaussianfit.dic_gauss:
            x = self.xdataFit  #self.data_hist.xData
            y_fit = self.gaussianfit.gaussian(x,
                                              *self.gaussianfit.dic_gauss[key])
            self.gaussian_plots[key] = pg.PlotCurveItem(x=x, y=y_fit, pen='r')
        # ---  --- #
        for key in self.gaussian_plots:
            self.plot_hist.addItem(self.gaussian_plots[key])

    def relativeHeightsLayout(self):
        self.matrelatFrame = QFrame()
        self.matrelat_layout = QGridLayout()
        self.matrelat_layout.setColumnMinimumWidth(0, 200)
        n = 0
        self.matrelat = np.zeros([n, n])
        numbering = np.arange(n)
        # --- with qtable --- #
        self.table = QTableWidget()
        self.matrelat_layout.addWidget(self.table)
        # ---  --- #
        self.matrelatFrame.setLayout(self.matrelat_layout)

    def removeAllSpans(self):
        KEYS = list(self.dic_spanfitting.keys())
        for key in KEYS:
            span_to_remove = self.dic_spanfitting[key]
            self.plot_hist.removeItem(span_to_remove.span)
            del self.dic_spanfitting[key]

    def setNewSaveFile(self):
        # --- stop timers to avoid over load --- #
        wasOn = self.camera_view.isOn
        self.camera_view.stop_continuous_view()
        self.fittingtimer.stop()
        # ---  --- #
        filename = self.savefile.getSaveFileName()
        dir_path = self.savefile.directory().absolutePath()
        os.chdir(dir_path)
        self.savefile_name.setText(filename[0])
        # --- set image count --- #
        self.img_count = 0
        # --- restart processes --- #
        if self.fittingactivate.checkState() != 0:
            self.fittingtimer.start()
        if wasOn:
            self.camera_view.start_continuous_view()

    def setXdataPoints(self):
        if type(self.data_hist.xData) != type(None):
            self.xdataFit = np.linspace(np.min(self.data_hist.xData),
                                        np.max(self.data_hist.xData),
                                        self.fitting_xdataNbre.value())
        else:
            self.xdataFit = np.linspace(0, 100, self.fitting_xdataNbre.value())

    def setFittingMethod(self):
        ind = self.modeselect.currentIndex()
        if ind == 0:
            self.gaussianfit.setMode('all')
            self.button_makefit.setEnabled(False)
            self.button_makefit.setFlat(True)
            self.fittingactivate.setCheckState(2)
            self.removeAllLabels()
            self.removeAllSpans()
            self.power_peak = []
        elif ind == 1:
            self.gaussianfit.setMode('pbp')
            self.button_makefit.setEnabled(True)
            self.button_makefit.setFlat(False)
            self.fittingactivate.setCheckState(0)
            self.initPeakByPeakFitting()
            self.initPowerEstimation()

    def setFPS(self):
        self.fps = self.fps_input.value()
        self.contview.setFPS(self.fps)
        self.timer.setInterval(1e3 / self.fps)

    def setFittingRate(self):
        self.fittingtimer.setInterval(1e3 / self.frqcyfitting.value())

    def setModeFitting(self):
        ind = self.normalise_hist.currentIndex()
        if ind == 0:
            self.normalise = False
            self.gaussianfit.setMaxAmp(255)
            #self.plot_hist.setYRange(0, 255)
            self.plot_hist.getViewBox().enableAutoRange(pg.ViewBox.YAxis,
                                                        enable=True)
            #self.threshold.setValue(255)
        elif ind == 1:
            self.normalise = True
            self.gaussianfit.setMaxAmp(1.)
            self.plot_hist.setYRange(0, 1.)
            self.threshold.setValue(1.)
        # ---  --- #
        self.updatePlots()

    def setLinkToCameraTimer(self):
        if self.histrealtime.checkState() == 0:
            self.camera_view.frame_updated.disconnect(self.updatePlotHistogram)
        elif self.histrealtime.checkState() == 2:
            self.camera_view.frame_updated.connect(self.updatePlotHistogram)

    def singleShotFittingPlot(self):
        self.quickPeakCount()
        self.getParamFit()
        self.plotGaussianFit()
        self.updatePowerPeak()
        self.updateParamLayout()
        self.updateRelativeHeightMatrix()

    def updatePowerPeak(self):
        if len(self.power_peak) != len(list(self.dic_spanfitting.keys())):
            self.log.addText(
                'Error: in updatePowerPeak, length of power_peak list and number of span do not coincide.'
            )
            return None
        # ---  --- #
        for i in range(len(self.power_peak)):
            region = self.dic_spanfitting['span_{}'.format(i)].span.getRegion()
            m, M = int(np.min(region)), int(np.max(region))
            self.power_peak[i] = np.sum(self.data_hist.yData[m:M])
        # ---  --- #
        self.updateParamLayout()

    def updateParamLayout(self):
        try:
            n = self.param_peak.shape[0]
        except:
            self.log.addText('self.peakcount most likely not defined yet')
            return None
        self.fitting_param_dspl.clear()
        self.fitting_param_dspl.setItem(0, 0,
                                        QTableWidgetItem('Peak position'))
        self.fitting_param_dspl.setItem(1, 0,
                                        QTableWidgetItem('Peak amplitudes'))
        self.fitting_param_dspl.setItem(2, 0, QTableWidgetItem('STD'))
        self.fitting_param_dspl.setItem(3, 0, QTableWidgetItem('Measured max'))
        self.fitting_param_dspl.setItem(4, 0, QTableWidgetItem('Peak power'))
        self.fitting_param_dspl.setColumnCount(n + 1)
        # ---  --- #
        if not n >= 1:
            return None
        for i in range(n):
            try:
                self.fitting_param_dspl.setItem(
                    0, i + 1,
                    QTableWidgetItem('{:.3f}'.format(self.param_peak[i, 0])))
                self.fitting_param_dspl.setItem(
                    1, i + 1,
                    QTableWidgetItem('{:.3f}'.format(self.param_peak[i, 1])))
                self.fitting_param_dspl.setItem(
                    2, i + 1,
                    QTableWidgetItem('{:.3f}'.format(self.param_peak[i, 2])))
                self.fitting_param_dspl.setItem(
                    3, i + 1,
                    QTableWidgetItem('{:.3f}'.format(self.measured_max[i])))
                if len(self.power_peak) != 0:
                    self.fitting_param_dspl.setItem(
                        4, i + 1,
                        QTableWidgetItem('{:.3f}'.format(self.power_peak[i])))
            except:
                pass

    def updateRelativeHeightMatrix(self):
        n = self.param_peak.shape[0]
        self.table.clear()
        self.table.setRowCount(n)
        self.table.setColumnCount(n)
        self.matrelat = np.zeros([n, n])
        # ---  --- #
        if not n >= 1:
            return None
        for i in range(n):
            for j in range(n):
                try:
                    self.table.setItem(
                        i, j,
                        QTableWidgetItem(
                            str(
                                round(
                                    self.param_peak[i, 1] /
                                    self.param_peak[j, 1], 3))))
                except:
                    pass
        #self.matrelat_layout.setRowMinimumHeight(0, 35*n)

    def updatePlots(self):
        self.quickPeakCount()
        if self.peakcount > self.nbrpeak.value():
            return None
        if self.fittingactivate.checkState() == 2:
            self.getParamFit()
            self.plotGaussianFit()
            self.updateParamLayout()
            self.updateRelativeHeightMatrix()

    def updatePlotHistogram(self):
        frame = self.camera_view.frame
        if type(frame) == type(None):
            return None
        # ---  --- #
        # ---  --- #
        ydata = np.sum(frame, axis=0) / frame.shape[0]
        if self.normalise:
            try:
                ydata = ydata / np.max(ydata)
            except:
                err_msg = 'Error: in updatePlotHistogram. ydata/np.max(ydata) does not work.'
                err_msg += '\nydata max: {}'.format(np.max(ydata))
                self.log.addText(err_msg)
        # --- plot data --- #
        self.data_hist.setData(ydata)
    def requestWrite(self,
                     nodes,
                     file_name=None,
                     limit_mimetypes=None,
                     file_handler=None):
        if self._writing:
            raise OutputDeviceError.DeviceBusyError()

        dialog = QFileDialog()

        dialog.setWindowTitle(catalog.i18nc("@title:window", "Save to File"))
        dialog.setFileMode(QFileDialog.AnyFile)
        dialog.setAcceptMode(QFileDialog.AcceptSave)

        # Ensure platform never ask for overwrite confirmation since we do this ourselves
        dialog.setOption(QFileDialog.DontConfirmOverwrite)

        if sys.platform == "linux" and "KDE_FULL_SESSION" in os.environ:
            dialog.setOption(QFileDialog.DontUseNativeDialog)

        filters = []
        mime_types = []
        selected_filter = None
        last_used_type = Preferences.getInstance().getValue(
            "local_file/last_used_type")

        if not file_handler:
            file_handler = Application.getInstance().getMeshFileHandler()

        file_types = file_handler.getSupportedFileTypesWrite()

        file_types.sort(key=lambda k: k["description"])
        if limit_mimetypes:
            file_types = list(
                filter(lambda i: i["mime_type"] in limit_mimetypes,
                       file_types))

        if len(file_types) == 0:
            Logger.log("e", "There are no file types available to write with!")
            raise OutputDeviceError.WriteRequestFailedError()

        for item in file_types:
            type_filter = "{0} (*.{1})".format(item["description"],
                                               item["extension"])
            filters.append(type_filter)
            mime_types.append(item["mime_type"])
            if last_used_type == item["mime_type"]:
                selected_filter = type_filter
                if file_name:
                    file_name += "." + item["extension"]

        dialog.setNameFilters(filters)
        if selected_filter is not None:
            dialog.selectNameFilter(selected_filter)

        if file_name is not None:
            dialog.selectFile(file_name)

        stored_directory = Preferences.getInstance().getValue(
            "local_file/dialog_save_path")
        dialog.setDirectory(stored_directory)

        if not dialog.exec_():
            raise OutputDeviceError.UserCanceledError()

        save_path = dialog.directory().absolutePath()
        Preferences.getInstance().setValue("local_file/dialog_save_path",
                                           save_path)

        selected_type = file_types[filters.index(dialog.selectedNameFilter())]
        Preferences.getInstance().setValue("local_file/last_used_type",
                                           selected_type["mime_type"])

        file_name = dialog.selectedFiles()[0]

        if os.path.exists(file_name):
            result = QMessageBox.question(
                None, catalog.i18nc("@title:window", "File Already Exists"),
                catalog.i18nc(
                    "@label",
                    "The file <filename>{0}</filename> already exists. Are you sure you want to overwrite it?"
                ).format(file_name))
            if result == QMessageBox.No:
                raise OutputDeviceError.UserCanceledError()

        self.writeStarted.emit(self)

        if file_handler:
            file_writer = file_handler.getWriter(selected_type["id"])
        else:
            file_writer = Application.getInstance().getMeshFileHandler(
            ).getWriter(selected_type["id"])

        try:
            mode = selected_type["mode"]
            if mode == MeshWriter.OutputMode.TextMode:
                Logger.log("d", "Writing to Local File %s in text mode",
                           file_name)
                stream = open(file_name, "wt", encoding="utf-8")
            elif mode == MeshWriter.OutputMode.BinaryMode:
                Logger.log("d", "Writing to Local File %s in binary mode",
                           file_name)
                stream = open(file_name, "wb")

            job = WriteFileJob(file_writer, stream, nodes, mode)
            job.setFileName(file_name)
            job.progress.connect(self._onJobProgress)
            job.finished.connect(self._onWriteJobFinished)

            message = Message(
                catalog.i18nc(
                    "@info:progress",
                    "Saving to <filename>{0}</filename>").format(file_name), 0,
                False, -1)
            message.show()

            job._message = message
            self._writing = True
            job.start()
        except PermissionError as e:
            Logger.log("e", "Permission denied when trying to write to %s: %s",
                       file_name, str(e))
            raise OutputDeviceError.PermissionDeniedError(
                catalog.i18nc(
                    "@info:status",
                    "Permission denied when trying to save <filename>{0}</filename>"
                ).format(file_name)) from e
        except OSError as e:
            Logger.log("e",
                       "Operating system would not let us write to %s: %s",
                       file_name, str(e))
            raise OutputDeviceError.WriteRequestFailedError(
                catalog.i18nc(
                    "@info:status",
                    "Could not save to <filename>{0}</filename>: <message>{1}</message>"
                ).format()) from e
Exemple #22
0
    def requestWrite(self,
                     nodes,
                     file_name=None,
                     limit_mimetypes=None,
                     file_handler=None,
                     **kwargs):
        application = cast(CuraApplication, Application.getInstance())
        machine_manager = application.getMachineManager()
        global_stack = machine_manager.activeMachine

        filename_format = Application.getInstance().getPreferences().getValue(
            "gcode_filename_format/filename_format")

        Logger.log("d", "filename_format = %s", filename_format)

        if filename_format is "":
            filename_format = DEFAULT_FILENAME_FORMAT

        if self._writing:
            raise OutputDeviceError.DeviceBusyError()

        self.getModifiedPrintSettings(application, global_stack)

        dialog = QFileDialog()

        dialog.setWindowTitle(catalog.i18nc("@title:window", "Save to File"))
        dialog.setFileMode(QFileDialog.AnyFile)
        dialog.setAcceptMode(QFileDialog.AcceptSave)

        dialog.setOption(QFileDialog.DontConfirmOverwrite)

        if sys.platform == "linux" and "KDE_FULL_SESSION" in os.environ:
            dialog.setOption(QFileDialog.DontUseNativeDialog)

        filters = []
        mime_types = []
        selected_filter = None

        if "preferred_mimetypes" in kwargs and kwargs[
                "preferred_mimetypes"] is not None:
            preferred_mimetypes = kwargs["preferred_mimetypes"]
        else:
            preferred_mimetypes = Application.getInstance().getPreferences(
            ).getValue("gcode_filename_format/last_used_type")
        preferred_mimetype_list = preferred_mimetypes.split(";")

        if not file_handler:
            file_handler = Application.getInstance().getMeshFileHandler()

        file_types = file_handler.getSupportedFileTypesWrite()

        file_types.sort(key=lambda k: k["description"])
        if limit_mimetypes:
            file_types = list(
                filter(lambda i: i["mime_type"] in limit_mimetypes,
                       file_types))

        file_types = [ft for ft in file_types if not ft["hide_in_file_dialog"]]

        if len(file_types) == 0:
            Logger.log("e", "There are no file types available to write with!")
            raise OutputDeviceError.WriteRequestFailedError(
                catalog.i18nc(
                    "@info:warning",
                    "There are no file types available to write with!"))

        preferred_mimetype = None
        for mime_type in preferred_mimetype_list:
            if any(ft["mime_type"] == mime_type for ft in file_types):
                preferred_mimetype = mime_type
                break

        for item in file_types:
            type_filter = "{0} (*.{1})".format(item["description"],
                                               item["extension"])
            filters.append(type_filter)
            mime_types.append(item["mime_type"])
            if preferred_mimetype == item["mime_type"]:
                selected_filter = type_filter
                file_name = self.parseFilenameFormat(filename_format,
                                                     file_name, application,
                                                     global_stack)
                #file_name += self.filenameTackOn(print_setting)
                if file_name:
                    file_name += "." + item["extension"]

        stored_directory = Application.getInstance().getPreferences().getValue(
            "gcode_filename_format/dialog_save_path")
        dialog.setDirectory(stored_directory)

        if file_name is not None:
            dialog.selectFile(file_name)

        dialog.setNameFilters(filters)
        if selected_filter is not None:
            dialog.selectNameFilter(selected_filter)

        if not dialog.exec_():
            raise OutputDeviceError.UserCanceledError()

        save_path = dialog.directory().absolutePath()
        Application.getInstance().getPreferences().setValue(
            "gcode_filename_format/dialog_save_path", save_path)

        selected_type = file_types[filters.index(dialog.selectedNameFilter())]
        Application.getInstance().getPreferences().setValue(
            "gcode_filename_format/last_used_type", selected_type["mime_type"])

        file_name = dialog.selectedFiles()[0]
        Logger.log("d", "Writing to [%s]..." % file_name)

        if os.path.exists(file_name):
            result = QMessageBox.question(
                None, catalog.i18nc("@title:window", "File Already Exists"),
                catalog.i18nc(
                    "@label Don't translate the XML tag <filename>!",
                    "The file <filename>{0}</filename> already exists. Are you sure you want to overwrite it?"
                ).format(file_name))
            if result == QMessageBox.No:
                raise OutputDeviceError.UserCanceledError()

        self.writeStarted.emit(self)

        if file_handler:
            file_writer = file_handler.getWriter(selected_type["id"])
        else:
            file_writer = Application.getInstance().getMeshFileHandler(
            ).getWriter(selected_type["id"])

        try:
            mode = selected_type["mode"]
            if mode == MeshWriter.OutputMode.TextMode:
                Logger.log("d", "Writing to Local File %s in text mode",
                           file_name)
                stream = open(file_name, "wt", encoding="utf-8")
            elif mode == MeshWriter.OutputMode.BinaryMode:
                Logger.log("d", "Writing to Local File %s in binary mode",
                           file_name)
                stream = open(file_name, "wb")
            else:
                Logger.log("e", "Unrecognised OutputMode.")
                return None

            job = WriteFileJob(file_writer, stream, nodes, mode)
            job.setFileName(file_name)
            job.setAddToRecentFiles(True)
            job.progress.connect(self._onJobProgress)
            job.finished.connect(self._onWriteJobFinished)

            message = Message(
                catalog.i18nc(
                    "@info:progress Don't translate the XML tags <filename>!",
                    "Saving to <filename>{0}</filename>").format(file_name), 0,
                False, -1, catalog.i18nc("@info:title", "Saving"))
            message.show()

            job.setMessage(message)
            self._writing = True
            job.start()
        except PermissionError as e:
            Logger.log("e", "Permission denied when trying to write to %s: %s",
                       file_name, str(e))
            raise OutputDeviceError.PermissionDeniedError(
                catalog.i18nc(
                    "@info:status Don't translate the XML tags <filename>!",
                    "Permission denied when trying to save <filename>{0}</filename>"
                ).format(file_name)) from e
        except OSError as e:
            Logger.log("e",
                       "Operating system would not let us write to %s: %s",
                       file_name, str(e))
            raise OutputDeviceError.WriteRequestFailedError(
                catalog.i18nc(
                    "@info:status Don't translate the XML tags <filename> or <message>!",
                    "Could not save to <filename>{0}</filename>: <message>{1}</message>"
                ).format()) from e
    def requestWrite(self,
                     nodes,
                     file_name=None,
                     limit_mimetypes=None,
                     file_handler=None,
                     **kwargs):
        if self._writing:
            raise OutputDeviceError.DeviceBusyError()

        # Set up and display file dialog
        dialog = QFileDialog()

        dialog.setWindowTitle(self._translations.get("save_file_window"))
        dialog.setFileMode(QFileDialog.AnyFile)
        dialog.setAcceptMode(QFileDialog.AcceptSave)

        # Ensure platform never ask for overwrite confirmation since we do this ourselves
        dialog.setOption(QFileDialog.DontConfirmOverwrite)

        if sys.platform == "linux" and "KDE_FULL_SESSION" in os.environ:
            dialog.setOption(QFileDialog.DontUseNativeDialog)

        filters = []
        mime_types = []
        selected_filter = None

        if "preferred_mimetypes" in kwargs and kwargs[
                "preferred_mimetypes"] is not None:
            preferred_mimetypes = kwargs["preferred_mimetypes"]
        else:
            preferred_mimetypes = Application.getInstance().getPreferences(
            ).getValue("local_file/last_used_type")
        preferred_mimetype_list = preferred_mimetypes.split(";")

        if not file_handler:
            file_handler = Application.getInstance().getMeshFileHandler()

        file_types = file_handler.getSupportedFileTypesWrite()

        file_types.sort(key=lambda k: k["description"])
        if limit_mimetypes:
            file_types = list(
                filter(lambda i: i["mime_type"] in limit_mimetypes,
                       file_types))

        file_types = [ft for ft in file_types if not ft["hide_in_file_dialog"]]

        if len(file_types) == 0:
            Logger.log("e", "There are no file types available to write with!")
            raise OutputDeviceError.WriteRequestFailedError(
                self._translations.get("no_file_warning"))

        # Find the first available preferred mime type
        preferred_mimetype = None
        for mime_type in preferred_mimetype_list:
            if any(ft["mime_type"] == mime_type for ft in file_types):
                preferred_mimetype = mime_type
                break

        for item in file_types:
            type_filter = "{0} (*.{1})".format(item["description"],
                                               item["extension"])
            filters.append(type_filter)
            mime_types.append(item["mime_type"])
            if preferred_mimetype == item["mime_type"]:
                selected_filter = type_filter
                if file_name:
                    file_name += "." + item["extension"]

        # CURA-6411: This code needs to be before dialog.selectFile and the filters, because otherwise in macOS (for some reason) the setDirectory call doesn't work.
        stored_directory = Application.getInstance().getPreferences().getValue(
            "local_file/dialog_save_path")
        dialog.setDirectory(stored_directory)

        # Add the file name before adding the extension to the dialog
        if file_name is not None:
            dialog.selectFile(file_name)

        dialog.setNameFilters(filters)
        if selected_filter is not None:
            dialog.selectNameFilter(selected_filter)

        if not dialog.exec_():
            raise OutputDeviceError.UserCanceledError()

        save_path = dialog.directory().absolutePath()
        Application.getInstance().getPreferences().setValue(
            "local_file/dialog_save_path", save_path)

        selected_type = file_types[filters.index(dialog.selectedNameFilter())]
        Application.getInstance().getPreferences().setValue(
            "local_file/last_used_type", selected_type["mime_type"])

        # Get file name from file dialog
        file_name = dialog.selectedFiles()[0]
        Logger.log("d", "Writing to [%s]..." % file_name)

        if os.path.exists(file_name):
            result = QMessageBox.question(
                None,
                self._translations.get("file_exists_window").format(
                    file_name[file_name.rfind("/") + 1:]),
                self._translations.get("file_overwrite_label").format(
                    file_name[file_name.rfind("/") + 1:]))
            if result == QMessageBox.No:
                raise OutputDeviceError.UserCanceledError()

        self.writeStarted.emit(self)

        # Actually writing file
        if file_handler:
            file_writer = file_handler.getWriter(selected_type["id"])
        else:
            file_writer = Application.getInstance().getMeshFileHandler(
            ).getWriter(selected_type["id"])

        try:
            mode = selected_type["mode"]
            if mode == MeshWriter.OutputMode.TextMode:
                Logger.log("d", "Writing to Local File %s in text mode",
                           file_name)
                stream = open(file_name, "wt", encoding="utf-8")
            elif mode == MeshWriter.OutputMode.BinaryMode:
                Logger.log("d", "Writing to Local File %s in binary mode",
                           file_name)
                stream = open(file_name, "wb")
            else:
                Logger.log("e", "Unrecognised OutputMode.")
                return None

            # Adding screeshot section
            screenshot_string = utils.add_screenshot()

            if screenshot_string != "":
                stream.write(screenshot_string)
            # End of screeshot section

            job = WriteFileJob(file_writer, stream, nodes, mode)
            job.setFileName(file_name)
            # The file will be added into the "recent files" list upon success
            job.setAddToRecentFiles(True)
            job.progress.connect(self._onJobProgress)
            job.finished.connect(self._onWriteJobFinished)

            message = Message(
                self._translations.get("file_saving_progress").format(
                    file_name), 0, False, -1,
                self._translations.get("file_saving_title"))
            message.show()

            job.setMessage(message)
            self._writing = True
            job.start()
        except PermissionError as e:
            Logger.log("e", "Permission denied when trying to write to %s: %s",
                       file_name, str(e))
            raise OutputDeviceError.PermissionDeniedError(
                self._translations.get("permission_denied").format(
                    file_name)) from e
        except OSError as e:
            Logger.log("e",
                       "Operating system would not let us write to %s: %s",
                       file_name, str(e))
            raise OutputDeviceError.WriteRequestFailedError(
                self._translations.get("permission_denied2").format(
                    file_name, str(e))) from e