diff --git a/activity_browser/layouts/tabs/impact_categories.py b/activity_browser/layouts/tabs/impact_categories.py index 8f751e3f9..7c249b22f 100644 --- a/activity_browser/layouts/tabs/impact_categories.py +++ b/activity_browser/layouts/tabs/impact_categories.py @@ -68,6 +68,13 @@ def __init__(self, parent): self.table = MethodsTable(self) self.table.setToolTip( "Drag (groups of) impact categories to the calculation setup") + + # auto-search + self.debounce_search = QtCore.QTimer() + self.debounce_search.setInterval(300) + self.debounce_search.setSingleShot(True) + self.debounce_search.timeout.connect(self.set_search_term) + # self.search_box = QtWidgets.QLineEdit() self.search_box.setPlaceholderText("Search impact categories") @@ -122,34 +129,33 @@ def __init__(self, parent): self.table.setVisible(False) self.setLayout(container) - self.reset_search_button.clicked.connect(self.table.sync) - self.reset_search_button.clicked.connect(self.tree.model.sync) - - self.search_button.clicked.connect(lambda: self.table.sync(query=self.search_box.text())) - self.search_button.clicked.connect(lambda: self.tree.model.sync(query=self.search_box.text())) - self.reset_search_button.clicked.connect(self.search_box.clear) - self.search_box.returnPressed.connect(lambda: self.table.sync(query=self.search_box.text())) - self.search_box.returnPressed.connect(lambda: self.tree.model.sync(query=self.search_box.text())) - - signals.project_selected.connect(self.search_box.clear) self.connect_signals() def connect_signals(self): self.mode_radio_list.toggled.connect(self.update_view) - @QtCore.Slot(tuple, name="searchCopiedMethod") - def method_copied(self, method: tuple) -> None: - """If a method is successfully copied, we might want to filter, but for now do nothing.""" - # """If a method is successfully copied, sync and filter for new name.""" - # query = ", ".join(method) - # self.search_box.setText(query) + self.reset_search_button.clicked.connect(self.table.sync) + self.reset_search_button.clicked.connect(self.tree.model.sync) + + self.search_button.clicked.connect(self.set_search_term) + self.search_button.clicked.connect(self.set_search_term) + self.search_box.returnPressed.connect(self.set_search_term) + self.search_box.returnPressed.connect(self.set_search_term) + self.search_box.textChanged.connect(self.debounce_search.start) + + self.reset_search_button.clicked.connect(self.search_box.clear) + signals.project_selected.connect(self.search_box.clear) @QtCore.Slot(bool, name="isListToggled") def update_view(self, toggled: bool): self.tree.setVisible(not toggled) - # self.tree_settings_layout_container.setVisible(not toggled) self.table.setVisible(toggled) + def set_search_term(self): + search_term = self.search_box.text().strip() + self.table.sync(query=search_term) + self.tree.model.sync(query=search_term) + class CharacterizationFactorsTab(ABTab): def __init__(self, parent=None): diff --git a/activity_browser/layouts/tabs/project_manager.py b/activity_browser/layouts/tabs/project_manager.py index 89855ff42..3bdf926a0 100644 --- a/activity_browser/layouts/tabs/project_manager.py +++ b/activity_browser/layouts/tabs/project_manager.py @@ -212,6 +212,12 @@ def __init__(self, parent): self.header_layout.setAlignment(QtCore.Qt.AlignLeft) self.header_widget.setLayout(self.header_layout) + # auto-search + self.debounce_search = QtCore.QTimer() + self.debounce_search.setInterval(300) + self.debounce_search.setSingleShot(True) + self.debounce_search.timeout.connect(self.set_search_term) + self.setup_search() # Overall Layout @@ -234,6 +240,7 @@ def setup_search(self): # 1st search box self.search_box = QtWidgets.QLineEdit() self.search_box.setPlaceholderText("Search") + self.search_box.textChanged.connect(self.debounce_search.start) self.search_box.returnPressed.connect(self.set_search_term) # search @@ -256,5 +263,5 @@ def setup_search(self): self.header_layout.addWidget(self.reset_search_button) def set_search_term(self): - search_term = self.search_box.text() + search_term = self.search_box.text().strip() self.table.search(search_term) diff --git a/activity_browser/ui/tables/models/inventory.py b/activity_browser/ui/tables/models/inventory.py index ce294de4d..af78ea7e3 100644 --- a/activity_browser/ui/tables/models/inventory.py +++ b/activity_browser/ui/tables/models/inventory.py @@ -102,7 +102,7 @@ def df_from_metadata(self, db_name: str) -> pd.DataFrame: def sync(self, db_name: str, df: pd.DataFrame = None) -> None: if df is not None: # skip the rest of the sync here if a dataframe is directly supplied - log.info("Pandas Dataframe passed to sync.", df.shape) + log.debug("Pandas Dataframe passed to sync.", df.shape) self._dataframe = df self.updated.emit() return diff --git a/activity_browser/ui/tables/views.py b/activity_browser/ui/tables/views.py index 31fc900f5..43f5fd210 100644 --- a/activity_browser/ui/tables/views.py +++ b/activity_browser/ui/tables/views.py @@ -296,7 +296,7 @@ def update_proxy_model(self) -> None: def quick_filter(self) -> None: # remove weird whitespace from input - query = self.input_line.text().translate(str.maketrans('', '', '\n\t\r')) + query = self.input_line.text().translate(str.maketrans('', '', '\n\t\r')).strip() # convert to filter col_name = {v: k for k, v in self.model.filterable_columns.items()}[self.selected_column] diff --git a/activity_browser/ui/widgets/dialog.py b/activity_browser/ui/widgets/dialog.py index af18813ac..b5fe1ebff 100644 --- a/activity_browser/ui/widgets/dialog.py +++ b/activity_browser/ui/widgets/dialog.py @@ -939,7 +939,7 @@ def __init__(self, idx: int, @property def get_state(self) -> tuple: # remove weird whitespace from input - query_line = self.filter_query_line.text().translate(str.maketrans('', '', '\n\t\r')) + query_line = self.filter_query_line.text().translate(str.maketrans('', '', '\n\t\r')).strip() # if valid, return a tuple with the state, otherwise, return None if query_line == '': return None @@ -1002,7 +1002,7 @@ def __init__(self, idx: int, @property def get_state(self) -> tuple: # remove weird whitespace from input - query_line = self.filter_query_line.text().translate(str.maketrans('', '', ' \n\t\r')) + query_line = self.filter_query_line.text().translate(str.maketrans('', '', ' \n\t\r')).strip() # if valid, return a tuple with the state, otherwise, return None if query_line == '': return None diff --git a/tests/test_add_default_data.py b/tests/test_add_default_data.py index 70a0ed505..4afa0d38a 100644 --- a/tests/test_add_default_data.py +++ b/tests/test_add_default_data.py @@ -76,10 +76,15 @@ def test_search_biosphere(qtbot, ab_app): with qtbot.waitSignal(act_bio_widget.search_box.returnPressed, timeout=1000): qtbot.keyClicks(act_bio_widget.search_box, 'Pentanol') qtbot.keyPress(act_bio_widget.search_box, QtCore.Qt.Key_Return) + + # Reset search box & timer so it doesn't auto-search after this test + act_bio_widget.search_box.clear() + act_bio_widget.debounce_search.stop() # We found some results! assert act_bio_widget.table.rowCount() > 0 # And the table is now definitely smaller than it was. assert act_bio_widget.table.rowCount() < initial_amount + def test_fail_open_biosphere(ab_app): diff --git a/tests/test_projects.py b/tests/test_projects.py index d374b305e..233302406 100644 --- a/tests/test_projects.py +++ b/tests/test_projects.py @@ -2,6 +2,8 @@ import brightway2 as bw from PySide2 import QtCore, QtWidgets +from activity_browser.ui.widgets.dialog import ProjectDeletionDialog + def test_new_project(qtbot, ab_app, monkeypatch): qtbot.waitForWindowShown(ab_app.main_window) @@ -30,17 +32,25 @@ def test_change_project(qtbot, ab_app): assert bw.projects.current == 'pytest_project_del' -#def test_delete_project(qtbot, ab_app, monkeypatch): -# qtbot.waitForWindowShown(ab_app.main_window) -# assert bw.projects.current == 'pytest_project_del' -# monkeypatch.setattr( -# QtWidgets.QMessageBox, "question", -# staticmethod(lambda *args: QtWidgets.QMessageBox.Yes) -# ) -# project_tab = ab_app.main_window.left_panel.tabs['Project'] -# qtbot.mouseClick( -# project_tab.projects_widget.delete_project_button, -# QtCore.Qt.LeftButton -# ) -# -# assert bw.projects.current == 'default' \ No newline at end of file +def test_delete_project(qtbot, ab_app, monkeypatch): + qtbot.waitForWindowShown(ab_app.main_window) + assert bw.projects.current == 'pytest_project_del' + monkeypatch.setattr( + ProjectDeletionDialog, "exec_", + staticmethod(lambda *args: ProjectDeletionDialog.Accepted) + ) + monkeypatch.setattr( + ProjectDeletionDialog, "deletion_warning_checked", + staticmethod(lambda *args: True) + ) + monkeypatch.setattr( + QtWidgets.QMessageBox, "information", + staticmethod(lambda *args: True) + ) + project_tab = ab_app.main_window.left_panel.tabs['Project'] + qtbot.mouseClick( + project_tab.projects_widget.delete_project_button, + QtCore.Qt.LeftButton + ) + + assert bw.projects.current == 'default' \ No newline at end of file