Skip to content

Commit

Permalink
Clean project typing
Browse files Browse the repository at this point in the history
  • Loading branch information
don4get committed Apr 13, 2020
1 parent 2e286bf commit 02760d7
Show file tree
Hide file tree
Showing 12 changed files with 346 additions and 184 deletions.
8 changes: 6 additions & 2 deletions nodedge/edge.py
Original file line number Diff line number Diff line change
Expand Up @@ -236,7 +236,7 @@ def removeFromSockets(self):
self.targetSocket = None
self.sourceSocket = None

def remove(self, silentForSocket: Optional[Socket] = None):
def remove(self, silentForSocket: Optional[Socket] = None, silent: bool = False):
"""
Safely remove this `Edge`.
Expand All @@ -250,6 +250,8 @@ def remove(self, silentForSocket: Optional[Socket] = None):
:param silentForSocket: Socket for whom the removal is silent
:type silentForSocket: Optional[:class:`~nodedge.socket.Socket`]
:param silent: ``True`` if no events should be triggered during removing
:type silent: ``bool``
"""

oldSockets = [self.sourceSocket, self.targetSocket]
Expand Down Expand Up @@ -278,14 +280,16 @@ def remove(self, silentForSocket: Optional[Socket] = None):
try:
for socket in oldSockets:
if socket is not None and socket.node is not None:
if silent:
continue
if silentForSocket is not None and socket == silentForSocket:
# if we requested silence for Socket and it's this one,
# skip notifications
continue

socket.node.onEdgeConnectionChanged(self)
if socket.isInput:
socket.node.onInputChanged(self)
socket.node.onInputChanged(socket)
except Exception as e:
dumpException(e)

Expand Down
18 changes: 18 additions & 0 deletions nodedge/editor_widget.py
Original file line number Diff line number Diff line change
Expand Up @@ -12,6 +12,7 @@
from PyQt5.QtWidgets import (
QApplication,
QGraphicsItem,
QLabel,
QMessageBox,
QVBoxLayout,
QWidget,
Expand Down Expand Up @@ -274,3 +275,20 @@ def addNodes(self) -> None:
)

self.scene.history.storeInitialStamp()

def addCustomNode(self):
"""Testing method to create a custom Node with custom content"""

class NNodeContent(QLabel):
def __init__(self, parentNode, parent=None):
super().__init__("FooBar")
self.node = parentNode
self.setParent(parent)

class NNode(Node):
NodeContentClass = NNodeContent

self.scene.setNodeClassSelector(lambda data: NNode)
node = NNode(self.scene, "A Custom Node 1", inputSocketTypes=[0, 1, 2])

self.__logger.debug("node content:", node.content)
68 changes: 51 additions & 17 deletions nodedge/editor_window.py
Original file line number Diff line number Diff line change
Expand Up @@ -26,12 +26,16 @@ class EditorWindow(QMainWindow):
"""
:class:`~nodedge.editor_window.EditorWindow` class
The editor window is the base of the multi document interface (MDI) :class:`~nodedge.mdi_window.MdiWindow`.
The editor window is the base of the multi document interface (MDI)
:class:`~nodedge.mdi_window.MdiWindow`.
The application can be opened with the :class:`~nodedge.editor_window.EditorWindow` as main window, even if
it is not the main use case.
The application can be opened with the
:class:`~nodedge.editor_window.EditorWindow` as main window, even if it is not
the main use case.
"""

EditorWidgetClass = EditorWidget

def __init__(self, parent: Optional[QWidget] = None):
"""
:Instance Attributes:
Expand All @@ -43,8 +47,8 @@ def __init__(self, parent: Optional[QWidget] = None):
super().__init__(parent)

logging.basicConfig(
format="%(asctime)s|%(levelname).4s|%(filename)10s|%(lineno).3s|" # type: ignore
"%(message)s|%(funcName)s".format("%Y/%m/%d %H:%M:%S")
format="%(asctime)s|%(levelname).4s|%(filename)10s|" # type: ignore
"%(lineno).3s|%(message)s|%(funcName)s".format("%Y/%m/%d %H:%M:%S")
)

self.__logger = logging.getLogger(__file__)
Expand All @@ -58,8 +62,8 @@ def __init__(self, parent: Optional[QWidget] = None):
)
self.clipboard: QClipboard = self.instance.clipboard()

# Pycharm does not recognise resolve connect method so the inspection is disabled.
# noinspection PyUnresolvedReferences
# Pycharm does not recognise resolve connect method so the inspection is
# disabled. noinspection PyUnresolvedReferences
self.clipboard.dataChanged.connect(self.onClipboardChanged) # type: ignore

self.lastActiveEditorWidget = None
Expand All @@ -73,8 +77,9 @@ def currentEditorWidget(self) -> EditorWidget:
.. note::
The :class:`~nodedge.editor_window.EditorWindow` has only one :class:`~nodedge.editor_widget.EditorWidget`.
This method is overridden by the :class:`~nodedge.mdi_window.MdiWindow` which may have several
The :class:`~nodedge.editor_window.EditorWindow` has only one
:class:`~nodedge.editor_widget.EditorWidget`. This method is overridden
by the :class:`~nodedge.mdi_window.MdiWindow` which may have several
:class:`~nodedge.editor_widget.EditorWidget`.
:rtype: :class:`~nodedge.editor_widget`
Expand All @@ -96,7 +101,7 @@ def initUI(self) -> None:

self.createMenus()

self.editorWidget = EditorWidget()
self.editorWidget = self.__class__.EditorWidgetClass()
self.setCentralWidget(self.editorWidget)
self.editorWidget.scene.addHasBeenModifiedListener(self.updateTitle)

Expand All @@ -112,7 +117,8 @@ def initUI(self) -> None:
# noinspection PyAttributeOutsideInit
def createStatusBar(self) -> None:
"""
Create Status bar and connect to :class:`~nodedge.graphics_view.GraphicsView`'s scenePosChanged event.
Create Status bar and connect to
:class:`~nodedge.graphics_view.GraphicsView`'s scenePosChanged event.
"""
self.statusBar().showMessage("")
self.statusMousePos = QLabel("")
Expand Down Expand Up @@ -275,7 +281,10 @@ def openFile(self, filename):
if self.maybeSave():
if filename is None:
filename, _ = QFileDialog.getOpenFileName(
parent=self, caption="Open graph from file"
parent=self,
caption="Open graph from file",
directory=EditorWindow.getFileDialogDirectory(),
filter=EditorWindow.getFileDialogFilter(),
)

if filename == "":
Expand All @@ -290,7 +299,8 @@ def openFile(self, filename):

def saveFile(self):
"""
Save serialized JSON version of the currently opened file, in a JSON file based on the editor's filename.
Save serialized JSON version of the currently opened file, in a JSON file
based on the editor's filename.
"""
self.__logger.debug("Saving graph")
if not self.currentEditorWidget.hasName:
Expand All @@ -305,12 +315,15 @@ def saveFile(self):

def saveFileAs(self):
"""
Save serialized JSON version of the currently opened file, allowing the user to choose the filename via a
``QFileDialog``.
Save serialized JSON version of the currently opened file, allowing the user
to choose the filename via a ``QFileDialog``.
"""
self.__logger.debug("Saving graph as...")
filename, _ = QFileDialog.getSaveFileName(
parent=self, caption="Save graph to file"
parent=self,
caption="Save graph to file",
directory=EditorWindow.getFileDialogDirectory(),
filter=EditorWindow.getFileDialogFilter(),
)

if filename == "":
Expand Down Expand Up @@ -404,9 +417,30 @@ def paste(self):

self.currentEditorWidget.scene.clipboard.deserialize(data)

@staticmethod
def getFileDialogDirectory() -> str:
"""
Returns starting directory for ``QFileDialog`` file open/save
:return: starting directory for ``QFileDialog`` file open/save
:rtype: ``str``
"""
return ""

@staticmethod
def getFileDialogFilter():
"""
Returns ``str`` standard file open/save filter for ``QFileDialog``
:return: standard file open/save filter for ``QFileDialog``
:rtype: ``str``
"""
return "Graph (*.json);;All files (*)"

def maybeSave(self):
"""
If current :class:`~nodedge.scene.Scene` is modified, ask a dialog to save the changes.
If current :class:`~nodedge.scene.Scene` is modified, ask a dialog to save
the changes.
:return: ``True`` if the action calling this method is allowed to continue.
``False`` if we should cancel operation.
Expand Down
70 changes: 46 additions & 24 deletions nodedge/graphics_node.py
Original file line number Diff line number Diff line change
Expand Up @@ -4,7 +4,7 @@
"""

import logging
from typing import Optional
from typing import Optional, cast

from PyQt5.QtCore import QRectF, Qt
from PyQt5.QtGui import QBrush, QColor, QFont, QPainterPath, QPen
Expand All @@ -14,8 +14,9 @@
QGraphicsSceneMouseEvent,
)

from nodedge.graphics_node_content import GraphicsNodeContentProxy
from nodedge.graphics_node_content import GraphicsNodeContent, GraphicsNodeContentProxy
from nodedge.graphics_node_title_item import GraphicsNodeTitleItem
from nodedge.graphics_scene import GraphicsScene


class GraphicsNode(QGraphicsItem):
Expand All @@ -24,31 +25,34 @@ class GraphicsNode(QGraphicsItem):
The graphics node is the graphical representation of a node.
"""

def __init__(self, node: "Node", parent: Optional[QGraphicsItem] = None) -> None: # type: ignore
def __init__(
self, node: "Node", parent: Optional[QGraphicsItem] = None # type: ignore
) -> None:
"""
:param node: reference to :class:`~nodedge.node.Node`
:type node: :class:`~nodedge.node.Node`
:param parent: parent widget
:type parent: ``Optional[QGraphicsItem]``
"""
super().__init__(parent)
self.node = node
self.content = self.node.content
self.node: "Node" = node # type: ignore

self.__logger = logging.getLogger(__file__)
self.__logger.setLevel(logging.INFO)

self._title: str = "Unnamed"

self.initUI()
self._wasMoved = False
self._lastSelectedState = False
self.hovered = False
self._wasMoved: bool = False
self._lastSelectedState: bool = False
self.hovered: bool = False

@property
def title(self):
"""
Title of this graphical node.
Title of this :class:`~nodedge.graphics_node.GraphicsNode`.
:getter: Return current Graphics Node title
:getter: Return current :class:`~nodedge.graphics_node.GraphicsNode` title
:setter: Store and make visible the new title
:type: ``str``
"""
Expand All @@ -67,6 +71,17 @@ def selectedState(self):
def selectedState(self, value):
self._lastSelectedState = value

@property
def content(self):
"""
:getter: Return reference to
:class:`~nodedge.graphics_node_content.GraphicsNodeContent`
:rtype: :class:`~nodedge.graphics_node_content.GraphicsNodeContent`
"""
return self.node.content if self.node else None

def initUI(self) -> None:
"""
Set up this ``QGraphicsItem``.
Expand Down Expand Up @@ -130,17 +145,21 @@ def initTitle(self) -> None:
# noinspection PyAttributeOutsideInit
def initContent(self) -> None:
"""
Set up the `grContent` - ``QGraphicsProxyWidget`` to have a container for `GraphicsContent`.
Set up the
:class:`~nodedge.graphics_node_content.GraphicsNodeContentProxy`
to have a container for
:class:`~nodedge.graphics_node_content.GraphicsNodeContent`.
"""

self.content.setGeometry(
int(self.edgePadding),
int(self.titleHeight + self.edgePadding),
int(self.width - 2 * self.edgePadding),
int(self.height - 2 * self.edgePadding - self.titleHeight),
)
self.graphicsContentProxy = GraphicsNodeContentProxy(self)
self.graphicsContentProxy.setWidget(self.content)
if self.content is not None:
self.content.setGeometry(
int(self.edgePadding),
int(self.titleHeight + self.edgePadding),
int(self.width - 2 * self.edgePadding),
int(self.height - 2 * self.edgePadding - self.titleHeight),
)
self.graphicsContentProxy = GraphicsNodeContentProxy(self)
self.graphicsContentProxy.setWidget(self.content)

def boundingRect(self):
"""
Expand All @@ -150,7 +169,7 @@ def boundingRect(self):

def paint(self, painter, QStyleOptionGraphicsItem, widget=None):
"""
Paint the rounded rectangular `Node`.
Paint the rounded rectangular :class:`~nodedge.node.Node`.
"""
# title
pathTitle = QPainterPath()
Expand Down Expand Up @@ -216,20 +235,22 @@ def paint(self, painter, QStyleOptionGraphicsItem, widget=None):

def mouseMoveEvent(self, event):
"""
Override Qt's event to detect that we moved this graphical node.
Override Qt's event to detect that we moved this .
"""
super().mouseMoveEvent(event)

# TODO: Optimize this condition. Just update the selected blocks.
for node in self.scene().scene.nodes:
graphicsScene: GraphicsScene = cast(GraphicsScene, self.scene())
for node in graphicsScene.scene.nodes:
if node.graphicsNode.isSelected():
node.updateConnectedEdges()

self._wasMoved = True

def mouseReleaseEvent(self, event):
"""
Handle Qt's event when we move, select or deselect this graphical node.
Handle Qt's event when we move, select or deselect this
:class:`~nodedge.graphics_node.GraphicsNode`.
"""
super().mouseReleaseEvent(event)

Expand Down Expand Up @@ -260,7 +281,8 @@ def mouseReleaseEvent(self, event):
def hoverEnterEvent(self, event: QGraphicsSceneHoverEvent) -> None:
"""
Handle Qt's hover event.
It adds a highlighting boundary around the graphical node.
It adds a highlighting boundary around this
:class:`~nodedge.graphics_node.GraphicsNode`.
"""
self.hovered = True
self.update()
Expand Down

0 comments on commit 02760d7

Please sign in to comment.