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

silx.app.view.test.test_plotselection : Added test for CustomPlotSelectionWindow #4145

Merged
merged 2 commits into from
Jul 1, 2024
Merged
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
22 changes: 17 additions & 5 deletions src/silx/app/view/CustomPlotSelectionWindow.py
Original file line number Diff line number Diff line change
Expand Up @@ -35,6 +35,8 @@
import silx.io.url
import silx.io.utils
from silx.gui.hdf5 import _utils
import weakref


# Custom role for highlighting the drop zones
_DROP_HIGHLIGHT_ROLE = qt.Qt.UserRole + 1
Expand Down Expand Up @@ -120,7 +122,7 @@ def __init__(self, plot, parent=None):
self._yParent.setEditable(False)
root.appendRow(self._yParent)

self._plot1D = plot
self._plot1D = weakref.proxy(plot)
self._index = 0

self._xDataset = None
Expand Down Expand Up @@ -332,6 +334,8 @@ def __init__(self, model, parent=None):
def _createIconWidget(self, row: int, parentItem: qt.QStandardItem):
"""Create the icon widget for a row in the model"""
fileItem = parentItem.child(row, 1)
if fileItem is None:
return
iconItem = parentItem.child(row, 0)
curve = fileItem.data(qt.Qt.UserRole)
if curve is None:
Expand Down Expand Up @@ -599,16 +603,16 @@ def __init__(self, parent=None):
super().__init__(parent)
self.setWindowTitle("Plot selection")

plot1D = _DropPlot1D()
model = _FileListModel(plot1D)
self._plot1D = _DropPlot1D()
model = _FileListModel(self._plot1D)

self._treeView = _DropTreeView(model, self)
plot1D.setTreeView(self._treeView)
self._plot1D.setTreeView(self._treeView)

centralWidget = qt.QSplitter()

centralWidget.addWidget(self._treeView)
centralWidget.addWidget(plot1D)
centralWidget.addWidget(self._plot1D)

centralWidget.setCollapsible(0, False)
centralWidget.setCollapsible(1, False)
Expand All @@ -620,6 +624,14 @@ def __init__(self, parent=None):
toolbar.addClearAction(self._treeView)
self.addToolBar(qt.Qt.TopToolBarArea, toolbar)

def getPlot1D(self) -> _DropPlot1D:
"""Return the plot widget."""
return self._plot1D

def getTreeView(self) -> _DropTreeView:
"""Return the tree view widget."""
return self._treeView

def showEvent(self, event):
super().showEvent(event)
self.sigVisibilityChanged.emit(True)
Expand Down
234 changes: 234 additions & 0 deletions src/silx/app/view/test/test_plotselection.py
Original file line number Diff line number Diff line change
@@ -0,0 +1,234 @@
import pytest
from silx.gui import qt
from silx.io.dictdump import dicttoh5
import silx.io
from silx.app.view.CustomPlotSelectionWindow import CustomPlotSelectionWindow


@pytest.fixture
def setupMimeData(tmpdir):
# Create HDF5 file with 1D dataset in tmpdir
filename = str(tmpdir.join("test.h5"))
dicttoh5({"x": [1, 2, 3], "y1": [1, 2], "y2": [4, 3, 2, 1], "y3": []}, filename)

# Create mime data
mime_data = qt.QMimeData()
url = silx.io.url.DataUrl(file_path=filename, data_path="/x")
mime_data.setData("application/x-silx-uri", url.path().encode())

return mime_data


@pytest.fixture
def setupInvalidMimeData(tmpdir):
# Create HDF5 file with 2D dataset in tmpdir
filename = str(tmpdir.join("test.h5"))
dicttoh5({"x": [[1, 2], [3, 4]], "y": [[1, 2], [3, 4]]}, filename)

# Create mime data
mime_data = qt.QMimeData()
url = silx.io.url.DataUrl(file_path=filename, data_path="/x")
mime_data.setData("application/x-silx-uri", url.path().encode())

return mime_data


def testDrop(qapp, setupMimeData, qWidgetFactory):
window = qWidgetFactory(CustomPlotSelectionWindow)

mime_data = setupMimeData

# Create drag enter event
dragEnterEvent = qt.QDragEnterEvent(
qt.QPoint(0, 0), qt.Qt.CopyAction, mime_data, qt.Qt.LeftButton, qt.Qt.NoModifier
)
window.getPlot1D().dragEnterEvent(dragEnterEvent)
qapp.processEvents()

# Create drag move event
dragMoveEvent = qt.QDragMoveEvent(
qt.QPoint(50, 50),
qt.Qt.CopyAction,
mime_data,
qt.Qt.LeftButton,
qt.Qt.NoModifier,
)
window.getPlot1D().dragMoveEvent(dragMoveEvent)
qapp.processEvents()

# Create drop event
dropEvent = qt.QDropEvent(
qt.QPoint(50, 50),
qt.Qt.CopyAction,
mime_data,
qt.Qt.LeftButton,
qt.Qt.NoModifier,
)
window.getPlot1D().dropEvent(dropEvent)
qapp.processEvents()

# Verify the drop by checking if the data is in the model
model = window.getTreeView().model()
assert model.rowCount() == 2

x_item = model.getXParent()
y_item = model.getYParent().child(0, 1)

assert x_item is not None
assert y_item is not None


def testRemoveDataset(setupMimeData, qapp, qWidgetFactory):
window = qWidgetFactory(CustomPlotSelectionWindow)

mime_data = setupMimeData

# Create drop event for X dataset
dragEnterEvent = qt.QDragEnterEvent(
qt.QPoint(0, 0), qt.Qt.CopyAction, mime_data, qt.Qt.LeftButton, qt.Qt.NoModifier
)
window.getPlot1D().dragEnterEvent(dragEnterEvent)
qapp.processEvents()

# Create drop event for Y1 dataset
dropEvent = qt.QDropEvent(
qt.QPoint(50, 50),
qt.Qt.CopyAction,
mime_data,
qt.Qt.LeftButton,
qt.Qt.NoModifier,
)
window.getPlot1D().dropEvent(dropEvent)
qapp.processEvents()

model = window.getTreeView().model()
assert model.getYParent().rowCount() == 2

# Remove the dataset
window.getTreeView()._removeFile(model.getYParent().child(0, 2), model.getYParent())
qapp.processEvents()

assert model.getYParent().rowCount() == 1


def testResetModel(setupMimeData, qapp, qWidgetFactory):
window = qWidgetFactory(CustomPlotSelectionWindow)

mime_data = setupMimeData

# Create drop event for X dataset
dragEnterEvent = qt.QDragEnterEvent(
qt.QPoint(0, 0), qt.Qt.CopyAction, mime_data, qt.Qt.LeftButton, qt.Qt.NoModifier
)
window.getPlot1D().dragEnterEvent(dragEnterEvent)
qapp.processEvents()

# Create drop event for dataset
dropEvent = qt.QDropEvent(
qt.QPoint(50, 50),
qt.Qt.CopyAction,
mime_data,
qt.Qt.LeftButton,
qt.Qt.NoModifier,
)
window.getPlot1D().dropEvent(dropEvent)
qapp.processEvents()

model = window.getTreeView().model()
assert model.getYParent().rowCount() == 2

# Reset the model
model.clearAll()
qapp.processEvents()

assert model.getXParent().rowCount() == 0
assert model.getYParent().rowCount() == 1


def testMultipleDrop(qapp, setupMimeData, qWidgetFactory, qapp_utils):
window = qWidgetFactory(CustomPlotSelectionWindow)

mime_data = setupMimeData

# Create drag enter event
dragEnterEvent = qt.QDragEnterEvent(
qt.QPoint(0, 0), qt.Qt.CopyAction, mime_data, qt.Qt.LeftButton, qt.Qt.NoModifier
)

# Create drag move event
dragMoveEvent = qt.QDragMoveEvent(
qt.QPoint(50, 50),
qt.Qt.CopyAction,
mime_data,
qt.Qt.LeftButton,
qt.Qt.NoModifier,
)

# Create drop event
dropEvent = qt.QDropEvent(
qt.QPoint(50, 50),
qt.Qt.CopyAction,
mime_data,
qt.Qt.LeftButton,
qt.Qt.NoModifier,
)

for _ in range(2):
window.getPlot1D().dragEnterEvent(dragEnterEvent)
qapp.processEvents()
window.getPlot1D().dragMoveEvent(dragMoveEvent)
qapp.processEvents()
window.getPlot1D().dropEvent(dropEvent)
qapp.processEvents()

# Verify the drop by checking if the data is in the model
model = window.getTreeView().model()
assert model.rowCount() == 2
print(model.rowCount())

x_item = model.getXParent()
y_item1 = model.getYParent().child(0, 1)
y_item2 = model.getYParent().child(1, 1)

assert x_item is not None
assert y_item1 is not None
assert y_item2 is not None


def testDropInvalid(qapp, setupInvalidMimeData, qWidgetFactory, qapp_utils):
window = qWidgetFactory(CustomPlotSelectionWindow)

mime_data = setupInvalidMimeData

# Create drag enter event
dragEnterEvent = qt.QDragEnterEvent(
qt.QPoint(0, 0), qt.Qt.CopyAction, mime_data, qt.Qt.LeftButton, qt.Qt.NoModifier
)
window.getPlot1D().dragEnterEvent(dragEnterEvent)
qapp.processEvents()

# Create drag move event
dragMoveEvent = qt.QDragMoveEvent(
qt.QPoint(50, 50),
qt.Qt.CopyAction,
mime_data,
qt.Qt.LeftButton,
qt.Qt.NoModifier,
)
window.getPlot1D().dragMoveEvent(dragMoveEvent)
qapp.processEvents()

# Create drop event
dropEvent = qt.QDropEvent(
qt.QPoint(50, 50),
qt.Qt.CopyAction,
mime_data,
qt.Qt.LeftButton,
qt.Qt.NoModifier,
)
window.getPlot1D().dropEvent(dropEvent)
qapp.processEvents()

# Verify the drop by checking if the data is in the model
model = window.getTreeView().model()
assert model.rowCount() == 2
43 changes: 43 additions & 0 deletions src/silx/conftest.py
Original file line number Diff line number Diff line change
Expand Up @@ -157,6 +157,49 @@ def qapp_utils(qapp):
utils.tearDownClass()


@pytest.fixture
def qWidgetFactory(qapp, qapp_utils):
"""QWidget factory as fixture

This fixture provides a function taking a QWidget subclass as argument
which returns an instance of this QWidget making sure it is shown first
and destroyed once the test is done.
"""
from silx.gui import qt
from silx.gui.qt.inspect import isValid

widgets = []

def createWidget(cls, *args, **kwargs):
widget = cls(*args, **kwargs)
widget.setAttribute(qt.Qt.WA_DeleteOnClose)
widget.show()
qapp_utils.qWaitForWindowExposed(widget)
widgets.append(widget)

return widget

yield createWidget

qapp.processEvents()

for widget in widgets:
if isValid(widget):
widget.close()
qapp.processEvents()

# Wait some time for all widgets to be deleted
for _ in range(10):
validWidgets = [widget for widget in widgets if isValid(widget)]
if validWidgets:
qapp_utils.qWait(10)

validWidgets = [widget for widget in widgets if isValid(widget)]
assert not validWidgets, f"Some widgets were not destroyed: {validWidgets}"

del widgets


@pytest.fixture
def tmp_h5py_file():
with BytesIO() as buffer:
Expand Down
42 changes: 1 addition & 41 deletions src/silx/gui/conftest.py
Original file line number Diff line number Diff line change
@@ -1,47 +1,7 @@
import pytest

from silx.gui import qt
from silx.gui.qt.inspect import isValid


@pytest.fixture(autouse=True)
def auto_qapp(qapp):
pass



@pytest.fixture
def qWidgetFactory(qapp, qapp_utils):
"""QWidget factory as fixture

This fixture provides a function taking a QWidget subclass as argument
which returns an instance of this QWidget making sure it is shown first
and destroyed once the test is done.
"""
widgets = []

def createWidget(cls, *args, **kwargs):
widget = cls(*args, **kwargs)
widget.setAttribute(qt.Qt.WA_DeleteOnClose)
widget.show()
qapp_utils.qWaitForWindowExposed(widget)
widgets.append(widget)

return widget

yield createWidget

qapp.processEvents()

for widget in widgets:
if isValid(widget):
widget.close()
qapp.processEvents()

# Wait some time for all widgets to be deleted
for _ in range(10):
validWidgets = [widget for widget in widgets if isValid(widget)]
if validWidgets:
qapp_utils.qWait(10)

validWidgets = [widget for widget in widgets if isValid(widget)]
assert not validWidgets, f"Some widgets were not destroyed: {validWidgets}"
Loading