프로젝트

일반

사용자정보

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

hytos / DTI_PID / DTI_PID / Shapes / SymbolSvgItem.py @ 90bc60db

이력 | 보기 | 이력해설 | 다운로드 (37.1 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 QEngineeringAbstractItem import QEngineeringAbstractItem
16

    
17
import SelectAttributeDialog
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.connectors = []
47
        self.attrs = [] # attributes
48
        self._owner = None
49
        self.parentSymbol = ''
50
        self.childSymbol = ''
51
        self.hasInstrumentLabel = 0
52

    
53
        self.setAcceptHoverEvents(True)
54
        self.setAcceptedMouseButtons(Qt.LeftButton)
55
        self.setAcceptTouchEvents(True)
56
        
57
        self.isClick = False
58
        self.currentCursor = 0
59
        self.transfer = Transfer()
60

    
61

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

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

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

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

    
98
        if self._owner is None:
99
            self._color = self.DEFAULT_COLOR
100
        self.setColor(self._color)
101

    
102

    
103
    '''
104
        @brief  build symbol item
105
        @author humkyung
106
        @date   2018.05.02
107
        @history    2018.05.09  Jeongwoo    Clear self.connectors
108
                    2018.05.30  Jeongwoo    Add parameters (parentSymbol, childSymbol)
109
    '''
110
    def buildItem(self, name, type, angle, loc, size, origin, connPts, parentSymbol, childSymbol, hasInstrumentLabel):
111
        try:
112
            docData = AppDocData.instance()
113
            symbolInfo = docData.getSymbolByQuery('name', name)
114
            self.name = name
115
            self.type = type
116
            self.angle = angle
117
            self.loc = loc
118
            self.size = size
119
            self.origin = origin
120
            originalPoint = symbolInfo.getOriginalPoint().split(',')
121
            self.symbolOrigin = (float(originalPoint[0]), float(originalPoint[1]))
122

    
123
            # setting connectors
124
            connectionPoints = symbolInfo.getConnectionPoint().split('/')
125
            for index in range(len(connectionPoints)):
126
                split = connectionPoints[index].split(',')
127
                self.setConnector()
128
                self.connectors[index].setPos((float(split[0]), float(split[1])))
129
                self.connectors[index].connectPoint = (float(split[0]), float(split[1]))
130
                self.connectors[index].sceneConnectPoint = connPts[index] if len(connPts) > index else None
131
                
132
            self.parentSymbol = parentSymbol
133
            self.childSymbol = childSymbol
134
            self.hasInstrumentLabel = hasInstrumentLabel
135
            self.currentPointModeIndex = 0
136

    
137
            '''
138
            self.connectors.clear()
139
            center = (loc[0] + size[0]*0.5, loc[1] + size[1]*0.5)
140
            for pt in self.connPts:
141
                connector = QEngineeringConnectorItem(self)
142
                connector.setPos((pt[0] - loc[0], pt[1] - loc[1]))
143
                connector.setParentItem(self)
144
                self.connectors.append(connector)
145
            '''
146

    
147
            self.setToolTip(self.name)
148
        except Exception as ex:
149
            print('error occured({}) in {}:{}'.format(ex, sys.exc_info()[-1].tb_frame.f_code.co_filename, sys.exc_info()[-1].tb_lineno))
150

    
151
    '''
152
        @brief  return bounding box of symbol
153
        @author humkyung
154
        @date   2018.04.08
155
    '''
156
    def rect(self):
157
        return self.sceneBoundingRect()
158
        
159
    '''
160
        @brief  return true if line is able to connect symbol
161
        @author humkyung
162
        @date   2018.04.13
163
    '''
164
    def isConnectable(self, line, offset,  toler=10):
165
        for connector in self.connectors:
166
            dx = connector.sceneConnectPoint[0] - (line[0][0] + offset[0])
167
            dy = connector.sceneConnectPoint[1] - (line[0][1] + offset[1])
168
            if (math.sqrt(dx*dx + dy*dy) < toler): return True
169
            dx = connector.sceneConnectPoint[0] - (line[-1][0] + offset[0])
170
            dy = connector.sceneConnectPoint[1] - (line[-1][1] + offset[1])
171
            if (math.sqrt(dx*dx + dy*dy) < toler): return True
172

    
173
        return False
174
 
175
    '''
176
        @brief      check if symbol and given item is jointed
177
        @author     humkyung
178
        @date       2018.07.03
179
    '''
180
    def isJointed(self, item, toler=5):
181
        import math
182
        from EngineeringLineItem import QEngineeringLineItem
183

    
184
        lhs = []
185
        for connector in self.connectors:
186
            lhs.append(connector.sceneConnectPoint)
187

    
188
        if type(item) is QEngineeringLineItem:
189
            rhs = [item.startPoint(), item.endPoint()]
190
        elif issubclass(type(item), SymbolSvgItem):
191
            rhs = []
192
            for connector in item.connectors:
193
                rhs.append(connector.sceneConnectPoint)
194
        else:
195
            rhs = []
196

    
197
        for pt in lhs:
198
            for _pt in rhs:
199
                dx = _pt[0] - pt[0]
200
                dy = _pt[1] - pt[1]
201
                if math.sqrt(dx*dx + dy*dy) < toler:
202
                    return True
203

    
204
        return False
205
       
206
    '''
207
        @brief      connect line and symbol is able to be connected and return line
208
        @author     humkyung
209
        @date       2018.04.16
210
        @history    humkyung 2018.05.08 check if symbol is possible to be connected
211
                    Jeongwoo 2018.05.15 Connect each symbol and line
212
    '''
213
    def connectIfPossible(self, obj, toler=10):
214
        from shapely.geometry import Point
215
        from EngineeringLineItem import QEngineeringLineItem
216
        res = []
217

    
218
        if type(obj) is QEngineeringLineItem:
219
            startPt = obj.startPoint()
220
            endPt = obj.endPoint()
221
            for i in range(len(self.connectors)):
222
                if (self.connectors[i].connectedItem is None) and (Point(startPt[0], startPt[1]).distance(Point(self.connectors[i].sceneConnectPoint[0], self.connectors[i].sceneConnectPoint[1])) < toler):
223
                    self.connectors[i].connectedItem = obj 
224
                    obj.connectors[0].connectedItem = self
225
                    res.append(obj)
226
                if (self.connectors[i].connectedItem is None) and (Point(endPt[0], endPt[1]).distance(Point(self.connectors[i].sceneConnectPoint[0], self.connectors[i].sceneConnectPoint[1])) < toler):
227
                    self.connectors[i].connectedItem = obj
228
                    obj.connectors[1].connectedItem = self
229
                    res.append(obj)
230
        elif issubclass(type(obj), SymbolSvgItem):
231
            for i in range(len(self.connectors)):
232
                for j in range(len(obj.connectors)):
233
                    _pt = Point(obj.connectors[j].sceneConnectPoint[0], obj.connectors[j].sceneConnectPoint[1])
234
                    if (self.connectors[i].connectedItem is None) and (_pt.distance(Point(self.connectors[i].sceneConnectPoint[0], self.connectors[i].sceneConnectPoint[1])) < toler):
235
                        self.connectors[i].connectedItem = obj 
236
                        obj.connectors[j].connectedItem = self
237
                        res.append(obj)
238

    
239
        return res
240

    
241
    '''
242
        @brief  get connection point close to given point in tolerance
243
        @author humkyung
244
        @dat
245
    '''
246
    def getConnectionPointCloseTo(self, pt, toler=10):
247
        import math
248

    
249
        for connector in self.connectors:
250
            dx = connector.sceneConnectPoint[0] - pt[0]
251
            dy = connector.sceneConnectPoint[1] - pt[1]
252
            if math.sqrt(dx*dx + dy*dy) < toler: return connPt
253
            
254
        return None
255

    
256
    '''
257
        @brief  return center of symbol
258
        @author humkyung
259
        @date   2018.04.08
260
    '''
261
    def center(self):
262
        return self.sceneBoundingRect().center()
263
        
264
    '''
265
        @brief      highlight connector and attribute
266
        @authro     humkyung
267
        @date       2018.05.02
268
    '''
269
    def hoverEnterEvent(self, event):
270
        try:
271
            self._savedColor = self.getColor()
272
            self.setColor(SymbolSvgItem.HIGHLIGHT)
273
            self.currentCursor = int(Qt.OpenHandCursor)
274
            cursor = QCursor(Qt.OpenHandCursor)
275
            QApplication.instance().setOverrideCursor(cursor)
276
            self.update()
277

    
278
            for attr in self.attrs:
279
                attr.setDefaultTextColor(Qt.red)
280
                attr.update()
281
        except Exception as ex:
282
            from App import App
283

    
284
            message = 'error occured({}) in {}:{}'.format(ex, sys.exc_info()[-1].tb_frame.f_code.co_filename, sys.exc_info()[-1].tb_lineno)
285
            App.mainWin().addMessage(MessageType.Error, message)
286

    
287
    '''
288
        @brief      unhighlight connector and attribute
289
        @author     humkyung
290
        @date       2018.05.02
291
        @history    kyouho 2018.07.18 edit ArrowCursor
292
    '''
293
    def hoverLeaveEvent(self, event):
294
        self.setColor(self._savedColor)
295
        self.currentCursor = int(Qt.ArrowCursor)
296
        cursor = QCursor(Qt.ArrowCursor)
297
        QApplication.instance().setOverrideCursor(cursor)
298
        self.update()
299

    
300
        for attr in self.attrs:
301
            attr.setDefaultTextColor(Qt.blue)
302
            attr.update()
303

    
304
    '''
305
        @brief  change cursor to CrossCursor if mouse point is close to connection point
306
        @author humkyung
307
        @date   2018.04.28
308
    '''
309
    def hoverMoveEvent(self, event):
310
        pass
311
    '''
312
        scenePos = self.mapToScene(event.pos())
313
        connPt = self.getConnectionPointCloseTo((scenePos.x(), scenePos.y()), 5)
314
        if connPt is not None:
315
            cursor = QCursor(Qt.CrossCursor)
316
            QApplication.instance().changeOverrideCursor(cursor)
317
        else:
318
            cursor = QCursor(Qt.OpenHandCursor)
319
            QApplication.instance().changeOverrideCursor(cursor)
320

321
        self.update()
322
    '''
323

    
324
    '''
325
        @brief      Mouse Press Event
326
        @author     Jeongwoo
327
        @date       18.04.11
328
        @history    kyouho 2018.07.18 add isClick logic
329
    '''
330
    def mousePressEvent(self, event):
331
        if event.buttons() == Qt.LeftButton:
332
            self.clicked.emit(self)
333
            #Type에 따라서 isClick 조절 설정 가능
334
            self.isClick = True
335

    
336
    '''
337
        @brief      Mouse Release Event
338
        @author     kyouho
339
        @date       18.07.17
340
    '''
341
    def mouseReleaseEvent(self, event):
342
        super().mouseReleaseEvent(event)
343
        if self.isClick:
344
            self.isClick = False
345
            self.currentCursor = int(Qt.ArrowCursor)
346
            cursor = QCursor(Qt.ArrowCursor)
347
            QApplication.instance().setOverrideCursor(cursor)
348
            self.update()
349

    
350
            scenePos = self.mapToScene(event.pos())
351
            result = self.findTextItemInPoint(scenePos)
352
            if result[0]:
353
                item = result[1]
354

    
355
                dialog = SelectAttributeDialog.QSelectAttributeDialog(None, self.type)
356
                dialog.exec_()
357
                
358
                if dialog.dialogResult and dialog.selectedAttribute:
359
                    attrStr = dialog.selectedAttribute
360
                    item.attribute = attrStr
361

    
362
                    # 기존 연결되있는 다른 SymbolItem의 Attr 제거
363
                    self.removeAttr(item)
364
                    # 자기 자신의 똑같은 attribute 제거
365
                    self.removeSelfAttr(attrStr)
366

    
367
                    self.attrs.append(item)
368

    
369
    '''
370
        @brief      Mouse Move Event
371
        @author     kyouho
372
        @date       18.07.17
373
    '''
374
    def removeSelfAttr(self, attributeName):
375
        for attr in self.attrs:
376
            if attr.attribute == attributeName:
377
                self.attrs.remove(attr)
378

    
379
    '''
380
        @brief      Mouse Move Event
381
        @author     kyouho
382
        @date       18.07.17
383
    '''
384
    def mouseMoveEvent(self, event):
385
        if self.isClick and self.currentCursor != int(Qt.ClosedHandCursor):
386
            self.currentCursor = int(Qt.ClosedHandCursor)
387
            cursor = QCursor(Qt.ClosedHandCursor)
388
            QApplication.instance().setOverrideCursor(cursor)
389
            self.update()
390

    
391
    '''
392
        @brief      Find TextItem contain Point
393
        @author     kyouho
394
        @date       18.07.17
395
    '''
396
    def findTextItemInPoint(self, point):
397
        from EngineeringTextItem import QEngineeringTextItem
398
        
399
        scene = self.scene()
400
 
401
        for item in scene.items():
402
            if type(item) is QEngineeringTextItem:
403
                if self.isOverlapItemAndPoint(item, point):
404
                    return (True, item)
405

    
406
        return (False,)
407

    
408
    '''
409
        @brief      Check Overlap
410
        @author     kyouho
411
        @date       18.07.17
412
    '''
413
    def isOverlapItemAndPoint(self, item, point):
414
        x = point.x()
415
        y = point.y()
416
        loc = item.loc
417
        size = item.size
418

    
419
        if loc[0] <= x and loc[0] + size[0] >= x and loc[1] <= y and loc[1] + size[1] >= y:
420
            return True
421
        else:
422
            return False
423

    
424
    '''
425
        @brief      Remove Attr
426
        @author     kyouho
427
        @date       18.07.17
428
    '''
429
    def removeAttr(self, item):
430
        scene = self.scene()
431
        for symbol in scene.items():
432
            if type(symbol) is SymbolSvgItem:
433
                for attr in symbol.attrs:
434
                    if attr == item:
435
                        symbol.attrs.remove(item)
436

    
437
    '''
438
        @brief  remove item when user press delete key
439
        @author humkyung
440
        @date   2018.04.23
441
        @history    2018.05.17  Jeongwoo    Add if-statement and move 'break'
442
                    2018.05.25  Jeongwoo    Seperate delete item method
443
    '''
444
    def keyPressEvent(self, event):
445
        if event.key() == Qt.Key_Delete:
446
            self.deleteSvgItemFromScene()
447
        elif event.key() == Qt.Key_R:
448
            self.rotateSymbol()
449
        elif event.key() == Qt.Key_O:
450
            self.changeStandardPoint()
451
        elif event.key() == Qt.Key_C:
452
            self.changeConnPoint()
453
            
454
    '''
455
        @brief      connect attribute
456
        @author     humkyung
457
        @date       2018.05.02
458
        @history    humkyung 2018.05.09 append only nearest size attribute
459
    '''
460
    def connectAttribute(self, attributes):
461
        import math
462
        from QEngineeringSizeTextItem import QEngineeringSizeTextItem
463

    
464
        self.attrs.clear()
465

    
466
        dist = max(self.sceneBoundingRect().height(), self.sceneBoundingRect().width())
467
        center = self.sceneBoundingRect().center()
468

    
469
        minDist = None
470
        selected = None
471
        for attr in attributes:
472
            if type(attr) is QEngineeringSizeTextItem:
473
                dx = attr.center().x() - center.x()
474
                dy = attr.center().y() - center.y()
475
                length = math.sqrt(dx*dx + dy*dy)
476
                if (length < dist*2) and (minDist is None or length < minDist):
477
                    minDist = length
478
                    selected = attr
479

    
480
        if selected is not None: self.attrs.append(selected)
481

    
482

    
483
    '''
484
        @Auther     Yecheol
485
        @Date       2018.07.06
486
        @History    add Get not connected Attribute Item
487
                    humkyung 2018.07.23 fixed the code
488
    '''
489
    def getConnectedLabel(self, worker):
490
        import math
491
        from QEngineeringInstrumentItem import QEngineeringInstrumentItem
492

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

    
495
        for symbol in findSymbols:
496
            isConnected = False
497
            for connector in symbol.connectors:
498
                if connector.connectedItem is not None:
499
                     isConnected = True
500
                     break
501
                    
502
            if isConnected == False:
503
                dx = symbol.origin[0] - self.origin[0]
504
                dy = symbol.origin[1] - self.origin[1]
505
                if math.sqrt(dx*dx + dy*dy) < 200:
506
                    self.attrs.append(symbol)
507

    
508
    '''
509
        @brief      get attribute
510
        @author     humkyung
511
        @date       2018.06.14
512
        @history    kyouho  2018.07.18  Add only attr QEngineeringTextItem
513
    '''
514
    def getAttributes(self):
515
        from EngineeringTextItem import QEngineeringTextItem
516
        from QEngineeringInstrumentItem import QEngineeringInstrumentItem
517
        attrs = {}
518
        
519
        # 해당 Type의 attribute setting
520
        docData = AppDocData.instance()
521
        symbolAttrs = docData.getSymbolAttribute(self.type)
522
        for attr in symbolAttrs:
523
            attrs[attr] = ''
524

    
525
        for attr in self.attrs:
526
            if type(attr) is QEngineeringTextItem:
527
                attrs[attr.attribute] = attr.text()
528
            elif type(attr) is QEngineeringInstrumentItem:
529
                attrs['Label'] = '{}'.format(attr)
530
        
531
        return attrs
532
    
533
    '''
534
        @brief      generate xml code
535
        @author     humkyung
536
        @date       2018.04.23
537
        @history    humkyung 2018.04.25 add angle xml node
538
                    humkyung 2018.04.27 add originalpoint xml node
539
                    humkyung 2018.05.02 add attribute of symbol
540
                    Jeongwoo 2018.05.30 add attribute of symbol (parentSymbol, childSymbol, type, connectionPoint)
541
                    yecheol  2018.07.11 add attribute of symbol (hasInstrumentLabel)
542
                    humkyung 2018.07.20 write owner's uid to xml
543
                    humkyung 2018.07.23 write connected item's uid to xml
544
                    kyouho  2018.07.31 
545
    '''
546
    def toXml(self):
547
        from xml.etree.ElementTree import Element, SubElement, dump, ElementTree
548

    
549
        try:
550
            node = Element('SYMBOL')
551
            uidNode = Element('UID')
552
            uidNode.text = str(self.uid)
553
            node.append(uidNode)
554

    
555
            nameNode = Element('NAME')
556
            nameNode.text = self.name
557
            node.append(nameNode)
558

    
559
            typeNode = Element('TYPE')
560
            typeNode.text = self.type
561
            node.append(typeNode)
562

    
563
            # write owner's uid to xml
564
            if self.owner is not None:
565
                ownerNode = Element('OWNER')
566
                ownerNode.text = str(self.owner.uid)
567
                node.append(ownerNode)
568
            # up to here
569

    
570
            originNode = Element('ORIGINALPOINT')
571
            originNode.text = '{},{}'.format(self.origin[0], self.origin[1])
572
            node.append(originNode)
573

    
574
            connectorsNode = Element('CONNECTORS')
575
            for connector in self.connectors:
576
                connectorNode = Element('CONNECTOR')
577
                connectedItemNode = Element('CONNECTEDITEM')
578
                connectedItemNode.text = str(connector.connectedItem.uid) if connector.connectedItem is not None else 'None'
579
                connectPointNode = Element('CONNECTPOINT')
580
                connectPointNode.text = str(connector.connectPoint[0]) + ',' + str(connector.connectPoint[1])
581
                sceneConnectPointNode = Element('SCENECONNECTPOINT')
582
                sceneConnectPointNode.text = str(connector.sceneConnectPoint[0]) + ',' + str(connector.sceneConnectPoint[1])
583

    
584
                connectorNode.append(connectedItemNode)
585
                connectorNode.append(connectPointNode)
586
                connectorNode.append(sceneConnectPointNode)
587
                connectorsNode.append(connectorNode)
588
            node.append(connectorsNode)
589

    
590
            connectionNode = Element('CONNECTIONPOINT')
591
            connectionPoint = ''
592
            if self.connectors is not None:
593
                for index in range(len(self.connectors)):
594
                    if index != 0:
595
                        connectionPoint = connectionPoint + "/"
596
                    connTuple = self.connectors[index].sceneConnectPoint
597
                    connectionPoint = connectionPoint + str(connTuple[0]) + "," + str(connTuple[1])
598
            connectionNode.text = connectionPoint
599
            node.append(connectionNode)
600

    
601
            rect = self.sceneBoundingRect()
602
            locNode = Element('LOCATION')
603
            locNode.text = '{},{}'.format(self.loc[0], self.loc[1])
604
            node.append(locNode)
605

    
606
            sizeNode = Element('SIZE')
607
            sizeNode.text = '{},{}'.format(rect.width(), rect.height())
608
            node.append(sizeNode)
609

    
610
            angleNode = Element('ANGLE')
611
            angleNode.text = str(self.angle)
612
            node.append(angleNode)
613

    
614
            parentSymbolNode = Element('PARENT')
615
            parentSymbolNode.text = str(self.parentSymbol)
616
            node.append(parentSymbolNode)
617

    
618
            childSymbolNode = Element('CHILD')
619
            childSymbolNode.text = str(self.childSymbol)
620
            node.append(childSymbolNode)
621

    
622
            hasInstrumentLabelNode = Element('HASINSTRUMENTLABEL')
623
            hasInstrumentLabelNode.text = str(self.hasInstrumentLabel)
624
            node.append(hasInstrumentLabelNode)
625

    
626
            attributesNode = Element('SYMBOLATTRIBUTES')
627
            for attr in self.attrs:
628
                attributeNode = Element('SYMBOLATTRIBUTE')
629
                attributeNode.text = str(attr.uid)
630
                attributesNode.append(attributeNode)
631
            node.append(attributesNode)
632

    
633
            currentPointModeIndexNode = Element('CURRENTPOINTMODEINDEX')
634
            currentPointModeIndexNode.text = str(self.currentPointModeIndex)
635
            node.append(currentPointModeIndexNode)
636

    
637
        except Exception as ex:
638
            return str(self.uid)
639
            print('error occured({}) in {}:{}'.format(ex, sys.exc_info()[-1].tb_frame.f_code.co_filename, sys.exc_info()[-1].tb_lineno))
640

    
641
        return node 
642

    
643
    '''
644
        @brief  generate xml code for attribute
645
        @author humkyung
646
        @date   2018.05.02
647
    '''
648
    def toXmlAsAttribute(self, parent):
649
        for attr in self.attrs:
650
            parent.append(attr.toXml(self))
651

    
652
    '''
653
        @brief      parse xml code
654
        @author     humkyung
655
        @date       2018.07.20
656
        @history    humkyung 2018.07.20 parse uid from xml node
657
                    humkyung 2018.07.23 parse connected item's uid from xml node
658
                    kyouho  2018.07.31 
659
    '''
660
    @staticmethod 
661
    def fromXml(node):
662
        import uuid
663
        item = [None, None]
664

    
665
        try:
666
            uidNode = node.find('UID')
667
            uid = uidNode.text if uidNode is not None else uuid.uuid4() # generate UUID
668

    
669
            pt = [float(x) for x in node.find('LOCATION').text.split(',')]
670
            size = [float(x) for x in node.find('SIZE').text.split(',')]
671
            name = node.find('NAME').text
672
            angle = float(node.find('ANGLE').text)
673
            type = node.find('TYPE').text
674
            origin = [float(x) for x in node.find('ORIGINALPOINT').text.split(',')]
675
            connPts = []
676
            if node.find('CONNECTIONPOINT').text is not None:
677
                connPts = [(float(x.split(',')[0]), float(x.split(',')[1])) for x in node.find('CONNECTIONPOINT').text.split('/')]
678
            baseSymbol = node.find('PARENT').text
679
            childSymbolNode = node.find('CHILD')
680
            childSymbol = ''
681
            if childSymbolNode is not None:
682
                childSymbol = childSymbolNode.text
683
            
684
            ownerNode = node.find('OWNER')
685
            owner = ownerNode.text if ownerNode is not None else None
686

    
687
            hasInstrumentLabelNode = node.find('HASINSTRUMENTLABEL')
688
            hasInstrumentLabel = hasInstrumentLabelNode.text if hasInstrumentLabelNode is not None else 'False'
689

    
690
            project = AppDocData.instance().getCurrentProject()
691
            svgFilePath = os.path.join(project.getSvgFilePath(), type, name + '.svg')
692
            if os.path.isfile(svgFilePath):
693
                item[0] = SymbolSvgItem.createItem(type, svgFilePath, uid)
694
                item[0].buildItem(name, type, angle, pt, size, origin, connPts, baseSymbol, childSymbol, hasInstrumentLabel)
695
                
696
                connectors = node.find('CONNECTORS')
697
                if connectors is not None:
698
                    iterIndex = 0
699
                    for connector in connectors.iter('CONNECTOR'):
700
                        connectedItemStr = connector.find('CONNECTEDITEM').text
701
                        connectPointStr = connector.find('CONNECTPOINT').text.split(',')
702
                        sceneConnectPointStr = connector.find('SCENECONNECTPOINT').text.split(',')
703

    
704
                        item[0].connectors[iterIndex].connectedItem = connectedItemStr if connectedItemStr != 'None' else None
705
                        item[0].connectors[iterIndex].connectPoint = (float(connectPointStr[0]), float(connectPointStr[1]))
706
                        item[0].connectors[iterIndex].sceneConnectPoint = (float(sceneConnectPointStr[0]), float(sceneConnectPointStr[1]))
707

    
708
                        iterIndex += 1
709
                
710
                attributes = node.find('SYMBOLATTRIBUTES')
711
                if attributes is not None:
712
                    for attr in attributes.iter('SYMBOLATTRIBUTE'):
713
                        item[0].attrs.append(attr.text)
714

    
715
                currentPointModeIndex = node.find('CURRENTPOINTMODEINDEX')
716
                if currentPointModeIndex is not None:
717
                    item[0].currentPointModeIndex = int(currentPointModeIndex.text)
718
                item[1] = owner
719
        except Exception as ex:
720
            print('error occured({}) in {}:{}'.format(ex, sys.exc_info()[-1].tb_frame.f_code.co_filename, sys.exc_info()[-1].tb_lineno))
721

    
722
        return item
723

    
724
    '''
725
        @brief      create item corresponding to given type
726
        @author     humkyung
727
        @date       2018.05.02
728
        @history    2018.05.08  Jeongwoo    Change type name (Piping OPC''S → Piping OPC's)
729
                    humkyung 2018.05.10 change symbol's color to blue
730
                    humkyung 2018.07.19 create nozzle instance if type is 'Nozzles'
731
    '''
732
    @staticmethod
733
    def createItem(type, path, uid=None):
734
        from QEngineeringOPCItem import QEngineeringOPCItem
735
        from QEngineeringEquipmentItem import QEngineeringEquipmentItem
736
        from QEngineeringInstrumentItem import QEngineeringInstrumentItem
737
        from EngineeringNozzleItem import QEngineeringNozzleItem
738
        from AppDocData import AppDocData
739

    
740
        docData = AppDocData.instance()
741

    
742
        item = None
743
        cateogry = docData.getSymbolCategoryByType(type)
744
        if type == "Piping OPC's":
745
            item = QEngineeringOPCItem(path, uid)
746
        elif cateogry == 'Equipment':
747
            item = QEngineeringEquipmentItem(path, uid)
748
        elif cateogry == 'Instrumentation':
749
            item = QEngineeringInstrumentItem(path, uid)
750
        elif type == 'Nozzles':
751
            item = QEngineeringNozzleItem(path, uid)
752
        else:
753
            item = SymbolSvgItem(path, uid)
754

    
755
        return item
756

    
757
    '''
758
        @brief      change svg's color
759
        @author     humkyung
760
        @date       2018.05.10
761
        @history    2018.05.11  Jeongwoo    Override QEngineeringAbstractItem's
762
                    humkyung 2018.05.13 update after change color
763
    '''
764
    def setColor(self, color):
765
        self._color = color
766
        self.changeAttributes('fill', color)
767
        self.changeAttributes('stroke', color)
768
        self.renderer().load(self._document.toByteArray())
769
        self.update()
770

    
771
    '''
772
        @brief      Get Color code
773
        @author     Jeongwoo
774
        @date       2018.05.17
775
    '''
776
    def getColor(self):
777
        return self._color
778

    
779
    '''
780
        @brief  change attributes
781
        @author humkyung
782
        @date   2018.05.10
783
    '''
784
    def changeAttributes(self, attName, attValue):
785
        root = self._document.documentElement()
786
        node = root.firstChild()
787
        while not node.isNull():
788
            if node.isElement():
789
                element = node.toElement()
790
                if element.hasAttribute(attName):
791
                    element.setAttribute(attName, attValue)
792

    
793
                if element.hasChildNodes():
794
                    recursiveChangeAttributes(element.firstChild(), attName, attValue)
795

    
796
            node = node.nextSibling()
797

    
798
    '''
799
        @brief  change attribute
800
        @author humkyung
801
        @date   2018.05.10
802
    '''
803
    def recursiveChangeAttributes(self, node, attName, attValue):
804
        while not node.isNull():
805
            if node.isElement():
806
                element = node.toElement()
807
                if element.hasAttribute(attName):
808
                    element.setAttribute(attName, attValue)
809

    
810
                if node.hasChildNodes():
811
                    recursiveChangeAttributes(node.firstChild(), attName, attValue)
812
            
813
            node = node.nextSibling()
814

    
815
    '''
816
        @brief  draw rect when item is selected
817
        @author humkyung
818
        @date   2018.07.07
819
    '''
820
    def drawFocusRect(self, painter):
821
        self.focuspen = QPen(Qt.DotLine)
822
        self.focuspen.setColor(Qt.black)
823
        self.focuspen.setWidthF(1.5)
824
        hilightColor = QColor(255, 0, 0, 127)
825
        painter.setBrush(QBrush(hilightColor))
826
        painter.setPen(self.focuspen)
827
        painter.drawRect(self.boundingRect())
828

    
829
    '''
830
        @brief  override paint(draw connection points)
831
        @author humkyung
832
        @date   2018.04.21
833
    '''
834
    def paint(self, painter, options=None, widget=None):
835
        painter.setClipRect(options.exposedRect)
836
        QGraphicsSvgItem.paint(self, painter, options, widget)
837
        if self.isSelected():
838
            self.drawFocusRect(painter)
839

    
840
    '''
841
        @brief      Add Svg Item into ImageViewer's Scene
842
        @author     Jeongwoo
843
        @date       2018.05.03
844
        @history    add connectors which's parent is symbol
845
                    kyouho  2018.07.30  remove connectors logic
846
    '''
847
    def addSvgItemToScene(self, scene):
848
        transform = QTransform()
849
        transform.translate(self.loc[0] + self.symbolOrigin[0], self.loc[1] + self.symbolOrigin[1])
850
        transform.rotateRadians(-self.angle)
851
        currentPoint = self.getCurrentPoint()
852
        transform.translate(-currentPoint[0], -currentPoint[1])
853

    
854
        self.setTransform(transform)
855
        scene.addItem(self)
856

    
857

    
858
    '''
859
        @brief      
860
        @author     humkyung
861
        @date       2018.07.27
862
    '''
863
    def onConnectorPosChaned(self, connector):
864
        pass
865

    
866
    '''
867
        @brief      set connector
868
        @author     kyouho
869
        @date       2018.07.26
870
    '''
871
    def setConnector(self):
872
        connector = QEngineeringConnectorItem(self)
873
        connector.setParentItem(self)
874
        self.connectors.append(connector)
875

    
876
    '''
877
    '''
878
    def refreshConnector(self):
879
        for connector in self.connectors:
880
            connector.buildItem()
881

    
882
    '''
883
        @brief      Delete svg item
884
        @author     Jeongwoo
885
        @date       2018.05.25
886
    '''
887
    def deleteSvgItemFromScene(self):
888
        for connector in self.connectors:
889
            if connector.connectedItem is not None:
890
                connector.connectedItem.removeSymbol(self)
891
                break
892

    
893
        self.transfer.onRemoved.emit(self)
894
        
895
    '''
896
        @brief      Return real item position
897
        @author     Jeongwoo
898
        @date       2018.05.25
899
    '''
900
    def boundingRectOnScene(self):
901
        rect = self.boundingRect()
902
        rect.moveTo(self.loc[0], self.loc[1])
903
        return rect
904

    
905
    '''
906
        @brief      rotate Symbol
907
        @author     kyouho
908
        @date       2018.07.24
909
    '''
910
    def rotateSymbol(self):
911
        #degree 0
912
        if 0 == self.angle:
913
            self.angle = 1.57
914
        #degree 90
915
        elif (1.57 == self.angle):
916
            self.angle = 3.14
917
        #degree 180
918
        elif 3.14 == self.angle:
919
            self.angle = 4.71
920
        #degree 270
921
        elif 4.71 == self.angle :
922
            self.angle = 0
923

    
924
        currentPoint = self.getCurrentPoint()
925
        self.reSettingSymbol(currentPoint, self.angle)
926

    
927
    '''
928
        @brief      resetting rotate Symbol
929
        @author     kyouho
930
        @date       2018.07.24
931
    '''
932
    def reSettingSymbol(self, standardPoint, angle):
933
        transform = QTransform()
934
        
935
        transform.translate(self.loc[0] + self.symbolOrigin[0], self.loc[1] + self.symbolOrigin[1])
936
        transform.rotateRadians(-angle)
937
        transform.translate(-standardPoint[0], -standardPoint[1])
938

    
939
        self.setTransform(transform)
940

    
941
        from EngineeringLineItem import QEngineeringLineItem
942
        for connector in self.connectors:
943
            if connector.connectedItem is not None and type(connector.connectedItem) == QEngineeringLineItem:
944
                line = connector.connectedItem
945
                line.reDrawLine(self, connector.center())
946

    
947

    
948
    '''
949
        @brief      change Conn point 
950
        @author     kyouho
951
        @date       2018.07.25
952
    '''
953
    def changeConnPoint(self):
954
        if len(self.connectors) == 2:
955

    
956
            conn1Item = self.connectors[0].connectedItem
957
            conn2Item = self.connectors[1].connectedItem
958
            self.connectors[0].connectedItem = conn2Item
959
            self.connectors[1].connectedItem = conn1Item
960

    
961
            currentPoint = self.getCurrentPoint()
962
            self.reSettingSymbol(currentPoint, self.angle)
963

    
964
    '''
965
        @brief      change standard point
966
        @author     kyouho
967
        @date       2018.07.24
968
    '''
969
    def changeStandardPoint(self):
970
        connPtsCount = len(self.connectors)
971
        
972
        if self.currentPointModeIndex < connPtsCount:
973
            self.currentPointModeIndex += 1
974
        else:
975
            self.currentPointModeIndex = 0
976

    
977
        currentPoint = self.getCurrentPoint()
978
        self.reSettingSymbol(currentPoint, self.angle)
979
    
980
    '''
981
        @brief      get standard point
982
        @author     kyouho
983
        @date       2018.07.25
984
    '''
985
    def getCurrentPoint(self):
986
        pointList = []
987
        pointList.append(self.symbolOrigin)
988
        for connector in self.connectors:
989
            pointList.append(connector.connectPoint)
990

    
991
        return pointList[self.currentPointModeIndex]
992

    
993
    '''
994
        @brief      심볼 회전 시 서로 다른 기준점으로 회전하기 때문에 기준점을 이후 개발한 SymbolSvgItem 기준의 회전좌표로 이동하기 위해서 만듬 (loc 기준으로 회전해야함)
995
        @author     kyouho
996
        @date       18.08.06
997
    '''
998
    def reCalculationRotatedItem(self):
999

    
1000
        transform = QTransform()
1001
        transform.translate(self.loc[0] + self.symbolOrigin[0], self.loc[1] + self.symbolOrigin[1])
1002
        transform.rotateRadians(-self.angle)
1003
        currentPoint = self.getCurrentPoint()
1004
        transform.translate(-currentPoint[0], -currentPoint[1])
1005
        # 시작점을 구하기 위해서
1006
        goPoint = transform.map(QPoint(self.symbolOrigin[0], self.symbolOrigin[1]))
1007
        
1008
        self.loc = [self.loc[0] + self.origin[0] - goPoint.x(), self.loc[1] + self.origin[1] - goPoint.y()]
1009

    
1010

    
1011
def recursiveChangeAttributes(node, attName, attValue):
1012
    while not node.isNull():
1013
        if node.isElement():
1014
            element = node.toElement()
1015
            if element.hasAttribute(attName):
1016
                element.setAttribute(attName, attValue)
1017

    
1018
            if node.hasChildNodes():
1019
                recursiveChangeAttributes(node.firstChild(), attName, attValue)
1020
        
1021
        node = node.nextSibling()
1022

    
1023
'''
1024
    @brief      The class transfer pyqtSignal Event. Cause Subclass of QGraphicsRectItem can't use pyqtSignal
1025
    @author     Jeongwoo
1026
    @date       2018.06.18
1027
'''
1028
class Transfer(QObject):
1029
    onRemoved = pyqtSignal(QGraphicsItem)
1030

    
1031
    def __init__(self, parent = None):
1032
        QObject.__init__(self, parent)
1033

    
1034

    
1035
if __name__ == '__main__':
1036
    f = QFile('d:/Projects/DTIPID/DTI_PID/DTI_PID/SG_TEST/svg/ANGLE VALVE.svg')
1037
    f.open(QIODevice.ReadOnly)
1038
    array = f.readAll()
1039
    document = QDomDocument()
1040
    document.setContent(array)
1041

    
1042
    root = document.documentElement()
1043
    node = root.firstChild()
1044
    while not node.isNull():
1045
        if node.isElement():
1046
            element = node.toElement()
1047
            if element.hasAttribute('fill'):
1048
                element.setAttribute('fill', '#FFFFF')
1049

    
1050
            if element.hasChildNodes():
1051
                recursiveChangeAttributes(element.firstChild(), 'fill', '#FFFFF')
1052

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