Skip to content

Commit e6610ee

Browse files
committed
copy measurement
1 parent 66ad7c4 commit e6610ee

File tree

3 files changed

+67
-3
lines changed

3 files changed

+67
-3
lines changed

omc3_gui/segment_by_segment/main_controller.py

Lines changed: 44 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -81,6 +81,7 @@ def connect_signals(self):
8181
view.button_load_measurement.clicked.connect(self.open_measurements)
8282
view.button_edit_measurement.clicked.connect(self.edit_measurement)
8383
view.button_remove_measurement.clicked.connect(self.remove_measurement)
84+
view.button_copy_measurement.clicked.connect(self.copy_measurement)
8485

8586
view.button_run_matcher.clicked.connect(self.run_matcher)
8687
view.button_edit_corrections.clicked.connect(self.edit_corrections)
@@ -158,6 +159,7 @@ def set_measurement_interaction_buttons_enabled(self, enabled: bool = True):
158159
view.button_edit_measurement,
159160
view.button_run_matcher,
160161
view.button_edit_corrections,
162+
view.button_copy_measurement,
161163
)
162164
for button in measurement_interaction_buttons:
163165
button.setEnabled(enabled)
@@ -261,6 +263,44 @@ def edit_measurement(self, measurement: OpticsMeasurement | None = None):
261263
if dialog.exec_() == dialog.Accepted:
262264
LOGGER.debug("Edit dialog closed. Updating measurement.")
263265

266+
@Slot()
267+
def copy_measurement(self, measurement: OpticsMeasurement | None = None):
268+
""" Create a copy of the given measurement and add it to the GUI.
269+
If no measurement is given, the currently selected measurement is copied.
270+
271+
Args:
272+
measurement (OpticsMeasurement | None, optional): The measurement to copy. Defaults to None.
273+
"""
274+
if measurement is None:
275+
try:
276+
measurement = self.get_single_measurement()
277+
except ValueError as e:
278+
LOGGER.warning(str(e))
279+
return
280+
281+
if measurement.output_dir is None: # should not be possible, but better to catch
282+
LOGGER.error("Cannot copy measurement without output directory.")
283+
return
284+
285+
LOGGER.debug(f"Copying {measurement.display()}.")
286+
new_measurement = measurement.copy()
287+
288+
# might already have a counter from previous copy
289+
name = re.sub(r"_\d+$", "", measurement.output_dir.name)
290+
291+
for count in range(1, 1000): # limit to avoid infinite loop
292+
new_measurement.output_dir = measurement.output_dir.with_name(f"{name}_{count:d}")
293+
try:
294+
self.add_measurement(new_measurement)
295+
except ValueError:
296+
continue
297+
break
298+
else:
299+
LOGGER.error(
300+
"Could not copy measurement. Counter limit exeeded. Not sure what went wrong."
301+
)
302+
return
303+
264304
@Slot()
265305
def remove_measurement(self, measurements: Sequence[OpticsMeasurement] | None = None):
266306
""" Remove measurements from the GUI.
@@ -298,6 +338,10 @@ def measurement_selection_changed(self, measurements: Sequence[OpticsMeasurement
298338
return
299339

300340
self.set_measurement_interaction_buttons_enabled(True)
341+
if len(measurements) > 1:
342+
view.button_edit_measurement.setEnabled(False)
343+
view.button_copy_measurement.setEnabled(False)
344+
301345
self.set_all_segment_buttons_enabled(True)
302346

303347
# Group the segments for the measurements into table-items when they have the same defintion ---

omc3_gui/segment_by_segment/main_view.py

Lines changed: 7 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -72,6 +72,7 @@ def __init__(self, parent=None):
7272
self.button_load_measurement: QtWidgets.QPushButton = None
7373
self.button_remove_measurement: QtWidgets.QPushButton = None
7474
self.button_edit_measurement: QtWidgets.QPushButton = None
75+
self.button_copy_measurement: QtWidgets.QPushButton = None
7576
self.button_edit_corrections: QtWidgets.QPushButton = None
7677
self.button_run_matcher: QtWidgets.QPushButton = None
7778

@@ -237,9 +238,14 @@ def build_measurement_buttons():
237238
grid_buttons_filler.add(remove)
238239
self.button_remove_measurement = remove
239240

241+
copy = DefaultButton("Copy")
242+
copy.setToolTip("Create a virtual copy of the measurement, with a different output dir.")
243+
grid_buttons_filler.add(copy)
244+
self.button_copy_measurement = copy
245+
240246
matcher = RunButton("Run Matcher")
241247
matcher.setToolTip("Run the Segment-by-Segment Matcher.")
242-
grid_buttons_filler.add(matcher, col_span=2)
248+
grid_buttons_filler.add(matcher)
243249
self.button_run_matcher = matcher
244250

245251
edit_corrections = ChangeButton("Corrections")

omc3_gui/segment_by_segment/measurement_model.py

Lines changed: 16 additions & 2 deletions
Original file line numberDiff line numberDiff line change
@@ -8,7 +8,7 @@
88
from __future__ import annotations
99

1010
import logging
11-
from dataclasses import dataclass, field, fields
11+
from dataclasses import dataclass, field, fields, asdict
1212
from pathlib import Path
1313
from typing import TYPE_CHECKING, Any, ClassVar
1414

@@ -175,6 +175,20 @@ def get_sbs_parameters(self) -> dict[str, Any]:
175175
return parameters
176176

177177
# Builder ------------------------------------------------------------------
178+
def copy(self) -> OpticsMeasurement:
179+
""" Creates a copy of the measurement. """
180+
new_measurement = OpticsMeasurement(
181+
**{
182+
f.name: getattr(self, f.name) for f in fields(self)
183+
if not f.name.startswith("_")
184+
},
185+
)
186+
for segment in self.segments:
187+
new_segment = segment.copy()
188+
new_segment.measurement = new_measurement
189+
new_measurement.add_segment(new_segment)
190+
return new_measurement
191+
178192
@classmethod
179193
def from_path(cls, path: Path) -> OpticsMeasurement:
180194
""" Creates an OpticsMeasurement from a folder, by trying
@@ -300,4 +314,4 @@ def map_lhc_year(year: str | None) -> str:
300314
return "2018"
301315

302316
return year
303-
317+

0 commit comments

Comments
 (0)