프로젝트

일반

사용자정보

통계
| 개정판:

hytos / DTI_PID / DTI_PID / Shapes / EngineeringLineNoTextItem.py @ ea0ccb6f

이력 | 보기 | 이력해설 | 다운로드 (60.1 KB)

1
# coding: utf-8
2
""" This is engineering line no text item module """
3

    
4
import os.path
5
import sys
6
import copy
7

    
8
from EngineeringFromMarkItem import EngineeringFromMarkItem
9
from EngineeringToMarkItem import EngineeringToMarkItem
10

    
11
try:
12
    from PyQt5.QtCore import *
13
    from PyQt5.QtGui import *
14
    from PyQt5.QtWidgets import *
15
except ImportError:
16
    try:
17
        from PyQt4.QtCore import Qt, QRectF, pyqtSignal, QT_VERSION_STR, QRect
18
        from PyQt4.QtGui import QGraphicsView, QGraphicsScene, QImage, QPixmap, QPainterPath, QFileDialog, QFont
19
    except ImportError:
20
        raise ImportError("ImageViewerQt: Requires PyQt5 or PyQt4.")
21

    
22
from UserInputAttribute import UserInputAttribute
23
from OcrResultDialog import QOcrResultDialog
24
from AppDocData import AppDocData
25
from EngineeringTextItem import QEngineeringTextItem
26
from TextInfo import TextInfo
27

    
28
lineColumnList = ['UID', 'LINE_SIZE', 'LINE_SYMBOL', 'LINE_NO', 'LINE_CLASS', 'LINE_ROUTING_FROM', 'LINE_ROUTING_TO',
29
                  'SERVICE_FLUID', 'SERVICE_DENSITY', 'SERVICE_STATE', 'OPERATION_CONDITION_TEMP',
30
                  'OPERATION_CONDITION_PRESS', 'DESIGN_CONDITION_TEMP', 'DESIGN_CONDITION_PRESS', 'TEST_CONDITION_TEMP',
31
                  'TEST_CONDITION_PRESS', 'INSUL_CODE', 'PAINT_CODE', 'NDE_CODE', 'PWHT', 'PNID_NO']
32

    
33

    
34
class QEngineeringLineNoTextItem(QEngineeringTextItem):
35
    '''
36
        @history    18.05.14    Jeongwoo    Add variable self.runs
37
                    humkyung 2018.07.09 add stream no
38
    '''
39

    
40
    def __init__(self, uid=None, parent=None):
41
        from SymbolAttr import SymbolProp
42
        from EngineeringFreezeItem import QEngineeringFreezeItem
43

    
44
        QEngineeringTextItem.__init__(self, uid, parent)
45

    
46
        self._properties = { SymbolProp(None, 'From', 'Comp Item'): None, \
47
                                SymbolProp(None, 'To', 'Comp Item'): None, \
48
                                SymbolProp(None, 'Config', 'String'): None }  # , SymbolProp(None, 'Freeze', 'Boolean'):False}
49
        self._runs = []
50

    
51
        self.lineNoFromToIndicator = []
52
        self.lineNoFromToIndicatorShowFlag = False
53

    
54
        """ create freeze control """
55
        # self.freeze_item = QEngineeringFreezeItem(-QEngineeringFreezeItem.FREEZE_SIZE*0.5, -QEngineeringFreezeItem.FREEZE_SIZE*0.5, QEngineeringFreezeItem.FREEZE_SIZE, QEngineeringFreezeItem.FREEZE_SIZE)
56
        # self.freeze_item.setParentItem(self)
57
        # self.freeze_item.setZValue(self.zValue() + 1)
58
        # self.freeze_item.setPen(Qt.black)
59

    
60
    @property
61
    def Size(self):
62
        """ return line no's size """
63
        attrs = self.getAttributes()
64
        matches = [value for attr, value in attrs.items() if attr.Attribute.upper() == 'NOMINALDIAMETER']
65
        return matches[0] if matches else ''
66

    
67
    def empty(self):
68
        """ return True if run is empty else return False """
69
        return False if self._runs else True
70

    
71
    #def setVisible(self, visible):
72
    #    """ override visible value """
73
    #    super(QEngineeringTextItem, self).setVisible(visible)
74
    #    for run in self.runs:
75
    #        run.visible = visible
76

    
77
    @property
78
    def connected_line(self):
79
        """return connected line"""
80
        if self.conns:
81
            if type(self.conns[0]) is str:
82
                matches = [x for x in self.scene().items() if hasattr(x, 'uid') and str(x.uid) == str(self.conns[0])]
83
                if matches:
84
                    self.conns[0] = matches[0]
85

    
86
            return self.conns[0]
87

    
88
        return None
89

    
90
    '''
91
        @brief  getter of runs
92
        @author humkyung
93
        @date   2018.05.11
94
    '''
95

    
96
    @property
97
    def runs(self):
98
        return self._runs
99

    
100
    '''
101
        @brief  setter of runs
102
        @author humkyung
103
        @date   2018.05.11
104
    '''
105

    
106
    @runs.setter
107
    def runs(self, value):
108
        self._runs = value
109

    
110
    def hoverEnterEvent(self, event):
111
        """ highlight line no text and run's item """
112
        from App import App
113

    
114
        try:
115
            self.hover = True
116
            self.update()
117

    
118
            for run in self.runs:
119
                for item in run.items:
120
                    item.hoverEnterEvent(event, True)
121

    
122
                    # display from / to indicator
123
                    if not self.lineNoFromToIndicatorShowFlag:
124
                        if not self.lineNoFromToIndicator or len(self.lineNoFromToIndicator) < 2:
125
                            if run is self.runs[0] and (item is run.items[0] or item is run.items[-1]):
126
                                _label = EngineeringFromMarkItem(10, color=self._color) \
127
                                    if not self.lineNoFromToIndicator else EngineeringToMarkItem(10, color=self._color)
128
                                _label.setZValue(500)
129
                                self.scene().addItem(_label)
130
                                #_label.setParentItem(self)
131
                                _label.setPos(QPointF(item.origin[0], item.origin[1]))
132
                                self.lineNoFromToIndicator.append(_label)
133
                        elif self.lineNoFromToIndicator:
134
                            if run is self.runs[0] and (item is run.items[0]):
135
                                self.lineNoFromToIndicator[0].setPos(QPointF(item.origin[0], item.origin[1]))
136
                                self.lineNoFromToIndicator[0].setVisible(True)
137
                            elif run is self.runs[0] and (item is run.items[-1]):
138
                                self.lineNoFromToIndicator[1].setPos(QPointF(item.origin[0], item.origin[1]))
139
                                self.lineNoFromToIndicator[1].setVisible(True)
140

    
141
            if not self.runs:
142
                _from = self.prop('From')
143
                _to = self.prop('To')
144
                if _from and _to:
145
                    for item in [_from, _to]:
146
                    # display from / to indicator
147
                        if not self.lineNoFromToIndicator or len(self.lineNoFromToIndicator) < 2:
148
                            _label = EngineeringFromMarkItem(10, color=self._color) \
149
                                if not self.lineNoFromToIndicator else EngineeringToMarkItem(10, color=self._color)
150
                            _label.setZValue(500)
151
                            self.scene().addItem(_label)
152
                            _label.setPos(QPointF(item.origin[0], item.origin[1]))
153
                            self.lineNoFromToIndicator.append(_label)
154
                        elif self.lineNoFromToIndicator:
155
                            if item is _from:
156
                                self.lineNoFromToIndicator[0].setPos(QPointF(item.origin[0], item.origin[1]))
157
                                self.lineNoFromToIndicator[0].setVisible(True)
158
                            elif item is _to:
159
                                self.lineNoFromToIndicator[1].setPos(QPointF(item.origin[0], item.origin[1]))
160
                                self.lineNoFromToIndicator[1].setVisible(True)
161

    
162
        except Exception as ex:
163
            from App import App
164
            from AppDocData import MessageType
165

    
166
            message = 'error occurred({}) in {}:{}'.format(ex, sys.exc_info()[-1].tb_frame.f_code.co_filename,
167
                                                           sys.exc_info()[-1].tb_lineno)
168
            App.mainWnd().addMessage.emit(MessageType.Error, message)
169

    
170
    def contextMenuEvent(self, event):
171
        items = self.scene().selectedItems()
172
        if len(items) == 1 and self in items:
173
            menu = QMenu()
174

    
175
            '''
176
            explodeAction = QAction('Explode', None)
177
            explodeAction.triggered.connect(self.contextExplode)
178
            menu.addAction(explodeAction)
179

180
            explodeKeepAction = QAction('Explode(keep from, to)', None)
181
            explodeKeepAction.triggered.connect(self.contextExplodeKeep)
182
            menu.addAction(explodeKeepAction)
183
            '''
184

    
185
            explodeAction = QAction('Explode', None)
186
            explodeAction.triggered.connect(self.contextExplode)
187
            menu.addAction(explodeAction)
188

    
189
            explodeKeepAction = QAction('Explode(keep from, to)', None)
190
            explodeKeepAction.triggered.connect(self.contextExplodeKeep)
191
            menu.addAction(explodeKeepAction)
192

    
193
            fromAction = QAction('Set From(S)', None)
194
            fromAction.triggered.connect(self.contextFrom)
195
            menu.addAction(fromAction)
196

    
197
            toAction = QAction('Set To(D)', None)
198
            toAction.triggered.connect(self.contextTo)
199
            menu.addAction(toAction)
200

    
201
            showAction = QAction('Show From, To(H)', None) if not self.lineNoFromToIndicatorShowFlag else QAction('Hide From, To(H)', None)
202
            showAction.triggered.connect(self.contextShow)
203
            menu.addAction(showAction)
204

    
205
            allAction = QAction('Select All in View(A)', None)
206
            allAction.triggered.connect(self.contextSelectAll)
207
            menu.addAction(allAction)
208

    
209
            highlightAction = QAction('Highlight', None)
210
            highlightAction.triggered.connect(lambda: self.contextHighlight(self))
211
            menu.addAction(highlightAction)
212

    
213
            actions = []
214
            for index in range(len(self.runs)):
215
                actions.append(QAction('Highlight Run ' + str(index + 1), None))
216

    
217
            binding = [lambda index=index: actions[index].triggered.connect(lambda: self.contextHighlight(self.runs[index])) for index in range(len(self.runs))]
218
    
219
            for index in range(len(actions)):
220
                binding[index]()
221
                menu.addAction(actions[index])
222

    
223
            editAction = QAction('Edit(Return)', None)
224
            editAction.triggered.connect(self.contextEdit)
225
            menu.addAction(editAction)
226

    
227
            rotateAction = QAction('Rotate(R)', None)
228
            rotateAction.triggered.connect(self.contextRotate)
229
            menu.addAction(rotateAction)
230

    
231
            deleteAction = QAction('Delete(E)', None)
232
            deleteAction.triggered.connect(self.contextDelete)
233
            menu.addAction(deleteAction)
234

    
235
            menu.exec_(event.screenPos())
236

    
237
    def contextSelectAll(self):
238
        from App import App
239
        
240
        rect = App.mainWnd().graphicsView.viewport().rect()
241
        view_rect = App.mainWnd().graphicsView.mapToScene(rect).boundingRect()
242
        lineNos = [item for item in self.scene().items() if type(item) is QEngineeringLineNoTextItem and view_rect.contains(item.sceneBoundingRect().center())]
243
        for lineNo in lineNos:
244
            lineNo.setSelected(True)
245

    
246
    def contextShow(self):
247
        self.lineNoFromToIndicatorShowFlag = not self.lineNoFromToIndicatorShowFlag
248
        if self.lineNoFromToIndicatorShowFlag:
249
            if self.runs and self.runs[0].items:
250
                for item in [self.runs[0].items[0], self.runs[0].items[-1]]:
251
                    # display from / to indicator
252
                    if not self.lineNoFromToIndicator or len(self.lineNoFromToIndicator) < 2:
253
                        _label = EngineeringFromMarkItem(10, color=self._color) \
254
                            if not self.lineNoFromToIndicator else EngineeringToMarkItem(10, color=self._color)
255
                        _label.setZValue(500)
256
                        self.scene().addItem(_label)
257
                        _label.setPos(QPointF(item.origin[0], item.origin[1]))
258
                        self.lineNoFromToIndicator.append(_label)
259
                    elif self.lineNoFromToIndicator:
260
                        if item is self.runs[0].items[0]:
261
                            self.lineNoFromToIndicator[0].setPos(QPointF(item.origin[0], item.origin[1]))
262
                            self.lineNoFromToIndicator[0].setVisible(True)
263
                        elif item is self.runs[0].items[-1]:
264
                            self.lineNoFromToIndicator[1].setPos(QPointF(item.origin[0], item.origin[1]))
265
                            self.lineNoFromToIndicator[1].setVisible(True)
266
            elif not self.runs:
267
                _from = self.prop('From')
268
                _to = self.prop('To')
269
                if _from and _to:
270
                    for item in [_from, _to]:
271
                    # display from / to indicator
272
                        if not self.lineNoFromToIndicator or len(self.lineNoFromToIndicator) < 2:
273
                            _label = EngineeringFromMarkItem(10, color=self._color) \
274
                                if not self.lineNoFromToIndicator else EngineeringToMarkItem(10, color=self._color)
275
                            _label.setZValue(500)
276
                            self.scene().addItem(_label)
277
                            _label.setPos(QPointF(item.origin[0], item.origin[1]))
278
                            self.lineNoFromToIndicator.append(_label)
279
                        elif self.lineNoFromToIndicator:
280
                            if item is _from:
281
                                self.lineNoFromToIndicator[0].setPos(QPointF(item.origin[0], item.origin[1]))
282
                                self.lineNoFromToIndicator[0].setVisible(True)
283
                            elif item is _to:
284
                                self.lineNoFromToIndicator[1].setPos(QPointF(item.origin[0], item.origin[1]))
285
                                self.lineNoFromToIndicator[1].setVisible(True)
286
        else:
287
            if self.lineNoFromToIndicator:
288
                for _label in self.lineNoFromToIndicator:
289
                    _label.setVisible(False)            
290

    
291
    def contextFrom(self):
292
        from App import App
293
        import SelectAttributeCommand
294
        _from = None
295
        for prop, value in self.properties.items():
296
            if prop.Attribute == 'From':
297
                _from = prop
298
                break
299
        cmd = SelectAttributeCommand.SelectAttributeCommand(self, _from, App.mainWnd().graphicsView)
300
        cmd.onSuccess.connect(App.mainWnd().resultPropertyTableWidget.onSuccessSelectAttribute)
301
        App.mainWnd().graphicsView.command = cmd
302

    
303
    def contextTo(self):
304
        from App import App
305
        import SelectAttributeCommand
306
        _to = None
307
        for prop, value in self.properties.items():
308
            if prop.Attribute == 'To':
309
                _to = prop
310
                break
311
        cmd = SelectAttributeCommand.SelectAttributeCommand(self, _to, App.mainWnd().graphicsView)
312
        cmd.onSuccess.connect(App.mainWnd().resultPropertyTableWidget.onSuccessSelectAttribute)
313
        App.mainWnd().graphicsView.command = cmd
314

    
315
    def contextHighlight(self, item):
316
        from App import App
317
        from HighlightCommand import HighlightCommand
318
        HighlightCommand(App.mainWnd().graphicsView).execute(item)
319

    
320
    def contextExplode(self):
321
        from App import App
322
        App.mainWnd().itemTreeWidget.explode_line_no_from_context(self)
323

    
324
    def contextExplodeKeep(self):
325
        from App import App
326
        App.mainWnd().itemTreeWidget.explode_line_no_from_context(self, True)
327

    
328
    def contextReverse(self):
329
        self.reverse()
330

    
331
    def contextDelete(self):
332
        event = QKeyEvent(QEvent.KeyPress, Qt.Key_Delete, Qt.NoModifier)
333
        self.scene().keyPressEvent(event)
334

    
335
    def contextEdit(self):
336
        event = QKeyEvent(QEvent.KeyPress, Qt.Key_Return, Qt.NoModifier)
337
        self.keyPressEvent(event)
338

    
339
    def contextRotate(self):
340
        event = QKeyEvent(QEvent.KeyPress, Qt.Key_R, Qt.NoModifier)
341
        self.keyPressEvent(event)
342

    
343
    def hoverLeaveEvent(self, event):
344
        """ unhighlight line no text and run's item """
345
        try:
346
            self.hover = False
347
            self.update()
348

    
349
            for run in self.runs:
350
                for item in run.items:
351
                    item.hoverLeaveEvent(event, True)
352

    
353
            if not self.lineNoFromToIndicatorShowFlag:
354
                if self.lineNoFromToIndicator:
355
                    for _label in self.lineNoFromToIndicator:
356
                        _label.setVisible(False)
357
        except Exception as ex:
358
            from App import App
359
            from AppDocData import MessageType
360

    
361
            message = 'error occurred({}) in {}:{}'.format(ex, sys.exc_info()[-1].tb_frame.f_code.co_filename,
362
                                                           sys.exc_info()[-1].tb_lineno)
363
            App.mainWnd().addMessage.emit(MessageType.Error, message)
364

    
365

    
366
    def keyPressEvent(self, event):
367
        """ reverse line routine when user press 'C' key """
368
        if event.key() == Qt.Key_C:
369
            self.reverse()
370
        elif event.key() == Qt.Key_S:
371
            self.contextFrom()
372
        elif event.key() == Qt.Key_D:
373
            self.contextTo()
374
        elif event.key() == Qt.Key_H:
375
            self.contextShow()
376
        elif event.key() == Qt.Key_A:
377
            self.contextSelectAll()
378

    
379
        QEngineeringTextItem.keyPressEvent(self, event)
380

    
381
    def update_flow_mark(self, position, minLength):
382
        """ update line flow mark """
383
        import math
384
        from EngineeringLineItem import QEngineeringLineItem
385

    
386
        allowed_error_radian = 0.09
387

    
388
        try:
389
            for run in self.runs:
390
                pre = None
391
                preRadian = None
392
                for item in run.items:
393
                    if pre is None and type(item) is QEngineeringLineItem and item.is_piping(True) and item.length() > minLength:
394
                        pre = item
395
                        start = item.line().p1()
396
                        end = item.line().p2()
397
                        _dir = [(end.x() - start.x()) / item.length(), (end.y() - start.y()) / item.length()]
398
                        radian = math.atan2(_dir[1], _dir[0]) - math.pi / 2
399
                        preRadian = radian if radian >= 0 else radian + 2 * math.pi
400
                        preRadian = abs(preRadian - math.pi)
401

    
402
                    elif pre and type(pre) is QEngineeringLineItem and type(item) is QEngineeringLineItem and item.is_piping(True):
403
                        start = item.line().p1()
404
                        end = item.line().p2()
405
                        _dir = [(end.x() - start.x()) / item.length(), (end.y() - start.y()) / item.length()]
406
                        radian = math.atan2(_dir[1], _dir[0]) - math.pi / 2
407
                        currRadian = radian if radian >= 0 else radian + 2 * math.pi
408
                        currRadian = abs(currRadian - math.pi)
409
                        if abs(currRadian - preRadian) > allowed_error_radian:
410
                            # insert flow mark at pre line
411
                            if pre.length() > minLength:
412
                                # if str(pre.uid) == '62edfbe5-29fd-49af-840b-6dce051e04d1':
413
                                # print(math.atan2(preDir[0], preDir[1]) - math.pi / 2)
414
                                # print(currRadian)
415
                                # print(preRadian)
416
                                pre.flowMark = position
417
                                pre.update_arrow()
418

    
419
                            pre = item
420
                            preRadian = currRadian
421

    
422
                if pre and type(item) is QEngineeringLineItem and item.is_piping(True) and item.length() > minLength:
423
                    pre.flowMark = position
424
                    pre.update_arrow()
425

    
426
        except Exception as ex:
427
            from App import App
428
            from AppDocData import MessageType
429

    
430
            message = 'error occurred({}) in {}:{}'.format(ex, sys.exc_info()[-1].tb_frame.f_code.co_filename,
431
                                                           sys.exc_info()[-1].tb_lineno)
432
            App.mainWnd().addMessage.emit(MessageType.Error, message)
433

    
434
    """
435
    def paint(self, painter, options=None, widget=None):
436
        QEngineeringTextItem.paint(self, painter, options, widget)
437
        if self.freeze_item is None:
438
            from EngineeringFreezeItem import QEngineeringFreezeItem
439

440
            self.freeze_item = QEngineeringFreezeItem(0, 0, QEngineeringFreezeItem.FREEZE_SIZE, QEngineeringFreezeItem.FREEZE_SIZE)
441
            self.freeze_item.setParentItem(self)
442
            self.freeze_item.setZValue(self.zValue() + 1)
443
            self.freeze_item.setPen(Qt.black)
444
    """
445

    
446
    def reverse(self):
447
        """ reverse line routine """
448

    
449
        if self.runs:
450
            self.runs[0].reverse()
451
            _from = self.prop('From')
452
            _to = self.prop('To')
453
            self.set_property('From', _to)
454
            self.set_property('To', _from)
455

    
456
    def getLongestTwoPoints(self, pts):
457
        import math
458
        res = [None, None]
459

    
460
        maxDistance = None
461
        for i in range(len(pts)):
462
            for j in range(i + 1, len(pts)):
463
                dx = pts[i][0] - pts[j][0]
464
                dy = pts[i][1] - pts[j][1]
465
                dist = math.sqrt(dx * dx + dy * dy)
466
                if (maxDistance is None) or (maxDistance < dist):
467
                    maxDistance = dist
468
                    res[0] = pts[i]
469
                    res[1] = pts[j]
470

    
471
        return res
472

    
473
    '''
474
        @brief      set attribute
475
        @author     humkyung
476
        @date       2018.07.20
477
    '''
478

    
479
    def set_attrib(self, attrib, value):
480
        matches = [attr for attr in self.attrs if attr.UID == attrib.UID]
481
        if len(matches) == 1:
482
            self.attrs[matches[0]] = value
483
        else:
484
            self.attrs[attrib] = value
485

    
486
    def removeSelfAttr(self, attributeName):
487
        pass
488

    
489
    '''
490
        @brief      get attribute
491
        @author     kyouho
492
        @date       2018.09.06
493
    '''
494
    def getLineNoAttributes(self, _attrs=None):
495
        from SymbolAttr import SymbolAttr
496
        from Configs import LineNoConfig
497
        import csv
498

    
499
        if _attrs is None:
500
            _attrs = {}
501

    
502
        try:
503
            docData = AppDocData.instance()
504

    
505
            line_no_configs = LineNoConfig.instance()
506
            config = None
507
            if line_no_configs:
508
                for line_no_config in line_no_configs:
509
                    item = line_no_config.parse(self.text())
510
                    if item[0]:
511
                        config = line_no_config
512
                        break
513
            else:
514
                item = (False,)
515

    
516
            if item[0]:
517
                # Line No 부분
518
                attr = SymbolAttr()
519
                attr.Attribute = 'LINE NO'
520
                attr.DisplayAttribute = 'Line No'
521
                attr.AttributeType = 'String'
522
                attr.IsProp = 5
523
                attr.Index = -1
524
                _attrs[attr] = self.text()
525

    
526
                result = item[1]
527
                configs = list(csv.reader([config.value], delimiter=self.delimiter, escapechar='^'))[0]
528
                props = docData.getLineProperties()
529
                for prop in props:
530
                    if prop.UID in configs:
531
                        for i in range(len(configs)):
532
                            if prop.UID == configs[i]:
533
                                _attrs[prop] = result[i]
534
                                break
535
                    else:
536
                        matches = [attr for attr in self.attrs if attr.UID == prop.UID]
537
                        if len(matches) == 1:
538
                            _attrs[matches[0]] = self.attrs[matches[0]]
539
                        # else:
540
                        #    _attrs[prop] = ''
541
        except Exception as ex:
542
            from App import App
543
            from AppDocData import MessageType
544

    
545
            message = 'error occurred({}) in {}:{}'.format(ex, sys.exc_info()[-1].tb_frame.f_code.co_filename,
546
                                                           sys.exc_info()[-1].tb_lineno)
547
            App.mainWnd().addMessage.emit(MessageType.Error, message)
548

    
549
        return _attrs
550

    
551
    @staticmethod
552
    def from_database(component):
553
        """ get line no item from database """
554
        import uuid
555
        from AppDocData import AppDocData
556
        from TextItemFactory import TextItemFactory
557
        from SymbolAttr import SymbolAttr
558

    
559
        item = None
560

    
561
        try:
562
            x = float(component['X'])
563
            y = float(component['Y'])
564
            width = float(component['Width']) if component['Width'] is not None else 0
565
            height = float(component['Height']) if component['Height'] is not None else 0
566
            angle = float(component['Rotation']) if component['Rotation'] is not None else 0
567
            text = component['Value']
568

    
569
            configs = AppDocData.instance().getConfigs('Data', 'Grid')
570
            grid = int(configs[0].value) if 1 == len(configs) else -1
571
            if grid == 1:
572
                x = round(x)
573
                y = round(y)
574
                width = round(width)
575
                height = round(height)
576
                
577
            textInfo = TextInfo(text, x, y, width, height, angle)
578
            connline = component['Connected'] if component['Connected'] is not None else None
579

    
580
            item = TextItemFactory.instance().createTextItem(textInfo)
581
            if item is not None:
582
                item.setVisible(False)
583
                for key in item._properties.keys():
584
                    if key.Attribute != 'Config':
585
                        item._properties[key] = key.parse_value(component[key.Attribute])
586

    
587
                app_doc_data = AppDocData.instance()
588

    
589
                # get associations 
590
                associations = app_doc_data.get_component_associations(component['UID'])
591
                if associations:
592
                    for assoc in associations:
593
                        _attrType = assoc['Type']
594
                        if not _attrType in item._associations:
595
                            item._associations[_attrType] = []
596
                        item._associations[_attrType].append(
597
                            uuid.UUID(assoc['Association']) if assoc['Association'] != 'None' else None)
598
                # up to here
599

    
600
                '''
601
                # get associations 
602
                associations = app_doc_data.get_component_associations(component['UID'])
603
                if associations:
604
                    for assoc in associations:
605
                        _attrType = assoc['Type']
606
                        if not _attrType in item._associations:
607
                            item._associations[_attrType] = []
608
                        item._associations[_attrType].append(
609
                            uuid.UUID(assoc['Association']) if assoc['Association'] != 'None' else None)
610
                # up to here
611
                '''
612

    
613
                attrs = app_doc_data.get_component_attributes(component['UID'])
614
                for _attr in attrs:
615
                    attr = SymbolAttr.from_record(_attr)
616
                    item.attrs[attr] = _attr['Value']
617

    
618
                item.uid = uuid.UUID(component['UID'])
619
                item.loc = [x, y]
620
                item.size = [width, height]
621
                item.angle = angle
622
                item.setToolTip('<b>{}</b><br>LINE NO={}'.format(str(item.uid), text))
623

    
624
                """ apply freeze value """
625
                # item.freeze_item.update_freeze(item.prop('Freeze'))
626

    
627
                if connline is not None:
628
                    item.conns.append(connline)
629
        except Exception as ex:
630
            from App import App
631
            from AppDocData import MessageType
632

    
633
            message = 'error occurred({}) in {}:{}'.format(ex, sys.exc_info()[-1].tb_frame.f_code.co_filename,
634
                                                           sys.exc_info()[-1].tb_lineno)
635
            App.mainWnd().addMessage.emit(MessageType.Error, message)
636
            return None
637

    
638
        return item
639

    
640
    @staticmethod
641
    def fromXml(node):
642
        """ generate EngineeringLineNoTextItem from xml node """
643
        import uuid
644
        from TextItemFactory import TextItemFactory
645
        from SymbolAttr import SymbolAttr
646

    
647
        item = None
648

    
649
        try:
650
            location = node.find('LOCATION').text if node.find('LOCATION') is not None else '0,0'
651
            x = float(location.split(',')[0])
652
            y = float(location.split(',')[1])
653
            width = float(node.find('WIDTH').text) if node.find('WIDTH') is not None else 0
654
            height = float(node.find('HEIGHT').text) if node.find('HEIGHT') is not None else 0
655
            angle = float(node.find('ANGLE').text) if node.find('ANGLE') is not None else 0
656
            text = node.find('TEXT').text
657

    
658
            configs = AppDocData.instance().getConfigs('Data', 'Grid')
659
            grid = int(configs[0].value) if 1 == len(configs) else -1
660
            if grid == 1:
661
                x = round(x)
662
                y = round(y)
663
                width = round(width)
664
                height = round(height)
665

    
666
            textInfo = TextInfo(text, x, y, width, height, angle)
667
            connline = node.find('CONNLINE').text if node.find('CONNLINE') is not None else None
668

    
669
            configs = AppDocData.instance().getConfigs('Data', 'Grid')
670
            grid = int(configs[0].value) if 1 == len(configs) else -1
671
            if grid == 1:
672
                x = round(x)
673
                y = round(y)
674
                width = round(width)
675
                height = round(height)
676

    
677
            matches = [prop_node for prop_node in node.iter('PROPERTY') if prop_node.attrib['Attribute'] == 'Config']
678
            if matches:
679
                item = TextItemFactory.instance().createTextItem(textInfo, matches[0].text)
680
            else:
681
                item = TextItemFactory.instance().createTextItem(textInfo)
682

    
683
            if item is not None:
684
                item.setVisible(False)
685
                for prop_node in node.iter('PROPERTY'):
686
                    matches = [prop for prop in item._properties.keys() if
687
                               prop.Attribute == prop_node.attrib['Attribute'] and prop.Attribute != 'Config']
688
                    if matches:
689
                        item._properties[matches[0]] = matches[0].parse_value(prop_node.text)
690

    
691
                for attr_node in node.iterfind('ATTRIBUTE'):
692
                    attr = SymbolAttr.fromXml(attr_node)
693
                    item.attrs[attr] = attr_node.text
694

    
695
                item.uid = uuid.UUID(node.find('UID').text)
696
                item.loc = [x, y]
697
                item.size = [width, height]
698
                item.angle = angle
699
                item.setToolTip('<b>{}</b><br>LINE NO={}'.format(str(item.uid), text))
700

    
701
                # get associations 
702
                attributeValue = node.find('ASSOCIATIONS')
703
                if attributeValue is not None:
704
                    for assoc in attributeValue.iter('ASSOCIATION'):
705
                        _attrType = assoc.attrib['TYPE']
706
                        if not _attrType in item._associations:
707
                            item._associations[_attrType] = []
708
                        item._associations[_attrType].append(uuid.UUID(assoc.text) if assoc.text != 'None' else None)
709
                # up to here
710

    
711
                """ apply freeze value """
712
                # item.freeze_item.update_freeze(item.prop('Freeze'))
713

    
714
                if connline is not None:
715
                    item.conns.append(connline)
716
        except Exception as ex:
717
            from App import App
718
            from AppDocData import MessageType
719

    
720
            message = 'error occurred({}) in {}:{}'.format(ex, sys.exc_info()[-1].tb_frame.f_code.co_filename,
721
                                                           sys.exc_info()[-1].tb_lineno)
722
            App.mainWnd().addMessage.emit(MessageType.Error, message)
723
            return None
724

    
725
        return item
726

    
727
    '''
728
        @brief      generate xml code
729
        @author     humkyung
730
        @date       2018.04.23
731
        @history    humkyung 2018.05.02 write symbol's attribute
732
                    humkyung 2018.05.16 write run information to xml
733
    '''
734

    
735
    def toXml(self):
736
        from xml.etree.ElementTree import Element, SubElement, dump, ElementTree
737
        from EngineeringLineItem import QEngineeringLineItem
738
        from SymbolSvgItem import SymbolSvgItem
739

    
740
        try:
741
            #docData = AppDocData.instance()
742
            #configs = docData.getConfigs('Line No', 'Delimiter')
743
            #delimiter = configs[0].value if 1 == len(configs) else '-'
744
            #lineNoconfigs = docData.getConfigs('Line No', 'Configuration')
745

    
746
            node = Element('LINE_NO')
747
            uidNode = Element('UID')
748
            uidNode.text = str(self.uid)
749
            node.append(uidNode)
750

    
751
            textNode = Element('TEXT')
752
            textNode.text = self.text()
753
            node.append(textNode)
754

    
755
            locNode = Element('LOCATION')
756
            locNode.text = '{},{}'.format(self.loc[0], self.loc[1])
757
            node.append(locNode)
758

    
759
            widthNode = Element('WIDTH')
760
            widthNode.text = str(self.size[0])
761
            node.append(widthNode)
762

    
763
            heightNode = Element('HEIGHT')
764
            heightNode.text = str(self.size[1])
765
            node.append(heightNode)
766

    
767
            angleNode = Element('ANGLE')
768
            angleNode.text = str(self.angle)
769
            node.append(angleNode)
770

    
771
            areaNode = Element('AREA')
772
            areaNode.text = self.area
773
            node.append(areaNode)
774

    
775
            for run in self.runs:
776
                if run and run.items:
777
                    node.append(run.toXml())
778
            
779
            attributeValueNode = Element('ASSOCIATIONS')
780
            for key, value in self._associations.items():
781
                for assoc in value:
782
                    assoc_node = Element('ASSOCIATION')
783
                    assoc_node.attrib['TYPE'] = str(key)
784
                    assoc_node.text = str(assoc)
785
                    attributeValueNode.append(assoc_node)
786
            node.append(attributeValueNode)
787

    
788
            properties_node = Element('PROPERTIES')
789
            for prop, value in self.properties.items():
790
                prop_node = prop.toXml()
791
                prop_node.text = str(value) if value else ''
792
                properties_node.append(prop_node)
793
            node.append(properties_node)
794

    
795
            _attrs = self.getAttributes()
796
            for key in _attrs.keys():
797
                if key.UID is not None:
798
                    attrNode = key.toXml()
799
                    attrNode.text = str(_attrs[key])
800
                    node.append(attrNode)
801

    
802
            if self.conns:
803
                connNode = Element('CONNLINE')
804
                connNode.text = str(self.conns[0].uid) if hasattr(self.conns[0], 'uid') else str(self.conns[0])
805
                node.append(connNode)
806

    
807
            sceneNode = Element('SCENE')
808
            sceneNode.text = str(self.sceneBoundingRect()).replace('PyQt5.QtCore.QRectF(', '').replace(' ', '').replace(
809
                ')', '') if self.scene() else '{},{},{},{}'.format(self.loc[0], self.loc[1], self.size[0], self.size[1])
810
            node.append(sceneNode)
811

    
812
        except Exception as ex:
813
            from App import App
814
            from AppDocData import MessageType
815

    
816
            message = 'error occurred({}) in {}:{}'.format(ex, sys.exc_info()[-1].tb_frame.f_code.co_filename,
817
                                                           sys.exc_info()[-1].tb_lineno)
818
            App.mainWnd().addMessage.emit(MessageType.Error, message)
819

    
820
            return None
821

    
822
        return node
823

    
824
    def to_svg(self, parent) -> list:
825
        """convert line no item to svg"""
826
        import re
827
        from xml.etree.ElementTree import Element, SubElement, dump, ElementTree
828
        from App import App
829

    
830
        res = []
831
        try:
832
            app_doc_data = AppDocData.instance()
833
            prj = app_doc_data.getCurrentProject()
834

    
835
            node = Element('g')
836
            node.attrib['id'] = str(self.uid)
837
            node.attrib['class'] = 'Pipe'
838
            node.attrib['data-tag-name'] = self.toPlainText()
839
            node.attrib['font-family'] = self.font().family()
840
            node.attrib['font-size'] = str(self.boundingRect().height())  # str(self.font().pointSizeF())
841
            node.attrib['font-weight'] = str(self.font().weight())
842

    
843
            except_pattern = re.compile('[^a-zA-Z0-9-_]')
844
            for attr, value in self.getAttributes().items():
845
                node.attrib[re.sub(except_pattern, '_', attr.Attribute)] = value if value else ''
846
            trans = self.sceneTransform()
847
            node.attrib['transform'] = f"matrix(" \
848
                                       f"{trans.m11()},{trans.m12()}," \
849
                                       f"{trans.m21()},{trans.m22()}," \
850
                                       f"{trans.m31()},{trans.m32()}" \
851
                                       f")"
852

    
853
            text = Element('text')
854
            text.text = self.toPlainText()
855
            text.attrib['textLength'] = str(self.boundingRect().width())
856
            text.attrib['lengthAdjust'] = 'spacingAndGlyphs'
857
            text.attrib['alignment-baseline'] = 'hanging'  # align left-top corner
858
            node.append(text)
859

    
860
            connected_line = self.connected_line
861
            if connected_line:
862
                conn_node = connected_line.to_svg(self)
863
                if conn_node:
864
                    node.extend(conn_node)
865

    
866
            res.append(node)
867
        except Exception as ex:
868
            from App import App
869
            from AppDocData import MessageType
870
            message = 'error occurred({}) in {}:{}'.format(ex, sys.exc_info()[-1].tb_frame.f_code.co_filename,
871
                                                           sys.exc_info()[-1].tb_lineno)
872
            App.mainWnd().addMessage.emit(MessageType.Error, message)
873

    
874
        return res
875

    
876
    def end_break(self):
877
        '''
878
            @brief  end break check
879
            @author euisung
880
            @date   2019.05.07
881
            @history    2019.05.19  euisung    can cover at both end that contact other line's middle
882
                        2019.05.19  euisung    no more used integrated with linetracer
883
        '''
884
        from EngineeringLineItem import QEngineeringLineItem
885
        from SymbolSvgItem import SymbolSvgItem
886
        from AppDocData import AppDocData
887
        end_breaks = []
888

    
889
        try:
890
            docdata = AppDocData.instance()
891

    
892
            line_from = self.prop('From')
893
            line_to = self.prop('To')
894

    
895
            end_break_names = docdata.getSymbolListByType('type', 'End Break')
896
            if len(end_break_names) is 0:
897
                return end_breaks
898

    
899
            svgFileName = end_break_names[0].sName
900
            symbol = AppDocData.instance().getSymbolByQuery('name', svgFileName)
901
            svgFilePath = os.path.join(AppDocData.instance().getCurrentProject().getSvgFilePath(), symbol.getType(),
902
                                       svgFileName + '.svg')
903

    
904
            for line_end in [line_from, line_to]:
905
                for connector in line_end.connectors:
906
                    if connector.connectedItem is not None and connector.connectedItem.owner is not self:
907
                        end_break = SymbolSvgItem.createItem(symbol.getType(), None, svgFilePath)
908
                        pt = [connector.center()[0] - float(symbol.getOriginalPoint().split(',')[0]),
909
                              connector.center()[1] - float(symbol.getOriginalPoint().split(',')[1])]
910
                        origin = [0, 0]
911
                        if 2 == len(symbol.getOriginalPoint().split(',')):
912
                            tokens = symbol.getOriginalPoint().split(',')
913
                            origin = [pt[0] + float(tokens[0]), pt[1] + float(tokens[1])]
914
                        end_break.buildItem(svgFileName, symbol.getType(), 5.7, pt,
915
                                            [end_break.boundingRect().width(), end_break.boundingRect().height()],
916
                                            origin, [], symbol.getBaseSymbol(), symbol.getAdditionalSymbol(),
917
                                            symbol.getHasInstrumentLabel())
918

    
919
                        end_break.set_property('Connected Item', connector.connectedItem)
920
                        end_break.setToolTip('owner : ' + str(line_end))
921
                        end_break.area = 'Drawing'
922
                        end_break.owner = line_end
923
                        end_breaks.append(end_break)
924
        except Exception as ex:
925
            from App import App
926
            from AppDocData import MessageType
927

    
928
            message = 'error occurred({}) in {}:{}'.format(ex, sys.exc_info()[-1].tb_frame.f_code.co_filename,
929
                                                           sys.exc_info()[-1].tb_lineno)
930
            App.mainWnd().addMessage.emit(MessageType.Error, message)
931

    
932
        return end_breaks
933

    
934
    '''
935
        @Override (QEngineeringTextItem)
936
        @brief  get connected items
937
        @author Jeongwoo
938
        @date   2018.05.15
939
    '''
940

    
941
    def getConnectedItems(self):
942
        visited = []
943

    
944
        try:
945
            for run in self.runs:
946
                visited.extend(run.items)
947
        except Exception as ex:
948
            from App import App
949
            from AppDocData import MessageType
950

    
951
            message = 'error occurred({}) in {}:{}'.format(ex, sys.exc_info()[-1].tb_frame.f_code.co_filename,
952
                                                           sys.exc_info()[-1].tb_lineno)
953
            App.mainWnd().addMessage.emit(MessageType.Error, message)
954

    
955
        return visited
956

    
957
    def explode(self, remainFromTo=False):
958
        """ explode line no """
959

    
960
        # if False == self.prop('Freeze'):
961
        try:
962
            for index in reversed(range(len(self.runs))):
963
                self.runs[index].explode()
964
        except Exception as ex:
965
            from App import App
966
            from AppDocData import MessageType
967

    
968
            message = 'error occurred({}) in {}:{}'.format(ex, sys.exc_info()[-1].tb_frame.f_code.co_filename,
969
                                                           sys.exc_info()[-1].tb_lineno) + ' Item UID : ' + str(self.uid)
970
            App.mainWnd().addMessage.emit(MessageType.Error, message)
971
        finally:
972
            self.runs.clear()
973
            if not remainFromTo:
974
                self.set_property('From', None)
975
                self.set_property('To', None)
976

    
977
            if hasattr(self, 'lineNoFromToIndicator') and self.lineNoFromToIndicator:
978
                self.lineNoFromToIndicatorShowFlag = False
979
                if self.scene():
980
                    self.lineNoFromToIndicator[0].setVisible(False)
981
                    if len(self.lineNoFromToIndicator) == 2:
982
                        self.lineNoFromToIndicator[1].setVisible(False)
983

    
984
    '''
985
        @brief      generate sql phrase to save to database(Notice: Line No's symbol is is 1)
986
        @author     humkyung
987
        @date       2018.08.14
988
    '''
989
    def toSql_return_separately(self):
990
        import uuid
991
        from EngineeringAbstractItem import QEngineeringAbstractItem
992

    
993
        res = []
994
        resLater = []
995

    
996
        app_doc_data = AppDocData.instance()
997
        cols = ['UID', 'Drawings_UID', 'Symbol_UID', 'X', 'Y', 'Width', 'Height', 'Rotation', 'Value', 'Connected',
998
                '[From]', '[To]']
999
        if type(self) is QEngineeringLineNoTextItem:
1000
            values = ['?', '?', "(select UID from Symbol where Name='Line NO' and SymbolType_UID=-1)", '?', '?', '?',
1001
                      '?', '?', '?', '?', '?', '?']
1002
        else:
1003
            values = ['?', '?', "(select UID from Symbol where Name='Trim Line NO' and SymbolType_UID=-1)", '?', '?',
1004
                      '?', '?', '?', '?', '?', '?', '?']
1005
        params = [(str(self.uid), str(app_doc_data.activeDrawing.UID), self.loc[0], self.loc[1], self.size[0],
1006
                   self.size[1], str(self.angle), \
1007
                   self.text(), str(self.conns[0]) if self.conns else None, str(self.prop('From')),
1008
                   str(self.prop('To')))]
1009
        sql = 'insert into Components({}) values({})'.format(','.join(cols), ','.join(values))
1010
        res.append((sql, tuple(params)))
1011

    
1012
        cols = ['UID', 'Components_UID', 'LineProperties_UID', 'Value']
1013
        values = ['?', '?', '?', '?']
1014
        params = []
1015
        attrs = self.getAttributes()
1016
        for key, value in attrs.items():
1017
            if key.Attribute == 'LINE NO':  # or key.IsProp != 5:
1018
                continue
1019
            params.append((str(uuid.uuid4()), str(self.uid), str(key.UID), str(value)))
1020
        sql = 'insert into LineNoAttributes({}) values({})'.format(','.join(cols), ','.join(values))
1021
        resLater.append((sql, tuple(params)))
1022

    
1023
        if self.associations():
1024
            cols = ['UID', '[Type]', 'Components_UID', 'Association']
1025
            values = ['?', '?', '?', '?']
1026
            params = []
1027
            for assoc in self.associations():
1028
                params.append(
1029
                    (str(uuid.uuid4()), QEngineeringAbstractItem.assoc_type(assoc), str(self.uid), str(assoc.uid)))
1030
            sql = 'insert into Associations({}) values({})'.format(','.join(cols), ','.join(values))
1031
            resLater.append((sql, tuple(params)))
1032

    
1033
        # insert line no's Attributes
1034
        cols = ['UID', 'Components_UID', 'SymbolAttribute_UID', 'Value', 'Association_UID', 'Freeze']
1035
        values = ['?', '?', '?', '?', '?', '?']
1036
        params = []
1037
        for key in attrs.keys():
1038
            if key.IsProp != 5:
1039
                params.append((str(uuid.uuid4()), str(self.uid), str(key.UID), str(attrs[key]), str(key.AssocItem),
1040
                               str(key.Freeze)))
1041
        sql = 'insert into Attributes({}) values({})'.format(','.join(cols), ','.join(values))
1042
        res.append((sql, tuple(params)))
1043

    
1044
        if self.associations():
1045
            cols = ['UID', '[Type]', 'Components_UID', 'Association']
1046
            values = ['?', '?', '?', '?']
1047
            params = []
1048
            for assoc in self.associations():
1049
                params.append(
1050
                    (str(uuid.uuid4()), QEngineeringAbstractItem.assoc_type(assoc), str(self.uid), str(assoc.uid)))
1051
            sql = 'insert into Associations({}) values({})'.format(','.join(cols), ','.join(values))
1052
            resLater.append((sql, tuple(params)))
1053

    
1054
        _index = 0
1055
        for run in self.runs:
1056
            if run and run.items:
1057
                resLater.extend(run.to_sql(_index, self))
1058
                _index += 1
1059

    
1060
        return res, resLater
1061

    
1062
    '''
1063
        @brief      return Line Data List
1064
        @author     kyouho
1065
        @date       2018.08.14
1066
    '''
1067

    
1068
    def getLineDataList(self):
1069
        dataList = []
1070
        try:
1071
            import uuid
1072
            global lineColumnList
1073

    
1074
            docData = AppDocData.instance()
1075
            attrs = self.getAttributes()
1076
            for index in range(len(lineColumnList)):
1077
                dataList.append('')
1078

    
1079
            dataList[20] = docData.imgName
1080

    
1081
            for key in attrs.keys():
1082
                if type(key) is not UserInputAttribute:
1083
                    lineProp = docData.getLinePropertiesByUID(key.UID)
1084
                    if lineProp:
1085
                        attrName = lineProp[0].Attribute.upper().replace(' ', '')
1086
                    else:
1087
                        attrName = key.Attribute.upper().replace(' ', '')
1088

    
1089
                    data = attrs[key]
1090
                    if attrName == 'NOMINALDIAMETER':
1091
                        dataList[1] = data
1092
                    elif attrName == 'FLUIDCODE':
1093
                        dataList[2] = data
1094
                        dataList[7] = data
1095
                    elif attrName == 'TAGSEQNO':
1096
                        pass
1097
                    elif attrName == 'INSULATIONPURPOSE':
1098
                        dataList[16] = data
1099
                    elif attrName == 'STREAMNO':
1100
                        pass
1101
                    elif attrName == 'LINENO' or attrName == 'LINE NO':
1102
                        dataList[3] = data
1103
                    elif attrName == 'PNIDNUMBER':
1104
                        pass
1105
                    elif attrName == 'PIPINGMATERIALSCLASS':
1106
                        dataList[4] = data
1107
                    elif attrName == '':
1108
                        pass
1109
                else:
1110
                    typeUID = key.Attribute
1111
                    value = key.text
1112
                    lineAttr = docData.getLinePropertiesByUID(key.UD)
1113

    
1114
                    for index in range(len(lineColumnList)):
1115
                        if lineColumnList[index] == lineAttr[0].Attribute:
1116
                            dataList[index] = value
1117
        except Exception as ex:
1118
            from App import App
1119
            from AppDocData import MessageType
1120

    
1121
            message = 'error occurred({}) in {}:{}'.format(ex, sys.exc_info()[-1].tb_frame.f_code.co_filename,
1122
                                                           sys.exc_info()[-1].tb_lineno)
1123
            App.mainWnd().addMessage.emit(MessageType.Error, message)
1124

    
1125
        if dataList[0] == '':
1126
            dataList[0] = str(uuid.uuid4())
1127

    
1128
        return dataList
1129

    
1130
    def EvaluatedEQ(self):
1131
        ''' evaluate line no's From / To equipment '''
1132

    
1133
        from EngineeringNozzleItem import QEngineeringNozzleItem
1134
        from EngineeringVendorItem import QEngineeringVendorItem
1135
        from EngineeringEquipmentItem import QEngineeringEquipmentItem
1136
        from EngineeringLineItem import QEngineeringLineItem
1137

    
1138
        pool = []
1139
        visited = []
1140
        if self.runs and self.runs[0]:
1141
            pool.append(self)
1142
            _attrs = self.getAttributes()
1143

    
1144
        from_found = False
1145
        to_found = False
1146

    
1147
        
1148
        try:
1149
            while pool:
1150
                lineNo = pool.pop()
1151
                if lineNo not in visited:
1152
                    visited.append(lineNo)
1153
                else:
1154
                    continue
1155

    
1156
                if lineNo.runs and lineNo.runs[0]:
1157
                    items = lineNo.runs[0].items
1158
                    if len(items) > 2:
1159
                        if type(items[0]) is QEngineeringNozzleItem and not from_found:
1160
                            for connector in items[0].connectors:
1161
                                # From
1162
                                if (type(connector.connectedItem) is QEngineeringVendorItem or type(
1163
                                        connector.connectedItem) is QEngineeringEquipmentItem) and \
1164
                                        connector.connectedItem not in items:
1165
                                    for _attr in _attrs:
1166
                                        if _attr.Attribute == 'From_eq' and self.add_assoc_item(connector.connectedItem,
1167
                                                                                                at=_attr.AttrAt):
1168
                                            _attr.AssocItem = connector.connectedItem
1169
                                            from_found = True
1170
                                            break
1171
                                    break
1172
                        elif not from_found:
1173
                            if type(items[0]) is QEngineeringLineItem and items[0].connectors[0].connectedItem and items[0].connectors[0].connectedItem.owner:
1174
                                pool.append(items[0].connectors[0].connectedItem.owner)
1175
                            else:
1176
                                next_items = [connector.connectedItem for connector in items[0].connectors if connector.connectedItem and \
1177
                                        connector.connectedItem is not items[1] and items[0].next_connected(items[1], connector.connectedItem)]
1178
                                if next_items and next_items[0].owner:
1179
                                    pool.append(next_items[0].owner)
1180

    
1181
                        if type(items[-1]) is QEngineeringNozzleItem and not to_found:
1182
                            for connector in items[-1].connectors:
1183
                                # To
1184
                                if (type(connector.connectedItem) is QEngineeringVendorItem or type(
1185
                                        connector.connectedItem) is QEngineeringEquipmentItem) and \
1186
                                        connector.connectedItem not in items:
1187
                                    for _attr in _attrs:
1188
                                        if _attr.Attribute == 'To_eq' and self.add_assoc_item(connector.connectedItem,
1189
                                                                                            at=_attr.AttrAt):
1190
                                            _attr.AssocItem = connector.connectedItem
1191
                                            to_found = True
1192
                                            break
1193
                                    break
1194
                        elif not to_found:
1195
                            if type(items[-1]) is QEngineeringLineItem and items[-1].connectors[1].connectedItem and items[-1].connectors[1].connectedItem.owner:
1196
                                pool.append(items[-1].connectors[1].connectedItem.owner)
1197
                            else:
1198
                                next_items = [connector.connectedItem for connector in items[-1].connectors if connector.connectedItem and \
1199
                                        connector.connectedItem is not items[-2] and items[-1].next_connected(items[-2], connector.connectedItem)]
1200
                                if next_items and next_items[0].owner:
1201
                                    pool.append(next_items[0].owner)
1202
        except Exception as ex:
1203
            from App import App
1204
            from AppDocData import MessageType
1205

    
1206
            message = 'error occurred({}) in {}:{}'.format(ex, sys.exc_info()[-1].tb_frame.f_code.co_filename,
1207
                                                           sys.exc_info()[-1].tb_lineno)
1208
            App.mainWnd().addMessage.emit(MessageType.Error, message)
1209

    
1210
    def sort_order_text(self):
1211
        """ return true if line no same"""
1212

    
1213
        app_doc_data = AppDocData.instance()
1214
        
1215
        configs = app_doc_data.getConfigs('Sort', 'LineNoKeys')
1216
        targets = configs[0].value.split(',') if configs else []
1217

    
1218
        if targets:
1219
            attrs = self.getAttributes(True)
1220
            matches = []
1221

    
1222
            for key in targets:
1223
                _matches = [_key for _key in list(attrs.keys()) if str(_key.UID) == key]
1224
                if _matches:
1225
                    matches.append(attrs[_matches[0]])
1226
        else:
1227
            matches = [self.text()]
1228

    
1229
        return '_'.join(matches)
1230
    
1231
    def validate(self):
1232
        """ validation check """
1233

    
1234
        from SymbolSvgItem import SymbolSvgItem
1235
        from AppDocData import AppDocData
1236
        from EngineeringReducerItem import QEngineeringReducerItem
1237
        from EngineeringLineItem import QEngineeringLineItem
1238
        from EngineeringAbstractItem import QEngineeringAbstractItem
1239

    
1240
        errors = []
1241

    
1242
        try:
1243
            _translate = QCoreApplication.translate
1244

    
1245
            docdata = AppDocData.instance()
1246
            dataPath = docdata.getErrorItemSvgPath()
1247

    
1248
            lineNoError = False
1249

    
1250
            _error = super().validate()
1251
            errors.extend(_error)
1252

    
1253
            _from = self.prop('From')
1254
            _to = self.prop('To')
1255

    
1256
            if not _from or not _to:
1257
                lineNoError = True
1258
            elif self.runs:
1259
                if self.runs[0].items[0] is not _from:
1260
                    lineNoError = True
1261
                elif self.runs[0].items[-1] is not _to:
1262
                    lineNoError = True
1263
            else:
1264
                return errors
1265

    
1266
            size_errors = []
1267
            branch_errors = []
1268
            for run in self.runs:
1269
                sizes = []
1270
                for item in run.items:
1271
                    item_size = None
1272
                    attrs = item.getAttributes()
1273
                    for prop, value in attrs.items():
1274
                        if prop.Attribute.upper() == 'Size'.upper() or prop.Attribute.upper() == 'NominalDiameter'.upper():
1275
                            if value and value != 'None':
1276
                                item_size = value
1277
                                if type(item) is QEngineeringReducerItem or (issubclass(type(item), SymbolSvgItem) and item.iType == 22): # Relief Valve
1278
                                    sizes.append([item, item.mainSubSize[0], item.mainSubSize[1]])
1279
                                    break
1280
                                else:
1281
                                    sizes.append([item, value, value])
1282
                                    break
1283

    
1284
                    if item_size and type(item) is QEngineeringLineItem:
1285
                        for conn in item.connectors:
1286
                            if conn.connectedItem and type(conn.connectedItem) is QEngineeringLineItem and \
1287
                                conn._connected_at == QEngineeringAbstractItem.CONNECTED_AT_BODY:
1288
                                _item_size = None
1289
                                attrs = conn.connectedItem.getAttributes()
1290
                                for prop, value in attrs.items():
1291
                                    if prop.Attribute.upper() == 'Size'.upper() or prop.Attribute.upper() == 'NominalDiameter'.upper():
1292
                                        if value and value != 'None':
1293
                                            _item_size = value
1294
                                            break
1295
                            
1296
                                if _item_size and self.inch_to_number(item_size) > self.inch_to_number(_item_size):
1297
                                    branch_errors.append(item)
1298
                                    branch_errors.append(conn.connectedItem)
1299

    
1300
                if len(sizes) > 1:
1301
                    for index in range(len(sizes) - 1):
1302
                        if sizes[index][2] != sizes[index + 1][1] and \
1303
                            type(sizes[index][0]) is not QEngineeringReducerItem and type(sizes[index + 1][0]) is not QEngineeringReducerItem \
1304
                            and (hasattr(sizes[index][0], 'iType') and sizes[index][0].iType != 22) and \
1305
                            (hasattr(sizes[index + 1][0], 'iType') and sizes[index + 1][0].iType != 22):
1306
                                size_errors.append(sizes[index][0])
1307
                                size_errors.append(sizes[index + 1][0])
1308
                        elif sizes[index][1] not in sizes[index + 1] and sizes[index][2] not in sizes[index + 1]:
1309
                                size_errors.append(sizes[index][0])
1310
                                size_errors.append(sizes[index + 1][0])
1311

    
1312
            for size in size_errors:
1313
                error = SymbolSvgItem.createItem('Error', None, dataPath)
1314
                error.setPosition([size.sceneBoundingRect().center().x(), size.sceneBoundingRect().center().y()])
1315
                error.parent = size
1316
                error.msg = _translate('Size change error', 'Size change error')
1317
                error.setToolTip(error.msg)
1318
                error.area = 'Drawing'
1319
                error.name = 'Error'
1320
                errors.append(error)
1321

    
1322
            for size in branch_errors:
1323
                error = SymbolSvgItem.createItem('Error', None, dataPath)
1324
                error.setPosition([size.sceneBoundingRect().center().x(), size.sceneBoundingRect().center().y()])
1325
                error.parent = size
1326
                error.msg = _translate('Branch Size error', 'Branch Size error')
1327
                error.setToolTip(error.msg)
1328
                error.area = 'Drawing'
1329
                error.name = 'Error'
1330
                errors.append(error)
1331

    
1332
            if self.runs and self.runs[0].items:
1333
                _size = self.Size
1334
                found = False
1335
                if _size:
1336
                    for item in self.runs[0].items:
1337
                        if type(item) is QEngineeringReducerItem or (issubclass(type(item), SymbolSvgItem) and item.iType == 22):
1338
                            continue
1339
                        _size2 = item.Size
1340
                        if _size2 and _size2 != 'None' and _size2 != _size:
1341
                            found = True
1342
                            break
1343

    
1344
                        #attrs = item.getAttributes()
1345
                        #for prop, value in attrs.items():
1346
                        #    if prop.Attribute.upper() == 'Size'.upper() or prop.Attribute.upper() == 'NominalDiameter'.upper():
1347
                        #        if value and value != 'None' and _size != value:
1348
                        #            found = True
1349
                        #            break
1350
                        
1351
                        if found:
1352
                            break
1353
                
1354
                if found:
1355
                    error = SymbolSvgItem.createItem('Error', None, dataPath)
1356
                    error.setPosition([self.sceneBoundingRect().center().x(), self.sceneBoundingRect().center().y()])
1357
                    error.parent = self
1358
                    error.msg = _translate('Main run size warning', 'Main run size warning')
1359
                    error.setToolTip(error.msg)
1360
                    error.area = 'Drawing'
1361
                    error.name = 'Warning'
1362
                    errors.append(error)
1363

    
1364
            if lineNoError:
1365
                error = SymbolSvgItem.createItem('Error', None, dataPath)
1366
                error.setPosition([self.sceneBoundingRect().center().x(), self.sceneBoundingRect().center().y()])
1367
                error.parent = self
1368
                error.msg = _translate('From/ To error', 'From/ To error')
1369
                error.setToolTip(error.msg)
1370
                error.area = 'Drawing'
1371
                error.name = 'Error'
1372
                errors.append(error)
1373

    
1374
        except Exception as ex:
1375
            from App import App
1376
            from AppDocData import MessageType
1377

    
1378
            message = 'error occurred({}) in {}:{}'.format(ex, sys.exc_info()[-1].tb_frame.f_code.co_filename,
1379
                                                           sys.exc_info()[-1].tb_lineno)
1380
            App.mainWnd().addMessage.emit(MessageType.Error, message)
1381

    
1382
        return errors
클립보드 이미지 추가 (최대 크기: 500 MB)