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

Initial implementation of the undelete mechanism for fitting tabs - PR #2778 rebased to main #3140

Open
wants to merge 3 commits into
base: main
Choose a base branch
from
Open
Show file tree
Hide file tree
Changes from 1 commit
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
3 changes: 1 addition & 2 deletions src/sas/qtgui/Perspectives/Fitting/ConstraintWidget.py
Original file line number Diff line number Diff line change
Expand Up @@ -285,7 +285,7 @@ def getTabsForFit(self):
"""
Returns list of tab names selected for fitting
"""
return [tab for tab in self.tabs_for_fitting if self.tabs_for_fitting[tab]]
return [tab for tab in self.tabs_for_fitting if ObjectLibrary.getObject(tab) is not None]

def onChainFit(self, is_checked):
"""
Expand Down Expand Up @@ -332,7 +332,6 @@ def onFit(self):
weights = {}
for tab in tabs_to_fit:
tab_object = ObjectLibrary.getObject(tab)
#weight = FittingUtilities.getWeight(tab_object.data, tab_object.is2D, flag=tab_object.weighting)
weight = FittingUtilities.getRelativeError(tab_object.data, tab_object.is2D, flag=tab_object.weighting)
weights[tab] = weight

Expand Down
61 changes: 58 additions & 3 deletions src/sas/qtgui/Perspectives/Fitting/FittingPerspective.py
Original file line number Diff line number Diff line change
@@ -1,5 +1,6 @@
import numpy
import copy
import re

from typing import Optional

Expand Down Expand Up @@ -62,6 +63,10 @@ def __init__(self, parent=None, data=None):
# The tabs need to be movabe
self.setMovable(True)

# Remember the last tab closed
self.lastTabClosed = None
self.installEventFilter(self)

self.communicate = self.parent.communicator()

# Initialize the first tab
Expand Down Expand Up @@ -96,6 +101,14 @@ def __init__(self, parent=None, data=None):
self.plusButton.setToolTip("Add a new Fit Page")
self.plusButton.clicked.connect(lambda: self.addFit(None))

def eventFilter(self, widget, event):
if event.type() == QtCore.QEvent.KeyPress:
key = event.key()
# check for Ctrl-T press
if key == QtCore.Qt.Key_T and event.modifiers() == QtCore.Qt.ControlModifier:
self.addClosedTab()
return True
return QtCore.QObject.eventFilter(self, widget, event)

def updateWindowTitle(self):
"""
Expand Down Expand Up @@ -261,7 +274,7 @@ def addFit(self, data, is_batch=False, tab_index=None):
self.tabs.append(tab)
if data:
self.updateFitDict(data, tab_name)
self.maxIndex = max([tab.tab_id for tab in self.tabs], default=0) + 1
self.maxIndex = self.nextAvailableTabIndex()

icon = QtGui.QIcon()
if is_batch:
Expand All @@ -272,6 +285,38 @@ def addFit(self, data, is_batch=False, tab_index=None):
# Notify listeners
self.tabsModifiedSignal.emit()

def nextAvailableTabIndex(self):
"""
Returns the index of the next available tab
"""
max1 = max([tab.tab_id for tab in self.tabs], default=0)
if self.lastTabClosed is None:
return max1 + 1
max2 = self.lastTabClosed.tab_id
rozyczko marked this conversation as resolved.
Show resolved Hide resolved
return max(max1, max2) + 1

def addClosedTab(self):
"""
Recover the deleted tab.
The tab is held in self.lastTabClosed
"""
if self.lastTabClosed is None:
return
tab = self.lastTabClosed
icon = QtGui.QIcon()
# tab_name = self.getTabName()
tab_name = "FitPage" + str(tab.tab_id)
ObjectLibrary.addObject(tab_name, tab)
self.addTab(tab, icon, tab_name)
# Update the list of tabs
self.tabs.append(tab)
# Show the new tab
self.setCurrentWidget(tab)
# lastTabClosed is no longer valid
self.lastTabClosed = None
# Notify listeners
self.tabsModifiedSignal.emit()

def addConstraintTab(self):
"""
Add a new C&S fitting tab
Expand Down Expand Up @@ -326,7 +371,10 @@ def closeTabByIndex(self, index):
try:
ObjectLibrary.deleteObjectByRef(self.tabs[index])
self.removeTab(index)
del self.tabs[index]
# can't just delete the tab, since we still hold a reference to it
# del self.tabs[index]
# Instead, we just recreate self.tabs without the deleted tab
self.tabs = [tab for tab in self.tabs if tab is not self.tabs[index]]
self.tabsModifiedSignal.emit()
except IndexError:
# The tab might have already been deleted previously
Expand All @@ -349,8 +397,15 @@ def tabCloses(self, index):
"""
Update local bookkeeping on tab close
"""
# update the last-tab closed information
# this should be done only for regular fitting
if not isinstance(self.tabs[index], ConstraintWidget) and \
Copy link
Contributor

Choose a reason for hiding this comment

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

Deleting data, then restoring a tab restores the tab with the deleted data set. This should be handled in dataDeleted below.

Copy link
Member Author

Choose a reason for hiding this comment

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

Not really. Deleting data happens from quite a few locations and shouldn't be polluted with the tab recovery code, which is not really deleting the data...

not self.tabs[index].is_batch_fitting:
self.lastTabClosed = self.tabs[index]

# don't remove the last tab
if len(self.tabs) <= 1:
# remove the tab from the tabbed group
self.resetTab(index)
return
self.closeTabByIndex(index)
Expand Down Expand Up @@ -574,7 +629,7 @@ def getTabByName(self, name):
"""
assert isinstance(name, str)
for tab in self.tabs:
if tab.modelName() == name:
if hasattr(tab, 'modelName') and tab.modelName() == name:
return tab
return None

Expand Down
Loading