프로젝트

일반

사용자정보

통계
| 개정판:

hytos / DTI_PID / DTI_PID / Shapes / EngineeringLineNoTextItem.py @ 40606a5d

이력 | 보기 | 이력해설 | 다운로드 (61.8 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
        menu = QMenu()
173
        if len(items) == 1 and self in items:
174
            '''
175
            explodeAction = QAction('Explode', None)
176
            explodeAction.triggered.connect(self.contextExplode)
177
            menu.addAction(explodeAction)
178

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

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

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

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

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

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

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

    
208
            searchAction = QAction('Search All Duplicate Line No', None)
209
            searchAction.triggered.connect(self.contextSearch)
210
            menu.addAction(searchAction)
211

    
212
            highlightAction = QAction('Highlight', None)
213
            highlightAction.triggered.connect(lambda: self.contextHighlight(self))
214
            menu.addAction(highlightAction)
215

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

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

    
226
            editAction = QAction('Edit(Return)', None)
227
            editAction.triggered.connect(self.contextEdit)
228
            menu.addAction(editAction)
229

    
230
            rotateAction = QAction('Rotate(R)', None)
231
            rotateAction.triggered.connect(self.contextRotate)
232
            menu.addAction(rotateAction)
233

    
234
            deleteAction = QAction('Delete(E)', None)
235
            deleteAction.triggered.connect(self.contextDelete)
236
            menu.addAction(deleteAction)
237
        else:
238
            alignAction = QAction('Resize Selected Texts with This ', None)
239
            alignAction.triggered.connect(self.contextResizeText)
240
            menu.addAction(alignAction)
241

    
242
        menu.exec_(event.screenPos())
243

    
244
    def contextResizeText(self):
245
        textItems = [item for item in self.scene().selectedItems() if item is not self and type(item) is QEngineeringLineNoTextItem]
246
        allowed_error = 0.01
247

    
248
        for text in textItems:
249
            if abs(self.angle - text.angle) < allowed_error:
250
                dx = round(self.size[0] - text.size[0])
251
                dy = round(self.size[1] - text.size[1])
252
            else:
253
                dx = round(self.size[1] - text.size[0])
254
                dy = round(self.size[0] - text.size[1])
255

    
256
            text.size[1] = text.size[1] + dy
257
            if abs(text.angle - 1.57) < allowed_error or abs(text.angle - 3.14) < allowed_error:
258
                text.loc[1] = text.loc[1] - dy
259

    
260
            text.size[0] = text.size[0] + dx
261
            if abs(text.angle - 4.71) < allowed_error or abs(text.angle - 4.71) < allowed_error or abs(text.angle - 3.14) < allowed_error:
262
                text.loc[0] = text.loc[0] - dx
263

    
264
            text.update_font()
265
            text.update()
266

    
267
    def contextSearch(self):
268
        from App import App
269
        from TextItemEditDialog import QTextItemEditDialog
270

    
271
        dlgTextItemEdit = QTextItemEditDialog(App.mainWnd(), 'Line No')
272
        dlgTextItemEdit.show()
273
        dlgTextItemEdit.exec_()
274

    
275
    def contextSelectAll(self):
276
        from App import App
277
        
278
        rect = App.mainWnd().graphicsView.viewport().rect()
279
        view_rect = App.mainWnd().graphicsView.mapToScene(rect).boundingRect()
280
        lineNos = [item for item in self.scene().items() if type(item) is QEngineeringLineNoTextItem and view_rect.contains(item.sceneBoundingRect().center())]
281
        for lineNo in lineNos:
282
            lineNo.setSelected(True)
283

    
284
    def contextShow(self):
285
        self.lineNoFromToIndicatorShowFlag = not self.lineNoFromToIndicatorShowFlag
286
        if self.lineNoFromToIndicatorShowFlag:
287
            if self.runs and self.runs[0].items:
288
                for item in [self.runs[0].items[0], self.runs[0].items[-1]]:
289
                    # display from / to indicator
290
                    if not self.lineNoFromToIndicator or len(self.lineNoFromToIndicator) < 2:
291
                        _label = EngineeringFromMarkItem(10, color=self._color) \
292
                            if not self.lineNoFromToIndicator else EngineeringToMarkItem(10, color=self._color)
293
                        _label.setZValue(500)
294
                        self.scene().addItem(_label)
295
                        _label.setPos(QPointF(item.origin[0], item.origin[1]))
296
                        self.lineNoFromToIndicator.append(_label)
297
                    elif self.lineNoFromToIndicator:
298
                        if item is self.runs[0].items[0]:
299
                            self.lineNoFromToIndicator[0].setPos(QPointF(item.origin[0], item.origin[1]))
300
                            self.lineNoFromToIndicator[0].setVisible(True)
301
                        elif item is self.runs[0].items[-1]:
302
                            self.lineNoFromToIndicator[1].setPos(QPointF(item.origin[0], item.origin[1]))
303
                            self.lineNoFromToIndicator[1].setVisible(True)
304
            elif not self.runs:
305
                _from = self.prop('From')
306
                _to = self.prop('To')
307
                if _from and _to:
308
                    for item in [_from, _to]:
309
                    # display from / to indicator
310
                        if not self.lineNoFromToIndicator or len(self.lineNoFromToIndicator) < 2:
311
                            _label = EngineeringFromMarkItem(10, color=self._color) \
312
                                if not self.lineNoFromToIndicator else EngineeringToMarkItem(10, color=self._color)
313
                            _label.setZValue(500)
314
                            self.scene().addItem(_label)
315
                            _label.setPos(QPointF(item.origin[0], item.origin[1]))
316
                            self.lineNoFromToIndicator.append(_label)
317
                        elif self.lineNoFromToIndicator:
318
                            if item is _from:
319
                                self.lineNoFromToIndicator[0].setPos(QPointF(item.origin[0], item.origin[1]))
320
                                self.lineNoFromToIndicator[0].setVisible(True)
321
                            elif item is _to:
322
                                self.lineNoFromToIndicator[1].setPos(QPointF(item.origin[0], item.origin[1]))
323
                                self.lineNoFromToIndicator[1].setVisible(True)
324
        else:
325
            if self.lineNoFromToIndicator:
326
                for _label in self.lineNoFromToIndicator:
327
                    _label.setVisible(False)            
328

    
329
    def contextFrom(self):
330
        from App import App
331
        import SelectAttributeCommand
332
        _from = None
333
        for prop, value in self.properties.items():
334
            if prop.Attribute == 'From':
335
                _from = prop
336
                break
337
        cmd = SelectAttributeCommand.SelectAttributeCommand(self, _from, App.mainWnd().graphicsView)
338
        cmd.onSuccess.connect(App.mainWnd().resultPropertyTableWidget.onSuccessSelectAttribute)
339
        App.mainWnd().graphicsView.command = cmd
340

    
341
    def contextTo(self):
342
        from App import App
343
        import SelectAttributeCommand
344
        _to = None
345
        for prop, value in self.properties.items():
346
            if prop.Attribute == 'To':
347
                _to = prop
348
                break
349
        cmd = SelectAttributeCommand.SelectAttributeCommand(self, _to, App.mainWnd().graphicsView)
350
        cmd.onSuccess.connect(App.mainWnd().resultPropertyTableWidget.onSuccessSelectAttribute)
351
        App.mainWnd().graphicsView.command = cmd
352

    
353
    def contextHighlight(self, item):
354
        from App import App
355
        from HighlightCommand import HighlightCommand
356
        HighlightCommand(App.mainWnd().graphicsView).execute(item)
357

    
358
    def contextExplode(self):
359
        from App import App
360
        App.mainWnd().itemTreeWidget.explode_line_no_from_context(self)
361

    
362
    def contextExplodeKeep(self):
363
        from App import App
364
        App.mainWnd().itemTreeWidget.explode_line_no_from_context(self, True)
365

    
366
    def contextReverse(self):
367
        self.reverse()
368

    
369
    def contextDelete(self):
370
        event = QKeyEvent(QEvent.KeyPress, Qt.Key_Delete, Qt.NoModifier)
371
        self.scene().keyPressEvent(event)
372

    
373
    def contextEdit(self):
374
        event = QKeyEvent(QEvent.KeyPress, Qt.Key_Return, Qt.NoModifier)
375
        self.keyPressEvent(event)
376

    
377
    def contextRotate(self):
378
        event = QKeyEvent(QEvent.KeyPress, Qt.Key_R, Qt.NoModifier)
379
        self.keyPressEvent(event)
380

    
381
    def hoverLeaveEvent(self, event):
382
        """ unhighlight line no text and run's item """
383
        try:
384
            self.hover = False
385
            self.update()
386

    
387
            for run in self.runs:
388
                for item in run.items:
389
                    item.hoverLeaveEvent(event, True)
390

    
391
            if not self.lineNoFromToIndicatorShowFlag:
392
                if self.lineNoFromToIndicator:
393
                    for _label in self.lineNoFromToIndicator:
394
                        _label.setVisible(False)
395
        except Exception as ex:
396
            from App import App
397
            from AppDocData import MessageType
398

    
399
            message = 'error occurred({}) in {}:{}'.format(ex, sys.exc_info()[-1].tb_frame.f_code.co_filename,
400
                                                           sys.exc_info()[-1].tb_lineno)
401
            App.mainWnd().addMessage.emit(MessageType.Error, message)
402

    
403

    
404
    def keyPressEvent(self, event):
405
        """ reverse line routine when user press 'C' key """
406
        if event.key() == Qt.Key_C:
407
            self.reverse()
408
        elif event.key() == Qt.Key_S:
409
            self.contextFrom()
410
        elif event.key() == Qt.Key_D:
411
            self.contextTo()
412
        elif event.key() == Qt.Key_H:
413
            self.contextShow()
414
        elif event.key() == Qt.Key_A:
415
            self.contextSelectAll()
416

    
417
        QEngineeringTextItem.keyPressEvent(self, event)
418

    
419
    def update_flow_mark(self, position, minLength):
420
        """ update line flow mark """
421
        import math
422
        from EngineeringLineItem import QEngineeringLineItem
423

    
424
        allowed_error_radian = 0.09
425

    
426
        try:
427
            for run in self.runs:
428
                pre = None
429
                preRadian = None
430
                for item in run.items:
431
                    if pre is None and type(item) is QEngineeringLineItem and item.is_piping(True) and item.length() > minLength:
432
                        pre = item
433
                        start = item.line().p1()
434
                        end = item.line().p2()
435
                        _dir = [(end.x() - start.x()) / item.length(), (end.y() - start.y()) / item.length()]
436
                        radian = math.atan2(_dir[1], _dir[0]) - math.pi / 2
437
                        preRadian = radian if radian >= 0 else radian + 2 * math.pi
438
                        preRadian = abs(preRadian - math.pi)
439

    
440
                    elif pre and type(pre) is QEngineeringLineItem and type(item) is QEngineeringLineItem and item.is_piping(True):
441
                        start = item.line().p1()
442
                        end = item.line().p2()
443
                        _dir = [(end.x() - start.x()) / item.length(), (end.y() - start.y()) / item.length()]
444
                        radian = math.atan2(_dir[1], _dir[0]) - math.pi / 2
445
                        currRadian = radian if radian >= 0 else radian + 2 * math.pi
446
                        currRadian = abs(currRadian - math.pi)
447
                        if abs(currRadian - preRadian) > allowed_error_radian:
448
                            # insert flow mark at pre line
449
                            if pre.length() > minLength:
450
                                # if str(pre.uid) == '62edfbe5-29fd-49af-840b-6dce051e04d1':
451
                                # print(math.atan2(preDir[0], preDir[1]) - math.pi / 2)
452
                                # print(currRadian)
453
                                # print(preRadian)
454
                                pre.flowMark = position
455
                                pre.update_arrow()
456

    
457
                            pre = item
458
                            preRadian = currRadian
459

    
460
                if pre and type(item) is QEngineeringLineItem and item.is_piping(True) and item.length() > minLength:
461
                    pre.flowMark = position
462
                    pre.update_arrow()
463

    
464
        except Exception as ex:
465
            from App import App
466
            from AppDocData import MessageType
467

    
468
            message = 'error occurred({}) in {}:{}'.format(ex, sys.exc_info()[-1].tb_frame.f_code.co_filename,
469
                                                           sys.exc_info()[-1].tb_lineno)
470
            App.mainWnd().addMessage.emit(MessageType.Error, message)
471

    
472
    """
473
    def paint(self, painter, options=None, widget=None):
474
        QEngineeringTextItem.paint(self, painter, options, widget)
475
        if self.freeze_item is None:
476
            from EngineeringFreezeItem import QEngineeringFreezeItem
477

478
            self.freeze_item = QEngineeringFreezeItem(0, 0, QEngineeringFreezeItem.FREEZE_SIZE, QEngineeringFreezeItem.FREEZE_SIZE)
479
            self.freeze_item.setParentItem(self)
480
            self.freeze_item.setZValue(self.zValue() + 1)
481
            self.freeze_item.setPen(Qt.black)
482
    """
483

    
484
    def reverse(self):
485
        """ reverse line routine """
486

    
487
        if self.runs:
488
            self.runs[0].reverse()
489
            _from = self.prop('From')
490
            _to = self.prop('To')
491
            self.set_property('From', _to)
492
            self.set_property('To', _from)
493

    
494
    def getLongestTwoPoints(self, pts):
495
        import math
496
        res = [None, None]
497

    
498
        maxDistance = None
499
        for i in range(len(pts)):
500
            for j in range(i + 1, len(pts)):
501
                dx = pts[i][0] - pts[j][0]
502
                dy = pts[i][1] - pts[j][1]
503
                dist = math.sqrt(dx * dx + dy * dy)
504
                if (maxDistance is None) or (maxDistance < dist):
505
                    maxDistance = dist
506
                    res[0] = pts[i]
507
                    res[1] = pts[j]
508

    
509
        return res
510

    
511
    '''
512
        @brief      set attribute
513
        @author     humkyung
514
        @date       2018.07.20
515
    '''
516

    
517
    def set_attrib(self, attrib, value):
518
        matches = [attr for attr in self.attrs if attr.UID == attrib.UID]
519
        if len(matches) == 1:
520
            self.attrs[matches[0]] = value
521
        else:
522
            self.attrs[attrib] = value
523

    
524
    def removeSelfAttr(self, attributeName):
525
        pass
526

    
527
    '''
528
        @brief      get attribute
529
        @author     kyouho
530
        @date       2018.09.06
531
    '''
532
    def getLineNoAttributes(self, _attrs=None):
533
        from SymbolAttr import SymbolAttr
534
        from Configs import LineNoConfig
535
        import csv
536

    
537
        if _attrs is None:
538
            _attrs = {}
539

    
540
        try:
541
            docData = AppDocData.instance()
542

    
543
            line_no_configs = LineNoConfig.instance()
544
            config = None
545
            if line_no_configs:
546
                for line_no_config in line_no_configs:
547
                    item = line_no_config.parse(self.text())
548
                    if item[0]:
549
                        config = line_no_config
550
                        break
551
            else:
552
                item = (False,)
553

    
554
            if item[0]:
555
                # Line No 부분
556
                attr = SymbolAttr()
557
                attr.Attribute = 'LINE NO'
558
                attr.DisplayAttribute = 'Line No'
559
                attr.AttributeType = 'String'
560
                attr.IsProp = 5
561
                attr.Index = -1
562
                _attrs[attr] = self.text()
563

    
564
                result = item[1]
565
                configs = list(csv.reader([config.value], delimiter=self.delimiter, escapechar='^'))[0]
566
                props = docData.getLineProperties()
567
                for prop in props:
568
                    if prop.UID in configs:
569
                        for i in range(len(configs)):
570
                            if prop.UID == configs[i]:
571
                                _attrs[prop] = result[i]
572
                                break
573
                    else:
574
                        matches = [attr for attr in self.attrs if attr.UID == prop.UID]
575
                        if len(matches) == 1:
576
                            _attrs[matches[0]] = self.attrs[matches[0]]
577
                        # else:
578
                        #    _attrs[prop] = ''
579
        except Exception as ex:
580
            from App import App
581
            from AppDocData import MessageType
582

    
583
            message = 'error occurred({}) in {}:{}'.format(ex, sys.exc_info()[-1].tb_frame.f_code.co_filename,
584
                                                           sys.exc_info()[-1].tb_lineno)
585
            App.mainWnd().addMessage.emit(MessageType.Error, message)
586

    
587
        return _attrs
588

    
589
    @staticmethod
590
    def from_database(component):
591
        """ get line no item from database """
592
        import uuid
593
        from AppDocData import AppDocData
594
        from TextItemFactory import TextItemFactory
595
        from SymbolAttr import SymbolAttr
596

    
597
        item = None
598

    
599
        try:
600
            x = float(component['X'])
601
            y = float(component['Y'])
602
            width = float(component['Width']) if component['Width'] is not None else 0
603
            height = float(component['Height']) if component['Height'] is not None else 0
604
            angle = float(component['Rotation']) if component['Rotation'] is not None else 0
605
            text = component['Value']
606

    
607
            configs = AppDocData.instance().getConfigs('Data', 'Grid')
608
            grid = int(configs[0].value) if 1 == len(configs) else -1
609
            if grid == 1:
610
                x = round(x)
611
                y = round(y)
612
                width = round(width)
613
                height = round(height)
614
                
615
            textInfo = TextInfo(text, x, y, width, height, angle)
616
            connline = component['Connected'] if component['Connected'] is not None else None
617

    
618
            item = TextItemFactory.instance().createTextItem(textInfo)
619
            if item is not None:
620
                item.setVisible(False)
621
                for key in item._properties.keys():
622
                    if key.Attribute != 'Config':
623
                        item._properties[key] = key.parse_value(component[key.Attribute])
624

    
625
                app_doc_data = AppDocData.instance()
626

    
627
                # get associations 
628
                associations = app_doc_data.get_component_associations(component['UID'])
629
                if associations:
630
                    for assoc in associations:
631
                        _attrType = assoc['Type']
632
                        if not _attrType in item._associations:
633
                            item._associations[_attrType] = []
634
                        item._associations[_attrType].append(
635
                            uuid.UUID(assoc['Association']) if assoc['Association'] != 'None' else None)
636
                # up to here
637

    
638
                '''
639
                # get associations 
640
                associations = app_doc_data.get_component_associations(component['UID'])
641
                if associations:
642
                    for assoc in associations:
643
                        _attrType = assoc['Type']
644
                        if not _attrType in item._associations:
645
                            item._associations[_attrType] = []
646
                        item._associations[_attrType].append(
647
                            uuid.UUID(assoc['Association']) if assoc['Association'] != 'None' else None)
648
                # up to here
649
                '''
650

    
651
                attrs = app_doc_data.get_component_attributes(component['UID'])
652
                for _attr in attrs:
653
                    attr = SymbolAttr.from_record(_attr)
654
                    item.attrs[attr] = _attr['Value']
655

    
656
                item.uid = uuid.UUID(component['UID'])
657
                item.loc = [x, y]
658
                item.size = [width, height]
659
                item.angle = angle
660
                item.setToolTip('<b>{}</b><br>LINE NO={}'.format(str(item.uid), text))
661

    
662
                """ apply freeze value """
663
                # item.freeze_item.update_freeze(item.prop('Freeze'))
664

    
665
                if connline is not None:
666
                    item.conns.append(connline)
667
        except Exception as ex:
668
            from App import App
669
            from AppDocData import MessageType
670

    
671
            message = 'error occurred({}) in {}:{}'.format(ex, sys.exc_info()[-1].tb_frame.f_code.co_filename,
672
                                                           sys.exc_info()[-1].tb_lineno)
673
            App.mainWnd().addMessage.emit(MessageType.Error, message)
674
            return None
675

    
676
        return item
677

    
678
    @staticmethod
679
    def fromXml(node):
680
        """ generate EngineeringLineNoTextItem from xml node """
681
        import uuid
682
        from TextItemFactory import TextItemFactory
683
        from SymbolAttr import SymbolAttr
684

    
685
        item = None
686

    
687
        try:
688
            location = node.find('LOCATION').text if node.find('LOCATION') is not None else '0,0'
689
            x = float(location.split(',')[0])
690
            y = float(location.split(',')[1])
691
            width = float(node.find('WIDTH').text) if node.find('WIDTH') is not None else 0
692
            height = float(node.find('HEIGHT').text) if node.find('HEIGHT') is not None else 0
693
            angle = float(node.find('ANGLE').text) if node.find('ANGLE') is not None else 0
694
            text = node.find('TEXT').text
695

    
696
            configs = AppDocData.instance().getConfigs('Data', 'Grid')
697
            grid = int(configs[0].value) if 1 == len(configs) else -1
698
            if grid == 1:
699
                x = round(x)
700
                y = round(y)
701
                width = round(width)
702
                height = round(height)
703

    
704
            textInfo = TextInfo(text, x, y, width, height, angle)
705
            connline = node.find('CONNLINE').text if node.find('CONNLINE') is not None else None
706

    
707
            configs = AppDocData.instance().getConfigs('Data', 'Grid')
708
            grid = int(configs[0].value) if 1 == len(configs) else -1
709
            if grid == 1:
710
                x = round(x)
711
                y = round(y)
712
                width = round(width)
713
                height = round(height)
714

    
715
            matches = [prop_node for prop_node in node.iter('PROPERTY') if prop_node.attrib['Attribute'] == 'Config']
716
            if matches:
717
                item = TextItemFactory.instance().createTextItem(textInfo, matches[0].text)
718
            else:
719
                item = TextItemFactory.instance().createTextItem(textInfo)
720

    
721
            if item is not None:
722
                item.setVisible(False)
723
                for prop_node in node.iter('PROPERTY'):
724
                    matches = [prop for prop in item._properties.keys() if
725
                               prop.Attribute == prop_node.attrib['Attribute'] and prop.Attribute != 'Config']
726
                    if matches:
727
                        item._properties[matches[0]] = matches[0].parse_value(prop_node.text)
728

    
729
                for attr_node in node.iterfind('ATTRIBUTE'):
730
                    attr = SymbolAttr.fromXml(attr_node)
731
                    item.attrs[attr] = attr_node.text
732

    
733
                item.uid = uuid.UUID(node.find('UID').text)
734
                item.loc = [x, y]
735
                item.size = [width, height]
736
                item.angle = angle
737
                item.setToolTip('<b>{}</b><br>LINE NO={}'.format(str(item.uid), text))
738

    
739
                # get associations 
740
                attributeValue = node.find('ASSOCIATIONS')
741
                if attributeValue is not None:
742
                    for assoc in attributeValue.iter('ASSOCIATION'):
743
                        _attrType = assoc.attrib['TYPE']
744
                        if not _attrType in item._associations:
745
                            item._associations[_attrType] = []
746
                        item._associations[_attrType].append(uuid.UUID(assoc.text) if assoc.text != 'None' else None)
747
                # up to here
748

    
749
                """ apply freeze value """
750
                # item.freeze_item.update_freeze(item.prop('Freeze'))
751

    
752
                if connline is not None:
753
                    item.conns.append(connline)
754
        except Exception as ex:
755
            from App import App
756
            from AppDocData import MessageType
757

    
758
            message = 'error occurred({}) in {}:{}'.format(ex, sys.exc_info()[-1].tb_frame.f_code.co_filename,
759
                                                           sys.exc_info()[-1].tb_lineno)
760
            App.mainWnd().addMessage.emit(MessageType.Error, message)
761
            return None
762

    
763
        return item
764

    
765
    '''
766
        @brief      generate xml code
767
        @author     humkyung
768
        @date       2018.04.23
769
        @history    humkyung 2018.05.02 write symbol's attribute
770
                    humkyung 2018.05.16 write run information to xml
771
    '''
772

    
773
    def toXml(self):
774
        from xml.etree.ElementTree import Element, SubElement, dump, ElementTree
775
        from EngineeringLineItem import QEngineeringLineItem
776
        from SymbolSvgItem import SymbolSvgItem
777

    
778
        try:
779
            #docData = AppDocData.instance()
780
            #configs = docData.getConfigs('Line No', 'Delimiter')
781
            #delimiter = configs[0].value if 1 == len(configs) else '-'
782
            #lineNoconfigs = docData.getConfigs('Line No', 'Configuration')
783

    
784
            node = Element('LINE_NO')
785
            uidNode = Element('UID')
786
            uidNode.text = str(self.uid)
787
            node.append(uidNode)
788

    
789
            textNode = Element('TEXT')
790
            textNode.text = self.text()
791
            node.append(textNode)
792

    
793
            locNode = Element('LOCATION')
794
            locNode.text = '{},{}'.format(self.loc[0], self.loc[1])
795
            node.append(locNode)
796

    
797
            widthNode = Element('WIDTH')
798
            widthNode.text = str(self.size[0])
799
            node.append(widthNode)
800

    
801
            heightNode = Element('HEIGHT')
802
            heightNode.text = str(self.size[1])
803
            node.append(heightNode)
804

    
805
            angleNode = Element('ANGLE')
806
            angleNode.text = str(self.angle)
807
            node.append(angleNode)
808

    
809
            areaNode = Element('AREA')
810
            areaNode.text = self.area
811
            node.append(areaNode)
812

    
813
            for run in self.runs:
814
                if run and run.items:
815
                    node.append(run.toXml())
816
            
817
            attributeValueNode = Element('ASSOCIATIONS')
818
            for key, value in self._associations.items():
819
                for assoc in value:
820
                    assoc_node = Element('ASSOCIATION')
821
                    assoc_node.attrib['TYPE'] = str(key)
822
                    assoc_node.text = str(assoc)
823
                    attributeValueNode.append(assoc_node)
824
            node.append(attributeValueNode)
825

    
826
            properties_node = Element('PROPERTIES')
827
            for prop, value in self.properties.items():
828
                prop_node = prop.toXml()
829
                prop_node.text = str(value) if value else ''
830
                properties_node.append(prop_node)
831
            node.append(properties_node)
832

    
833
            _attrs = self.getAttributes()
834
            for key in _attrs.keys():
835
                if key.UID is not None:
836
                    attrNode = key.toXml()
837
                    attrNode.text = str(_attrs[key])
838
                    node.append(attrNode)
839

    
840
            if self.conns:
841
                connNode = Element('CONNLINE')
842
                connNode.text = str(self.conns[0].uid) if hasattr(self.conns[0], 'uid') else str(self.conns[0])
843
                node.append(connNode)
844

    
845
            sceneNode = Element('SCENE')
846
            sceneNode.text = str(self.sceneBoundingRect()).replace('PyQt5.QtCore.QRectF(', '').replace(' ', '').replace(
847
                ')', '') if self.scene() else '{},{},{},{}'.format(self.loc[0], self.loc[1], self.size[0], self.size[1])
848
            node.append(sceneNode)
849

    
850
        except Exception as ex:
851
            from App import App
852
            from AppDocData import MessageType
853

    
854
            message = 'error occurred({}) in {}:{}'.format(ex, sys.exc_info()[-1].tb_frame.f_code.co_filename,
855
                                                           sys.exc_info()[-1].tb_lineno)
856
            App.mainWnd().addMessage.emit(MessageType.Error, message)
857

    
858
            return None
859

    
860
        return node
861

    
862
    def to_svg(self, parent) -> list:
863
        """convert line no item to svg"""
864
        import re
865
        from xml.etree.ElementTree import Element, SubElement, dump, ElementTree
866
        from App import App
867

    
868
        res = []
869
        try:
870
            app_doc_data = AppDocData.instance()
871
            prj = app_doc_data.getCurrentProject()
872

    
873
            node = Element('g')
874
            node.attrib['id'] = str(self.uid)
875
            node.attrib['class'] = 'Pipe'
876
            node.attrib['data-tag-name'] = self.toPlainText()
877
            node.attrib['font-family'] = self.font().family()
878
            node.attrib['font-size'] = str(self.boundingRect().height())  # str(self.font().pointSizeF())
879
            node.attrib['font-weight'] = str(self.font().weight())
880

    
881
            except_pattern = re.compile('[^a-zA-Z0-9-_]')
882
            for attr, value in self.getAttributes().items():
883
                node.attrib[re.sub(except_pattern, '_', attr.Attribute)] = value if value else ''
884
            trans = self.sceneTransform()
885
            node.attrib['transform'] = f"matrix(" \
886
                                       f"{trans.m11()},{trans.m12()}," \
887
                                       f"{trans.m21()},{trans.m22()}," \
888
                                       f"{trans.m31()},{trans.m32()}" \
889
                                       f")"
890

    
891
            text = Element('text')
892
            text.text = self.toPlainText()
893
            text.attrib['textLength'] = str(self.boundingRect().width())
894
            text.attrib['lengthAdjust'] = 'spacingAndGlyphs'
895
            text.attrib['alignment-baseline'] = 'hanging'  # align left-top corner
896
            node.append(text)
897

    
898
            connected_line = self.connected_line
899
            if connected_line:
900
                conn_node = connected_line.to_svg(self)
901
                if conn_node:
902
                    node.extend(conn_node)
903

    
904
            res.append(node)
905
        except Exception as ex:
906
            from App import App
907
            from AppDocData import MessageType
908
            message = 'error occurred({}) in {}:{}'.format(ex, sys.exc_info()[-1].tb_frame.f_code.co_filename,
909
                                                           sys.exc_info()[-1].tb_lineno)
910
            App.mainWnd().addMessage.emit(MessageType.Error, message)
911

    
912
        return res
913

    
914
    def end_break(self):
915
        '''
916
            @brief  end break check
917
            @author euisung
918
            @date   2019.05.07
919
            @history    2019.05.19  euisung    can cover at both end that contact other line's middle
920
                        2019.05.19  euisung    no more used integrated with linetracer
921
        '''
922
        from EngineeringLineItem import QEngineeringLineItem
923
        from SymbolSvgItem import SymbolSvgItem
924
        from AppDocData import AppDocData
925
        end_breaks = []
926

    
927
        try:
928
            docdata = AppDocData.instance()
929

    
930
            line_from = self.prop('From')
931
            line_to = self.prop('To')
932

    
933
            end_break_names = docdata.getSymbolListByType('type', 'End Break')
934
            if len(end_break_names) is 0:
935
                return end_breaks
936

    
937
            svgFileName = end_break_names[0].sName
938
            symbol = AppDocData.instance().getSymbolByQuery('name', svgFileName)
939
            svgFilePath = os.path.join(AppDocData.instance().getCurrentProject().getSvgFilePath(), symbol.getType(),
940
                                       svgFileName + '.svg')
941

    
942
            for line_end in [line_from, line_to]:
943
                for connector in line_end.connectors:
944
                    if connector.connectedItem is not None and connector.connectedItem.owner is not self:
945
                        end_break = SymbolSvgItem.createItem(symbol.getType(), None, svgFilePath)
946
                        pt = [connector.center()[0] - float(symbol.getOriginalPoint().split(',')[0]),
947
                              connector.center()[1] - float(symbol.getOriginalPoint().split(',')[1])]
948
                        origin = [0, 0]
949
                        if 2 == len(symbol.getOriginalPoint().split(',')):
950
                            tokens = symbol.getOriginalPoint().split(',')
951
                            origin = [pt[0] + float(tokens[0]), pt[1] + float(tokens[1])]
952
                        end_break.buildItem(svgFileName, symbol.getType(), 5.7, pt,
953
                                            [end_break.boundingRect().width(), end_break.boundingRect().height()],
954
                                            origin, [], symbol.getBaseSymbol(), symbol.getAdditionalSymbol(),
955
                                            symbol.getHasInstrumentLabel())
956

    
957
                        end_break.set_property('Connected Item', connector.connectedItem)
958
                        end_break.setToolTip('owner : ' + str(line_end))
959
                        end_break.area = 'Drawing'
960
                        end_break.owner = line_end
961
                        end_breaks.append(end_break)
962
        except Exception as ex:
963
            from App import App
964
            from AppDocData import MessageType
965

    
966
            message = 'error occurred({}) in {}:{}'.format(ex, sys.exc_info()[-1].tb_frame.f_code.co_filename,
967
                                                           sys.exc_info()[-1].tb_lineno)
968
            App.mainWnd().addMessage.emit(MessageType.Error, message)
969

    
970
        return end_breaks
971

    
972
    '''
973
        @Override (QEngineeringTextItem)
974
        @brief  get connected items
975
        @author Jeongwoo
976
        @date   2018.05.15
977
    '''
978

    
979
    def getConnectedItems(self):
980
        visited = []
981

    
982
        try:
983
            for run in self.runs:
984
                visited.extend(run.items)
985
        except Exception as ex:
986
            from App import App
987
            from AppDocData import MessageType
988

    
989
            message = 'error occurred({}) in {}:{}'.format(ex, sys.exc_info()[-1].tb_frame.f_code.co_filename,
990
                                                           sys.exc_info()[-1].tb_lineno)
991
            App.mainWnd().addMessage.emit(MessageType.Error, message)
992

    
993
        return visited
994

    
995
    def explode(self, remainFromTo=False):
996
        """ explode line no """
997

    
998
        # if False == self.prop('Freeze'):
999
        try:
1000
            for index in reversed(range(len(self.runs))):
1001
                self.runs[index].explode()
1002
        except Exception as ex:
1003
            from App import App
1004
            from AppDocData import MessageType
1005

    
1006
            message = 'error occurred({}) in {}:{}'.format(ex, sys.exc_info()[-1].tb_frame.f_code.co_filename,
1007
                                                           sys.exc_info()[-1].tb_lineno) + ' Item UID : ' + str(self.uid)
1008
            App.mainWnd().addMessage.emit(MessageType.Error, message)
1009
        finally:
1010
            self.runs.clear()
1011
            if not remainFromTo:
1012
                self.set_property('From', None)
1013
                self.set_property('To', None)
1014

    
1015
            if hasattr(self, 'lineNoFromToIndicator') and self.lineNoFromToIndicator:
1016
                self.lineNoFromToIndicatorShowFlag = False
1017
                if self.scene():
1018
                    self.lineNoFromToIndicator[0].setVisible(False)
1019
                    if len(self.lineNoFromToIndicator) == 2:
1020
                        self.lineNoFromToIndicator[1].setVisible(False)
1021

    
1022
    '''
1023
        @brief      generate sql phrase to save to database(Notice: Line No's symbol is is 1)
1024
        @author     humkyung
1025
        @date       2018.08.14
1026
    '''
1027
    def toSql_return_separately(self):
1028
        import uuid
1029
        from EngineeringAbstractItem import QEngineeringAbstractItem
1030

    
1031
        res = []
1032
        resLater = []
1033

    
1034
        app_doc_data = AppDocData.instance()
1035
        cols = ['UID', 'Drawings_UID', 'Symbol_UID', 'X', 'Y', 'Width', 'Height', 'Rotation', 'Value', 'Connected',
1036
                '[From]', '[To]']
1037
        if type(self) is QEngineeringLineNoTextItem:
1038
            values = ['?', '?', "(select UID from Symbol where Name='Line NO' and SymbolType_UID=-1)", '?', '?', '?',
1039
                      '?', '?', '?', '?', '?', '?']
1040
        else:
1041
            values = ['?', '?', "(select UID from Symbol where Name='Trim Line NO' and SymbolType_UID=-1)", '?', '?',
1042
                      '?', '?', '?', '?', '?', '?', '?']
1043
        _from = self.prop('From')
1044
        if not _from:
1045
            _from = ''
1046
        _to = self.prop('To')
1047
        if not _to:
1048
            _to = ''
1049
        params = [(str(self.uid), str(app_doc_data.activeDrawing.UID), self.loc[0], self.loc[1], self.size[0],
1050
                   self.size[1], str(self.angle), \
1051
                   self.text(), str(self.conns[0]) if self.conns else None, str(_from), str(_to))]
1052
        sql = 'insert into Components({}) values({})'.format(','.join(cols), ','.join(values))
1053
        res.append((sql, tuple(params)))
1054

    
1055
        cols = ['UID', 'Components_UID', 'LineProperties_UID', 'Value']
1056
        values = ['?', '?', '?', '?']
1057
        params = []
1058
        attrs = self.getAttributes()
1059
        for key, value in attrs.items():
1060
            if key.Attribute == 'LINE NO':  # or key.IsProp != 5:
1061
                continue
1062
            params.append((str(uuid.uuid4()), str(self.uid), str(key.UID), str(value)))
1063
        sql = 'insert into LineNoAttributes({}) values({})'.format(','.join(cols), ','.join(values))
1064
        resLater.append((sql, tuple(params)))
1065

    
1066
        if self.associations():
1067
            cols = ['UID', '[Type]', 'Components_UID', 'Association']
1068
            values = ['?', '?', '?', '?']
1069
            params = []
1070
            for assoc in self.associations():
1071
                params.append(
1072
                    (str(uuid.uuid4()), QEngineeringAbstractItem.assoc_type(assoc), str(self.uid), str(assoc.uid)))
1073
            sql = 'insert into Associations({}) values({})'.format(','.join(cols), ','.join(values))
1074
            resLater.append((sql, tuple(params)))
1075

    
1076
        # insert line no's Attributes
1077
        cols = ['UID', 'Components_UID', 'SymbolAttribute_UID', 'Value', 'Association_UID', 'Freeze']
1078
        values = ['?', '?', '?', '?', '?', '?']
1079
        params = []
1080
        for key in attrs.keys():
1081
            if key.IsProp != 5:
1082
                params.append((str(uuid.uuid4()), str(self.uid), str(key.UID), str(attrs[key]), str(key.AssocItem),
1083
                               str(key.Freeze)))
1084
        sql = 'insert into Attributes({}) values({})'.format(','.join(cols), ','.join(values))
1085
        res.append((sql, tuple(params)))
1086

    
1087
        if self.associations():
1088
            cols = ['UID', '[Type]', 'Components_UID', 'Association']
1089
            values = ['?', '?', '?', '?']
1090
            params = []
1091
            for assoc in self.associations():
1092
                params.append(
1093
                    (str(uuid.uuid4()), QEngineeringAbstractItem.assoc_type(assoc), str(self.uid), str(assoc.uid)))
1094
            sql = 'insert into Associations({}) values({})'.format(','.join(cols), ','.join(values))
1095
            resLater.append((sql, tuple(params)))
1096

    
1097
        _index = 0
1098
        for run in self.runs:
1099
            if run and run.items:
1100
                resLater.extend(run.to_sql(_index, self))
1101
                _index += 1
1102

    
1103
        return res, resLater
1104

    
1105
    '''
1106
        @brief      return Line Data List
1107
        @author     kyouho
1108
        @date       2018.08.14
1109
        @ no more used
1110
    '''
1111
    def getLineDataList(self):
1112
        dataList = []
1113
        '''
1114
        try:
1115
            import uuid
1116
            global lineColumnList
1117

1118
            docData = AppDocData.instance()
1119
            attrs = self.getAttributes()
1120
            for index in range(len(lineColumnList)):
1121
                dataList.append('')
1122

1123
            dataList[20] = docData.imgName
1124

1125
            for key in attrs.keys():
1126
                if type(key) is not UserInputAttribute:
1127
                    lineProp = docData.getLinePropertiesByUID(key.UID)
1128
                    if lineProp:
1129
                        attrName = lineProp[0].Attribute.upper().replace(' ', '')
1130
                    else:
1131
                        attrName = key.Attribute.upper().replace(' ', '')
1132

1133
                    data = attrs[key]
1134
                    if attrName == 'NOMINALDIAMETER':
1135
                        dataList[1] = data
1136
                    elif attrName == 'FLUIDCODE':
1137
                        dataList[2] = data
1138
                        dataList[7] = data
1139
                    elif attrName == 'TAGSEQNO':
1140
                        pass
1141
                    elif attrName == 'INSULATIONPURPOSE':
1142
                        dataList[16] = data
1143
                    elif attrName == 'STREAMNO':
1144
                        pass
1145
                    elif attrName == 'LINENO' or attrName == 'LINE NO':
1146
                        dataList[3] = data
1147
                    elif attrName == 'PNIDNUMBER':
1148
                        pass
1149
                    elif attrName == 'PIPINGMATERIALSCLASS':
1150
                        dataList[4] = data
1151
                    elif attrName == '':
1152
                        pass
1153
                else:
1154
                    typeUID = key.Attribute
1155
                    value = key.text
1156
                    lineAttr = docData.getLinePropertiesByUID(key.UD)
1157

1158
                    for index in range(len(lineColumnList)):
1159
                        if lineColumnList[index] == lineAttr[0].Attribute:
1160
                            dataList[index] = value
1161
        except Exception as ex:
1162
            from App import App
1163
            from AppDocData import MessageType
1164

1165
            message = 'error occurred({}) in {}:{}'.format(ex, sys.exc_info()[-1].tb_frame.f_code.co_filename,
1166
                                                           sys.exc_info()[-1].tb_lineno)
1167
            App.mainWnd().addMessage.emit(MessageType.Error, message)
1168

1169
        if dataList[0] == '':
1170
            dataList[0] = str(uuid.uuid4())
1171
        '''
1172

    
1173
        return dataList
1174

    
1175
    def EvaluatedEQ(self):
1176
        ''' evaluate line no's From / To equipment '''
1177

    
1178
        from EngineeringNozzleItem import QEngineeringNozzleItem
1179
        from EngineeringVendorItem import QEngineeringVendorItem
1180
        from EngineeringEquipmentItem import QEngineeringEquipmentItem
1181
        from EngineeringLineItem import QEngineeringLineItem
1182

    
1183
        pool = []
1184
        visited = []
1185
        if self.runs and self.runs[0]:
1186
            pool.append(self)
1187
            _attrs = self.getAttributes()
1188

    
1189
        from_found = False
1190
        to_found = False
1191

    
1192
        
1193
        try:
1194
            while pool:
1195
                lineNo = pool.pop()
1196
                if lineNo not in visited:
1197
                    visited.append(lineNo)
1198
                else:
1199
                    continue
1200

    
1201
                if lineNo.runs and lineNo.runs[0]:
1202
                    items = lineNo.runs[0].items
1203
                    if len(items) > 2:
1204
                        if type(items[0]) is QEngineeringNozzleItem and not from_found:
1205
                            for connector in items[0].connectors:
1206
                                # From
1207
                                if (type(connector.connectedItem) is QEngineeringVendorItem or type(
1208
                                        connector.connectedItem) is QEngineeringEquipmentItem) and \
1209
                                        connector.connectedItem not in items:
1210
                                    for _attr in _attrs:
1211
                                        if _attr.Attribute == 'From_eq' and self.add_assoc_item(connector.connectedItem,
1212
                                                                                                at=_attr.AttrAt):
1213
                                            _attr.AssocItem = connector.connectedItem
1214
                                            from_found = True
1215
                                            break
1216
                                    break
1217
                        elif not from_found:
1218
                            if type(items[0]) is QEngineeringLineItem and items[0].connectors[0].connectedItem and items[0].connectors[0].connectedItem.owner:
1219
                                pool.append(items[0].connectors[0].connectedItem.owner)
1220
                            else:
1221
                                next_items = [connector.connectedItem for connector in items[0].connectors if connector.connectedItem and \
1222
                                        connector.connectedItem is not items[1] and items[0].next_connected(items[1], connector.connectedItem)]
1223
                                if next_items and next_items[0].owner:
1224
                                    pool.append(next_items[0].owner)
1225

    
1226
                        if type(items[-1]) is QEngineeringNozzleItem and not to_found:
1227
                            for connector in items[-1].connectors:
1228
                                # To
1229
                                if (type(connector.connectedItem) is QEngineeringVendorItem or type(
1230
                                        connector.connectedItem) is QEngineeringEquipmentItem) and \
1231
                                        connector.connectedItem not in items:
1232
                                    for _attr in _attrs:
1233
                                        if _attr.Attribute == 'To_eq' and self.add_assoc_item(connector.connectedItem,
1234
                                                                                            at=_attr.AttrAt):
1235
                                            _attr.AssocItem = connector.connectedItem
1236
                                            to_found = True
1237
                                            break
1238
                                    break
1239
                        elif not to_found:
1240
                            if type(items[-1]) is QEngineeringLineItem and items[-1].connectors[1].connectedItem and items[-1].connectors[1].connectedItem.owner:
1241
                                pool.append(items[-1].connectors[1].connectedItem.owner)
1242
                            else:
1243
                                next_items = [connector.connectedItem for connector in items[-1].connectors if connector.connectedItem and \
1244
                                        connector.connectedItem is not items[-2] and items[-1].next_connected(items[-2], connector.connectedItem)]
1245
                                if next_items and next_items[0].owner:
1246
                                    pool.append(next_items[0].owner)
1247
        except Exception as ex:
1248
            from App import App
1249
            from AppDocData import MessageType
1250

    
1251
            message = 'error occurred({}) in {}:{}'.format(ex, sys.exc_info()[-1].tb_frame.f_code.co_filename,
1252
                                                           sys.exc_info()[-1].tb_lineno)
1253
            App.mainWnd().addMessage.emit(MessageType.Error, message)
1254

    
1255
    def sort_order_text(self):
1256
        """ return true if line no same"""
1257

    
1258
        app_doc_data = AppDocData.instance()
1259
        
1260
        configs = app_doc_data.getConfigs('Sort', 'LineNoKeys')
1261
        targets = configs[0].value.split(',') if configs else []
1262

    
1263
        if targets:
1264
            attrs = self.getAttributes(True)
1265
            matches = []
1266

    
1267
            for key in targets:
1268
                _matches = [_key for _key in list(attrs.keys()) if str(_key.UID) == key]
1269
                if _matches:
1270
                    matches.append(attrs[_matches[0]])
1271
        else:
1272
            matches = [self.text()]
1273

    
1274
        return '_'.join(matches)
1275
    
1276
    def validate(self):
1277
        """ validation check """
1278

    
1279
        from SymbolSvgItem import SymbolSvgItem
1280
        from AppDocData import AppDocData
1281
        from EngineeringReducerItem import QEngineeringReducerItem
1282
        from EngineeringLineItem import QEngineeringLineItem
1283
        from EngineeringAbstractItem import QEngineeringAbstractItem
1284

    
1285
        errors = []
1286

    
1287
        try:
1288
            _translate = QCoreApplication.translate
1289

    
1290
            docdata = AppDocData.instance()
1291
            dataPath = docdata.getErrorItemSvgPath()
1292

    
1293
            lineNoError = False
1294

    
1295
            _error = super().validate()
1296
            errors.extend(_error)
1297

    
1298
            _from = self.prop('From')
1299
            _to = self.prop('To')
1300

    
1301
            if not _from or not _to:
1302
                lineNoError = True
1303
            elif self.runs:
1304
                if self.runs[0].items[0] is not _from:
1305
                    lineNoError = True
1306
                elif self.runs[0].items[-1] is not _to:
1307
                    lineNoError = True
1308
            else:
1309
                return errors
1310

    
1311
            size_errors = []
1312
            branch_errors = []
1313
            for run in self.runs:
1314
                sizes = []
1315
                for item in run.items:
1316
                    item_size = None
1317
                    attrs = item.getAttributes()
1318
                    for prop, value in attrs.items():
1319
                        if prop.Attribute.upper() == 'Size'.upper() or prop.Attribute.upper() == 'NominalDiameter'.upper():
1320
                            if value and value != 'None':
1321
                                item_size = value
1322
                                if type(item) is QEngineeringReducerItem or (issubclass(type(item), SymbolSvgItem) and item.iType == 22): # Relief Valve
1323
                                    sizes.append([item, item.mainSubSize[0], item.mainSubSize[1]])
1324
                                    break
1325
                                else:
1326
                                    sizes.append([item, value, value])
1327
                                    break
1328

    
1329
                    if item_size and type(item) is QEngineeringLineItem:
1330
                        for conn in item.connectors:
1331
                            if conn.connectedItem and type(conn.connectedItem) is QEngineeringLineItem and \
1332
                                conn._connected_at == QEngineeringAbstractItem.CONNECTED_AT_BODY:
1333
                                _item_size = None
1334
                                attrs = conn.connectedItem.getAttributes()
1335
                                for prop, value in attrs.items():
1336
                                    if prop.Attribute.upper() == 'Size'.upper() or prop.Attribute.upper() == 'NominalDiameter'.upper():
1337
                                        if value and value != 'None':
1338
                                            _item_size = value
1339
                                            break
1340
                            
1341
                                if _item_size and self.inch_to_number(item_size) > self.inch_to_number(_item_size):
1342
                                    branch_errors.append(item)
1343
                                    branch_errors.append(conn.connectedItem)
1344

    
1345
                if len(sizes) > 1:
1346
                    for index in range(len(sizes) - 1):
1347
                        if sizes[index][2] != sizes[index + 1][1] and \
1348
                            type(sizes[index][0]) is not QEngineeringReducerItem and type(sizes[index + 1][0]) is not QEngineeringReducerItem \
1349
                            and (hasattr(sizes[index][0], 'iType') and sizes[index][0].iType != 22) and \
1350
                            (hasattr(sizes[index + 1][0], 'iType') and sizes[index + 1][0].iType != 22):
1351
                                size_errors.append(sizes[index][0])
1352
                                size_errors.append(sizes[index + 1][0])
1353
                        elif sizes[index][1] not in sizes[index + 1] and sizes[index][2] not in sizes[index + 1]:
1354
                                size_errors.append(sizes[index][0])
1355
                                size_errors.append(sizes[index + 1][0])
1356

    
1357
            for size in size_errors:
1358
                error = SymbolSvgItem.createItem('Error', None, dataPath)
1359
                error.setPosition([size.sceneBoundingRect().center().x(), size.sceneBoundingRect().center().y()])
1360
                error.parent = size
1361
                error.msg = _translate('Size change error', 'Size change error')
1362
                error.setToolTip(error.msg)
1363
                error.area = 'Drawing'
1364
                error.name = 'Error'
1365
                errors.append(error)
1366

    
1367
            for size in branch_errors:
1368
                error = SymbolSvgItem.createItem('Error', None, dataPath)
1369
                error.setPosition([size.sceneBoundingRect().center().x(), size.sceneBoundingRect().center().y()])
1370
                error.parent = size
1371
                error.msg = _translate('Branch Size error', 'Branch Size error')
1372
                error.setToolTip(error.msg)
1373
                error.area = 'Drawing'
1374
                error.name = 'Error'
1375
                errors.append(error)
1376

    
1377
            if self.runs and self.runs[0].items:
1378
                _size = self.Size
1379
                found = False
1380
                if _size:
1381
                    for item in self.runs[0].items:
1382
                        if type(item) is QEngineeringReducerItem or (issubclass(type(item), SymbolSvgItem) and item.iType == 22):
1383
                            continue
1384
                        _size2 = item.EvaluatedSize
1385
                        if _size2 and _size2 != 'None' and _size2 == _size:
1386
                            found = True
1387
                            break
1388

    
1389
                        #attrs = item.getAttributes()
1390
                        #for prop, value in attrs.items():
1391
                        #    if prop.Attribute.upper() == 'Size'.upper() or prop.Attribute.upper() == 'NominalDiameter'.upper():
1392
                        #        if value and value != 'None' and _size != value:
1393
                        #            found = True
1394
                        #            break
1395
                        
1396
                        if found:
1397
                            break
1398
                
1399
                if not found:
1400
                    error = SymbolSvgItem.createItem('Error', None, dataPath)
1401
                    error.setPosition([self.sceneBoundingRect().center().x(), self.sceneBoundingRect().center().y()])
1402
                    error.parent = self
1403
                    error.msg = _translate('Main run size warning', 'Main run size warning')
1404
                    error.setToolTip(error.msg)
1405
                    error.area = 'Drawing'
1406
                    error.name = 'Warning'
1407
                    errors.append(error)
1408

    
1409
            if lineNoError:
1410
                error = SymbolSvgItem.createItem('Error', None, dataPath)
1411
                error.setPosition([self.sceneBoundingRect().center().x(), self.sceneBoundingRect().center().y()])
1412
                error.parent = self
1413
                error.msg = _translate('From/ To error', 'From/ To error')
1414
                error.setToolTip(error.msg)
1415
                error.area = 'Drawing'
1416
                error.name = 'Error'
1417
                errors.append(error)
1418

    
1419
        except Exception as ex:
1420
            from App import App
1421
            from AppDocData import MessageType
1422

    
1423
            message = 'error occurred({}) in {}:{}'.format(ex, sys.exc_info()[-1].tb_frame.f_code.co_filename,
1424
                                                           sys.exc_info()[-1].tb_lineno)
1425
            App.mainWnd().addMessage.emit(MessageType.Error, message)
1426

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