프로젝트

일반

사용자정보

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

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

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

1
#!/usr/bin/env/python3
2
# coding: utf-8
3

    
4
import sys
5
import os
6
import math
7
from PyQt5.QtGui import *
8
from PyQt5.QtCore import *
9
from PyQt5.QtSvg import *
10
from PyQt5.QtWidgets import (QApplication, QGraphicsItem)
11
from PyQt5.QtXml import *
12

    
13
from AppDocData import *
14
from EngineeringConnectorItem import QEngineeringConnectorItem
15
from EngineeringAbstractItem import QEngineeringAbstractItem
16
from EngineeringConnectorItem import QEngineeringConnectorItem
17
from UserInputAttribute import UserInputAttribute
18
import SelectAttributeCommand
19

    
20
class SymbolSvgItem(QGraphicsSvgItem, QEngineeringAbstractItem):
21
    """ This is symbolsvgitem class """
22

    
23
    clicked = pyqtSignal(QGraphicsSvgItem)
24
    ZVALUE = 50
25
    HOVER_COLOR = 'url(#hover)'
26

    
27
    '''
28
        @history    18.04.11    Jeongwoo    Add Variable (Name, Type)
29
                    18.05.11    Jeongwoo    Declare variable self.color
30
                    18.05.25    Jeongwoo    Call setColor() method
31
                    18.05.30    Jeongwoo    Add self variables (parentSymbol, childSymbol)
32
    '''
33
    def __init__(self, path, uid=None, flip=0):
34
        import uuid
35
        from SymbolAttr import SymbolProp
36

    
37
        QGraphicsSvgItem.__init__(self)
38
        QEngineeringAbstractItem.__init__(self)
39

    
40
        self.setFlags(QGraphicsItem.ItemIsSelectable|QGraphicsItem.ItemIsFocusable)#|QGraphicsItem.ItemIsMovable)
41

    
42
        self.uid = uuid.uuid4() if uid is None else uuid.UUID(uid, version=4)
43
        self.name = ''
44
        self.type = ''
45
        self.angle = 0
46
        self.origin = None
47
        self.loc = None
48
        self.size = None
49
        self._owner = None
50
        self.parentSymbol = ''
51
        self.childSymbol = '' 
52
        self.hasInstrumentLabel = 0
53
        self.flip = flip
54
        # attributeType uid
55
        self.attribute = ''
56
        self._properties = {SymbolProp(None, 'Supplied By', 'String'):None}
57
        
58
        self.setAcceptDrops(True)
59
        self.setAcceptHoverEvents(True)
60
        self.setAcceptedMouseButtons(Qt.LeftButton)
61
        self.setAcceptTouchEvents(True)
62
        
63
        self.currentCursor = 0
64
        self.transfer = Transfer()
65

    
66
        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

    
75
            self._color = self.get_attribute('fill')
76
        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

    
81
        self.setZValue(SymbolSvgItem.ZVALUE)
82

    
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
    '''
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
        @history    2018.05.17  Jeongwoo    Add Calling setColor if self._owner is None or not
101
    '''
102
    @owner.setter
103
    def owner(self, value):
104
        self._owner = value
105

    
106
        if self._owner is None:
107
            self._color = self.DEFAULT_COLOR
108
        self.setColor(self._color)
109

    
110
    @property
111
    def properties(self):
112
        """ getter of properties """
113
        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
        return self._properties
121

    
122
    @properties.setter
123
    def properties(self, value):
124
        """ setter of properties """
125
        self._properties = value
126

    
127
    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
    def validate(self):
133
        '''
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
        from EngineeringSpecBreakItem import QEngineeringSpecBreakItem
141
        errors = []
142
        if type(self) is QEngineeringSpecBreakItem:
143
            return errors
144
        docdata = AppDocData.instance()
145
        dataPath = docdata.getErrorItemSvgPath()
146
        origin = [int(pt) for pt in docdata.getAppConfigs('app', 'error origin point')[0].value.split(',')]
147
        
148
        # check flow for 2 connection point symbol
149
        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

    
161
        # check disconnected point
162
        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
        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
        #denominator = len(errors) + 1
181
        #molecule = 1
182
        for error in errors:
183
            error.setPosition([self.sceneBoundingRect().center().x(), self.sceneBoundingRect().center().y()], origin)
184
            #molecule = molecule + 1
185
        
186
        return errors
187

    
188
    def includes(self, pt, margin=0):
189
        """
190
        return True if symbol contains given point else return False
191
        """
192
        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

    
198
        return True if (pt[0] >= minX and pt[0] <= maxX and pt[1] >= minY and pt[1] <= maxY) else False
199

    
200
    def associations(self):
201
        """
202
        return associated instance
203
        """
204
        import uuid
205

    
206
        res = []
207
        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
                    matches = [x for x in self.scene().items() if hasattr(x, 'uid') and str(x.uid) == str(assoc)]
212
                    if matches: res.append(matches[0]) # TODO: need to update association with instance
213
                # up to here
214
                elif assoc:
215
                    res.append(assoc)
216

    
217
        return res
218

    
219
    def texts(self):
220
        """
221
        return text type of associations
222
        """
223
        from EngineeringTextItem import QEngineeringTextItem
224

    
225
        return [x for x in self.associations() if issubclass(type(x), QEngineeringTextItem)]
226

    
227
    def symbols(self):
228
        """
229
        return symbol type of associations
230
        """
231
        return [x for x in self.associations() if issubclass(type(x), SymbolSvgItem)]
232

    
233
    def toSql(self):
234
        """
235
        convert valve data to sql query
236
        """
237
        import uuid
238
        from AppDocData import AppDocData
239

    
240
        res = []
241
        appDocData = AppDocData.instance()
242

    
243
        cols = ['UID', 'ITEM_NO', 'PNID_NO']
244
        values = ['?','?','?']
245
        param = [str(self.uid), self.name, appDocData.activeDrawing.name]
246
        sql = 'insert or replace into VALVE_DATA_LIST({}) values({})'.format(','.join(cols), ','.join(values))
247
        res.append((sql, tuple(param)))
248

    
249
        _attrs = self.getAttributes()
250
        for key in _attrs.keys():
251
            cols = ['UID', 'Components_UID', 'SymbolAttribute_UID', 'Value']
252
            values = ['?', '?', '?', '?']
253
            param = [str(uuid.uuid4()), str(self.uid), key.UID, _attrs[key]]
254

    
255
            sql = 'insert or replace into Attributes({}) values({})'.format(','.join(cols), ','.join(values))
256
            res.append((sql, tuple(param)))
257

    
258
        # save connectors to database
259
        for connector in self.connectors:
260
            res.append(connector.toSql())
261
        # up to here
262

    
263
        return res
264

    
265
    '''
266
        @brief  build symbol item
267
        @author humkyung
268
        @date   2018.05.02
269
        @history    2018.05.09  Jeongwoo    Clear self.connectors
270
                    2018.05.30  Jeongwoo    Add parameters (parentSymbol, childSymbol)
271
    '''
272
    def buildItem(self, name, _type, angle, loc, size, origin, connPts, parentSymbol, childSymbol, hasInstrumentLabel):
273
        try:
274
            docData = AppDocData.instance()
275
            self.name = name
276
            self.type = _type
277
            self.angle = angle
278
            self.loc = loc
279
            self.size = size
280
            self.origin = origin
281
            symbolInfo = docData.getSymbolByQuery('name', name)
282
            originalPoint = symbolInfo.getOriginalPoint().split(',')
283
            self.symbolOrigin = [float(originalPoint[0]), float(originalPoint[1])]
284
            if self.flip is 1:
285
                self.symbolOrigin[0] = self.size[0] - self.symbolOrigin[0]
286

    
287
            # setting connectors
288
            connectionPoints = symbolInfo.getConnectionPoint().split('/')
289
            #print(connectionPoints)
290
            for index in range(len(connectionPoints)):
291
                if connectionPoints[index] == '':
292
                    break
293
                tokens = connectionPoints[index].split(',')
294

    
295
                direction = 'AUTO'
296
                symbol_idx = '0'
297
                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
                elif len(tokens) == 4:
305
                    direction = tokens[0]
306
                    x = float(tokens[1])
307
                    y = float(tokens[2])
308
                    symbol_idx = tokens[3]
309

    
310
                self.setConnector()
311
                self.connectors[index].direction = direction
312
                self.connectors[index].symbol_idx = symbol_idx
313
                self.connectors[index].setPos((x, y))
314
                self.connectors[index].connectPoint = (x, y)
315
                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
                
319
            self.parentSymbol = parentSymbol
320
            self.childSymbol = childSymbol
321
            self.hasInstrumentLabel = hasInstrumentLabel
322
            self.currentPointModeIndex = 0
323

    
324
            tooltip = '<b>{}</b><br>{}={}'.format(str(self.uid), self.type, self.name)
325
            self.setToolTip(tooltip)
326
        except Exception as ex:
327
            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

    
332
    '''
333
        @brief  return bounding box of symbol
334
        @author humkyung
335
        @date   2018.04.08
336
    '''
337
    def rect(self):
338
        return self.sceneBoundingRect()
339
        
340
    '''
341
        @brief  return true if line is able to connect symbol
342
        @author humkyung
343
        @date   2018.04.13
344
    '''
345
    def is_connectable(self, line, toler=10):
346
        start_pt = line.startPoint()
347
        end_pt = line.endPoint()
348
        for connector in self.connectors:
349
            dx = connector.sceneConnectPoint[0] - (start_pt[0])
350
            dy = connector.sceneConnectPoint[1] - (start_pt[1])
351
            if (math.sqrt(dx*dx + dy*dy) < toler): return True
352
            dx = connector.sceneConnectPoint[0] - (end_pt[0])
353
            dy = connector.sceneConnectPoint[1] - (end_pt[1])
354
            if (math.sqrt(dx*dx + dy*dy) < toler): return True
355

    
356
        return False
357
 
358
    '''
359
        @author     humkyung
360
        @date       2018.07.03
361
    '''
362
    def is_connected(self, item, at=QEngineeringAbstractItem.CONNECTED_AT_PT):
363
        """ check if given item is connected to self """
364

    
365
        _connectors = [connector for connector in self.connectors if (connector.connectedItem == item and (connector._connected_at == at if at else True))]
366
        return len(_connectors) > 0
367

    
368
    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
    '''
379
        @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
                    Jeongwoo 2018.05.15 Connect each symbol and line
384
    '''
385
    def connect_if_possible(self, obj, toler=10):
386
        from shapely.geometry import Point
387
        from EngineeringLineItem import QEngineeringLineItem
388

    
389
        res = []
390
        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
                        if self.connectors[i].connectedItem is None:
397
                            self.connectors[i].connect(obj)
398
                        if obj.connectors[0].connectedItem is None:
399
                            obj.connectors[0].connect(self)
400
                        
401
                        res.append(obj)
402
                    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
                            self.connectors[i].connect(obj)
405
                        if obj.connectors[1].connectedItem is None:
406
                            obj.connectors[1].connect(self)
407
                        
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
                                self.connectors[i].connect(obj)
416
                            if obj.connectors[j].connectedItem is None:
417
                                obj.connectors[j].connect(self)
418

    
419
                            res.append(obj)
420
        except Exception as ex:
421
            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

    
425
        return res
426

    
427
    '''
428
        @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
        @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
        for connector in self.connectors:
446
            dx = connector.sceneConnectPoint[0] - pt[0]
447
            dy = connector.sceneConnectPoint[1] - pt[1]
448
            if math.sqrt(dx*dx + dy*dy) < toler: return connPt
449
            
450
        return None
451

    
452
    '''
453
        @brief  return center of symbol
454
        @author humkyung
455
        @date   2018.04.08
456
    '''
457
    def center(self):
458
        return self.sceneBoundingRect().center()
459
        
460
    '''
461
        @brief      highlight connector and attribute
462
        @authro     humkyung
463
        @date       2018.05.02
464
    '''
465
    def hoverEnterEvent(self, event):
466
        try:
467
            self.hover = True
468
            self.update()
469

    
470
            for assoc in self.associations():
471
                assoc.hoverEnterEvent(event)
472
        except Exception as ex: 
473
            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

    
477
    '''
478
        @brief      unhighlight connector and attribute
479
        @author     humkyung
480
        @date       2018.05.02
481
        @history    kyouho 2018.07.18 edit ArrowCursor
482
    '''
483
    def hoverLeaveEvent(self, event):
484
        self.hover = False
485
        self.update()
486

    
487
        for assoc in self.associations():
488
            assoc.hoverLeaveEvent(event)
489

    
490
    '''
491
        @brief      set highlight
492
        @author     kyouho
493
        @date       2018.08.27
494
    '''
495
    def setHightlight(self):
496
        self.setColor('url(#hover)')
497
        self.update()
498

    
499
    '''
500
        @brief      unset highlight
501
        @author     kyouho
502
        @date       2018.08.27
503
    '''
504
    def unsetHightlight(self):
505
        self.setColor('url(#normal)')
506
        self.update()
507

    
508
    '''
509
        @brief  change cursor to CrossCursor if mouse point is close to connection point
510
        @author humkyung
511
        @date   2018.04.28
512
    '''
513
    def hoverMoveEvent(self, event):
514
        pass
515

    
516
    '''
517
        @brief      Mouse Press Event
518
        @author     Jeongwoo
519
        @date       18.04.11
520
        @history    kyouho 2018.07.18 add isClick logic
521
    '''
522
    def mousePressEvent(self, event):
523
        if event.buttons() == Qt.LeftButton:
524
            self.clicked.emit(self)
525

    
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
    #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
    def removeSelfAttr(self, attributeName):
547
        for attr in self.attrs:
548
            if attr.Attribute == attributeName:
549
                del self.attrs[attr]
550

    
551
    '''
552
        @brief      Find TextItem contain Point
553
        @author     kyouho
554
        @date       18.07.17
555
    '''
556
    def findTextItemInPoint(self, point):
557
        from EngineeringTextItem import QEngineeringTextItem
558
        
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

    
568
    '''
569
        @brief      Check Overlap
570
        @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
            if issubclass(type(symbol), SymbolSvgItem):
593
                for attr in symbol.attrs:
594
                    if attr == item:
595
                        symbol.attrs.remove(item)
596

    
597
    '''
598
        @brief  remove item when user press delete key
599
        @author humkyung
600
        @date   2018.04.23
601
        @history    2018.05.17  Jeongwoo    Add if-statement and move 'break'
602
                    2018.05.25  Jeongwoo    Seperate delete item method
603
    '''
604
    def keyPressEvent(self, event):
605
        if self.isSelected() and event.key() == Qt.Key_Delete:
606
            self.deleteSvgItemFromScene()
607
        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
        elif event.key() == Qt.Key_F:
614
            self.flipSymbol()
615
           
616
    '''
617
        @brief      connect attribute
618
        @author     humkyung
619
        @date       2018.05.02
620
        @history    humkyung 2018.05.09 append only nearest size attribute
621
    '''
622
    def connectAttribute(self, attributes, clear=True):
623
        import math
624
        from EngineeringTextItem import QEngineeringTextItem
625
        from QEngineeringSizeTextItem import QEngineeringSizeTextItem
626
        from EngineeringInstrumentItem import QEngineeringInstrumentItem
627
        from EngineeringValveOperCodeTextItem import QEngineeringValveOperCodeTextItem
628

    
629
        if clear:
630
            self.attrs.clear()
631
            self._associations.clear()
632

    
633
        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
                if type(attr) is QEngineeringSizeTextItem or type(attr) is QEngineeringValveOperCodeTextItem or type(attr) is QEngineeringTextItem:
641
                    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
                elif type(attr) is QEngineeringInstrumentItem:
648
                    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

    
654
            if selected is not None:
655
                self.add_assoc_item(selected)
656

    
657
        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

    
662
    '''
663
        @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
        dialog = QRotateSymbolDialog(None, self.angle)
670
        (isAccept, angle) = dialog.showDialog()
671
  
672
        if isAccept:
673
            self.rotateSymbol(angle)
674

    
675
    '''
676
        @brief      get attribute
677
        @author     humkyung
678
        @date       2018.06.14
679
        @history    kyouho  2018.07.18  Add only attr QEngineeringTextItem
680
    '''
681
    def getAttributes(self):
682
        _attrs = {}
683
        try:
684
            from AppDocData import AppDocData
685
            from EngineeringAbstractItem import QEngineeringAbstractItem
686
            from EngineeringTextItem import QEngineeringTextItem
687
            from EngineeringValveOperCodeTextItem import QEngineeringValveOperCodeTextItem
688

    
689
            # 해당 Type의 attribute setting
690
            docData = AppDocData.instance()
691
            symbolAttrs = docData.getSymbolAttribute(self.type)
692

    
693
            _texts = self.texts()
694
            _symbols = self.symbols()
695
            for attr in symbolAttrs:
696
                if attr.AttributeType == 'Size Text Item' or attr.AttributeType == 'Text Item' or attr.AttributeType == 'Valve Oper Code':
697
                    at = int(attr.AttrAt)
698
                    items = [text for text in _texts if QEngineeringAbstractItem.assoc_type(text) == attr.AttributeType]
699
                    if len(items) > at:
700
                        item = items[at]
701
                        _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
                    if len(_symbols) > at:
707
                        item = _symbols[at]
708
                        _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
        
724
        return _attrs
725

    
726
    '''
727
        @brief      generate xml code
728
        @author     humkyung
729
        @date       2018.04.23
730
        @history    humkyung 2018.04.25 add angle xml node
731
                    humkyung 2018.04.27 add originalpoint xml node
732
                    humkyung 2018.05.02 add attribute of symbol
733
                    Jeongwoo 2018.05.30 add attribute of symbol (parentSymbol, childSymbol, type, connectionPoint)
734
                    yecheol  2018.07.11 add attribute of symbol (hasInstrumentLabel)
735
                    humkyung 2018.07.20 write owner's uid to xml
736
                    humkyung 2018.07.23 write connected item's uid to xml
737
                    kyouho  2018.07.31 
738
                    humkyung 2018.09.06 write area to xml
739
    '''
740
    def toXml(self):
741
        from xml.etree.ElementTree import Element, SubElement, dump, ElementTree
742
        from EngineeringAbstractItem import QEngineeringAbstractItem
743
        from EngineeringTextItem import QEngineeringTextItem
744
        from EngineeringSpecBreakItem import QEngineeringSpecBreakItem
745
        from SymbolAttr import SymbolAttr
746

    
747
        try:
748
            node = Element('SYMBOL')
749
            uidNode = Element('UID')
750
            uidNode.text = str(self.uid)
751
            node.append(uidNode)
752

    
753
            nameNode = Element('NAME')
754
            nameNode.text = self.name
755
            node.append(nameNode)
756

    
757
            attributeValueNode = Element('ASSOCIATIONS')
758
            for assoc in self.associations():
759
                assoc_node = Element('ASSOCIATION')
760
                assoc_node.attrib['TYPE'] = QEngineeringAbstractItem.assoc_type(assoc)
761
                assoc_node.text = str(assoc.uid)
762
                attributeValueNode.append(assoc_node)
763
            node.append(attributeValueNode)
764

    
765
            typeNode = Element('TYPE')
766
            typeNode.text = self.type
767
            node.append(typeNode)
768

    
769
            # 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
            originNode = Element('ORIGINALPOINT')
777
            originNode.text = '{},{}'.format(self.origin[0], self.origin[1])
778
            node.append(originNode)
779

    
780
            connectorsNode = Element('CONNECTORS')
781
            for connector in self.connectors:
782
                connectorsNode.append(connector.toXml())
783
            node.append(connectorsNode)
784

    
785
            connectionNode = Element('CONNECTIONPOINT')
786
            connection_point = []
787
            if self.connectors is not None:
788
                for connector in self.connectors:
789
                    connection_point.append(repr(connector))
790
            connectionNode.text = '/'.join(connection_point)
791
            node.append(connectionNode)
792

    
793
            rect = self.sceneBoundingRect()
794
            locNode = Element('LOCATION')
795
            locNode.text = '{},{}'.format(self.loc[0], self.loc[1])
796
            node.append(locNode)
797

    
798
            sizeNode = Element('SIZE')
799
            #sizeNode.text = '{},{}'.format(rect.width(), rect.height())
800
            sizeNode.text = '{},{}'.format(self.size[0], self.size[1])
801
            node.append(sizeNode)
802

    
803
            angleNode = Element('ANGLE')
804
            angleNode.text = str(self.angle)
805
            node.append(angleNode)
806

    
807
            parentSymbolNode = Element('PARENT')
808
            parentSymbolNode.text = str(self.parentSymbol)
809
            node.append(parentSymbolNode)
810

    
811
            childSymbolNode = Element('CHILD')
812
            childSymbolNode.text = str(self.childSymbol)
813
            node.append(childSymbolNode)
814

    
815
            hasInstrumentLabelNode = Element('HASINSTRUMENTLABEL')
816
            hasInstrumentLabelNode.text = str(self.hasInstrumentLabel)
817
            node.append(hasInstrumentLabelNode)
818

    
819
            areaNode = Element('AREA')
820
            areaNode.text = self.area
821
            node.append(areaNode)
822

    
823
            flipNode = Element('FLIP')
824
            flipNode.text = str(self.flip)
825
            node.append(flipNode)
826
            
827
            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

    
834
            attributesNode = Element('SYMBOLATTRIBUTES')
835
            _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
                elif type(attr) is tuple and type(self) is QEngineeringSpecBreakItem:
842
                    attributeNode = Element(attr[0].upper().replace(' ',''))
843
                    attributeNode.text = str(attr[1] if attr[1] is not None else '')
844
                    attributesNode.append(attributeNode)
845

    
846
            node.append(attributesNode)
847

    
848
            currentPointModeIndexNode = Element('CURRENTPOINTMODEINDEX')
849
            currentPointModeIndexNode.text = str(self.currentPointModeIndex)
850
            node.append(currentPointModeIndexNode)
851
        except Exception as ex:
852
            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
            return None
857

    
858
        return node 
859

    
860
    '''
861
        @brief      parse xml code
862
        @author     humkyung
863
        @date       2018.07.20
864
        @history    humkyung 2018.07.20 parse uid from xml node
865
                    humkyung 2018.07.23 parse connected item's uid from xml node
866
                    kyouho  2018.07.31 
867
                    humkyung 2018.09.06 assign area to item
868
    '''
869
    @staticmethod 
870
    def fromXml(node):
871
        import uuid
872
        from EngineeringSpecBreakItem import QEngineeringSpecBreakItem
873
        from SymbolAttr import SymbolAttr
874
        item = [None, None]
875

    
876
        try:
877
            uidNode = node.find('UID')
878
            uid = uidNode.text if uidNode is not None else uuid.uuid4() # generate UUID
879

    
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
            _type = node.find('TYPE').text
885
            origin = [float(x) for x in node.find('ORIGINALPOINT').text.split(',')]
886
            connPts = []
887
            if node.find('CONNECTIONPOINT').text is not None:
888
                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
            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
            flipLabelNode = node.find('FLIP')
906
            flipLabel = int(flipLabelNode.text) if flipLabelNode is not None else 0
907

    
908
            appDocData = AppDocData.instance()
909
            project = appDocData.getCurrentProject()
910
            svgFilePath = os.path.join(project.getSvgFilePath(), _type, name + '.svg')
911
            if os.path.isfile(svgFilePath):
912
                item[0] = SymbolSvgItem.createItem(_type, svgFilePath, uid, flip=flipLabel)
913
                item[0].setVisible(False)
914
                item[0].buildItem(name, _type, angle, pt, size, origin, connPts, baseSymbol, childSymbol, hasInstrumentLabel)
915

    
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

    
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
                
933
                connectors = node.find('CONNECTORS')
934
                if connectors is not None:
935
                    iterIndex = 0
936
                    for connector in connectors.iter('CONNECTOR'):
937
                        item[0].connectors[iterIndex].parse_xml(connector)
938
                        iterIndex += 1
939
                
940
                # get associations 
941
                attributeValue = node.find('ASSOCIATIONS')
942
                if attributeValue is not None:
943
                    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
                # up to here
949

    
950
                attributes = node.find('SYMBOLATTRIBUTES')
951
                if attributes is not None:
952
                    for attr in attributes.iter('ATTRIBUTE'):
953
                        _attr = SymbolAttr.fromXml(attr)
954
                        if type(item[0]) is not QEngineeringSpecBreakItem:
955
                            item[0].attrs[_attr] = attr.text
956
                        else:
957
                            if _attr.AttributeType == 'Spec':
958
                                item[0].attrs[_attr] = [attr.text.split(',')[0], attr.text.split(',')[1]]
959
                            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
                    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

    
972
                currentPointModeIndex = node.find('CURRENTPOINTMODEINDEX')
973
                if currentPointModeIndex is not None:
974
                    item[0].currentPointModeIndex = int(currentPointModeIndex.text)
975

    
976
                if type(item[0]) is QEngineeringSpecBreakItem:
977
                    item[0].connectors[0].setPos((item[0].connectors[0].connectPoint[0], item[0].connectors[0].connectPoint[1]))
978

    
979
                item[1] = owner
980
        except Exception as ex:
981
            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

    
985
        return item
986

    
987
    '''
988
        @brief      create item corresponding to given type
989
        @author     humkyung
990
        @date       2018.05.02
991
        @history    2018.05.08  Jeongwoo    Change type name (Piping OPC''S → Piping OPC's)
992
                    humkyung 2018.05.10 change symbol's color to blue
993
                    humkyung 2018.07.19 create nozzle instance if type is 'Nozzles'
994
    '''
995
    @staticmethod
996
    def createItem(type, path, uid=None, flip=0):
997
        from QEngineeringOPCItem import QEngineeringOPCItem
998
        from EngineeringEquipmentItem import QEngineeringEquipmentItem
999
        from EngineeringInstrumentItem import QEngineeringInstrumentItem
1000
        from EngineeringNozzleItem import QEngineeringNozzleItem
1001
        from EngineeringSpecBreakItem import QEngineeringSpecBreakItem
1002
        from EngineeringReducerItem import QEngineeringReducerItem
1003
        from EngineeringErrorItem import QEngineeringErrorItem
1004
        from AppDocData import AppDocData
1005

    
1006
        docData = AppDocData.instance()
1007

    
1008
        item = None
1009
        cateogry = docData.getSymbolCategoryByType(type)
1010
        if type == "Piping OPC's":
1011
            item = QEngineeringOPCItem(path, uid, flip=flip)
1012
        elif cateogry == 'Equipment':
1013
            item = QEngineeringEquipmentItem(path, uid, flip=flip)
1014
        elif cateogry == 'Instrumentation':
1015
            item = QEngineeringInstrumentItem(path, uid, flip=flip)
1016
        elif type == 'Nozzles':
1017
            item = QEngineeringNozzleItem(path, uid, flip=flip)
1018
        elif type == 'Segment Breaks':
1019
            item = QEngineeringSpecBreakItem(path, uid, flip=flip)
1020
        elif type == 'Reducers':
1021
            item = QEngineeringReducerItem(path, uid, flip=flip)
1022
        elif type == 'Error':
1023
            item = QEngineeringErrorItem(path, uid, flip=flip)
1024
        else:
1025
            item = SymbolSvgItem(path, uid, flip=flip)
1026

    
1027
        return item
1028

    
1029
    '''
1030
        @brief      change svg's color
1031
        @author     humkyung
1032
        @date       2018.05.10
1033
        @history    2018.05.11  Jeongwoo    Override QEngineeringAbstractItem's
1034
                    humkyung 2018.05.13 update after change color
1035
    '''
1036
    def setColor(self, color):
1037
        self.changeAttributes('fill', color)
1038
        self.changeAttributes('stroke', color)
1039
        self.renderer().load(self._document.toByteArray())
1040
        self.update()
1041

    
1042
    def getColor(self):
1043
        """
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

    
1048
    '''
1049
        @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
        @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
    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
    '''
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

    
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
    '''
1151
        @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
        from EngineeringAbstractItem import QEngineeringAbstractItem
1157
        from EngineeringTextItem import QEngineeringTextItem
1158

    
1159
        self.setColor(self.getColor())
1160

    
1161
        painter.setClipRect(options.exposedRect)
1162
        QGraphicsSvgItem.paint(self, painter, options, widget)
1163
        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
        if self.isSelected():
1172
            self.drawFocusRect(painter)
1173

    
1174
    '''
1175
        @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
                    kyouho  2018.07.30  remove connectors logic
1180
    '''
1181
    def addSvgItemToScene(self, scene):
1182
        transform = QTransform()
1183
        #print(self.symbolOrigin)
1184

    
1185
        transform.translate(self.loc[0] + self.symbolOrigin[0], self.loc[1] + self.symbolOrigin[1])
1186
        transform.rotateRadians(-self.angle)
1187
        currentPoint = self.getCurrentPoint()
1188
        transform.translate(-currentPoint[0], -currentPoint[1])
1189

    
1190
        if self.flip is 1:
1191
            transform.scale(-1.0, 1.0)
1192
            transform.translate(-self.size[0], 0)
1193
            #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

    
1201
        self.setTransform(transform)
1202
        scene.addItem(self)
1203

    
1204

    
1205
    '''
1206
        @brief      
1207
        @author     humkyung
1208
        @date       2018.07.27
1209
    '''
1210
    def onConnectorPosChaned(self, connector):
1211
        pass
1212

    
1213
    '''
1214
        @brief      set connector
1215
        @author     kyouho
1216
        @date       2018.07.26
1217
    '''
1218
    def setConnector(self):
1219
        connector = QEngineeringConnectorItem(parent=self)
1220
        connector.setParentItem(self)
1221
        self.connectors.append(connector)
1222

    
1223
    '''
1224
    '''
1225
    def refreshConnector(self):
1226
        for connector in self.connectors:
1227
            connector.buildItem()
1228

    
1229
    '''
1230
        @brief      Delete svg item
1231
        @author     Jeongwoo
1232
        @date       2018.05.25
1233
    '''
1234
    def deleteSvgItemFromScene(self):
1235
        for connector in self.connectors:
1236
            if connector.connectedItem is not None:
1237
                try:
1238
                    connector.connectedItem.removeSymbol(self)
1239
                except Exception as ex:
1240
                    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
                break
1246

    
1247
        self.transfer.onRemoved.emit(self)
1248
        
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

    
1259
    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
    '''
1274
        @brief      rotate Symbol
1275
        @author     kyouho
1276
        @date       2018.07.24
1277
    '''
1278
    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
            else:
1293
                self.angle = 0
1294
        else:
1295
            self.angle = angle
1296

    
1297
        self.size[0], self.size[1] = self.size[1], self.size[0]
1298
        
1299
        scene = self.scene()
1300
        #self.scene().removeItem(self)
1301
        #self.addSvgItemToScene(scene)
1302
        currentPoint = self.getCurrentPoint()
1303
        self.reSettingSymbol(currentPoint, self.angle)
1304

    
1305
    '''
1306
        @brief      resetting rotate Symbol
1307
        @author     kyouho
1308
        @date       2018.07.24
1309
    '''
1310
    def reSettingSymbol(self, standardPoint, angle):
1311
        transform = QTransform()
1312
        
1313
        transform.translate(self.loc[0] + self.symbolOrigin[0], self.loc[1] + self.symbolOrigin[1])
1314
        transform.rotateRadians(-angle)
1315
        transform.translate(-standardPoint[0], -standardPoint[1])
1316

    
1317
        if self.flip is 1:
1318
            transform.scale(-1.0, 1.0)
1319
            transform.translate(-self.size[0], 0)
1320

    
1321
        self.setTransform(transform)
1322

    
1323
        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

    
1329

    
1330
    '''
1331
        @brief      change Conn point 
1332
        @author     kyouho
1333
        @date       2018.07.25
1334
    '''
1335
    def changeConnPoint(self):
1336
        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

    
1346
    '''
1347
        @brief      change standard point
1348
        @author     kyouho
1349
        @date       2018.07.24
1350
    '''
1351
    def changeStandardPoint(self):
1352
        connPtsCount = len(self.connectors)
1353
        
1354
        if self.currentPointModeIndex < connPtsCount:
1355
            self.currentPointModeIndex += 1
1356
        else:
1357
            self.currentPointModeIndex = 0
1358

    
1359
        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
        from EngineeringSpecBreakItem import QEngineeringSpecBreakItem
1369

    
1370
        pointList = []
1371
        pointList.append(self.symbolOrigin)
1372
        for connector in self.connectors:
1373
            pointList.append(connector.connectPoint)
1374

    
1375
        if type(self) is QEngineeringSpecBreakItem:
1376
            self.currentPointModeIndex = 1
1377

    
1378
        return pointList[self.currentPointModeIndex]
1379

    
1380
    '''
1381
        @brief      심볼 회전 시 서로 다른 기준점으로 회전하기 때문에 기준점을 이후 개발한 SymbolSvgItem 기준의 회전좌표로 이동하기 위해서 만듬 (loc 기준으로 회전해야함)
1382
        @author     kyouho
1383
        @date       18.08.06
1384
    '''
1385
    def reCalculationRotatedItem(self):
1386

    
1387
        transform = QTransform()
1388
        transform.translate(self.loc[0] + self.symbolOrigin[0], self.loc[1] + self.symbolOrigin[1])
1389
        transform.rotateRadians(-self.angle)
1390
        currentPoint = self.getCurrentPoint()
1391
        transform.translate(-currentPoint[0], -currentPoint[1])
1392
        # 시작점을 구하기 위해서
1393
        goPoint = transform.map(QPoint(self.symbolOrigin[0], self.symbolOrigin[1]))
1394
        
1395
        self.loc = [self.loc[0] + self.origin[0] - goPoint.x(), self.loc[1] + self.origin[1] - goPoint.y()]
1396

    
1397

    
1398
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
'''
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

    
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
        node = node.nextSibling()
클립보드 이미지 추가 (최대 크기: 500 MB)