프로젝트

일반

사용자정보

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

hytos / HYTOS / HYTOS / Shapes / SymbolSvgItem.py @ 4f696492

이력 | 보기 | 이력해설 | 다운로드 (101 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
def is_float(s):
21
    try:
22
        if s:
23
            float(s)
24
            return True
25
        else:
26
            return False
27
    except ValueError:
28
        return False
29

    
30

    
31
def is_blank(s):
32
    return not (s and s.strip())
33

    
34

    
35
def convert_to_fixed_point(value):
36
    if is_float(str(value)):
37
        tokens = f"{float(value):.10f}".split('.')
38
        if len(tokens) == 2:
39
            # 소수점 아래가 있을 경우 소수점 아래의 trailing zero를 제거한다.
40
            if is_blank(tokens[1].rstrip('0')):
41
                return tokens[0]
42
            else:
43
                tokens[1] = tokens[1].rstrip('0')
44
                return '.'.join(tokens)
45
        else:
46
            return tokens[0]
47
    else:
48
        return value
49

    
50

    
51
class SymbolSvgItem(QGraphicsSvgItem, QEngineeringAbstractItem):
52
    """This is SymbolSvgItem class"""
53

    
54
    clicked = pyqtSignal(QGraphicsSvgItem)
55
    ZVALUE = 100
56
    HOVER_COLOR = 'url(#hover)'
57
    COUNTERS = {}
58

    
59
    '''
60
        @history    18.04.11    Jeongwoo    Add Variable (Name, Type)
61
                    18.05.11    Jeongwoo    Declare variable self.color
62
                    18.05.25    Jeongwoo    Call setColor() method
63
                    18.05.30    Jeongwoo    Add self variables (parentSymbol, childSymbol)
64
    '''
65

    
66
    def __init__(self, uid=None, flip=0, symbol=None):
67
        import uuid
68
        from SymbolAttr import SymbolProp
69

    
70
        QGraphicsSvgItem.__init__(self)
71
        QEngineeringAbstractItem.__init__(self)
72

    
73
        self.setFlags(
74
            QGraphicsItem.ItemIsSelectable | QGraphicsItem.ItemIsFocusable | QGraphicsItem.ItemIsMovable |
75
            QGraphicsItem.ItemSendsGeometryChanges | QGraphicsItem.ItemClipsToShape)
76

    
77
        self.dbUid = None
78
        self.uid = uuid.uuid4() if uid is None else uuid.UUID(uid, version=4)
79
        self.name = ''
80
        self.category = ''
81
        self.type = ''
82
        self.angle = 0
83
        self._scale = 1
84
        self.origin = None
85
        self.loc = None
86
        self.size = None
87
        self._owner = None
88
        self.parentSymbol = ''
89
        self.childSymbol = ''
90
        self.hasInstrumentLabel = 0
91
        # attributeType uid
92
        self.attribute = {}
93
        self._tag_no = None
94
        self._selected_idx = None
95
        self.setAcceptDrops(True)
96
        self.setAcceptHoverEvents(True)
97
        self.setAcceptedMouseButtons(Qt.LeftButton)
98
        self.setAcceptTouchEvents(True)
99

    
100
        self.currentCursor = 0
101
        self.transfer = Transfer()
102

    
103
        try:
104
            app_doc_data = AppDocData.instance()
105
            shape = None
106
            if symbol:
107
                shape = app_doc_data.read_symbol_shape(app_doc_data.activeDrawing.path, symbol)
108

    
109
            self._document = QDomDocument()
110
            self._document.setContent(shape)
111
            self._renderer = QSvgRenderer(self._document.toByteArray())
112
            self.setSharedRenderer(self._renderer)
113

    
114
            self._color = self.get_attribute('fill')
115
        except Exception as ex:
116
            from App import App
117
            from AppDocData import MessageType
118

    
119
            message = 'error occurred({}) in {}:{}'.format(ex, sys.exc_info()[-1].tb_frame.f_code.co_filename,
120
                                                           sys.exc_info()[-1].tb_lineno)
121
            App.mainWnd().addMessage.emit(MessageType.Error, message)
122

    
123
        self.setZValue(SymbolSvgItem.ZVALUE)
124
        self.desc_labels = {}
125

    
126
    def has_attribute(self):
127
        if len(self.attribute) > 0:
128
            return True
129
        else:
130
            return False
131

    
132
    def __str__(self):
133
        """ return string represent uuid """
134
        return str(self.uid)
135

    
136
    @property
137
    def tag_no(self):
138
        return self._tag_no
139

    
140
    @tag_no.setter
141
    def tag_no(self, value):
142
        self._tag_no = value
143

    
144
    @property
145
    def owner(self):
146
        """getter owner"""
147
        import uuid
148

    
149
        if self._owner and type(self._owner) is uuid.UUID:
150
            matches = [x for x in self.scene().items() if hasattr(x, 'uid') and str(x.uid) == str(self._owner)]
151
            if matches: self._owner = matches[0]
152

    
153
        if type(self._owner) is not uuid.UUID and type(self._owner) is not str:
154
            return self._owner
155
        else:
156
            self._owner = None
157
            return None
158

    
159
    @owner.setter
160
    def owner(self, value):
161
        """setter owner"""
162
        self._owner = value
163

    
164
        if self._owner is None:
165
            self._color = self.DEFAULT_COLOR
166
        self.setColor(self._color)
167

    
168
    def validate(self):
169
        """validate symbol data"""
170

    
171
        res = []
172

    
173
        for conn in self.connectors:
174
            error = conn.validate()
175
            if error:
176
                res.append(error)
177

    
178
        return res
179

    
180
    @property
181
    def corners(self):
182
        rect = self.sceneBoundingRect()
183
        return [rect.topLeft(), rect.bottomLeft(), rect.bottomRight(), rect.topRight()]
184

    
185
    def resize(self, change):
186
        """ resize item """
187
        try:
188
            rect = self.boundingRect()
189
            if rect.isValid():
190
                self.resetTransform()
191
                self.setPos(change.topLeft())
192
                scale = min([change.width() / rect.width(), change.height() / rect.height()])
193
                # scale the item
194
                self.setScale(scale)
195

    
196
                # scale down for label
197
                for conn, label in self.desc_labels.items():
198
                    label.setScale(1/scale)
199
                # up to here
200

    
201
                self.prepareGeometryChange()
202
                self.update()
203
        except Exception as ex:
204
            from App import App
205

    
206
            message = 'error occurred({}) in {}:{}'.format(ex, sys.exc_info()[-1].tb_frame.f_code.co_filename,
207
                                                           sys.exc_info()[-1].tb_lineno)
208
            App.mainWnd().addMessage.emit(MessageType.Error, message)
209

    
210
    def toSql(self):
211
        import uuid
212
        """ convert valve data to sql query """
213

    
214
        res = []
215

    
216
        try:
217
            rect = self.sceneBoundingRect()
218

    
219
            cols = ['UID', 'Symbols_UID', 'Name', '[Index]', 'X', 'Y', 'Rotation', 'Scale']
220
            values = ['?', '?', '?', '?', '?', '?', '?', '?']
221
            param = [str(self.uid), str(self.dbUid), str(self.tag_no) if self.tag_no is not None else self.tag_no,
222
                     self.index, rect.left(), rect.top(),
223
                     str(self.angle), self.transform().m11()]
224
            sql = 'insert or replace into Components({}) values({})'.format(','.join(cols), ','.join(values))
225
            res.append((sql, tuple(param)))
226

    
227
            # save connectors to database
228
            index = 1
229
            for connector in self.connectors:
230
                res.extend(connector.toSql(index))
231
                index += 1
232
            # up to here
233

    
234
            # save nozzle label
235
            for conn, label in self.desc_labels.items():
236
                res.extend(label.toSql(conn))
237
            # up to here
238

    
239
        except Exception as ex:
240
            from App import App
241

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

    
246
        return res
247

    
248
    def buildItem(self, name, _type, angle, scale, loc, origin, connPts, dbUid=None, pointsUids=None, index=None):
249
        """build symbol item"""
250

    
251
        from App import App
252

    
253
        try:
254
            # index가 없을때(사용자 생성시) 같은 이름의 심볼 인덱스의 최대값 + 1을 index로 설정
255
            if not index:
256
                matches = [item for item in App.mainWnd().graphicsView.scene.items()
257
                           if type(item) is SymbolSvgItem and item.name == name]
258
                if matches:
259
                    matches.sort(key=lambda item: item.index)
260
                    index = matches[-1].index + 1
261
                else:
262
                    index = 1
263

    
264
            self.name = name
265
            self.index = index
266
            self.type = _type
267
            self.angle = angle
268
            self._scale = scale
269
            self.loc = loc
270

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

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

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

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

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

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

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

    
315
            tooltip = f"<b>{self.uid}</b><br>{self.type}={self.name}_{self.index}"
316
            self.setToolTip(tooltip)
317
        except Exception as ex:
318
            from App import App
319

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

    
324
    def get_label_pos_of_connector(self, conn, label):
325
        """return label position of given connector"""
326

    
327
        res = None
328

    
329
        app_doc_data = AppDocData.instance()
330
        if conn.data.pos:
331
            res = QPointF(conn.data.pos[0], conn.data.pos[1])
332
        else:
333
            label_rect = label.boundingRect()
334
            conn_rect = conn.mapRectFromParent(conn.boundingRect())
335
            dx, dy = conn.dir()
336

    
337
            if dx == 1:
338
                res = QPointF(conn_rect.x() + conn_rect.width() * 0.5, conn_rect.y())
339
            elif dy == -1:
340
                res = QPointF(conn_rect.x() + conn_rect.width()*0.5, conn_rect.y() - label_rect.height())
341
            elif dy == 1:
342
                res = QPointF(conn_rect.x() + conn_rect.width()*0.5, conn_rect.y() + conn_rect.height()*0.5)
343
            elif dx == -1:
344
                res = QPointF(conn_rect.x() - label_rect.width(), conn_rect.y() + conn_rect.height()*0.5)
345

    
346
        return res
347

    
348
    def build_label(self):
349
        try:
350
            """build equipment label"""
351

    
352
            rect = self.boundingRect()
353

    
354
            app_doc_data = AppDocData.instance()
355
            units = [attr[1] for attr in app_doc_data.activeDrawing.attrs if attr[0] == 'Units'][0]
356

    
357
            self.update_label_contents()
358

    
359
            if self.category == 'Equipment - [ Pressure Drop ]':
360
                if self.type == 'Air Fin Cooler':
361
                    conns = [conn for conn in self.connectors if conn.data and conn.data.elevation is not None]
362
                    if conns:
363
                        pos = self.get_label_pos_of_connector(conns[0], self.desc_labels[conns[0]])
364
                        self.desc_labels[conns[0]].setPos(pos)
365
                elif self.type == 'Filter':
366
                    if self.tag_no:
367
                        conns = [conn for conn in self.connectors if conn.data and conn.data.elevation is not None]
368
                        if conns:
369
                            pos = self.get_label_pos_of_connector(conns[0], self.desc_labels[conns[0]])
370
                            self.desc_labels[conns[0]].setPos(pos)
371
                elif self.type == 'Heat Exchanger':
372
                    if self.tag_no:
373
                        nozzles = []
374
                        for conn in self.connectors:
375
                            if conn.data and (conn.data.pressure_drop is not None or conn.data.elevation is not None):
376
                                nozzle = str(conn).rsplit('_', 1)[1]
377
                                nozzles.append(nozzle)
378

    
379
                        if len(nozzles) > 0:
380
                            if self.name == 'HEX_DP':
381
                                if 'N1' in nozzles and 'N2' in nozzles:
382
                                    label_rect = self.desc_labels[self.connectors[0]].boundingRect()
383
                                    pos = self.get_label_pos_of_connector(self.connectors[0],
384
                                                                           self.desc_labels[self.connectors[0]])
385
                                    self.desc_labels[self.connectors[0]].setPos(pos)
386
                                elif 'N1' in nozzles:
387
                                    pos = self.get_label_pos_of_connector(self.connectors[0],
388
                                                                          self.desc_labels[self.connectors[0]])
389
                                    self.desc_labels[self.connectors[0]].setPos(pos)
390
                                elif 'N2' in nozzles:
391
                                    pos = self.get_label_pos_of_connector(self.connectors[1],
392
                                                                          self.desc_labels[self.connectors[1]])
393
                                    self.desc_labels[self.connectors[1]].setPos(pos)
394
                            elif self.name == 'HEX_H':
395
                                if 'N1' in nozzles and 'N2' in nozzles:
396
                                    pos = self.get_label_pos_of_connector(self.connectors[0],
397
                                                                          self.desc_labels[self.connectors[0]])
398
                                    self.desc_labels[self.connectors[0]].setPos(pos)
399
                                elif 'N1' in nozzles:
400
                                    pos = self.get_label_pos_of_connector(self.connectors[0],
401
                                                                          self.desc_labels[self.connectors[0]])
402
                                    self.desc_labels[self.connectors[0]].setPos(pos)
403
                                elif 'N2' in nozzles:
404
                                    pos = self.get_label_pos_of_connector(self.connectors[1],
405
                                                                          self.desc_labels[self.connectors[1]])
406
                                    self.desc_labels[self.connectors[1]].setPos(pos)
407
                            elif self.name == 'HEX_K':
408
                                if 'N1' in nozzles and 'N2' in nozzles:
409
                                    pos = self.get_label_pos_of_connector(self.connectors[0],
410
                                                                          self.desc_labels[self.connectors[0]])
411
                                    self.desc_labels[self.connectors[0]].setPos(pos)
412
                                elif 'N1' in nozzles:
413
                                    pos = self.get_label_pos_of_connector(self.connectors[0],
414
                                                                          self.desc_labels[self.connectors[0]])
415
                                    self.desc_labels[self.connectors[0]].setPos(pos)
416
                                elif 'N2' in nozzles:
417
                                    pos = self.get_label_pos_of_connector(self.connectors[1],
418
                                                                          self.desc_labels[self.connectors[1]])
419
                                    self.desc_labels[self.connectors[1]].setPos(pos)
420
                            elif self.name == 'HEX_P':
421
                                if 'N1' in nozzles and 'N2' in nozzles:
422
                                    pos = self.get_label_pos_of_connector(self.connectors[0],
423
                                                                          self.desc_labels[self.connectors[0]])
424
                                    self.desc_labels[self.connectors[0]].setPos(pos)
425
                                elif 'N1' in nozzles:
426
                                    pos = self.get_label_pos_of_connector(self.connectors[0],
427
                                                                          self.desc_labels[self.connectors[0]])
428
                                    self.desc_labels[self.connectors[0]].setPos(pos)
429
                                elif 'N2' in nozzles:
430
                                    pos = self.get_label_pos_of_connector(self.connectors[1],
431
                                                                          self.desc_labels[self.connectors[1]])
432
                                    self.desc_labels[self.connectors[1]].setPos(pos)
433
                            elif self.name == 'HEX_V':
434
                                if 'N1' in nozzles and 'N2' in nozzles:
435
                                    pos = self.get_label_pos_of_connector(self.connectors[2],
436
                                                                          self.desc_labels[self.connectors[2]])
437
                                    self.desc_labels[self.connectors[2]].setPos(pos)
438
                                elif 'N1' in nozzles:
439
                                    pos = self.get_label_pos_of_connector(self.connectors[0],
440
                                                                          self.desc_labels[self.connectors[0]])
441
                                    self.desc_labels[self.connectors[0]].setPos(pos)
442
                                elif 'N2' in nozzles:
443
                                    pos = self.get_label_pos_of_connector(self.connectors[1],
444
                                                                          self.desc_labels[self.connectors[1]])
445
                                    self.desc_labels[self.connectors[1]].setPos(pos)
446
                elif self.type == 'Miscellaneous':
447
                    if self.name == 'M_Coil':
448
                        if self.tag_no:
449
                            conns = [conn for conn in self.connectors if conn.data and conn.data.elevation is not None]
450
                            if conns:
451
                                pos = self.get_label_pos_of_connector(conns[0], self.desc_labels[conns[0]])
452
                                self.desc_labels[conns[0]].setPos(pos)
453
                    elif self.name == 'M_DP_E':
454
                        if self.tag_no:
455
                            nozzles = []
456
                            for conn in self.connectors:
457
                                if conn.data and (conn.data.pressure_drop is not None or conn.data.elevation is not None):
458
                                    nozzle = str(conn).rsplit('_', 1)[1]
459
                                    nozzles.append(nozzle)
460

    
461
                            if len(nozzles) > 0:
462
                                if 'N1' in nozzles and 'N2' in nozzles:
463
                                    label_rect = self.desc_labels[self.connectors[0]].boundingRect()
464
                                    pos = self.get_label_pos_of_connector(self.connectors[0],
465
                                                                          self.desc_labels[self.connectors[0]])
466
                                    self.desc_labels[self.connectors[0]].setPos(pos)
467
                                elif 'N1' in nozzles:
468
                                    pos = self.get_label_pos_of_connector(self.connectors[0],
469
                                                                          self.desc_labels[self.connectors[0]])
470
                                    self.desc_labels[self.connectors[0]].setPos(pos)
471
                                elif 'N2' in nozzles:
472
                                    pos = self.get_label_pos_of_connector(self.connectors[1],
473
                                                                          self.desc_labels[self.connectors[1]])
474
                                    self.desc_labels[self.connectors[1]].setPos(pos)
475
                    elif self.name == 'M_React':
476
                        if self.tag_no:
477
                            nozzles = []
478
                            for conn in self.connectors:
479
                                if conn.data and (conn.data.pressure_drop is not None or conn.data.elevation is not None):
480
                                    nozzle = str(conn).rsplit('_', 1)[1]
481
                                    nozzles.append(nozzle)
482

    
483
                            if len(nozzles) > 0:
484
                                if ('N1' in nozzles or 'N2' in nozzles or 'N6' in nozzles) and ('N3' in nozzles or 'N4' in nozzles or 'N5' in nozzles):
485
                                    if 'N1' in nozzles:
486
                                        top_index = 0
487
                                    elif 'N2' in nozzles:
488
                                        top_index = 1
489
                                    elif 'N6' in nozzles:
490
                                        top_index = 5
491

    
492
                                    if 'N3' in nozzles:
493
                                        btm_index = 2
494
                                    elif 'N4' in nozzles:
495
                                        btm_index = 3
496
                                    elif 'N5' in nozzles:
497
                                        btm_index = 4
498

    
499
                                    pos = self.get_label_pos_of_connector(self.connectors[top_index],
500
                                                                          self.desc_labels[self.connectors[top_index]])
501
                                    self.desc_labels[self.connectors[top_index]].setPos(pos)
502

    
503
                                elif 'N1' in nozzles or 'N2' in nozzles or 'N6' in nozzles:
504
                                    if 'N1' in nozzles:
505
                                        index = 0
506
                                    elif 'N2' in nozzles:
507
                                        index = 1
508
                                    elif 'N6' in nozzles:
509
                                        index = 5
510

    
511
                                    pos = self.get_label_pos_of_connector(self.connectors[index],
512
                                                                          self.desc_labels[self.connectors[index]])
513
                                    self.desc_labels[self.connectors[index]].setPos(pos)
514

    
515
                                elif 'N3' in nozzles or 'N4' in nozzles or 'N5' in nozzles:
516
                                    if 'N3' in nozzles:
517
                                        index = 2
518
                                    elif 'N4' in nozzles:
519
                                        index = 3
520
                                    elif 'N5' in nozzles:
521
                                        index = 4
522

    
523
                                    pos = self.get_label_pos_of_connector(self.connectors[index],
524
                                                                          self.desc_labels[self.connectors[index]])
525
                                    self.desc_labels[self.connectors[index]].setPos(pos)
526
                elif self.type == 'Strainer':
527
                    if self.tag_no:
528
                        conns = [conn for conn in self.connectors
529
                                 if conn.data and conn.data.pressure_drop is not None and conn.data.elevation is not None]
530
                        if conns:
531
                            pos = self.get_label_pos_of_connector(conns[0], self.desc_labels[conns[0]])
532
                            self.desc_labels[conns[0]].setPos(pos)
533
            elif self.category == 'Equipment - [ Pressurized ]':
534
                if self.type == 'Battery Limit':
535
                    if self.tag_no:
536
                        conns = [conn for conn in self.connectors
537
                                 if conn.data and conn.data.pressure is not None and conn.data.elevation is not None]
538
                        if conns:
539
                            pos = self.get_label_pos_of_connector(conns[0], self.desc_labels[conns[0]])
540
                            self.desc_labels[conns[0]].setPos(pos)
541
                elif self.type == 'Column':
542
                    if self.tag_no:
543
                        for conn in self.connectors:
544
                            if conn.data and (conn.data.pressure_drop is not None or conn.data.elevation is not None):
545
                                nozzle = str(conn).rsplit('_', 1)[1]
546
                                pos = self.get_label_pos_of_connector(conn, self.desc_labels[conn])
547
                                self.desc_labels[conn].setPos(pos)
548
                elif self.type == 'Drum':
549
                    if self.tag_no:
550
                        for conn in self.connectors:
551
                            if conn.data and (conn.data.pressure_drop is not None or conn.data.elevation is not None):
552
                                nozzle = str(conn).rsplit('_', 1)[1]
553
                                pos = self.get_label_pos_of_connector(conn, self.desc_labels[conn])
554
                                self.desc_labels[conn].setPos(pos)
555
                elif self.type == 'Miscellaneous':
556
                    if self.tag_no:
557
                        for conn in self.connectors:
558
                            if conn.data and (conn.data.pressure_drop is not None or conn.data.elevation is not None):
559
                                nozzle = str(conn).rsplit('_', 1)[1]
560
                                if conn.data:
561
                                    pos = self.get_label_pos_of_connector(conn, self.desc_labels[conn])
562
                                    self.desc_labels[conn].setPos(pos)
563
                elif self.type == 'Tank':
564
                    if self.tag_no:
565
                        for conn in self.connectors:
566
                            if conn.data and conn.connectedItem and \
567
                                    (conn.data.pressure_drop is not None or conn.data.elevation is not None):
568
                                nozzle = str(conn).rsplit('_', 1)[1]
569
                                pos = self.get_label_pos_of_connector(conn, self.desc_labels[conn])
570
                                self.desc_labels[conn].setPos(pos)
571
            elif self.category == 'Equipment - [ Rotating ]':
572
                if self.type == 'Compressor':
573
                    if self.name in ('L_Comp', 'R_Comp'):
574
                        if self.tag_no:
575
                            for conn in self.connectors:
576
                                if conn.data and (conn.data.pressure_drop is not None or conn.data.elevation is not None):
577
                                    nozzle = str(conn).rsplit('_', 1)[1]
578
                                    pos = self.get_label_pos_of_connector(conn, self.desc_labels[conn])
579
                                    self.desc_labels[conn].setPos(pos)
580
                    elif self.name in ('L_Komp', 'R_Komp'):
581
                        if self.tag_no:
582
                            conns = [conn for conn in self.connectors if conn.data and conn.data.elevation is not None]
583
                            if conns:
584
                                pos = self.get_label_pos_of_connector(conns[0], self.desc_labels[conns[0]])
585
                                self.desc_labels[conns[0]].setPos(pos)
586
                elif self.type == 'Pump':
587
                    if self.tag_no:
588
                        conns = [conn for conn in self.connectors if conn.data and conn.data.elevation is not None]
589
                        if conns:
590
                            pos = self.get_label_pos_of_connector(conns[0], self.desc_labels[conns[0]])
591
                            self.desc_labels[conns[0]].setPos(pos)
592
            elif self.category == 'Instrument':
593
                if self.type == 'Flowmeter':
594
                    if self.tag_no:
595
                        data = self.connectors[0].data
596
                        if data:
597
                            pos = self.get_label_pos_of_connector(self.connectors[0], self.desc_labels[self.connectors[0]])
598
                            self.desc_labels[self.connectors[0]].setPos(pos)
599
                elif self.type == 'Line Splitter':
600
                    if self.tag_no:
601
                        conns = [conn for conn in self.connectors
602
                                 if conn.data and conn.data.pressure_drop is not None and conn.data.elevation is not None]
603
                        if conns:
604
                            pos = self.get_label_pos_of_connector(conns[0], self.desc_labels[conns[0]])
605
                            self.desc_labels[conns[0]].setPos(pos)
606
                elif self.type == 'Reducer':
607
                    if self.tag_no:
608
                        conns = [conn for conn in self.connectors
609
                                 if conn.data and conn.data.pressure_drop is not None and conn.data.elevation is not None]
610
                        if conns:
611
                            pos = self.get_label_pos_of_connector(conns[0], self.desc_labels[conns[0]])
612
                            self.desc_labels[conns[0]].setPos(pos)
613
                elif self.type == 'Valve':
614
                    if self.tag_no and self.name in ('CV_H', 'CV_V'):
615
                        conns = [conn for conn in self.connectors if conn.data and conn.data.elevation is not None]
616
                        if conns:
617
                            pos = self.get_label_pos_of_connector(conns[0], self.desc_labels[conns[0]])
618
                            self.desc_labels[conns[0]].setPos(pos)
619
                    elif self.tag_no and self.name in ('MV_H', 'MV_V'):
620
                        conns = [conn for conn in self.connectors
621
                                 if conn.data and conn.data.pressure_drop is not None and conn.data.elevation is not None]
622
                        if conns:
623
                            pos = self.get_label_pos_of_connector(conns[0], self.desc_labels[conns[0]])
624
                            self.desc_labels[conns[0]].setPos(pos)
625

    
626
            configs = app_doc_data.getAppConfigs('option', 'TagFontSize')
627
            font_size = configs[0].value if configs and len(configs) == 1 else '6'
628

    
629
            configs = app_doc_data.getAppConfigs('option', 'TagFontColor')
630
            font_color = configs[0].value if configs and len(configs) == 1 else '#000000'
631

    
632
            for conn, label in self.desc_labels.items():
633
                label.set_font_size(font_size)
634
                label.set_font_color(font_color)
635

    
636
            self.align_labels()
637
        except Exception as ex:
638
            from App import App
639
            message = 'error occurred({}) in {}:{}'.format(ex, sys.exc_info()[-1].tb_frame.f_code.co_filename,
640
                                                           sys.exc_info()[-1].tb_lineno)
641
            App.mainWnd().addMessage.emit(MessageType.Error, message)
642

    
643
    def align_labels(self) -> None:
644
        """align labels which has same direction"""
645

    
646
        sides = {}
647
        matches = [(conn.dir(), label) for conn, label in self.desc_labels.items() if label.toPlainText()]
648
        for dir, label in matches:
649
            if dir in sides:
650
                sides[dir].append(label)
651
            else:
652
                sides[dir] = [label]
653

    
654
        for dir, labels in sides.items():
655
            if len(labels) > 1:
656

    
657
                # sort labels
658
                if dir[0] == 1 or dir[0] == -1:
659
                    sorted_labels = sorted(labels, key=lambda label: label.sceneBoundingRect().top())
660
                else:
661
                    sorted_labels = sorted(labels, key=lambda label: label.sceneBoundingRect().left())
662
                # up to here
663

    
664
                for i in range(len(sorted_labels)):
665
                    for j in range(i + 1, len(sorted_labels)):
666
                        if sorted_labels[i].collidesWithItem(sorted_labels[j]):
667
                            rect1 = sorted_labels[i].sceneBoundingRect()
668
                            rect2 = sorted_labels[j].sceneBoundingRect()
669
                            if dir[0] == 1 or dir[0] == -1:
670
                                overlap = rect1.bottom() - rect2.top()
671
                                pos = sorted_labels[i].pos()
672
                                pos.setY(pos.y() - overlap*0.5)
673
                                sorted_labels[i].setPos(pos)
674
                                pos = sorted_labels[j].pos()
675
                                pos.setY(pos.y() + overlap*0.5)
676
                                sorted_labels[j].setPos(pos)
677
                            else:
678
                                overlap = rect1.right() - rect2.left()
679
                                pos = sorted_labels[i].pos()
680
                                pos.setX(pos.x() - overlap*0.5)
681
                                sorted_labels[i].setPos(pos)
682
                                pos = sorted_labels[j].pos()
683
                                pos.setX(pos.x() + overlap*0.5)
684
                                sorted_labels[j].setPos(pos)
685

    
686
    def update_label_contents(self) -> None:
687
        """update equipment label contents"""
688

    
689
        rect = self.boundingRect()
690

    
691
        app_doc_data = AppDocData.instance()
692
        units = [attr[1] for attr in app_doc_data.activeDrawing.attrs if attr[0] == 'Units'][0]
693

    
694
        # clear labels
695
        for conn, label in self.desc_labels.items():
696
            label.setEnabled(False)
697

    
698
        if self.category == 'Equipment - [ Pressure Drop ]':
699
            if self.type == 'Air Fin Cooler':
700
                conns = [conn for conn in self.connectors if conn.data and conn.data.elevation is not None]
701
                if conns:
702
                    if conns[0].data.desc is None:
703
                        self.desc_labels[conns[0]].setHtml(
704
                            f"{self.tag_no}<br>{convert_to_fixed_point(conns[0].data.pressure_drop) if conns[0].data.pressure_drop is not None else 0} {units['Pressure']}<br>"
705
                            f"{convert_to_fixed_point(conns[0].data.elevation)} {units['Length']}")
706
                    else:
707
                        self.desc_labels[conns[0]].setHtml(conns[0].data.desc)
708
                    self.desc_labels[conns[0]].setEnabled(True)
709
            elif self.type == 'Filter':
710
                if self.tag_no:
711
                    conns = [conn for conn in self.connectors if conn.data and conn.data.elevation is not None]
712
                    if conns:
713
                        if conns[0].data.desc is None:
714
                            self.desc_labels[conns[0]].setHtml(
715
                                f"{self.tag_no}<br>{convert_to_fixed_point(conns[0].data.pressure_drop) if conns[0].data.pressure_drop is not None else 0} {units['Pressure']}<br>"
716
                                f"{convert_to_fixed_point(conns[0].data.elevation)} {units['Length']}")
717
                        else:
718
                            self.desc_labels[conns[0]].setHtml(conns[0].data.desc)
719

    
720
                        self.desc_labels[conns[0]].setEnabled(True)
721
            elif self.type == 'Heat Exchanger':
722
                if self.tag_no:
723
                    nozzles = []
724
                    for conn in self.connectors:
725
                        if conn.data and (conn.data.pressure_drop is not None or conn.data.elevation is not None):
726
                            nozzle = str(conn).rsplit('_', 1)[1]
727
                            nozzles.append(nozzle)
728

    
729
                    if len(nozzles) > 0:
730
                        if self.name == 'HEX_DP':
731
                            if 'N1' in nozzles and 'N2' in nozzles:
732
                                if self.connectors[0].data.desc is None:
733
                                    self.desc_labels[self.connectors[0]].setHtml(
734
                                        f"{self.tag_no}<br>[S] : {convert_to_fixed_point(self.connectors[1].data.pressure_drop)} [T] : {convert_to_fixed_point(self.connectors[0].data.pressure_drop)} {units['Pressure']}<br>"
735
                                        f"[S] : {convert_to_fixed_point(self.connectors[1].data.elevation)} [T] : {convert_to_fixed_point(self.connectors[0].data.elevation)} {units['Length']}")
736
                                else:
737
                                    self.desc_labels[self.connectors[0]].setHtml(self.connectors[0].data.desc)
738

    
739
                                self.desc_labels[self.connectors[0]].setEnabled(True)
740
                            elif 'N1' in nozzles:
741
                                if self.connectors[0].data.desc is None:
742
                                    self.desc_labels[self.connectors[0]].setHtml(
743
                                        f"{self.tag_no}<br>[T] : {convert_to_fixed_point(self.connectors[0].data.pressure_drop)} {units['Pressure']}<br>"
744
                                        f"[T] : {convert_to_fixed_point(self.connectors[0].data.elevation)} {units['Length']}")
745
                                else:
746
                                    self.desc_labels[self.connectors[0]].setHtml(self.connectors[0].data.desc)
747

    
748
                                self.desc_labels[self.connectors[0]].setEnabled(True)
749
                            elif 'N2' in nozzles:
750
                                if self.connectors[1].data.desc is None:
751
                                    self.desc_labels[self.connectors[1]].setHtml(
752
                                        f"{self.tag_no}<br>[S] : {convert_to_fixed_point(self.connectors[1].data.pressure_drop)} {units['Pressure']}<br>"
753
                                        f"[S] : {convert_to_fixed_point(self.connectors[1].data.elevation)} {units['Length']}")
754
                                else:
755
                                    self.desc_labels[self.connectors[1]].setHtml(self.connectors[1].data.desc)
756

    
757
                                self.desc_labels[self.connectors[1]].setEnabled(True)
758
                        elif self.name == 'HEX_H':
759
                            if 'N1' in nozzles and 'N2' in nozzles:
760
                                if self.connectors[0].data.desc is None:
761
                                    self.desc_labels[self.connectors[0]].setHtml(
762
                                        f"{self.tag_no}<br>[S] : {convert_to_fixed_point(self.connectors[0].data.pressure_drop)} [T] : {convert_to_fixed_point(self.connectors[1].data.pressure_drop)} {units['Pressure']}<br>"
763
                                        f"[S] : {convert_to_fixed_point(self.connectors[0].data.elevation)} [T] : {convert_to_fixed_point(self.connectors[1].data.elevation)} {units['Length']}")
764
                                else:
765
                                    self.desc_labels[self.connectors[0]].setHtml(self.connectors[0].data.desc)
766

    
767
                                self.desc_labels[self.connectors[0]].setEnabled(True)
768
                            elif 'N1' in nozzles:
769
                                if self.connectors[0].data.desc is None:
770
                                    self.desc_labels[self.connectors[0]].setHtml(
771
                                        f"{self.tag_no}<br>[S] : {convert_to_fixed_point(self.connectors[0].data.pressure_drop)} {units['Pressure']}<br>"
772
                                        f"[S] : {convert_to_fixed_point(self.connectors[0].data.elevation)} {units['Length']}")
773
                                else:
774
                                    self.desc_labels[self.connectors[0]].setHtml(self.connectors[0].data.desc)
775

    
776
                                self.desc_labels[self.connectors[0]].setEnabled(True)
777
                            elif 'N2' in nozzles:
778
                                if self.connectors[1].data.desc is None:
779
                                    self.desc_labels[self.connectors[1]].setHtml(
780
                                        f"{self.tag_no}<br>[T] : {convert_to_fixed_point(self.connectors[1].data.pressure_drop)} {units['Pressure']}<br>"
781
                                        f"[T] : {convert_to_fixed_point(self.connectors[1].data.elevation)} {units['Length']}")
782
                                else:
783
                                    self.desc_labels[self.connectors[1]].setHtml(self.connectors[1].data.desc)
784

    
785
                                self.desc_labels[self.connectors[1]].setEnabled(True)
786
                        elif self.name == 'HEX_K':
787
                            if 'N1' in nozzles and 'N2' in nozzles:
788
                                if self.connectors[0].data.desc is None:
789
                                    self.desc_labels[self.connectors[0]].setHtml(
790
                                        f"{self.tag_no}<br>[S] : {convert_to_fixed_point(self.connectors[1].data.pressure_drop)} [T] : {convert_to_fixed_point(self.connectors[0].data.pressure_drop)} {units['Pressure']}<br>"
791
                                        f"[S] : {convert_to_fixed_point(self.connectors[1].data.elevation)} [T] : {convert_to_fixed_point(self.connectors[0].data.elevation)} {units['Length']}")
792
                                else:
793
                                    self.desc_labels[self.connectors[0]].setHtml(self.connectors[0].data.desc)
794

    
795
                                self.desc_labels[self.connectors[0]].setEnabled(True)
796
                            elif 'N1' in nozzles:
797
                                if self.connectors[0].data.desc is None:
798
                                    self.desc_labels[self.connectors[0]].setHtml(
799
                                        f"{self.tag_no}<br>[T] : {convert_to_fixed_point(self.connectors[0].data.pressure_drop)} {units['Pressure']}<br>"
800
                                        f"[T] : {convert_to_fixed_point(self.connectors[0].data.elevation)} {units['Length']}")
801
                                else:
802
                                    self.desc_labels[self.connectors[0]].setHtml(self.connectors[0].data.desc)
803

    
804
                                self.desc_labels[self.connectors[0]].setEnabled(True)
805
                            elif 'N2' in nozzles:
806
                                if self.connectors[1].data.desc is None:
807
                                    self.desc_labels[self.connectors[1]].setHtml(
808
                                        f"{self.tag_no}<br>[S] : {convert_to_fixed_point(self.connectors[1].data.pressure_drop)} {units['Pressure']}<br>"
809
                                        f"[S] : {convert_to_fixed_point(self.connectors[1].data.elevation)} {units['Length']}")
810
                                else:
811
                                    self.desc_labels[self.connectors[1]].setHtml(self.connectors[1].data.desc)
812

    
813
                                self.desc_labels[self.connectors[1]].setEnabled(True)
814
                        elif self.name == 'HEX_P':
815
                            if 'N1' in nozzles and 'N2' in nozzles:
816
                                if self.connectors[0].data.desc is None:
817
                                    self.desc_labels[self.connectors[0]].setHtml(
818
                                        f"{self.tag_no}<br>[A] : {convert_to_fixed_point(self.connectors[0].data.pressure_drop)} [B] : {convert_to_fixed_point(self.connectors[1].data.pressure_drop)} {units['Pressure']}<br>"
819
                                        f"[A] : {convert_to_fixed_point(self.connectors[0].data.elevation)} [B] : {convert_to_fixed_point(self.connectors[1].data.elevation)} {units['Length']}")
820
                                else:
821
                                    self.desc_labels[self.connectors[0]].setHtml(self.connectors[0].data.desc)
822

    
823
                                self.desc_labels[self.connectors[0]].setEnabled(True)
824
                            elif 'N1' in nozzles:
825
                                if self.connectors[0].data.desc is None:
826
                                    self.desc_labels[self.connectors[0]].setHtml(
827
                                        f"{self.tag_no}<br>[A] : {convert_to_fixed_point(self.connectors[0].data.pressure_drop)} {units['Pressure']}<br>"
828
                                        f"[A] : {convert_to_fixed_point(self.connectors[0].data.elevation)} {units['Length']}")
829
                                else:
830
                                    self.desc_labels[self.connectors[0]].setHtml(self.connectors[0].data.desc)
831

    
832
                                self.desc_labels[self.connectors[0]].setEnabled(True)
833
                            elif 'N2' in nozzles:
834
                                if self.connectors[1].data.desc is None:
835
                                    self.desc_labels[self.connectors[1]].setHtml(
836
                                        f"{self.tag_no}<br>[B] : {convert_to_fixed_point(self.connectors[1].data.pressure_drop)} {units['Pressure']}<br>"
837
                                        f"[B] : {convert_to_fixed_point(self.connectors[1].data.elevation)} {units['Length']}")
838
                                else:
839
                                    self.desc_labels[self.connectors[1]].setHtml(self.connectors[1].data.desc)
840

    
841
                                self.desc_labels[self.connectors[1]].setEnabled(True)
842
                        elif self.name == 'HEX_V':
843
                            if 'N1' in nozzles and 'N2' in nozzles:
844
                                if self.connectors[0].data.desc is None:
845
                                    self.desc_labels[self.connectors[0]].setHtml(
846
                                        f"{self.tag_no}<br>[S] : {convert_to_fixed_point(self.connectors[1].data.pressure_drop)} [T] : {convert_to_fixed_point(self.connectors[0].data.pressure_drop)} {units['Pressure']}<br>"
847
                                        f"[S] : {convert_to_fixed_point(self.connectors[1].data.elevation)} [T] : {convert_to_fixed_point(self.connectors[0].data.elevation)} {units['Length']}")
848
                                else:
849
                                    self.desc_labels[self.connectors[0]].setHtml(self.connectors[0].data.desc)
850

    
851
                                self.desc_labels[self.connectors[0]].setEnabled(True)
852
                            elif 'N1' in nozzles:
853
                                if self.connectors[0].data.desc is None:
854
                                    self.desc_labels[self.connectors[0]].setHtml(
855
                                        f"{self.tag_no}<br>[T] : {convert_to_fixed_point(self.connectors[0].data.pressure_drop)} {units['Pressure']}<br>"
856
                                        f"[T] : {convert_to_fixed_point(self.connectors[0].data.elevation)} {units['Length']}")
857
                                else:
858
                                    self.desc_labels[self.connectors[0]].setHtml(self.connectors[0].data.desc)
859

    
860
                                self.desc_labels[self.connectors[0]].setEnabled(True)
861
                            elif 'N2' in nozzles:
862
                                if self.connectors[1].data.desc is None:
863
                                    self.desc_labels[self.connectors[1]].setHtml(
864
                                        f"{self.tag_no}<br>[S] : {convert_to_fixed_point(self.connectors[1].data.pressure_drop)} {units['Pressure']}<br>"
865
                                        f"[S] : {convert_to_fixed_point(self.connectors[1].data.elevation)} {units['Length']}")
866
                                else:
867
                                    self.desc_labels[self.connectors[1]].setHtml(self.connectors[1].data.desc)
868

    
869
                                self.desc_labels[self.connectors[1]].setEnabled(True)
870
            elif self.type == 'Miscellaneous':
871
                if self.name == 'M_Coil':
872
                    if self.tag_no:
873
                        conns = [conn for conn in self.connectors if conn.data and conn.data.elevation is not None]
874
                        if conns:
875
                            if conns[0].data.desc is None:
876
                                self.desc_labels[conns[0]].setHtml(
877
                                    f"{self.tag_no}<br>{convert_to_fixed_point(conns[0].data.pressure_drop) if conns[0].data.pressure_drop is not None else 0} {units['Pressure']}<br>"
878
                                    f"{convert_to_fixed_point(conns[0].data.elevation)} {units['Length']}")
879
                            else:
880
                                self.desc_labels[conns[0]].setHtml(conns[0].data.desc)
881

    
882
                            self.desc_labels[conns[0]].setEnabled(True)
883
                elif self.name == 'M_DP_E':
884
                    if self.tag_no:
885
                        nozzles = []
886
                        for conn in self.connectors:
887
                            if conn.data and (conn.data.pressure_drop is not None or conn.data.elevation is not None):
888
                                nozzle = str(conn).rsplit('_', 1)[1]
889
                                nozzles.append(nozzle)
890

    
891
                        if len(nozzles) > 0:
892
                            if 'N1' in nozzles and 'N2' in nozzles:
893
                                if self.connectors[0].data.desc is None:
894
                                    self.desc_labels[self.connectors[0]].setHtml(
895
                                        f"{self.tag_no}<br>[H] : {convert_to_fixed_point(self.connectors[1].data.pressure_drop)} [V] : {convert_to_fixed_point(self.connectors[0].data.pressure_drop)} {units['Pressure']}<br>"
896
                                        f"[H] : {convert_to_fixed_point(self.connectors[1].data.elevation)} [V] : {convert_to_fixed_point(self.connectors[0].data.elevation)} {units['Length']}")
897
                                else:
898
                                    self.desc_labels[self.connectors[0]].setHtml(self.connectors[0].data.desc)
899

    
900
                                self.desc_labels[self.connectors[0]].setEnabled(True)
901
                            elif 'N1' in nozzles:
902
                                if self.connectors[0].data.desc is None:
903
                                    self.desc_labels[self.connectors[0]].setHtml(
904
                                        f"{self.tag_no}<br>[V] : {convert_to_fixed_point(self.connectors[0].data.pressure_drop)} {units['Pressure']}<br>"
905
                                        f"[V] : {convert_to_fixed_point(self.connectors[0].data.elevation)} {units['Length']}")
906
                                else:
907
                                    self.desc_labels[self.connectors[0]].setHtml(self.connectors[0].data.desc)
908

    
909
                                self.desc_labels[self.connectors[0]].setEnabled(True)
910
                            elif 'N2' in nozzles:
911
                                if self.connectors[1].data.desc is None:
912
                                    self.desc_labels[self.connectors[1]].setHtml(
913
                                        f"{self.tag_no}<br>[H] : {convert_to_fixed_point(self.connectors[1].data.pressure_drop)} {units['Pressure']}<br>"
914
                                        f"[H] : {convert_to_fixed_point(self.connectors[1].data.elevation)} {units['Length']}")
915
                                else:
916
                                    self.desc_labels[self.connectors[1]].setHtml(self.connectors[1].data.desc)
917

    
918
                                self.desc_labels[self.connectors[1]].setEnabled(True)
919
                elif self.name == 'M_React':
920
                    if self.tag_no:
921
                        nozzles = []
922
                        for conn in self.connectors:
923
                            if conn.data and (conn.data.pressure_drop is not None or conn.data.elevation is not None):
924
                                nozzle = str(conn).rsplit('_', 1)[1]
925
                                nozzles.append(nozzle)
926

    
927
                        if len(nozzles) > 0:
928
                            if ('N1' in nozzles or 'N2' in nozzles or 'N6' in nozzles) and (
929
                                    'N3' in nozzles or 'N4' in nozzles or 'N5' in nozzles):
930
                                if 'N1' in nozzles:
931
                                    top_index = 0
932
                                elif 'N2' in nozzles:
933
                                    top_index = 1
934
                                elif 'N6' in nozzles:
935
                                    top_index = 5
936

    
937
                                if 'N3' in nozzles:
938
                                    btm_index = 2
939
                                elif 'N4' in nozzles:
940
                                    btm_index = 3
941
                                elif 'N5' in nozzles:
942
                                    btm_index = 4
943

    
944
                                if self.connectors[top_index].data.desc is None:
945
                                    self.desc_labels[self.connectors[top_index]].setHtml(
946
                                        f"[DP] : {convert_to_fixed_point(self.connectors[top_index].data.pressure_drop)} {units['Pressure']}<br>"
947
                                        f"[Top] : {convert_to_fixed_point(self.connectors[top_index].data.elevation)} {units['Length']}<br>"
948
                                        f"[Btm] : {convert_to_fixed_point(self.connectors[btm_index].data.elevation)} {units['Length']}")
949
                                else:
950
                                    self.desc_labels[self.connectors[top_index]].setHtml(self.connectors[top_index].data.desc)
951

    
952
                                self.desc_labels[self.connectors[top_index]].setEnabled(True)
953
                            elif 'N1' in nozzles or 'N2' in nozzles or 'N6' in nozzles:
954
                                if 'N1' in nozzles:
955
                                    index = 0
956
                                elif 'N2' in nozzles:
957
                                    index = 1
958
                                elif 'N6' in nozzles:
959
                                    index = 5
960

    
961
                                if self.connectors[index].data.desc is None:
962
                                    self.desc_labels[self.connectors[index]].setHtml(
963
                                        f"[DP] : {convert_to_fixed_point(self.connectors[index].data.pressure_drop)} {units['Pressure']}<br>"
964
                                        f"[Top] : {convert_to_fixed_point(self.connectors[index].data.elevation)} {units['Length']}")
965
                                else:
966
                                    self.desc_labels[self.connectors[index]].setHtml(self.connectors[index].data.desc)
967

    
968
                                self.desc_labels[self.connectors[index]].setEnabled(True)
969
                            elif 'N3' in nozzles or 'N4' in nozzles or 'N5' in nozzles:
970
                                if 'N3' in nozzles:
971
                                    index = 2
972
                                elif 'N4' in nozzles:
973
                                    index = 3
974
                                elif 'N5' in nozzles:
975
                                    index = 4
976

    
977
                                if self.connectors[index].data.desc is None:
978
                                    self.desc_labels[self.connectors[index]].setHtml(
979
                                        f"[DP] : {convert_to_fixed_point(self.connectors[index].data.pressure_drop)} {units['Pressure']}<br>"
980
                                        f"[Btm] : {convert_to_fixed_point(self.connectors[index].data.elevation)} {units['Length']}")
981
                                else:
982
                                    self.desc_labels[self.connectors[index]].setHtml(self.connectors[index].data.desc)
983

    
984
                                self.desc_labels[self.connectors[index]].setEnabled(True)
985
            elif self.type == 'Strainer':
986
                if self.tag_no:
987
                    conns = [conn for conn in self.connectors
988
                             if conn.data and conn.data.pressure_drop is not None and conn.data.elevation is not None]
989
                    if conns:
990
                        if conns[0].data.desc is None:
991
                            self.desc_labels[conns[0]].setHtml(
992
                                f"{self.tag_no}<br>{convert_to_fixed_point(conns[0].data.pressure_drop)} {units['Pressure']}<br>"
993
                                f"{convert_to_fixed_point(conns[0].data.elevation)} {units['Length']}")
994
                        else:
995
                            self.desc_labels[conns[0]].setHtml(conns[0].data.desc)
996

    
997
                        self.desc_labels[conns[0]].setEnabled(True)
998
        elif self.category == 'Equipment - [ Pressurized ]':
999
            if self.type == 'Battery Limit':
1000
                if self.tag_no:
1001
                    conns = [conn for conn in self.connectors
1002
                             if conn.data and conn.data.pressure is not None and conn.data.elevation is not None]
1003
                    if conns:
1004
                        if conns[0].data.desc is None:
1005
                            self.desc_labels[conns[0]].setHtml(
1006
                                f"{self.tag_no}<br>{convert_to_fixed_point(conns[0].data.pressure)} {units['Pressure']}(g)<br>"
1007
                                f"{convert_to_fixed_point(conns[0].data.elevation)} {units['Length']}")
1008
                        else:
1009
                            self.desc_labels[conns[0]].setHtml(conns[0].data.desc)
1010

    
1011
                        self.desc_labels[conns[0]].setEnabled(True)
1012
            elif self.type == 'Column':
1013
                if self.tag_no:
1014
                    for conn in self.connectors:
1015
                        if conn.data and (conn.data.pressure_drop is not None or conn.data.elevation is not None):
1016
                            nozzle = str(conn).rsplit('_', 1)[1]
1017
                            if conn.data.desc is None:
1018
                                self.desc_labels[conn].setHtml(
1019
                                    f"{self.tag_no}_{nozzle}<br>{convert_to_fixed_point(conn.data.pressure)} "
1020
                                    f"{units['Pressure']}(g)<br>{convert_to_fixed_point(conn.data.elevation)} {units['Length']}")
1021
                            else:
1022
                                self.desc_labels[conn].setHtml(conn.data.desc)
1023

    
1024
                            self.desc_labels[conn].setEnabled(True)
1025
            elif self.type == 'Drum':
1026
                if self.tag_no:
1027
                    for conn in self.connectors:
1028
                        if conn.data and (conn.data.pressure_drop is not None or conn.data.elevation is not None):
1029
                            nozzle = str(conn).rsplit('_', 1)[1]
1030
                            if conn.data.desc is None:
1031
                                self.desc_labels[conn].setHtml(
1032
                                    f"{self.tag_no}_{nozzle}<br>{convert_to_fixed_point(conn.data.pressure)} "
1033
                                    f"{units['Pressure']}(g)<br>{convert_to_fixed_point(conn.data.elevation)} {units['Length']}")
1034
                            else:
1035
                                self.desc_labels[conn].setHtml(conn.data.desc)
1036

    
1037
                            self.desc_labels[conn].setEnabled(True)
1038
            elif self.type == 'Miscellaneous':
1039
                if self.tag_no:
1040
                    for conn in self.connectors:
1041
                        if conn.data and (conn.data.pressure_drop is not None or conn.data.elevation is not None):
1042
                            nozzle = str(conn).rsplit('_', 1)[1]
1043
                            if conn.data:
1044
                                if conn.data.desc is None:
1045
                                    self.desc_labels[conn].setHtml(
1046
                                        f"{self.tag_no}_{nozzle}<br>{convert_to_fixed_point(conn.data.pressure)} "
1047
                                        f"{units['Pressure']}(g)<br>{convert_to_fixed_point(conn.data.elevation)} {units['Length']}")
1048
                                else:
1049
                                    self.desc_labels[conn].setHtml(conn.data.desc)
1050

    
1051
                                self.desc_labels[conn].setEnabled(True)
1052
            elif self.type == 'Tank':
1053
                if self.tag_no:
1054
                    for conn in self.connectors:
1055
                        if conn.data and conn.connectedItem and \
1056
                                (conn.data.pressure_drop is not None or conn.data.elevation is not None):
1057
                            nozzle = str(conn).rsplit('_', 1)[1]
1058
                            if conn.data.desc is None:
1059
                                self.desc_labels[conn].setHtml(
1060
                                    f"{self.tag_no}_{nozzle}<br>{convert_to_fixed_point(conn.data.pressure)} "
1061
                                    f"{units['Pressure']}(g)<br>{convert_to_fixed_point(conn.data.elevation)} {units['Length']}")
1062
                            else:
1063
                                self.desc_labels[conn].setHtml(conn.data.desc)
1064

    
1065
                            self.desc_labels[conn].setEnabled(True)
1066
        elif self.category == 'Equipment - [ Rotating ]':
1067
            if self.type == 'Compressor':
1068
                if self.name in ('L_Comp', 'R_Comp'):
1069
                    if self.tag_no:
1070
                        for conn in self.connectors:
1071
                            if conn.data and (conn.data.pressure_drop is not None or conn.data.elevation is not None):
1072
                                nozzle = str(conn).rsplit('_', 1)[1]
1073
                                if conn.data.desc is None:
1074
                                    self.desc_labels[conn].setHtml(
1075
                                        f"{self.tag_no}_{nozzle}<br>{convert_to_fixed_point(conn.data.pressure)} "
1076
                                        f"{units['Pressure']}(g)<br>{convert_to_fixed_point(conn.data.elevation)} {units['Length']}")
1077
                                else:
1078
                                    self.desc_labels[conn].setHtml(conn.data.desc)
1079

    
1080
                                self.desc_labels[conn].setEnabled(True)
1081
                elif self.name in ('L_Komp', 'R_Komp'):
1082
                    if self.tag_no:
1083
                        conns = [conn for conn in self.connectors if conn.data and conn.data.elevation is not None]
1084
                        if conns:
1085
                            if conns[0].data.desc is None:
1086
                                self.desc_labels[conns[0]].setHtml(
1087
                                    f"{self.tag_no}<br>"
1088
                                    f"{convert_to_fixed_point(conns[0].data.pressure_drop) if conns[0].data.pressure_drop is not None else 0} {units['Pressure']}<br>"
1089
                                    f"{convert_to_fixed_point(conns[0].data.elevation)} {units['Length']}")
1090
                            else:
1091
                                self.desc_labels[conns[0]].setHtml(conns[0].data.desc)
1092

    
1093
                            self.desc_labels[conns[0]].setEnabled(True)
1094
            elif self.type == 'Pump':
1095
                if self.tag_no:
1096
                    conns = [conn for conn in self.connectors if conn.data and conn.data.elevation is not None]
1097
                    if conns:
1098
                        if conns[0].data.desc is None:
1099
                            self.desc_labels[conns[0]].setHtml(
1100
                                f"{self.tag_no}<br>"
1101
                                f"{convert_to_fixed_point(conns[0].data.pressure_drop) if conns[0].data.pressure_drop is not None else 0} {units['Pressure']}<br>"
1102
                                f"{convert_to_fixed_point(conns[0].data.elevation)} {units['Length']}")
1103
                        else:
1104
                            self.desc_labels[conns[0]].setHtml(conns[0].data.desc)
1105

    
1106
                        self.desc_labels[conns[0]].setEnabled(True)
1107
        elif self.category == 'Instrument':
1108
            if self.type == 'Flowmeter':
1109
                if self.tag_no:
1110
                    data = self.connectors[0].data
1111
                    if data:
1112
                        if self.connectors[0].data.desc is None:
1113
                            self.desc_labels[self.connectors[0]].setHtml(
1114
                                f"{self.tag_no}<br>{convert_to_fixed_point(data.pressure_drop)} "
1115
                                f"{units['Pressure']}<br>{convert_to_fixed_point(data.elevation)} {units['Length']}")
1116
                        else:
1117
                            self.desc_labels[self.connectors[0]].setHtml(self.connectors[0].data.desc)
1118

    
1119
                        self.desc_labels[self.connectors[0]].setEnabled(True)
1120
            elif self.type == 'Line Splitter':
1121
                if self.tag_no:
1122
                    conns = [conn for conn in self.connectors
1123
                             if conn.data and conn.data.pressure_drop is not None and conn.data.elevation is not None]
1124
                    if conns:
1125
                        if conns[0].data.desc is None:
1126
                            self.desc_labels[conns[0]].setHtml(
1127
                                f"{self.tag_no}<br>{convert_to_fixed_point(conns[0].data.pressure_drop)} "
1128
                                f"{units['Pressure']}<br>{convert_to_fixed_point(conns[0].data.elevation)} {units['Length']}")
1129
                        else:
1130
                            self.desc_labels[conns[0]].setHtml(conns[0].data.desc)
1131

    
1132
                        self.desc_labels[conns[0]].setEnabled(True)
1133
            elif self.type == 'Reducer':
1134
                if self.tag_no:
1135
                    conns = [conn for conn in self.connectors
1136
                             if conn.data and conn.data.pressure_drop is not None and conn.data.elevation is not None]
1137
                    if conns:
1138
                        if conns[0].data.desc is None:
1139
                            self.desc_labels[conns[0]].setHtml(
1140
                                f"{self.tag_no}<br>{convert_to_fixed_point(conns[0].data.pressure_drop)} "
1141
                                f"{units['Pressure']}<br>{convert_to_fixed_point(conns[0].data.elevation)} {units['Length']}")
1142
                        else:
1143
                            self.desc_labels[conns[0]].setHtml(conns[0].data.desc)
1144

    
1145
                        self.desc_labels[conns[0]].setEnabled(True)
1146
            elif self.type == 'Valve':
1147
                if self.tag_no and self.name in ('CV_H', 'CV_V'):
1148
                    conns = [conn for conn in self.connectors if conn.data and conn.data.elevation is not None]
1149
                    if conns:
1150
                        if conns[0].data.desc is None:
1151
                            self.desc_labels[conns[0]].setHtml(
1152
                                f"{self.tag_no}<br>{convert_to_fixed_point(conns[0].data.pressure_drop) if conns[0].data.pressure_drop is not None else 0} {units['Pressure']}<br>"
1153
                                f"{convert_to_fixed_point(conns[0].data.elevation)} {units['Length']}")
1154
                        else:
1155
                            self.desc_labels[conns[0]].setHtml(conns[0].data.desc)
1156

    
1157
                        self.desc_labels[conns[0]].setEnabled(True)
1158
                elif self.tag_no and self.name in ('MV_H', 'MV_V'):
1159
                    conns = [conn for conn in self.connectors
1160
                             if conn.data and conn.data.pressure_drop is not None and conn.data.elevation is not None]
1161
                    if conns:
1162
                        if conns[0].data.desc is None:
1163
                            self.desc_labels[conns[0]].setHtml(
1164
                                f"{self.tag_no}<br>{convert_to_fixed_point(conns[0].data.pressure_drop)} "
1165
                                f"{units['Pressure']}<br>{convert_to_fixed_point(conns[0].data.elevation)} {units['Length']}")
1166
                        else:
1167
                            self.desc_labels[conns[0]].setHtml(conns[0].data.desc)
1168

    
1169
                        self.desc_labels[conns[0]].setEnabled(True)
1170

    
1171
        configs = app_doc_data.getAppConfigs('option', 'TagFontSize')
1172
        font_size = configs[0].value if configs and len(configs) == 1 else '6'
1173

    
1174
        configs = app_doc_data.getAppConfigs('option', 'TagFontColor')
1175
        font_color = configs[0].value if configs and len(configs) == 1 else '#000000'
1176

    
1177
        for conn, label in self.desc_labels.items():
1178
            label.set_font_size(font_size)
1179
            label.set_font_color(font_color)
1180
            label.setHtml(label.toPlainText().replace('\n', '<br>'))
1181

    
1182
    def rect(self):
1183
        """return bounding box of symbol"""
1184
        return self.sceneBoundingRect()
1185

    
1186
    '''
1187
        @brief  return true if line is able to connect symbol
1188
        @author humkyung
1189
        @date   2018.04.13
1190
    '''
1191

    
1192
    def is_connectable(self, item, toler=10):
1193
        # from EngineeringLineItem import QEngineeringLineItem
1194

    
1195
        '''
1196
        if False:#type(item) is QEngineeringLineItem:
1197
            line = item
1198
            start_pt = line.startPoint()
1199
            end_pt = line.endPoint()
1200
            for connector in self.connectors:
1201
                dx = connector.sceneConnectPoint[0] - (start_pt[0])
1202
                dy = connector.sceneConnectPoint[1] - (start_pt[1])
1203
                if (math.sqrt(dx*dx + dy*dy) < toler): return True
1204
                dx = connector.sceneConnectPoint[0] - (end_pt[0])
1205
                dy = connector.sceneConnectPoint[1] - (end_pt[1])
1206
                if (math.sqrt(dx*dx + dy*dy) < toler): return True
1207
        elif True:#issubclass(type(item), SymbolSvgItem):
1208
        '''
1209
        for connector in self.connectors:
1210
            for iConnector in item.connectors:
1211
                dx = connector.sceneConnectPoint[0] - iConnector.sceneConnectPoint[0]
1212
                dy = connector.sceneConnectPoint[1] - iConnector.sceneConnectPoint[1]
1213
                if (math.sqrt(dx * dx + dy * dy) < toler): return True
1214

    
1215
        return False
1216

    
1217
    '''
1218
        @author     humkyung
1219
        @date       2018.07.03
1220
    '''
1221

    
1222
    def is_connected(self, item, at=QEngineeringAbstractItem.CONNECTED_AT_PT):
1223
        """ check if given item is connected to self """
1224

    
1225
        _connectors = [connector for connector in self.connectors if
1226
                       (connector.connectedItem == item and (connector._connected_at == at if at else True))]
1227
        return len(_connectors) > 0
1228

    
1229
    def getConnectionPointCloseTo(self, pt, toler=10):
1230
        """get connection point close to given point in tolerance"""
1231
        import math
1232

    
1233
        for connector in self.connectors:
1234
            center = connector.center()
1235

    
1236
            dx = center[0] - pt[0]
1237
            dy = center[1] - pt[1]
1238

    
1239
            if math.sqrt(dx * dx + dy * dy) < toler:
1240
                return center
1241

    
1242
        return None
1243

    
1244
    '''
1245
        @brief  return center of symbol
1246
        @author humkyung
1247
        @date   2018.04.08
1248
    '''
1249

    
1250
    def center(self):
1251
        return self.sceneBoundingRect().center()
1252

    
1253
    def hoverEnterEvent(self, event):
1254
        self.highlight(True)
1255

    
1256
    '''
1257
        @brief      unhighlight connector and attribute
1258
        @author     humkyung
1259
        @date       2018.05.02
1260
        @history    kyouho 2018.07.18 edit ArrowCursor
1261
    '''
1262

    
1263
    def hoverLeaveEvent(self, event):
1264
        self.highlight(False)
1265

    
1266
    def highlight(self, flag):
1267
        """ highlight/unhighlight the symbol """
1268

    
1269
        try:
1270
            self.hover = flag
1271
            self.setZValue(QEngineeringAbstractItem.HOVER_ZVALUE) if flag else self.setZValue(SymbolSvgItem.ZVALUE)
1272
            self.update()
1273
        except Exception as ex:
1274
            from App import App
1275
            message = 'error occurred({}) in {}:{}'.format(ex, sys.exc_info()[-1].tb_frame.f_code.co_filename,
1276
                                                           sys.exc_info()[-1].tb_lineno)
1277
            App.mainWnd().addMessage.emit(MessageType.Error, message)
1278

    
1279
    '''
1280
        @brief      set highlight
1281
        @author     kyouho
1282
        @date       2018.08.27
1283
    '''
1284

    
1285
    def setHightlight(self):
1286
        self.setColor('url(#hover)')
1287
        self.update()
1288

    
1289
    '''
1290
        @brief      unset highlight
1291
        @author     kyouho
1292
        @date       2018.08.27
1293
    '''
1294

    
1295
    def unsetHightlight(self):
1296
        self.setColor('url(#normal)')
1297
        self.update()
1298

    
1299
    '''
1300
        @brief  change cursor to CrossCursor if mouse point is close to connection point
1301
        @author humkyung
1302
        @date   2018.04.28
1303
    '''
1304

    
1305
    def hoverMoveEvent(self, event):
1306
        pass
1307

    
1308
    def mousePressEvent(self, event):
1309
        import math
1310

    
1311
        if event.buttons() == Qt.LeftButton:
1312
            toler = 10
1313

    
1314
            # try to select corner
1315
            self._selected_idx = None
1316
            pos = event.scenePos()
1317
            for idx, corner in enumerate(self.corners):
1318
                dx = corner.x() - pos.x()
1319
                dy = corner.y() - pos.y()
1320
                if math.sqrt(dx * dx + dy * dy) < toler:
1321
                    self._selected_idx = idx
1322
                    break
1323
            # up to here
1324

    
1325
            if self._selected_idx is None:
1326
                self.clicked.emit(self)
1327

    
1328
        #super(SymbolSvgItem, self).mousePressEvent(event)
1329

    
1330
    def mouseMoveEvent(self, event):
1331
        """reshape dimension"""
1332

    
1333
        if event.buttons() == Qt.LeftButton and self._selected_idx is not None:
1334
            corners = [event.scenePos(), self.corners[(self._selected_idx + 2) % 4]]
1335
            min_x, min_y = min(corners, key=lambda pt: pt.x()).x(), min(corners, key=lambda pt: pt.y()).y()
1336
            max_x, max_y = max(corners, key=lambda pt: pt.x()).x(), max(corners, key=lambda pt: pt.y()).y()
1337

    
1338
            self.resize(QRectF(min_x, min_y, max_x - min_x, max_y - min_y))
1339
            return
1340

    
1341
        super(SymbolSvgItem, self).mouseMoveEvent(event)
1342

    
1343
    def mouseReleaseEvent(self, event):
1344
        self._selected_idx = None
1345
        super(SymbolSvgItem, self).mouseReleaseEvent(event)
1346

    
1347
    def itemChange(self, change, value):
1348
        """ call signals when item's position is changed """
1349
        if change == QGraphicsItem.ItemPositionHasChanged:
1350
            self.transfer.on_pos_changed.emit(self)
1351
            """
1352
            for conn in self.connectors:
1353
                if conn.conectedItem:
1354
                    line = conn.connectedItem.parentItem()
1355
                    start = line.connectors[-1].connectedItem.center()
1356
                    end = line.connectors[-2].connectedItem.center()
1357
                    dx, dy = end[-1] - start[0], end[1] - start[1]
1358
            """
1359

    
1360
            self.scene().contents_changed.emit()
1361
            return value
1362

    
1363
        return super().itemChange(change, value)
1364

    
1365
    '''
1366
        @brief      Check Overlap
1367
        @author     kyouho
1368
        @date       18.07.17
1369
    '''
1370

    
1371
    def isOverlapItemAndPoint(self, item, point):
1372
        x = point.x()
1373
        y = point.y()
1374
        loc = item.loc
1375
        size = item.size
1376

    
1377
        if loc[0] <= x and loc[0] + size[0] >= x and loc[1] <= y and loc[1] + size[1] >= y:
1378
            return True
1379
        else:
1380
            return False
1381

    
1382
    '''
1383
        @brief  remove item when user press delete key
1384
        @author humkyung
1385
        @date   2018.04.23
1386
        @history    2018.05.17  Jeongwoo    Add if-statement and move 'break'
1387
                    2018.05.25  Jeongwoo    Seperate delete item method
1388
    '''
1389

    
1390
    def keyPressEvent(self, event):
1391
        if not self.isSelected(): return
1392

    
1393
        if event.key() == Qt.Key_Delete:
1394
            self.deleteSvgItemFromScene()
1395
        elif event.key() == Qt.Key_QuoteLeft:
1396
            self.mouseDoubleClickEvent(event)
1397

    
1398
    '''
1399
        @brief      connect attribute
1400
        @author     humkyung
1401
        @date       2018.05.02
1402
        @history    humkyung 2018.05.09 append only nearest size attribute
1403
    '''
1404

    
1405
    def connectAttribute(self, attributes, clear=True):
1406
        import math
1407

    
1408
        try:
1409
            if clear:
1410
                self.clear_attr_and_assoc_item()
1411

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

    
1415
            dist = max(self.sceneBoundingRect().height(), self.sceneBoundingRect().width()) * ratio
1416
            center = self.sceneBoundingRect().center()
1417

    
1418
            minDist = None
1419
            selected = None
1420
            for attr in attributes:
1421
                # size text and operation code text will find onwer themselves in findowner method
1422
                if False:  # type(attr) is QEngineeringSizeTextItem or type(attr) is QEngineeringValveOperCodeTextItem:
1423
                    dx = attr.center().x() - center.x()
1424
                    dy = attr.center().y() - center.y()
1425
                    length = math.sqrt(dx * dx + dy * dy)
1426
                    if (length < dist) and (minDist is None or length < minDist):
1427
                        minDist = length
1428
                        selected = attr
1429
                elif type(attr) is QEngineeringInstrumentItem:
1430
                    if not attr.is_connected:
1431
                        dx = attr.center().x() - center.x()
1432
                        dy = attr.center().y() - center.y()
1433
                        if math.sqrt(dx * dx + dy * dy) < dist:
1434
                            if self.add_assoc_item(attr):
1435
                                attr.owner = self
1436

    
1437
            if selected is not None:
1438
                if self.add_assoc_item(selected):
1439
                    selected.owner = self
1440

    
1441
        except Exception as ex:
1442
            from App import App
1443
            message = 'error occured({}) in {}:{}'.format(ex, sys.exc_info()[-1].tb_frame.f_code.co_filename,
1444
                                                          sys.exc_info()[-1].tb_lineno)
1445
            App.mainWnd().addMessage.emit(MessageType.Error, message)
1446

    
1447
    '''
1448
        @brief      Double click event, Show rotate symbol dialog
1449
        @author     euisung
1450
        @date       2019.04.16
1451
    '''
1452

    
1453
    def mouseDoubleClickEvent(self, event):
1454
        func_map = [
1455
            (('Equipment - [ Pressure Drop ]', 'Air Fin Cooler', 'AF_Cooler'), self.show_AirFinCooler),
1456
            (('Equipment - [ Pressure Drop ]', 'Filter', ('Filter_H', 'Filter_V')), self.show_Filter),
1457
            (('Equipment - [ Pressure Drop ]', 'Heat Exchanger', ('HEX_DP', 'HEX_H', 'HEX_K', 'HEX_V')),
1458
             self.show_ShlTubHeatExchanger),
1459
            (('Equipment - [ Pressure Drop ]', 'Heat Exchanger', ('HEX_P')), self.show_PlateHeatExchanger),
1460
            (('Equipment - [ Pressure Drop ]', 'Miscellaneous', ('M_Coil')), self.show_Coil),
1461
            (('Equipment - [ Pressure Drop ]', 'Miscellaneous', ('M_DP_E')), self.show_DP_Equipment),
1462
            (('Equipment - [ Pressure Drop ]', 'Miscellaneous', ('M_React')), self.show_Reactor),
1463
            (('Equipment - [ Pressure Drop ]', 'Strainer', ('T_Strainer_H', 'T_Strainer_V')), self.show_Strainer_T),
1464
            (('Equipment - [ Pressure Drop ]', 'Strainer', ('Y_Strainer_H', 'Y_Strainer_V')), self.show_Strainer_Y),
1465
            (('Equipment - [ Pressurized ]', 'Battery Limit', None), self.show_BatteryLimit),
1466
            (('Equipment - [ Pressurized ]', 'Column', ('CwT')), self.show_Tray),
1467
            (('Equipment - [ Pressurized ]', 'Column', ('CwP_Single')), self.show_SinglePacked),
1468
            (('Equipment - [ Pressurized ]', 'Column', ('CwP_Dual')), self.show_DualPacked),
1469
            (('Equipment - [ Pressurized ]', 'Drum', ('Drum_H')), self.show_Drum_Horizontal),
1470
            (('Equipment - [ Pressurized ]', 'Drum', ('Drum_V')), self.show_Drum_Vertical),
1471
            (('Equipment - [ Pressurized ]', 'Miscellaneous', ('ME')), self.show_Equipment),
1472
            (('Equipment - [ Pressurized ]', 'Tank', ('Ball_Tank')), self.show_Ball),
1473
            (('Equipment - [ Pressurized ]', 'Tank', ('CRT')), self.show_ConeRoof),
1474
            (('Equipment - [ Pressurized ]', 'Tank', ('DRT')), self.show_DomeRoof),
1475
            (('Equipment - [ Rotating ]', 'Compressor', ('L_Comp', 'R_Comp')), self.show_Compressor),
1476
            (('Equipment - [ Rotating ]', 'Compressor', ('L_Komp', 'R_Komp')), self.show_Kompressor),
1477
            (('Equipment - [ Rotating ]', 'Pump', ('L_Pump', 'R_Pump', 'V_Pump')), self.show_Pump),
1478
            (('Instrument', 'Valve', ('CV_H', 'CV_V')), self.show_ValveControl),
1479
            (('Instrument', 'Valve', ('MV_H', 'MV_V')), self.show_ValveManual),
1480
            (('Instrument', 'Line Splitter', ('Line_Splitter')), self.show_LineSplitter),
1481
            (('Instrument', 'Flowmeter', (
1482
                'Ori_Flowmeter_H', 'Oth_Flowmeter_H', 'Ven_Flowmeter_H', 'Ori_Flowmeter_V', 'Oth_Flowmeter_V',
1483
                'Ven_Flowmeter_V')), self.show_Flowmeter),
1484
            (('Instrument', 'Reducer', ('Re_Ex_Dw', 'Re_Ex_L', 'Re_Ex_R', 'Re_Ex_Up')), self.show_Reducer)
1485
        ]
1486

    
1487
        connectedItems = [connector for connector in self.connectors if connector.connectedItem is not None]
1488
        if len(connectedItems) < 1:
1489
            msg = QMessageBox()
1490
            msg.setIcon(QMessageBox.Information)
1491
            msg.setText(self.tr('Connect Line before Data input'))
1492
            msg.setWindowTitle(self.tr("Information"))
1493
            msg.setStandardButtons(QMessageBox.Ok)
1494
            msg.exec_()
1495
            return
1496

    
1497
        matches = [func for func in func_map if func[0][0] == self.category and func[0][1] == self.type and
1498
                   (func[0][2] is None or self.name in func[0][2])]
1499
        if matches: matches[0][1]()
1500

    
1501
    def reset_nozzle_desc(self) -> None:
1502
        """reset all of nozzle descriptions"""
1503

    
1504
        for conn, label in self.desc_labels.items():
1505
            conn.data.desc = None
1506

    
1507
    def change_output_font_color(self):
1508
        row_count = App.mainWnd().tableWidgetDeviation.rowCount()
1509
        col_count = App.mainWnd().tableWidgetDeviation.columnCount()
1510
        for row in range(row_count):
1511
            for col in range(col_count):
1512
                if row == 0:
1513
                    item = App.mainWnd().tableWidgetDeviation.item(row, col)
1514
                    item.setText('RUN CALCULATION')
1515
                    item.setForeground(Qt.red)
1516
                    App.mainWnd().tableWidgetDeviation.setItem(row, col, item)
1517
                else:
1518
                    App.mainWnd().tableWidgetDeviation.item(row, col).setForeground(QBrush(QColor(169, 169, 169)))
1519

    
1520
        row_count = App.mainWnd().tableWidgetOutput.rowCount()
1521
        col_count = App.mainWnd().tableWidgetOutput.columnCount()
1522
        for row in range(row_count):
1523
            for col in range(col_count):
1524
                App.mainWnd().tableWidgetOutput.item(row, col).setForeground(QBrush(QColor(169, 169, 169)))
1525
                col_span = App.mainWnd().tableWidgetOutput.columnSpan(row, col)
1526
                if col_span > 1:
1527
                    break
1528

    
1529
    def show_AirFinCooler(self):
1530
        from AirFinCooler import QAirFinCooler
1531

    
1532
        dialog = QAirFinCooler()
1533
        modified = dialog.show_dialog(self)
1534
        if modified:
1535
            self.reset_nozzle_desc()
1536
            self.update_label_contents()
1537
            self.validate()
1538
            self.change_output_font_color()
1539

    
1540
    def show_Filter(self):
1541
        from Filter import QFilter
1542

    
1543
        dialog = QFilter()
1544
        modified = dialog.show_dialog(self)
1545
        if modified:
1546
            self.reset_nozzle_desc()
1547
            self.update_label_contents()
1548
            self.validate()
1549
            self.change_output_font_color()
1550

    
1551
    def show_Coil(self):
1552
        from Coil import QCoil
1553

    
1554
        dialog = QCoil()
1555
        modified = dialog.show_dialog(self)
1556
        if modified:
1557
            self.reset_nozzle_desc()
1558
            self.update_label_contents()
1559
            self.validate()
1560
            self.change_output_font_color()
1561

    
1562
    def show_DP_Equipment(self):
1563
        from DP_Equipment import QDP_Equipment
1564

    
1565
        dialog = QDP_Equipment()
1566
        modified = dialog.show_dialog(self)
1567
        if modified:
1568
            self.reset_nozzle_desc()
1569
            self.update_label_contents()
1570
            self.validate()
1571
            self.change_output_font_color()
1572

    
1573
    def show_Reactor(self):
1574
        from Reactor import QReactor
1575

    
1576
        dialog = QReactor()
1577
        modified = dialog.show_dialog(self)
1578
        if modified:
1579
            self.reset_nozzle_desc()
1580
            self.update_label_contents()
1581
            self.validate()
1582
            self.change_output_font_color()
1583

    
1584
    def show_Strainer_T(self):
1585
        from Strainer_T import QStrainer_T
1586

    
1587
        dialog = QStrainer_T()
1588
        modified = dialog.show_dialog(self)
1589
        if modified:
1590
            self.reset_nozzle_desc()
1591
            self.update_label_contents()
1592
            self.validate()
1593
            self.change_output_font_color()
1594

    
1595
    def show_Strainer_Y(self):
1596
        from Strainer_Y import QStrainer_Y
1597

    
1598
        dialog = QStrainer_Y()
1599
        modified = dialog.show_dialog(self)
1600
        if modified:
1601
            self.reset_nozzle_desc()
1602
            self.update_label_contents()
1603
            self.validate()
1604
            self.change_output_font_color()
1605

    
1606
    def show_BatteryLimit(self):
1607
        from BatteryLimit import QBatteryLimit
1608

    
1609
        dialog = QBatteryLimit()
1610
        modified = dialog.show_dialog(self)
1611
        if modified:
1612
            self.reset_nozzle_desc()
1613
            self.update_label_contents()
1614
            self.validate()
1615
            self.change_output_font_color()
1616

    
1617
    def show_Tray(self):
1618
        from Tray import QTray
1619

    
1620
        dialog = QTray()
1621
        modified = dialog.show_dialog(self)
1622
        if modified:
1623
            self.reset_nozzle_desc()
1624
            self.update_label_contents()
1625
            self.validate()
1626
            self.change_output_font_color()
1627

    
1628
    def show_SinglePacked(self):
1629
        from SinglePacked import QSinglePacked
1630

    
1631
        dialog = QSinglePacked()
1632
        modified = dialog.show_dialog(self)
1633
        if modified:
1634
            self.reset_nozzle_desc()
1635
            self.update_label_contents()
1636
            self.validate()
1637
            self.change_output_font_color()
1638

    
1639
    def show_DualPacked(self):
1640
        from DualPacked import QDualPacked
1641

    
1642
        dialog = QDualPacked()
1643
        modified = dialog.show_dialog(self)
1644
        if modified:
1645
            self.reset_nozzle_desc()
1646
            self.update_label_contents()
1647
            self.validate()
1648
            self.change_output_font_color()
1649

    
1650
    def show_Drum_Horizontal(self):
1651
        from Drum_Horizontal import QDrum_Horizontal
1652

    
1653
        dialog = QDrum_Horizontal()
1654
        modified = dialog.show_dialog(self)
1655
        if modified:
1656
            self.reset_nozzle_desc()
1657
            self.update_label_contents()
1658
            self.validate()
1659
            self.change_output_font_color()
1660

    
1661
    def show_Drum_Vertical(self):
1662
        from Drum_Vertical import QDrum_Vertical
1663

    
1664
        dialog = QDrum_Vertical()
1665
        modified = dialog.show_dialog(self)
1666
        if modified:
1667
            self.reset_nozzle_desc()
1668
            self.update_label_contents()
1669
            self.validate()
1670
            self.change_output_font_color()
1671

    
1672
    def show_PlateHeatExchanger(self):
1673
        from PlateHeatExchanger import QPlateHeatExchanger
1674

    
1675
        dialog = QPlateHeatExchanger()
1676
        modified = dialog.show_dialog(self)
1677
        if modified:
1678
            self.reset_nozzle_desc()
1679
            self.update_label_contents()
1680
            self.validate()
1681
            self.change_output_font_color()
1682

    
1683
    def show_Equipment(self):
1684
        from Equipment import QEquipment
1685

    
1686
        dialog = QEquipment()
1687
        modified = dialog.show_dialog(self)
1688
        if modified:
1689
            self.reset_nozzle_desc()
1690
            self.update_label_contents()
1691
            self.validate()
1692
            self.change_output_font_color()
1693

    
1694
    def show_Ball(self):
1695
        from Ball import QBall
1696

    
1697
        dialog = QBall()
1698
        modified = dialog.show_dialog(self)
1699
        if modified:
1700
            self.reset_nozzle_desc()
1701
            self.update_label_contents()
1702
            self.validate()
1703
            self.change_output_font_color()
1704

    
1705
    def show_ShlTubHeatExchanger(self):
1706
        from ShlTubHeatExchanger import QShlTubHeatExchanger
1707

    
1708
        dialog = QShlTubHeatExchanger()
1709
        modified = dialog.show_dialog(self)
1710
        if modified:
1711
            self.reset_nozzle_desc()
1712
            self.update_label_contents()
1713
            self.validate()
1714
            self.change_output_font_color()
1715

    
1716
    def show_ConeRoof(self):
1717
        from ConeRoof import QConeRoof
1718

    
1719
        dialog = QConeRoof()
1720
        modified = dialog.show_dialog(self)
1721
        if modified:
1722
            self.reset_nozzle_desc()
1723
            self.update_label_contents()
1724
            self.validate()
1725
            self.change_output_font_color()
1726

    
1727
    def show_DomeRoof(self):
1728
        from DomeRoof import QDomeRoof
1729

    
1730
        dialog = QDomeRoof()
1731
        modified = dialog.show_dialog(self)
1732
        if modified:
1733
            self.reset_nozzle_desc()
1734
            self.update_label_contents()
1735
            self.validate()
1736
            self.change_output_font_color()
1737

    
1738
    def show_Compressor(self):
1739
        from Compressor import QCompressor
1740

    
1741
        dialog = QCompressor()
1742
        modified = dialog.show_dialog(self)
1743
        if modified:
1744
            self.reset_nozzle_desc()
1745
            self.update_label_contents()
1746
            self.validate()
1747
            self.change_output_font_color()
1748

    
1749
    def show_Kompressor(self):
1750
        from Kompressor import QKompressor
1751

    
1752
        dialog = QKompressor()
1753
        modified = dialog.show_dialog(self)
1754
        if modified:
1755
            self.reset_nozzle_desc()
1756
            self.update_label_contents()
1757
            self.validate()
1758
            self.change_output_font_color()
1759

    
1760
    def show_Pump(self):
1761
        from Pump import QPump
1762

    
1763
        dialog = QPump()
1764
        modified = dialog.show_dialog(self)
1765
        if modified:
1766
            self.reset_nozzle_desc()
1767
            self.update_label_contents()
1768
            self.validate()
1769
            self.change_output_font_color()
1770

    
1771
    def show_ValveControl(self):
1772
        from Valve_Control import QValve_Control
1773

    
1774
        dialog = QValve_Control()
1775
        modified = dialog.show_dialog(self)
1776
        if modified:
1777
            self.reset_nozzle_desc()
1778
            self.update_label_contents()
1779
            self.validate()
1780
            self.change_output_font_color()
1781

    
1782
    def show_ValveManual(self):
1783
        from Valve_Manual import QValve_Manual
1784

    
1785
        dialog = QValve_Manual()
1786
        modified = dialog.show_dialog(self)
1787
        if modified:
1788
            self.reset_nozzle_desc()
1789
            self.update_label_contents()
1790
            self.validate()
1791
            self.change_output_font_color()
1792

    
1793
    def show_LineSplitter(self):
1794
        from LineSplitter import QLineSplitter
1795

    
1796
        dialog = QLineSplitter()
1797
        modified = dialog.show_dialog(self)
1798
        if modified:
1799
            self.reset_nozzle_desc()
1800
            self.update_label_contents()
1801
            self.validate()
1802
            self.change_output_font_color()
1803

    
1804
    def show_Flowmeter(self):
1805
        from Flowmeter import QFlowmeter
1806

    
1807
        dialog = QFlowmeter()
1808
        modified = dialog.show_dialog(self)
1809
        if modified:
1810
            self.reset_nozzle_desc()
1811
            self.update_label_contents()
1812
            self.validate()
1813
            self.change_output_font_color()
1814

    
1815
    def show_Reducer(self):
1816
        from Reducer import QReducer
1817

    
1818
        dialog = QReducer()
1819
        modified = dialog.show_dialog(self)
1820
        if modified:
1821
            self.reset_nozzle_desc()
1822
            self.update_label_contents()
1823
            self.validate()
1824
            self.change_output_font_color()
1825

    
1826
    @staticmethod
1827
    def fromDatabase(componentInfos):
1828
        """ create a componenet from database """
1829
        item = None
1830

    
1831
        try:
1832
            uid = componentInfos[0]['Comp_UID']  # uid@Components
1833
            tag_no = componentInfos[0]['Name']  # name@Components
1834
            index = componentInfos[0]['Comp_Index']
1835
            dbUid = componentInfos[0]['Symbols_UID']  # Symbol_UID@Components
1836
            category = componentInfos[0]['Category']  # Category@SymbolType
1837
            _type = componentInfos[0]['Type']  # Type@SymbolType
1838
            name = componentInfos[0]['Symbol_Name']  # Name@Symbols
1839
            originalPoint = componentInfos[0]['OriginalPoint']  # OriginalPoint@Symbols
1840
            x = componentInfos[0]['Comp_X']  # X@Components
1841
            y = componentInfos[0]['Comp_Y']  # Y@Components
1842
            angle = componentInfos[0]['Rotation']  # Rotation@Components
1843
            scale = componentInfos[0]['Scale']  # Scale@Components
1844

    
1845
            pt = []
1846
            pt.append(float(x))
1847
            pt.append(float(y))
1848

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

    
1851
            connPts = []
1852

    
1853
            pointsUids = []
1854
            for componentInfo in componentInfos:
1855
                pointsUid = componentInfo['Point_UID']  # uid@Points
1856
                pointsUids.append(pointsUid)
1857

    
1858
            item = SymbolSvgItem.createItem(_type, uid, None, 0, dbUid)
1859
            item.setVisible(False)
1860
            item.buildItem(name, _type, float(angle), float(scale), pt, origin, connPts, dbUid, pointsUids, index)
1861
            item.tag_no = tag_no
1862
            item.build_label()
1863

    
1864
        except Exception as ex:
1865
            from App import App
1866
            message = 'error occurred({}) in {}:{}'.format(ex, sys.exc_info()[-1].tb_frame.f_code.co_filename,
1867
                                                           sys.exc_info()[-1].tb_lineno)
1868
            App.mainWnd().addMessage.emit(MessageType.Error, message)
1869

    
1870
        return item
1871

    
1872
    '''
1873
        @brief      create item corresponding to given type
1874
        @author     humkyung
1875
        @date       2018.05.02
1876
        @history    2018.05.08  Jeongwoo    Change type name (Piping OPC''S → Piping OPC's)
1877
                    humkyung 2018.05.10 change symbol's color to blue
1878
                    humkyung 2018.07.19 create nozzle instance if type is 'Nozzles'
1879
    '''
1880

    
1881
    @staticmethod
1882
    def createItem(type, uid=None, owner=None, flip=0, symbol=None):
1883
        import uuid
1884

    
1885
        item = SymbolSvgItem(uid, flip=flip, symbol=symbol)
1886

    
1887
        if owner is not None:
1888
            item.owner = uuid.UUID(owner)
1889

    
1890
        return item
1891

    
1892
    '''
1893
        @brief      change svg's color
1894
        @author     humkyung
1895
        @date       2018.05.10
1896
        @history    2018.05.11  Jeongwoo    Override QEngineeringAbstractItem's
1897
                    humkyung 2018.05.13 update after change color
1898
    '''
1899

    
1900
    def setColor(self, color):
1901
        self.changeAttributes('fill', color)
1902
        self.changeAttributes('stroke', color)
1903
        self.renderer().load(self._document.toByteArray())
1904
        self.update()
1905

    
1906
    def getColor(self):
1907
        """ return hover color if mouse is over otherwise reutrn owner's color if owner exist else this color """
1908
        return SymbolSvgItem.HOVER_COLOR if self.hover else (
1909
            self.owner._color if self.owner and hasattr(self.owner, '_color') else self._color)
1910

    
1911
    '''
1912
        @brief  get attributes from svg file
1913
        @author humkyung
1914
        @date   2019.03.08
1915
    '''
1916

    
1917
    def get_attribute(self, attName):
1918
        root = self._document.documentElement()
1919
        node = root.firstChild()
1920
        while not node.isNull():
1921
            if node.isElement():
1922
                element = node.toElement()
1923
                if element.hasAttribute(attName):
1924
                    return element.attribute(attName)
1925

    
1926
                if element.hasChildNodes():
1927
                    att_val = self.recursive_get_attribute(element.firstChild(), attName)
1928
                    if att_val is not None: return att_val
1929

    
1930
            node = node.nextSibling()
1931

    
1932
        return None
1933

    
1934
    '''
1935
        @brief  get recursively attribute
1936
        @author humkyung
1937
        @date   2019.03.08
1938
    '''
1939

    
1940
    def recursive_get_attribute(self, node, attName):
1941
        while not node.isNull():
1942
            if node.isElement():
1943
                element = node.toElement()
1944
                if element.hasAttribute(attName):
1945
                    return element.attribute(attName)
1946

    
1947
                if node.hasChildNodes():
1948
                    att_val = self.recursive_get_attribute(node.firstChild(), attName)
1949
                    if att_val is not None: return att_val
1950

    
1951
            node = node.nextSibling()
1952

    
1953
        return None
1954

    
1955
    '''
1956
        @brief  change attributes
1957
        @author humkyung
1958
        @date   2018.05.10
1959
    '''
1960

    
1961
    def changeAttributes(self, attName, attValue):
1962
        root = self._document.documentElement()
1963
        node = root.firstChild()
1964
        while not node.isNull():
1965
            if node.isElement():
1966
                element = node.toElement()
1967
                if element.hasAttribute(attName):
1968
                    element.setAttribute(attName, attValue)
1969

    
1970
                if element.hasChildNodes():
1971
                    recursiveChangeAttributes(element.firstChild(), attName, attValue)
1972

    
1973
            node = node.nextSibling()
1974

    
1975
    '''
1976
        @brief  change attribute
1977
        @author humkyung
1978
        @date   2018.05.10
1979
    '''
1980

    
1981
    def recursiveChangeAttributes(self, node, attName, attValue):
1982
        while not node.isNull():
1983
            if node.isElement():
1984
                element = node.toElement()
1985
                if element.hasAttribute(attName):
1986
                    element.setAttribute(attName, attValue)
1987

    
1988
                if node.hasChildNodes():
1989
                    recursiveChangeAttributes(node.firstChild(), attName, attValue)
1990

    
1991
            node = node.nextSibling()
1992

    
1993
    '''
1994
        @brief  draw rect when item is selected
1995
        @author humkyung
1996
        @date   2018.07.07
1997
    '''
1998

    
1999
    def draw_focus_rect(self, painter):
2000
        self.focuspen = QPen(Qt.DotLine)
2001
        self.focuspen.setColor(Qt.black)
2002
        self.focuspen.setWidthF(1.5)
2003
        hilightColor = QColor(255, 0, 0, 127)
2004
        painter.setBrush(QBrush(hilightColor))
2005
        painter.setPen(self.focuspen)
2006
        painter.drawRect(self.boundingRect())
2007

    
2008
    def paint(self, painter, options=None, widget=None):
2009
        """override paint(draw connection points)"""
2010
        from EngineeringAbstractItem import QEngineeringAbstractItem
2011
        from EngineeringTextItem import QEngineeringTextItem
2012

    
2013
        self.setColor(self.getColor())
2014

    
2015
        painter.setClipRect(options.exposedRect)
2016
        QGraphicsSvgItem.paint(self, painter, options, widget)
2017
        """
2018
        for attr in self.attrs:
2019
            if issubclass(type(attr), QEngineeringTextItem):
2020
                color = QEngineeringAbstractItem.HOVER_COLOR if self.hover else (
2021
                    self._owner._color if self._owner else QEngineeringAbstractItem.DEFAULT_COLOR)
2022
                attr.setColor(color)
2023
            elif issubclass(type(attr), SymbolSvgItem):
2024
                attr.setColor(self.getColor())
2025
                attr.update()
2026
        """
2027

    
2028
        if self.isSelected():
2029
            self.draw_focus_rect(painter)
2030

    
2031
    def addSvgItemToScene(self, scene):
2032
        """add svg item to scene"""
2033
        transform = QTransform()
2034

    
2035
        transform.translate(self.loc[0] + self.symbolOrigin[0], self.loc[1] + self.symbolOrigin[1])
2036
        transform.rotateRadians(-self.angle)
2037
        transform.translate(-self.symbolOrigin[0], -self.symbolOrigin[1])
2038
        transform.scale(self._scale, self._scale)
2039

    
2040
        self.setTransform(transform)
2041
        scene.addItem(self)
2042

    
2043
    '''
2044
        @brief      
2045
        @author     humkyung
2046
        @date       2018.07.27
2047
    '''
2048

    
2049
    def onConnectorPosChaned(self, connector):
2050
        pass
2051

    
2052
    def set_connector(self, uid, index=None):
2053
        """set connector"""
2054
        from AppDocData import AppDocData
2055

    
2056
        app_doc_data = AppDocData.instance()
2057
        connector = QEngineeringConnectorItem(uid, parent=self, index=index)
2058
        connector.data = app_doc_data.get_nozzle_data(uid)
2059
        self.connectors.append(connector)
2060

    
2061
        # set label
2062
        label = QEngineeringEqpDescTextItem('', self)
2063
        self.desc_labels[connector] = label
2064

    
2065
    def deleteSvgItemFromScene(self):
2066
        """ remove self from scene """
2067
        try:
2068
            for conn in self.connectors:
2069
                if conn.connectedItem is not None:
2070
                    conn.connectedItem.connect(None)
2071
        except Exception as ex:
2072
            from App import App
2073
            from AppDocData import MessageType
2074

    
2075
            message = 'error occurred({}) in {}:{}'.format(ex, sys.exc_info()[-1].tb_frame.f_code.co_filename,
2076
                                                           sys.exc_info()[-1].tb_lineno)
2077
            App.mainWnd().addMessage.emit(MessageType.Error, message)
2078

    
2079
        self.transfer.onRemoved.emit(self)
2080

    
2081
    '''
2082
        @brief      get standard point
2083
        @author     kyouho
2084
        @date       2018.07.25
2085
    '''
2086

    
2087
    def getCurrentPoint(self):
2088

    
2089
        pointList = []
2090
        pointList.append(self.symbolOrigin)
2091
        for connector in self.connectors:
2092
            pointList.append(connector.connectPoint)
2093

    
2094
        # if type(self) is QEngineeringSpecBreakItem:
2095
        #    self.currentPointModeIndex = 1
2096

    
2097
        return pointList[self.currentPointModeIndex]
2098

    
2099
    '''
2100
        @brief      심볼 회전 시 서로 다른 기준점으로 회전하기 때문에 기준점을 이후 개발한 SymbolSvgItem 기준의 회전좌표로 이동하기 위해서 만듬 (loc 기준으로 회전해야함)
2101
        @author     kyouho
2102
        @date       18.08.06
2103
    '''
2104

    
2105
    def reCalculationRotatedItem(self):
2106

    
2107
        transform = QTransform()
2108
        transform.translate(self.loc[0] + self.symbolOrigin[0], self.loc[1] + self.symbolOrigin[1])
2109
        transform.rotateRadians(-self.angle)
2110
        currentPoint = self.getCurrentPoint()
2111
        transform.translate(-currentPoint[0], -currentPoint[1])
2112
        # 시작점을 구하기 위해서
2113
        goPoint = transform.map(QPoint(self.symbolOrigin[0], self.symbolOrigin[1]))
2114

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

    
2117
    def moveto(self, to, timeLine=5000, rotation=0):
2118
        """Move the item from one position to one other."""
2119

    
2120
        anim = QPropertyAnimation(self, b'pos')
2121
        rect = self.sceneBoundingRect()
2122
        anim.setStartValue(QPointF(0, 0))
2123
        anim.setEndValue(QPointF(100, 10))
2124
        anim.setDuration(10000)
2125
        anim.start()
2126

    
2127

    
2128
def recursiveChangeAttributes(node, attName, attValue):
2129
    while not node.isNull():
2130
        if node.isElement():
2131
            element = node.toElement()
2132
            if element.hasAttribute(attName):
2133
                element.setAttribute(attName, attValue)
2134

    
2135
            if node.hasChildNodes():
2136
                recursiveChangeAttributes(node.firstChild(), attName, attValue)
2137

    
2138
        node = node.nextSibling()
2139

    
2140

    
2141
'''
2142
    @brief      The class transfer pyqtSignal Event. Cause Subclass of QGraphicsRectItem can't use pyqtSignal
2143
    @author     Jeongwoo
2144
    @date       2018.06.18
2145
'''
2146

    
2147

    
2148
class Transfer(QObject):
2149
    on_pos_changed = pyqtSignal(QGraphicsItem)
2150
    on_size_changed = pyqtSignal(QGraphicsItem)
2151
    onRemoved = pyqtSignal(QGraphicsItem)
2152

    
2153
    def __init__(self, parent=None):
2154
        QObject.__init__(self, parent)
2155

    
2156

    
2157
if __name__ == '__main__':
2158
    f = QFile('d:/Projects/DTIPID/DTI_PID/DTI_PID/SG_TEST/svg/ANGLE VALVE.svg')
2159
    f.open(QIODevice.ReadOnly)
2160
    array = f.readAll()
2161
    document = QDomDocument()
2162
    document.setContent(array)
2163

    
2164
    root = document.documentElement()
2165
    node = root.firstChild()
2166
    while not node.isNull():
2167
        if node.isElement():
2168
            element = node.toElement()
2169
            if element.hasAttribute('fill'):
2170
                element.setAttribute('fill', '#FFFFF')
2171

    
2172
            if element.hasChildNodes():
2173
                recursiveChangeAttributes(element.firstChild(), 'fill', '#FFFFF')
2174

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