프로젝트

일반

사용자정보

통계
| 개정판:

hytos / DTI_PID / DTI_PID / Shapes / SymbolSvgItem.py @ 85a460a6

이력 | 보기 | 이력해설 | 다운로드 (42.9 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 UserInputAttribute import UserInputAttribute
17
import SelectAttributeCommand
18

    
19
class SymbolSvgItem(QGraphicsSvgItem, QEngineeringAbstractItem):
20
    clicked = pyqtSignal(QGraphicsSvgItem)
21
    ZVALUE = 50
22
    HIGHLIGHT = '#BC4438'
23

    
24
    '''
25
        @history    18.04.11    Jeongwoo    Add Variable (Name, Type)
26
                    18.05.11    Jeongwoo    Declare variable self.color
27
                    18.05.25    Jeongwoo    Call setColor() method
28
                    18.05.30    Jeongwoo    Add self variables (parentSymbol, childSymbol)
29
    '''
30
    def __init__(self, path, uid=None):
31
        import uuid
32

    
33
        QGraphicsSvgItem.__init__(self)
34
        QEngineeringAbstractItem.__init__(self)
35

    
36
        self.setFlags(QGraphicsItem.ItemIsSelectable|QGraphicsItem.ItemIsFocusable)
37
                      #QGraphicsItem.ItemIsMovable)
38
        
39
        self.uid = uuid.uuid4() if uid is None else uid
40
        self.name = ''
41
        self.type = ''
42
        self.angle = 0
43
        self.origin = None
44
        self.loc = None
45
        self.size = None
46
        self._owner = None
47
        self.parentSymbol = ''
48
        self.childSymbol = '' 
49
        self.hasInstrumentLabel = 0
50
        # attributeType uid
51
        self.attribute = ''
52
        
53
        self._texts = []    # contains text items
54
        self._symbols = []  # contains symbol items
55

    
56
        self.setAcceptHoverEvents(True)
57
        self.setAcceptedMouseButtons(Qt.LeftButton)
58
        self.setAcceptTouchEvents(True)
59
        
60
        self.currentCursor = 0
61
        self.transfer = Transfer()
62

    
63
        try:
64
            f = QFile(path)
65
            f.open(QIODevice.ReadOnly)
66
            array = f.readAll()
67
            self._document = QDomDocument()
68
            self._document.setContent(array)
69
            self._renderer = QSvgRenderer(self._document.toByteArray())
70
            self.setSharedRenderer(self._renderer)
71

    
72
            self.setColor(self._color)
73
            self._savedColor = self.getColor()
74
        except Exception as ex:
75
            print('error occured({}) in {}:{}'.format(ex, sys.exc_info()[-1].tb_frame.f_code.co_filename, sys.exc_info()[-1].tb_lineno))
76
        finally:
77
            f.close()
78

    
79
        self.setZValue(SymbolSvgItem.ZVALUE)
80
            
81
    '''
82
        @breif  getter owner
83
        @author humkyung
84
        @date   2018.05.10
85
    '''
86
    @property
87
    def owner(self):
88
        return self._owner
89

    
90
    '''
91
        @brief  setter owner
92
        @author humkyung
93
        @date   2018.05.10
94
        @history    2018.05.17  Jeongwoo    Add Calling setColor if self._owner is None or not
95
    '''
96
    @owner.setter
97
    def owner(self, value):
98
        self._owner = value
99

    
100
        if self._owner is None:
101
            self._color = self.DEFAULT_COLOR
102
        self.setColor(self._color)
103

    
104
    def toSql(self):
105
        """
106
        convert valve data to sql query
107
        """
108
        from AppDocData import AppDocData
109

    
110
        appDocData = AppDocData.instance()
111

    
112
        cols = ['UID', 'ITEM_NO', 'PNID_NO']
113
        values = ['?','?','?']
114
        param = [str(self.uid), self.name, appDocData.activeDrawing.name]
115
        _attrs = self.getAttributes()
116
        for key in _attrs.keys():
117
            cols.append(key.Attribute)
118
            values.append('?')
119
            param.append(_attrs[key])
120

    
121
        sql = 'insert or replace into VALVE_DATA_LIST({}) values({})'.format(','.join(cols), ','.join(values))
122
        return (sql, tuple(param))
123

    
124
    '''
125
        @brief  build symbol item
126
        @author humkyung
127
        @date   2018.05.02
128
        @history    2018.05.09  Jeongwoo    Clear self.connectors
129
                    2018.05.30  Jeongwoo    Add parameters (parentSymbol, childSymbol)
130
    '''
131
    def buildItem(self, name, type, angle, loc, size, origin, connPts, parentSymbol, childSymbol, hasInstrumentLabel):
132
        try:
133
            docData = AppDocData.instance()
134
            self.name = name
135
            self.type = type
136
            self.angle = angle
137
            self.loc = loc
138
            self.size = size
139
            self.origin = origin
140
            symbolInfo = docData.getSymbolByQuery('name', name)
141
            originalPoint = symbolInfo.getOriginalPoint().split(',')
142
            self.symbolOrigin = (float(originalPoint[0]), float(originalPoint[1]))
143

    
144
            # setting connectors
145
            connectionPoints = symbolInfo.getConnectionPoint().split('/')
146
            for index in range(len(connectionPoints)):
147
                tokens = connectionPoints[index].split(',')
148

    
149
                direction = 'AUTO'
150
                if len(tokens) == 2:
151
                    x = float(tokens[0])
152
                    y = float(tokens[1])
153
                elif len(tokens) == 3:
154
                    direction = tokens[0]
155
                    x = float(tokens[1])
156
                    y = float(tokens[2])
157

    
158
                self.setConnector()
159
                self.connectors[index].direction = direction
160
                self.connectors[index].setPos((x, y))
161
                self.connectors[index].connectPoint = (x, y)
162
                self.connectors[index].sceneConnectPoint = (connPts[index][0], connPts[index][1]) if len(connPts[index]) == 2 else (connPts[index][1], connPts[index][2]) \
163
                    if len(connPts) > index else None
164
                
165
            self.parentSymbol = parentSymbol
166
            self.childSymbol = childSymbol
167
            self.hasInstrumentLabel = hasInstrumentLabel
168
            self.currentPointModeIndex = 0
169

    
170
            self.setToolTip(self.name)
171
        except Exception as ex:
172
            from App import App 
173

    
174
            message = 'error occured({}) in {}:{}'.format(ex, sys.exc_info()[-1].tb_frame.f_code.co_filename, sys.exc_info()[-1].tb_lineno)
175
            App.mainWnd().addMessage.emit(MessageType.Error, message)
176

    
177
    '''
178
        @brief  return bounding box of symbol
179
        @author humkyung
180
        @date   2018.04.08
181
    '''
182
    def rect(self):
183
        return self.sceneBoundingRect()
184
        
185
    '''
186
        @brief  return true if line is able to connect symbol
187
        @author humkyung
188
        @date   2018.04.13
189
    '''
190
    def isConnectable(self, line, offset,  toler=10):
191
        for connector in self.connectors:
192
            dx = connector.sceneConnectPoint[0] - (line[0][0] + offset[0])
193
            dy = connector.sceneConnectPoint[1] - (line[0][1] + offset[1])
194
            if (math.sqrt(dx*dx + dy*dy) < toler): return True
195
            dx = connector.sceneConnectPoint[0] - (line[-1][0] + offset[0])
196
            dy = connector.sceneConnectPoint[1] - (line[-1][1] + offset[1])
197
            if (math.sqrt(dx*dx + dy*dy) < toler): return True
198

    
199
        return False
200
 
201
    '''
202
        @brief      check if symbol and given item is jointed
203
        @author     humkyung
204
        @date       2018.07.03
205
    '''
206
    def isJointed(self, item, toler=5):
207
        import math
208
        from EngineeringLineItem import QEngineeringLineItem
209

    
210
        lhs = []
211
        for connector in self.connectors:
212
            lhs.append(connector.sceneConnectPoint)
213

    
214
        if type(item) is QEngineeringLineItem:
215
            rhs = [item.startPoint(), item.endPoint()]
216
        elif issubclass(type(item), SymbolSvgItem):
217
            rhs = []
218
            for connector in item.connectors:
219
                rhs.append(connector.sceneConnectPoint)
220
        else:
221
            rhs = []
222

    
223
        for pt in lhs:
224
            for _pt in rhs:
225
                dx = _pt[0] - pt[0]
226
                dy = _pt[1] - pt[1]
227
                if math.sqrt(dx*dx + dy*dy) < toler:
228
                    return True
229

    
230
        return False
231
       
232
    '''
233
        @brief      connect line and symbol is able to be connected and return line
234
        @author     humkyung
235
        @date       2018.04.16
236
        @history    humkyung 2018.05.08 check if symbol is possible to be connected
237
                    Jeongwoo 2018.05.15 Connect each symbol and line
238
    '''
239
    def connectIfPossible(self, obj, toler=10):
240
        from shapely.geometry import Point
241
        from EngineeringLineItem import QEngineeringLineItem
242
        res = []
243
        try:
244
            if type(obj) is QEngineeringLineItem:
245
                startPt = obj.startPoint()
246
                endPt = obj.endPoint()
247
                for i in range(len(self.connectors)):
248
                    if (Point(startPt[0], startPt[1]).distance(Point(self.connectors[i].sceneConnectPoint[0], self.connectors[i].sceneConnectPoint[1])) < toler):
249
                        if self.connectors[i].connectedItem is None:
250
                            self.connectors[i].connectedItem = obj
251
                        if obj.connectors[0].connectedItem is None:
252
                            obj.connectors[0].connectedItem = self
253
                        
254
                        res.append(obj)
255
                    if (Point(endPt[0], endPt[1]).distance(Point(self.connectors[i].sceneConnectPoint[0], self.connectors[i].sceneConnectPoint[1])) < toler):
256
                        if self.connectors[i].connectedItem is None:
257
                            self.connectors[i].connectedItem = obj
258
                        if obj.connectors[1].connectedItem is None:
259
                            obj.connectors[1].connectedItem = self
260
                        
261
                        res.append(obj)
262
            elif issubclass(type(obj), SymbolSvgItem):
263
                for i in range(len(self.connectors)):
264
                    for j in range(len(obj.connectors)):
265
                        _pt = Point(obj.connectors[j].sceneConnectPoint[0], obj.connectors[j].sceneConnectPoint[1])
266
                        if (_pt.distance(Point(self.connectors[i].sceneConnectPoint[0], self.connectors[i].sceneConnectPoint[1])) < toler):
267
                            if self.connectors[i].connectedItem is None:
268
                                self.connectors[i].connectedItem = obj
269
                            if obj.connectors[j].connectedItem is None :
270
                                obj.connectors[j].connectedItem = self
271

    
272
                            res.append(obj)
273
        except Exception as ex:
274
            print('error occured({}) in {}:{}'.format(ex, sys.exc_info()[-1].tb_frame.f_code.co_filename, sys.exc_info()[-1].tb_lineno))
275

    
276
        return res
277

    
278
    '''
279
        @brief      check connector overlap specbreak
280
        @author     kyouho
281
        @date       2018.08.30
282
    '''
283
    def isConnectSpecBreak(self, specBreakList):
284
        for connector in self.connectors:
285
            for specBreak in specBreakList:
286
                if connector.isOverlapConnector(specBreak.connectors[0]):
287
                    return (True, connector)
288

    
289
        return (False,)
290

    
291
    '''
292
        @brief      disconnect connector item
293
        @author     kyouho
294
        @date       2018.08.30
295
    '''
296
    def disconnectedItemAtConnector(self, connector):
297
        for conn in self.connectors:
298
            if conn.isOverlapConnector(connector):
299
                conn.connectedItem = None
300

    
301
    '''
302
        @brief  get connection point close to given point in tolerance
303
        @author humkyung
304
        @dat
305
    '''
306
    def getConnectionPointCloseTo(self, pt, toler=10):
307
        import math
308

    
309
        for connector in self.connectors:
310
            dx = connector.sceneConnectPoint[0] - pt[0]
311
            dy = connector.sceneConnectPoint[1] - pt[1]
312
            if math.sqrt(dx*dx + dy*dy) < toler: return connPt
313
            
314
        return None
315

    
316
    '''
317
        @brief  return center of symbol
318
        @author humkyung
319
        @date   2018.04.08
320
    '''
321
    def center(self):
322
        return self.sceneBoundingRect().center()
323
        
324
    '''
325
        @brief      highlight connector and attribute
326
        @authro     humkyung
327
        @date       2018.05.02
328
    '''
329
    def hoverEnterEvent(self, event):
330
        try:
331
            from EngineeringTextItem import QEngineeringTextItem
332
            self.setHightlight()
333
            self.currentCursor = int(Qt.OpenHandCursor)
334
            cursor = QCursor(Qt.OpenHandCursor)
335
            QApplication.instance().setOverrideCursor(cursor)
336
            self.update()
337

    
338
            for attr in self.attrs:
339
                if issubclass(type(attr), QEngineeringTextItem):
340
                    attr.setDefaultTextColor(Qt.red)
341
                    attr.update()
342
                elif issubclass(type(attr), SymbolSvgItem):
343
                    attr._savedColor = attr.getColor()
344
                    attr.setColor(SymbolSvgItem.HIGHLIGHT)
345
                    attr.update()
346
        except Exception as ex: 
347
            print('error occured({}) in {}:{}'.format(ex, sys.exc_info()[-1].tb_frame.f_code.co_filename, sys.exc_info()[-1].tb_lineno))
348

    
349
    '''
350
        @brief      unhighlight connector and attribute
351
        @author     humkyung
352
        @date       2018.05.02
353
        @history    kyouho 2018.07.18 edit ArrowCursor
354
    '''
355
    def hoverLeaveEvent(self, event):
356
        from EngineeringTextItem import QEngineeringTextItem
357
        self.unsetHightlight()
358
        self.currentCursor = int(Qt.ArrowCursor)
359
        cursor = QCursor(Qt.ArrowCursor)
360
        QApplication.instance().setOverrideCursor(cursor)
361
        self.update()
362

    
363
        for attr in self.attrs:
364
            if issubclass(type(attr), QEngineeringTextItem):
365
                attr.setDefaultTextColor(Qt.blue)
366
                attr.update()
367
            elif issubclass(type(attr), SymbolSvgItem):
368
                attr.setColor(attr._savedColor)
369
                attr.update()
370

    
371
    '''
372
        @brief      set highlight
373
        @author     kyouho
374
        @date       2018.08.27
375
    '''
376
    def setHightlight(self):
377
        self.setColor(SymbolSvgItem.HIGHLIGHT)
378
        self.update()
379

    
380
    '''
381
        @brief      unset highlight
382
        @author     kyouho
383
        @date       2018.08.27
384
    '''
385
    def unsetHightlight(self):
386
        self.setColor(self._savedColor)
387
        self.update()
388

    
389
    '''
390
        @brief  change cursor to CrossCursor if mouse point is close to connection point
391
        @author humkyung
392
        @date   2018.04.28
393
    '''
394
    def hoverMoveEvent(self, event):
395
        pass
396
    '''
397
        scenePos = self.mapToScene(event.pos())
398
        connPt = self.getConnectionPointCloseTo((scenePos.x(), scenePos.y()), 5)
399
        if connPt is not None:
400
            cursor = QCursor(Qt.CrossCursor)
401
            QApplication.instance().changeOverrideCursor(cursor)
402
        else:
403
            cursor = QCursor(Qt.OpenHandCursor)
404
            QApplication.instance().changeOverrideCursor(cursor)
405

406
        self.update()
407
    '''
408

    
409
    '''
410
        @brief      Mouse Press Event
411
        @author     Jeongwoo
412
        @date       18.04.11
413
        @history    kyouho 2018.07.18 add isClick logic
414
    '''
415
    def mousePressEvent(self, event):
416
        if event.buttons() == Qt.LeftButton:
417
            self.clicked.emit(self)
418

    
419
    '''
420
        @brief      Mouse Release Event
421
        @author     kyouho
422
        @date       18.07.17
423
    '''
424
    def mouseReleaseEvent(self, event):
425
        super().mouseReleaseEvent(event)
426

    
427
    '''
428
        @brief      Mouse Move Event
429
        @author     kyouho
430
        @date       18.07.17
431
    '''
432
    def removeSelfAttr(self, attributeName):
433
        for attr in self.attrs:
434
            if attr.attribute == attributeName:
435
                self.attrs.remove(attr)
436

    
437
    '''
438
        @brief      Find TextItem contain Point
439
        @author     kyouho
440
        @date       18.07.17
441
    '''
442
    def findTextItemInPoint(self, point):
443
        from EngineeringTextItem import QEngineeringTextItem
444
        
445
        scene = self.scene()
446
 
447
        for item in scene.items():
448
            if type(item) is QEngineeringTextItem:
449
                if self.isOverlapItemAndPoint(item, point):
450
                    return (True, item)
451

    
452
        return (False,)
453

    
454
    '''
455
        @brief      Check Overlap
456
        @author     kyouho
457
        @date       18.07.17
458
    '''
459
    def isOverlapItemAndPoint(self, item, point):
460
        x = point.x()
461
        y = point.y()
462
        loc = item.loc
463
        size = item.size
464

    
465
        if loc[0] <= x and loc[0] + size[0] >= x and loc[1] <= y and loc[1] + size[1] >= y:
466
            return True
467
        else:
468
            return False
469

    
470
    '''
471
        @brief      Remove Attr
472
        @author     kyouho
473
        @date       18.07.17
474
    '''
475
    def removeAttr(self, item):
476
        scene = self.scene()
477
        for symbol in scene.items():
478
            if issubclass(type(symbol), SymbolSvgItem):
479
                for attr in symbol.attrs:
480
                    if attr == item:
481
                        symbol.attrs.remove(item)
482

    
483
    '''
484
        @brief  remove item when user press delete key
485
        @author humkyung
486
        @date   2018.04.23
487
        @history    2018.05.17  Jeongwoo    Add if-statement and move 'break'
488
                    2018.05.25  Jeongwoo    Seperate delete item method
489
    '''
490
    def keyPressEvent(self, event):
491
        if event.key() == Qt.Key_Delete:
492
            self.deleteSvgItemFromScene()
493
        elif event.key() == Qt.Key_R:
494
            self.rotateSymbol()
495
        elif event.key() == Qt.Key_O:
496
            self.changeStandardPoint()
497
        elif event.key() == Qt.Key_C:
498
            self.changeConnPoint()
499
            
500
    '''
501
        @brief      connect attribute
502
        @author     humkyung
503
        @date       2018.05.02
504
        @history    humkyung 2018.05.09 append only nearest size attribute
505
    '''
506
    def connectAttribute(self, attributes):
507
        import math
508
        from QEngineeringSizeTextItem import QEngineeringSizeTextItem
509

    
510
        self.attrs.clear()
511

    
512
        try:
513
            dist = max(self.sceneBoundingRect().height(), self.sceneBoundingRect().width())
514
            center = self.sceneBoundingRect().center()
515

    
516
            minDist = None
517
            selected = None
518
            for attr in attributes:
519
                if type(attr) is QEngineeringSizeTextItem:
520
                    dx = attr.center().x() - center.x()
521
                    dy = attr.center().y() - center.y()
522
                    length = math.sqrt(dx*dx + dy*dy)
523
                    if (length < dist*2) and (minDist is None or length < minDist):
524
                        minDist = length
525
                        selected = attr
526

    
527
            if selected is not None:
528
                self._texts.append(selected)
529
        except Exception as ex:
530
            from App import App 
531
            message = 'error occured({}) in {}:{}'.format(ex, sys.exc_info()[-1].tb_frame.f_code.co_filename, sys.exc_info()[-1].tb_lineno)
532
            App.mainWnd().addMessage.emit(MessageType.Error, message)
533

    
534
    '''
535
        @Auther     Yecheol
536
        @Date       2018.07.06
537
        @History    add Get not connected Attribute Item
538
                    humkyung 2018.07.23 fixed the code
539
    '''
540
    def getConnectedLabel(self, worker):
541
        import math
542
        from EngineeringInstrumentItem import QEngineeringInstrumentItem
543

    
544
        findSymbols = [symbol for symbol in worker.graphicsView.scene.items() if type(symbol) is QEngineeringInstrumentItem]
545

    
546
        for symbol in findSymbols:
547
            isConnected = False
548
            for connector in symbol.connectors:
549
                if connector.connectedItem is not None:
550
                     isConnected = True
551
                     break
552
                    
553
            if isConnected == False:
554
                dx = symbol.origin[0] - self.origin[0]
555
                dy = symbol.origin[1] - self.origin[1]
556
                if math.sqrt(dx*dx + dy*dy) < 200:
557
                    self.attrs.append(symbol)
558

    
559
    '''
560
        @brief      get attribute
561
        @author     humkyung
562
        @date       2018.06.14
563
        @history    kyouho  2018.07.18  Add only attr QEngineeringTextItem
564
    '''
565
    def getAttributes(self):
566
        _attrs = {}
567
        try:
568
            from AppDocData import AppDocData
569
            from EngineeringTextItem import QEngineeringTextItem
570

    
571
            # 해당 Type의 attribute setting
572
            docData = AppDocData.instance()
573
            symbolAttrs = docData.getSymbolAttribute(self.type)
574
            for attr in symbolAttrs:
575
                if attr.AttributeType == 'Text Item':
576
                    at = int(attr.AttrAt)
577
                    if len(self._texts) > at:
578
                        item = self._texts[at]
579
                        _attrs[attr] = eval(attr.Expression) if attr.Expression else ''
580
                    else:
581
                        _attrs[attr] = ''
582
                elif attr.AttributeType == 'Symbol Item':
583
                    at = int(attr.AttrAt)
584
                    if len(self._symbols) > at:
585
                        item = self._symbols[at]
586
                        _attrs[attr] = eval(attr.Expression) if attr.Expression else ''
587
                    else:
588
                        _attrs[attr] = ''
589
                else:
590
                    matches = [prop for prop in self.attrs if prop.UID == attr.UID]
591
                    if len(matches) == 1:
592
                        _attrs[matches[0]] = self.attrs[matches[0]]
593
                    else:
594
                        _attrs[attr] = ''
595
        except Exception as ex:
596
            from App import App 
597
            from AppDocData import MessageType
598

    
599
            message = 'error occured({}) in {}:{}'.format(ex, sys.exc_info()[-1].tb_frame.f_code.co_filename, sys.exc_info()[-1].tb_lineno)
600
            App.mainWnd().addMessage.emit(MessageType.Error, message)
601
        
602
        return _attrs
603

    
604
    '''
605
        @brief      generate xml code
606
        @author     humkyung
607
        @date       2018.04.23
608
        @history    humkyung 2018.04.25 add angle xml node
609
                    humkyung 2018.04.27 add originalpoint xml node
610
                    humkyung 2018.05.02 add attribute of symbol
611
                    Jeongwoo 2018.05.30 add attribute of symbol (parentSymbol, childSymbol, type, connectionPoint)
612
                    yecheol  2018.07.11 add attribute of symbol (hasInstrumentLabel)
613
                    humkyung 2018.07.20 write owner's uid to xml
614
                    humkyung 2018.07.23 write connected item's uid to xml
615
                    kyouho  2018.07.31 
616
                    humkyung 2018.09.06 write area to xml
617
    '''
618
    def toXml(self):
619
        from xml.etree.ElementTree import Element, SubElement, dump, ElementTree
620
        from EngineeringSpecBreakItem import QEngineeringSpecBreakItem
621
        from SymbolAttr import SymbolAttr
622

    
623
        try:
624
            node = Element('SYMBOL')
625
            uidNode = Element('UID')
626
            uidNode.text = str(self.uid)
627
            node.append(uidNode)
628

    
629
            nameNode = Element('NAME')
630
            nameNode.text = self.name
631
            node.append(nameNode)
632

    
633
            attributeValueNode = Element('ATTRIBUTEVALUE')
634
            attributeValueNode.text = self.attribute
635
            node.append(attributeValueNode)
636

    
637
            typeNode = Element('TYPE')
638
            typeNode.text = self.type
639
            node.append(typeNode)
640

    
641
            # write owner's uid to xml
642
            if self.owner is not None:
643
                ownerNode = Element('OWNER')
644
                ownerNode.text = str(self.owner.uid)
645
                node.append(ownerNode)
646
            # up to here
647

    
648
            originNode = Element('ORIGINALPOINT')
649
            originNode.text = '{},{}'.format(self.origin[0], self.origin[1])
650
            node.append(originNode)
651

    
652
            connectorsNode = Element('CONNECTORS')
653
            for connector in self.connectors:
654
                connectorNode = Element('CONNECTOR')
655
                connectedItemNode = Element('CONNECTEDITEM')
656
                connectedItemNode.text = str(connector.connectedItem.uid) if connector.connectedItem is not None else 'None'
657
                connectPointNode = Element('CONNECTPOINT')
658
                connectPointNode.text = str(connector.connectPoint[0]) + ',' + str(connector.connectPoint[1])
659
                sceneConnectPointNode = Element('SCENECONNECTPOINT')
660
                sceneConnectPointNode.text = str(connector.sceneConnectPoint[0]) + ',' + str(connector.sceneConnectPoint[1])
661

    
662
                connectorNode.append(connectedItemNode)
663
                connectorNode.append(connectPointNode)
664
                connectorNode.append(sceneConnectPointNode)
665
                connectorsNode.append(connectorNode)
666
            node.append(connectorsNode)
667

    
668
            connectionNode = Element('CONNECTIONPOINT')
669
            connectionPoint = ''
670
            if self.connectors is not None:
671
                for index in range(len(self.connectors)):
672
                    if index != 0:
673
                        connectionPoint = connectionPoint + "/"
674
                    connTuple = self.connectors[index].sceneConnectPoint
675
                    connectionPoint = connectionPoint + str(connTuple[0]) + "," + str(connTuple[1])
676
            connectionNode.text = connectionPoint
677
            node.append(connectionNode)
678

    
679
            rect = self.sceneBoundingRect()
680
            locNode = Element('LOCATION')
681
            locNode.text = '{},{}'.format(self.loc[0], self.loc[1])
682
            node.append(locNode)
683

    
684
            sizeNode = Element('SIZE')
685
            sizeNode.text = '{},{}'.format(rect.width(), rect.height())
686
            node.append(sizeNode)
687

    
688
            angleNode = Element('ANGLE')
689
            angleNode.text = str(self.angle)
690
            node.append(angleNode)
691

    
692
            parentSymbolNode = Element('PARENT')
693
            parentSymbolNode.text = str(self.parentSymbol)
694
            node.append(parentSymbolNode)
695

    
696
            childSymbolNode = Element('CHILD')
697
            childSymbolNode.text = str(self.childSymbol)
698
            node.append(childSymbolNode)
699

    
700
            hasInstrumentLabelNode = Element('HASINSTRUMENTLABEL')
701
            hasInstrumentLabelNode.text = str(self.hasInstrumentLabel)
702
            node.append(hasInstrumentLabelNode)
703

    
704
            areaNode = Element('AREA')
705
            areaNode.text = self.area
706
            node.append(areaNode)
707

    
708
            attributesNode = Element('SYMBOLATTRIBUTES')
709
            _attrs = self.getAttributes()
710
            for attr in _attrs:
711
                if type(attr) is SymbolAttr:
712
                    _node = attr.toXml()
713
                    _node.text = _attrs[attr]
714
                    attributesNode.append(_node)
715
                elif type(attr) is tuple and type(self) is QEngineeringSpecBreakItem:
716
                    attributeNode = Element(attr[0].upper().replace(' ',''))
717
                    attributeNode.text = str(attr[1] if attr[1] is not None else '')
718
                    attributesNode.append(attributeNode)
719

    
720
            node.append(attributesNode)
721

    
722
            currentPointModeIndexNode = Element('CURRENTPOINTMODEINDEX')
723
            currentPointModeIndexNode.text = str(self.currentPointModeIndex)
724
            node.append(currentPointModeIndexNode)
725

    
726
        except Exception as ex:
727
            from App import App 
728
            message = 'error occured({}) in {}:{}'.format(ex, sys.exc_info()[-1].tb_frame.f_code.co_filename, sys.exc_info()[-1].tb_lineno)
729
            App.mainWnd().addMessage.emit(MessageType.Error, message)
730

    
731
            return str(self.uid)
732

    
733
        return node 
734

    
735
    '''
736
        @brief      parse xml code
737
        @author     humkyung
738
        @date       2018.07.20
739
        @history    humkyung 2018.07.20 parse uid from xml node
740
                    humkyung 2018.07.23 parse connected item's uid from xml node
741
                    kyouho  2018.07.31 
742
                    humkyung 2018.09.06 assign area to item
743
    '''
744
    @staticmethod 
745
    def fromXml(node):
746
        import uuid
747
        from EngineeringSpecBreakItem import QEngineeringSpecBreakItem
748
        from SymbolAttr import SymbolAttr
749
        item = [None, None]
750

    
751
        try:
752
            uidNode = node.find('UID')
753
            uid = uidNode.text if uidNode is not None else uuid.uuid4() # generate UUID
754

    
755
            pt = [float(x) for x in node.find('LOCATION').text.split(',')]
756
            size = [float(x) for x in node.find('SIZE').text.split(',')]
757
            name = node.find('NAME').text
758
            angle = float(node.find('ANGLE').text)
759
            _type = node.find('TYPE').text
760
            origin = [float(x) for x in node.find('ORIGINALPOINT').text.split(',')]
761
            connPts = []
762
            if node.find('CONNECTIONPOINT').text is not None:
763
                connPts = [(float(x.split(',')[0]), float(x.split(',')[1])) for x in node.find('CONNECTIONPOINT').text.split('/')]
764
            baseSymbol = node.find('PARENT').text
765
            childSymbolNode = node.find('CHILD')
766
            childSymbol = ''
767
            if childSymbolNode is not None:
768
                childSymbol = childSymbolNode.text
769
            
770
            ownerNode = node.find('OWNER')
771
            owner = ownerNode.text if ownerNode is not None else None
772

    
773
            hasInstrumentLabelNode = node.find('HASINSTRUMENTLABEL')
774
            hasInstrumentLabel = hasInstrumentLabelNode.text if hasInstrumentLabelNode is not None else 'False'
775

    
776
            appDocData = AppDocData.instance()
777
            project = appDocData.getCurrentProject()
778
            svgFilePath = os.path.join(project.getSvgFilePath(), _type, name + '.svg')
779
            if os.path.isfile(svgFilePath):
780
                item[0] = SymbolSvgItem.createItem(_type, svgFilePath, uid)
781
                item[0].buildItem(name, _type, angle, pt, size, origin, connPts, baseSymbol, childSymbol, hasInstrumentLabel)
782

    
783
                ## assign area
784
                areaNode = node.find('AREA')
785
                if areaNode is None:
786
                    for area in appDocData.getAreaList():
787
                        if area.contains(pt):
788
                            item[0].area = area.name
789
                            break
790
                else:
791
                    item[0].area = areaNode.text
792
                ## up to here
793
                
794
                connectors = node.find('CONNECTORS')
795
                if connectors is not None:
796
                    iterIndex = 0
797
                    for connector in connectors.iter('CONNECTOR'):
798
                        connectedItemStr = connector.find('CONNECTEDITEM').text
799
                        connectPointStr = connector.find('CONNECTPOINT').text.split(',')
800
                        sceneConnectPointStr = connector.find('SCENECONNECTPOINT').text.split(',')
801

    
802
                        item[0].connectors[iterIndex].connectedItem = connectedItemStr if connectedItemStr != 'None' else None
803
                        item[0].connectors[iterIndex].connectPoint = (float(connectPointStr[0]), float(connectPointStr[1]))
804
                        item[0].connectors[iterIndex].sceneConnectPoint = (float(sceneConnectPointStr[0]), float(sceneConnectPointStr[1]))
805

    
806
                        iterIndex += 1
807
                
808
                attributeValue = node.find('ATTRIBUTEVALUE')
809
                if attributeValue is not None:
810
                    item[0].attribute = attributeValue.text
811

    
812
                attributes = node.find('SYMBOLATTRIBUTES')
813
                if attributes is not None:
814
                    for attr in attributes.iter('ATTRIBUTE'):
815
                        _attr = SymbolAttr.fromXml(attr)
816
                        item[0].attrs[_attr] = attr.text
817
                    for attr in attributes.iter('USERINPUTATTRIBUTE'):
818
                        typeUID = attr.find('TYPEUID').text
819
                        typeValue = attr.find('TYPEVALUE').text
820
                        item[0].attrs.append(UserInputAttribute(typeUID, typeValue))
821

    
822
                    if type(item[0]) is QEngineeringSpecBreakItem:
823
                        upStreamNode = attributes.find('UPSTREAM')
824
                        downStreamNode = attributes.find('DOWNSTREAM')
825
                        if upStreamNode is not None :
826
                            item[0].attrs.append(('Up Stream', upStreamNode.text))
827
                        if downStreamNode is not None:
828
                            item[0].attrs.append(('Down Stream', downStreamNode.text))
829

    
830
                currentPointModeIndex = node.find('CURRENTPOINTMODEINDEX')
831
                if currentPointModeIndex is not None:
832
                    item[0].currentPointModeIndex = int(currentPointModeIndex.text)
833

    
834
                if type(item[0]) is QEngineeringSpecBreakItem:
835
                    item[0].connectors[0].setPos((item[0].connectors[0].connectPoint[0], item[0].connectors[0].connectPoint[1]))
836

    
837
                item[1] = owner
838
        except Exception as ex:
839
            from App import App 
840
            message = 'error occured({}) in {}:{}'.format(ex, sys.exc_info()[-1].tb_frame.f_code.co_filename, sys.exc_info()[-1].tb_lineno)
841
            App.mainWnd().addMessage.emit(MessageType.Error, message)
842

    
843
        return item
844

    
845
    '''
846
        @brief      create item corresponding to given type
847
        @author     humkyung
848
        @date       2018.05.02
849
        @history    2018.05.08  Jeongwoo    Change type name (Piping OPC''S → Piping OPC's)
850
                    humkyung 2018.05.10 change symbol's color to blue
851
                    humkyung 2018.07.19 create nozzle instance if type is 'Nozzles'
852
    '''
853
    @staticmethod
854
    def createItem(type, path, uid=None):
855
        from QEngineeringOPCItem import QEngineeringOPCItem
856
        from EngineeringEquipmentItem import QEngineeringEquipmentItem
857
        from EngineeringInstrumentItem import QEngineeringInstrumentItem
858
        from EngineeringNozzleItem import QEngineeringNozzleItem
859
        from EngineeringSpecBreakItem import QEngineeringSpecBreakItem
860
        from AppDocData import AppDocData
861

    
862
        docData = AppDocData.instance()
863

    
864
        item = None
865
        cateogry = docData.getSymbolCategoryByType(type)
866
        if type == "Piping OPC's":
867
            item = QEngineeringOPCItem(path, uid)
868
        elif cateogry == 'Equipment':
869
            item = QEngineeringEquipmentItem(path, uid)
870
        elif cateogry == 'Instrumentation':
871
            item = QEngineeringInstrumentItem(path, uid)
872
        elif type == 'Nozzles':
873
            item = QEngineeringNozzleItem(path, uid)
874
        elif type == 'Segment Breaks':
875
            item = QEngineeringSpecBreakItem(path, uid)
876
        else:
877
            item = SymbolSvgItem(path, uid)
878

    
879
        return item
880

    
881
    '''
882
        @brief      change svg's color
883
        @author     humkyung
884
        @date       2018.05.10
885
        @history    2018.05.11  Jeongwoo    Override QEngineeringAbstractItem's
886
                    humkyung 2018.05.13 update after change color
887
    '''
888
    def setColor(self, color):
889
        self._color = color
890
        self.changeAttributes('fill', color)
891
        self.changeAttributes('stroke', color)
892
        self.renderer().load(self._document.toByteArray())
893
        self.update()
894

    
895
    '''
896
        @brief      Get Color code
897
        @author     Jeongwoo
898
        @date       2018.05.17
899
    '''
900
    def getColor(self):
901
        return self._color
902

    
903
    '''
904
        @brief  change attributes
905
        @author humkyung
906
        @date   2018.05.10
907
    '''
908
    def changeAttributes(self, attName, attValue):
909
        root = self._document.documentElement()
910
        node = root.firstChild()
911
        while not node.isNull():
912
            if node.isElement():
913
                element = node.toElement()
914
                if element.hasAttribute(attName):
915
                    element.setAttribute(attName, attValue)
916

    
917
                if element.hasChildNodes():
918
                    recursiveChangeAttributes(element.firstChild(), attName, attValue)
919

    
920
            node = node.nextSibling()
921

    
922
    '''
923
        @brief  change attribute
924
        @author humkyung
925
        @date   2018.05.10
926
    '''
927
    def recursiveChangeAttributes(self, node, attName, attValue):
928
        while not node.isNull():
929
            if node.isElement():
930
                element = node.toElement()
931
                if element.hasAttribute(attName):
932
                    element.setAttribute(attName, attValue)
933

    
934
                if node.hasChildNodes():
935
                    recursiveChangeAttributes(node.firstChild(), attName, attValue)
936
            
937
            node = node.nextSibling()
938

    
939
    '''
940
        @brief  draw rect when item is selected
941
        @author humkyung
942
        @date   2018.07.07
943
    '''
944
    def drawFocusRect(self, painter):
945
        self.focuspen = QPen(Qt.DotLine)
946
        self.focuspen.setColor(Qt.black)
947
        self.focuspen.setWidthF(1.5)
948
        hilightColor = QColor(255, 0, 0, 127)
949
        painter.setBrush(QBrush(hilightColor))
950
        painter.setPen(self.focuspen)
951
        painter.drawRect(self.boundingRect())
952

    
953
    '''
954
        @brief  override paint(draw connection points)
955
        @author humkyung
956
        @date   2018.04.21
957
    '''
958
    def paint(self, painter, options=None, widget=None):
959
        painter.setClipRect(options.exposedRect)
960
        QGraphicsSvgItem.paint(self, painter, options, widget)
961
        if self.isSelected():
962
            self.drawFocusRect(painter)
963

    
964
    '''
965
        @brief      Add Svg Item into ImageViewer's Scene
966
        @author     Jeongwoo
967
        @date       2018.05.03
968
        @history    add connectors which's parent is symbol
969
                    kyouho  2018.07.30  remove connectors logic
970
    '''
971
    def addSvgItemToScene(self, scene):
972
        transform = QTransform()
973
        transform.translate(self.loc[0] + self.symbolOrigin[0], self.loc[1] + self.symbolOrigin[1])
974
        transform.rotateRadians(-self.angle)
975
        currentPoint = self.getCurrentPoint()
976
        transform.translate(-currentPoint[0], -currentPoint[1])
977

    
978
        self.setTransform(transform)
979
        scene.addItem(self)
980

    
981

    
982
    '''
983
        @brief      
984
        @author     humkyung
985
        @date       2018.07.27
986
    '''
987
    def onConnectorPosChaned(self, connector):
988
        pass
989

    
990
    '''
991
        @brief      set connector
992
        @author     kyouho
993
        @date       2018.07.26
994
    '''
995
    def setConnector(self):
996
        connector = QEngineeringConnectorItem(self)
997
        connector.setParentItem(self)
998
        self.connectors.append(connector)
999

    
1000
    '''
1001
    '''
1002
    def refreshConnector(self):
1003
        for connector in self.connectors:
1004
            connector.buildItem()
1005

    
1006
    '''
1007
        @brief      Delete svg item
1008
        @author     Jeongwoo
1009
        @date       2018.05.25
1010
    '''
1011
    def deleteSvgItemFromScene(self):
1012
        for connector in self.connectors:
1013
            if connector.connectedItem is not None:
1014
                connector.connectedItem.removeSymbol(self)
1015
                break
1016

    
1017
        self.transfer.onRemoved.emit(self)
1018
        
1019
    '''
1020
        @brief      Return real item position
1021
        @author     Jeongwoo
1022
        @date       2018.05.25
1023
    '''
1024
    def boundingRectOnScene(self):
1025
        rect = self.boundingRect()
1026
        rect.moveTo(self.loc[0], self.loc[1])
1027
        return rect
1028

    
1029
    '''
1030
        @brief      rotate Symbol
1031
        @author     kyouho
1032
        @date       2018.07.24
1033
    '''
1034
    def rotateSymbol(self):
1035
        #degree 0
1036
        if 0 == self.angle:
1037
            self.angle = 1.57
1038
        #degree 90
1039
        elif (1.57 == self.angle):
1040
            self.angle = 3.14
1041
        #degree 180
1042
        elif 3.14 == self.angle:
1043
            self.angle = 4.71
1044
        #degree 270
1045
        elif 4.71 == self.angle :
1046
            self.angle = 0
1047

    
1048
        currentPoint = self.getCurrentPoint()
1049
        self.reSettingSymbol(currentPoint, self.angle)
1050

    
1051
    '''
1052
        @brief      resetting rotate Symbol
1053
        @author     kyouho
1054
        @date       2018.07.24
1055
    '''
1056
    def reSettingSymbol(self, standardPoint, angle):
1057
        transform = QTransform()
1058
        
1059
        transform.translate(self.loc[0] + self.symbolOrigin[0], self.loc[1] + self.symbolOrigin[1])
1060
        transform.rotateRadians(-angle)
1061
        transform.translate(-standardPoint[0], -standardPoint[1])
1062

    
1063
        self.setTransform(transform)
1064

    
1065
        from EngineeringLineItem import QEngineeringLineItem
1066
        for connector in self.connectors:
1067
            if connector.connectedItem is not None and type(connector.connectedItem) == QEngineeringLineItem:
1068
                line = connector.connectedItem
1069
                line.reDrawLine(self, connector.center())
1070

    
1071

    
1072
    '''
1073
        @brief      change Conn point 
1074
        @author     kyouho
1075
        @date       2018.07.25
1076
    '''
1077
    def changeConnPoint(self):
1078
        if len(self.connectors) == 2:
1079

    
1080
            conn1Item = self.connectors[0].connectedItem
1081
            conn2Item = self.connectors[1].connectedItem
1082
            self.connectors[0].connectedItem = conn2Item
1083
            self.connectors[1].connectedItem = conn1Item
1084

    
1085
            currentPoint = self.getCurrentPoint()
1086
            self.reSettingSymbol(currentPoint, self.angle)
1087

    
1088
    '''
1089
        @brief      change standard point
1090
        @author     kyouho
1091
        @date       2018.07.24
1092
    '''
1093
    def changeStandardPoint(self):
1094
        connPtsCount = len(self.connectors)
1095
        
1096
        if self.currentPointModeIndex < connPtsCount:
1097
            self.currentPointModeIndex += 1
1098
        else:
1099
            self.currentPointModeIndex = 0
1100

    
1101
        currentPoint = self.getCurrentPoint()
1102
        self.reSettingSymbol(currentPoint, self.angle)
1103
    
1104
    '''
1105
        @brief      get standard point
1106
        @author     kyouho
1107
        @date       2018.07.25
1108
    '''
1109
    def getCurrentPoint(self):
1110
        from EngineeringSpecBreakItem import QEngineeringSpecBreakItem
1111

    
1112
        pointList = []
1113
        pointList.append(self.symbolOrigin)
1114
        for connector in self.connectors:
1115
            pointList.append(connector.connectPoint)
1116

    
1117
        if type(self) is QEngineeringSpecBreakItem:
1118
            self.currentPointModeIndex = 1
1119

    
1120
        return pointList[self.currentPointModeIndex]
1121

    
1122
    '''
1123
        @brief      심볼 회전 시 서로 다른 기준점으로 회전하기 때문에 기준점을 이후 개발한 SymbolSvgItem 기준의 회전좌표로 이동하기 위해서 만듬 (loc 기준으로 회전해야함)
1124
        @author     kyouho
1125
        @date       18.08.06
1126
    '''
1127
    def reCalculationRotatedItem(self):
1128

    
1129
        transform = QTransform()
1130
        transform.translate(self.loc[0] + self.symbolOrigin[0], self.loc[1] + self.symbolOrigin[1])
1131
        transform.rotateRadians(-self.angle)
1132
        currentPoint = self.getCurrentPoint()
1133
        transform.translate(-currentPoint[0], -currentPoint[1])
1134
        # 시작점을 구하기 위해서
1135
        goPoint = transform.map(QPoint(self.symbolOrigin[0], self.symbolOrigin[1]))
1136
        
1137
        self.loc = [self.loc[0] + self.origin[0] - goPoint.x(), self.loc[1] + self.origin[1] - goPoint.y()]
1138

    
1139

    
1140
def recursiveChangeAttributes(node, attName, attValue):
1141
    while not node.isNull():
1142
        if node.isElement():
1143
            element = node.toElement()
1144
            if element.hasAttribute(attName):
1145
                element.setAttribute(attName, attValue)
1146

    
1147
            if node.hasChildNodes():
1148
                recursiveChangeAttributes(node.firstChild(), attName, attValue)
1149
        
1150
        node = node.nextSibling()
1151

    
1152
'''
1153
    @brief      The class transfer pyqtSignal Event. Cause Subclass of QGraphicsRectItem can't use pyqtSignal
1154
    @author     Jeongwoo
1155
    @date       2018.06.18
1156
'''
1157
class Transfer(QObject):
1158
    onRemoved = pyqtSignal(QGraphicsItem)
1159

    
1160
    def __init__(self, parent = None):
1161
        QObject.__init__(self, parent)
1162

    
1163

    
1164
if __name__ == '__main__':
1165
    f = QFile('d:/Projects/DTIPID/DTI_PID/DTI_PID/SG_TEST/svg/ANGLE VALVE.svg')
1166
    f.open(QIODevice.ReadOnly)
1167
    array = f.readAll()
1168
    document = QDomDocument()
1169
    document.setContent(array)
1170

    
1171
    root = document.documentElement()
1172
    node = root.firstChild()
1173
    while not node.isNull():
1174
        if node.isElement():
1175
            element = node.toElement()
1176
            if element.hasAttribute('fill'):
1177
                element.setAttribute('fill', '#FFFFF')
1178

    
1179
            if element.hasChildNodes():
1180
                recursiveChangeAttributes(element.firstChild(), 'fill', '#FFFFF')
1181

    
1182
        node = node.nextSibling()
클립보드 이미지 추가 (최대 크기: 500 MB)