프로젝트

일반

사용자정보

통계
| 브랜치(Branch): | 개정판:

hytos / DTI_PID / DTI_PID / Shapes / SymbolSvgItem.py @ df4661c5

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

1 0f777efa humkyung
#!/usr/bin/env/python3
2
# coding: utf-8
3
4
import sys
5
import os
6 0f4a186f humkyung
import math
7 0f777efa humkyung
from PyQt5.QtGui import *
8
from PyQt5.QtCore import *
9
from PyQt5.QtSvg import *
10 3a4cc147 humkyung
from PyQt5.QtWidgets import (QApplication, QGraphicsItem)
11 3216847d humkyung
from PyQt5.QtXml import *
12 0f777efa humkyung
13 90bc60db humkyung
from AppDocData import *
14 57ab567c humkyung
from EngineeringConnectorItem import QEngineeringConnectorItem
15 3d6ff047 humkyung
from EngineeringAbstractItem import QEngineeringAbstractItem
16 f21800ed humkyung
from EngineeringConnectorItem import QEngineeringConnectorItem
17 357646b0 gaqhf
from UserInputAttribute import UserInputAttribute
18 ac10260c gaqhf
import SelectAttributeCommand
19 2885ca96 gaqhf
20 ce9281d7 humkyung
class SymbolSvgItem(QGraphicsSvgItem, QEngineeringAbstractItem):
21 df4661c5 humkyung
    """ This is symbolsvgitem class """
22
23 18a0281b 김정우
    clicked = pyqtSignal(QGraphicsSvgItem)
24 ed948580 humkyung
    ZVALUE = 50
25 3ebd61eb humkyung
    HOVER_COLOR = 'url(#hover)'
26 18a0281b 김정우
27 0bcf00da 김정우
    '''
28 18a0281b 김정우
        @history    18.04.11    Jeongwoo    Add Variable (Name, Type)
29 d1576bff 김정우
                    18.05.11    Jeongwoo    Declare variable self.color
30 93ed7203 김정우
                    18.05.25    Jeongwoo    Call setColor() method
31 34f2b549 김정우
                    18.05.30    Jeongwoo    Add self variables (parentSymbol, childSymbol)
32 0bcf00da 김정우
    '''
33 190a20fb esham21
    def __init__(self, path, uid=None, flip=0):
34 6fb1a52e humkyung
        import uuid
35 a208ed03 humkyung
        from SymbolAttr import SymbolProp
36 6fb1a52e humkyung
37 c9c0b30b humkyung
        QGraphicsSvgItem.__init__(self)
38 ce9281d7 humkyung
        QEngineeringAbstractItem.__init__(self)
39 0f777efa humkyung
40 be23d25c esham21
        self.setFlags(QGraphicsItem.ItemIsSelectable|QGraphicsItem.ItemIsFocusable)#|QGraphicsItem.ItemIsMovable)
41 8336d4c8 esham21
42 c82b5644 humkyung
        self.uid = uuid.uuid4() if uid is None else uuid.UUID(uid, version=4)
43 0bcf00da 김정우
        self.name = ''
44 18a0281b 김정우
        self.type = ''
45 02ed19e4 humkyung
        self.angle = 0
46 18f54b2f humkyung
        self.origin = None
47 02ed19e4 humkyung
        self.loc = None
48
        self.size = None
49 5fbc4298 humkyung
        self._owner = None
50 34f2b549 김정우
        self.parentSymbol = ''
51 a98f2100 gaqhf
        self.childSymbol = '' 
52 66ddb055 예철 임
        self.hasInstrumentLabel = 0
53 9aaebab3 esham21
        self.flip = flip
54 5953ddc1 gaqhf
        # attributeType uid
55
        self.attribute = ''
56 a208ed03 humkyung
        self._properties = {SymbolProp(None, 'Supplied By', 'String'):None}
57 be3e0c2d humkyung
        
58 8336d4c8 esham21
        self.setAcceptDrops(True)
59 0f777efa humkyung
        self.setAcceptHoverEvents(True)
60 18a0281b 김정우
        self.setAcceptedMouseButtons(Qt.LeftButton)
61 55765a6c humkyung
        self.setAcceptTouchEvents(True)
62 3216847d humkyung
        
63 2885ca96 gaqhf
        self.currentCursor = 0
64 d7080855 humkyung
        self.transfer = Transfer()
65 2885ca96 gaqhf
66 c9c0b30b humkyung
        try:
67
            f = QFile(path)
68
            f.open(QIODevice.ReadOnly)
69
            array = f.readAll()
70
            self._document = QDomDocument()
71
            self._document.setContent(array)
72
            self._renderer = QSvgRenderer(self._document.toByteArray())
73
            self.setSharedRenderer(self._renderer)
74 93ed7203 김정우
75 3ebd61eb humkyung
            self._color = self.get_attribute('fill')
76 c9c0b30b humkyung
        except Exception as ex:
77
            print('error occured({}) in {}:{}'.format(ex, sys.exc_info()[-1].tb_frame.f_code.co_filename, sys.exc_info()[-1].tb_lineno))
78
        finally:
79
            f.close()
80 ed948580 humkyung
81
        self.setZValue(SymbolSvgItem.ZVALUE)
82 ce1ae611 humkyung
83
        app_doc_data = AppDocData.instance()
84
        configs = app_doc_data.getConfigs('Symbol Style', 'Opacity')
85
        self.setOpacity(float(configs[0].value)/100 if configs else 0.5)
86
87 5fbc4298 humkyung
    '''
88
        @breif  getter owner
89
        @author humkyung
90
        @date   2018.05.10
91
    '''
92
    @property
93
    def owner(self):
94
        return self._owner
95
96
    '''
97
        @brief  setter owner
98
        @author humkyung
99
        @date   2018.05.10
100 5b782afc 김정우
        @history    2018.05.17  Jeongwoo    Add Calling setColor if self._owner is None or not
101 5fbc4298 humkyung
    '''
102
    @owner.setter
103
    def owner(self, value):
104
        self._owner = value
105 0f777efa humkyung
106 5b782afc 김정우
        if self._owner is None:
107
            self._color = self.DEFAULT_COLOR
108 ce9281d7 humkyung
        self.setColor(self._color)
109
110 a208ed03 humkyung
    @property
111
    def properties(self):
112
        """ getter of properties """
113 df4661c5 humkyung
        import uuid
114
115
        for prop,value in self._properties.items():
116
            if prop.is_selectable and type(value) is uuid.UUID:
117
                matches = [x for x in self.scene().items() if hasattr(x, 'uid') and str(x.uid) == str(value)]
118
                if matches: self._properties[prop] = matches[0]
119
            
120 a208ed03 humkyung
        return self._properties
121
122
    @properties.setter
123
    def properties(self, value):
124
        """ setter of properties """
125
        self._properties = value
126
127 df4661c5 humkyung
    def set_property(self, property, value):
128
        """ set property with given value """
129
        matches = [prop for prop,_ in self._properties.items() if prop.Attribute == property]
130
        if matches: self._properties[matches[0]] = value
131
132 25a69af0 humkyung
    def validate(self):
133 223f4e6c esham21
        '''
134
            @brief  validation check : flow
135
            @author euisung
136
            @date   2019.04.16
137
        '''
138
        from EngineeringErrorItem import QEngineeringErrorItem
139
        from EngineeringLineItem import QEngineeringLineItem
140 3e016424 esham21
        from EngineeringSpecBreakItem import QEngineeringSpecBreakItem
141 223f4e6c esham21
        errors = []
142 3e016424 esham21
        if type(self) is QEngineeringSpecBreakItem:
143
            return errors
144 0db1c7e6 esham21
        docdata = AppDocData.instance()
145
        dataPath = docdata.getErrorItemSvgPath()
146
        origin = [int(pt) for pt in docdata.getAppConfigs('app', 'error origin point')[0].value.split(',')]
147 223f4e6c esham21
        
148 0db1c7e6 esham21
        # check flow for 2 connection point symbol
149 223f4e6c esham21
        if len(self.connectors) is 2:
150
            if type(self.connectors[0].connectedItem) is QEngineeringLineItem and type(self.connectors[1].connectedItem) is QEngineeringLineItem:
151
                if self.includes(self.connectors[0].connectedItem.startPoint(), 5) is not self.includes(self.connectors[1].connectedItem.endPoint(), 5):
152
                    #print(self.sceneBoundingRect())
153
                    error = SymbolSvgItem.createItem('Error', dataPath)
154
                    error.parent = self
155
                    error.msg = 'flow error'
156
                    error.setToolTip(error.msg)
157
                    error.area = 'Drawing'
158
                    error.name = 'Error'
159
                    errors.append(error)
160 0db1c7e6 esham21
161
        # check disconnected point
162 53034219 esham21
        disconnect = False
163
        if len(self.connectors) is not 0:
164
            disconnect = True
165
            for connector in self.connectors:
166
                if connector.connectedItem is not None:
167
                    disconnect = False
168
                    break
169
        
170 ee573f67 esham21
        if disconnect:
171
            error = SymbolSvgItem.createItem('Error', dataPath)
172
            error.parent = self
173
            error.msg = 'disconnected'
174
            error.setToolTip(error.msg)
175
            error.area = 'Drawing'
176
            error.name = 'Error'
177
            errors.append(error)
178
179
        # set error position
180 95427e07 esham21
        #denominator = len(errors) + 1
181
        #molecule = 1
182 ee573f67 esham21
        for error in errors:
183 95427e07 esham21
            error.setPosition([self.sceneBoundingRect().center().x(), self.sceneBoundingRect().center().y()], origin)
184
            #molecule = molecule + 1
185 223f4e6c esham21
        
186
        return errors
187 25a69af0 humkyung
188 223f4e6c esham21
    def includes(self, pt, margin=0):
189 d6518150 humkyung
        """
190
        return True if symbol contains given point else return False
191
        """
192 223f4e6c esham21
        rect = self.sceneBoundingRect()
193
        minX = rect.x() - margin
194
        minY = rect.y() - margin
195
        maxX = minX + rect.width() + margin
196
        maxY = minY + rect.height() + margin
197 cc747b58 esham21
198 d6518150 humkyung
        return True if (pt[0] >= minX and pt[0] <= maxX and pt[1] >= minY and pt[1] <= maxY) else False
199 cc747b58 esham21
200 820ed509 humkyung
    def associations(self):
201 4b4d954c humkyung
        """
202 820ed509 humkyung
        return associated instance
203 4b4d954c humkyung
        """
204
        import uuid
205
206
        res = []
207 820ed509 humkyung
        for key in self._associations.keys():
208
            for assoc in self._associations[key]:
209
                # find owner with uid
210
                if assoc and type(assoc) is uuid.UUID:
211 5376996a esham21
                    matches = [x for x in self.scene().items() if hasattr(x, 'uid') and str(x.uid) == str(assoc)]
212 a4806b86 humkyung
                    if matches: res.append(matches[0]) # TODO: need to update association with instance
213 820ed509 humkyung
                # up to here
214
                elif assoc:
215
                    res.append(assoc)
216 4b4d954c humkyung
217
        return res
218
219
    def texts(self):
220
        """
221 820ed509 humkyung
        return text type of associations
222 4b4d954c humkyung
        """
223
        from EngineeringTextItem import QEngineeringTextItem
224
225 820ed509 humkyung
        return [x for x in self.associations() if issubclass(type(x), QEngineeringTextItem)]
226 4b4d954c humkyung
227
    def symbols(self):
228
        """
229 820ed509 humkyung
        return symbol type of associations
230 4b4d954c humkyung
        """
231 820ed509 humkyung
        return [x for x in self.associations() if issubclass(type(x), SymbolSvgItem)]
232 4b4d954c humkyung
233 c28d2e4c esham21
    def toSql(self):
234
        """
235
        convert valve data to sql query
236
        """
237 1efd2d2e humkyung
        import uuid
238 c28d2e4c esham21
        from AppDocData import AppDocData
239
240 55321a0d humkyung
        res = []
241 c28d2e4c esham21
        appDocData = AppDocData.instance()
242
243
        cols = ['UID', 'ITEM_NO', 'PNID_NO']
244
        values = ['?','?','?']
245
        param = [str(self.uid), self.name, appDocData.activeDrawing.name]
246 55321a0d humkyung
        sql = 'insert or replace into VALVE_DATA_LIST({}) values({})'.format(','.join(cols), ','.join(values))
247
        res.append((sql, tuple(param)))
248
249 c28d2e4c esham21
        _attrs = self.getAttributes()
250
        for key in _attrs.keys():
251 1efd2d2e humkyung
            cols = ['UID', 'Components_UID', 'SymbolAttribute_UID', 'Value']
252 55321a0d humkyung
            values = ['?', '?', '?', '?']
253 1efd2d2e humkyung
            param = [str(uuid.uuid4()), str(self.uid), key.UID, _attrs[key]]
254 c28d2e4c esham21
255 55321a0d humkyung
            sql = 'insert or replace into Attributes({}) values({})'.format(','.join(cols), ','.join(values))
256
            res.append((sql, tuple(param)))
257
258 1efd2d2e humkyung
        # save connectors to database
259
        for connector in self.connectors:
260
            res.append(connector.toSql())
261
        # up to here
262 673d8cba esham21
263 1efd2d2e humkyung
        return res
264 17704fb0 humkyung
265
    '''
266 0cf624b6 gaqhf
        @brief  build symbol item
267
        @author humkyung
268
        @date   2018.05.02
269 171704df 김정우
        @history    2018.05.09  Jeongwoo    Clear self.connectors
270 34f2b549 김정우
                    2018.05.30  Jeongwoo    Add parameters (parentSymbol, childSymbol)
271 f21ec5b3 humkyung
    '''
272 ee195020 humkyung
    def buildItem(self, name, _type, angle, loc, size, origin, connPts, parentSymbol, childSymbol, hasInstrumentLabel):
273 f21ec5b3 humkyung
        try:
274 157e3a3e gaqhf
            docData = AppDocData.instance()
275 f21ec5b3 humkyung
            self.name = name
276 ee195020 humkyung
            self.type = _type
277 f21ec5b3 humkyung
            self.angle = angle
278
            self.loc = loc
279
            self.size = size
280
            self.origin = origin
281 89325f4b humkyung
            symbolInfo = docData.getSymbolByQuery('name', name)
282 157e3a3e gaqhf
            originalPoint = symbolInfo.getOriginalPoint().split(',')
283 9aaebab3 esham21
            self.symbolOrigin = [float(originalPoint[0]), float(originalPoint[1])]
284 789d0d3a esham21
            if self.flip is 1:
285 9aaebab3 esham21
                self.symbolOrigin[0] = self.size[0] - self.symbolOrigin[0]
286 740725ef gaqhf
287
            # setting connectors
288 157e3a3e gaqhf
            connectionPoints = symbolInfo.getConnectionPoint().split('/')
289 0c291a7c esham21
            #print(connectionPoints)
290 740725ef gaqhf
            for index in range(len(connectionPoints)):
291 0c291a7c esham21
                if connectionPoints[index] == '':
292
                    break
293 9ea20a89 humkyung
                tokens = connectionPoints[index].split(',')
294
295
                direction = 'AUTO'
296 4edbb659 humkyung
                symbol_idx = '0'
297 9ea20a89 humkyung
                if len(tokens) == 2:
298
                    x = float(tokens[0])
299
                    y = float(tokens[1])
300
                elif len(tokens) == 3:
301
                    direction = tokens[0]
302
                    x = float(tokens[1])
303
                    y = float(tokens[2])
304 4edbb659 humkyung
                elif len(tokens) == 4:
305
                    direction = tokens[0]
306
                    x = float(tokens[1])
307
                    y = float(tokens[2])
308
                    symbol_idx = tokens[3]
309 9ea20a89 humkyung
310 740725ef gaqhf
                self.setConnector()
311 9ea20a89 humkyung
                self.connectors[index].direction = direction
312 4edbb659 humkyung
                self.connectors[index].symbol_idx = symbol_idx
313 d7ddc5c0 gaqhf
                self.connectors[index].setPos((x, y))
314 9ea20a89 humkyung
                self.connectors[index].connectPoint = (x, y)
315 4edbb659 humkyung
                self.connectors[index].sceneConnectPoint = (connPts[index][0], connPts[index][1]) if len(connPts[index]) == 2 else \
316
                                                           (connPts[index][1], connPts[index][2]) if len(connPts[index]) == 3 else \
317
                                                           (connPts[index][1], connPts[index][2]) if len(connPts[index]) == 4 else None
318 740725ef gaqhf
                
319 34f2b549 김정우
            self.parentSymbol = parentSymbol
320
            self.childSymbol = childSymbol
321 66ddb055 예철 임
            self.hasInstrumentLabel = hasInstrumentLabel
322 53fa5967 gaqhf
            self.currentPointModeIndex = 0
323 740725ef gaqhf
324 3ec1874a humkyung
            tooltip = '<b>{}</b><br>{}={}'.format(str(self.uid), self.type, self.name)
325
            self.setToolTip(tooltip)
326 f21ec5b3 humkyung
        except Exception as ex:
327 9ea20a89 humkyung
            from App import App 
328
329
            message = 'error occured({}) in {}:{}'.format(ex, sys.exc_info()[-1].tb_frame.f_code.co_filename, sys.exc_info()[-1].tb_lineno)
330
            App.mainWnd().addMessage.emit(MessageType.Error, message)
331 f21ec5b3 humkyung
332
    '''
333 02ed19e4 humkyung
        @brief  return bounding box of symbol
334
        @author humkyung
335
        @date   2018.04.08
336
    '''
337
    def rect(self):
338 3a4cc147 humkyung
        return self.sceneBoundingRect()
339 02ed19e4 humkyung
        
340
    '''
341 0f4a186f humkyung
        @brief  return true if line is able to connect symbol
342
        @author humkyung
343
        @date   2018.04.13
344
    '''
345 f21800ed humkyung
    def is_connectable(self, line, toler=10):
346
        start_pt = line.startPoint()
347
        end_pt = line.endPoint()
348 740725ef gaqhf
        for connector in self.connectors:
349 f21800ed humkyung
            dx = connector.sceneConnectPoint[0] - (start_pt[0])
350
            dy = connector.sceneConnectPoint[1] - (start_pt[1])
351 0f4a186f humkyung
            if (math.sqrt(dx*dx + dy*dy) < toler): return True
352 f21800ed humkyung
            dx = connector.sceneConnectPoint[0] - (end_pt[0])
353
            dy = connector.sceneConnectPoint[1] - (end_pt[1])
354 0f4a186f humkyung
            if (math.sqrt(dx*dx + dy*dy) < toler): return True
355
356
        return False
357 d2c68320 humkyung
 
358
    '''
359
        @author     humkyung
360
        @date       2018.07.03
361
    '''
362 f21800ed humkyung
    def is_connected(self, item, at=QEngineeringAbstractItem.CONNECTED_AT_PT):
363
        """ check if given item is connected to self """
364 d2c68320 humkyung
365 22adf874 humkyung
        _connectors = [connector for connector in self.connectors if (connector.connectedItem == item and (connector._connected_at == at if at else True))]
366 f21800ed humkyung
        return len(_connectors) > 0
367 d2c68320 humkyung
368 c5463994 humkyung
    def next_connected(self, lhs, rhs):
369
        """ tes given two item's are next connected(ex: 0-1, 2-3) """
370
371
        lhs_matches = [at for at in range(len(self.connectors)) if self.connectors[at].connectedItem == lhs]
372
        rhs_matches = [at for at in range(len(self.connectors)) if self.connectors[at].connectedItem == rhs]
373
        if lhs_matches and rhs_matches:
374
            return (lhs_matches[0] in [0,1] and rhs_matches[0] in [0,1]) or (lhs_matches[0] in [2,3] and rhs_matches[0] in [2,3])
375
376
        return False
377
378 0f4a186f humkyung
    '''
379 79a8001e humkyung
        @brief      connect line and symbol is able to be connected and return line
380
        @author     humkyung
381
        @date       2018.04.16
382
        @history    humkyung 2018.05.08 check if symbol is possible to be connected
383 5e79f8c1 김정우
                    Jeongwoo 2018.05.15 Connect each symbol and line
384 8c5431cc humkyung
    '''
385 f21800ed humkyung
    def connect_if_possible(self, obj, toler=10):
386 8c5431cc humkyung
        from shapely.geometry import Point
387 d7080855 humkyung
        from EngineeringLineItem import QEngineeringLineItem
388 f21800ed humkyung
389 8c5431cc humkyung
        res = []
390 35d36394 gaqhf
        try:
391
            if type(obj) is QEngineeringLineItem:
392
                startPt = obj.startPoint()
393
                endPt = obj.endPoint()
394
                for i in range(len(self.connectors)):
395
                    if (Point(startPt[0], startPt[1]).distance(Point(self.connectors[i].sceneConnectPoint[0], self.connectors[i].sceneConnectPoint[1])) < toler):
396 1dbb865c gaqhf
                        if self.connectors[i].connectedItem is None:
397 f21800ed humkyung
                            self.connectors[i].connect(obj)
398 35d36394 gaqhf
                        if obj.connectors[0].connectedItem is None:
399 f21800ed humkyung
                            obj.connectors[0].connect(self)
400 35d36394 gaqhf
                        
401 79a8001e humkyung
                        res.append(obj)
402 35d36394 gaqhf
                    if (Point(endPt[0], endPt[1]).distance(Point(self.connectors[i].sceneConnectPoint[0], self.connectors[i].sceneConnectPoint[1])) < toler):
403
                        if self.connectors[i].connectedItem is None:
404 f21800ed humkyung
                            self.connectors[i].connect(obj)
405 35d36394 gaqhf
                        if obj.connectors[1].connectedItem is None:
406 f21800ed humkyung
                            obj.connectors[1].connect(self)
407 35d36394 gaqhf
                        
408
                        res.append(obj)
409
            elif issubclass(type(obj), SymbolSvgItem):
410
                for i in range(len(self.connectors)):
411
                    for j in range(len(obj.connectors)):
412
                        _pt = Point(obj.connectors[j].sceneConnectPoint[0], obj.connectors[j].sceneConnectPoint[1])
413
                        if (_pt.distance(Point(self.connectors[i].sceneConnectPoint[0], self.connectors[i].sceneConnectPoint[1])) < toler):
414
                            if self.connectors[i].connectedItem is None:
415 f21800ed humkyung
                                self.connectors[i].connect(obj)
416
                            if obj.connectors[j].connectedItem is None:
417
                                obj.connectors[j].connect(self)
418 35d36394 gaqhf
419
                            res.append(obj)
420
        except Exception as ex:
421 f21800ed humkyung
            from App import App 
422
            message = 'error occured({}) in {}:{}'.format(ex, sys.exc_info()[-1].tb_frame.f_code.co_filename, sys.exc_info()[-1].tb_lineno)
423
            App.mainWnd().addMessage.emit(MessageType.Error, message)
424 8c5431cc humkyung
425
        return res
426
427
    '''
428 a98f2100 gaqhf
        @brief      disconnect connector item
429
        @author     kyouho
430
        @date       2018.08.30
431
    '''
432
    def disconnectedItemAtConnector(self, connector):
433
        for conn in self.connectors:
434
            if conn.isOverlapConnector(connector):
435
                conn.connectedItem = None
436
437
    '''
438 6fad8ffd humkyung
        @brief  get connection point close to given point in tolerance
439
        @author humkyung
440
        @dat
441
    '''
442
    def getConnectionPointCloseTo(self, pt, toler=10):
443
        import math
444
445 740725ef gaqhf
        for connector in self.connectors:
446
            dx = connector.sceneConnectPoint[0] - pt[0]
447
            dy = connector.sceneConnectPoint[1] - pt[1]
448 6fad8ffd humkyung
            if math.sqrt(dx*dx + dy*dy) < toler: return connPt
449
            
450
        return None
451
452
    '''
453 02ed19e4 humkyung
        @brief  return center of symbol
454
        @author humkyung
455
        @date   2018.04.08
456
    '''
457
    def center(self):
458 3a4cc147 humkyung
        return self.sceneBoundingRect().center()
459 02ed19e4 humkyung
        
460 24015dc6 humkyung
    '''
461 b9334e15 humkyung
        @brief      highlight connector and attribute
462
        @authro     humkyung
463
        @date       2018.05.02
464 24015dc6 humkyung
    '''
465 0f777efa humkyung
    def hoverEnterEvent(self, event):
466 90bc60db humkyung
        try:
467 3ebd61eb humkyung
            self.hover = True
468
            self.update()
469
470 9a5aef6e humkyung
            for assoc in self.associations():
471
                assoc.hoverEnterEvent(event)
472 ac10260c gaqhf
        except Exception as ex: 
473 9a5aef6e humkyung
            from App import App 
474
            message = 'error occured({}) in {}:{}'.format(ex, sys.exc_info()[-1].tb_frame.f_code.co_filename, sys.exc_info()[-1].tb_lineno)
475
            App.mainWnd().addMessage.emit(MessageType.Error, message)
476 d0a58b30 gaqhf
477 24015dc6 humkyung
    '''
478 b9334e15 humkyung
        @brief      unhighlight connector and attribute
479
        @author     humkyung
480
        @date       2018.05.02
481
        @history    kyouho 2018.07.18 edit ArrowCursor
482 24015dc6 humkyung
    '''
483 0f777efa humkyung
    def hoverLeaveEvent(self, event):
484 3ebd61eb humkyung
        self.hover = False
485
        self.update()
486
487 9a5aef6e humkyung
        for assoc in self.associations():
488
            assoc.hoverLeaveEvent(event)
489 4efdc42f gaqhf
490
    '''
491
        @brief      set highlight
492
        @author     kyouho
493
        @date       2018.08.27
494
    '''
495
    def setHightlight(self):
496 b52cccb4 humkyung
        self.setColor('url(#hover)')
497 4efdc42f gaqhf
        self.update()
498
499
    '''
500
        @brief      unset highlight
501
        @author     kyouho
502
        @date       2018.08.27
503
    '''
504
    def unsetHightlight(self):
505 b52cccb4 humkyung
        self.setColor('url(#normal)')
506 4efdc42f gaqhf
        self.update()
507
508 6fad8ffd humkyung
    '''
509
        @brief  change cursor to CrossCursor if mouse point is close to connection point
510
        @author humkyung
511
        @date   2018.04.28
512
    '''
513 0f777efa humkyung
    def hoverMoveEvent(self, event):
514 3216847d humkyung
        pass
515 18a0281b 김정우
516
    '''
517
        @brief      Mouse Press Event
518
        @author     Jeongwoo
519
        @date       18.04.11
520 2885ca96 gaqhf
        @history    kyouho 2018.07.18 add isClick logic
521 18a0281b 김정우
    '''
522
    def mousePressEvent(self, event):
523 0ed45c45 김정우
        if event.buttons() == Qt.LeftButton:
524
            self.clicked.emit(self)
525 2885ca96 gaqhf
526
    '''
527
        @brief      Mouse Release Event
528
        @author     kyouho
529
        @date       18.07.17
530
    '''
531
    def mouseReleaseEvent(self, event):
532
        super().mouseReleaseEvent(event)
533
534 8336d4c8 esham21
    #def dropEvent(self, event):
535
    #    '''
536
    #        @brief      Mouse Drop Event
537
    #        @author     euisung
538
    #        @date       2019.04.01
539
    #    '''
540
    #    print('d')
541
    #    super().dropEvent(event)
542
    
543
    #def dragLeaveEvent(self, event):
544
    #    print('l')
545
546 7e9d9ecd gaqhf
    def removeSelfAttr(self, attributeName):
547
        for attr in self.attrs:
548 673d8cba esham21
            if attr.Attribute == attributeName:
549 820ed509 humkyung
                del self.attrs[attr]
550 7e9d9ecd gaqhf
551
    '''
552
        @brief      Find TextItem contain Point
553 2885ca96 gaqhf
        @author     kyouho
554
        @date       18.07.17
555
    '''
556
    def findTextItemInPoint(self, point):
557 c80d49e6 humkyung
        from EngineeringTextItem import QEngineeringTextItem
558 2885ca96 gaqhf
        
559
        scene = self.scene()
560
 
561
        for item in scene.items():
562
            if type(item) is QEngineeringTextItem:
563
                if self.isOverlapItemAndPoint(item, point):
564
                    return (True, item)
565
566
        return (False,)
567 d0a58b30 gaqhf
568 2885ca96 gaqhf
    '''
569 7e9d9ecd gaqhf
        @brief      Check Overlap
570 2885ca96 gaqhf
        @author     kyouho
571
        @date       18.07.17
572
    '''
573
    def isOverlapItemAndPoint(self, item, point):
574
        x = point.x()
575
        y = point.y()
576
        loc = item.loc
577
        size = item.size
578
579
        if loc[0] <= x and loc[0] + size[0] >= x and loc[1] <= y and loc[1] + size[1] >= y:
580
            return True
581
        else:
582
            return False
583
584
    '''
585
        @brief      Remove Attr
586
        @author     kyouho
587
        @date       18.07.17
588
    '''
589
    def removeAttr(self, item):
590
        scene = self.scene()
591
        for symbol in scene.items():
592 357646b0 gaqhf
            if issubclass(type(symbol), SymbolSvgItem):
593 2885ca96 gaqhf
                for attr in symbol.attrs:
594
                    if attr == item:
595
                        symbol.attrs.remove(item)
596 3a4cc147 humkyung
597
    '''
598 55765a6c humkyung
        @brief  remove item when user press delete key
599
        @author humkyung
600
        @date   2018.04.23
601 5b782afc 김정우
        @history    2018.05.17  Jeongwoo    Add if-statement and move 'break'
602 a3a805a0 김정우
                    2018.05.25  Jeongwoo    Seperate delete item method
603 55765a6c humkyung
    '''
604 84d775f4 gaqhf
    def keyPressEvent(self, event):
605 c82b5644 humkyung
        if self.isSelected() and event.key() == Qt.Key_Delete:
606 a3a805a0 김정우
            self.deleteSvgItemFromScene()
607 84d775f4 gaqhf
        elif event.key() == Qt.Key_R:
608
            self.rotateSymbol()
609
        elif event.key() == Qt.Key_O:
610
            self.changeStandardPoint()
611
        elif event.key() == Qt.Key_C:
612
            self.changeConnPoint()
613 853c2faf esham21
        elif event.key() == Qt.Key_F:
614
            self.flipSymbol()
615
           
616 55765a6c humkyung
    '''
617 83f4006f humkyung
        @brief      connect attribute
618
        @author     humkyung
619
        @date       2018.05.02
620
        @history    humkyung 2018.05.09 append only nearest size attribute
621 24015dc6 humkyung
    '''
622 72edf08b humkyung
    def connectAttribute(self, attributes, clear=True):
623 24015dc6 humkyung
        import math
624 a4806b86 humkyung
        from EngineeringTextItem import QEngineeringTextItem
625 24015dc6 humkyung
        from QEngineeringSizeTextItem import QEngineeringSizeTextItem
626 820ed509 humkyung
        from EngineeringInstrumentItem import QEngineeringInstrumentItem
627 a4806b86 humkyung
        from EngineeringValveOperCodeTextItem import QEngineeringValveOperCodeTextItem
628 24015dc6 humkyung
629 72edf08b humkyung
        if clear:
630
            self.attrs.clear()
631
            self._associations.clear()
632 24015dc6 humkyung
633 be3e0c2d humkyung
        try:
634
            dist = max(self.sceneBoundingRect().height(), self.sceneBoundingRect().width())
635
            center = self.sceneBoundingRect().center()
636
637
            minDist = None
638
            selected = None
639
            for attr in attributes:
640 a4806b86 humkyung
                if type(attr) is QEngineeringSizeTextItem or type(attr) is QEngineeringValveOperCodeTextItem or type(attr) is QEngineeringTextItem:
641 be3e0c2d humkyung
                    dx = attr.center().x() - center.x()
642
                    dy = attr.center().y() - center.y()
643
                    length = math.sqrt(dx*dx + dy*dy)
644
                    if (length < dist*2) and (minDist is None or length < minDist):
645
                        minDist = length
646
                        selected = attr
647 820ed509 humkyung
                elif type(attr) is QEngineeringInstrumentItem:
648 72edf08b humkyung
                    if not attr.is_connected:
649
                        dx = attr.center().x() - center.x()
650
                        dy = attr.center().y() - center.y()
651
                        if math.sqrt(dx*dx + dy*dy) < dist*2:
652
                            self.add_assoc_item(attr)
653 be3e0c2d humkyung
654
            if selected is not None:
655 820ed509 humkyung
                self.add_assoc_item(selected)
656
657 be3e0c2d humkyung
        except Exception as ex:
658
            from App import App 
659
            message = 'error occured({}) in {}:{}'.format(ex, sys.exc_info()[-1].tb_frame.f_code.co_filename, sys.exc_info()[-1].tb_lineno)
660
            App.mainWnd().addMessage.emit(MessageType.Error, message)
661 66ddb055 예철 임
662
    '''
663 6d715a6e esham21
        @brief      Double click event, Show rotate symbol dialog
664
        @author     euisung
665
        @date       2019.04.16
666
    '''
667
    def mouseDoubleClickEvent(self, event):
668
        from RotateSymbolDialog import QRotateSymbolDialog
669 223f4e6c esham21
        dialog = QRotateSymbolDialog(None, self.angle)
670 6d715a6e esham21
        (isAccept, angle) = dialog.showDialog()
671
  
672
        if isAccept:
673
            self.rotateSymbol(angle)
674
675
    '''
676 a3ae6dab humkyung
        @brief      get attribute
677
        @author     humkyung
678
        @date       2018.06.14
679 2885ca96 gaqhf
        @history    kyouho  2018.07.18  Add only attr QEngineeringTextItem
680 18f21a9a humkyung
    '''
681
    def getAttributes(self):
682 62dc9ffa humkyung
        _attrs = {}
683 b8d39c65 humkyung
        try:
684
            from AppDocData import AppDocData
685 04271a49 humkyung
            from EngineeringAbstractItem import QEngineeringAbstractItem
686 b8d39c65 humkyung
            from EngineeringTextItem import QEngineeringTextItem
687 a4806b86 humkyung
            from EngineeringValveOperCodeTextItem import QEngineeringValveOperCodeTextItem
688 7e9d9ecd gaqhf
689 b8d39c65 humkyung
            # 해당 Type의 attribute setting
690
            docData = AppDocData.instance()
691
            symbolAttrs = docData.getSymbolAttribute(self.type)
692 820ed509 humkyung
693
            _texts = self.texts()
694
            _symbols = self.symbols()
695 b8d39c65 humkyung
            for attr in symbolAttrs:
696 a4806b86 humkyung
                if attr.AttributeType == 'Size Text Item' or attr.AttributeType == 'Text Item' or attr.AttributeType == 'Valve Oper Code':
697 b8d39c65 humkyung
                    at = int(attr.AttrAt)
698 f9f40aff esham21
                    items = [text for text in _texts if QEngineeringAbstractItem.assoc_type(text) == attr.AttributeType]
699 a4806b86 humkyung
                    if len(items) > at:
700
                        item = items[at]
701 b8d39c65 humkyung
                        _attrs[attr] = eval(attr.Expression) if attr.Expression else ''
702
                    else:
703
                        _attrs[attr] = ''
704
                elif attr.AttributeType == 'Symbol Item':
705
                    at = int(attr.AttrAt)
706 820ed509 humkyung
                    if len(_symbols) > at:
707
                        item = _symbols[at]
708 b8d39c65 humkyung
                        _attrs[attr] = eval(attr.Expression) if attr.Expression else ''
709
                    else:
710
                        _attrs[attr] = ''
711
                else:
712
                    matches = [prop for prop in self.attrs if prop.UID == attr.UID]
713
                    if len(matches) == 1:
714
                        _attrs[matches[0]] = self.attrs[matches[0]]
715
                    else:
716
                        _attrs[attr] = ''
717
        except Exception as ex:
718
            from App import App 
719
            from AppDocData import MessageType
720
721
            message = 'error occured({}) in {}:{}'.format(ex, sys.exc_info()[-1].tb_frame.f_code.co_filename, sys.exc_info()[-1].tb_lineno)
722
            App.mainWnd().addMessage.emit(MessageType.Error, message)
723 2885ca96 gaqhf
        
724 62dc9ffa humkyung
        return _attrs
725 b8d39c65 humkyung
726 18f21a9a humkyung
    '''
727 d2f7bd48 humkyung
        @brief      generate xml code
728
        @author     humkyung
729
        @date       2018.04.23
730
        @history    humkyung 2018.04.25 add angle xml node
731 18f54b2f humkyung
                    humkyung 2018.04.27 add originalpoint xml node
732 24015dc6 humkyung
                    humkyung 2018.05.02 add attribute of symbol
733 f09eb8ff 김정우
                    Jeongwoo 2018.05.30 add attribute of symbol (parentSymbol, childSymbol, type, connectionPoint)
734 66ddb055 예철 임
                    yecheol  2018.07.11 add attribute of symbol (hasInstrumentLabel)
735 cf1f887b humkyung
                    humkyung 2018.07.20 write owner's uid to xml
736 17704fb0 humkyung
                    humkyung 2018.07.23 write connected item's uid to xml
737 5da1fdfd gaqhf
                    kyouho  2018.07.31 
738 baf331db humkyung
                    humkyung 2018.09.06 write area to xml
739 68ce37ea humkyung
    '''
740
    def toXml(self):
741
        from xml.etree.ElementTree import Element, SubElement, dump, ElementTree
742 72899189 humkyung
        from EngineeringAbstractItem import QEngineeringAbstractItem
743 820ed509 humkyung
        from EngineeringTextItem import QEngineeringTextItem
744 0cf624b6 gaqhf
        from EngineeringSpecBreakItem import QEngineeringSpecBreakItem
745 85a460a6 humkyung
        from SymbolAttr import SymbolAttr
746 68ce37ea humkyung
747
        try:
748
            node = Element('SYMBOL')
749 6fb1a52e humkyung
            uidNode = Element('UID')
750
            uidNode.text = str(self.uid)
751 18f54b2f humkyung
            node.append(uidNode)
752 68ce37ea humkyung
753
            nameNode = Element('NAME')
754
            nameNode.text = self.name
755 18f54b2f humkyung
            node.append(nameNode)
756
757 820ed509 humkyung
            attributeValueNode = Element('ASSOCIATIONS')
758
            for assoc in self.associations():
759
                assoc_node = Element('ASSOCIATION')
760 72899189 humkyung
                assoc_node.attrib['TYPE'] = QEngineeringAbstractItem.assoc_type(assoc)
761 820ed509 humkyung
                assoc_node.text = str(assoc.uid)
762
                attributeValueNode.append(assoc_node)
763 5953ddc1 gaqhf
            node.append(attributeValueNode)
764
765 f09eb8ff 김정우
            typeNode = Element('TYPE')
766
            typeNode.text = self.type
767
            node.append(typeNode)
768
769 cf1f887b humkyung
            # write owner's uid to xml
770
            if self.owner is not None:
771
                ownerNode = Element('OWNER')
772
                ownerNode.text = str(self.owner.uid)
773
                node.append(ownerNode)
774
            # up to here
775
776 18f54b2f humkyung
            originNode = Element('ORIGINALPOINT')
777
            originNode.text = '{},{}'.format(self.origin[0], self.origin[1])
778
            node.append(originNode)
779 68ce37ea humkyung
780 5da1fdfd gaqhf
            connectorsNode = Element('CONNECTORS')
781
            for connector in self.connectors:
782 f21800ed humkyung
                connectorsNode.append(connector.toXml())
783 5da1fdfd gaqhf
            node.append(connectorsNode)
784 17704fb0 humkyung
785 f09eb8ff 김정우
            connectionNode = Element('CONNECTIONPOINT')
786 4edbb659 humkyung
            connection_point = []
787 740725ef gaqhf
            if self.connectors is not None:
788 4edbb659 humkyung
                for connector in self.connectors:
789
                    connection_point.append(repr(connector))
790
            connectionNode.text = '/'.join(connection_point)
791 f09eb8ff 김정우
            node.append(connectionNode)
792
793 68ce37ea humkyung
            rect = self.sceneBoundingRect()
794 6fb1a52e humkyung
            locNode = Element('LOCATION')
795 6b99140a gaqhf
            locNode.text = '{},{}'.format(self.loc[0], self.loc[1])
796 18f54b2f humkyung
            node.append(locNode)
797 68ce37ea humkyung
798
            sizeNode = Element('SIZE')
799 48662961 esham21
            #sizeNode.text = '{},{}'.format(rect.width(), rect.height())
800
            sizeNode.text = '{},{}'.format(self.size[0], self.size[1])
801 18f54b2f humkyung
            node.append(sizeNode)
802 68ce37ea humkyung
803 d2f7bd48 humkyung
            angleNode = Element('ANGLE')
804
            angleNode.text = str(self.angle)
805
            node.append(angleNode)
806 34f2b549 김정우
807 f09eb8ff 김정우
            parentSymbolNode = Element('PARENT')
808
            parentSymbolNode.text = str(self.parentSymbol)
809
            node.append(parentSymbolNode)
810 34f2b549 김정우
811 f09eb8ff 김정우
            childSymbolNode = Element('CHILD')
812
            childSymbolNode.text = str(self.childSymbol)
813
            node.append(childSymbolNode)
814 66ddb055 예철 임
815
            hasInstrumentLabelNode = Element('HASINSTRUMENTLABEL')
816
            hasInstrumentLabelNode.text = str(self.hasInstrumentLabel)
817
            node.append(hasInstrumentLabelNode)
818 16ca5a01 gaqhf
819 baf331db humkyung
            areaNode = Element('AREA')
820
            areaNode.text = self.area
821
            node.append(areaNode)
822
823 789d0d3a esham21
            flipNode = Element('FLIP')
824
            flipNode.text = str(self.flip)
825
            node.append(flipNode)
826 ff096d3a esham21
            
827 a208ed03 humkyung
            properties_node = Element('PROPERTIES')
828
            for prop,value in self.properties.items():
829
                prop_node = prop.toXml()
830
                prop_node.text = '' if not value else str(value.uid) if prop.is_selectable else str(value)
831
                properties_node.append(prop_node)
832
            node.append(properties_node)
833 789d0d3a esham21
834 16ca5a01 gaqhf
            attributesNode = Element('SYMBOLATTRIBUTES')
835 85a460a6 humkyung
            _attrs = self.getAttributes()
836
            for attr in _attrs:
837
                if type(attr) is SymbolAttr:
838
                    _node = attr.toXml()
839
                    _node.text = _attrs[attr]
840
                    attributesNode.append(_node)
841 40db2c6f gaqhf
                elif type(attr) is tuple and type(self) is QEngineeringSpecBreakItem:
842 6a187649 gaqhf
                    attributeNode = Element(attr[0].upper().replace(' ',''))
843
                    attributeNode.text = str(attr[1] if attr[1] is not None else '')
844
                    attributesNode.append(attributeNode)
845 357646b0 gaqhf
846 16ca5a01 gaqhf
            node.append(attributesNode)
847
848 6b99140a gaqhf
            currentPointModeIndexNode = Element('CURRENTPOINTMODEINDEX')
849
            currentPointModeIndexNode.text = str(self.currentPointModeIndex)
850
            node.append(currentPointModeIndexNode)
851 68ce37ea humkyung
        except Exception as ex:
852 85a460a6 humkyung
            from App import App 
853
            message = 'error occured({}) in {}:{}'.format(ex, sys.exc_info()[-1].tb_frame.f_code.co_filename, sys.exc_info()[-1].tb_lineno)
854
            App.mainWnd().addMessage.emit(MessageType.Error, message)
855
856 c82b5644 humkyung
            return None
857 68ce37ea humkyung
858
        return node 
859
860 24015dc6 humkyung
    '''
861 cf1f887b humkyung
        @brief      parse xml code
862
        @author     humkyung
863
        @date       2018.07.20
864
        @history    humkyung 2018.07.20 parse uid from xml node
865 17704fb0 humkyung
                    humkyung 2018.07.23 parse connected item's uid from xml node
866 5da1fdfd gaqhf
                    kyouho  2018.07.31 
867 baf331db humkyung
                    humkyung 2018.09.06 assign area to item
868 cf1f887b humkyung
    '''
869
    @staticmethod 
870
    def fromXml(node):
871
        import uuid
872 0cf624b6 gaqhf
        from EngineeringSpecBreakItem import QEngineeringSpecBreakItem
873 85a460a6 humkyung
        from SymbolAttr import SymbolAttr
874 cf1f887b humkyung
        item = [None, None]
875
876
        try:
877
            uidNode = node.find('UID')
878 7aa3c8e5 gaqhf
            uid = uidNode.text if uidNode is not None else uuid.uuid4() # generate UUID
879 cf1f887b humkyung
880
            pt = [float(x) for x in node.find('LOCATION').text.split(',')]
881
            size = [float(x) for x in node.find('SIZE').text.split(',')]
882
            name = node.find('NAME').text
883
            angle = float(node.find('ANGLE').text)
884 0cf624b6 gaqhf
            _type = node.find('TYPE').text
885 cf1f887b humkyung
            origin = [float(x) for x in node.find('ORIGINALPOINT').text.split(',')]
886
            connPts = []
887
            if node.find('CONNECTIONPOINT').text is not None:
888 4edbb659 humkyung
                for conn_pt in node.find('CONNECTIONPOINT').text.split('/'):
889
                    tokens = conn_pt.split(',')
890
                    connPts.append(('AUTO', float(tokens[0]), float(tokens[1]), '0') if len(tokens) == 2 else \
891
                                   (tokens[0], float(tokens[1]), float(tokens[2]), '0') if len(tokens) == 3 else \
892
                                   (tokens[0], float(tokens[1]), float(tokens[2]), tokens[3]))
893 cf1f887b humkyung
            baseSymbol = node.find('PARENT').text
894
            childSymbolNode = node.find('CHILD')
895
            childSymbol = ''
896
            if childSymbolNode is not None:
897
                childSymbol = childSymbolNode.text
898
            
899
            ownerNode = node.find('OWNER')
900
            owner = ownerNode.text if ownerNode is not None else None
901
902
            hasInstrumentLabelNode = node.find('HASINSTRUMENTLABEL')
903
            hasInstrumentLabel = hasInstrumentLabelNode.text if hasInstrumentLabelNode is not None else 'False'
904
905 789d0d3a esham21
            flipLabelNode = node.find('FLIP')
906 ff096d3a esham21
            flipLabel = int(flipLabelNode.text) if flipLabelNode is not None else 0
907
908 baf331db humkyung
            appDocData = AppDocData.instance()
909
            project = appDocData.getCurrentProject()
910 0cf624b6 gaqhf
            svgFilePath = os.path.join(project.getSvgFilePath(), _type, name + '.svg')
911 cf1f887b humkyung
            if os.path.isfile(svgFilePath):
912 789d0d3a esham21
                item[0] = SymbolSvgItem.createItem(_type, svgFilePath, uid, flip=flipLabel)
913 7765b508 humkyung
                item[0].setVisible(False)
914 0cf624b6 gaqhf
                item[0].buildItem(name, _type, angle, pt, size, origin, connPts, baseSymbol, childSymbol, hasInstrumentLabel)
915 a208ed03 humkyung
916
                for prop_node in node.iter('PROPERTY'):
917
                    matches = [prop for prop in item[0]._properties.keys() if prop.Attribute == prop_node.attrib['Attribute']]
918
                    if matches:
919
                        matches[0].parse_xml(prop_node)
920
                        item[0]._properties[matches[0]] = uuid.UUID(prop_node.text) if prop_node.text and matches[0].is_selectable else prop_node.text if prop_node.text else ''
921 baf331db humkyung
922
                ## assign area
923
                areaNode = node.find('AREA')
924
                if areaNode is None:
925
                    for area in appDocData.getAreaList():
926
                        if area.contains(pt):
927
                            item[0].area = area.name
928
                            break
929
                else:
930
                    item[0].area = areaNode.text
931
                ## up to here
932 5da1fdfd gaqhf
                
933
                connectors = node.find('CONNECTORS')
934
                if connectors is not None:
935
                    iterIndex = 0
936
                    for connector in connectors.iter('CONNECTOR'):
937 f21800ed humkyung
                        item[0].connectors[iterIndex].parse_xml(connector)
938 5da1fdfd gaqhf
                        iterIndex += 1
939
                
940 820ed509 humkyung
                # get associations 
941
                attributeValue = node.find('ASSOCIATIONS')
942 5953ddc1 gaqhf
                if attributeValue is not None:
943 820ed509 humkyung
                    for assoc in attributeValue.iter('ASSOCIATION'):
944
                        _type = assoc.attrib['TYPE']
945
                        if not _type in item[0]._associations:
946
                            item[0]._associations[_type] = []
947
                        item[0]._associations[_type].append(uuid.UUID(assoc.text))
948 4b4d954c humkyung
                # up to here
949 5953ddc1 gaqhf
950 16ca5a01 gaqhf
                attributes = node.find('SYMBOLATTRIBUTES')
951
                if attributes is not None:
952 85a460a6 humkyung
                    for attr in attributes.iter('ATTRIBUTE'):
953
                        _attr = SymbolAttr.fromXml(attr)
954 09cda933 esham21
                        if type(item[0]) is not QEngineeringSpecBreakItem:
955
                            item[0].attrs[_attr] = attr.text
956
                        else:
957 d6971546 esham21
                            if _attr.AttributeType == 'Spec':
958
                                item[0].attrs[_attr] = [attr.text.split(',')[0], attr.text.split(',')[1]]
959 09cda933 esham21
                            elif _attr.Attribute == 'UpStream':
960
                                for initKey in item[0].attrs.keys():
961
                                    if initKey.Attribute == 'UpStream':
962
                                        item[0].attrs[initKey] = attr.text
963
                            elif _attr.Attribute == 'DownStream':
964
                                for initKey in item[0].attrs.keys():
965
                                    if initKey.Attribute == 'DownStream':
966
                                        item[0].attrs[initKey] = attr.text
967 357646b0 gaqhf
                    for attr in attributes.iter('USERINPUTATTRIBUTE'):
968
                        typeUID = attr.find('TYPEUID').text
969
                        typeValue = attr.find('TYPEVALUE').text
970
                        item[0].attrs.append(UserInputAttribute(typeUID, typeValue))
971 16ca5a01 gaqhf
972 6b99140a gaqhf
                currentPointModeIndex = node.find('CURRENTPOINTMODEINDEX')
973
                if currentPointModeIndex is not None:
974
                    item[0].currentPointModeIndex = int(currentPointModeIndex.text)
975 6a187649 gaqhf
976 0cf624b6 gaqhf
                if type(item[0]) is QEngineeringSpecBreakItem:
977 28040f54 gaqhf
                    item[0].connectors[0].setPos((item[0].connectors[0].connectPoint[0], item[0].connectors[0].connectPoint[1]))
978 6a187649 gaqhf
979 cf1f887b humkyung
                item[1] = owner
980
        except Exception as ex:
981 85a460a6 humkyung
            from App import App 
982
            message = 'error occured({}) in {}:{}'.format(ex, sys.exc_info()[-1].tb_frame.f_code.co_filename, sys.exc_info()[-1].tb_lineno)
983
            App.mainWnd().addMessage.emit(MessageType.Error, message)
984 cf1f887b humkyung
985
        return item
986
987
    '''
988 c9c0b30b humkyung
        @brief      create item corresponding to given type
989
        @author     humkyung
990
        @date       2018.05.02
991 bd61ffde 김정우
        @history    2018.05.08  Jeongwoo    Change type name (Piping OPC''S → Piping OPC's)
992 c9c0b30b humkyung
                    humkyung 2018.05.10 change symbol's color to blue
993 bc085959 humkyung
                    humkyung 2018.07.19 create nozzle instance if type is 'Nozzles'
994 24015dc6 humkyung
    '''
995
    @staticmethod
996 190a20fb esham21
    def createItem(type, path, uid=None, flip=0):
997 24015dc6 humkyung
        from QEngineeringOPCItem import QEngineeringOPCItem
998 afabd84e humkyung
        from EngineeringEquipmentItem import QEngineeringEquipmentItem
999 9100a182 humkyung
        from EngineeringInstrumentItem import QEngineeringInstrumentItem
1000 25e0cacb Gyusu
        from EngineeringNozzleItem import QEngineeringNozzleItem
1001 0cf624b6 gaqhf
        from EngineeringSpecBreakItem import QEngineeringSpecBreakItem
1002 96df8663 humkyung
        from EngineeringReducerItem import QEngineeringReducerItem
1003 2605a8f9 esham21
        from EngineeringErrorItem import QEngineeringErrorItem
1004 1312f1fb humkyung
        from AppDocData import AppDocData
1005
1006
        docData = AppDocData.instance()
1007 24015dc6 humkyung
1008
        item = None
1009 1312f1fb humkyung
        cateogry = docData.getSymbolCategoryByType(type)
1010 bd61ffde 김정우
        if type == "Piping OPC's":
1011 d5fe6ee9 esham21
            item = QEngineeringOPCItem(path, uid, flip=flip)
1012 1312f1fb humkyung
        elif cateogry == 'Equipment':
1013 d5fe6ee9 esham21
            item = QEngineeringEquipmentItem(path, uid, flip=flip)
1014 1312f1fb humkyung
        elif cateogry == 'Instrumentation':
1015 d5fe6ee9 esham21
            item = QEngineeringInstrumentItem(path, uid, flip=flip)
1016 bc085959 humkyung
        elif type == 'Nozzles':
1017 d5fe6ee9 esham21
            item = QEngineeringNozzleItem(path, uid, flip=flip)
1018 550cedb9 gaqhf
        elif type == 'Segment Breaks':
1019 d5fe6ee9 esham21
            item = QEngineeringSpecBreakItem(path, uid, flip=flip)
1020 96df8663 humkyung
        elif type == 'Reducers':
1021
            item = QEngineeringReducerItem(path, uid, flip=flip)
1022 2605a8f9 esham21
        elif type == 'Error':
1023 d5fe6ee9 esham21
            item = QEngineeringErrorItem(path, uid, flip=flip)
1024 24015dc6 humkyung
        else:
1025 9aaebab3 esham21
            item = SymbolSvgItem(path, uid, flip=flip)
1026 c9c0b30b humkyung
1027 24015dc6 humkyung
        return item
1028 3216847d humkyung
1029
    '''
1030 ce9281d7 humkyung
        @brief      change svg's color
1031
        @author     humkyung
1032
        @date       2018.05.10
1033 d1576bff 김정우
        @history    2018.05.11  Jeongwoo    Override QEngineeringAbstractItem's
1034 ce9281d7 humkyung
                    humkyung 2018.05.13 update after change color
1035 3216847d humkyung
    '''
1036
    def setColor(self, color):
1037
        self.changeAttributes('fill', color)
1038
        self.changeAttributes('stroke', color)
1039
        self.renderer().load(self._document.toByteArray())
1040 ce9281d7 humkyung
        self.update()
1041 3216847d humkyung
1042 5b782afc 김정우
    def getColor(self):
1043 3ebd61eb humkyung
        """
1044
        return hover color if mouse is over otherwise reutrn owner's color if owner exist else this color
1045
        """
1046
        return SymbolSvgItem.HOVER_COLOR if self.hover else (self.owner._color if self._owner else self._color)
1047 5b782afc 김정우
1048
    '''
1049 f296b1f9 humkyung
        @brief  get attributes from svg file
1050
        @author humkyung
1051
        @date   2019.03.08
1052
    '''
1053
    def get_attribute(self, attName):
1054
        root = self._document.documentElement()
1055
        node = root.firstChild()
1056
        while not node.isNull():
1057
            if node.isElement():
1058
                element = node.toElement()
1059
                if element.hasAttribute(attName):
1060
                    return element.attribute(attName)
1061
1062
                if element.hasChildNodes():
1063
                    att_val = self.recursive_get_attribute(element.firstChild(), attName)
1064
                    if att_val is not None: return att_val
1065
1066
            node = node.nextSibling()
1067
1068
        return None
1069
1070
    '''
1071
        @brief  get recursively attribute
1072
        @author humkyung
1073
        @date   2019.03.08
1074
    '''
1075
    def recursive_get_attribute(self, node, attName):
1076
        while not node.isNull():
1077
            if node.isElement():
1078
                element = node.toElement()
1079
                if element.hasAttribute(attName):
1080
                    return element.attribute(attName)
1081
1082
                if node.hasChildNodes():
1083
                    att_val = self.recursive_get_attribute(node.firstChild(), attName)
1084
                    if att_val is not None: return att_val
1085
            
1086
            node = node.nextSibling()
1087
1088
        return None
1089
1090
    '''
1091 3216847d humkyung
        @brief  change attributes
1092
        @author humkyung
1093
        @date   2018.05.10
1094
    '''
1095
    def changeAttributes(self, attName, attValue):
1096
        root = self._document.documentElement()
1097
        node = root.firstChild()
1098
        while not node.isNull():
1099
            if node.isElement():
1100
                element = node.toElement()
1101
                if element.hasAttribute(attName):
1102
                    element.setAttribute(attName, attValue)
1103
1104
                if element.hasChildNodes():
1105
                    recursiveChangeAttributes(element.firstChild(), attName, attValue)
1106
1107
            node = node.nextSibling()
1108
1109 ef4495fd humkyung
    def setAttribute(self, key, value):
1110
        """
1111
        set attribute with given value
1112
        """
1113
        matches = [attr for attr in self.attrs if attr.UID == key.UID]
1114
        if len(matches) == 1:
1115
            self.attrs[matches[0]] = value
1116
        else:
1117
            self.attrs[key] = value
1118
1119 3216847d humkyung
    '''
1120
        @brief  change attribute
1121
        @author humkyung
1122
        @date   2018.05.10
1123
    '''
1124
    def recursiveChangeAttributes(self, node, attName, attValue):
1125
        while not node.isNull():
1126
            if node.isElement():
1127
                element = node.toElement()
1128
                if element.hasAttribute(attName):
1129
                    element.setAttribute(attName, attValue)
1130
1131
                if node.hasChildNodes():
1132
                    recursiveChangeAttributes(node.firstChild(), attName, attValue)
1133
            
1134
            node = node.nextSibling()
1135 6d6ad72f humkyung
1136
    '''
1137
        @brief  draw rect when item is selected
1138
        @author humkyung
1139
        @date   2018.07.07
1140
    '''
1141
    def drawFocusRect(self, painter):
1142
        self.focuspen = QPen(Qt.DotLine)
1143
        self.focuspen.setColor(Qt.black)
1144
        self.focuspen.setWidthF(1.5)
1145
        hilightColor = QColor(255, 0, 0, 127)
1146
        painter.setBrush(QBrush(hilightColor))
1147
        painter.setPen(self.focuspen)
1148
        painter.drawRect(self.boundingRect())
1149
1150 24015dc6 humkyung
    '''
1151 3a4cc147 humkyung
        @brief  override paint(draw connection points)
1152
        @author humkyung
1153
        @date   2018.04.21
1154
    '''
1155
    def paint(self, painter, options=None, widget=None):
1156 3ebd61eb humkyung
        from EngineeringAbstractItem import QEngineeringAbstractItem
1157
        from EngineeringTextItem import QEngineeringTextItem
1158
1159
        self.setColor(self.getColor())
1160
1161 b9334e15 humkyung
        painter.setClipRect(options.exposedRect)
1162 3a4cc147 humkyung
        QGraphicsSvgItem.paint(self, painter, options, widget)
1163 3ebd61eb humkyung
        for attr in self.attrs:
1164
            if issubclass(type(attr), QEngineeringTextItem):
1165
                color = QEngineeringAbstractItem.HOVER_COLOR if self.hover else (self._owner._color if self._owner else QEngineeringAbstractItem.DEFAULT_COLOR)
1166
                attr.setColor(color)
1167
            elif issubclass(type(attr), SymbolSvgItem):
1168
                attr.setColor(self.getColor())
1169
                attr.update()
1170
1171 6d6ad72f humkyung
        if self.isSelected():
1172
            self.drawFocusRect(painter)
1173 a67b3200 김정우
1174
    '''
1175 d7080855 humkyung
        @brief      Add Svg Item into ImageViewer's Scene
1176
        @author     Jeongwoo
1177
        @date       2018.05.03
1178
        @history    add connectors which's parent is symbol
1179 d4c444bd gaqhf
                    kyouho  2018.07.30  remove connectors logic
1180 a67b3200 김정우
    '''
1181
    def addSvgItemToScene(self, scene):
1182
        transform = QTransform()
1183 9aaebab3 esham21
        #print(self.symbolOrigin)
1184 48662961 esham21
1185 d7ddc5c0 gaqhf
        transform.translate(self.loc[0] + self.symbolOrigin[0], self.loc[1] + self.symbolOrigin[1])
1186 e720020e gaqhf
        transform.rotateRadians(-self.angle)
1187 6b99140a gaqhf
        currentPoint = self.getCurrentPoint()
1188 d7ddc5c0 gaqhf
        transform.translate(-currentPoint[0], -currentPoint[1])
1189 6b99140a gaqhf
1190 9aaebab3 esham21
        if self.flip is 1:
1191
            transform.scale(-1.0, 1.0)
1192
            transform.translate(-self.size[0], 0)
1193 48662961 esham21
            #allowed_error = 0.01
1194
            #if abs(self.angle - 0) <= allowed_error or abs(self.angle - 3.14) <= allowed_error:
1195
            #    transform.translate(-self.size[0], 0)
1196
            #elif abs(self.angle - 1.57) <= allowed_error:
1197
            #    transform.translate(0, 0)
1198
            #else:
1199
            #    transform.translate(0, 0)
1200 9aaebab3 esham21
1201 a67b3200 김정우
        self.setTransform(transform)
1202 3216847d humkyung
        scene.addItem(self)
1203 d4c444bd gaqhf
1204 57ab567c humkyung
1205 a3a805a0 김정우
    '''
1206 0c37eaa7 humkyung
        @brief      
1207
        @author     humkyung
1208
        @date       2018.07.27
1209
    '''
1210
    def onConnectorPosChaned(self, connector):
1211
        pass
1212
1213
    '''
1214 09817c8c gaqhf
        @brief      set connector
1215
        @author     kyouho
1216
        @date       2018.07.26
1217
    '''
1218
    def setConnector(self):
1219 1efd2d2e humkyung
        connector = QEngineeringConnectorItem(parent=self)
1220 740725ef gaqhf
        connector.setParentItem(self)
1221
        self.connectors.append(connector)
1222 09817c8c gaqhf
1223
    '''
1224
    '''
1225
    def refreshConnector(self):
1226
        for connector in self.connectors:
1227
            connector.buildItem()
1228
1229
    '''
1230 a3a805a0 김정우
        @brief      Delete svg item
1231
        @author     Jeongwoo
1232
        @date       2018.05.25
1233
    '''
1234
    def deleteSvgItemFromScene(self):
1235 740725ef gaqhf
        for connector in self.connectors:
1236
            if connector.connectedItem is not None:
1237 6ec2ea86 esham21
                try:
1238
                    connector.connectedItem.removeSymbol(self)
1239 853c2faf esham21
                except Exception as ex:
1240 cfff1a70 esham21
                    from App import App
1241
                    from AppDocData import MessageType
1242
1243
                    message = 'error occured({}) in {}:{}'.format(ex, sys.exc_info()[-1].tb_frame.f_code.co_filename, sys.exc_info()[-1].tb_lineno)
1244
                    App.mainWnd().addMessage.emit(MessageType.Error, message)
1245 a3a805a0 김정우
                break
1246
1247 d7080855 humkyung
        self.transfer.onRemoved.emit(self)
1248 a3a805a0 김정우
        
1249
    '''
1250
        @brief      Return real item position
1251
        @author     Jeongwoo
1252
        @date       2018.05.25
1253
    '''
1254
    def boundingRectOnScene(self):
1255
        rect = self.boundingRect()
1256
        rect.moveTo(self.loc[0], self.loc[1])
1257
        return rect
1258 3216847d humkyung
1259 853c2faf esham21
    def flipSymbol(self):
1260
        '''
1261
            @brief  remove item when user press delete key
1262
            @author humkyung
1263
            @date   2018.04.23
1264
        '''
1265
        if self.flip is 0:
1266
            self.flip = 1
1267
        else:
1268
            self.flip = 0
1269
1270
        currentPoint = self.getCurrentPoint()
1271
        self.reSettingSymbol(currentPoint, self.angle)
1272
1273 53fa5967 gaqhf
    '''
1274
        @brief      rotate Symbol
1275
        @author     kyouho
1276
        @date       2018.07.24
1277
    '''
1278 6d715a6e esham21
    def rotateSymbol(self, angle=None):
1279
        if angle is None:
1280
            #degree 0
1281
            if 0 == self.angle:
1282
                self.angle = 1.57
1283
            #degree 90
1284
            elif (1.57 == self.angle):
1285
                self.angle = 3.14
1286
            #degree 180
1287
            elif 3.14 == self.angle:
1288
                self.angle = 4.71
1289
            #degree 270
1290
            elif 4.71 == self.angle :
1291
                self.angle = 0
1292 223f4e6c esham21
            else:
1293
                self.angle = 0
1294 6d715a6e esham21
        else:
1295
            self.angle = angle
1296 53fa5967 gaqhf
1297 48662961 esham21
        self.size[0], self.size[1] = self.size[1], self.size[0]
1298
        
1299 853c2faf esham21
        scene = self.scene()
1300
        #self.scene().removeItem(self)
1301
        #self.addSvgItemToScene(scene)
1302 295aef89 gaqhf
        currentPoint = self.getCurrentPoint()
1303
        self.reSettingSymbol(currentPoint, self.angle)
1304 53fa5967 gaqhf
1305
    '''
1306
        @brief      resetting rotate Symbol
1307
        @author     kyouho
1308
        @date       2018.07.24
1309
    '''
1310 295aef89 gaqhf
    def reSettingSymbol(self, standardPoint, angle):
1311 53fa5967 gaqhf
        transform = QTransform()
1312 295aef89 gaqhf
        
1313 d7ddc5c0 gaqhf
        transform.translate(self.loc[0] + self.symbolOrigin[0], self.loc[1] + self.symbolOrigin[1])
1314 e720020e gaqhf
        transform.rotateRadians(-angle)
1315 d7ddc5c0 gaqhf
        transform.translate(-standardPoint[0], -standardPoint[1])
1316 53fa5967 gaqhf
1317 853c2faf esham21
        if self.flip is 1:
1318
            transform.scale(-1.0, 1.0)
1319
            transform.translate(-self.size[0], 0)
1320
1321 53fa5967 gaqhf
        self.setTransform(transform)
1322 6104131e gaqhf
1323 0ebafb60 gaqhf
        from EngineeringLineItem import QEngineeringLineItem
1324
        for connector in self.connectors:
1325
            if connector.connectedItem is not None and type(connector.connectedItem) == QEngineeringLineItem:
1326
                line = connector.connectedItem
1327
                line.reDrawLine(self, connector.center())
1328 295aef89 gaqhf
1329 8c3a7bc6 gaqhf
1330
    '''
1331
        @brief      change Conn point 
1332
        @author     kyouho
1333
        @date       2018.07.25
1334
    '''
1335
    def changeConnPoint(self):
1336 0ebafb60 gaqhf
        if len(self.connectors) == 2:
1337
1338
            conn1Item = self.connectors[0].connectedItem
1339
            conn2Item = self.connectors[1].connectedItem
1340
            self.connectors[0].connectedItem = conn2Item
1341
            self.connectors[1].connectedItem = conn1Item
1342
1343
            currentPoint = self.getCurrentPoint()
1344
            self.reSettingSymbol(currentPoint, self.angle)
1345 8c3a7bc6 gaqhf
1346 53fa5967 gaqhf
    '''
1347
        @brief      change standard point
1348
        @author     kyouho
1349
        @date       2018.07.24
1350
    '''
1351
    def changeStandardPoint(self):
1352 740725ef gaqhf
        connPtsCount = len(self.connectors)
1353 53fa5967 gaqhf
        
1354
        if self.currentPointModeIndex < connPtsCount:
1355
            self.currentPointModeIndex += 1
1356
        else:
1357
            self.currentPointModeIndex = 0
1358
1359 295aef89 gaqhf
        currentPoint = self.getCurrentPoint()
1360
        self.reSettingSymbol(currentPoint, self.angle)
1361
    
1362
    '''
1363
        @brief      get standard point
1364
        @author     kyouho
1365
        @date       2018.07.25
1366
    '''
1367
    def getCurrentPoint(self):
1368 d7ddc5c0 gaqhf
        from EngineeringSpecBreakItem import QEngineeringSpecBreakItem
1369
1370 53fa5967 gaqhf
        pointList = []
1371 295aef89 gaqhf
        pointList.append(self.symbolOrigin)
1372 740725ef gaqhf
        for connector in self.connectors:
1373
            pointList.append(connector.connectPoint)
1374 53fa5967 gaqhf
1375 d7ddc5c0 gaqhf
        if type(self) is QEngineeringSpecBreakItem:
1376
            self.currentPointModeIndex = 1
1377
1378 295aef89 gaqhf
        return pointList[self.currentPointModeIndex]
1379 53fa5967 gaqhf
1380 e720020e gaqhf
    '''
1381
        @brief      심볼 회전 시 서로 다른 기준점으로 회전하기 때문에 기준점을 이후 개발한 SymbolSvgItem 기준의 회전좌표로 이동하기 위해서 만듬 (loc 기준으로 회전해야함)
1382
        @author     kyouho
1383
        @date       18.08.06
1384
    '''
1385
    def reCalculationRotatedItem(self):
1386
1387
        transform = QTransform()
1388 dda5aa49 gaqhf
        transform.translate(self.loc[0] + self.symbolOrigin[0], self.loc[1] + self.symbolOrigin[1])
1389 e720020e gaqhf
        transform.rotateRadians(-self.angle)
1390 21a1712e gaqhf
        currentPoint = self.getCurrentPoint()
1391 dda5aa49 gaqhf
        transform.translate(-currentPoint[0], -currentPoint[1])
1392
        # 시작점을 구하기 위해서
1393
        goPoint = transform.map(QPoint(self.symbolOrigin[0], self.symbolOrigin[1]))
1394 21a1712e gaqhf
        
1395 dda5aa49 gaqhf
        self.loc = [self.loc[0] + self.origin[0] - goPoint.x(), self.loc[1] + self.origin[1] - goPoint.y()]
1396 e720020e gaqhf
1397 53fa5967 gaqhf
1398 3216847d humkyung
def recursiveChangeAttributes(node, attName, attValue):
1399
    while not node.isNull():
1400
        if node.isElement():
1401
            element = node.toElement()
1402
            if element.hasAttribute(attName):
1403
                element.setAttribute(attName, attValue)
1404
1405
            if node.hasChildNodes():
1406
                recursiveChangeAttributes(node.firstChild(), attName, attValue)
1407
        
1408
        node = node.nextSibling()
1409
1410 d7080855 humkyung
'''
1411
    @brief      The class transfer pyqtSignal Event. Cause Subclass of QGraphicsRectItem can't use pyqtSignal
1412
    @author     Jeongwoo
1413
    @date       2018.06.18
1414
'''
1415
class Transfer(QObject):
1416
    onRemoved = pyqtSignal(QGraphicsItem)
1417
1418
    def __init__(self, parent = None):
1419
        QObject.__init__(self, parent)
1420
1421 3216847d humkyung
1422
if __name__ == '__main__':
1423
    f = QFile('d:/Projects/DTIPID/DTI_PID/DTI_PID/SG_TEST/svg/ANGLE VALVE.svg')
1424
    f.open(QIODevice.ReadOnly)
1425
    array = f.readAll()
1426
    document = QDomDocument()
1427
    document.setContent(array)
1428
1429
    root = document.documentElement()
1430
    node = root.firstChild()
1431
    while not node.isNull():
1432
        if node.isElement():
1433
            element = node.toElement()
1434
            if element.hasAttribute('fill'):
1435
                element.setAttribute('fill', '#FFFFF')
1436
1437
            if element.hasChildNodes():
1438
                recursiveChangeAttributes(element.firstChild(), 'fill', '#FFFFF')
1439
1440 0de326cb humkyung
        node = node.nextSibling()
클립보드 이미지 추가 (최대 크기: 500 MB)