| Total Complexity | 95 |
| Total Lines | 528 |
| Duplicated Lines | 0 % |
Complex classes like Orange.canvas.canvas.items.NodeItem often do a lot of different things. To break such a class down, we need to identify a cohesive component within that class. A common approach to find such a component is to look for fields/methods that share the same prefixes, or suffixes.
Once you have determined the fields that belong together, you can apply the Extract Class refactoring. If the component makes sense as a sub-class, Extract Subclass is also a candidate, and is often faster.
| 1 | """ |
||
| 773 | class NodeItem(QGraphicsObject): |
||
| 774 | """ |
||
| 775 | An widget node item in the canvas. |
||
| 776 | """ |
||
| 777 | |||
| 778 | #: Signal emitted when the scene position of the node has changed. |
||
| 779 | positionChanged = Signal() |
||
| 780 | |||
| 781 | #: Signal emitted when the geometry of the channel anchors changes. |
||
| 782 | anchorGeometryChanged = Signal() |
||
| 783 | |||
| 784 | #: Signal emitted when the item has been activated (by a mouse double |
||
| 785 | #: click or a keyboard) |
||
| 786 | activated = Signal() |
||
| 787 | |||
| 788 | #: The item is under the mouse. |
||
| 789 | hovered = Signal() |
||
| 790 | |||
| 791 | #: Span of the anchor in degrees |
||
| 792 | ANCHOR_SPAN_ANGLE = 90 |
||
| 793 | |||
| 794 | #: Z value of the item |
||
| 795 | Z_VALUE = 100 |
||
| 796 | |||
| 797 | def __init__(self, widget_description=None, parent=None, **kwargs): |
||
| 798 | self.__boundingRect = None |
||
| 799 | QGraphicsObject.__init__(self, parent, **kwargs) |
||
| 800 | self.setFlag(QGraphicsItem.ItemSendsGeometryChanges, True) |
||
| 801 | self.setFlag(QGraphicsItem.ItemHasNoContents, True) |
||
| 802 | self.setFlag(QGraphicsItem.ItemIsSelectable, True) |
||
| 803 | self.setFlag(QGraphicsItem.ItemIsMovable, True) |
||
| 804 | self.setFlag(QGraphicsItem.ItemIsFocusable, True) |
||
| 805 | |||
| 806 | # central body shape item |
||
| 807 | self.shapeItem = None |
||
| 808 | |||
| 809 | # in/output anchor items |
||
| 810 | self.inputAnchorItem = None |
||
| 811 | self.outputAnchorItem = None |
||
| 812 | |||
| 813 | # title text item |
||
| 814 | self.captionTextItem = None |
||
| 815 | |||
| 816 | # error, warning, info items |
||
| 817 | self.errorItem = None |
||
| 818 | self.warningItem = None |
||
| 819 | self.infoItem = None |
||
| 820 | |||
| 821 | self.__title = "" |
||
| 822 | self.__processingState = 0 |
||
| 823 | self.__progress = -1 |
||
| 824 | self.__statusMessage = "" |
||
| 825 | |||
| 826 | self.__error = None |
||
| 827 | self.__warning = None |
||
| 828 | self.__info = None |
||
| 829 | |||
| 830 | self.__anchorLayout = None |
||
| 831 | self.__animationEnabled = False |
||
| 832 | |||
| 833 | self.setZValue(self.Z_VALUE) |
||
| 834 | self.setupGraphics() |
||
| 835 | |||
| 836 | self.setWidgetDescription(widget_description) |
||
| 837 | |||
| 838 | @classmethod |
||
| 839 | def from_node(cls, node): |
||
| 840 | """ |
||
| 841 | Create an :class:`NodeItem` instance and initialize it from a |
||
| 842 | :class:`SchemeNode` instance. |
||
| 843 | |||
| 844 | """ |
||
| 845 | self = cls() |
||
| 846 | self.setWidgetDescription(node.description) |
||
| 847 | # self.setCategoryDescription(node.category) |
||
| 848 | return self |
||
| 849 | |||
| 850 | @classmethod |
||
| 851 | def from_node_meta(cls, meta_description): |
||
| 852 | """ |
||
| 853 | Create an `NodeItem` instance from a node meta description. |
||
| 854 | """ |
||
| 855 | self = cls() |
||
| 856 | self.setWidgetDescription(meta_description) |
||
| 857 | return self |
||
| 858 | |||
| 859 | def setupGraphics(self): |
||
| 860 | """ |
||
| 861 | Set up the graphics. |
||
| 862 | """ |
||
| 863 | shape_rect = QRectF(-24, -24, 48, 48) |
||
| 864 | |||
| 865 | self.shapeItem = NodeBodyItem(self) |
||
| 866 | self.shapeItem.setShapeRect(shape_rect) |
||
| 867 | self.shapeItem.setAnimationEnabled(self.__animationEnabled) |
||
| 868 | |||
| 869 | # Rect for widget's 'ears'. |
||
| 870 | anchor_rect = QRectF(-31, -31, 62, 62) |
||
| 871 | self.inputAnchorItem = SinkAnchorItem(self) |
||
| 872 | input_path = QPainterPath() |
||
| 873 | start_angle = 180 - self.ANCHOR_SPAN_ANGLE / 2 |
||
| 874 | input_path.arcMoveTo(anchor_rect, start_angle) |
||
| 875 | input_path.arcTo(anchor_rect, start_angle, self.ANCHOR_SPAN_ANGLE) |
||
| 876 | self.inputAnchorItem.setAnchorPath(input_path) |
||
| 877 | |||
| 878 | self.outputAnchorItem = SourceAnchorItem(self) |
||
| 879 | output_path = QPainterPath() |
||
| 880 | start_angle = self.ANCHOR_SPAN_ANGLE / 2 |
||
| 881 | output_path.arcMoveTo(anchor_rect, start_angle) |
||
| 882 | output_path.arcTo(anchor_rect, start_angle, - self.ANCHOR_SPAN_ANGLE) |
||
| 883 | self.outputAnchorItem.setAnchorPath(output_path) |
||
| 884 | |||
| 885 | self.inputAnchorItem.hide() |
||
| 886 | self.outputAnchorItem.hide() |
||
| 887 | |||
| 888 | # Title caption item |
||
| 889 | self.captionTextItem = NameTextItem(self) |
||
| 890 | |||
| 891 | self.captionTextItem.setPlainText("") |
||
| 892 | self.captionTextItem.setPos(0, 33) |
||
| 893 | |||
| 894 | def iconItem(standard_pixmap): |
||
| 895 | item = GraphicsIconItem(self, icon=standard_icon(standard_pixmap), |
||
| 896 | iconSize=QSize(16, 16)) |
||
| 897 | item.hide() |
||
| 898 | return item |
||
| 899 | |||
| 900 | self.errorItem = iconItem(QStyle.SP_MessageBoxCritical) |
||
| 901 | self.warningItem = iconItem(QStyle.SP_MessageBoxWarning) |
||
| 902 | self.infoItem = iconItem(QStyle.SP_MessageBoxInformation) |
||
| 903 | |||
| 904 | self.prepareGeometryChange() |
||
| 905 | self.__boundingRect = None |
||
| 906 | |||
| 907 | # TODO: Remove the set[Widget|Category]Description. The user should |
||
| 908 | # handle setting of icons, title, ... |
||
| 909 | def setWidgetDescription(self, desc): |
||
| 910 | """ |
||
| 911 | Set widget description. |
||
| 912 | """ |
||
| 913 | self.widget_description = desc |
||
| 914 | if desc is None: |
||
| 915 | return |
||
| 916 | |||
| 917 | icon = icon_loader.from_description(desc).get(desc.icon) |
||
| 918 | if icon: |
||
| 919 | self.setIcon(icon) |
||
| 920 | |||
| 921 | if not self.title(): |
||
| 922 | self.setTitle(desc.name) |
||
| 923 | |||
| 924 | if desc.inputs: |
||
| 925 | self.inputAnchorItem.show() |
||
| 926 | if desc.outputs: |
||
| 927 | self.outputAnchorItem.show() |
||
| 928 | |||
| 929 | tooltip = NodeItem_toolTipHelper(self) |
||
| 930 | self.setToolTip(tooltip) |
||
| 931 | |||
| 932 | def setWidgetCategory(self, desc): |
||
| 933 | """ |
||
| 934 | Set the widget category. |
||
| 935 | """ |
||
| 936 | self.category_description = desc |
||
| 937 | if desc and desc.background: |
||
| 938 | background = NAMED_COLORS.get(desc.background, desc.background) |
||
| 939 | color = QColor(background) |
||
| 940 | if color.isValid(): |
||
| 941 | self.setColor(color) |
||
| 942 | |||
| 943 | def setIcon(self, icon): |
||
| 944 | """ |
||
| 945 | Set the node item's icon (:class:`QIcon`). |
||
| 946 | """ |
||
| 947 | if isinstance(icon, QIcon): |
||
| 948 | self.icon_item = GraphicsIconItem(self.shapeItem, icon=icon, |
||
| 949 | iconSize=QSize(36, 36)) |
||
| 950 | self.icon_item.setPos(-18, -18) |
||
| 951 | else: |
||
| 952 | raise TypeError |
||
| 953 | |||
| 954 | def setColor(self, color, selectedColor=None): |
||
| 955 | """ |
||
| 956 | Set the widget color. |
||
| 957 | """ |
||
| 958 | if selectedColor is None: |
||
| 959 | selectedColor = saturated(color, 150) |
||
| 960 | palette = create_palette(color, selectedColor) |
||
| 961 | self.shapeItem.setPalette(palette) |
||
| 962 | |||
| 963 | def setPalette(self, palette): |
||
| 964 | # TODO: The palette should override the `setColor` |
||
| 965 | raise NotImplementedError |
||
| 966 | |||
| 967 | def setTitle(self, title): |
||
| 968 | """ |
||
| 969 | Set the node title. The title text is displayed at the bottom of the |
||
| 970 | node. |
||
| 971 | |||
| 972 | """ |
||
| 973 | self.__title = title |
||
| 974 | self.__updateTitleText() |
||
| 975 | |||
| 976 | def title(self): |
||
| 977 | """ |
||
| 978 | Return the node title. |
||
| 979 | """ |
||
| 980 | return self.__title |
||
| 981 | |||
| 982 | title_ = Property(str, fget=title, fset=setTitle, |
||
| 983 | doc="Node title text.") |
||
| 984 | |||
| 985 | def setFont(self, font): |
||
| 986 | """ |
||
| 987 | Set the title text font (:class:`QFont`). |
||
| 988 | """ |
||
| 989 | if font != self.font(): |
||
| 990 | self.prepareGeometryChange() |
||
| 991 | self.captionTextItem.setFont(font) |
||
| 992 | self.__updateTitleText() |
||
| 993 | |||
| 994 | def font(self): |
||
| 995 | """ |
||
| 996 | Return the title text font. |
||
| 997 | """ |
||
| 998 | return self.captionTextItem.font() |
||
| 999 | |||
| 1000 | def setAnimationEnabled(self, enabled): |
||
| 1001 | """ |
||
| 1002 | Set the node animation enabled state. |
||
| 1003 | """ |
||
| 1004 | if self.__animationEnabled != enabled: |
||
| 1005 | self.__animationEnabled = enabled |
||
| 1006 | self.shapeItem.setAnimationEnabled(enabled) |
||
| 1007 | |||
| 1008 | def animationEnabled(self): |
||
| 1009 | """ |
||
| 1010 | Are node animations enabled. |
||
| 1011 | """ |
||
| 1012 | return self.__animationEnabled |
||
| 1013 | |||
| 1014 | def setProcessingState(self, state): |
||
| 1015 | """ |
||
| 1016 | Set the node processing state i.e. the node is processing |
||
| 1017 | (is busy) or is idle. |
||
| 1018 | |||
| 1019 | """ |
||
| 1020 | if self.__processingState != state: |
||
| 1021 | self.__processingState = state |
||
| 1022 | self.shapeItem.setProcessingState(state) |
||
| 1023 | if not state: |
||
| 1024 | # Clear the progress meter. |
||
| 1025 | self.setProgress(-1) |
||
| 1026 | if self.__animationEnabled: |
||
| 1027 | self.shapeItem.ping() |
||
| 1028 | |||
| 1029 | def processingState(self): |
||
| 1030 | """ |
||
| 1031 | The node processing state. |
||
| 1032 | """ |
||
| 1033 | return self.__processingState |
||
| 1034 | |||
| 1035 | processingState_ = Property(int, fget=processingState, |
||
| 1036 | fset=setProcessingState) |
||
| 1037 | |||
| 1038 | def setProgress(self, progress): |
||
| 1039 | """ |
||
| 1040 | Set the node work progress state (number between 0 and 100). |
||
| 1041 | """ |
||
| 1042 | if progress is None or progress < 0 or not self.__processingState: |
||
| 1043 | progress = -1 |
||
| 1044 | |||
| 1045 | progress = max(min(progress, 100), -1) |
||
| 1046 | if self.__progress != progress: |
||
| 1047 | self.__progress = progress |
||
| 1048 | self.shapeItem.setProgress(progress) |
||
| 1049 | self.__updateTitleText() |
||
| 1050 | |||
| 1051 | def progress(self): |
||
| 1052 | """ |
||
| 1053 | Return the node work progress state. |
||
| 1054 | """ |
||
| 1055 | return self.__progress |
||
| 1056 | |||
| 1057 | progress_ = Property(float, fget=progress, fset=setProgress, |
||
| 1058 | doc="Node progress state.") |
||
| 1059 | |||
| 1060 | def setStatusMessage(self, message): |
||
| 1061 | """ |
||
| 1062 | Set the node status message text. |
||
| 1063 | |||
| 1064 | This text is displayed below the node's title. |
||
| 1065 | |||
| 1066 | """ |
||
| 1067 | if self.__statusMessage != message: |
||
| 1068 | self.__statusMessage = message |
||
| 1069 | self.__updateTitleText() |
||
| 1070 | |||
| 1071 | def statusMessage(self): |
||
| 1072 | return self.__statusMessage |
||
| 1073 | |||
| 1074 | def setStateMessage(self, message): |
||
| 1075 | """ |
||
| 1076 | Set a state message to display over the item. |
||
| 1077 | |||
| 1078 | Parameters |
||
| 1079 | ---------- |
||
| 1080 | message : UserMessage |
||
| 1081 | Message to display. `message.severity` is used to determine |
||
| 1082 | the icon and `message.contents` is used as a tool tip. |
||
| 1083 | |||
| 1084 | """ |
||
| 1085 | # TODO: Group messages by message_id not by severity |
||
| 1086 | # and deprecate set[Error|Warning|Error]Message |
||
| 1087 | if message.severity == UserMessage.Info: |
||
| 1088 | self.setInfoMessage(message.contents) |
||
| 1089 | elif message.severity == UserMessage.Warning: |
||
| 1090 | self.setWarningMessage(message.contents) |
||
| 1091 | elif message.severity == UserMessage.Error: |
||
| 1092 | self.setErrorMessage(message.contents) |
||
| 1093 | |||
| 1094 | def setErrorMessage(self, message): |
||
| 1095 | if self.__error != message: |
||
| 1096 | self.__error = message |
||
| 1097 | self.__updateMessages() |
||
| 1098 | |||
| 1099 | def setWarningMessage(self, message): |
||
| 1100 | if self.__warning != message: |
||
| 1101 | self.__warning = message |
||
| 1102 | self.__updateMessages() |
||
| 1103 | |||
| 1104 | def setInfoMessage(self, message): |
||
| 1105 | if self.__info != message: |
||
| 1106 | self.__info = message |
||
| 1107 | self.__updateMessages() |
||
| 1108 | |||
| 1109 | def newInputAnchor(self): |
||
| 1110 | """ |
||
| 1111 | Create and return a new input :class:`AnchorPoint`. |
||
| 1112 | """ |
||
| 1113 | if not (self.widget_description and self.widget_description.inputs): |
||
| 1114 | raise ValueError("Widget has no inputs.") |
||
| 1115 | |||
| 1116 | anchor = AnchorPoint() |
||
| 1117 | self.inputAnchorItem.addAnchor(anchor, position=1.0) |
||
| 1118 | |||
| 1119 | positions = self.inputAnchorItem.anchorPositions() |
||
| 1120 | positions = uniform_linear_layout(positions) |
||
| 1121 | self.inputAnchorItem.setAnchorPositions(positions) |
||
| 1122 | |||
| 1123 | return anchor |
||
| 1124 | |||
| 1125 | def removeInputAnchor(self, anchor): |
||
| 1126 | """ |
||
| 1127 | Remove input anchor. |
||
| 1128 | """ |
||
| 1129 | self.inputAnchorItem.removeAnchor(anchor) |
||
| 1130 | |||
| 1131 | positions = self.inputAnchorItem.anchorPositions() |
||
| 1132 | positions = uniform_linear_layout(positions) |
||
| 1133 | self.inputAnchorItem.setAnchorPositions(positions) |
||
| 1134 | |||
| 1135 | def newOutputAnchor(self): |
||
| 1136 | """ |
||
| 1137 | Create and return a new output :class:`AnchorPoint`. |
||
| 1138 | """ |
||
| 1139 | if not (self.widget_description and self.widget_description.outputs): |
||
| 1140 | raise ValueError("Widget has no outputs.") |
||
| 1141 | |||
| 1142 | anchor = AnchorPoint(self) |
||
| 1143 | self.outputAnchorItem.addAnchor(anchor, position=1.0) |
||
| 1144 | |||
| 1145 | positions = self.outputAnchorItem.anchorPositions() |
||
| 1146 | positions = uniform_linear_layout(positions) |
||
| 1147 | self.outputAnchorItem.setAnchorPositions(positions) |
||
| 1148 | |||
| 1149 | return anchor |
||
| 1150 | |||
| 1151 | def removeOutputAnchor(self, anchor): |
||
| 1152 | """ |
||
| 1153 | Remove output anchor. |
||
| 1154 | """ |
||
| 1155 | self.outputAnchorItem.removeAnchor(anchor) |
||
| 1156 | |||
| 1157 | positions = self.outputAnchorItem.anchorPositions() |
||
| 1158 | positions = uniform_linear_layout(positions) |
||
| 1159 | self.outputAnchorItem.setAnchorPositions(positions) |
||
| 1160 | |||
| 1161 | def inputAnchors(self): |
||
| 1162 | """ |
||
| 1163 | Return a list of all input anchor points. |
||
| 1164 | """ |
||
| 1165 | return self.inputAnchorItem.anchorPoints() |
||
| 1166 | |||
| 1167 | def outputAnchors(self): |
||
| 1168 | """ |
||
| 1169 | Return a list of all output anchor points. |
||
| 1170 | """ |
||
| 1171 | return self.outputAnchorItem.anchorPoints() |
||
| 1172 | |||
| 1173 | def setAnchorRotation(self, angle): |
||
| 1174 | """ |
||
| 1175 | Set the anchor rotation. |
||
| 1176 | """ |
||
| 1177 | self.inputAnchorItem.setRotation(angle) |
||
| 1178 | self.outputAnchorItem.setRotation(angle) |
||
| 1179 | self.anchorGeometryChanged.emit() |
||
| 1180 | |||
| 1181 | def anchorRotation(self): |
||
| 1182 | """ |
||
| 1183 | Return the anchor rotation. |
||
| 1184 | """ |
||
| 1185 | return self.inputAnchorItem.rotation() |
||
| 1186 | |||
| 1187 | def boundingRect(self): |
||
| 1188 | # TODO: Important because of this any time the child |
||
| 1189 | # items change geometry the self.prepareGeometryChange() |
||
| 1190 | # needs to be called. |
||
| 1191 | if self.__boundingRect is None: |
||
| 1192 | self.__boundingRect = self.childrenBoundingRect() |
||
| 1193 | return self.__boundingRect |
||
| 1194 | |||
| 1195 | def shape(self): |
||
| 1196 | # Shape for mouse hit detection. |
||
| 1197 | # TODO: Should this return the union of all child items? |
||
| 1198 | return self.shapeItem.shape() |
||
| 1199 | |||
| 1200 | def __updateTitleText(self): |
||
| 1201 | """ |
||
| 1202 | Update the title text item. |
||
| 1203 | """ |
||
| 1204 | text = ['<div align="center">%s' % escape(self.title())] |
||
| 1205 | |||
| 1206 | status_text = [] |
||
| 1207 | |||
| 1208 | progress_included = False |
||
| 1209 | if self.__statusMessage: |
||
| 1210 | msg = escape(self.__statusMessage) |
||
| 1211 | format_fields = dict(parse_format_fields(msg)) |
||
| 1212 | if "progress" in format_fields and len(format_fields) == 1: |
||
| 1213 | # Insert progress into the status text format string. |
||
| 1214 | spec, _ = format_fields["progress"] |
||
| 1215 | if spec != None: |
||
| 1216 | progress_included = True |
||
| 1217 | progress_str = "{0:.0f}%".format(self.progress()) |
||
| 1218 | status_text.append(msg.format(progress=progress_str)) |
||
| 1219 | else: |
||
| 1220 | status_text.append(msg) |
||
| 1221 | |||
| 1222 | if self.progress() >= 0 and not progress_included: |
||
| 1223 | status_text.append("%i%%" % int(self.progress())) |
||
| 1224 | |||
| 1225 | if status_text: |
||
| 1226 | text += ["<br/>", |
||
| 1227 | '<span style="font-style: italic">', |
||
| 1228 | "<br/>".join(status_text), |
||
| 1229 | "</span>"] |
||
| 1230 | text += ["</div>"] |
||
| 1231 | text = "".join(text) |
||
| 1232 | |||
| 1233 | # The NodeItems boundingRect could change. |
||
| 1234 | self.prepareGeometryChange() |
||
| 1235 | self.__boundingRect = None |
||
| 1236 | self.captionTextItem.setHtml(text) |
||
| 1237 | self.captionTextItem.document().adjustSize() |
||
| 1238 | width = self.captionTextItem.textWidth() |
||
| 1239 | self.captionTextItem.setPos(-width / 2.0, 33) |
||
| 1240 | |||
| 1241 | def __updateMessages(self): |
||
| 1242 | """ |
||
| 1243 | Update message items (position, visibility and tool tips). |
||
| 1244 | """ |
||
| 1245 | items = [self.errorItem, self.warningItem, self.infoItem] |
||
| 1246 | |||
| 1247 | messages = [self.__error, self.__warning, self.__info] |
||
| 1248 | for message, item in zip(messages, items): |
||
| 1249 | item.setVisible(bool(message)) |
||
| 1250 | item.setToolTip(message or "") |
||
| 1251 | |||
| 1252 | shown = [item for item in items if item.isVisible()] |
||
| 1253 | count = len(shown) |
||
| 1254 | if count: |
||
| 1255 | spacing = 3 |
||
| 1256 | rects = [item.boundingRect() for item in shown] |
||
| 1257 | width = sum(rect.width() for rect in rects) |
||
| 1258 | width += spacing * max(0, count - 1) |
||
| 1259 | height = max(rect.height() for rect in rects) |
||
| 1260 | origin = self.shapeItem.boundingRect().top() - spacing - height |
||
| 1261 | origin = QPointF(-width / 2, origin) |
||
| 1262 | for item, rect in zip(shown, rects): |
||
| 1263 | item.setPos(origin) |
||
| 1264 | origin = origin + QPointF(rect.width() + spacing, 0) |
||
| 1265 | |||
| 1266 | def mousePressEvent(self, event): |
||
| 1267 | if self.shapeItem.path().contains(event.pos()): |
||
| 1268 | return QGraphicsObject.mousePressEvent(self, event) |
||
| 1269 | else: |
||
| 1270 | event.ignore() |
||
| 1271 | |||
| 1272 | def mouseDoubleClickEvent(self, event): |
||
| 1273 | if self.shapeItem.path().contains(event.pos()): |
||
| 1274 | QGraphicsObject.mouseDoubleClickEvent(self, event) |
||
| 1275 | QTimer.singleShot(0, self.activated.emit) |
||
| 1276 | else: |
||
| 1277 | event.ignore() |
||
| 1278 | |||
| 1279 | def contextMenuEvent(self, event): |
||
| 1280 | if self.shapeItem.path().contains(event.pos()): |
||
| 1281 | return QGraphicsObject.contextMenuEvent(self, event) |
||
| 1282 | else: |
||
| 1283 | event.ignore() |
||
| 1284 | |||
| 1285 | def focusInEvent(self, event): |
||
| 1286 | self.shapeItem.setHasFocus(True) |
||
| 1287 | return QGraphicsObject.focusInEvent(self, event) |
||
| 1288 | |||
| 1289 | def focusOutEvent(self, event): |
||
| 1290 | self.shapeItem.setHasFocus(False) |
||
| 1291 | return QGraphicsObject.focusOutEvent(self, event) |
||
| 1292 | |||
| 1293 | def itemChange(self, change, value): |
||
| 1294 | if change == QGraphicsItem.ItemSelectedChange: |
||
| 1295 | self.shapeItem.setSelected(value) |
||
| 1296 | self.captionTextItem.setSelectionState(value) |
||
| 1297 | elif change == QGraphicsItem.ItemPositionHasChanged: |
||
| 1298 | self.positionChanged.emit() |
||
| 1299 | |||
| 1300 | return QGraphicsObject.itemChange(self, change, value) |
||
| 1301 | |||
| 1362 |