Skip to content
New issue

Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.

By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.

Already on GitHub? Sign in to your account

Multiple Live Viewers can be opened simultaneously #2398

Merged
merged 7 commits into from
Nov 21, 2024
Merged
Show file tree
Hide file tree
Changes from all commits
Commits
File filter

Filter by extension

Filter by extension

Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
1 change: 1 addition & 0 deletions docs/release_notes/next/feature-2361-multiple-live-viewers
Original file line number Diff line number Diff line change
@@ -0,0 +1 @@
#2361: Multiple Live Viewers can now be opened and pointed to different directories simultaneously
16 changes: 8 additions & 8 deletions mantidimaging/eyes_tests/live_viewer_window_test.py
Original file line number Diff line number Diff line change
Expand Up @@ -54,7 +54,7 @@ def _make_simple_dir(self, directory: Path):
@mock.patch("time.time", return_value=4000.0)
def test_live_view_opens_without_data(self, _mock_time, _mock_image_watcher):
self.imaging.show_live_viewer(self.live_directory)
self.check_target(widget=self.imaging.live_viewer)
self.check_target(widget=self.imaging.live_viewer_list[-1])

@mock.patch('mantidimaging.gui.windows.live_viewer.presenter.LiveViewerWindowPresenter.load_image')
@mock.patch('mantidimaging.gui.windows.live_viewer.model.ImageWatcher')
Expand All @@ -64,8 +64,8 @@ def test_live_view_opens_with_data(self, _mock_time, _mock_image_watcher, mock_l
image_list = [Image_Data(path) for path in file_list]
mock_load_image.return_value = self._generate_image()
self.imaging.show_live_viewer(self.live_directory)
self.imaging.live_viewer.presenter.model._handle_image_changed_in_list(image_list)
self.check_target(widget=self.imaging.live_viewer)
self.imaging.live_viewer_list[-1].presenter.model._handle_image_changed_in_list(image_list)
self.check_target(widget=self.imaging.live_viewer_list[-1])

@mock.patch('mantidimaging.gui.windows.live_viewer.presenter.LiveViewerWindowPresenter.load_image')
@mock.patch('mantidimaging.gui.windows.live_viewer.model.ImageWatcher')
Expand All @@ -75,8 +75,8 @@ def test_live_view_opens_with_bad_data(self, _mock_time, _mock_image_watcher, mo
image_list = [Image_Data(path) for path in file_list]
mock_load_image.side_effect = ValueError
self.imaging.show_live_viewer(self.live_directory)
self.imaging.live_viewer.presenter.model._handle_image_changed_in_list(image_list)
self.check_target(widget=self.imaging.live_viewer)
self.imaging.live_viewer_list[-1].presenter.model._handle_image_changed_in_list(image_list)
self.check_target(widget=self.imaging.live_viewer_list[-1])

@mock.patch('mantidimaging.gui.windows.live_viewer.presenter.LiveViewerWindowPresenter.load_image')
@mock.patch('mantidimaging.gui.windows.live_viewer.model.ImageWatcher')
Expand All @@ -86,6 +86,6 @@ def test_rotate_operation_rotates_image(self, _mock_time, _mock_image_watcher, m
image_list = [Image_Data(path) for path in file_list]
mock_load_image.return_value = self._generate_image()
self.imaging.show_live_viewer(self.live_directory)
self.imaging.live_viewer.presenter.model._handle_image_changed_in_list(image_list)
self.imaging.live_viewer.rotate_angles_group.actions()[1].trigger()
self.check_target(widget=self.imaging.live_viewer)
self.imaging.live_viewer_list[-1].presenter.model._handle_image_changed_in_list(image_list)
self.imaging.live_viewer_list[-1].rotate_angles_group.actions()[1].trigger()
self.check_target(widget=self.imaging.live_viewer_list[-1])
3 changes: 2 additions & 1 deletion mantidimaging/gui/windows/live_viewer/presenter.py
Original file line number Diff line number Diff line change
Expand Up @@ -46,7 +46,8 @@ def __init__(self, view: LiveViewerWindowView, main_window: MainWindowView):

def close(self) -> None:
"""Close the window."""
self.model.close()
if self.model is not None:
self.model.close()
self.model = None # type: ignore # Presenter instance to be destroyed -type can be inconsistent
self.view = None # type: ignore # Presenter instance to be destroyed -type can be inconsistent

Expand Down
4 changes: 2 additions & 2 deletions mantidimaging/gui/windows/live_viewer/view.py
Original file line number Diff line number Diff line change
Expand Up @@ -28,9 +28,9 @@ class LiveViewerWindowView(BaseMainWindowView):

def __init__(self, main_window: MainWindowView, live_dir_path: Path) -> None:
super().__init__(None, 'gui/ui/live_viewer_window.ui')
self.setWindowTitle("Mantid Imaging - Live Viewer")
self.main_window = main_window
self.path = live_dir_path
self.setWindowTitle(f"Mantid Imaging - Live Viewer - {str(self.path)}")
self.presenter = LiveViewerWindowPresenter(self, main_window)
self.live_viewer = LiveViewWidget()
self.imageLayout.addWidget(self.live_viewer)
Expand Down Expand Up @@ -88,7 +88,7 @@ def set_image_index(self, index: int) -> None:

def closeEvent(self, e) -> None:
"""Close the window and remove it from the main window list"""
self.main_window.live_viewer = None
self.main_window.live_viewer_list.remove(self)
self.presenter.close()
self.live_viewer.handle_deleted()
super().closeEvent(e)
Expand Down
16 changes: 6 additions & 10 deletions mantidimaging/gui/windows/main/view.py
Original file line number Diff line number Diff line change
Expand Up @@ -101,7 +101,7 @@ class MainWindowView(BaseMainWindowView):
filters: FiltersWindowView | None = None
recon: ReconstructWindowView | None = None
spectrum_viewer: SpectrumViewerWindowView | None = None
live_viewer: LiveViewerWindowView | None = None
live_viewer_list: list[LiveViewerWindowView] = []
settings_window: SettingsWindowView | None = None

image_load_dialog: ImageLoadDialog | None = None
Expand Down Expand Up @@ -474,13 +474,9 @@ def live_view_choose_directory(self) -> None:
self.show_live_viewer(Path(live_data_directory))

def show_live_viewer(self, live_data_path: Path) -> None:
if not self.live_viewer:
self.live_viewer = LiveViewerWindowView(self, live_data_path)
self.live_viewer.show()
else:
self.live_viewer.activateWindow()
self.live_viewer.raise_()
self.live_viewer.show()
live_viewer = LiveViewerWindowView(self, live_data_path)
self.live_viewer_list.append(live_viewer)
self.live_viewer_list[-1].show()

@property
def stack_list(self) -> list[StackId]:
Expand Down Expand Up @@ -563,8 +559,8 @@ def closeEvent(self, event) -> None:
# Close additional windows which do not have the MainWindow as parent
if self.recon:
self.recon.close()
if self.live_viewer:
self.live_viewer.close()
while self.live_viewer_list:
self.live_viewer_list[-1].close()
if self.spectrum_viewer:
self.spectrum_viewer.close()
if self.filters:
Expand Down
Loading