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

Add functionality for moving viewers between tabs #2387

Merged
merged 7 commits into from
May 15, 2023
Merged
29 changes: 29 additions & 0 deletions glue/app/qt/application.py
Original file line number Diff line number Diff line change
Expand Up @@ -1410,6 +1410,35 @@ def screenshot(self, filename):
image.save(filename)
painter.end()

def move_viewer_to_tab(self, viewer, tab):
"""
Move the given viewer to the given tab.
If the given tab is the same as the current tab,
do nothing.
"""
current_window = viewer.parent()
current_tab = current_window.mdiArea()
new_tab = self.tab(tab)
if new_tab is None:
raise ValueError(f"Invalid tab index: {tab}")
if current_tab is not new_tab:

# We do this rather than just use setParent on current_window
# so that the moved window is put in a reasonable place
# in the new tab (i.e. not on top of another viewer),
# because there may be another viewer in the new tab
# with the same position.
# Also, if we don't resize, moved windows will get progressively
# smaller. This is because the new MDI window will be sized
# according to the size of the old viewer, which is slightly
# smaller than the parent window.
current_tab.removeSubWindow(current_window)
viewer.resize(current_window.size())
current_window.setWidget(None)
current_window.close()

self.add_widget(viewer, tab=tab)

def add_datasets(self, *args, **kwargs):
result = super(GlueApplication, self).add_datasets(*args, **kwargs)
run_autolinker(self.data_collection)
Expand Down
27 changes: 27 additions & 0 deletions glue/app/qt/tests/test_application.py
Original file line number Diff line number Diff line change
Expand Up @@ -235,6 +235,33 @@ def test_subset_facet(self):
with patch('glue.dialogs.subset_facet.qt.SubsetFacetDialog.exec_'):
act._do_action()

def test_move_viewer_to_tab(self):

# Create a viewer in the first tab
viewer = self.app.new_data_viewer(ScatterViewer)
assert viewer.parent().mdiArea() is self.app.tab(0)

# Move it to a new tab
self.app.new_tab()
self.app.move_viewer_to_tab(viewer, 1)
assert viewer.parent().mdiArea() is self.app.tab(1)
assert set(self.app.tab(0).subWindowList()) == {self.app._terminal}
assert set(self.app.tab(1).subWindowList()) == {viewer.parent()}

# Move it back to the first tab
self.app.move_viewer_to_tab(viewer, 0)
assert viewer.parent().mdiArea() is self.app.tab(0)
assert set(self.app.tab(0).subWindowList()) == {self.app._terminal, viewer.parent()}
assert len(self.app.tab(1).subWindowList()) == 0

# Check that we do nothing if the given tab is the same as the
# viewer's current tab
parent = viewer.parent()
viewer_state = viewer.state
self.app.move_viewer_to_tab(viewer, 0)
assert parent is viewer.parent()
Copy link
Member

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Could you test that viewer state is preserved when moving it between tabs?

Copy link
Member Author

@Carifio24 Carifio24 Apr 27, 2023

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

@astrofrog I've added in that check

assert viewer_state is viewer.state

# FIXME: The following test fails and causes subsequent issues if run with
#
# pytest -s -v -x glue
Expand Down
Binary file added glue/icons/windows.png
Loading
Sorry, something went wrong. Reload?
Sorry, we cannot display this file.
Sorry, this file is invalid so it cannot be displayed.
1 change: 1 addition & 0 deletions glue/viewers/common/qt/__init__.py
Original file line number Diff line number Diff line change
@@ -0,0 +1 @@
from . import tools # noqa
7 changes: 5 additions & 2 deletions glue/viewers/common/qt/data_viewer.py
Original file line number Diff line number Diff line change
Expand Up @@ -65,8 +65,11 @@ class DataViewer(Viewer, BaseQtViewerWidget,
_default_mouse_mode_cls = None

inherit_tools = True
tools = ['save']
subtools = {'save': []}
tools = ['save', 'window']
subtools = {
'save': [],
'window': ['window:movetab']
}

_close_on_last_layer_removed = True

Expand Down
33 changes: 33 additions & 0 deletions glue/viewers/common/qt/tools.py
Original file line number Diff line number Diff line change
@@ -0,0 +1,33 @@
from glue.config import viewer_tool
from glue.utils.qt import pick_item
from glue.viewers.common.tool import Tool, SimpleToolMenu

__all__ = ['MoveTabTool', 'WindowTool']


@viewer_tool
class WindowTool(SimpleToolMenu):
"""
A generic "window operations" tool that the Qt app and plugins
can register tools for windowing operations with.
"""

tool_id = 'window'
icon = 'windows'
tool_tip = 'Modify the viewer window'


@viewer_tool
class MoveTabTool(Tool):

icon = 'windows'
tool_id = 'window:movetab'
action_text = 'Move to another tab'
tool_tip = 'Move viewer to another tab'

def activate(self):
app = self.viewer.session.application
default = 1 if (app.tab_count > 1 and app.current_tab == app.tab(0)) else 0
tab = pick_item(range(app.tab_count), app.tab_names, title="Move Viewer", label="Select a tab", default=default)
if tab is not None:
app.move_viewer_to_tab(self.viewer, tab)