# Copyright (C) 2022 ISIS Rutherford Appleton Laboratory UKRI
# SPDX - License - Identifier: GPL-3.0-or-later
import os
import traceback
from enum import auto, Enum
from logging import getLogger
from pathlib import Path
from typing import TYPE_CHECKING, Optional
from mantidimaging.core.io.loader import load_log
from mantidimaging.core.io.loader.loader import read_in_file_information, FileInformation
from mantidimaging.core.io.utility import get_file_extension, get_prefix, find_images, find_log, find_180deg_proj
from mantidimaging.core.utility.data_containers import LoadingParameters, ImageParameters
from mantidimaging.gui.windows.load_dialog.field import Field
if TYPE_CHECKING:
from mantidimaging.gui.windows.load_dialog import MWLoadDialog # pragma: no cover
logger = getLogger(__name__)
[docs]
class Notification(Enum):
UPDATE_ALL_FIELDS = auto()
UPDATE_FLAT_OR_DARK = auto()
UPDATE_SINGLE_FILE = auto()
UPDATE_SAMPLE_LOG = auto()
[docs]
class LoadPresenter:
view: 'MWLoadDialog'
def __init__(self, view: 'MWLoadDialog'):
self.view = view
self.image_format = ''
self.single_mem = 0
self.last_file_info: Optional[FileInformation] = None
self.dtype = '32'
[docs]
def notify(self, n: Notification, **baggage):
try:
if n == Notification.UPDATE_ALL_FIELDS:
self.do_update_sample()
elif n == Notification.UPDATE_FLAT_OR_DARK:
self.do_update_flat_or_dark(**baggage)
elif n == Notification.UPDATE_SINGLE_FILE:
self.do_update_single_file(**baggage)
elif n == Notification.UPDATE_SAMPLE_LOG:
self.do_update_sample_log(**baggage)
except RuntimeError as err:
self.view.show_error(str(err), traceback.format_exc())
[docs]
def do_update_sample(self):
"""
Updates the memory usage and the indices in the dialog.
"""
selected_file = self.view.select_file("Sample")
if not selected_file:
return False
self.view.sample.path = selected_file
self.view.sample.widget.setExpanded(True)
sample_filename = self.view.sample.file()
self.image_format = get_file_extension(sample_filename)
filename = self.view.sample.path_text()
dirname = self.view.sample.directory()
try:
self.last_file_info = read_in_file_information(dirname,
in_prefix=get_prefix(filename),
in_format=self.image_format)
except Exception as e:
getLogger(__name__).error(f"Failed to read file {sample_filename} {e}")
self.view.show_error("Failed to read this file. See log for details.", traceback.format_exc())
self.last_file_info = None
return
sample_dirname = Path(dirname)
self.view.flat_before.set_images(
find_images(sample_dirname,
"Flat",
suffix="Before",
look_without_suffix=True,
image_format=self.image_format,
logger=logger))
self.view.flat_after.set_images(
find_images(sample_dirname, "Flat", suffix="After", image_format=self.image_format, logger=logger))
self.view.dark_before.set_images(
find_images(sample_dirname,
"Dark",
suffix="Before",
look_without_suffix=True,
image_format=self.image_format,
logger=logger))
self.view.dark_after.set_images(
find_images(sample_dirname, "Dark", suffix="After", image_format=self.image_format, logger=logger))
self.view.proj_180deg.path = find_180deg_proj(sample_dirname, self.image_format, logger)
try:
self.set_sample_log(self.view.sample_log, sample_dirname, self.view.sample.directory(),
self.last_file_info.filenames)
except RuntimeError as err:
self.view.show_error(str(err), traceback.format_exc())
self.view.sample_log.use = False
self.view.flat_before_log.path = find_log(sample_dirname, self.view.flat_before.directory(), logger)
self.view.flat_before_log.use = False
self.view.flat_after_log.path = find_log(sample_dirname, self.view.flat_after.directory(), logger)
self.view.flat_after_log.use = False
self.view.images_are_sinograms.setChecked(self.last_file_info.sinograms)
self.view.sample.update_indices(self.last_file_info.shape[0])
self.view.sample.update_shape(self.last_file_info.shape[1:])
self.view.enable_preview_all_buttons()
[docs]
def do_update_flat_or_dark(self, field: Field, name: str, suffix: str):
selected_file = self.view.select_file(name)
if not selected_file:
return
selected_dir = Path(os.path.dirname(selected_file))
field.set_images(find_images(selected_dir, name, suffix, image_format=self.image_format, logger=logger))
[docs]
def get_parameters(self) -> LoadingParameters:
lp = LoadingParameters()
sample_log = self.view.sample_log.path_text() if self.view.sample_log.use.isChecked() else None
lp.sample = ImageParameters(input_path=self.view.sample.directory(),
format=self.image_format,
prefix=get_prefix(self.view.sample.path_text()),
indices=self.view.sample.indices,
log_file=sample_log)
lp.name = self.view.sample.file()
lp.pixel_size = self.view.pixelSize.value()
if self.view.flat_before.use.isChecked() and self.view.flat_before.path_text() != "":
flat_before_log = self.view.flat_before_log.path_text() if self.view.flat_before_log.use.isChecked() \
else None
lp.flat_before = ImageParameters(input_path=self.view.flat_before.directory(),
prefix=get_prefix(self.view.flat_before.path_text()),
format=self.image_format,
log_file=flat_before_log)
if self.view.flat_after.use.isChecked() and self.view.flat_after.path_text() != "":
flat_after_log = self.view.flat_after_log.path_text() if self.view.flat_after_log.use.isChecked() \
else None
lp.flat_after = ImageParameters(input_path=self.view.flat_after.directory(),
prefix=get_prefix(self.view.flat_after.path_text()),
format=self.image_format,
log_file=flat_after_log)
if self.view.dark_before.use.isChecked() and self.view.dark_before.path_text() != "":
lp.dark_before = ImageParameters(input_path=self.view.dark_before.directory(),
prefix=get_prefix(self.view.dark_before.path_text()),
format=self.image_format)
if self.view.dark_after.use.isChecked() and self.view.dark_after.path_text() != "":
lp.dark_after = ImageParameters(input_path=self.view.dark_after.directory(),
prefix=get_prefix(self.view.dark_after.path_text()),
format=self.image_format)
if self.view.proj_180deg.use.isChecked() and self.view.proj_180deg.path_text() != "":
lp.proj_180deg = ImageParameters(input_path=self.view.proj_180deg.directory(),
prefix=os.path.splitext(self.view.proj_180deg.path_text())[0],
format=self.image_format)
lp.dtype = self.view.pixel_bit_depth.currentText()
lp.sinograms = self.view.images_are_sinograms.isChecked()
lp.pixel_size = self.view.pixelSize.value()
return lp
def _update_field_action(self, field: Field, file_name):
if file_name is not None:
field.path = file_name
field.use = True # type: ignore
[docs]
def do_update_single_file(self, field: Field, name: str, is_image_file: bool):
file_name = self.view.select_file(name, is_image_file)
if file_name is None:
return
self._update_field_action(field, file_name)
[docs]
def do_update_sample_log(self, field: Field, name: str, is_image_file: bool):
if self.last_file_info is None:
raise RuntimeError("Please select sample data to be loaded first!")
file_name = self.view.select_file(name, is_image_file)
# this is set when the user selects sample data
self.ensure_sample_log_consistency(field, file_name, self.last_file_info.filenames)
[docs]
def ensure_sample_log_consistency(self, field: Field, file_name, image_filenames):
if file_name is None or file_name == "":
return
log = load_log(file_name)
log.raise_if_angle_missing(image_filenames)
self._update_field_action(field, file_name)
[docs]
def set_sample_log(self, sample_log: Field, sample_dirname, log_name, image_filenames):
sample_log_filepath = find_log(sample_dirname, log_name, logger)
self.ensure_sample_log_consistency(sample_log, sample_log_filepath, image_filenames)
sample_log.path = sample_log_filepath