Skip to content

Commit

Permalink
clean unique key list
Browse files Browse the repository at this point in the history
  • Loading branch information
tlambert03 committed Oct 13, 2024
1 parent 2b50b45 commit 95a0fbd
Show file tree
Hide file tree
Showing 2 changed files with 335 additions and 1 deletion.
2 changes: 1 addition & 1 deletion src/pymmcore_widgets/config_presets/_oc_dialog.py
Original file line number Diff line number Diff line change
Expand Up @@ -154,7 +154,7 @@ def addNames(self, names: Iterable[str]) -> None:

def currentName(self) -> str | None:
if (current := self._name_list.currentItem()) is not None:
return current.text()
return current.text() # type: ignore [no-any-return]
return None

Check warning on line 158 in src/pymmcore_widgets/config_presets/_oc_dialog.py

View check run for this annotation

Codecov / codecov/patch

src/pymmcore_widgets/config_presets/_oc_dialog.py#L156-L158

Added lines #L156 - L158 were not covered by tests

def setCurrentName(self, name: str) -> None:
Expand Down
334 changes: 334 additions & 0 deletions src/pymmcore_widgets/config_presets/_unique_name_list.py
Original file line number Diff line number Diff line change
@@ -0,0 +1,334 @@
from __future__ import annotations

Check warning on line 1 in src/pymmcore_widgets/config_presets/_unique_name_list.py

View check run for this annotation

Codecov / codecov/patch

src/pymmcore_widgets/config_presets/_unique_name_list.py#L1

Added line #L1 was not covered by tests

import warnings
from typing import TYPE_CHECKING, overload

Check warning on line 4 in src/pymmcore_widgets/config_presets/_unique_name_list.py

View check run for this annotation

Codecov / codecov/patch

src/pymmcore_widgets/config_presets/_unique_name_list.py#L3-L4

Added lines #L3 - L4 were not covered by tests

from qtpy.QtCore import Qt, Signal
from qtpy.QtWidgets import (

Check warning on line 7 in src/pymmcore_widgets/config_presets/_unique_name_list.py

View check run for this annotation

Codecov / codecov/patch

src/pymmcore_widgets/config_presets/_unique_name_list.py#L6-L7

Added lines #L6 - L7 were not covered by tests
QHBoxLayout,
QListWidget,
QListWidgetItem,
QMessageBox,
QPushButton,
QVBoxLayout,
QWidget,
)
from superqt.utils import signals_blocked

Check warning on line 16 in src/pymmcore_widgets/config_presets/_unique_name_list.py

View check run for this annotation

Codecov / codecov/patch

src/pymmcore_widgets/config_presets/_unique_name_list.py#L16

Added line #L16 was not covered by tests

if TYPE_CHECKING:
from collections.abc import Iterable


class UniqueListWidget(QListWidget):

Check warning on line 22 in src/pymmcore_widgets/config_presets/_unique_name_list.py

View check run for this annotation

Codecov / codecov/patch

src/pymmcore_widgets/config_presets/_unique_name_list.py#L22

Added line #L22 was not covered by tests
@overload
def addItem(self, item: QListWidgetItem | None, /) -> None: ...
@overload
def addItem(self, label: str | None, /) -> None: ...
def addItem(self, item: QListWidgetItem | str | None) -> None:
if item is None:
item = QListWidgetItem()
txt = item.text() if isinstance(item, QListWidgetItem) else item
for i in self._iter_texts():
if i == txt:
raise ValueError(f"Item with text {txt!r} already exists.")
super().addItem(item)

Check warning on line 34 in src/pymmcore_widgets/config_presets/_unique_name_list.py

View check run for this annotation

Codecov / codecov/patch

src/pymmcore_widgets/config_presets/_unique_name_list.py#L27-L34

Added lines #L27 - L34 were not covered by tests

def addItems(self, labels: Iterable[str | None]) -> None:
for label in labels:
self.addItem(label)

Check warning on line 38 in src/pymmcore_widgets/config_presets/_unique_name_list.py

View check run for this annotation

Codecov / codecov/patch

src/pymmcore_widgets/config_presets/_unique_name_list.py#L36-L38

Added lines #L36 - L38 were not covered by tests

def _iter_texts(self) -> Iterable[str]:
for i in range(self.count()):
if item := self.item(i):
yield item.text()

Check warning on line 43 in src/pymmcore_widgets/config_presets/_unique_name_list.py

View check run for this annotation

Codecov / codecov/patch

src/pymmcore_widgets/config_presets/_unique_name_list.py#L40-L43

Added lines #L40 - L43 were not covered by tests


class UniqueKeyList(QWidget):

Check warning on line 46 in src/pymmcore_widgets/config_presets/_unique_name_list.py

View check run for this annotation

Codecov / codecov/patch

src/pymmcore_widgets/config_presets/_unique_name_list.py#L46

Added line #L46 was not covered by tests
"""A QListWidget container that displays a list of unique keys.
Buttons are provided to add, remove, and duplicate keys. The text of each key is
editable, and the widget ensures that all keys are unique (*provided the API of the
underlying QListWidget is not used directly*). Signals are emitted when keys are
added, removed, or changed.
Parameters
----------
parent : QWidget | None
The parent widget.
base_key : str
The base key used to generate new keys. Default is 'Item'.
confirm_removal : bool
Whether to confirm removal of items with a dialog. Default is True.
"""

keyAdded = Signal(str, object) # new key, old_key (if duplicated) | None
keyRemoved = Signal(str) # removed key
keyChanged = Signal(str, str) # new key, old key
currentkeyChanged = Signal()

Check warning on line 67 in src/pymmcore_widgets/config_presets/_unique_name_list.py

View check run for this annotation

Codecov / codecov/patch

src/pymmcore_widgets/config_presets/_unique_name_list.py#L64-L67

Added lines #L64 - L67 were not covered by tests
# TODO: could possibly add removingKey, and changingKey signals if needed

def __init__(

Check warning on line 70 in src/pymmcore_widgets/config_presets/_unique_name_list.py

View check run for this annotation

Codecov / codecov/patch

src/pymmcore_widgets/config_presets/_unique_name_list.py#L70

Added line #L70 was not covered by tests
self,
parent: QWidget | None = None,
*,
base_key: str = "Item",
confirm_removal: bool = True,
) -> None:
super().__init__(parent)

Check warning on line 77 in src/pymmcore_widgets/config_presets/_unique_name_list.py

View check run for this annotation

Codecov / codecov/patch

src/pymmcore_widgets/config_presets/_unique_name_list.py#L77

Added line #L77 was not covered by tests

self._base_key = base_key
self._confirm_removal = confirm_removal
self._select_new_items = True
self._default_flags = (

Check warning on line 82 in src/pymmcore_widgets/config_presets/_unique_name_list.py

View check run for this annotation

Codecov / codecov/patch

src/pymmcore_widgets/config_presets/_unique_name_list.py#L79-L82

Added lines #L79 - L82 were not covered by tests
Qt.ItemFlag.ItemIsEditable
| Qt.ItemFlag.ItemIsSelectable
| Qt.ItemFlag.ItemIsEnabled
)

# stores the text of the currently selected item in case of editing
self._active_item_text: str = ""

Check warning on line 89 in src/pymmcore_widgets/config_presets/_unique_name_list.py

View check run for this annotation

Codecov / codecov/patch

src/pymmcore_widgets/config_presets/_unique_name_list.py#L89

Added line #L89 was not covered by tests
# stores the texts of the items before the current item was changed
self._previous_keys: set[str] = set()

Check warning on line 91 in src/pymmcore_widgets/config_presets/_unique_name_list.py

View check run for this annotation

Codecov / codecov/patch

src/pymmcore_widgets/config_presets/_unique_name_list.py#L91

Added line #L91 was not covered by tests

# WIDGETS ---------------------------------------------------

self._list_widget = QListWidget(self)
self._list_widget.setEditTriggers(

Check warning on line 96 in src/pymmcore_widgets/config_presets/_unique_name_list.py

View check run for this annotation

Codecov / codecov/patch

src/pymmcore_widgets/config_presets/_unique_name_list.py#L95-L96

Added lines #L95 - L96 were not covered by tests
QListWidget.EditTrigger.DoubleClicked
| QListWidget.EditTrigger.SelectedClicked
)

self.btn_new = QPushButton("New")
self.btn_remove = QPushButton("Remove...")
self.btn_duplicate = QPushButton("Duplicate")

Check warning on line 103 in src/pymmcore_widgets/config_presets/_unique_name_list.py

View check run for this annotation

Codecov / codecov/patch

src/pymmcore_widgets/config_presets/_unique_name_list.py#L101-L103

Added lines #L101 - L103 were not covered by tests

# connections ------------------------------------

self._list_widget.currentItemChanged.connect(self._on_current_item_changed)
self._list_widget.itemChanged.connect(self._on_item_changed)

Check warning on line 108 in src/pymmcore_widgets/config_presets/_unique_name_list.py

View check run for this annotation

Codecov / codecov/patch

src/pymmcore_widgets/config_presets/_unique_name_list.py#L107-L108

Added lines #L107 - L108 were not covered by tests

self.btn_new.clicked.connect(self._add_unique_key)
self.btn_remove.clicked.connect(self._remove_current)
self.btn_duplicate.clicked.connect(self._duplicate_current)

Check warning on line 112 in src/pymmcore_widgets/config_presets/_unique_name_list.py

View check run for this annotation

Codecov / codecov/patch

src/pymmcore_widgets/config_presets/_unique_name_list.py#L110-L112

Added lines #L110 - L112 were not covered by tests

# layout ---------------------------------------------------

# public so that subclasses can add more buttons

self.btn_layout = QVBoxLayout()
self.btn_layout.addWidget(self.btn_new)
self.btn_layout.addWidget(self.btn_remove)
self.btn_layout.addWidget(self.btn_duplicate)
self.btn_layout.addStretch()

Check warning on line 122 in src/pymmcore_widgets/config_presets/_unique_name_list.py

View check run for this annotation

Codecov / codecov/patch

src/pymmcore_widgets/config_presets/_unique_name_list.py#L118-L122

Added lines #L118 - L122 were not covered by tests

layout = QHBoxLayout(self)
layout.addWidget(self._list_widget)
layout.addLayout(self.btn_layout)

Check warning on line 126 in src/pymmcore_widgets/config_presets/_unique_name_list.py

View check run for this annotation

Codecov / codecov/patch

src/pymmcore_widgets/config_presets/_unique_name_list.py#L124-L126

Added lines #L124 - L126 were not covered by tests

# PUBLIC API ---------------------------------------------------

def listWidget(self) -> QListWidget:

Check warning on line 130 in src/pymmcore_widgets/config_presets/_unique_name_list.py

View check run for this annotation

Codecov / codecov/patch

src/pymmcore_widgets/config_presets/_unique_name_list.py#L130

Added line #L130 was not covered by tests
"""Return the QListWidget used to display the keys.
Note that directly using the QListWidget API can bypass the uniqueness checks
and emissions of signals. Use with caution.
"""
return self._list_widget

Check warning on line 136 in src/pymmcore_widgets/config_presets/_unique_name_list.py

View check run for this annotation

Codecov / codecov/patch

src/pymmcore_widgets/config_presets/_unique_name_list.py#L136

Added line #L136 was not covered by tests

def clear(self) -> None:

Check warning on line 138 in src/pymmcore_widgets/config_presets/_unique_name_list.py

View check run for this annotation

Codecov / codecov/patch

src/pymmcore_widgets/config_presets/_unique_name_list.py#L138

Added line #L138 was not covered by tests
"""Clear all keys from the list."""
self._list_widget.clear()

Check warning on line 140 in src/pymmcore_widgets/config_presets/_unique_name_list.py

View check run for this annotation

Codecov / codecov/patch

src/pymmcore_widgets/config_presets/_unique_name_list.py#L140

Added line #L140 was not covered by tests

def addKey(self, key: str | QListWidgetItem) -> None:

Check warning on line 142 in src/pymmcore_widgets/config_presets/_unique_name_list.py

View check run for this annotation

Codecov / codecov/patch

src/pymmcore_widgets/config_presets/_unique_name_list.py#L142

Added line #L142 was not covered by tests
"""Add a key to the list.
Parameters
----------
key : str | QListWidgetItem
The key to add. If a QListWidgetItem is provided, its text must be unique.
Raises
------
ValueError
If the key is already in the list.
"""
if isinstance(key, QListWidgetItem):
item, txt = key, key.text()

Check warning on line 156 in src/pymmcore_widgets/config_presets/_unique_name_list.py

View check run for this annotation

Codecov / codecov/patch

src/pymmcore_widgets/config_presets/_unique_name_list.py#L155-L156

Added lines #L155 - L156 were not covered by tests
else:
txt = str(key)
item = QListWidgetItem(txt)

Check warning on line 159 in src/pymmcore_widgets/config_presets/_unique_name_list.py

View check run for this annotation

Codecov / codecov/patch

src/pymmcore_widgets/config_presets/_unique_name_list.py#L158-L159

Added lines #L158 - L159 were not covered by tests

if any(i == txt for i in self._iter_texts()):
raise ValueError(f"Item with text {txt!r} already exists.")

Check warning on line 162 in src/pymmcore_widgets/config_presets/_unique_name_list.py

View check run for this annotation

Codecov / codecov/patch

src/pymmcore_widgets/config_presets/_unique_name_list.py#L161-L162

Added lines #L161 - L162 were not covered by tests

item.setFlags(self._default_flags)
self._list_widget.addItem(item)
self.keyAdded.emit(txt, None)

Check warning on line 166 in src/pymmcore_widgets/config_presets/_unique_name_list.py

View check run for this annotation

Codecov / codecov/patch

src/pymmcore_widgets/config_presets/_unique_name_list.py#L164-L166

Added lines #L164 - L166 were not covered by tests

# select the new item
if self._select_new_items:
self._list_widget.setCurrentRow(self._list_widget.count() - 1)

Check warning on line 170 in src/pymmcore_widgets/config_presets/_unique_name_list.py

View check run for this annotation

Codecov / codecov/patch

src/pymmcore_widgets/config_presets/_unique_name_list.py#L169-L170

Added lines #L169 - L170 were not covered by tests

def addKeys(self, keys: Iterable[str]) -> None:

Check warning on line 172 in src/pymmcore_widgets/config_presets/_unique_name_list.py

View check run for this annotation

Codecov / codecov/patch

src/pymmcore_widgets/config_presets/_unique_name_list.py#L172

Added line #L172 was not covered by tests
"""Add multiple keys to the list.
Raises
------
ValueError
If any of the keys are already in the list.
"""
with signals_blocked(self):
for key in keys:
self.addKey(key)

Check warning on line 182 in src/pymmcore_widgets/config_presets/_unique_name_list.py

View check run for this annotation

Codecov / codecov/patch

src/pymmcore_widgets/config_presets/_unique_name_list.py#L180-L182

Added lines #L180 - L182 were not covered by tests

# slightly hacky... this is to ensure that the currentkeyChanged signal
# is emitted only once after all keys have been added
for key in keys:
self.keyAdded.emit(key, None)
self.currentkeyChanged.emit()

Check warning on line 188 in src/pymmcore_widgets/config_presets/_unique_name_list.py

View check run for this annotation

Codecov / codecov/patch

src/pymmcore_widgets/config_presets/_unique_name_list.py#L186-L188

Added lines #L186 - L188 were not covered by tests

def removeKey(self, key: str | int) -> None:

Check warning on line 190 in src/pymmcore_widgets/config_presets/_unique_name_list.py

View check run for this annotation

Codecov / codecov/patch

src/pymmcore_widgets/config_presets/_unique_name_list.py#L190

Added line #L190 was not covered by tests
"""Remove a key from the list.
Parameters
----------
key : str | int
The key to remove. If a string is provided, the first item with that text
will be removed. If an integer is provided, the item at that index will be
removed.
"""
if isinstance(key, int):
idx: int = key

Check warning on line 201 in src/pymmcore_widgets/config_presets/_unique_name_list.py

View check run for this annotation

Codecov / codecov/patch

src/pymmcore_widgets/config_presets/_unique_name_list.py#L200-L201

Added lines #L200 - L201 were not covered by tests
else:
for i, txt in enumerate(self._iter_texts()):
if txt == key:
idx = i
break

Check warning on line 206 in src/pymmcore_widgets/config_presets/_unique_name_list.py

View check run for this annotation

Codecov / codecov/patch

src/pymmcore_widgets/config_presets/_unique_name_list.py#L203-L206

Added lines #L203 - L206 were not covered by tests
else: # key not found
return

Check warning on line 208 in src/pymmcore_widgets/config_presets/_unique_name_list.py

View check run for this annotation

Codecov / codecov/patch

src/pymmcore_widgets/config_presets/_unique_name_list.py#L208

Added line #L208 was not covered by tests

# NOTE! takeItem will result in current Item changing, which will trigger
# _on_current_item_changed BEFORE the item is actually removed.
# so we need to update self._previous_keys manually here
if item := self._list_widget.takeItem(idx):
self._previous_keys = set(self._iter_texts())
self.keyRemoved.emit(item.text())

Check warning on line 215 in src/pymmcore_widgets/config_presets/_unique_name_list.py

View check run for this annotation

Codecov / codecov/patch

src/pymmcore_widgets/config_presets/_unique_name_list.py#L213-L215

Added lines #L213 - L215 were not covered by tests

def currentkey(self) -> str | None:

Check warning on line 217 in src/pymmcore_widgets/config_presets/_unique_name_list.py

View check run for this annotation

Codecov / codecov/patch

src/pymmcore_widgets/config_presets/_unique_name_list.py#L217

Added line #L217 was not covered by tests
"""Return the text of the currently selected item."""
if (current := self._list_widget.currentItem()) is not None:
return current.text() # type: ignore [no-any-return]
return None

Check warning on line 221 in src/pymmcore_widgets/config_presets/_unique_name_list.py

View check run for this annotation

Codecov / codecov/patch

src/pymmcore_widgets/config_presets/_unique_name_list.py#L219-L221

Added lines #L219 - L221 were not covered by tests

def setCurrentkey(self, key: str) -> None:

Check warning on line 223 in src/pymmcore_widgets/config_presets/_unique_name_list.py

View check run for this annotation

Codecov / codecov/patch

src/pymmcore_widgets/config_presets/_unique_name_list.py#L223

Added line #L223 was not covered by tests
"""Set the currently selected item by its text."""
if key == self.currentkey():
return
for i, txt in enumerate(self._iter_texts()):
if txt == key:
self._list_widget.setCurrentRow(i)
return
warnings.warn(f"Item with text {key!r} not found.", stacklevel=2)

Check warning on line 231 in src/pymmcore_widgets/config_presets/_unique_name_list.py

View check run for this annotation

Codecov / codecov/patch

src/pymmcore_widgets/config_presets/_unique_name_list.py#L225-L231

Added lines #L225 - L231 were not covered by tests

def setConfirmRemoval(self, confirm: bool) -> None:

Check warning on line 233 in src/pymmcore_widgets/config_presets/_unique_name_list.py

View check run for this annotation

Codecov / codecov/patch

src/pymmcore_widgets/config_presets/_unique_name_list.py#L233

Added line #L233 was not covered by tests
"""Set whether to confirm removal of items with a dialog."""
self._confirm_removal = confirm

Check warning on line 235 in src/pymmcore_widgets/config_presets/_unique_name_list.py

View check run for this annotation

Codecov / codecov/patch

src/pymmcore_widgets/config_presets/_unique_name_list.py#L235

Added line #L235 was not covered by tests

def setSelectNewItems(self, select: bool) -> None:

Check warning on line 237 in src/pymmcore_widgets/config_presets/_unique_name_list.py

View check run for this annotation

Codecov / codecov/patch

src/pymmcore_widgets/config_presets/_unique_name_list.py#L237

Added line #L237 was not covered by tests
"""Set whether to select new items after adding them."""
self._select_new_items = select

Check warning on line 239 in src/pymmcore_widgets/config_presets/_unique_name_list.py

View check run for this annotation

Codecov / codecov/patch

src/pymmcore_widgets/config_presets/_unique_name_list.py#L239

Added line #L239 was not covered by tests

def setDefaultFlags(self, flags: Qt.ItemFlag) -> None:

Check warning on line 241 in src/pymmcore_widgets/config_presets/_unique_name_list.py

View check run for this annotation

Codecov / codecov/patch

src/pymmcore_widgets/config_presets/_unique_name_list.py#L241

Added line #L241 was not covered by tests
"""Set the default flags for new items."""
self._default_flags = flags

Check warning on line 243 in src/pymmcore_widgets/config_presets/_unique_name_list.py

View check run for this annotation

Codecov / codecov/patch

src/pymmcore_widgets/config_presets/_unique_name_list.py#L243

Added line #L243 was not covered by tests

def setBaseKey(self, base_key: str) -> None:

Check warning on line 245 in src/pymmcore_widgets/config_presets/_unique_name_list.py

View check run for this annotation

Codecov / codecov/patch

src/pymmcore_widgets/config_presets/_unique_name_list.py#L245

Added line #L245 was not covered by tests
"""Set the base key used to generate new keys.
By default, the base key is 'Item'.
"""
self._base_key = base_key

Check warning on line 250 in src/pymmcore_widgets/config_presets/_unique_name_list.py

View check run for this annotation

Codecov / codecov/patch

src/pymmcore_widgets/config_presets/_unique_name_list.py#L250

Added line #L250 was not covered by tests

# PRIVATE ---------------------------------------------------

def _iter_texts(self) -> Iterable[str]:

Check warning on line 254 in src/pymmcore_widgets/config_presets/_unique_name_list.py

View check run for this annotation

Codecov / codecov/patch

src/pymmcore_widgets/config_presets/_unique_name_list.py#L254

Added line #L254 was not covered by tests
"""Convenience method to iterate over the texts of the items."""
for i in range(self._list_widget.count()):
if item := self._list_widget.item(i):
yield item.text()

Check warning on line 258 in src/pymmcore_widgets/config_presets/_unique_name_list.py

View check run for this annotation

Codecov / codecov/patch

src/pymmcore_widgets/config_presets/_unique_name_list.py#L256-L258

Added lines #L256 - L258 were not covered by tests

def _next_unique_key(self, base_key: str | None = None) -> str:

Check warning on line 260 in src/pymmcore_widgets/config_presets/_unique_name_list.py

View check run for this annotation

Codecov / codecov/patch

src/pymmcore_widgets/config_presets/_unique_name_list.py#L260

Added line #L260 was not covered by tests
"""Return the next unique key in the form 'base_key [i?]'."""
if base_key is None:
base_key = self._base_key

Check warning on line 263 in src/pymmcore_widgets/config_presets/_unique_name_list.py

View check run for this annotation

Codecov / codecov/patch

src/pymmcore_widgets/config_presets/_unique_name_list.py#L262-L263

Added lines #L262 - L263 were not covered by tests

new_key = base_key
existing = set(self._iter_texts())
i = 1

Check warning on line 267 in src/pymmcore_widgets/config_presets/_unique_name_list.py

View check run for this annotation

Codecov / codecov/patch

src/pymmcore_widgets/config_presets/_unique_name_list.py#L265-L267

Added lines #L265 - L267 were not covered by tests
# NOTE: if an intermediate key is removed, it will be reused
while new_key in existing:
new_key = f"{base_key} {i}"
i += 1
return new_key

Check warning on line 272 in src/pymmcore_widgets/config_presets/_unique_name_list.py

View check run for this annotation

Codecov / codecov/patch

src/pymmcore_widgets/config_presets/_unique_name_list.py#L269-L272

Added lines #L269 - L272 were not covered by tests

def _add_unique_key(self) -> None:

Check warning on line 274 in src/pymmcore_widgets/config_presets/_unique_name_list.py

View check run for this annotation

Codecov / codecov/patch

src/pymmcore_widgets/config_presets/_unique_name_list.py#L274

Added line #L274 was not covered by tests
"""Add a new item to the list."""
self.addKey(self._next_unique_key())

Check warning on line 276 in src/pymmcore_widgets/config_presets/_unique_name_list.py

View check run for this annotation

Codecov / codecov/patch

src/pymmcore_widgets/config_presets/_unique_name_list.py#L276

Added line #L276 was not covered by tests

def _remove_current(self) -> None:

Check warning on line 278 in src/pymmcore_widgets/config_presets/_unique_name_list.py

View check run for this annotation

Codecov / codecov/patch

src/pymmcore_widgets/config_presets/_unique_name_list.py#L278

Added line #L278 was not covered by tests
"""Remove the currently selected item."""
if (current := self._list_widget.currentItem()) is None:
return

Check warning on line 281 in src/pymmcore_widgets/config_presets/_unique_name_list.py

View check run for this annotation

Codecov / codecov/patch

src/pymmcore_widgets/config_presets/_unique_name_list.py#L280-L281

Added lines #L280 - L281 were not covered by tests

if self._confirm_removal:
if (

Check warning on line 284 in src/pymmcore_widgets/config_presets/_unique_name_list.py

View check run for this annotation

Codecov / codecov/patch

src/pymmcore_widgets/config_presets/_unique_name_list.py#L283-L284

Added lines #L283 - L284 were not covered by tests
QMessageBox.question(
self,
"Remove Preset",
f"Are you sure you want to remove {current.text()!r}?",
QMessageBox.StandardButton.Yes | QMessageBox.StandardButton.No,
)
== QMessageBox.StandardButton.No
):
return

Check warning on line 293 in src/pymmcore_widgets/config_presets/_unique_name_list.py

View check run for this annotation

Codecov / codecov/patch

src/pymmcore_widgets/config_presets/_unique_name_list.py#L293

Added line #L293 was not covered by tests

self.removeKey(self._list_widget.currentRow())

Check warning on line 295 in src/pymmcore_widgets/config_presets/_unique_name_list.py

View check run for this annotation

Codecov / codecov/patch

src/pymmcore_widgets/config_presets/_unique_name_list.py#L295

Added line #L295 was not covered by tests

def _duplicate_current(self) -> None:

Check warning on line 297 in src/pymmcore_widgets/config_presets/_unique_name_list.py

View check run for this annotation

Codecov / codecov/patch

src/pymmcore_widgets/config_presets/_unique_name_list.py#L297

Added line #L297 was not covered by tests
"""Create a new key by duplicating the currently selected key."""
if (current := self._list_widget.currentItem()) is None:
return

Check warning on line 300 in src/pymmcore_widgets/config_presets/_unique_name_list.py

View check run for this annotation

Codecov / codecov/patch

src/pymmcore_widgets/config_presets/_unique_name_list.py#L299-L300

Added lines #L299 - L300 were not covered by tests

# get current key and create a new unique key based on it
base_key = current.text()
new_key = self._next_unique_key(f"{base_key} Copy")

Check warning on line 304 in src/pymmcore_widgets/config_presets/_unique_name_list.py

View check run for this annotation

Codecov / codecov/patch

src/pymmcore_widgets/config_presets/_unique_name_list.py#L303-L304

Added lines #L303 - L304 were not covered by tests
# add the new key, but block signals so that we can emit
# the keyAdded signal with the old key (which implies duplication)
with signals_blocked(self):
self.addKey(new_key)
self.keyAdded.emit(new_key, base_key)

Check warning on line 309 in src/pymmcore_widgets/config_presets/_unique_name_list.py

View check run for this annotation

Codecov / codecov/patch

src/pymmcore_widgets/config_presets/_unique_name_list.py#L307-L309

Added lines #L307 - L309 were not covered by tests

def _on_current_item_changed(

Check warning on line 311 in src/pymmcore_widgets/config_presets/_unique_name_list.py

View check run for this annotation

Codecov / codecov/patch

src/pymmcore_widgets/config_presets/_unique_name_list.py#L311

Added line #L311 was not covered by tests
self, current: QListWidgetItem | None, previous: QListWidgetItem | None
) -> None:
"""Called whenever the *current* item changes (not its data)."""
self._previous_keys = set(self._iter_texts())
if current is not None:

Check warning on line 316 in src/pymmcore_widgets/config_presets/_unique_name_list.py

View check run for this annotation

Codecov / codecov/patch

src/pymmcore_widgets/config_presets/_unique_name_list.py#L315-L316

Added lines #L315 - L316 were not covered by tests
# Store the text of the current item so that we can check for duplicates
# if the item is later edited.
prev_text, self._active_item_text = self._active_item_text, current.text()

Check warning on line 319 in src/pymmcore_widgets/config_presets/_unique_name_list.py

View check run for this annotation

Codecov / codecov/patch

src/pymmcore_widgets/config_presets/_unique_name_list.py#L319

Added line #L319 was not covered by tests
# emit signal if the key has changed
if prev_text != self._active_item_text:
self.currentkeyChanged.emit()

Check warning on line 322 in src/pymmcore_widgets/config_presets/_unique_name_list.py

View check run for this annotation

Codecov / codecov/patch

src/pymmcore_widgets/config_presets/_unique_name_list.py#L321-L322

Added lines #L321 - L322 were not covered by tests

def _on_item_changed(self, item: QListWidgetItem) -> None:

Check warning on line 324 in src/pymmcore_widgets/config_presets/_unique_name_list.py

View check run for this annotation

Codecov / codecov/patch

src/pymmcore_widgets/config_presets/_unique_name_list.py#L324

Added line #L324 was not covered by tests
"""Called whenever the data of item has changed.."""
new_text, previous_text = item.text(), self._active_item_text
if new_text != previous_text and new_text in self._previous_keys:
QMessageBox.warning(self, "Duplicate Item", f"{new_text!r} already exists.")
item.setText(previous_text)
return

Check warning on line 330 in src/pymmcore_widgets/config_presets/_unique_name_list.py

View check run for this annotation

Codecov / codecov/patch

src/pymmcore_widgets/config_presets/_unique_name_list.py#L326-L330

Added lines #L326 - L330 were not covered by tests

# it's a valid change
self._active_item_key = new_text
self.keyChanged.emit(new_text, previous_text)

Check warning on line 334 in src/pymmcore_widgets/config_presets/_unique_name_list.py

View check run for this annotation

Codecov / codecov/patch

src/pymmcore_widgets/config_presets/_unique_name_list.py#L333-L334

Added lines #L333 - L334 were not covered by tests

0 comments on commit 95a0fbd

Please sign in to comment.