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

🎉 Create a distinct clipboard for blocks #229

Merged
merged 3 commits into from
Jan 22, 2022
Merged
Show file tree
Hide file tree
Changes from 2 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
10 changes: 7 additions & 3 deletions pyflow/graphics/window.py
Original file line number Diff line number Diff line change
Expand Up @@ -23,6 +23,7 @@

from pyflow.qss import loadStylesheets
from pyflow.qss import __file__ as QSS_INIT_PATH
from pyflow.scene.clipboard import BlocksClipboard

QSS_PATH = pathlib.Path(QSS_INIT_PATH).parent

Expand Down Expand Up @@ -70,6 +71,9 @@ def __init__(self):
self.readSettings()
self.show()

# Block clipboard
self.clipboard = BlocksClipboard()

def createToolBars(self):
"""Does nothing, but is required by the QMainWindow interface."""

Expand Down Expand Up @@ -397,19 +401,19 @@ def onEditCut(self):
"""Cut the selected items if not in edit mode."""
current_window = self.activeMdiChild()
if self.is_not_editing(current_window):
current_window.scene.clipboard.cut()
self.clipboard.cut(current_window.scene)

def onEditCopy(self):
"""Copy the selected items if not in edit mode."""
current_window = self.activeMdiChild()
if self.is_not_editing(current_window):
current_window.scene.clipboard.copy()
self.clipboard.copy(current_window.scene)

def onEditPaste(self):
"""Paste the selected items if not in edit mode."""
current_window = self.activeMdiChild()
if self.is_not_editing(current_window):
current_window.scene.clipboard.paste()
self.clipboard.paste(current_window.scene)

def onEditDelete(self):
"""Delete the selected items if not in edit mode."""
Expand Down
58 changes: 30 additions & 28 deletions pyflow/scene/clipboard.py
Original file line number Diff line number Diff line change
Expand Up @@ -3,45 +3,42 @@

""" Module for the handling of scene clipboard operations. """

from typing import TYPE_CHECKING, OrderedDict
from typing import TYPE_CHECKING, OrderedDict, Union
from warnings import warn

import json
from PyQt5.QtWidgets import QApplication

from pyflow.core.edge import Edge

if TYPE_CHECKING:
from pyflow.scene import Scene
from pyflow.graphics.view import View


class SceneClipboard:

"""Helper object to handle clipboard operations on an Scene."""

def __init__(self, scene: "Scene"):
"""Helper object to handle clipboard operations on an Scene.
class BlocksClipboard:

Args:
scene: Scene reference.
"""Helper object to handle clipboard operations on blocks."""

"""
self.scene = scene
def __init__(self):
"""Helper object to handle clipboard operations on blocks."""
self.blocks_data: Union[None, OrderedDict] = None

def cut(self):
def cut(self, scene: "Scene"):
"""Cut the selected items and put them into clipboard."""
self.scene = scene
Copy link
Member

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

The attribute scene should be set in the init function, or not be an attribute at all.

self._store(self._serializeSelected(delete=True))

def copy(self):
def copy(self, scene: "Scene"):
"""Copy the selected items into clipboard."""
self.scene = scene
MathisFederico marked this conversation as resolved.
Show resolved Hide resolved
self._store(self._serializeSelected(delete=False))

def paste(self):
def paste(self, scene: "Scene"):
"""Paste the items in clipboard into the current scene."""
self._deserializeData(self._gatherData())
self.scene = scene
MathisFederico marked this conversation as resolved.
Show resolved Hide resolved
data = self._gatherData()
if data is not None:
self._deserializeData(data)

def _serializeSelected(self, delete=False) -> OrderedDict:
"""Serialize the items in the scene"""
selected_blocks, selected_edges = self.scene.sortedSelectedItems()
selected_sockets = {}

Expand Down Expand Up @@ -78,6 +75,8 @@ def _find_bbox_center(self, blocks_data):
return (xmin + xmax) / 2, (ymin + ymax) / 2

def _deserializeData(self, data: OrderedDict, set_selected=True):
"""Deserialize the items and put them in the scene"""

if data is None:
return

Expand Down Expand Up @@ -117,13 +116,16 @@ def _deserializeData(self, data: OrderedDict, set_selected=True):
)

def _store(self, data: OrderedDict):
str_data = json.dumps(data, indent=4)
QApplication.instance().clipboard().setText(str_data)

def _gatherData(self) -> str:
str_data = QApplication.instance().clipboard().text()
try:
return json.loads(str_data)
except ValueError as valueerror:
warn(f"Clipboard text could not be loaded into json data: {valueerror}")
"""Store the data in the clipboard if it is valid."""

if "blocks" not in data or not data["blocks"]:
self.blocks_data = None
return

self.blocks_data = data

def _gatherData(self) -> Union[OrderedDict, None]:
"""Return the data stored in the clipboard."""
if self.blocks_data is None:
warn(f"No object is loaded")
return self.blocks_data
2 changes: 0 additions & 2 deletions pyflow/scene/scene.py
Original file line number Diff line number Diff line change
Expand Up @@ -16,7 +16,6 @@
from pyflow.core.serializable import Serializable
from pyflow.blocks.block import Block
from pyflow.core.edge import Edge
from pyflow.scene.clipboard import SceneClipboard
from pyflow.scene.history import SceneHistory
from pyflow.core.kernel import Kernel
from pyflow.scene.from_ipynb_conversion import ipynb_to_ipyg
Expand Down Expand Up @@ -56,7 +55,6 @@ def __init__(
self._has_been_modified_listeners = []

self.history = SceneHistory(self)
self.clipboard = SceneClipboard(self)

self.kernel = Kernel()
self.threadpool = QThreadPool()
Expand Down
9 changes: 6 additions & 3 deletions tests/unit/scene/test_clipboard.py
Original file line number Diff line number Diff line change
Expand Up @@ -7,12 +7,12 @@
from pytest_mock import MockerFixture
import pytest_check as check

from pyflow.scene.clipboard import SceneClipboard
from pyflow.scene.clipboard import BlocksClipboard


class TestSerializeSelected:

"""SceneClipboard._serializeSelected"""
"""BlocksClipboard._serializeSelected"""

@pytest.fixture(autouse=True)
def setup(self, mocker: MockerFixture):
Expand Down Expand Up @@ -42,7 +42,10 @@ def setup(self, mocker: MockerFixture):
edge.destination_socket.id = dummy_edges_links[i][1]

self.scene.sortedSelectedItems.return_value = self.blocks, self.edges
self.clipboard = SceneClipboard(self.scene)
self.clipboard = BlocksClipboard()
MathisFederico marked this conversation as resolved.
Show resolved Hide resolved
# Manually set the clipboard current scene
# Because private functions of the clipboard are used
self.clipboard.scene = self.scene

def test_serialize_selected_blocks(self, mocker: MockerFixture):
"""should allow for blocks serialization."""
Expand Down