프로젝트

일반

사용자정보

통계
| 개정판:

hytos / HYTOS / HYTOS / Shapes / SymbolSvgItem.py @ ae3e5e31

이력 | 보기 | 이력해설 | 다운로드 (51.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
from PyQt5.QtWidgets import QGraphicsView, QGraphicsScene, QFileDialog, QMessageBox
13

    
14
from AppDocData import *
15
from EngineeringAbstractItem import QEngineeringAbstractItem
16
from EngineeringConnectorItem import QEngineeringConnectorItem
17
from EngineeringEqpDescTextItem import QEngineeringEqpDescTextItem
18

    
19

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

    
23
    clicked = pyqtSignal(QGraphicsSvgItem)
24
    ZVALUE = 100
25
    HOVER_COLOR = 'url(#hover)'
26
    COUNTERS = {}
27

    
28
    '''
29
        @history    18.04.11    Jeongwoo    Add Variable (Name, Type)
30
                    18.05.11    Jeongwoo    Declare variable self.color
31
                    18.05.25    Jeongwoo    Call setColor() method
32
                    18.05.30    Jeongwoo    Add self variables (parentSymbol, childSymbol)
33
    '''
34

    
35
    def __init__(self, path, uid=None, flip=0):
36
        import uuid
37
        from SymbolAttr import SymbolProp
38

    
39
        QGraphicsSvgItem.__init__(self)
40
        QEngineeringAbstractItem.__init__(self)
41

    
42
        self.setFlags(
43
            QGraphicsItem.ItemIsSelectable | QGraphicsItem.ItemIsFocusable | QGraphicsItem.ItemIsMovable | QGraphicsItem.ItemSendsGeometryChanges)
44

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

    
69
        self.currentCursor = 0
70
        self.transfer = Transfer()
71

    
72
        try:
73
            f = QFile(path)
74
            f.open(QIODevice.ReadOnly)
75
            array = f.readAll()
76
            self._document = QDomDocument()
77
            self._document.setContent(array)
78
            self._renderer = QSvgRenderer(self._document.toByteArray())
79
            self.setSharedRenderer(self._renderer)
80

    
81
            self._color = self.get_attribute('fill')
82
        except Exception as ex:
83
            from App import App
84
            from AppDocData import MessageType
85

    
86
            message = 'error occurred({}) in {}:{}'.format(ex, sys.exc_info()[-1].tb_frame.f_code.co_filename,
87
                                                          sys.exc_info()[-1].tb_lineno)
88
            App.mainWnd().addMessage.emit(MessageType.Error, message)
89
        finally:
90
            f.close()
91

    
92
        self.setZValue(SymbolSvgItem.ZVALUE)
93
        self._desc_label = QEngineeringEqpDescTextItem('eqp name<br>pressure drop<br>elevation', self)
94

    
95
    def __str__(self):
96
        """ return string represent uuid """
97
        return str(self.uid)
98

    
99

    
100
    @property
101
    def tag_no(self):
102
        return self._tag_no
103

    
104
    @tag_no.setter
105
    def tag_no(self, value):
106
        self._tag_no = value
107

    
108
    '''
109
        @breif  getter owner
110
        @author humkyung
111
        @date   2018.05.10
112
    '''
113

    
114
    @property
115
    def owner(self):
116
        import uuid
117

    
118
        if self._owner and type(self._owner) is uuid.UUID:
119
            matches = [x for x in self.scene().items() if hasattr(x, 'uid') and str(x.uid) == str(self._owner)]
120
            if matches: self._owner = matches[0]
121

    
122
        if type(self._owner) is not uuid.UUID and type(self._owner) is not str:
123
            return self._owner
124
        else:
125
            self._owner = None
126
            return None
127

    
128
    '''
129
        @brief  setter owner
130
        @author humkyung
131
        @date   2018.05.10
132
        @history    2018.05.17  Jeongwoo    Add Calling setColor if self._owner is None or not
133
    '''
134

    
135
    @owner.setter
136
    def owner(self, value):
137
        self._owner = value
138

    
139
        if self._owner is None:
140
            self._color = self.DEFAULT_COLOR
141
        self.setColor(self._color)
142

    
143
    @property
144
    def properties(self):
145
        """ getter of properties """
146
        import uuid
147

    
148
        for prop, value in self._properties.items():
149
            try:
150
                if prop.is_selectable and type(value) is uuid.UUID and self.scene():
151
                    matches = [x for x in self.scene().items() if hasattr(x, 'uid') and str(x.uid) == str(value)]
152
                    if matches: self._properties[prop] = matches[0]
153

    
154
                if prop.Expression:
155
                    item = self._properties[prop]  # assign item
156
                    self._properties[prop] = eval(prop.Expression)
157
            except Exception as ex:
158
                from App import App
159

    
160
                message = 'error occurred({}) in {}:{}'.format(ex, sys.exc_info()[-1].tb_frame.f_code.co_filename,
161
                                                              sys.exc_info()[-1].tb_lineno)
162
                App.mainWnd().addMessage.emit(MessageType.Error, message)
163

    
164
        return self._properties
165

    
166
    @properties.setter
167
    def properties(self, value):
168
        """ setter of properties """
169
        self._properties = value
170

    
171
    def set_property(self, property, value):
172
        """ set property with given value """
173
        if issubclass(type(value), QEngineeringAbstractItem): self.add_assoc_item(value, 0)
174
        matches = [prop for prop, _ in self._properties.items() if prop.Attribute == property]
175
        if matches: self._properties[matches[0]] = value
176

    
177
    def prop(self, name):
178
        """ return the value of given property with name """
179
        matches = [(prop, value) for prop, value in self.properties.items() if prop.Attribute == name]
180
        if matches: return matches[0][1]
181

    
182
        return None
183

    
184
    @property
185
    def desc_label(self):
186
        """ return equipment description label """
187

    
188
        return self._desc_label
189

    
190
    @property
191
    def Size(self):
192
        """ return valve's size """
193
        from QEngineeringSizeTextItem import QEngineeringSizeTextItem
194

    
195
        matches = [assoc for assoc in self.associations() if type(assoc) is QEngineeringSizeTextItem]
196
        if matches:
197
            return matches[0].text()
198
        else:
199
            return None
200

    
201
    def includes(self, pt, margin=0):
202
        """ return True if symbol contains given point else return False """
203
        rect = self.sceneBoundingRect()
204
        allowed_error = 0.1
205

    
206
        if abs(rect.x() - 0) <= allowed_error and abs(rect.y() - 0) <= allowed_error:
207
            # when first recognition step, symbols are not in scene(not yet added) therefore cannot use scenebounding rect
208
            minX = self.loc[0] - margin
209
            minY = self.loc[1] - margin
210
            maxX = minX + self.size[0] + margin
211
            maxY = minY + self.size[1] + margin
212
        else:
213
            minX = rect.x() - margin
214
            minY = rect.y() - margin
215
            maxX = minX + rect.width() + margin
216
            maxY = minY + rect.height() + margin
217

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

    
220
    def toSql(self):
221
        """ convert valve data to sql query """
222

    
223
        res = []
224

    
225
        try:
226
            rect = self.sceneBoundingRect()
227

    
228
            cols = ['UID', 'Symbols_UID', 'Name', 'X', 'Y', 'Rotation', 'Scale']
229
            values = ['?', '?', '?', '?', '?', '?', '?']
230
            param = [str(self.uid), str(self.dbUid), str(self.tag_no), rect.left(), rect.top(), str(self.angle), self.transform().m11()]
231
            sql = 'insert or replace into Components({}) values({})'.format(','.join(cols), ','.join(values))
232
            res.append((sql, tuple(param)))
233

    
234
            # save connectors to database
235
            index = 1
236
            for connector in self.connectors:
237
                res.extend(connector.toSql(index))
238
                index += 1
239
            # up to here
240

    
241
        except Exception as ex:
242
            from App import App
243

    
244
            message = 'error occurred({}) in {}:{}'.format(ex, sys.exc_info()[-1].tb_frame.f_code.co_filename,
245
                                                          sys.exc_info()[-1].tb_lineno)
246
            App.mainWnd().addMessage.emit(MessageType.Error, message)
247

    
248
        return res
249

    
250
    '''
251
        @brief  build symbol item
252
        @author humkyung
253
        @date   2018.05.02
254
        @history    2018.05.09  Jeongwoo    Clear self.connectors
255
                    2018.05.30  Jeongwoo    Add parameters (parentSymbol, childSymbol)
256
    '''
257

    
258
    def buildItem(self, name, _type, angle, scale, loc, origin, connPts, dbUid=None, pointsUids=None):
259
        try:
260
            if name in SymbolSvgItem.COUNTERS:
261
                SymbolSvgItem.COUNTERS[name] += 1
262
            else:
263
                SymbolSvgItem.COUNTERS[name] = 1
264

    
265
            self.name = name
266
            self.index = SymbolSvgItem.COUNTERS[name]
267
            self.type = _type
268
            self.angle = angle
269
            self._scale = scale
270
            self.loc = loc
271

    
272
            docData = AppDocData.instance()
273
            if dbUid is None:
274
                symbolInfo = docData.getSymbolByQuery('name', name)
275
            else:
276
                symbolInfo = docData.getSymbolByQuery('UID', dbUid)
277

    
278
            self.dbUid = symbolInfo.uid
279
            self.category = symbolInfo.sCategory
280
            originalPoint = symbolInfo.getOriginalPoint().split(',')
281
            self.symbolOrigin = [float(originalPoint[0]), float(originalPoint[1])]
282

    
283
            # setting connectors
284
            connectionPoints = symbolInfo.getConnectionPoint().split('/')
285
            for index in range(len(connectionPoints)):
286
                if connectionPoints[index] == '':
287
                    break
288
                tokens = connectionPoints[index].split(',')
289

    
290
                direction = 'AUTO'
291
                symbol_idx = '0'
292

    
293
                if len(tokens) == 2:
294
                    x = float(tokens[0])
295
                    y = float(tokens[1])
296
                elif len(tokens) == 3:
297
                    direction = tokens[0]
298
                    x = float(tokens[1])
299
                    y = float(tokens[2])
300
                elif len(tokens) == 4:
301
                    direction = tokens[0]
302
                    x = float(tokens[1])
303
                    y = float(tokens[2])
304
                    symbol_idx = tokens[3]
305

    
306
                if pointsUids:
307
                    self.set_connector(pointsUids[index], index + 1)
308
                else:
309
                    self.set_connector(None, index + 1)
310

    
311
                self.connectors[index].direction = direction
312
                self.connectors[index].symbol_idx = symbol_idx
313
                self.connectors[index].setPos((x, y))
314
                self.connectors[index].connectPoint = (x, y)
315

    
316
            tooltip = '<b>{}</b><br>{}={}'.format(str(self.uid), self.type, self.name)
317
            self.setToolTip(tooltip)
318

    
319
            self.build_label()
320
        except Exception as ex:
321
            from App import App
322

    
323
            message = 'error occurred({}) in {}:{}'.format(ex, sys.exc_info()[-1].tb_frame.f_code.co_filename,
324
                                                          sys.exc_info()[-1].tb_lineno)
325
            App.mainWnd().addMessage.emit(MessageType.Error, message)
326

    
327
    def build_label(self):
328
        """ build equipment label """
329

    
330
        rect = self.boundingRect()
331
        if self.name in ('CV_H', 'CV_V') or self.name == 'Line_Splitter' or self.name in ('Filter_H', 'Filter_V'):
332
            if self.tag_no:
333
                data = self.connectors[0].data
334
                if data:
335
                    self.desc_label.setHtml(f"{self.tag_no}<br>{data.pressure_drop} kg/cm2<br>{data.elevation} m")
336
            else:
337
                self.desc_label.setHtml('')
338
        elif self.name in ('Y_Strainer_H', 'Y_Strainer_V'):
339
            if self.tag_no:
340
                data = self.connectors[0].data
341
                if data:
342
                    self.desc_label.setHtml(f"{self.tag_no}<br>{data.pressure_drop} kg/cm2<br>{data.elevation} m")
343
            else:
344
                self.desc_label.setHtml('')
345
        elif self.name in ('L_Pump', 'R_Pump', 'V_Pump'):
346
            if self.tag_no:
347
                data = self.connectors[0].data
348
                if data:
349
                    self.desc_label.setHtml(f"{self.tag_no}<br>{data.pressure_drop} kg/cm2<br>{data.elevation} m")
350
            else:
351
                self.desc_label.setHtml('')
352
        elif self.name in ('Ori_Flowmeter_H', 'Oth_Flowmeter_H', 'Ven_Flowmeter_H', 'Ori_Flowmeter_V', 'Oth_Flowmeter_V',
353
                           'Ven_Flowmeter_V'):
354
            if self.tag_no:
355
                data = self.connectors[0].data
356
                if data:
357
                    self.desc_label.setHtml(f"{self.tag_no}<br>{data.pressure_drop} kg/cm2<br>{data.elevation} m")
358
            else:
359
                self.desc_label.setHtml('')
360
        elif self.name in ('HEX_V', 'HEX_DP', 'HEX_H', 'HEX_K', 'HEX_V'):
361
            if self.tag_no:
362
                data = [conn.data for conn in self.connectors
363
                        if conn.data and (conn.data.pressure_drop is not None or conn.data.elevation is not None)]
364
                if data:
365
                    self.desc_label.setHtml(f"{self.tag_no}<br>{data[0].pressure_drop} kg/cm2<br>{data[0].elevation} m")
366
            else:
367
                self.desc_label.setHtml('')
368
        elif self.name == 'M_DP_E':
369
            if self.tag_no:
370
                data = [conn.data for conn in self.connectors
371
                        if conn.data and (conn.data.pressure_drop is not None or conn.data.elevation is not None)]
372
                if data:
373
                    self.desc_label.setHtml(f"{self.tag_no}<br>{data[0].pressure_drop} kg/cm2<br>{data[0].elevation} m")
374
            else:
375
                self.desc_label.setHtml('')
376
        elif self.type == 'Battery Limit':
377
            if self.tag_no:
378
                data = [conn.data for conn in self.connectors
379
                        if conn.data and (conn.data.pressure_drop is not None or conn.data.elevation is not None)]
380
                if data:
381
                    self.desc_label.setHtml(f"{self.tag_no}<br>{data[0].pressure} kg/cm2(g)<br>{data[0].elevation} m")
382
            else:
383
                self.desc_label.setHtml('')
384
        else:
385
            if self.tag_no:
386
                self.desc_label.setHtml(f"{self.tag_no}")
387
            else:
388
                self.desc_label.setHtml('')
389

    
390
        self.desc_label.setPos(QPointF(rect.width(), 0))
391

    
392
    '''
393
        @brief  return bounding box of symbol
394
        @author humkyung
395
        @date   2018.04.08
396
    '''
397

    
398
    def rect(self):
399
        return self.sceneBoundingRect()
400

    
401
    '''
402
        @brief  return true if line is able to connect symbol
403
        @author humkyung
404
        @date   2018.04.13
405
    '''
406

    
407
    def is_connectable(self, item, toler=10):
408
        # from EngineeringLineItem import QEngineeringLineItem
409

    
410
        '''
411
        if False:#type(item) is QEngineeringLineItem:
412
            line = item
413
            start_pt = line.startPoint()
414
            end_pt = line.endPoint()
415
            for connector in self.connectors:
416
                dx = connector.sceneConnectPoint[0] - (start_pt[0])
417
                dy = connector.sceneConnectPoint[1] - (start_pt[1])
418
                if (math.sqrt(dx*dx + dy*dy) < toler): return True
419
                dx = connector.sceneConnectPoint[0] - (end_pt[0])
420
                dy = connector.sceneConnectPoint[1] - (end_pt[1])
421
                if (math.sqrt(dx*dx + dy*dy) < toler): return True
422
        elif True:#issubclass(type(item), SymbolSvgItem):
423
        '''
424
        for connector in self.connectors:
425
            for iConnector in item.connectors:
426
                dx = connector.sceneConnectPoint[0] - iConnector.sceneConnectPoint[0]
427
                dy = connector.sceneConnectPoint[1] - iConnector.sceneConnectPoint[1]
428
                if (math.sqrt(dx * dx + dy * dy) < toler): return True
429

    
430
        return False
431

    
432
    '''
433
        @author     humkyung
434
        @date       2018.07.03
435
    '''
436

    
437
    def is_connected(self, item, at=QEngineeringAbstractItem.CONNECTED_AT_PT):
438
        """ check if given item is connected to self """
439

    
440
        _connectors = [connector for connector in self.connectors if
441
                       (connector.connectedItem == item and (connector._connected_at == at if at else True))]
442
        return len(_connectors) > 0
443

    
444
    def next_connected(self, lhs, rhs):
445
        """ check given two item's are next connected(ex: 0-1, 2-3) """
446

    
447
        lhs_matches = [at for at in range(len(self.connectors)) if self.connectors[at].connectedItem == lhs]
448
        rhs_matches = [at for at in range(len(self.connectors)) if self.connectors[at].connectedItem == rhs]
449
        if lhs_matches and rhs_matches:
450
            return (lhs_matches[0] in [0, 1] and rhs_matches[0] in [0, 1]) or (
451
                    lhs_matches[0] in [2, 3] and rhs_matches[0] in [2, 3])
452

    
453
        return False
454

    
455
    '''
456
        @brief      connect line and symbol is able to be connected and return line
457
        @author     humkyung
458
        @date       2018.04.16
459
        @history    humkyung 2018.05.08 check if symbol is possible to be connected
460
                    Jeongwoo 2018.05.15 Connect each symbol and line
461
    '''
462

    
463
    def connect_if_possible(self, obj, toler=10):
464
        from shapely.geometry import Point
465
        from EngineeringLineItem import QEngineeringLineItem
466

    
467
        res = []
468
        try:
469
            if type(obj) is QEngineeringLineItem:
470
                startPt = obj.startPoint()
471
                endPt = obj.endPoint()
472
                for i in range(len(self.connectors)):
473
                    if (Point(startPt[0], startPt[1]).distance(Point(self.connectors[i].sceneConnectPoint[0],
474
                                                                     self.connectors[i].sceneConnectPoint[1])) < toler):
475
                        if self.connectors[i].connectedItem is None:
476
                            self.connectors[i].connect(obj)
477
                        if obj.connectors[0].connectedItem is None:
478
                            obj.connectors[0].connect(self)
479

    
480
                        res.append(obj)
481
                    if (Point(endPt[0], endPt[1]).distance(Point(self.connectors[i].sceneConnectPoint[0],
482
                                                                 self.connectors[i].sceneConnectPoint[1])) < toler):
483
                        if self.connectors[i].connectedItem is None:
484
                            self.connectors[i].connect(obj)
485
                        if obj.connectors[1].connectedItem is None:
486
                            obj.connectors[1].connect(self)
487

    
488
                        res.append(obj)
489
            elif issubclass(type(obj), SymbolSvgItem):
490
                for i in range(len(self.connectors)):
491
                    for j in range(len(obj.connectors)):
492
                        _pt = Point(obj.connectors[j].sceneConnectPoint[0], obj.connectors[j].sceneConnectPoint[1])
493
                        if (_pt.distance(Point(self.connectors[i].sceneConnectPoint[0],
494
                                               self.connectors[i].sceneConnectPoint[1])) < toler):
495
                            if self.connectors[i].connectedItem is None:
496
                                self.connectors[i].connect(obj)
497
                            if obj.connectors[j].connectedItem is None:
498
                                obj.connectors[j].connect(self)
499

    
500
                            res.append(obj)
501
        except Exception as ex:
502
            from App import App
503
            message = 'error occurred({}) in {}:{}'.format(ex, sys.exc_info()[-1].tb_frame.f_code.co_filename,
504
                                                          sys.exc_info()[-1].tb_lineno)
505
            App.mainWnd().addMessage.emit(MessageType.Error, message)
506

    
507
        return res
508

    
509
    '''
510
        @brief      disconnect connector item
511
        @author     kyouho
512
        @date       2018.08.30
513
    '''
514

    
515
    def disconnectedItemAtConnector(self, connector):
516
        for conn in self.connectors:
517
            if conn.isOverlapConnector(connector):
518
                conn.connectedItem = None
519

    
520
    '''
521
        @brief  get connection point close to given point in tolerance
522
        @author humkyung
523
        @dat
524
    '''
525

    
526
    def getConnectionPointCloseTo(self, pt, toler=10):
527
        import math
528

    
529
        for connector in self.connectors:
530
            dx = connector.sceneConnectPoint[0] - pt[0]
531
            dy = connector.sceneConnectPoint[1] - pt[1]
532
            if math.sqrt(dx * dx + dy * dy) < toler: return connPt
533

    
534
        return None
535

    
536
    '''
537
        @brief  return center of symbol
538
        @author humkyung
539
        @date   2018.04.08
540
    '''
541

    
542
    def center(self):
543
        return self.sceneBoundingRect().center()
544

    
545
    '''
546
        @brief      highlight connector and attribute
547
        @authro     humkyung
548
        @date       2018.05.02
549
    '''
550

    
551
    def hoverEnterEvent(self, event):
552
        from Resizer import Resizer
553

    
554
        self.highlight(True)
555

    
556
        ''' 잠시 주석 처리
557
        """ create a resizer """
558
        resizer = Resizer.instance()
559
        resizer.connected = self
560
        resizerWidth = resizer.rect.width() / 2
561
        rect = self.sceneBoundingRect()
562
        resizerOffset = QPointF(resizerWidth, resizerWidth)
563
        resizer.setPos(rect.bottomRight() - resizerOffset)
564
        if resizer.receivers(resizer.resizeSignal) > 0: resizer.resizeSignal.disconnect()
565
        resizer.resizeSignal.connect(self.resize)
566
        try:
567
            self.transfer.on_pos_changed.disconnect(resizer.on_symbol_pos_changed)
568
        except Exception as ex:
569
            pass
570
        self.transfer.on_pos_changed.connect(resizer.on_symbol_pos_changed)
571
        resizer.setVisible(True)
572
        if not resizer.scene(): self.scene().addItem(resizer)
573
        '''
574

    
575
    '''
576
        @brief      unhighlight connector and attribute
577
        @author     humkyung
578
        @date       2018.05.02
579
        @history    kyouho 2018.07.18 edit ArrowCursor
580
    '''
581

    
582
    def hoverLeaveEvent(self, event):
583
        self.highlight(False)
584

    
585
    def highlight(self, flag):
586
        """ highlight/unhighlight the symbol """
587

    
588
        try:
589
            self.hover = flag
590
            self.setZValue(QEngineeringAbstractItem.HOVER_ZVALUE) if flag else self.setZValue(SymbolSvgItem.ZVALUE)
591
            self.update()
592
        except Exception as ex:
593
            from App import App
594
            message = 'error occurred({}) in {}:{}'.format(ex, sys.exc_info()[-1].tb_frame.f_code.co_filename,
595
                                                          sys.exc_info()[-1].tb_lineno)
596
            App.mainWnd().addMessage.emit(MessageType.Error, message)
597

    
598
    '''
599
        @brief      set highlight
600
        @author     kyouho
601
        @date       2018.08.27
602
    '''
603

    
604
    def setHightlight(self):
605
        self.setColor('url(#hover)')
606
        self.update()
607

    
608
    '''
609
        @brief      unset highlight
610
        @author     kyouho
611
        @date       2018.08.27
612
    '''
613

    
614
    def unsetHightlight(self):
615
        self.setColor('url(#normal)')
616
        self.update()
617

    
618
    '''
619
        @brief  change cursor to CrossCursor if mouse point is close to connection point
620
        @author humkyung
621
        @date   2018.04.28
622
    '''
623

    
624
    def hoverMoveEvent(self, event):
625
        pass
626

    
627
    '''
628
        @brief      Mouse Press Event
629
        @author     Jeongwoo
630
        @date       18.04.11
631
        @history    kyouho 2018.07.18 add isClick logic
632
    '''
633

    
634
    def mousePressEvent(self, event):
635
        if event.buttons() == Qt.LeftButton:
636
            self.clicked.emit(self)
637

    
638
    '''
639
        @brief      call on_pos_changed signal
640
        @author     humkyung
641
        @date       19.07.17
642
    '''
643

    
644
    def mouseReleaseEvent(self, event):
645
        super().mouseReleaseEvent(event)
646

    
647
    def itemChange(self, change, value):
648
        """ call signals when item's position is changed """
649
        if change == QGraphicsItem.ItemPositionHasChanged:
650
            self.transfer.on_pos_changed.emit(self)
651
            return value
652

    
653
        return super().itemChange(change, value)
654

    
655
    def removeSelfAttr(self, attributeName):
656
        target = None
657
        for attr in self.attrs:
658
            if attr.Attribute == attributeName:
659
                target = attr
660
                break
661

    
662
        if target:
663
            del self.attrs[attr]
664

    
665
    '''
666
        @brief      Check Overlap
667
        @author     kyouho
668
        @date       18.07.17
669
    '''
670

    
671
    def isOverlapItemAndPoint(self, item, point):
672
        x = point.x()
673
        y = point.y()
674
        loc = item.loc
675
        size = item.size
676

    
677
        if loc[0] <= x and loc[0] + size[0] >= x and loc[1] <= y and loc[1] + size[1] >= y:
678
            return True
679
        else:
680
            return False
681

    
682
    '''
683
        @brief  remove item when user press delete key
684
        @author humkyung
685
        @date   2018.04.23
686
        @history    2018.05.17  Jeongwoo    Add if-statement and move 'break'
687
                    2018.05.25  Jeongwoo    Seperate delete item method
688
    '''
689

    
690
    def keyPressEvent(self, event):
691
        if not self.isSelected(): return
692

    
693
        if event.key() == Qt.Key_Delete:
694
            self.deleteSvgItemFromScene()
695
        elif event.key() == Qt.Key_QuoteLeft:
696
            self.mouseDoubleClickEvent(event)
697

    
698
    '''
699
        @brief      connect attribute
700
        @author     humkyung
701
        @date       2018.05.02
702
        @history    humkyung 2018.05.09 append only nearest size attribute
703
    '''
704

    
705
    def connectAttribute(self, attributes, clear=True):
706
        import math
707

    
708
        try:
709
            if clear:
710
                self.clear_attr_and_assoc_item()
711

    
712
            configs = AppDocData.instance().getConfigs('Range', 'Detection Ratio')
713
            ratio = float(configs[0].value) if 1 == len(configs) else 1.5
714

    
715
            dist = max(self.sceneBoundingRect().height(), self.sceneBoundingRect().width()) * ratio
716
            center = self.sceneBoundingRect().center()
717

    
718
            minDist = None
719
            selected = None
720
            for attr in attributes:
721
                # size text and operation code text will find onwer themselves in findowner method
722
                if False:  # type(attr) is QEngineeringSizeTextItem or type(attr) is QEngineeringValveOperCodeTextItem:
723
                    dx = attr.center().x() - center.x()
724
                    dy = attr.center().y() - center.y()
725
                    length = math.sqrt(dx * dx + dy * dy)
726
                    if (length < dist) and (minDist is None or length < minDist):
727
                        minDist = length
728
                        selected = attr
729
                elif type(attr) is QEngineeringInstrumentItem:
730
                    if not attr.is_connected:
731
                        dx = attr.center().x() - center.x()
732
                        dy = attr.center().y() - center.y()
733
                        if math.sqrt(dx * dx + dy * dy) < dist:
734
                            if self.add_assoc_item(attr):
735
                                attr.owner = self
736

    
737
            if selected is not None:
738
                if self.add_assoc_item(selected):
739
                    selected.owner = self
740

    
741
        except Exception as ex:
742
            from App import App
743
            message = 'error occured({}) in {}:{}'.format(ex, sys.exc_info()[-1].tb_frame.f_code.co_filename,
744
                                                          sys.exc_info()[-1].tb_lineno)
745
            App.mainWnd().addMessage.emit(MessageType.Error, message)
746

    
747
    '''
748
        @brief      Double click event, Show rotate symbol dialog
749
        @author     euisung
750
        @date       2019.04.16
751
    '''
752

    
753
    def mouseDoubleClickEvent(self, event):
754
        func_map = [
755
            (('Equipment - [ Pressure Drop ]', 'Air Fin Cooler', 'AF_Cooler'), self.show_AirFinCooler),
756
            (('Equipment - [ Pressure Drop ]', 'Filter', ('Filter_H', 'Filter_V')), self.show_Filter),
757
            (('Equipment - [ Pressure Drop ]', 'Heat Exchanger', ('HEX_DP', 'HEX_H', 'HEX_K', 'HEX_V')),
758
             self.show_ShlTubHeatExchanger),
759
            (('Equipment - [ Pressure Drop ]', 'Heat Exchanger', ('HEX_P')), self.show_PlateHeatExchanger),
760
            (('Equipment - [ Pressure Drop ]', 'Miscellaneous', ('M_Coil')), self.show_Coil),
761
            (('Equipment - [ Pressure Drop ]', 'Miscellaneous', ('M_DP_E')), self.show_DP_Equipment),
762
            (('Equipment - [ Pressure Drop ]', 'Miscellaneous', ('M_React')), self.show_Reactor),
763
            (('Equipment - [ Pressure Drop ]', 'Strainer', ('T_Strainer_H', 'T_Strainer_V')), self.show_Strainer_T),
764
            (('Equipment - [ Pressure Drop ]', 'Strainer', ('Y_Strainer_H', 'Y_Strainer_V')), self.show_Strainer_Y),
765
            (('Equipment - [ Pressurized ]', 'Battery Limit', None), self.show_BatteryLimit),
766
            (('Equipment - [ Pressurized ]', 'Column', ('CwT')), self.show_Tray),
767
            (('Equipment - [ Pressurized ]', 'Column', ('CwP_Single')), self.show_SinglePacked),
768
            (('Equipment - [ Pressurized ]', 'Column', ('CwP_Dual')), self.show_DualPacked),
769
            (('Equipment - [ Pressurized ]', 'Drum', ('Drum_H')), self.show_Drum_Horizontal),
770
            (('Equipment - [ Pressurized ]', 'Drum', ('Drum_V')), self.show_Drum_Vertical),
771
            (('Equipment - [ Pressurized ]', 'Miscellaneous', ('ME')), self.show_Equipment),
772
            (('Equipment - [ Pressurized ]', 'Tank', ('Ball_Tank')), self.show_Ball),
773
            (('Equipment - [ Pressurized ]', 'Tank', ('CRT')), self.show_ConeRoof),
774
            (('Equipment - [ Pressurized ]', 'Tank', ('DRT')), self.show_DomeRoof),
775
            (('Equipment - [ Rotating ]', 'Compressor', ('L_Comp', 'R_Comp')), self.show_Compressor),
776
            (('Equipment - [ Rotating ]', 'Compressor', ('L_Komp', 'R_Komp')), self.show_Kompressor),
777
            (('Equipment - [ Rotating ]', 'Pump', ('L_Pump', 'R_Pump', 'V_Pump')), self.show_Pump),
778
            (('Instrument', 'Valve', ('CV_H', 'CV_V')), self.show_ValveControl),
779
            (('Instrument', 'Valve', ('MV_H', 'MV_V')), self.show_ValveManual),
780
            (('Instrument', 'Line Splitter', ('Line_Splitter')), self.show_LineSplitter),
781
            (('Instrument', 'Flowmeter', (
782
                'Ori_Flowmeter_H', 'Oth_Flowmeter_H', 'Ven_Flowmeter_H', 'Ori_Flowmeter_V', 'Oth_Flowmeter_V',
783
                'Ven_Flowmeter_V')), self.show_Flowmeter),
784
            (('Instrument', 'Reducer', ('Re_Ex_Dw', 'Re_Ex_L', 'Re_Ex_R', 'Re_Ex_Up')), self.show_Reducer)
785
        ]
786

    
787
        connectedItems = [connector for connector in self.connectors if connector.connectedItem is not None]
788
        if len(connectedItems) < 1:
789
            msg = QMessageBox()
790
            msg.setIcon(QMessageBox.Information)
791
            msg.setText(self.tr('Connect Line before Data input'))
792
            msg.setWindowTitle(self.tr("Notice"))
793
            msg.setStandardButtons(QMessageBox.Ok)
794
            msg.exec_()
795
            return
796

    
797
        matches = [func for func in func_map if func[0][0] == self.category and func[0][1] == self.type and (
798
                func[0][2] is None or self.name in func[0][2])]
799
        if matches: matches[0][1]()
800

    
801
    def show_AirFinCooler(self):
802
        from AirFinCooler import QAirFinCooler
803

    
804
        dialog = QAirFinCooler()
805
        if dialog.show_dialog(self):
806
            self.build_label()
807

    
808
    def show_Filter(self):
809
        from Filter import QFilter
810

    
811
        dialog = QFilter()
812
        if dialog.show_dialog(self):
813
            self.build_label()
814

    
815
    def show_Coil(self):
816
        from Coil import QCoil
817

    
818
        dialog = QCoil()
819
        if dialog.show_dialog(self):
820
            self.build_label()
821

    
822
    def show_DP_Equipment(self):
823
        from DP_Equipment import QDP_Equipment
824

    
825
        dialog = QDP_Equipment()
826
        if dialog.show_dialog(self):
827
            self.build_label()
828

    
829
    def show_Reactor(self):
830
        from Reactor import QReactor
831

    
832
        dialog = QReactor()
833
        if dialog.show_dialog(self):
834
            self.build_label()
835

    
836
    def show_Strainer_T(self):
837
        from Strainer_T import QStrainer_T
838

    
839
        dialog = QStrainer_T()
840
        if dialog.show_dialog(self):
841
            self.build_label()
842

    
843
    def show_Strainer_Y(self):
844
        from Strainer_Y import QStrainer_Y
845

    
846
        dialog = QStrainer_Y()
847
        if dialog.show_dialog(self):
848
            self.build_label()
849

    
850
    def show_BatteryLimit(self):
851
        from BatteryLimit import QBatteryLimit
852

    
853
        dialog = QBatteryLimit()
854
        if dialog.show_dialog(self):
855
            self.build_label()
856

    
857
    def show_Tray(self):
858
        from Tray import QTray
859

    
860
        dialog = QTray()
861
        if dialog.show_dialog(self):
862
            self.build_label()
863

    
864
    def show_SinglePacked(self):
865
        from SinglePacked import QSinglePacked
866

    
867
        dialog = QSinglePacked()
868
        if dialog.show_dialog(self):
869
            self.build_label()
870

    
871
    def show_DualPacked(self):
872
        from DualPacked import QDualPacked
873

    
874
        dialog = QDualPacked()
875
        if dialog.show_dialog(self):
876
            self.build_label()
877

    
878
    def show_Drum_Horizontal(self):
879
        from Drum_Horizontal import QDrum_Horizontal
880

    
881
        dialog = QDrum_Horizontal()
882
        if dialog.show_dialog(self):
883
            self.build_label()
884

    
885
    def show_Drum_Vertical(self):
886
        from Drum_Vertical import QDrum_Vertical
887

    
888
        dialog = QDrum_Vertical()
889
        if dialog.show_dialog(self):
890
            self.build_label()
891

    
892
    def show_PlateHeatExchanger(self):
893
        from PlateHeatExchanger import QPlateHeatExchanger
894

    
895
        dialog = QPlateHeatExchanger()
896
        dialog.show_dialog(self)
897

    
898
    def show_Equipment(self):
899
        from Equipment import QEquipment
900

    
901
        dialog = QEquipment()
902
        if dialog.show_dialog(self):
903
            self.build_label()
904

    
905
    def show_Ball(self):
906
        from Ball import QBall
907

    
908
        dialog = QBall()
909
        if dialog.show_dialog(self):
910
            self.build_label()
911

    
912
    def show_ShlTubHeatExchanger(self):
913
        from ShlTubHeatExchanger import QShlTubHeatExchanger
914

    
915
        dialog = QShlTubHeatExchanger()
916
        if dialog.show_dialog(self):
917
            self.build_label()
918

    
919
    def show_ConeRoof(self):
920
        from ConeRoof import QConeRoof
921

    
922
        dialog = QConeRoof()
923
        if dialog.show_dialog(self):
924
            self.build_label()
925

    
926
    def show_DomeRoof(self):
927
        from DomeRoof import QDomeRoof
928

    
929
        dialog = QDomeRoof()
930
        if dialog.show_dialog(self):
931
            self.build_label()
932

    
933
    def show_Compressor(self):
934
        from Compressor import QCompressor
935

    
936
        dialog = QCompressor()
937
        if dialog.show_dialog(self):
938
            self.build_label()
939

    
940
    def show_Kompressor(self):
941
        from Kompressor import QKompressor
942

    
943
        dialog = QKompressor()
944
        if dialog.show_dialog(self):
945
            self.build_label()
946

    
947
    def show_Pump(self):
948
        from Pump import QPump
949

    
950
        dialog = QPump()
951
        if dialog.show_dialog(self):
952
            self.build_label()
953

    
954
    def show_ValveControl(self):
955
        from Valve_Control import QValve_Control
956

    
957
        dialog = QValve_Control()
958
        if dialog.show_dialog(self):
959
            self.build_label()
960

    
961
    def show_ValveManual(self):
962
        from Valve_Manual import QValve_Manual
963

    
964
        dialog = QValve_Manual()
965
        if dialog.show_dialog(self):
966
            self.build_label()
967

    
968
    def show_LineSplitter(self):
969
        from LineSplitter import QLineSplitter
970

    
971
        dialog = QLineSplitter()
972
        if dialog.show_dialog(self):
973
            self.build_label()
974

    
975
    def show_Flowmeter(self):
976
        from Flowmeter import QFlowmeter
977

    
978
        dialog = QFlowmeter()
979
        if dialog.show_dialog(self):
980
            self.build_label()
981

    
982
    def show_Reducer(self):
983
        from Reducer import QReducer
984

    
985
        dialog = QReducer()
986
        if dialog.show_dialog(self):
987
            self.build_label()
988

    
989
    @staticmethod
990
    def fromDatabase(componentInfos):
991
        """ create a componenet from database """
992
        item = None
993

    
994
        try:
995
            uid = componentInfos[0][0]  # uid@Components
996
            tag_no = componentInfos[0][1]  # name@Components
997
            dbUid = componentInfos[0][2]  # Symbol_UID@Components
998
            category = componentInfos[0][3]  # Category@SymbolType
999
            _type = componentInfos[0][4]  # Type@SymbolType
1000
            name = componentInfos[0][5]  # Name@Symbols
1001
            originalPoint = componentInfos[0][6]  # OriginalPoint@Symbols
1002
            x = componentInfos[0][7]  # X@Components
1003
            y = componentInfos[0][8]  # Y@Components
1004
            angle = componentInfos[0][9]  # Rotation@Components
1005
            scale = componentInfos[0][10]  # Scale@Components
1006

    
1007
            pt = []
1008
            pt.append(float(x))
1009
            pt.append(float(y))
1010

    
1011
            origin = [float(x) for x in str(originalPoint).split(',')]
1012

    
1013
            connPts = []
1014

    
1015
            pointsUids = []
1016
            for componentInfo in componentInfos:
1017
                pointsUid = componentInfo[11]  # uid@Points
1018
                pointsUids.append(pointsUid)
1019

    
1020
            app_doc_data = AppDocData.instance()
1021
            svgFilePath = os.path.join(app_doc_data.symbol_file_path, category, _type, name + '.svg')
1022

    
1023
            if os.path.isfile(svgFilePath):
1024
                item = SymbolSvgItem.createItem(_type, svgFilePath, uid)
1025
                item.setVisible(False)
1026
                item.buildItem(name, _type, float(angle), float(scale), pt, origin, connPts, dbUid, pointsUids)
1027
                item.tag_no = tag_no
1028
        except Exception as ex:
1029
            from App import App
1030
            message = 'error occurred({}) in {}:{}'.format(ex, sys.exc_info()[-1].tb_frame.f_code.co_filename,
1031
                                                          sys.exc_info()[-1].tb_lineno)
1032
            App.mainWnd().addMessage.emit(MessageType.Error, message)
1033

    
1034
        return item
1035

    
1036
    '''
1037
        @brief      create item corresponding to given type
1038
        @author     humkyung
1039
        @date       2018.05.02
1040
        @history    2018.05.08  Jeongwoo    Change type name (Piping OPC''S → Piping OPC's)
1041
                    humkyung 2018.05.10 change symbol's color to blue
1042
                    humkyung 2018.07.19 create nozzle instance if type is 'Nozzles'
1043
    '''
1044

    
1045
    @staticmethod
1046
    def createItem(type, path, uid=None, owner=None, flip=0):
1047
        import uuid
1048

    
1049
        item = SymbolSvgItem(path, uid, flip=flip)
1050

    
1051
        if owner is not None:
1052
            item.owner = uuid.UUID(owner, version=4)
1053

    
1054
        return item
1055

    
1056
    '''
1057
        @brief      change svg's color
1058
        @author     humkyung
1059
        @date       2018.05.10
1060
        @history    2018.05.11  Jeongwoo    Override QEngineeringAbstractItem's
1061
                    humkyung 2018.05.13 update after change color
1062
    '''
1063

    
1064
    def setColor(self, color):
1065
        self.changeAttributes('fill', color)
1066
        self.changeAttributes('stroke', color)
1067
        self.renderer().load(self._document.toByteArray())
1068
        self.update()
1069

    
1070
    def getColor(self):
1071
        """ return hover color if mouse is over otherwise reutrn owner's color if owner exist else this color """
1072
        return SymbolSvgItem.HOVER_COLOR if self.hover else (
1073
            self.owner._color if self.owner and hasattr(self.owner, '_color') else self._color)
1074

    
1075
    '''
1076
        @brief  get attributes from svg file
1077
        @author humkyung
1078
        @date   2019.03.08
1079
    '''
1080

    
1081
    def get_attribute(self, attName):
1082
        root = self._document.documentElement()
1083
        node = root.firstChild()
1084
        while not node.isNull():
1085
            if node.isElement():
1086
                element = node.toElement()
1087
                if element.hasAttribute(attName):
1088
                    return element.attribute(attName)
1089

    
1090
                if element.hasChildNodes():
1091
                    att_val = self.recursive_get_attribute(element.firstChild(), attName)
1092
                    if att_val is not None: return att_val
1093

    
1094
            node = node.nextSibling()
1095

    
1096
        return None
1097

    
1098
    '''
1099
        @brief  get recursively attribute
1100
        @author humkyung
1101
        @date   2019.03.08
1102
    '''
1103

    
1104
    def recursive_get_attribute(self, node, attName):
1105
        while not node.isNull():
1106
            if node.isElement():
1107
                element = node.toElement()
1108
                if element.hasAttribute(attName):
1109
                    return element.attribute(attName)
1110

    
1111
                if node.hasChildNodes():
1112
                    att_val = self.recursive_get_attribute(node.firstChild(), attName)
1113
                    if att_val is not None: return att_val
1114

    
1115
            node = node.nextSibling()
1116

    
1117
        return None
1118

    
1119
    '''
1120
        @brief  change attributes
1121
        @author humkyung
1122
        @date   2018.05.10
1123
    '''
1124

    
1125
    def changeAttributes(self, attName, attValue):
1126
        root = self._document.documentElement()
1127
        node = root.firstChild()
1128
        while not node.isNull():
1129
            if node.isElement():
1130
                element = node.toElement()
1131
                if element.hasAttribute(attName):
1132
                    element.setAttribute(attName, attValue)
1133

    
1134
                if element.hasChildNodes():
1135
                    recursiveChangeAttributes(element.firstChild(), attName, attValue)
1136

    
1137
            node = node.nextSibling()
1138

    
1139
    '''
1140
        @brief  change attribute
1141
        @author humkyung
1142
        @date   2018.05.10
1143
    '''
1144

    
1145
    def recursiveChangeAttributes(self, node, attName, attValue):
1146
        while not node.isNull():
1147
            if node.isElement():
1148
                element = node.toElement()
1149
                if element.hasAttribute(attName):
1150
                    element.setAttribute(attName, attValue)
1151

    
1152
                if node.hasChildNodes():
1153
                    recursiveChangeAttributes(node.firstChild(), attName, attValue)
1154

    
1155
            node = node.nextSibling()
1156

    
1157
    '''
1158
        @brief  draw rect when item is selected
1159
        @author humkyung
1160
        @date   2018.07.07
1161
    '''
1162

    
1163
    def draw_focus_rect(self, painter):
1164
        self.focuspen = QPen(Qt.DotLine)
1165
        self.focuspen.setColor(Qt.black)
1166
        self.focuspen.setWidthF(1.5)
1167
        hilightColor = QColor(255, 0, 0, 127)
1168
        painter.setBrush(QBrush(hilightColor))
1169
        painter.setPen(self.focuspen)
1170
        painter.drawRect(self.boundingRect())
1171

    
1172
    '''
1173
        @brief  override paint(draw connection points)
1174
        @author humkyung
1175
        @date   2018.04.21
1176
    '''
1177

    
1178
    def paint(self, painter, options=None, widget=None):
1179
        from EngineeringAbstractItem import QEngineeringAbstractItem
1180
        from EngineeringTextItem import QEngineeringTextItem
1181

    
1182
        self.setColor(self.getColor())
1183

    
1184
        painter.setClipRect(options.exposedRect)
1185
        QGraphicsSvgItem.paint(self, painter, options, widget)
1186
        for attr in self.attrs:
1187
            if issubclass(type(attr), QEngineeringTextItem):
1188
                color = QEngineeringAbstractItem.HOVER_COLOR if self.hover else (
1189
                    self._owner._color if self._owner else QEngineeringAbstractItem.DEFAULT_COLOR)
1190
                attr.setColor(color)
1191
            elif issubclass(type(attr), SymbolSvgItem):
1192
                attr.setColor(self.getColor())
1193
                attr.update()
1194

    
1195
        if self.isSelected():
1196
            self.draw_focus_rect(painter)
1197

    
1198
    '''
1199
        @brief      Add Svg Item into ImageViewer's Scene
1200
        @author     Jeongwoo
1201
        @date       2018.05.03
1202
        @history    add connectors which's parent is symbol
1203
                    kyouho  2018.07.30  remove connectors logic
1204
    '''
1205

    
1206
    def addSvgItemToScene(self, scene):
1207
        transform = QTransform()
1208

    
1209
        transform.translate(self.loc[0] + self.symbolOrigin[0], self.loc[1] + self.symbolOrigin[1])
1210
        transform.rotateRadians(-self.angle)
1211
        transform.translate(-self.symbolOrigin[0], -self.symbolOrigin[1])
1212
        transform.scale(self._scale, self._scale)
1213

    
1214
        self.setTransform(transform)
1215
        scene.addItem(self)
1216

    
1217
    '''
1218
        @brief      
1219
        @author     humkyung
1220
        @date       2018.07.27
1221
    '''
1222

    
1223
    def onConnectorPosChaned(self, connector):
1224
        pass
1225

    
1226
    '''
1227
        @brief      set connector
1228
        @author     kyouho
1229
        @date       2018.07.26
1230
    '''
1231

    
1232
    def set_connector(self, uid, index=None):
1233
        from AppDocData import AppDocData
1234

    
1235
        app_doc_data = AppDocData.instance()
1236
        connector = QEngineeringConnectorItem(uid, parent=self, index=index)
1237
        connector.data = app_doc_data.get_nozzle_data(uid)
1238
        connector.setParentItem(self)
1239
        self.connectors.append(connector)
1240

    
1241
    '''
1242
    '''
1243

    
1244
    def refreshConnector(self):
1245
        for connector in self.connectors:
1246
            connector.buildItem()
1247

    
1248
    def deleteSvgItemFromScene(self):
1249
        """ remove self from scene """
1250
        try:
1251
            for conn in self.connectors:
1252
                if conn.connectedItem is not None:
1253
                    conn.connectedItem.connect(None)
1254
        except Exception as ex:
1255
            from App import App
1256
            from AppDocData import MessageType
1257

    
1258
            message = 'error occurred({}) in {}:{}'.format(ex, sys.exc_info()[-1].tb_frame.f_code.co_filename,
1259
                                                          sys.exc_info()[-1].tb_lineno)
1260
            App.mainWnd().addMessage.emit(MessageType.Error, message)
1261

    
1262
        self.transfer.onRemoved.emit(self)
1263

    
1264
    '''
1265
        @brief      Return real item position
1266
        @author     Jeongwoo
1267
        @date       2018.05.25
1268
    '''
1269

    
1270
    def boundingRectOnScene(self):
1271
        rect = self.boundingRect()
1272
        rect.moveTo(self.loc[0], self.loc[1])
1273
        return rect
1274

    
1275
    def flipSymbol(self):
1276
        '''
1277
            @brief  remove item when user press delete key
1278
            @author humkyung
1279
            @date   2018.04.23
1280
        '''
1281
        if self.flip is 0:
1282
            self.flip = 1
1283
        else:
1284
            self.flip = 0
1285

    
1286
        currentPoint = self.getCurrentPoint()
1287
        self.reSettingSymbol(currentPoint, self.angle)
1288

    
1289
    '''
1290
        @brief      rotate Symbol
1291
        @author     kyouho
1292
        @date       2018.07.24
1293
    '''
1294

    
1295
    def rotateSymbol(self, angle=None):
1296
        if angle is None:
1297
            # degree 0
1298
            if 0 == self.angle:
1299
                self.angle = 1.57
1300
            # degree 90
1301
            elif (1.57 == self.angle):
1302
                self.angle = 3.14
1303
            # degree 180
1304
            elif 3.14 == self.angle:
1305
                self.angle = 4.71
1306
            # degree 270
1307
            elif 4.71 == self.angle:
1308
                self.angle = 0
1309
            else:
1310
                self.angle = 0
1311

    
1312
            self.size[0], self.size[1] = self.size[1], self.size[0]
1313
        else:
1314
            self.angle = angle
1315

    
1316
        # scene = self.scene()
1317
        # self.scene().removeItem(self)
1318
        # self.addSvgItemToScene(scene)
1319
        currentPoint = self.getCurrentPoint()
1320
        self.reSettingSymbol(currentPoint, self.angle)
1321

    
1322
    '''
1323
        @brief      resetting rotate Symbol
1324
        @author     kyouho
1325
        @date       2018.07.24
1326
    '''
1327

    
1328
    def reSettingSymbol(self, standardPoint, angle):
1329
        transform = QTransform()
1330

    
1331
        transform.translate(self.loc[0] + self.symbolOrigin[0], self.loc[1] + self.symbolOrigin[1])
1332
        transform.rotateRadians(-angle)
1333
        transform.translate(-standardPoint[0], -standardPoint[1])
1334

    
1335
        if self.flip is 1:
1336
            transform.scale(-1.0, 1.0)
1337
            transform.translate(-self.size[0], 0)
1338

    
1339
        self.setTransform(transform)
1340
        self.reSettingConnetors()
1341

    
1342
    def reSettingConnetors(self):
1343
        for conn in self.connectors:
1344
            conn.sceneConnectPoint = (conn.sceneBoundingRect().center().x(), conn.sceneBoundingRect().center().y())
1345

    
1346
        from EngineeringLineItem import QEngineeringLineItem
1347
        for connector in self.connectors:
1348
            if connector.connectedItem is not None and type(connector.connectedItem) == QEngineeringLineItem:
1349
                line = connector.connectedItem
1350
                line.reDrawLine(self, connector.center())
1351
                line.update_arrow()
1352

    
1353
    '''
1354
        @brief      change Conn point 
1355
        @author     kyouho
1356
        @date       2018.07.25
1357
    '''
1358

    
1359
    def changeConnPoint(self):
1360
        if len(self.connectors) == 2:
1361
            conn1Item = self.connectors[0].connectedItem
1362
            conn2Item = self.connectors[1].connectedItem
1363
            self.connectors[0].connectedItem = conn2Item
1364
            self.connectors[1].connectedItem = conn1Item
1365

    
1366
            currentPoint = self.getCurrentPoint()
1367
            self.reSettingSymbol(currentPoint, self.angle)
1368

    
1369
    '''
1370
        @brief      change standard point
1371
        @author     kyouho
1372
        @date       2018.07.24
1373
    '''
1374

    
1375
    def changeStandardPoint(self):
1376
        connPtsCount = len(self.connectors)
1377

    
1378
        if self.currentPointModeIndex < connPtsCount:
1379
            self.currentPointModeIndex += 1
1380
        else:
1381
            self.currentPointModeIndex = 0
1382

    
1383
        currentPoint = self.getCurrentPoint()
1384
        self.reSettingSymbol(currentPoint, self.angle)
1385

    
1386
    '''
1387
        @brief      get standard point
1388
        @author     kyouho
1389
        @date       2018.07.25
1390
    '''
1391

    
1392
    def getCurrentPoint(self):
1393

    
1394
        pointList = []
1395
        pointList.append(self.symbolOrigin)
1396
        for connector in self.connectors:
1397
            pointList.append(connector.connectPoint)
1398

    
1399
        # if type(self) is QEngineeringSpecBreakItem:
1400
        #    self.currentPointModeIndex = 1
1401

    
1402
        return pointList[self.currentPointModeIndex]
1403

    
1404
    '''
1405
        @brief      심볼 회전 시 서로 다른 기준점으로 회전하기 때문에 기준점을 이후 개발한 SymbolSvgItem 기준의 회전좌표로 이동하기 위해서 만듬 (loc 기준으로 회전해야함)
1406
        @author     kyouho
1407
        @date       18.08.06
1408
    '''
1409

    
1410
    def reCalculationRotatedItem(self):
1411

    
1412
        transform = QTransform()
1413
        transform.translate(self.loc[0] + self.symbolOrigin[0], self.loc[1] + self.symbolOrigin[1])
1414
        transform.rotateRadians(-self.angle)
1415
        currentPoint = self.getCurrentPoint()
1416
        transform.translate(-currentPoint[0], -currentPoint[1])
1417
        # 시작점을 구하기 위해서
1418
        goPoint = transform.map(QPoint(self.symbolOrigin[0], self.symbolOrigin[1]))
1419

    
1420
        self.loc = [self.loc[0] + self.origin[0] - goPoint.x(), self.loc[1] + self.origin[1] - goPoint.y()]
1421

    
1422
    def resize(self, change):
1423
        """ resize item """
1424
        # Get the smaller side of the rect
1425
        rect = self.sceneBoundingRect()
1426
        loc = QPointF(rect.x(), rect.y())
1427
        self.resetTransform()
1428
        # self.setScale(1)
1429
        rect = self.sceneBoundingRect()
1430
        scale = [(change.width() - loc.x()) / rect.width(), (change.height() - loc.y()) / rect.height()]
1431
        # scale the item
1432
        if scale[0] > 0 and scale[1] > 0:
1433
            self.setPos(loc)
1434
            # self.setScale(scale[0] if scale[0] < scale[1] else scale[1])
1435
            trans = QTransform()
1436
            trans.scale(scale[0] if scale[0] < scale[1] else scale[1], scale[0] if scale[0] < scale[1] else scale[1])
1437
            self.setTransform(trans)
1438
            self.prepareGeometryChange()
1439
            self.update()
1440

    
1441
            self.transfer.on_size_changed.emit(self)
1442

    
1443
    def moveto(self, to, timeLine=5000, rotation=0):
1444
        """Move the item from one position to one other."""
1445

    
1446
        anim = QPropertyAnimation(self, b'pos')
1447
        rect = self.sceneBoundingRect()
1448
        anim.setStartValue(QPointF(0, 0))
1449
        anim.setEndValue(QPointF(100, 10))
1450
        anim.setDuration(10000)
1451
        anim.start()
1452

    
1453

    
1454
def recursiveChangeAttributes(node, attName, attValue):
1455
    while not node.isNull():
1456
        if node.isElement():
1457
            element = node.toElement()
1458
            if element.hasAttribute(attName):
1459
                element.setAttribute(attName, attValue)
1460

    
1461
            if node.hasChildNodes():
1462
                recursiveChangeAttributes(node.firstChild(), attName, attValue)
1463

    
1464
        node = node.nextSibling()
1465

    
1466

    
1467
'''
1468
    @brief      The class transfer pyqtSignal Event. Cause Subclass of QGraphicsRectItem can't use pyqtSignal
1469
    @author     Jeongwoo
1470
    @date       2018.06.18
1471
'''
1472

    
1473

    
1474
class Transfer(QObject):
1475
    on_pos_changed = pyqtSignal(QGraphicsItem)
1476
    on_size_changed = pyqtSignal(QGraphicsItem)
1477
    onRemoved = pyqtSignal(QGraphicsItem)
1478

    
1479
    def __init__(self, parent=None):
1480
        QObject.__init__(self, parent)
1481

    
1482

    
1483
if __name__ == '__main__':
1484
    f = QFile('d:/Projects/DTIPID/DTI_PID/DTI_PID/SG_TEST/svg/ANGLE VALVE.svg')
1485
    f.open(QIODevice.ReadOnly)
1486
    array = f.readAll()
1487
    document = QDomDocument()
1488
    document.setContent(array)
1489

    
1490
    root = document.documentElement()
1491
    node = root.firstChild()
1492
    while not node.isNull():
1493
        if node.isElement():
1494
            element = node.toElement()
1495
            if element.hasAttribute('fill'):
1496
                element.setAttribute('fill', '#FFFFF')
1497

    
1498
            if element.hasChildNodes():
1499
                recursiveChangeAttributes(element.firstChild(), 'fill', '#FFFFF')
1500

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