Skip to content

Commit 8989b6b

Browse files
committed
Right-click on a link to insert a widget
1 parent 60b153f commit 8989b6b

File tree

2 files changed

+98
-3
lines changed

2 files changed

+98
-3
lines changed

Orange/canvas/document/commands.py

Lines changed: 34 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -6,6 +6,8 @@
66

77
from AnyQt.QtWidgets import QUndoCommand
88

9+
from Orange.canvas.scheme import SchemeLink
10+
911

1012
class AddNodeCommand(QUndoCommand):
1113
def __init__(self, scheme, node, parent=None):
@@ -69,6 +71,38 @@ def undo(self):
6971
self.scheme.add_link(self.link)
7072

7173

74+
class InsertNodeCommand(QUndoCommand):
75+
def __init__(self, scheme, link, new_node, parent=None):
76+
QUndoCommand.__init__(self, "Remove link", parent)
77+
self.scheme = scheme
78+
self.original_link = link
79+
self.inserted_widget = new_node
80+
81+
possible_links = (self.scheme.propose_links(link.source_node, new_node),
82+
self.scheme.propose_links(new_node, link.sink_node))
83+
84+
if not possible_links[0] or not possible_links[1]:
85+
raise ValueError("Cannot insert widget: links not possible")
86+
87+
self.new_links = (
88+
SchemeLink(link.source_node, link.source_channel,
89+
new_node, possible_links[0][0][1]), # first link, first entry, output (1)
90+
SchemeLink(new_node, possible_links[1][0][0], # second link, first entry, input (0)
91+
link.sink_node, link.sink_channel))
92+
93+
def redo(self):
94+
self.scheme.add_node(self.inserted_widget)
95+
self.scheme.remove_link(self.original_link)
96+
self.scheme.add_link(self.new_links[0])
97+
self.scheme.add_link(self.new_links[1])
98+
99+
def undo(self):
100+
self.scheme.remove_link(self.new_links[0])
101+
self.scheme.remove_link(self.new_links[1])
102+
self.scheme.add_link(self.original_link)
103+
self.scheme.remove_node(self.inserted_widget)
104+
105+
72106
class AddAnnotationCommand(QUndoCommand):
73107
def __init__(self, scheme, annotation, parent=None):
74108
QUndoCommand.__init__(self, "Add annotation", parent)

Orange/canvas/document/schemeedit.py

Lines changed: 64 additions & 3 deletions
Original file line numberDiff line numberDiff line change
@@ -29,13 +29,14 @@
2929
)
3030

3131
from AnyQt.QtCore import (
32-
Qt, QObject, QEvent, QSignalMapper, QRectF, QCoreApplication
33-
)
32+
Qt, QObject, QEvent, QSignalMapper, QRectF, QCoreApplication,
33+
QPoint)
3434

3535
from AnyQt.QtCore import pyqtProperty as Property, pyqtSignal as Signal
3636

37+
from Orange.canvas.registry import WidgetDescription
3738
from .suggestions import Suggestions
38-
from ..registry.qt import whats_this_helper
39+
from ..registry.qt import whats_this_helper, QtWidgetRegistry
3940
from ..gui.quickhelp import QuickHelpTipEvent
4041
from ..gui.utils import message_information, disabled
4142
from ..scheme import (
@@ -171,6 +172,8 @@ def __init__(self, parent=None, ):
171172
self.__linkMenu = QMenu(self.tr("Link"), self)
172173
self.__linkMenu.addAction(self.__linkEnableAction)
173174
self.__linkMenu.addSeparator()
175+
self.__linkMenu.addAction(self.__nodeInsertAction)
176+
self.__linkMenu.addSeparator()
174177
self.__linkMenu.addAction(self.__linkRemoveAction)
175178
self.__linkMenu.addAction(self.__linkResetAction)
176179

@@ -328,6 +331,13 @@ def color_icon(color):
328331
toolTip=self.tr("Remove link."),
329332
)
330333

334+
self.__nodeInsertAction = \
335+
QAction(self.tr("Insert Widget"), self,
336+
objectName="node-insert-action",
337+
triggered=self.__nodeInsert,
338+
toolTip=self.tr("Insert widget."),
339+
)
340+
331341
self.__linkResetAction = \
332342
QAction(self.tr("Reset Signals"), self,
333343
objectName="link-reset-action",
@@ -346,6 +356,7 @@ def color_icon(color):
346356
self.__newArrowAnnotationAction,
347357
self.__linkEnableAction,
348358
self.__linkRemoveAction,
359+
self.__nodeInsertAction,
349360
self.__linkResetAction,
350361
self.__duplicateSelectedAction])
351362

@@ -867,6 +878,10 @@ def removeLink(self, link):
867878
command = commands.RemoveLinkCommand(self.__scheme, link)
868879
self.__undoStack.push(command)
869880

881+
def insertNode(self, link, new_node):
882+
command = commands.InsertNodeCommand(self.__scheme, link, new_node)
883+
self.__undoStack.push(command)
884+
870885
def onNewLink(self, func):
871886
"""
872887
Runs function when new link is added to current scheme.
@@ -1594,6 +1609,52 @@ def __linkReset(self):
15941609
)
15951610
action.edit_links()
15961611

1612+
def __nodeInsert(self):
1613+
"""
1614+
Node insert was requested from the context menu.
1615+
"""
1616+
if not self.__contextMenuTarget:
1617+
return
1618+
1619+
original_link = self.__contextMenuTarget
1620+
source_node = original_link.source_node
1621+
sink_node = original_link.sink_node
1622+
1623+
def is_compatible(source, sink):
1624+
return any(scheme.compatible_channels(output, input) \
1625+
for output in source.outputs \
1626+
for input in sink.inputs)
1627+
1628+
def filterFunc(index):
1629+
new_node_desc = index.data(QtWidgetRegistry.WIDGET_DESC_ROLE)
1630+
if isinstance(new_node_desc, WidgetDescription):
1631+
return is_compatible(source_node.description, new_node_desc) and\
1632+
is_compatible(new_node_desc, sink_node.description)
1633+
else:
1634+
return False
1635+
1636+
x = (source_node.position[0] + sink_node.position[0]) / 2
1637+
y = (source_node.position[1] + sink_node.position[1]) / 2
1638+
1639+
menu = self.quickMenu()
1640+
menu.setFilterFunc(filterFunc)
1641+
menu.setSortingFunc(None)
1642+
1643+
view = self.view()
1644+
try:
1645+
action = menu.exec_(view.mapToGlobal(view.mapFromScene(QPoint(x, y))))
1646+
finally:
1647+
menu.setFilterFunc(None)
1648+
1649+
if action:
1650+
item = action.property("item")
1651+
desc = item.data(QtWidgetRegistry.WIDGET_DESC_ROLE)
1652+
new_node = self.newNodeHelper(desc, position=(x, y))
1653+
else:
1654+
return
1655+
1656+
self.insertNode(original_link, new_node)
1657+
15971658
def __duplicateSelected(self):
15981659
"""
15991660
Duplicate currently selected nodes.

0 commit comments

Comments
 (0)