프로젝트

일반

사용자정보

통계
| 개정판:

hytos / DTI_PID / DTI_PID / QtImageViewerScene.py @ ebf14a7c

이력 | 보기 | 이력해설 | 다운로드 (14.3 KB)

1
# coding: utf-8
2
""" This is image viewer scene module """
3

    
4
import sys
5
import os.path
6
from SingletonInstance import SingletonInstance
7

    
8
try:
9
    from PyQt5.QtCore import *
10
    from PyQt5.QtGui import *
11
    from PyQt5.QtWidgets import *
12
except ImportError:
13
    try:
14
        from PyQt4.QtCore import *
15
        from PyQt4.QtGui import *
16
    except ImportError:
17
        raise ImportError("ImageViewerQt: Requires PyQt5 or PyQt4.")
18

    
19
__author__ = "humkyung <humkyung.doftech.co.kr>"
20
__version__ = '1.0.0'
21

    
22

    
23
class QtImageViewerScene(QGraphicsScene):
24
    """ This is image viewer scene class """
25
    contents_changed = pyqtSignal()
26

    
27
    def __init__(self, parent):
28
        QGraphicsScene.__init__(self, parent)
29

    
30
        self._undo_stack = QUndoStack(self)
31
        self._delta = QPointF()
32
        self._pressed_keys = set()
33

    
34
        self.contours = []
35
        self.contour_color = None
36
        self.circles = None
37

    
38
        self.guidesEnabled = False
39
        self._guidePen = QPen()
40
        self._guidePen.setColor(QColor(180, 180, 180))
41
        self._guidePen.setStyle(Qt.DashLine)
42
        self._guidePen.setWidthF(0.3)
43

    
44
        self._pressed_position = None
45

    
46
    @property
47
    def undo_stack(self):
48
        return self._undo_stack
49

    
50
    def addItem(self, item):
51
        """add given item to scene"""
52

    
53
        if hasattr(item, 'transfer'):
54
            item.transfer.onRemoved.connect(self.parent().itemRemoved)
55

    
56
        QGraphicsScene.addItem(self, item)
57
        self.contents_changed.emit()
58

    
59
    def removeItem(self, item):
60
        """remove given item from scene"""
61

    
62
        if hasattr(item, 'transfer') and item.transfer.receivers(item.transfer.onRemoved) > 0:
63
            item.transfer.onRemoved.disconnect(self.parent().itemRemoved)
64

    
65
        QGraphicsScene.removeItem(self, item)
66
        self.contents_changed.emit()
67

    
68
    def keyPressEvent(self, event: QKeyEvent):
69
        from SymbolSvgItem import SymbolSvgItem
70
        from EngineeringTextItem import QEngineeringTextItem
71
        from EngineeringLineItem import QEngineeringLineItem
72
        from QEngineeringTrimLineNoTextItem import QEngineeringLineNoTextItem
73
        from EngineeringSpecBreakItem import QEngineeringSpecBreakItem
74
        from EngineeringVendorItem import QEngineeringVendorItem
75
        from DeleteCommand import DeleteCommand
76
        from RotateCommand import RotateCommand
77
        from FlipCommand import FlipCommand
78
        from AppDocData import AppDocData
79

    
80
        try:
81
            #print('scene : ' + str(event.key()))
82
            if event.key() == Qt.Key_Delete or event.key() == Qt.Key_E:
83
                cmd = DeleteCommand(self, [item for item in self.selectedItems() if hasattr(item, 'transfer')])
84
                self._undo_stack.push(cmd)
85
            elif event.key() in [Qt.Key_S, Qt.Key_D, Qt.Key_H]:
86
                if self.selectedItems():
87
                    items = [text for text in self.selectedItems() if type(text) is QEngineeringLineNoTextItem]
88
                    #self._pressed_keys.add(event.key())
89
                    if items:
90
                        for item in items:
91
                            item.keyPressEvent(event)
92

    
93
                    event.accept()
94
                    return
95
            elif event.key() in [Qt.Key_Up, Qt.Key_Down, Qt.Key_Left, Qt.Key_Right, Qt.Key_Return]:
96
                
97
                    items = [text for text in self.selectedItems() if
98
                             issubclass(type(text), QEngineeringTextItem) or issubclass(type(text), SymbolSvgItem) or type(text) == QEngineeringLineItem]
99
                    self._pressed_keys.add(event.key())
100
                    if items:
101
                        for item in items:
102
                            item.keyPressEvent(event)
103

    
104
                    modifiers = QApplication.keyboardModifiers()
105
                    delta = 10 if modifiers == Qt.ControlModifier else 1
106
                    if event.key() == Qt.Key_Up:
107
                        self._delta.setY(self._delta.y() - delta)
108
                    elif event.key() == Qt.Key_Down:
109
                        self._delta.setY(self._delta.y() + delta)
110
                    elif event.key() == Qt.Key_Left:
111
                        self._delta.setX(self._delta.x() - delta)
112
                    elif event.key() == Qt.Key_Right:
113
                        self._delta.setX(self._delta.x() + delta)
114

    
115
                    event.accept()
116
                    return
117
            elif event.key() == Qt.Key_C and event.modifiers() & Qt.ControlModifier:
118
                from xml.etree import ElementTree
119
                import XmlGenerator as xg
120

    
121
                app_doc_data = AppDocData.instance()
122
                xml, result = xg.write_to_xml(app_doc_data.activeDrawing.file_path, app_doc_data.activeDrawing.width,
123
                                              app_doc_data.activeDrawing.height, self.selectedItems(), [])
124
                if xml:
125
                    QApplication.clipboard().setText(ElementTree.tostring(xml, encoding='unicode'))
126
            elif event.key() == Qt.Key_V and event.modifiers() & Qt.ControlModifier:
127
                from App import App
128
                import uuid
129
                from QtImageViewer import QtImageViewer
130
                from TextInfo import TextInfo
131

    
132
                app_doc_data = AppDocData.instance()
133
                clipboard = QApplication.clipboard()
134
                mime_data = clipboard.mimeData()
135
                if mime_data.hasText():
136
                    text = mime_data.text()
137
                    if text.find('<DWG>') != -1 and text.find('</DWG>') != -1:
138
                        from xml.etree import ElementTree
139

    
140
                        origin = self.views()[0].mapFromGlobal(QCursor.pos())
141
                        origin = self.views()[0].mapToScene(origin)
142

    
143
                        delta = None
144
                        root = ElementTree.fromstring(text)
145
                        for symbol in root.find('SYMBOLS').iter('SYMBOL'):
146
                            item = SymbolSvgItem.fromXml(symbol)
147
                            svg = QtImageViewer.createSymbolObject(item.name)
148
                            if not delta:
149
                                delta = origin - QPointF(item.origin[0], item.origin[1])
150

    
151
                            if type(svg) is QEngineeringSpecBreakItem:
152
                                specBreakAttrsFull = [attr for attr in app_doc_data.getSymbolAttribute('Segment Breaks') if attr.AttributeType == 'Spec' or attr.AttributeType == 'String']
153

    
154
                                from_attrs = item.attrs
155
                                to_attrs = svg.getAttributes()
156

    
157
                                for key in from_attrs.keys():
158
                                    if key.Attribute == 'UpStream' or key.Attribute == 'DownStream':
159
                                        continue
160
                                    for full in specBreakAttrsFull:
161
                                        if full.Attribute == key.Attribute:
162
                                            to_attrs[full] = from_attrs[key].copy()
163

    
164
                                if item.prop('Freeze'):
165
                                    svg.set_property('Freeze', True)
166
                                if item.prop('Show'):
167
                                    svg.set_property('Show', True)
168

    
169
                            QtImageViewer.matchSymbolToLine(self, svg, QPointF(item.origin[0], item.origin[1]) + delta, item.angle)
170
                            '''
171
                            # uid 새로 할당
172
                            item.uid = uuid.uuid4()
173
                            for connector in item.connectors:
174
                                connector.connectedItem = None
175
                            item.origin[0], item.origin[1] = origin.x(), origin.y()
176
                            item.transfer.onRemoved.connect(App.mainWnd().itemRemoved)
177
                            item.addSvgItemToScene(self, True)
178
                            item.setVisible(True)
179
                            '''
180
                        for text in root.find('TEXTINFOS').iter('ATTRIBUTE'):
181
                            width = float(text.find('WIDTH').text)
182
                            height = float(text.find('HEIGHT').text)
183
                            angle = float(text.find('ANGLE').text)
184
                            tokens = text.find('LOCATION').text.split(',')
185
                            loc = QPointF(float(tokens[0]), float(tokens[1]))
186
                            if not delta:
187
                                delta = origin - loc
188
                            pos = loc + delta
189
                            textInfo = TextInfo(text.find('VALUE').text, pos.x(), pos.y(), width, height, angle)
190
                            item = QEngineeringTextItem.create_text_with(self, textInfo)
191
                            item.transfer.onRemoved.connect(App.mainWnd().itemRemoved)
192

    
193
                        for node in root.find('LINEINFOS').iter('LINE'):
194
                            startPoint = [float(x) for x in node.find('STARTPOINT').text.split(',')]
195
                            endPoint = [float(x) for x in node.find('ENDPOINT').text.split(',')]
196
                            loc = QPointF(startPoint[0], startPoint[1])
197
                            if not delta:
198
                                delta = origin - loc
199
                            line = QEngineeringLineItem(vertices=[[startPoint[0] + delta.x(), startPoint[1] + delta.y()],
200
                                                                  [endPoint[0] + delta.x(), endPoint[1] + delta.y()]]) #.fromXml(node)
201
                            if line:
202
                                '''lineF = line.line()
203
                                loc = QPointF(lineF.x1(), lineF.y1())
204
                                if not anchor:
205
                                    anchor = loc
206
                                delta = origin - loc - anchor
207
                                lineF.translate(delta)
208
                                line.setLine(lineF)
209
                                line.setVisible(True)'''
210
                                self.addItem(line)
211

    
212
                        for vendor in root.find('VENDORS').iter('VENDOR'):
213
                            _type = vendor.attrib['Type'] if 'Type' in vendor.attrib else 'Vendor Package'
214
                            pointNode = vendor.find('POINT')
215
                            strPoints = pointNode.text
216
                            points = []
217
                            for strPoint in strPoints.split(QEngineeringVendorItem.DELIMITER):
218
                                point = strPoint.split(',')
219
                                points.append(QPoint(float(point[0]), float(point[1])))
220
                            polygon = QPolygonF(points)
221
                            item = QEngineeringVendorItem(polygon, pack_type=_type)
222
                            item.area = vendor.find('AREA').text
223

    
224
                            self.addItem(item)
225

    
226
            elif event.key() == Qt.Key_Z and event.modifiers() & Qt.ControlModifier:
227
                #self._undo_stack.undo()
228
                pass
229
            elif event.key() == Qt.Key_Y and event.modifiers() & Qt.ControlModifier:
230
                #self._undo_stack.redo()
231
                pass
232
            elif self.selectedItems() and event.key() == Qt.Key_R and not(event.modifiers() & Qt.ControlModifier):
233
                self._undo_stack.push(RotateCommand(self, self.selectedItems()))
234
            elif self.selectedItems() and event.key() == Qt.Key_F and not(event.modifiers() & Qt.ControlModifier):
235
                self._undo_stack.push(FlipCommand(self, self.selectedItems()))
236

    
237
            super(QtImageViewerScene, self).keyPressEvent(event)
238
        except Exception as ex:
239
            from App import App
240
            from AppDocData import MessageType
241

    
242
            message = f"error occurred({repr(ex)}) in {sys.exc_info()[-1].tb_frame.f_code.co_filename}:" \
243
                      f"{sys.exc_info()[-1].tb_lineno}"
244
            App.mainWnd().addMessage.emit(MessageType.Error, message)
245

    
246
    def keyReleaseEvent(self, event: QKeyEvent):
247
        from MoveCommand import MoveCommand
248

    
249
        if event.key() in [Qt.Key_Up, Qt.Key_Down, Qt.Key_Left, Qt.Key_Right] and not event.isAutoRepeat():
250
            if self.selectedItems() and not self._delta.isNull():
251
                self._undo_stack.push(MoveCommand(self, QPointF(self._delta)))
252
                self._delta.setX(0)
253
                self._delta.setY(0)
254

    
255
        super(QtImageViewerScene, self).keyReleaseEvent(event)
256

    
257
    def mousePressEvent(self, event: 'QGraphicsSceneMouseEvent') -> None:
258
        if self.selectedItems():
259
            self._pressed_position = event.scenePos()
260
        elif not self.selectedItems() and self.items(event.scenePos()):
261
            self._pressed_position = event.scenePos()
262

    
263
        super(QtImageViewerScene, self).mousePressEvent(event)
264

    
265
    def mouseReleaseEvent(self, event: 'QGraphicsSceneMouseEvent') -> None:
266
        from MoveCommand import MoveCommand
267

    
268
        if self._pressed_position and self._pressed_position != event.scenePos() and self.selectedItems():
269
            self._undo_stack.push(MoveCommand(self, event.scenePos() - self._pressed_position))
270

    
271
        self._pressed_position = None
272
        super(QtImageViewerScene, self).mouseReleaseEvent(event)
273

    
274
    def clear(self):
275
        """clear undo stack"""
276
        self._undo_stack.clear()
277
        super(QtImageViewerScene, self).clear()
278

    
279
    def drawForeground(self, painter: QPainter, rect: QRectF) -> None:
280
        """draw foreground"""
281
        if self.contours:
282
            pen = QPen(Qt.DotLine)
283
            pen.setColor(Qt.red)
284
            pen.setWidthF(2)
285
            painter.setPen(pen)
286
            for contour in self.contours:
287
                path = QPainterPath()
288
                poly = QPolygonF()
289
                for pt in contour:
290
                    poly.append(QPointF(pt[0], pt[1]))
291
                poly.append(poly[0])
292
                path.addPolygon(poly)
293
                painter.fillPath(path, QBrush(Qt.darkRed if self.contour_color is None else self.contour_color,
294
                                              Qt.SolidPattern))
295

    
296
        if self.circles:
297
            for circle in self.circles:
298
                painter.drawEllipse(circle[0], circle[1], circle[2], circle[2])
299
                pass
300

    
301
        """draw guid line"""
302
        if hasattr(self, 'coords') and self.guidesEnabled:
303
            painter.setClipRect(rect)
304
            painter.setPen(self._guidePen)
305
            painter.drawLine(round(self.coords.x()), round(rect.top()), round(self.coords.x()), round(rect.bottom()))
306
            painter.drawLine(round(rect.left()), round(self.coords.y()), round(rect.right()), round(self.coords.y()))
클립보드 이미지 추가 (최대 크기: 500 MB)