프로젝트

일반

사용자정보

통계
| 개정판:

hytos / HYTOS / HYTOS / Shapes / SymbolSvgItem.py @ 03940dd1

이력 | 보기 | 이력해설 | 다운로드 (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._scales = [1, 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
                scale = max(min([change.width() / rect.width(), change.height() / rect.height()]), 1)
191
                # scale the item
192
                self.setScale(scale)
193

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

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

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

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

    
212
        res = []
213

    
214
        try:
215
            rect = self.sceneBoundingRect()
216
            origin = self.mapToScene(self.transformOriginPoint())
217
            trans = self.transform()
218

    
219
            cols = ['UID', 'Symbols_UID', 'Name', '[Index]', 'X', 'Y', 'Rotation', 'ScaleX', 'ScaleY']
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, origin.x(), origin.y(),
223
                     self.rotation(), trans.m11(), trans.m22()]
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 = f'error occurred({repr(ex)}) in {sys.exc_info()[-1].tb_frame.f_code.co_filename}:' \
243
                      f'{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, scales: list, 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._scales = scales
269
            self.loc = loc
270

    
271
            app_doc_data = AppDocData.instance()
272
            if dbUid is None:
273
                symbolInfo = app_doc_data.getSymbolByQuery('name', name)
274
            else:
275
                symbolInfo = app_doc_data.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
        try:
692
            app_doc_data = AppDocData.instance()
693
            units = [attr[1] for attr in app_doc_data.activeDrawing.attrs if attr[0] == 'Units'][0]
694

    
695
            # clear labels
696
            for conn, label in self.desc_labels.items():
697
                """reset all of nozzle descriptions"""
698
                if conn.data:
699
                    conn.data.desc = None
700
                label.setEnabled(False)
701

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

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

    
733
                        if len(nozzles) > 0:
734
                            if self.name == 'HEX_DP':
735
                                if 'N1' in nozzles and 'N2' in nozzles:
736
                                    if self.connectors[0].data.desc is None:
737
                                        self.desc_labels[self.connectors[0]].setHtml(
738
                                            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>"
739
                                            f"[S] : {convert_to_fixed_point(self.connectors[1].data.elevation)} [T] : {convert_to_fixed_point(self.connectors[0].data.elevation)} {units['Length']}")
740
                                    else:
741
                                        self.desc_labels[self.connectors[0]].setHtml(self.connectors[0].data.desc)
742

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

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

    
761
                                    self.desc_labels[self.connectors[1]].setEnabled(True)
762
                            elif self.name == 'HEX_H':
763
                                if 'N1' in nozzles and 'N2' in nozzles:
764
                                    if self.connectors[0].data.desc is None:
765
                                        self.desc_labels[self.connectors[0]].setHtml(
766
                                            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>"
767
                                            f"[S] : {convert_to_fixed_point(self.connectors[0].data.elevation)} [T] : {convert_to_fixed_point(self.connectors[1].data.elevation)} {units['Length']}")
768
                                    else:
769
                                        self.desc_labels[self.connectors[0]].setHtml(self.connectors[0].data.desc)
770

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

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

    
789
                                    self.desc_labels[self.connectors[1]].setEnabled(True)
790
                            elif self.name == 'HEX_K':
791
                                if 'N1' in nozzles and 'N2' in nozzles:
792
                                    if self.connectors[0].data.desc is None:
793
                                        self.desc_labels[self.connectors[0]].setHtml(
794
                                            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>"
795
                                            f"[S] : {convert_to_fixed_point(self.connectors[1].data.elevation)} [T] : {convert_to_fixed_point(self.connectors[0].data.elevation)} {units['Length']}")
796
                                    else:
797
                                        self.desc_labels[self.connectors[0]].setHtml(self.connectors[0].data.desc)
798

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

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

    
817
                                    self.desc_labels[self.connectors[1]].setEnabled(True)
818
                            elif self.name == 'HEX_P':
819
                                if 'N1' in nozzles and 'N2' in nozzles:
820
                                    if self.connectors[0].data.desc is None:
821
                                        self.desc_labels[self.connectors[0]].setHtml(
822
                                            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>"
823
                                            f"[A] : {convert_to_fixed_point(self.connectors[0].data.elevation)} [B] : {convert_to_fixed_point(self.connectors[1].data.elevation)} {units['Length']}")
824
                                    else:
825
                                        self.desc_labels[self.connectors[0]].setHtml(self.connectors[0].data.desc)
826

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

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

    
845
                                    self.desc_labels[self.connectors[1]].setEnabled(True)
846
                            elif self.name == 'HEX_V':
847
                                if 'N1' in nozzles and 'N2' in nozzles:
848
                                    if self.connectors[0].data.desc is None:
849
                                        self.desc_labels[self.connectors[0]].setHtml(
850
                                            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>"
851
                                            f"[S] : {convert_to_fixed_point(self.connectors[1].data.elevation)} [T] : {convert_to_fixed_point(self.connectors[0].data.elevation)} {units['Length']}")
852
                                    else:
853
                                        self.desc_labels[self.connectors[0]].setHtml(self.connectors[0].data.desc)
854

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

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

    
873
                                    self.desc_labels[self.connectors[1]].setEnabled(True)
874
                elif self.type == 'Miscellaneous':
875
                    if self.name == 'M_Coil':
876
                        if self.tag_no:
877
                            conns = [conn for conn in self.connectors if conn.data and conn.data.elevation is not None]
878
                            if conns:
879
                                if conns[0].data.desc is None:
880
                                    self.desc_labels[conns[0]].setHtml(
881
                                        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>"
882
                                        f"{convert_to_fixed_point(conns[0].data.elevation)} {units['Length']}")
883
                                else:
884
                                    self.desc_labels[conns[0]].setHtml(conns[0].data.desc)
885

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

    
895
                            if len(nozzles) > 0:
896
                                if 'N1' in nozzles and 'N2' in nozzles:
897
                                    if self.connectors[0].data.desc is None:
898
                                        self.desc_labels[self.connectors[0]].setHtml(
899
                                            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>"
900
                                            f"[H] : {convert_to_fixed_point(self.connectors[1].data.elevation)} [V] : {convert_to_fixed_point(self.connectors[0].data.elevation)} {units['Length']}")
901
                                    else:
902
                                        self.desc_labels[self.connectors[0]].setHtml(self.connectors[0].data.desc)
903

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

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

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

    
931
                            if len(nozzles) > 0:
932
                                if ('N1' in nozzles or 'N2' in nozzles or 'N6' in nozzles) and \
933
                                        ('N3' in nozzles or 'N4' in nozzles or 'N5' in nozzles):
934
                                    if 'N1' in nozzles:
935
                                        top_index = 0
936
                                    elif 'N2' in nozzles:
937
                                        top_index = 1
938
                                    elif 'N6' in nozzles:
939
                                        top_index = 5
940

    
941
                                    if 'N3' in nozzles:
942
                                        btm_index = 2
943
                                    elif 'N4' in nozzles:
944
                                        btm_index = 3
945
                                    elif 'N5' in nozzles:
946
                                        btm_index = 4
947

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

    
956
                                    self.desc_labels[self.connectors[top_index]].setEnabled(True)
957
                                elif 'N1' in nozzles or 'N2' in nozzles or 'N6' in nozzles:
958
                                    if 'N1' in nozzles:
959
                                        index = 0
960
                                    elif 'N2' in nozzles:
961
                                        index = 1
962
                                    elif 'N6' in nozzles:
963
                                        index = 5
964

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

    
972
                                    self.desc_labels[self.connectors[index]].setEnabled(True)
973
                                elif 'N3' in nozzles or 'N4' in nozzles or 'N5' in nozzles:
974
                                    if 'N3' in nozzles:
975
                                        index = 2
976
                                    elif 'N4' in nozzles:
977
                                        index = 3
978
                                    elif 'N5' in nozzles:
979
                                        index = 4
980

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

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

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

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

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

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

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

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

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

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

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

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

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

    
1149
                            self.desc_labels[conns[0]].setEnabled(True)
1150
                elif self.type == 'Valve':
1151
                    if self.tag_no and self.name in ('CV_H', 'CV_V'):
1152
                        conns = [conn for conn in self.connectors if conn.data and conn.data.elevation is not None]
1153
                        if conns:
1154
                            if conns[0].data.desc is None:
1155
                                self.desc_labels[conns[0]].setHtml(
1156
                                    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>"
1157
                                    f"{convert_to_fixed_point(conns[0].data.elevation)} {units['Length']}")
1158
                            else:
1159
                                self.desc_labels[conns[0]].setHtml(conns[0].data.desc)
1160

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

    
1173
                            self.desc_labels[conns[0]].setEnabled(True)
1174

    
1175
            configs = app_doc_data.getAppConfigs('option', 'TagFontSize')
1176
            font_size = configs[0].value if configs and len(configs) == 1 else '6'
1177

    
1178
            configs = app_doc_data.getAppConfigs('option', 'TagFontColor')
1179
            font_color = configs[0].value if configs and len(configs) == 1 else '#000000'
1180

    
1181
            for conn, label in self.desc_labels.items():
1182
                label.set_font_size(font_size)
1183
                label.set_font_color(font_color)
1184
                label.setHtml(label.toPlainText().replace('\n', '<br>'))
1185
        except Exception as ex:
1186
            from App import App
1187
            message = f"error occurred({repr(ex)}) in {sys.exc_info()[-1].tb_frame.f_code.co_filename}:" \
1188
                      f"{sys.exc_info()[-1].tb_lineno}"
1189
            App.mainWnd().addMessage.emit(MessageType.Error, message)
1190

    
1191
    def rect(self):
1192
        """return bounding box of symbol"""
1193
        return self.sceneBoundingRect()
1194

    
1195
    '''
1196
        @brief  return true if line is able to connect symbol
1197
        @author humkyung
1198
        @date   2018.04.13
1199
    '''
1200

    
1201
    def is_connectable(self, item, toler=10):
1202
        # from EngineeringLineItem import QEngineeringLineItem
1203

    
1204
        '''
1205
        if False:#type(item) is QEngineeringLineItem:
1206
            line = item
1207
            start_pt = line.startPoint()
1208
            end_pt = line.endPoint()
1209
            for connector in self.connectors:
1210
                dx = connector.sceneConnectPoint[0] - (start_pt[0])
1211
                dy = connector.sceneConnectPoint[1] - (start_pt[1])
1212
                if (math.sqrt(dx*dx + dy*dy) < toler): return True
1213
                dx = connector.sceneConnectPoint[0] - (end_pt[0])
1214
                dy = connector.sceneConnectPoint[1] - (end_pt[1])
1215
                if (math.sqrt(dx*dx + dy*dy) < toler): return True
1216
        elif True:#issubclass(type(item), SymbolSvgItem):
1217
        '''
1218
        for connector in self.connectors:
1219
            for iConnector in item.connectors:
1220
                dx = connector.sceneConnectPoint[0] - iConnector.sceneConnectPoint[0]
1221
                dy = connector.sceneConnectPoint[1] - iConnector.sceneConnectPoint[1]
1222
                if (math.sqrt(dx * dx + dy * dy) < toler): return True
1223

    
1224
        return False
1225

    
1226
    '''
1227
        @author     humkyung
1228
        @date       2018.07.03
1229
    '''
1230

    
1231
    def is_connected(self, item, at=QEngineeringAbstractItem.CONNECTED_AT_PT):
1232
        """ check if given item is connected to self """
1233

    
1234
        _connectors = [connector for connector in self.connectors if
1235
                       (connector.connectedItem == item and (connector._connected_at == at if at else True))]
1236
        return len(_connectors) > 0
1237

    
1238
    def getConnectionPointCloseTo(self, pt, toler=10):
1239
        """get connection point close to given point in tolerance"""
1240
        import math
1241

    
1242
        for connector in self.connectors:
1243
            center = connector.center()
1244

    
1245
            dx = center[0] - pt[0]
1246
            dy = center[1] - pt[1]
1247

    
1248
            if math.sqrt(dx * dx + dy * dy) < toler:
1249
                return center
1250

    
1251
        return None
1252

    
1253
    '''
1254
        @brief  return center of symbol
1255
        @author humkyung
1256
        @date   2018.04.08
1257
    '''
1258

    
1259
    def center(self):
1260
        return self.sceneBoundingRect().center()
1261

    
1262
    def hoverEnterEvent(self, event):
1263
        self.highlight(True)
1264

    
1265
    '''
1266
        @brief      unhighlight connector and attribute
1267
        @author     humkyung
1268
        @date       2018.05.02
1269
        @history    kyouho 2018.07.18 edit ArrowCursor
1270
    '''
1271

    
1272
    def hoverLeaveEvent(self, event):
1273
        self.highlight(False)
1274

    
1275
    def highlight(self, flag):
1276
        """ highlight/unhighlight the symbol """
1277

    
1278
        try:
1279
            self.hover = flag
1280
            self.setZValue(QEngineeringAbstractItem.HOVER_ZVALUE) if flag else self.setZValue(SymbolSvgItem.ZVALUE)
1281
            self.update()
1282
        except Exception as ex:
1283
            from App import App
1284
            message = 'error occurred({}) in {}:{}'.format(ex, sys.exc_info()[-1].tb_frame.f_code.co_filename,
1285
                                                           sys.exc_info()[-1].tb_lineno)
1286
            App.mainWnd().addMessage.emit(MessageType.Error, message)
1287

    
1288
    '''
1289
        @brief      set highlight
1290
        @author     kyouho
1291
        @date       2018.08.27
1292
    '''
1293

    
1294
    def setHightlight(self):
1295
        self.setColor('url(#hover)')
1296
        self.update()
1297

    
1298
    '''
1299
        @brief      unset highlight
1300
        @author     kyouho
1301
        @date       2018.08.27
1302
    '''
1303

    
1304
    def unsetHightlight(self):
1305
        self.setColor('url(#normal)')
1306
        self.update()
1307

    
1308
    def get_selected_corner(self, pos):
1309
        toler = 5 * self.scale()
1310

    
1311
        corner = self.corners[2]
1312
        dx = corner.x() - pos.x()
1313
        dy = corner.y() - pos.y()
1314
        return math.sqrt(dx * dx + dy * dy) < toler
1315

    
1316
    def mousePressEvent(self, event):
1317
        import math
1318

    
1319
        if event.buttons() == Qt.LeftButton:
1320
            toler = 5*self.scale()
1321

    
1322
            # try to select corner
1323
            pos = event.scenePos()
1324
            corner = self.corners[2]
1325
            dx = corner.x() - pos.x()
1326
            dy = corner.y() - pos.y()
1327
            self._selected_idx = 2 if math.sqrt(dx * dx + dy * dy) < toler else None
1328
            # up to here
1329

    
1330
        super(SymbolSvgItem, self).mousePressEvent(event)
1331

    
1332
    def mouseMoveEvent(self, event):
1333
        """reshape dimension"""
1334

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

    
1340
            self.resize(QRectF(min_x, min_y, max_x - min_x, max_y - min_y))
1341
            return
1342

    
1343
        super(SymbolSvgItem, self).mouseMoveEvent(event)
1344

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

    
1349
    def itemChange(self, change, value):
1350
        """ call signals when item's position is changed """
1351
        if change == QGraphicsItem.ItemPositionHasChanged or change == QGraphicsItem.ItemScaleHasChanged:
1352
            self.transfer.on_pos_changed.emit(self)
1353
            self.scene().contents_changed.emit()
1354
            return value
1355

    
1356
        return super().itemChange(change, value)
1357

    
1358
    def keyPressEvent(self, event):
1359
        """key event handler"""
1360
        if not self.isSelected(): return
1361

    
1362
        if event.key() == Qt.Key_Delete:
1363
            self.deleteSvgItemFromScene()
1364
        elif event.key() == Qt.Key_QuoteLeft:
1365
            self.mouseDoubleClickEvent(event)
1366
        elif event.key() == Qt.Key_H:
1367
            from FlipCommand import FlipCommand
1368

    
1369
            try:
1370
                viewer = App.mainWnd().graphicsView
1371
                items = viewer.scene.selectedItems()
1372
                if items:
1373
                    viewer.scene.undo_stack.push(FlipCommand(viewer.scene, items, flip=1))
1374
            except Exception as ex:
1375
                message = f"error occurred({repr(ex)}) in {sys.exc_info()[-1].tb_frame.f_code.co_filename}:" \
1376
                          f"{sys.exc_info()[-1].tb_lineno}"
1377

    
1378
                self.addMessage.emit(MessageType.Error, message)
1379
        elif event.key() == Qt.Key_V:
1380
            from FlipCommand import FlipCommand
1381

    
1382
            try:
1383
                viewer = App.mainWnd().graphicsView
1384
                items = viewer.scene.selectedItems()
1385
                if items:
1386
                    viewer.scene.undo_stack.push(FlipCommand(viewer.scene, items, flip=2))
1387
            except Exception as ex:
1388
                message = f"error occurred({repr(ex)}) in {sys.exc_info()[-1].tb_frame.f_code.co_filename}:" \
1389
                          f"{sys.exc_info()[-1].tb_lineno}"
1390

    
1391
                self.addMessage.emit(MessageType.Error, message)
1392

    
1393

    
1394
    '''
1395
        @brief      Double click event, Show rotate symbol dialog
1396
        @author     euisung
1397
        @date       2019.04.16
1398
    '''
1399

    
1400
    def mouseDoubleClickEvent(self, event):
1401
        func_map = [
1402
            (('Equipment - [ Pressure Drop ]', 'Air Fin Cooler', 'AF_Cooler'), self.show_AirFinCooler),
1403
            (('Equipment - [ Pressure Drop ]', 'Filter', ('Filter_H', 'Filter_V')), self.show_Filter),
1404
            (('Equipment - [ Pressure Drop ]', 'Heat Exchanger', ('HEX_DP', 'HEX_H', 'HEX_K', 'HEX_V')),
1405
             self.show_ShlTubHeatExchanger),
1406
            (('Equipment - [ Pressure Drop ]', 'Heat Exchanger', ('HEX_P')), self.show_PlateHeatExchanger),
1407
            (('Equipment - [ Pressure Drop ]', 'Miscellaneous', ('M_Coil')), self.show_Coil),
1408
            (('Equipment - [ Pressure Drop ]', 'Miscellaneous', ('M_DP_E')), self.show_DP_Equipment),
1409
            (('Equipment - [ Pressure Drop ]', 'Miscellaneous', ('M_React')), self.show_Reactor),
1410
            (('Equipment - [ Pressure Drop ]', 'Strainer', ('T_Strainer_H', 'T_Strainer_V')), self.show_Strainer_T),
1411
            (('Equipment - [ Pressure Drop ]', 'Strainer', ('Y_Strainer_H', 'Y_Strainer_V')), self.show_Strainer_Y),
1412
            (('Equipment - [ Pressurized ]', 'Battery Limit', None), self.show_BatteryLimit),
1413
            (('Equipment - [ Pressurized ]', 'Column', ('CwT')), self.show_Tray),
1414
            (('Equipment - [ Pressurized ]', 'Column', ('CwP_Single')), self.show_SinglePacked),
1415
            (('Equipment - [ Pressurized ]', 'Column', ('CwP_Dual')), self.show_DualPacked),
1416
            (('Equipment - [ Pressurized ]', 'Drum', ('Drum_H')), self.show_Drum_Horizontal),
1417
            (('Equipment - [ Pressurized ]', 'Drum', ('Drum_V')), self.show_Drum_Vertical),
1418
            (('Equipment - [ Pressurized ]', 'Miscellaneous', ('ME')), self.show_Equipment),
1419
            (('Equipment - [ Pressurized ]', 'Tank', ('Ball_Tank')), self.show_Ball),
1420
            (('Equipment - [ Pressurized ]', 'Tank', ('CRT')), self.show_ConeRoof),
1421
            (('Equipment - [ Pressurized ]', 'Tank', ('DRT')), self.show_DomeRoof),
1422
            (('Equipment - [ Rotating ]', 'Compressor', ('L_Comp', 'R_Comp')), self.show_Compressor),
1423
            (('Equipment - [ Rotating ]', 'Compressor', ('L_Komp', 'R_Komp')), self.show_Kompressor),
1424
            (('Equipment - [ Rotating ]', 'Pump', ('L_Pump', 'R_Pump', 'V_Pump')), self.show_Pump),
1425
            (('Instrument', 'Valve', ('CV_H', 'CV_V')), self.show_ValveControl),
1426
            (('Instrument', 'Valve', ('MV_H', 'MV_V')), self.show_ValveManual),
1427
            (('Instrument', 'Line Splitter', ('Line_Splitter')), self.show_LineSplitter),
1428
            (('Instrument', 'Flowmeter', (
1429
                'Ori_Flowmeter_H', 'Oth_Flowmeter_H', 'Ven_Flowmeter_H', 'Ori_Flowmeter_V', 'Oth_Flowmeter_V',
1430
                'Ven_Flowmeter_V')), self.show_Flowmeter),
1431
            (('Instrument', 'Reducer', ('Re_Ex_Dw', 'Re_Ex_L', 'Re_Ex_R', 'Re_Ex_Up')), self.show_Reducer)
1432
        ]
1433

    
1434
        connectedItems = [connector for connector in self.connectors if connector.connectedItem is not None]
1435
        if len(connectedItems) < 1:
1436
            msg = QMessageBox()
1437
            msg.setIcon(QMessageBox.Information)
1438
            msg.setText(self.tr('Connect Line before Data input'))
1439
            msg.setWindowTitle(self.tr("Information"))
1440
            msg.setStandardButtons(QMessageBox.Ok)
1441
            msg.exec_()
1442
            return
1443

    
1444
        matches = [func for func in func_map if func[0][0] == self.category and func[0][1] == self.type and
1445
                   (func[0][2] is None or self.name in func[0][2])]
1446
        if matches:
1447
            matches[0][1]()
1448

    
1449
    def change_output_font_color(self):
1450

    
1451
        App.mainWnd().change_output_font_color()
1452

    
1453
        '''
1454
        row_count = App.mainWnd().tableWidgetDeviation.rowCount()
1455
        col_count = App.mainWnd().tableWidgetDeviation.columnCount()
1456
        for row in range(row_count):
1457
            for col in range(col_count):
1458
                if row == 0:
1459
                    item = App.mainWnd().tableWidgetDeviation.item(row, col)
1460
                    item.setText('RUN CALCULATION')
1461
                    item.setForeground(Qt.red)
1462
                    App.mainWnd().tableWidgetDeviation.setItem(row, col, item)
1463
                else:
1464
                    App.mainWnd().tableWidgetDeviation.item(row, col).setForeground(QBrush(QColor(169, 169, 169)))
1465

1466
        row_count = App.mainWnd().tableWidgetOutput.rowCount()
1467
        col_count = App.mainWnd().tableWidgetOutput.columnCount()
1468
        for row in range(row_count):
1469
            for col in range(col_count):
1470
                App.mainWnd().tableWidgetOutput.item(row, col).setForeground(QBrush(QColor(169, 169, 169)))
1471
                col_span = App.mainWnd().tableWidgetOutput.columnSpan(row, col)
1472
                if col_span > 1:
1473
                    break
1474
        '''
1475

    
1476
    def show_AirFinCooler(self):
1477
        from AirFinCooler import QAirFinCooler
1478

    
1479
        dialog = QAirFinCooler()
1480
        modified = dialog.show_dialog(self)
1481
        if modified:
1482
            self.update_label_contents()
1483
            self.validate()
1484
            self.change_output_font_color()
1485

    
1486
    def show_Filter(self):
1487
        from Filter import QFilter
1488

    
1489
        dialog = QFilter()
1490
        modified = dialog.show_dialog(self)
1491
        if modified:
1492
            self.update_label_contents()
1493
            self.validate()
1494
            self.change_output_font_color()
1495

    
1496
    def show_Coil(self):
1497
        from Coil import QCoil
1498

    
1499
        dialog = QCoil()
1500
        modified = dialog.show_dialog(self)
1501
        if modified:
1502
            self.update_label_contents()
1503
            self.validate()
1504
            self.change_output_font_color()
1505

    
1506
    def show_DP_Equipment(self):
1507
        from DP_Equipment import QDP_Equipment
1508

    
1509
        dialog = QDP_Equipment()
1510
        modified = dialog.show_dialog(self)
1511
        if modified:
1512
            self.update_label_contents()
1513
            self.validate()
1514
            self.change_output_font_color()
1515

    
1516
    def show_Reactor(self):
1517
        from Reactor import QReactor
1518

    
1519
        dialog = QReactor()
1520
        modified = dialog.show_dialog(self)
1521
        if modified:
1522
            self.update_label_contents()
1523
            self.validate()
1524
            self.change_output_font_color()
1525

    
1526
    def show_Strainer_T(self):
1527
        from Strainer_T import QStrainer_T
1528

    
1529
        dialog = QStrainer_T()
1530
        modified = dialog.show_dialog(self)
1531
        if modified:
1532
            self.update_label_contents()
1533
            self.validate()
1534
            self.change_output_font_color()
1535

    
1536
    def show_Strainer_Y(self):
1537
        from Strainer_Y import QStrainer_Y
1538

    
1539
        dialog = QStrainer_Y()
1540
        modified = dialog.show_dialog(self)
1541
        if modified:
1542
            self.update_label_contents()
1543
            self.validate()
1544
            self.change_output_font_color()
1545

    
1546
    def show_BatteryLimit(self):
1547
        from BatteryLimit import QBatteryLimit
1548

    
1549
        dialog = QBatteryLimit()
1550
        modified = dialog.show_dialog(self)
1551
        if modified:
1552
            self.update_label_contents()
1553
            self.validate()
1554
            self.change_output_font_color()
1555

    
1556
    def show_Tray(self):
1557
        from Tray import QTray
1558

    
1559
        dialog = QTray()
1560
        modified = dialog.show_dialog(self)
1561
        if modified:
1562
            self.update_label_contents()
1563
            self.validate()
1564
            self.change_output_font_color()
1565

    
1566
    def show_SinglePacked(self):
1567
        from SinglePacked import QSinglePacked
1568

    
1569
        dialog = QSinglePacked()
1570
        modified = dialog.show_dialog(self)
1571
        if modified:
1572
            self.update_label_contents()
1573
            self.validate()
1574
            self.change_output_font_color()
1575

    
1576
    def show_DualPacked(self):
1577
        from DualPacked import QDualPacked
1578

    
1579
        dialog = QDualPacked()
1580
        modified = dialog.show_dialog(self)
1581
        if modified:
1582
            self.update_label_contents()
1583
            self.validate()
1584
            self.change_output_font_color()
1585

    
1586
    def show_Drum_Horizontal(self):
1587
        from Drum_Horizontal import QDrum_Horizontal
1588

    
1589
        dialog = QDrum_Horizontal()
1590
        modified = dialog.show_dialog(self)
1591
        if modified:
1592
            self.update_label_contents()
1593
            self.validate()
1594
            self.change_output_font_color()
1595

    
1596
    def show_Drum_Vertical(self):
1597
        from Drum_Vertical import QDrum_Vertical
1598

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

    
1606
    def show_PlateHeatExchanger(self):
1607
        from PlateHeatExchanger import QPlateHeatExchanger
1608

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

    
1616
    def show_Equipment(self):
1617
        from Equipment import QEquipment
1618

    
1619
        dialog = QEquipment()
1620
        modified = dialog.show_dialog(self)
1621
        if modified:
1622
            self.update_label_contents()
1623
            self.validate()
1624
            self.change_output_font_color()
1625

    
1626
    def show_Ball(self):
1627
        from Ball import QBall
1628

    
1629
        dialog = QBall()
1630
        modified = dialog.show_dialog(self)
1631
        if modified:
1632
            self.update_label_contents()
1633
            self.validate()
1634
            self.change_output_font_color()
1635

    
1636
    def show_ShlTubHeatExchanger(self):
1637
        from ShlTubHeatExchanger import QShlTubHeatExchanger
1638

    
1639
        dialog = QShlTubHeatExchanger()
1640
        modified = dialog.show_dialog(self)
1641
        if modified:
1642
            self.update_label_contents()
1643
            self.validate()
1644
            self.change_output_font_color()
1645

    
1646
    def show_ConeRoof(self):
1647
        from ConeRoof import QConeRoof
1648

    
1649
        dialog = QConeRoof()
1650
        modified = dialog.show_dialog(self)
1651
        if modified:
1652
            self.update_label_contents()
1653
            self.validate()
1654
            self.change_output_font_color()
1655

    
1656
    def show_DomeRoof(self):
1657
        from DomeRoof import QDomeRoof
1658

    
1659
        dialog = QDomeRoof()
1660
        modified = dialog.show_dialog(self)
1661
        if modified:
1662
            self.update_label_contents()
1663
            self.validate()
1664
            self.change_output_font_color()
1665

    
1666
    def show_Compressor(self):
1667
        from Compressor import QCompressor
1668

    
1669
        dialog = QCompressor()
1670
        modified = dialog.show_dialog(self)
1671
        if modified:
1672
            self.update_label_contents()
1673
            self.validate()
1674
            self.change_output_font_color()
1675

    
1676
    def show_Kompressor(self):
1677
        from Kompressor import QKompressor
1678

    
1679
        dialog = QKompressor()
1680
        modified = dialog.show_dialog(self)
1681
        if modified:
1682
            self.update_label_contents()
1683
            self.validate()
1684
            self.change_output_font_color()
1685

    
1686
    def show_Pump(self):
1687
        from Pump import QPump
1688

    
1689
        dialog = QPump()
1690
        modified = dialog.show_dialog(self)
1691
        if modified:
1692
            self.update_label_contents()
1693
            self.validate()
1694
            self.change_output_font_color()
1695

    
1696
    def show_ValveControl(self):
1697
        from Valve_Control import QValve_Control
1698

    
1699
        dialog = QValve_Control()
1700
        modified = dialog.show_dialog(self)
1701
        if modified:
1702
            self.update_label_contents()
1703
            self.validate()
1704
            self.change_output_font_color()
1705

    
1706
    def show_ValveManual(self):
1707
        from Valve_Manual import QValve_Manual
1708

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

    
1716
    def show_LineSplitter(self):
1717
        from LineSplitter import QLineSplitter
1718

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

    
1726
    def show_Flowmeter(self):
1727
        from Flowmeter import QFlowmeter
1728

    
1729
        dialog = QFlowmeter()
1730
        modified = dialog.show_dialog(self)
1731
        if modified:
1732
            self.update_label_contents()
1733
            self.validate()
1734
            self.change_output_font_color()
1735

    
1736
    def show_Reducer(self):
1737
        from Reducer import QReducer
1738

    
1739
        dialog = QReducer()
1740
        modified = dialog.show_dialog(self)
1741
        if modified:
1742
            self.update_label_contents()
1743
            self.validate()
1744
            self.change_output_font_color()
1745

    
1746
    def rotate(self, angle: float) -> None:
1747
        """rotate symbol clockwise by given angle in degree about origin point"""
1748
        self.setRotation(angle)
1749

    
1750
    @staticmethod
1751
    def fromDatabase(componentInfos):
1752
        """ create a component from database """
1753
        item = None
1754

    
1755
        try:
1756
            uid = componentInfos[0]['Comp_UID']  # uid@Components
1757
            tag_no = componentInfos[0]['Name']  # name@Components
1758
            index = componentInfos[0]['Comp_Index']
1759
            dbUid = componentInfos[0]['Symbols_UID']  # Symbol_UID@Components
1760
            category = componentInfos[0]['Category']  # Category@SymbolType
1761
            _type = componentInfos[0]['Type']  # Type@SymbolType
1762
            name = componentInfos[0]['Symbol_Name']  # Name@Symbols
1763
            originalPoint = componentInfos[0]['OriginalPoint']  # OriginalPoint@Symbols
1764
            x = componentInfos[0]['Comp_X']  # X@Components
1765
            y = componentInfos[0]['Comp_Y']  # Y@Components
1766
            angle = componentInfos[0]['Rotation']  # Rotation@Components
1767
            #scale = componentInfos[0]['Scale']  # Scale@Components
1768
            scales = [float(componentInfos[0]['ScaleX']), float(componentInfos[0]['ScaleY'])]  # scale x, scale y
1769

    
1770
            pt = []
1771
            pt.append(float(x))
1772
            pt.append(float(y))
1773

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

    
1776
            connPts = []
1777

    
1778
            pointsUids = []
1779
            for componentInfo in componentInfos:
1780
                pointsUid = componentInfo['Point_UID']  # uid@Points
1781
                pointsUids.append(pointsUid)
1782

    
1783
            item = SymbolSvgItem.createItem(_type, uid, None, 0, dbUid)
1784
            item.setVisible(False)
1785
            item.buildItem(name, _type, float(angle), scales , pt, origin, connPts, dbUid, pointsUids, index)
1786
            item.tag_no = tag_no
1787
            item.build_label()
1788

    
1789
        except Exception as ex:
1790
            from App import App
1791
            message = f'error occurred({repr(ex)}) in {sys.exc_info()[-1].tb_frame.f_code.co_filename}:' \
1792
                      f'{sys.exc_info()[-1].tb_lineno}'
1793
            App.mainWnd().addMessage.emit(MessageType.Error, message)
1794

    
1795
        return item
1796

    
1797
    '''
1798
        @brief      create item corresponding to given type
1799
        @author     humkyung
1800
        @date       2018.05.02
1801
        @history    2018.05.08  Jeongwoo    Change type name (Piping OPC''S → Piping OPC's)
1802
                    humkyung 2018.05.10 change symbol's color to blue
1803
                    humkyung 2018.07.19 create nozzle instance if type is 'Nozzles'
1804
    '''
1805

    
1806
    @staticmethod
1807
    def createItem(type, uid=None, owner=None, flip=0, symbol=None):
1808
        import uuid
1809

    
1810
        item = SymbolSvgItem(uid, flip=flip, symbol=symbol)
1811

    
1812
        if owner is not None:
1813
            item.owner = uuid.UUID(owner)
1814

    
1815
        return item
1816

    
1817
    '''
1818
        @brief      change svg's color
1819
        @author     humkyung
1820
        @date       2018.05.10
1821
        @history    2018.05.11  Jeongwoo    Override QEngineeringAbstractItem's
1822
                    humkyung 2018.05.13 update after change color
1823
    '''
1824

    
1825
    def setColor(self, color):
1826
        self.changeAttributes('fill', color)
1827
        self.changeAttributes('stroke', color)
1828
        self.renderer().load(self._document.toByteArray())
1829
        self.update()
1830

    
1831
    def getColor(self):
1832
        """ return hover color if mouse is over otherwise reutrn owner's color if owner exist else this color """
1833
        return SymbolSvgItem.HOVER_COLOR if self.hover else (
1834
            self.owner._color if self.owner and hasattr(self.owner, '_color') else self._color)
1835

    
1836
    '''
1837
        @brief  get attributes from svg file
1838
        @author humkyung
1839
        @date   2019.03.08
1840
    '''
1841

    
1842
    def get_attribute(self, attName):
1843
        root = self._document.documentElement()
1844
        node = root.firstChild()
1845
        while not node.isNull():
1846
            if node.isElement():
1847
                element = node.toElement()
1848
                if element.hasAttribute(attName):
1849
                    return element.attribute(attName)
1850

    
1851
                if element.hasChildNodes():
1852
                    att_val = self.recursive_get_attribute(element.firstChild(), attName)
1853
                    if att_val is not None: return att_val
1854

    
1855
            node = node.nextSibling()
1856

    
1857
        return None
1858

    
1859
    '''
1860
        @brief  get recursively attribute
1861
        @author humkyung
1862
        @date   2019.03.08
1863
    '''
1864

    
1865
    def recursive_get_attribute(self, node, attName):
1866
        while not node.isNull():
1867
            if node.isElement():
1868
                element = node.toElement()
1869
                if element.hasAttribute(attName):
1870
                    return element.attribute(attName)
1871

    
1872
                if node.hasChildNodes():
1873
                    att_val = self.recursive_get_attribute(node.firstChild(), attName)
1874
                    if att_val is not None: return att_val
1875

    
1876
            node = node.nextSibling()
1877

    
1878
        return None
1879

    
1880
    '''
1881
        @brief  change attributes
1882
        @author humkyung
1883
        @date   2018.05.10
1884
    '''
1885

    
1886
    def changeAttributes(self, attName, attValue):
1887
        root = self._document.documentElement()
1888
        node = root.firstChild()
1889
        while not node.isNull():
1890
            if node.isElement():
1891
                element = node.toElement()
1892
                if element.hasAttribute(attName):
1893
                    element.setAttribute(attName, attValue)
1894

    
1895
                if element.hasChildNodes():
1896
                    recursiveChangeAttributes(element.firstChild(), attName, attValue)
1897

    
1898
            node = node.nextSibling()
1899

    
1900
    '''
1901
        @brief  change attribute
1902
        @author humkyung
1903
        @date   2018.05.10
1904
    '''
1905

    
1906
    def recursiveChangeAttributes(self, node, attName, attValue):
1907
        while not node.isNull():
1908
            if node.isElement():
1909
                element = node.toElement()
1910
                if element.hasAttribute(attName):
1911
                    element.setAttribute(attName, attValue)
1912

    
1913
                if node.hasChildNodes():
1914
                    recursiveChangeAttributes(node.firstChild(), attName, attValue)
1915

    
1916
            node = node.nextSibling()
1917

    
1918
    '''
1919
        @brief  draw rect when item is selected
1920
        @author humkyung
1921
        @date   2018.07.07
1922
    '''
1923

    
1924
    def draw_focus_rect(self, painter):
1925
        hilightColor = QColor(255, 0, 0, 127)
1926
        painter.setBrush(QBrush(hilightColor))
1927

    
1928
        corner = self.corners[2]
1929
        pt = self.mapFromScene(corner)
1930
        painter.drawEllipse(pt, 5, 5)
1931

    
1932
    def paint(self, painter, options=None, widget=None):
1933
        """override paint(draw connection points)"""
1934
        self.setColor(self.getColor())
1935

    
1936
        painter.setClipRect(options.exposedRect)
1937
        QGraphicsSvgItem.paint(self, painter, options, widget)
1938

    
1939
        if self.isSelected():
1940
            self.draw_focus_rect(painter)
1941

    
1942
    def addSvgItemToScene(self, scene):
1943
        """add svg item to scene"""
1944
        
1945
        try:
1946
            scene.addItem(self)
1947
            self.setTransformOriginPoint(QPointF(self.symbolOrigin[0], self.symbolOrigin[1]))  # affect only to rotation
1948
            trans = QTransform()
1949
            trans.scale(self._scales[0], self._scales[1])
1950
            self.setTransform(trans)
1951
            self.rotate(self.angle)
1952
            pt = trans.map(self.symbolOrigin[0], self.symbolOrigin[1])
1953
            self.setPos(self.loc[0] - pt[0], self.loc[1] - pt[1])
1954
            
1955
            # scale down for label
1956
            """
1957
            trans = QTransform()
1958
            trans.scale(1 / self._scales[0], 1 / self._scales[1])
1959
            for conn, label in self.desc_labels.items():
1960
                label.setTransform(trans)
1961
            """
1962
            # up to here
1963
        except Exception as ex:
1964
            from App import App
1965
            from AppDocData import MessageType
1966

    
1967
            message = f"error occurred({repr(ex)}) in {sys.exc_info()[-1].tb_frame.f_code.co_filename}:" \
1968
                      f"{sys.exc_info()[-1].tb_lineno}"
1969
            App.mainWnd().addMessage.emit(MessageType.Error, message)
1970

    
1971
    '''
1972
        @brief      
1973
        @author     humkyung
1974
        @date       2018.07.27
1975
    '''
1976

    
1977
    def onConnectorPosChaned(self, connector):
1978
        pass
1979

    
1980
    def set_connector(self, uid, index=None):
1981
        """set connector"""
1982
        from AppDocData import AppDocData
1983

    
1984
        app_doc_data = AppDocData.instance()
1985
        connector = QEngineeringConnectorItem(uid, parent=self, index=index)
1986
        connector.data = app_doc_data.get_nozzle_data(uid)
1987
        self.connectors.append(connector)
1988

    
1989
        # set label
1990
        label = QEngineeringEqpDescTextItem('', self)
1991
        self.desc_labels[connector] = label
1992

    
1993
    def deleteSvgItemFromScene(self):
1994
        """ remove self from scene """
1995
        try:
1996
            for conn in self.connectors:
1997
                if conn.connectedItem is not None:
1998
                    conn.connectedItem.connect(None)
1999
        except Exception as ex:
2000
            from App import App
2001
            from AppDocData import MessageType
2002

    
2003
            message = f'error occurred({repr(ex)}) in {sys.exc_info()[-1].tb_frame.f_code.co_filename}:' \
2004
                      f'{sys.exc_info()[-1].tb_lineno}'
2005
            App.mainWnd().addMessage.emit(MessageType.Error, message)
2006

    
2007
        self.transfer.onRemoved.emit(self)
2008
        
2009
    def flip_symbol(self, horizontal=True) -> None:
2010
        """flip symbol"""
2011
        trans = self.transform()
2012
        rect = self.boundingRect()
2013
        if horizontal:    # horizontal flip
2014
            trans.scale(-1, 1)
2015
            trans.translate(-rect.width(), 0)
2016
        else:  # vertical flip
2017
            trans.scale(1, -1)
2018
            trans.translate(0, -rect.height())
2019

    
2020
        self.resetTransform()
2021
        self.setTransform(trans)
2022

    
2023
    def getCurrentPoint(self):
2024
        """get current point"""
2025

    
2026
        pointList = []
2027
        pointList.append(self.symbolOrigin)
2028
        for connector in self.connectors:
2029
            pointList.append(connector.connectPoint)
2030

    
2031
        # if type(self) is QEngineeringSpecBreakItem:
2032
        #    self.currentPointModeIndex = 1
2033

    
2034
        return pointList[self.currentPointModeIndex]
2035

    
2036
    '''
2037
        @brief      심볼 회전 시 서로 다른 기준점으로 회전하기 때문에 기준점을 이후 개발한 SymbolSvgItem 기준의 회전좌표로 이동하기 위해서 만듬 (loc 기준으로 회전해야함)
2038
        @author     kyouho
2039
        @date       18.08.06
2040
    '''
2041

    
2042
    def reCalculationRotatedItem(self):
2043

    
2044
        transform = QTransform()
2045
        transform.translate(self.loc[0] + self.symbolOrigin[0], self.loc[1] + self.symbolOrigin[1])
2046
        transform.rotateRadians(-self.angle)
2047
        currentPoint = self.getCurrentPoint()
2048
        transform.translate(-currentPoint[0], -currentPoint[1])
2049
        # 시작점을 구하기 위해서
2050
        goPoint = transform.map(QPoint(self.symbolOrigin[0], self.symbolOrigin[1]))
2051

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

    
2054
    def moveto(self, to, timeLine=5000, rotation=0):
2055
        """Move the item from one position to one other."""
2056

    
2057
        anim = QPropertyAnimation(self, b'pos')
2058
        rect = self.sceneBoundingRect()
2059
        anim.setStartValue(QPointF(0, 0))
2060
        anim.setEndValue(QPointF(100, 10))
2061
        anim.setDuration(10000)
2062
        anim.start()
2063

    
2064

    
2065
def recursiveChangeAttributes(node, attName, attValue):
2066
    while not node.isNull():
2067
        if node.isElement():
2068
            element = node.toElement()
2069
            if element.hasAttribute(attName):
2070
                element.setAttribute(attName, attValue)
2071

    
2072
            if node.hasChildNodes():
2073
                recursiveChangeAttributes(node.firstChild(), attName, attValue)
2074

    
2075
        node = node.nextSibling()
2076

    
2077

    
2078
'''
2079
    @brief      The class transfer pyqtSignal Event. Cause Subclass of QGraphicsRectItem can't use pyqtSignal
2080
    @author     Jeongwoo
2081
    @date       2018.06.18
2082
'''
2083

    
2084

    
2085
class Transfer(QObject):
2086
    on_pos_changed = pyqtSignal(QGraphicsItem)
2087
    on_size_changed = pyqtSignal(QGraphicsItem)
2088
    onRemoved = pyqtSignal(QGraphicsItem)
2089

    
2090
    def __init__(self, parent=None):
2091
        QObject.__init__(self, parent)
2092

    
2093

    
2094
if __name__ == '__main__':
2095
    f = QFile('d:/Projects/DTIPID/DTI_PID/DTI_PID/SG_TEST/svg/ANGLE VALVE.svg')
2096
    f.open(QIODevice.ReadOnly)
2097
    array = f.readAll()
2098
    document = QDomDocument()
2099
    document.setContent(array)
2100

    
2101
    root = document.documentElement()
2102
    node = root.firstChild()
2103
    while not node.isNull():
2104
        if node.isElement():
2105
            element = node.toElement()
2106
            if element.hasAttribute('fill'):
2107
                element.setAttribute('fill', '#FFFFF')
2108

    
2109
            if element.hasChildNodes():
2110
                recursiveChangeAttributes(element.firstChild(), 'fill', '#FFFFF')
2111

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