Skip to content
Merged
Show file tree
Hide file tree
Changes from 7 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
Original file line number Diff line number Diff line change
Expand Up @@ -44,6 +44,10 @@ def get_group_workspace(self, group_name, run):
self._groups_and_pairs[group_name].update_counts_workspace(MuonRun(run), workspace)
return workspace

@property
def get_context(self):
return self._context

@property
def groups(self):
return self._groups_and_pairs.groups
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -5,36 +5,27 @@
# Institut Laue - Langevin & CSNS, Institute of High Energy Physics, CAS
# SPDX - License - Identifier: GPL - 3.0 +
import re

from contextlib import contextmanager
from mantidqtinterfaces.Muon.GUI.Common.muon_pair import MuonPair
from mantidqtinterfaces.Muon.GUI.Common.utilities.run_string_utils import valid_name_regex, valid_alpha_regex
from mantidqtinterfaces.Muon.GUI.Common.utilities.general_utils import round_value
from mantidqt.utils.observer_pattern import GenericObservable
from mantidqtinterfaces.Muon.GUI.Common.grouping_tab_widget.grouping_tab_widget_model import RowValid
from mantidqtinterfaces.Muon.GUI.Common.grouping_table_widget.grouping_table_widget_presenter import row_colors, row_tooltips


pair_columns = ["pair_name", "to_analyse", "group_1", "group_2", "alpha"]
from mantidqtinterfaces.Muon.GUI.Common.pairing_table_widget.pairing_table_widget_view import get_pair_columns, pair_columns


class PairingTablePresenter(object):
def __init__(self, view, model):
self._view = view
self._model = model

self._view.on_add_pair_button_clicked(self.handle_add_pair_button_checked_state)
self._view.on_remove_pair_button_clicked(self.handle_remove_pair_button_clicked)

self._view.on_user_changes_pair_name(self.validate_pair_name)
self._view.on_user_changes_alpha(self.validate_alpha)
self._view.on_guess_alpha_clicked(self.handle_guess_alpha_clicked)
self._view.on_table_data_changed(self.handle_data_change)
self._view.subscribe(self)
self._view.subscribe_notifiers_to_presenter()

self.selected_pair_changed_notifier = GenericObservable()

self._dataChangedNotifier = lambda: 0
self._on_alpha_clicked = lambda: 0
self._on_guess_alpha_requested = lambda pair_name, group1, group2: 0

# notify if Guess Alpha clicked for any table entries
self.guessAlphaNotifier = GenericObservable()
Expand All @@ -49,41 +40,95 @@ def notify_data_changed(self):
self._dataChangedNotifier()

def disable_editing(self):
self._view.disable_editing()
"""Disables editing mode."""
with self.disable_updates_context():
self._view.set_is_disabled(True)
self._view.disable_all_buttons()
self._disable_all_table_items()

def enable_editing(self):
self._view.enable_editing()
"""Enables editing mode."""
with self.disable_updates_context():
self._view.set_is_disabled(False)
self._view.enable_all_buttons()
self._enable_all_table_items()

@contextmanager
def disable_updates_context(self):
"""Context manager to disable updates."""
self.disable_updates()
try:
yield
finally:
self.enable_updates()

def disable_updates(self):
"""Prevent update signals being sent."""
self._view.set_is_updating(True)

def enable_updates(self):
"""Allow update signals to be sent."""
self._view.set_is_updating(False)

def num_rows(self):
return self._view.get_pairing_table.rowCount()

def num_cols(self):
return self._view.get_pairing_table.columnCount()

def remove_pair_by_index(self, index):
self._view.get_pairing_table.removeRow(index)

def remove_last_row(self):
last_row = self._view.get_pairing_table.rowCount() - 1
if last_row >= 0:
self._view.get_pairing_table.removeRow(last_row)

def clear(self):
# Go backwards to preserve indices
for row in reversed(range(self.num_rows())):
self._view.get_pairing_table.removeRow(row)

def get_selected_row_indices(self):
return list(set(index.row() for index in self._view.get_pairing_table.selectedIndexes()))

def get_selected_pair_names_and_indexes(self):
indexes = self.get_selected_row_indices()
return [[str(self._view.get_pairing_table.item(i, 0).text()), i] for i in indexes]

def handle_guess_alpha_clicked(self, row):
table_row = self._view.get_table_contents()[row]
table_row = self.get_table_contents()[row]
pair_name = table_row[0]
group1 = table_row[2]
group2 = table_row[3]
self.guessAlphaNotifier.notify_subscribers([pair_name, group1, group2])

def handle_data_change(self, row, col):
table = self._view.get_table_contents()
table = self.get_table_contents()
changed_item = self._view.get_table_item(row, col)
changed_item_text = self._view.get_table_item_text(row, col)
pair_name = self._view.get_table_item_text(row, 0)
changed_item_text = self.get_table_item_text(row, col)
pair_name = self.get_table_item_text(row, 0)
update_model = True
if pair_columns[col] == "pair_name" and not self.validate_pair_name(changed_item_text):
update_model = False
if pair_columns[col] == "group_1":
if changed_item_text == self._view.get_table_item_text(row, pair_columns.index("group_2")):
table[row][pair_columns.index("group_2")] = self._model.pairs[row].forward_group
if pair_columns[col] == "group_2":
if changed_item_text == self._view.get_table_item_text(row, pair_columns.index("group_1")):
table[row][pair_columns.index("group_1")] = self._model.pairs[row].backward_group
if pair_columns[col] == "alpha":
if not self.validate_alpha(changed_item_text):
match get_pair_columns()[col]:
case "pair_name" if not self.validate_pair_name(changed_item_text):
update_model = False
else:
rounded_item = round_value(changed_item_text, self._model._context.group_pair_context.alpha_precision)
table[row][col] = rounded_item
if pair_columns[col] == "to_analyse":
update_model = False
self.to_analyse_data_checkbox_changed(changed_item.checkState(), row, pair_name)
case "group_1":
if changed_item_text == self.get_table_item_text(row, get_pair_columns().index("group_2")):
table[row][get_pair_columns().index("group_2")] = self._model.pairs[row].forward_group
case "group_2":
if changed_item_text == self.get_table_item_text(row, get_pair_columns().index("group_1")):
table[row][get_pair_columns().index("group_1")] = self._model.pairs[row].backward_group
case "alpha":
if not self.validate_alpha(changed_item_text):
update_model = False
else:
rounded_item = round_value(changed_item_text, self._model.get_context.group_pair_context.alpha_precision)
table[row][col] = rounded_item
case "to_analyse":
update_model = False
self.to_analyse_data_checkbox_changed(changed_item.checkState(), row, pair_name)
case _:
pass

if update_model:
self.update_model_from_view(table)
Expand All @@ -94,7 +139,7 @@ def handle_data_change(self, row, col):

def update_model_from_view(self, table=None):
if not table:
table = self._view.get_table_contents()
table = self.get_table_contents()
self._model.clear_pairs()
for entry in table:
periods = self._model.get_periods(str(entry[2])) + self._model.get_periods(str(entry[3]))
Expand All @@ -108,14 +153,14 @@ def update_model_from_view(self, table=None):
self._model.add_pair(pair)

def update_view_from_model(self):
self._view.disable_updates()
self.disable_updates()

self._view.clear()
self.clear()
for pair in self._model.pairs:
if isinstance(pair, MuonPair):
to_analyse = True if pair.name in self._model.selected_pairs else False
forward_group_periods = self._model._context.group_pair_context[pair.forward_group].periods
backward_group_periods = self._model._context.group_pair_context[pair.backward_group].periods
forward_group_periods = self._model.get_context.group_pair_context[pair.forward_group].periods
backward_group_periods = self._model.get_context.group_pair_context[pair.backward_group].periods
forward_period_warning = self._model.validate_periods_list(forward_group_periods)
backward_period_warning = self._model.validate_periods_list(backward_group_periods)
if forward_period_warning == RowValid.invalid_for_all_runs or backward_period_warning == RowValid.invalid_for_all_runs:
Expand All @@ -128,7 +173,7 @@ def update_view_from_model(self):
tool_tip = row_tooltips[display_period_warning]
self.add_pair_to_view(pair, to_analyse, color, tool_tip)

self._view.enable_updates()
self.enable_updates()

def update_group_selections(self):
groups = self._model.group_names + [diff.name for diff in self._model.get_diffs("group")]
Expand All @@ -144,7 +189,7 @@ def to_analyse_data_checkbox_changed(self, state, row, pair_name):
self.selected_pair_changed_notifier.notify_subscribers(pair_info)

def plot_default_case(self):
for row in range(self._view.num_rows()):
for row in range(self.num_rows()):
self._view.set_to_analyse_state_quietly(row, True)
pair_name = self._view.get_table_item(row, 0).text()
self._model.add_pair_to_analysis(pair_name)
Expand All @@ -155,7 +200,7 @@ def plot_default_case(self):

def add_pair(self, pair):
"""Add a pair to the model and view"""
if self._view.num_rows() > 19:
if self.num_rows() > 19:
self._view.warning_popup("Cannot add more than 20 pairs.")
return
self.add_pair_to_model(pair)
Expand All @@ -167,12 +212,12 @@ def add_pair_to_model(self, pair):
def add_pair_to_view(
self, pair, to_analyse=False, color=row_colors[RowValid.valid_for_all_runs], tool_tip=row_tooltips[RowValid.valid_for_all_runs]
):
self._view.disable_updates()
self.disable_updates()
self.update_group_selections()
assert isinstance(pair, MuonPair)
entry = [str(pair.name), to_analyse, str(pair.forward_group), str(pair.backward_group), str(pair.alpha)]
self._view.add_entry_to_table(entry, color, tool_tip)
self._view.enable_updates()
self.add_entry_to_table(entry, color, tool_tip)
self.enable_updates()

"""
This is required to strip out the boolean value the clicked method
Expand Down Expand Up @@ -202,7 +247,7 @@ def handle_add_pair_button_clicked(self, group_1="", group_2=""):
self.notify_data_changed()

def handle_remove_pair_button_clicked(self):
pair_names = self._view.get_selected_pair_names_and_indexes()
pair_names = self.get_selected_pair_names_and_indexes()
if not pair_names:
self.remove_last_row_in_view_and_model()
else:
Expand All @@ -220,28 +265,115 @@ def remove_selected_rows_in_view_and_model(self, pair_names):
safe_to_rm.append([index, name])
for index, name in reversed(safe_to_rm):
self._model.remove_pair_from_analysis(name)
self._view.remove_pair_by_index(index)
self.remove_pair_by_index(index)
self._model.remove_pairs_by_name([name for index, name in safe_to_rm])
if warnings:
self._view.warning_popup(warnings)

def remove_last_row_in_view_and_model(self):
if self._view.num_rows() > 0:
name = self._view.get_table_contents()[-1][0]
if self.num_rows() > 0:
name = self.get_table_contents()[-1][0]
warning = self._model.check_if_used_by_diff(name)
if warning:
self._view.warning_popup(warning)
else:
self._view.remove_last_row()
self.remove_last_row()
self._model.remove_pair_from_analysis(name)
self._model.remove_pairs_by_name([name])

def get_table_item_text(self, row, col):
column_name = pair_columns[col]

match column_name:
case "group_1" | "group_2":
return self._view.get_widget_current_text(row, col)
case "guess_alpha":
return "Guess"
case _:
return self._view.get_item_text(row, col)

def get_table_contents(self):
if self._view.is_updating:
return []

ret = [[None for _ in range(self.num_cols())] for _ in range(self.num_rows())]
for row in range(self.num_rows()):
for col in range(self.num_cols()):
column_name = pair_columns[col]

match column_name:
case "group_1" | "group_2":
ret[row][col] = self._view.get_widget_current_text(row, col)
case "guess_alpha":
ret[row][col] = "Guess"
case _:
ret[row][col] = self._view.get_item_text(row, col)

return ret

# ------------------------------------------------------------------------------------------------------------------
# Enabling / Disabling the table
# ------------------------------------------------------------------------------------------------------------------
def _set_table_items_enabled(self, enable=True):
for row in range(self.num_rows()):
for col in range(self.num_cols()):
column_name = pair_columns[col]

if column_name in ["group_1", "group_2", "guess_alpha"]:
self._view.set_widget_enabled(row, col, enable)
elif enable:
# Actions for enabling items only
match column_name:
case "pair_name":
self._view.set_item_selectable_and_enabled(row, col)
case "alpha":
self._view.set_item_editable_and_enabled(row, col)
case "to_analyse":
self._view.set_item_checkable_and_enabled(row, col)
else:
# Actions only for disabling items
match column_name:
case _:
self._view.set_item_selectable(row, col)

def _disable_all_table_items(self):
self._set_table_items_enabled(enable=False)

def _enable_all_table_items(self):
self._set_table_items_enabled(enable=True)

def add_entry_to_table(self, row_entries, color=(255, 255, 255), tooltip=""):
"""Add an entry to the table based on row entries."""
assert len(row_entries) == self._view.get_pairing_table.columnCount() - 1

row_position = self._view.insert_row_in_table()
for i, entry in enumerate(row_entries):
item = self._view.create_table_item(entry, color, tooltip)
column_name = pair_columns[i]

match column_name:
case "pair_name":
self._view.add_pair_name_entry(row_position, i, entry)
case "group_1":
self._view.add_group_selector_entry(row_position, i, entry, group="group_1")
case "group_2":
self._view.add_group_selector_entry(row_position, i, entry, group="group_2")
case "alpha":
self._view.add_alpha_entry(row_position, i, entry)
case "to_analyse":
self._view.add_to_analyse_checkbox(item, entry)

self._view.set_item_in_table(row_position, i, item)

# "Guess Alpha" button in the last column
self._view.add_guess_alpha_button(row_position)

# ------------------------------------------------------------------------------------------------------------------
# Table entry validation
# ------------------------------------------------------------------------------------------------------------------

def _is_edited_name_duplicated(self, new_name):
is_name_column_being_edited = self._view.pairing_table.currentColumn() == 0
is_name_column_being_edited = self._view.get_pairing_table.currentColumn() == 0
is_name_unique = sum([new_name == name for name in self._model.group_and_pair_names]) == 0
return is_name_column_being_edited and not is_name_unique

Expand Down
Loading
Loading