프로젝트

일반

사용자정보

통계
| 개정판:

hytos / DTI_PID / DTI_PID / LineNoTracer.py @ 16df5f39

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

1
# coding: utf-8
2
""" This is line no tracer module """
3

    
4
import sys
5
import math
6
import asyncio
7
import shapely
8
from AppDocData import AppDocData, MessageType
9
from EngineeringLineItem import QEngineeringLineItem
10
from EngineeringLineNoTextItem import QEngineeringLineNoTextItem
11
from QEngineeringFlowArrowItem import QEngineeringFlowArrowItem
12
from SymbolSvgItem import SymbolSvgItem
13
from EngineeringTextItem import QEngineeringTextItem
14
from EngineeringUnknownItem import QEngineeringUnknownItem
15

    
16
try:
17
    from PyQt5.QtCore import *
18
    from PyQt5.QtGui import *
19
    from PyQt5.QtWidgets import *
20
except ImportError:
21
    try:
22
        from PyQt4.QtCore import *
23
        from PyQt4.QtGui import *
24
    except ImportError:
25
        raise ImportError("ImageViewerQt: Requires PyQt5 or PyQt4.")
26

    
27

    
28
class LineNoTracer:
29
    '''
30
        @history    2018.04.26 Jeongwoo Variable name changed (texts → lineNos)
31
    '''
32

    
33
    def __init__(self, symbols, lines, lineNos, specBreaks, lineIndicators, vendors, end_breaks):
34
        try:
35
            self._symbols = symbols
36
            self._lines = lines
37
            self._lineNos = lineNos
38
            self._spec_breaks = specBreaks
39
            self._lineIndicator = lineIndicators
40
            self._end_breaks = end_breaks
41
            self.maxValue = None
42

    
43
        except Exception as ex:
44
            from App import App
45

    
46
            message = 'error occurred({}) in {}:{}'.format(ex, sys.exc_info()[-1].tb_frame.f_code.co_filename,
47
                                                           sys.exc_info()[-1].tb_lineno)
48
            App.mainWnd().addMessage.emit(MessageType.Error, message)
49

    
50
    '''
51
        @brief  find primary lines connected to given line no
52
        @author humkyung
53
    '''
54

    
55
    def find_primary_lines(self, lineno, include_signal=True):
56
        from EngineeringLineItem import QEngineeringLineItem
57
        from EngineeringRunItem import QEngineeringRunItem
58

    
59
        connected_items = []
60

    
61
        _from = lineno.prop('From')
62
        _to = lineno.prop('To')
63
        if _from and _to and lineno.empty():
64
            connected_items = self.find_connected_objects(_from, to=_to, primary=True, include_signal=include_signal)
65
            if _from in connected_items and _to in connected_items:
66
                start = connected_items.index(_from)
67
                end = connected_items.index(_to)
68
                if start < end:
69
                    connected_items = connected_items[start:end + 1]
70
                else:
71
                    connected_items = connected_items[end:start + 1]
72
                    connected_items.reverse()
73
        elif _from and not _to and lineno.empty():
74
            connected_items = self.find_connected_objects(_from, primary=True, include_signal=include_signal)
75
        elif (not _from or not _to) and (1 == len(lineno.conns)):
76
            connected_items = self.find_connected_objects(lineno.conns[0], include_signal=include_signal)
77

    
78
        # print(connected_items)
79
        if connected_items:
80
            for item in connected_items:
81
                item.owner = lineno  # set item's owner
82

    
83
            line_run = QEngineeringRunItem()
84
            line_run.items = connected_items
85
            line_run.arrange_flow_direction()
86
            line_run.owner = lineno
87
            lineno.runs.append(line_run)
88

    
89
            lineno.set_property('From', connected_items[0])
90
            lineno.set_property('To', connected_items[-1])
91

    
92
        if _to is not None and connected_items and connected_items[-1] is not _to:
93
            _to.owner = None
94

    
95
        return connected_items
96

    
97
    '''
98
        @brief  find secondary lines
99
        @author humkyung
100
    '''
101

    
102
    def find_secondary_lines(self, lines_and_symbols, include_signal=True, is_trim=False):
103
        from EngineeringAbstractItem import QEngineeringAbstractItem
104
        from EngineeringLineItem import QEngineeringLineItem
105
        from EngineeringRunItem import QEngineeringRunItem
106
        from QEngineeringTrimLineNoTextItem import QEngineeringTrimLineNoTextItem
107

    
108
        try:
109
            foundCount = 1
110
            while foundCount:
111
                foundCount = 0
112
                notMatches = []
113
                for line in lines_and_symbols:
114
                    if line.owner is not None: continue
115

    
116
                    if not include_signal and type(line) is QEngineeringLineItem and not line.is_piping(): continue
117

    
118
                    end_break_components = []
119
                    if type(line) is QEngineeringLineItem:
120
                        for end_break in self._end_breaks:
121
                            if line is end_break.owner:
122
                                end_break_components.append(end_break.prop('Connected Item'))
123
                            elif line is end_break.prop('Connected Item'):
124
                                end_break_components.append(end_break.owner)
125

    
126
                    if not is_trim:
127
                        line_matches = [x for x in self._lines if x.owner and \
128
                                            line.is_connected(x, QEngineeringAbstractItem.CONNECTED_AT_BODY) and x not in end_break_components]
129
                        symbol_matches = [x for x in self._symbols if
130
                                          x.owner and line.is_connected(x) and x.canBeSecondary(line)]
131
                    else:
132
                        line_matches = [x for x in self._lines if x.owner and type(x.owner) is QEngineeringTrimLineNoTextItem and \
133
                                            line.is_connected(x, QEngineeringAbstractItem.CONNECTED_AT_BODY) and x not in end_break_components]
134
                        symbol_matches = [x for x in self._symbols if x.owner and type(
135
                            x.owner) is QEngineeringTrimLineNoTextItem and line.is_connected(x) and x.canBeSecondary(line)]
136

    
137
                    if line_matches or symbol_matches:
138
                        foundCount += 1
139
                        connected_items = self.find_connected_objects(line, include_signal=include_signal)
140

    
141
                        owner = line_matches[0].owner if line_matches else symbol_matches[0].owner
142
                        for item in connected_items:
143
                            item.owner = owner  # set item's owner
144

    
145
                        if connected_items:
146
                            line_run = QEngineeringRunItem()
147
                            line_run.items = connected_items
148
                            line_run.arrange_flow_direction()
149
                            if line_run.items is not None and len(line_run.items) > 0:
150
                                line_run.owner = owner
151
                                owner.runs.append(line_run)
152
                    else:
153
                        notMatches.append(line)
154
                # lines_and_symbols = notMatches
155
        except Exception as ex:
156
            from App import App
157

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

    
162
    '''
163
        @brief      trace line no
164
        @author     humkyung
165
        @date       2018.04.16
166
        @history    2018.04.26 Jeongwoo docDatalineNos = self.lineNos, Not For loop
167
                    humkyung 2018.05.08 add flow arrow
168
                    Jeongwoo 2018.05.14 Add [runs] on Primary/Secondary Line - Need to modify Secondary Line
169
                    Jeongwoo 2018.05.15 Make Comments [lineno.conns[0].owner = lineno]
170
                    Jeongwoo 2018.05.17 Modify find secondary lines with 'while'
171
                                        Modify find secondary lines with 'while' used sublist for unconnected line
172
                    humkyung 2018.05.18 set start line's owner before tracing
173
    '''
174

    
175
    def execute(self, displayMessage, updateProgress, toler=600):
176
        from EngineeringLineItem import QEngineeringLineItem
177
        from SymbolSvgItem import SymbolSvgItem
178
        from EngineeringRunItem import QEngineeringRunItem
179
        from QEngineeringTrimLineNoTextItem import QEngineeringTrimLineNoTextItem
180
        from EngineeringEquipmentItem import QEngineeringEquipmentItem
181

    
182
        try:
183
            app_doc_data = AppDocData.instance()
184

    
185
            configs = app_doc_data.getConfigs('Line No', 'Delimiter')
186
            if 1 == len(configs):
187
                #configs = app_doc_data.getConfigs('Line No', 'Configuration')
188

    
189
                for line_no in self._lineNos:
190
                    _from = line_no.prop('From')
191
                    _to = line_no.prop('To')
192

    
193
                    line_no.conns.clear()
194
                    minDist = None
195
                    startLine = None
196
                    for line in [line for line in self._lines if line.owner is None and line.is_piping(strong=True)]:
197
                        dist = line.distanceTo((line_no.center().x(), line_no.center().y()))
198
                        if (minDist is None) or (dist < minDist):
199
                            minDist = dist
200
                            startLine = line
201
                    if (startLine is not None) and (minDist < toler):
202
                        line_no.conns.append(startLine)
203
                        if not _from or not _to:
204
                            startLine.owner = line_no
205

    
206
                    if _from and _to and \
207
                            (type(_from) is QEngineeringLineItem or issubclass(type(_from), SymbolSvgItem)) and \
208
                            (type(_to) is QEngineeringLineItem or issubclass(type(_to), SymbolSvgItem)):
209
                        _from.owner = line_no
210
                        _to.owner = line_no
211
                        line_no._fixed = True
212
                    elif _from and not _to and (type(_from) is QEngineeringLineItem or issubclass(type(_from), SymbolSvgItem)):
213
                        _from.owner = line_no
214
                        line_no.set_property('To', None)
215
                        line_no._fixed = True if len([conn for conn in _from.connectors if conn.connectedItem]) == 1 else False
216
                    else:
217
                        line_no.set_property('From', None)
218
                        line_no.set_property('To', None)
219
                        line_no._fixed = False
220

    
221
                self.maxValue = len(self._lineNos) + 1  # line no's count + secondary line
222

    
223
                # find primary lines
224
                # sort line no with from,to value
225
                self._lineNos.sort(
226
                    key=lambda line_no: (1 if line_no.prop('From') else 0) + (1 if line_no.prop('To') else 0),
227
                    reverse=True)
228
                for lineno in self._lineNos:
229
                    if displayMessage: displayMessage.emit('{} {}'.format(lineno.text(), 'Topology Construction'))
230
                    self.find_primary_lines(lineno, include_signal=False)
231
                    if updateProgress: updateProgress.emit(self.maxValue)
232

    
233
                # find secondary lines
234
                lines_and_symbols = self._lines + self._symbols
235
                self.find_secondary_lines(lines_and_symbols, include_signal=False)
236

    
237
                # double check conn line cuz startLine may need at first step
238
                for lineno in self._lineNos:
239
                    lineno.conns.clear()
240
                    minDist = None
241
                    startLine = None
242
                    if len(lineno.runs) is 0:
243
                        continue
244
                    for line in [line for line in lineno.runs[0].items if
245
                                 type(line) is QEngineeringLineItem and line.is_piping(strong=True)]:
246
                        dist = line.distanceTo((lineno.center().x(), lineno.center().y()))
247
                        if (minDist is None) or (dist < minDist):
248
                            minDist = dist
249
                            startLine = line
250
                    if (startLine is not None):  # and (minDist < toler):
251
                        lineno.conns.append(startLine)
252

    
253
                if updateProgress: updateProgress.emit(self.maxValue)
254

    
255
            # make trim lines
256
            updateProgress.emit(-1)  # reset progressbar
257
            displayMessage.emit('Unknown line Topology Construction')
258
            orphanLines = [line for line in self._lines if line.owner is None]
259
            orphanSymbols = [symbol for symbol in self._symbols if
260
                             symbol.owner is None and type(symbol) is not QEngineeringEquipmentItem]
261
            if orphanLines + orphanSymbols:
262
                self.maxValue = len(orphanLines) + 1
263
                orphanLines = sorted(orphanLines, key=lambda param: param.length(), reverse=True)
264
                orphans = orphanLines + orphanSymbols
265
                while len(orphans) > 0:
266
                    trimLineNo = QEngineeringTrimLineNoTextItem()
267
                    trimLineNo.conns.append(orphans[0])
268
                    orphans[0].owner = trimLineNo
269
                    # orphanLines[0].linkedItem = trimLineNo
270

    
271
                    connectedItems = self.find_primary_lines(trimLineNo)
272
                    for item in connectedItems:
273
                        if item in orphans:
274
                            orphans.remove(item)
275
                            updateProgress.emit(self.maxValue)
276

    
277
                    self.find_secondary_lines(orphans, is_trim=True)
278
                    for item_index in reversed(range(len(orphans))):
279
                        item = orphans[item_index]
280
                        if item.owner is not None:
281
                            orphans.remove(item)
282
                            updateProgress.emit(self.maxValue)
283

    
284
                    app_doc_data.tracerLineNos.append(trimLineNo)
285

    
286
            if updateProgress: updateProgress.emit(self.maxValue)
287
        except Exception as ex:
288
            from App import App
289

    
290
            message = 'error occurred({}) in {}:{}'.format(ex, sys.exc_info()[-1].tb_frame.f_code.co_filename,
291
                                                           sys.exc_info()[-1].tb_lineno)
292
            App.mainWnd().addMessage.emit(MessageType.Error, message)
293

    
294
    '''
295
        @brief      find objects connected to given line while loop
296
        @author     humkyung
297
        @date       2018.04.16
298
        @history    humkyung 2018.05.08 find symbol or line connected to given object
299
                    humkyung 2018.05.10 set found object's owner
300
                    humkyung 2018.05.17 try to connect both symbol and line
301
                    humkyung 2018.06.22 order connected objects
302
    '''
303

    
304
    def find_connected_objects(self, start, to=None, primary=False, include_signal=True):
305
        from EngineeringLineItem import QEngineeringLineItem
306
        from EngineeringEquipmentItem import QEngineeringEquipmentItem
307
        from EngineeringInstrumentItem import QEngineeringInstrumentItem
308
        from SymbolSvgItem import SymbolSvgItem
309

    
310
        visited = [start]
311
        break_at_first = None
312

    
313
        try:
314
            pool = []
315
            pool.append((0, start))
316

    
317
            while len(pool) > 0:
318
                sign, obj = pool.pop()
319

    
320
                # """ check obj is upstream or downstream of spec break """
321
                # matches = [spec_break for spec_break in self._spec_breaks if spec_break.is_connected(obj)]
322
                # if matches or issubclass(type(obj), QEngineeringEquipmentItem):
323
                #    visited.pop(visited.index(obj))
324
                #    continue
325
                # print('obj={} pool={}'.format(obj, pool))
326

    
327
                match = False
328
                if not primary:
329
                    for end_break in self._end_breaks:
330
                        if obj is end_break.owner or obj is end_break.prop('Connected Item'):
331
                            if end_break.owner.is_connected(end_break.prop('Connected Item')) and \
332
                                    end_break.prop('Connected Item').is_connected(end_break.owner) and \
333
                                    len(visited) is not 1:
334
                                match = True
335
                                if obj.is_connected(break_at_first):
336
                                    visited.pop(visited.index(obj))
337
                                break
338
                            elif end_break.owner.is_connected(end_break.prop('Connected Item')) and \
339
                                    end_break.prop('Connected Item').is_connected(end_break.owner):
340
                                break_at_first = obj
341
                                break
342

    
343
                if issubclass(type(obj), QEngineeringEquipmentItem):
344
                    visited.pop(visited.index(obj))
345
                    continue
346
                elif match:
347
                    continue
348

    
349
                """ end loop if obj is to """
350
                if to is not None and str(obj.uid) == str(to.uid): break
351

    
352
                # nextmatches list always has one item
353
                if type(obj) is QEngineeringLineItem:
354
                    symbolMatches = [x for x in self._symbols if (x.owner is None or x.owner == start.owner) and (
355
                            x not in visited) and obj.is_connected(x)]
356
                    if include_signal:
357
                        lineMatches = [x for x in self._lines if
358
                                       (x.owner is None or x.owner == start.owner) and (x is not obj) and (
359
                                               x not in visited) and obj.is_connected(x)]
360
                    else:
361
                        lineMatches = [x for x in self._lines if
362
                                       x.is_piping() and (x.owner is None or x.owner == start.owner) and (
363
                                               x is not obj) and (x not in visited) and obj.is_connected(x)]
364
                    nextMatches = symbolMatches + lineMatches
365

    
366
                elif issubclass(type(obj), SymbolSvgItem):
367
                    # symbol can be connected with line and another symbol at the same time
368
                    if include_signal:
369
                        lineMatches = [x for x in self._lines if (x.owner is None or x.owner == start.owner) and (
370
                                x not in visited) and obj.is_connected(x)]
371
                    else:
372
                        lineMatches = [x for x in self._lines if
373
                                       x.is_piping() and (x.owner is None or x.owner == start.owner) and (
374
                                               x not in visited) and obj.is_connected(x)]
375
                    symbolMatches = [x for x in self._symbols if
376
                                     (x.owner is None or x.owner == start.owner) and (x is not obj) and (
377
                                             x not in visited) and obj.is_connected(x, None)]
378
                    nextMatches = symbolMatches + lineMatches
379

    
380
                    if len(nextMatches) > 1:  # choose one if connected items are more than 2
381
                        matches = [x for x in visited if obj.is_connected(x)]
382
                        if matches:
383
                            next_connected = [x for x in nextMatches if obj.next_connected(x, matches[0])]
384

    
385
                            if next_connected:
386
                                nextMatches = next_connected
387
                            else:
388
                                nextMatches = []
389

    
390
                    # if obj symbol has break connector and nextMatch connected that connector than break line group
391
                    if nextMatches and obj.break_connector and [index for index in obj.break_connector if
392
                                                                obj.connectors[index].connectedItem is nextMatches[0]]:
393
                        match = True
394
                        break
395

    
396
                # if obj item connected symbol that has break connector then break line group
397
                if nextMatches:
398
                    pop_index = []
399
                    index = 0
400
                    for nextMatch in nextMatches:
401
                        if hasattr(nextMatch, 'break_connector'):
402
                            if [index for index in nextMatch.break_connector if
403
                                nextMatch.connectors[index].connectedItem is obj]:
404
                                pop_index.append(index)
405
                        index += 1
406

    
407
                    for index in reversed(pop_index):
408
                        nextMatches.pop(index)
409

    
410
                # order connected objects
411
                matches = []
412
                matches.extend(nextMatches)
413

    
414
                if sign == 0 and len(matches) > 1:
415
                    mid = int(len(matches) * 0.5)
416
                    lhs = matches[0:mid]
417
                    rhs = matches[mid:]
418
                elif sign == -1:
419
                    lhs = matches
420
                    rhs = []
421
                else:
422
                    lhs = []
423
                    rhs = matches
424

    
425
                for match in lhs:
426
                    # print(match)
427
                    pool.append((-1, match))
428
                    visited.insert(0, match)
429

    
430
                for match in rhs:
431
                    # print(match)
432
                    pool.append((1, match))
433
                    visited.append(match)
434
                # up to here
435

    
436
        except Exception as ex:
437
            from App import App
438

    
439
            message = 'error occurred({}) in {}:{}'.format(ex, sys.exc_info()[-1].tb_frame.f_code.co_filename,
440
                                                           sys.exc_info()[-1].tb_lineno)
441
            App.mainWnd().addMessage.emit(MessageType.Error, message)
442

    
443
        # print(visited)
444
        return visited
445

    
446

    
447
'''
448
    @brief      connect attributes
449
    @author     humkyung
450
    @date       2018.06.17
451
    @history    humkyung 2018.06.21 paste connect attributes codes from recognizeLine function
452
                kyouho  2018.09.14  clear Item's owner 
453
'''
454
async def connectAttrImpl(worker, update_line_type, update_flow_mark, update_spec, update_stream_no):
455
    from App import App
456
    import uuid
457
    from LineNoTracer import LineNoTracer
458
    from AppDocData import AppDocData
459
    from EngineeringAbstractItem import QEngineeringAbstractItem
460
    from EngineeringSpecBreakItem import QEngineeringSpecBreakItem
461
    from EngineeringInstrumentItem import QEngineeringInstrumentItem
462
    from EngineeringReducerItem import QEngineeringReducerItem
463
    from EngineeringEquipmentItem import QEngineeringEquipmentItem
464
    from QEngineeringOPCItem import QEngineeringOPCItem
465
    from EngineeringSpecBreakItem import QEngineeringSpecBreakItem
466
    from EngineeringVendorItem import QEngineeringVendorItem
467
    from EngineeringEndBreakItem import QEngineeringEndBreakItem
468
    from EngineeringFlowMarkItem import QEngineeringFlowMarkItem
469
    from EngineeringReservedWordTextItem import QEngineeringReservedWordTextItem
470
    from QEngineeringSizeTextItem import QEngineeringSizeTextItem
471
    from EngineeringValveOperCodeTextItem import QEngineeringValveOperCodeTextItem
472
    from QEngineeringTrimLineNoTextItem import QEngineeringTrimLineNoTextItem
473
    from QEngineeringTagNoTextItem import QEngineeringTagNoTextItem
474
    from EngineeringErrorItem import QEngineeringErrorItem
475
    from EngineeringTextItem import QEngineeringTextItem
476
    from SpecialItemTypesDialog import SpecialItemTracer
477

    
478
    try:
479
        docdata = AppDocData.instance()
480
        worker.display_message.emit('Initializing...')
481

    
482
        ALL_ITEM = [item for item in worker.scene.items() if issubclass(type(item), QEngineeringAbstractItem)]
483
        for item in ALL_ITEM:
484
            item.setVisible(False)
485
        QApplication.processEvents()
486

    
487
        symbols = []
488
        lines = [item for item in worker.scene.items() if type(item) is QEngineeringLineItem]
489
        for line in lines:
490
            line._skip = False
491
        lineNos = []
492
        spec_breaks = []
493
        lineIndicator = []
494
        vendor_packages = [item for item in worker.scene.items() if
495
                           type(item) is QEngineeringVendorItem and item.pack_type == 'Vendor Package']
496
        equip_packages = [item for item in worker.scene.items() if
497
                          type(item) is QEngineeringVendorItem and item.pack_type == 'Equipment Package']
498
        end_breaks = []
499
        notes = []
500
        flow_marks = []
501

    
502
        for error_item in [item for item in worker.scene.items() if type(item) is QEngineeringErrorItem]:
503
            error_item.transfer.onRemoved.emit(error_item)
504

    
505
        for end_break in [item for item in worker.scene.items() if type(item) is QEngineeringEndBreakItem]:
506
            if not end_break.prop('Freeze'):
507
                end_break.transfer.onRemoved.emit(end_break)
508
            else:
509
                end_breaks.append(end_break)
510

    
511
        QApplication.processEvents()
512

    
513
        '''
514
        for flow_mark in [item for item in worker.scene.items() if type(item) is QEngineeringFlowMarkItem]:
515
            if not flow_mark.prop('Freeze'):
516
                flow_mark.transfer.onRemoved.emit(flow_mark)
517
            else:
518
                flow_marks.append(flow_mark)
519
        '''
520

    
521
        configs = docdata.getConfigs('Supplied by Tag Rule', 'by Vendor')
522
        vendorTag = configs[0].value if configs else 'By Vendor'
523
        for item in worker.scene.items():
524
            if type(item) is QEngineeringSpecBreakItem:
525
                spec_breaks.append(item)
526
            elif issubclass(type(item), SymbolSvgItem) and not (type(item) is QEngineeringErrorItem) and not (
527
                    type(item) is QEngineeringUnknownItem) and item.type != 'Notes' and not (
528
                    type(item) is QEngineeringEndBreakItem):
529
                matches = [vendor_package for vendor_package in vendor_packages if vendor_package.includes(item)]
530
                if matches:
531
                    item.set_property('Supplied By', vendorTag)
532
                else:
533
                    item.set_property('Supplied By', '')
534
                symbols.append(item)
535
            elif type(item) is QEngineeringLineNoTextItem:
536
                lineNos.append(item)
537
            elif type(item) is QEngineeringLineItem:
538
                # matches = [vendor_package for vendor_package in vendor_packages if vendor_package.includes(item)]
539
                # if not matches: lines.append(item)
540
                # for check line disappear bug
541
                pass
542
                # lines.append(item)
543
            elif type(item) is QEngineeringUnknownItem and item.lineIndicator != 'False':
544
                lineIndicator.append(item)
545
            elif issubclass(type(item), QEngineeringTextItem):
546
                item.owner = None
547
            elif item.type == 'Notes':
548
                notes.append(item)
549

    
550
        QApplication.processEvents()
551

    
552
        # remove unknown line's
553
        pastTrim = docdata.tracerLineNos
554
        treeWidget = App.mainWnd().itemTreeWidget
555
        for pastTrimIndex in reversed(range(len(pastTrim))):
556
            if type(pastTrim[pastTrimIndex]) is QEngineeringTrimLineNoTextItem:
557
                try:
558
                    connected_items = pastTrim[pastTrimIndex].getConnectedItems()
559
                    for item in connected_items:
560
                        treeWidget.addTreeItem(treeWidget.SymbolsTreeItem, item)
561
                    pastTrim[pastTrimIndex].explode()
562
                finally:
563
                    pass
564

    
565
        # trace line no
566
        tracer = LineNoTracer(symbols, lines, lineNos, spec_breaks, lineIndicator, vendor_packages, end_breaks)
567
        tracer.execute(worker.display_message, worker.updateProgress)
568
        # up to here
569

    
570
        # connect attribute
571
        worker.display_message.emit('Connecting Attribute...')
572
        QApplication.processEvents()
573
        texts = [item for item in worker.scene.items() if issubclass(type(item), QEngineeringTextItem)]
574
        for symbol in symbols:
575
            try:
576
                if symbol.iType == 18 or symbol.iType == 31: # opc will be checked later
577
                    symbol.clear_attr_and_assoc_item()
578
                    continue
579
                symbol.connectAttribute(texts)
580
            except Exception as ex:
581
                message = 'error occurred({}) in {}:{}'.format(repr(ex), sys.exc_info()[-1].tb_frame.f_code.co_filename,
582
                                                               sys.exc_info()[-1].tb_lineno)
583
                worker.display_message.emit(message)
584

    
585
        '''
586
        # clear line
587
        for line in lines:
588
            try:
589
                line.clear_attr_and_assoc_item()
590
            except Exception as ex:
591
                message = 'error occurred({}) in {}:{}'.format(repr(ex), sys.exc_info()[-1].tb_frame.f_code.co_filename,
592
                                                               sys.exc_info()[-1].tb_lineno)
593
                worker.display_message.emit(message)
594
        '''
595

    
596
        """ try to connect label to valve """
597
        labels = [symbol for symbol in symbols if symbol.iType == 19]  # Labels - Symbol => Instrument
598
        valves = [symbol for symbol in symbols if
599
                  symbol.iType == 34 or symbol.iType == 17 or symbol.iType == 22]  # Specialty Components, In-Line, Relief Devices
600
        for label in labels:
601
            label.connectAttribute(valves, clear=False)
602

    
603
        # for slope, etc.., symbol to line
604
        labels = [symbol for symbol in symbols if symbol.iType == 30]  # Labels - Line => Piping
605
        for label in labels:
606
            label.connectAttribute(lines, clear=False)
607

    
608
        '''
609
        # for alarm, symbol to symbol : no more used
610
        labels = [symbol for symbol in symbols if symbol.iType == 29]  # Labels - Piping Components => Instrument
611
        valves = [symbol for symbol in symbols if symbol.iType == 25]  # System Functions
612
        for label in labels:
613
            label.connectAttribute(valves, clear=False)
614
        '''
615

    
616
        QApplication.processEvents()
617
        for symbol in symbols:
618
            for assoc in symbol.associations():
619
                if assoc.owner is None and not issubclass(type(assoc), SymbolSvgItem):
620
                    assoc.owner = symbol
621

    
622
        """ restore note text item owner """
623
        for note in notes:
624
            for noteText in note.associations():
625
                noteText.owner = note
626

    
627
        """ try to find text item's owner """
628
        texts = [item for item in worker.scene.items() if type(item) is QEngineeringReservedWordTextItem]
629
        for text in texts:
630
            text.findOwner(lines)
631

    
632
        QApplication.processEvents()
633
        # restore and save manual edited attr's text item
634
        texts = [item for item in worker.scene.items() if issubclass(type(item), QEngineeringTextItem)]
635
        targetText = []
636
        for text in texts:
637
            if text.owner:
638
                continue
639
            found = False
640
            for symbol in symbols + lines:
641
                for attr in list(symbol.attrs.keys()):
642
                    # skip freezed attr or already consumed by symbol
643
                    if attr.AssocItem == text:
644
                        text.owner = symbol
645
                        found = True
646
                        break
647
                    # restore missing attr
648
                    elif type(attr.AssocItem) is str or type(attr.AssocItem) is uuid.UUID:
649
                        if str(attr.AssocItem) == str(text.uid):
650
                            symbol.add_assoc_item(text)
651
                            attr.AssocItem = text
652
                            text.owner = symbol
653
                            found = True
654
                        break
655
                if found: break
656
            if not found and (
657
                    type(text) is QEngineeringSizeTextItem or type(text) is QEngineeringValveOperCodeTextItem or \
658
                    type(text) is QEngineeringTagNoTextItem or type(text) is QEngineeringTextItem):
659
                targetText.append(text)
660

    
661
        # check opc
662
        for symbol in symbols:
663
            try:
664
                if symbol.iType == 18 or symbol.iType == 31:
665
                    symbol.connectAttribute(texts)
666
            except Exception as ex:
667
                message = 'error occurred({}) in {}:{}'.format(repr(ex), sys.exc_info()[-1].tb_frame.f_code.co_filename,
668
                                                               sys.exc_info()[-1].tb_lineno)
669
                worker.display_message.emit(message)
670

    
671
        worker.need_update_texts = []
672
        targetText = sorted(targetText, key=lambda param: len(param.text()), reverse=True)
673
        for symbol in symbols + equip_packages:
674
            symbol._skip = False
675
        for text in targetText:
676
            ret = text.findOwner(symbols) if type(text) is not QEngineeringTagNoTextItem else text.findOwner(
677
                symbols + equip_packages)
678
            if ret:
679
                worker.need_update_texts.append([text, ret])
680

    
681
        # need fix
682
        #for text in targetText: # find line size
683
        #    if type(text) is QEngineeringSizeTextItem and not text.owner:
684
        #        text.findOwner(lines)
685

    
686
        """ update line type """
687
        if update_line_type:
688
            worker.display_message.emit('Updating Line Type...')
689
            for line in lines:
690
                line.update_line_type()
691

    
692
        QApplication.processEvents()
693
        """ make end break """
694
        make_end_break(worker, end_breaks, lineNos)
695

    
696
        QApplication.processEvents()
697
        """ update spec break """
698
        if update_spec:
699
            make_spec(worker, spec_breaks, lines, lineNos)
700

    
701
        worker.updateProgress.emit(tracer.maxValue)
702

    
703
        # trace special item
704
        worker.display_message.emit('Finding line for special item...')
705
        QApplication.processEvents()
706
        tracer = SpecialItemTracer([item for item in worker.scene.items() if
707
                                    (type(item) is SymbolSvgItem or type(item) is QEngineeringTextItem) and
708
                                    item.special_item_type], lines)
709
        tracer.execute(worker.display_message, worker.updateProgress)
710
        # up to here
711

    
712
        ''' sort run flow order '''
713
        worker.display_message.emit('Sorting Lines...')
714
        QApplication.processEvents()
715
        sort_run_flow(worker)
716

    
717
        QApplication.processEvents()
718
        """ make flow mark """
719
        if update_flow_mark:
720
            make_flow_mark(worker, lines)
721

    
722
        ''' get line no's from/to equipment '''
723
        for lineNo in lineNos:
724
            lineNo.clear_attr_and_assoc_item()
725
            lineNo.EvaluatedEQ()
726

    
727
        ''' set stream no '''
728
        if update_stream_no:
729
            set_stream_no(worker)
730

    
731
        ''' visible on '''
732
        ALL_ITEM = [item for item in worker.scene.items() if issubclass(type(item), QEngineeringAbstractItem)]
733
        for item in ALL_ITEM:
734
            item.setVisible(True)
735

    
736
    except Exception as ex:
737
        message = 'error occurred({}) in {}:{}'.format(repr(ex), sys.exc_info()[-1].tb_frame.f_code.co_filename,
738
                                                       sys.exc_info()[-1].tb_lineno)
739
        worker.display_message.emit(message)
740
    except:
741
        (type1, value, traceback) = sys.exc_info()
742
        sys.excepthook(type1, value, traceback)
743

    
744
def set_stream_no(worker):
745
    ''' set stream no '''
746

    
747
    from App import App
748
    from SetStreamNoCommand import SetStreamCommand
749
    from LineListDialog import LineListDialog
750

    
751
    cmd = SetStreamCommand()
752
    cmd.display_message.connect(App.mainWnd().onAddMessage)
753
    cmd.execute(worker.scene)
754

    
755
    dialog = LineListDialog(None, scene=worker.scene)
756
    AppDocData.instance()._streamLineListModelDatas = dialog._model_datas
757

    
758
def make_end_break(worker, end_breaks, lineNos):
759
    ''' make end break '''
760

    
761
    from App import App
762
    import os
763

    
764
    try:
765
        docdata = AppDocData.instance()
766

    
767
        end_break_names = docdata.getSymbolListByType('type', 'End Break')
768
        if len(end_break_names) is not 0:
769
            svgFileName = end_break_names[0].sName
770
            symbol = end_break_names[0]
771
            svgFilePath = os.path.join(docdata.getCurrentProject().getSvgFilePath(), symbol.getType(),
772
                                       svgFileName + '.svg')
773

    
774
            lineNo_froms = []
775
            lineNo_tos = []
776

    
777
            for lineNo in lineNos:
778
                # lineNo_froms.append(lineNo.prop('From')) if lineNo.prop('From') is not None else None
779
                # lineNo_tos.append(lineNo.prop('To')) if lineNo.prop('To') is not None else None
780

    
781
                for run in lineNo.runs:
782
                    start = [run.items[0]]
783
                    end = [run.items[-1]] if run.items[0] is not run.items[-1] else []
784
                    lineNo_froms.extend(start)
785
                    lineNo_tos.extend(end)
786

    
787
            for line_end in lineNo_froms + lineNo_tos:
788
                # print(type(line_end))
789
                for connector in line_end.connectors:
790
                    if connector.connectedItem is not None and type(
791
                            connector.connectedItem.owner) is QEngineeringLineNoTextItem and connector.connectedItem.owner is not line_end.owner:
792
                        end_break = SymbolSvgItem.createItem(symbol.getType(), None, svgFilePath)
793
                        pt = [connector.center()[0] - float(symbol.getOriginalPoint().split(',')[0]),
794
                              connector.center()[1] - float(symbol.getOriginalPoint().split(',')[1])]
795
                        origin = [0, 0]
796
                        if 2 == len(symbol.getOriginalPoint().split(',')):
797
                            tokens = symbol.getOriginalPoint().split(',')
798
                            origin = [pt[0] + float(tokens[0]), pt[1] + float(tokens[1])]
799
                        end_break.buildItem(svgFileName, symbol.getType(), 3.83, pt,
800
                                            [end_break.boundingRect().width(), end_break.boundingRect().height()],
801
                                            origin, [], symbol.getBaseSymbol(), symbol.getAdditionalSymbol(),
802
                                            symbol.getHasInstrumentLabel())
803

    
804
                        end_break.set_property('Connected Item', connector.connectedItem)
805
                        end_break.setToolTip('owner : ' + str(line_end))
806
                        end_break.area = 'Drawing'
807
                        end_break.owner = line_end
808
                        end_breaks.append(end_break)
809

    
810
            if end_breaks:
811
                # check duplication
812
                dupl = set()
813
                for i in range(len(end_breaks)):
814
                    for j in range(len(end_breaks)):
815
                        if i == j:
816
                            continue
817
                        else:
818
                            setI = set([end_breaks[i].owner, end_breaks[i].prop('Connected Item')])
819
                            setJ = set([end_breaks[j].owner, end_breaks[j].prop('Connected Item')])
820
                            if not (setI - setJ):
821
                                index = [i, j]
822
                                index.sort()
823
                                index = tuple(index)
824
                                dupl.add(index)
825
                # print(dupl)
826
                dupl = list(set(
827
                    [(indexSet[1] if not end_breaks[indexSet[1]].prop('Freeze') else indexSet[0]) for indexSet in
828
                     list(dupl)]))
829
                dupl.sort(reverse=True)
830
                # print(dupl)
831
                for index in dupl:
832
                    end_breaks.pop(index)
833

    
834
                for end_break in end_breaks:
835
                    if not end_break.prop('Freeze'):
836
                        end_break.transfer.onRemoved.connect(App.mainWnd().itemRemoved)
837
                        # end break can be modeled only piping line
838
                        if (type(end_break.owner) is not QEngineeringLineItem or (
839
                                type(end_break.owner) is QEngineeringLineItem and (
840
                                end_break.owner.lineType == 'Secondary' or end_break.owner.lineType == 'Primary'))) \
841
                                and (type(end_break.prop('Connected Item')) is not QEngineeringLineItem or (
842
                                type(end_break.prop('Connected Item')) is QEngineeringLineItem and (
843
                                end_break.prop('Connected Item').lineType == 'Secondary' or end_break.prop(
844
                            'Connected Item').lineType == 'Primary'))):
845
                            end_break.addSvgItemToScene(worker.scene)
846

    
847
    except Exception as ex:
848
        message = 'error occurred({}) in {}:{}'.format(repr(ex), sys.exc_info()[-1].tb_frame.f_code.co_filename,
849
                                                       sys.exc_info()[-1].tb_lineno)
850
        worker.display_message.emit(message)
851

    
852

    
853
def make_spec(worker, spec_breaks, lines, lineNos):
854
    ''' update spec break '''
855

    
856
    from App import App
857
    import os, math
858

    
859
    try:
860
        docdata = AppDocData.instance()
861

    
862
        freezed_spec_breaks = []
863
        for spec_break in spec_breaks:
864
            if not spec_break.prop('Freeze'):
865
                spec_break.transfer.onRemoved.emit(spec_break)
866
            else:
867
                freezed_spec_breaks.append(spec_break)
868

    
869
        for line in lines:
870
            line.clear_labels()
871

    
872
        spec_break_names = docdata.getSymbolListByType('type', 'Segment Breaks')
873
        if len(spec_break_names) is not 0:
874
            configs = docdata.getConfigs('Range', 'Detection Ratio')
875
            ratio = float(configs[0].value) if 1 == len(configs) else 1.5
876
            ratio *= 2
877

    
878
            svgFileName = spec_break_names[0].sName
879
            symbol = spec_break_names[0]
880
            svgFilePath = os.path.join(docdata.getCurrentProject().getSvgFilePath(), symbol.getType(),
881
                                       svgFileName + '.svg')
882

    
883
            specBreakAttrsFull = [attr for attr in docdata.getSymbolAttribute('Segment Breaks') if
884
                                  attr.Target == 'ALL' and (
885
                                          attr.AttributeType == 'Spec' or attr.AttributeType == 'String')]
886
            specBreakAttrs = [attr.Attribute for attr in specBreakAttrsFull]
887

    
888
            line_ends = []
889
            # append upstream first and append downstream
890
            for lineNo in lineNos:
891
                for run in lineNo.runs:
892
                    line_ends.append(run.items[0]) if issubclass(type(run.items[0]), SymbolSvgItem) or (
893
                            type(run.items[0]) is QEngineeringLineItem and (
894
                            run.items[0].lineType == 'Secondary' or run.items[
895
                        0].lineType == 'Primary')) else None
896
            for lineNo in lineNos:
897
                for run in lineNo.runs:
898
                    if run.items[0] is not run.items[-1]:
899
                        line_ends.append(run.items[-1]) if issubclass(type(run.items[-1]), SymbolSvgItem) or (
900
                                type(run.items[-1]) is QEngineeringLineItem and (
901
                                run.items[-1].lineType == 'Secondary' or run.items[
902
                            -1].lineType == 'Primary')) else None
903

    
904
            spec_breaks = []
905
            for line_end in line_ends:
906
                for connector in line_end.connectors:
907
                    if connector.connectedItem is not None and type(
908
                            connector.connectedItem.owner) is QEngineeringLineNoTextItem and connector.connectedItem.owner is not line_end.owner:
909
                        spec_break = []  # upstream, downstream, [spec, up value, down value], ... , [ ... ]
910
                        match = False
911
                        for prop, value in [[prop, value] for prop, value in line_end.owner.getAttributes().items()
912
                                            if prop.Attribute in specBreakAttrs]:
913
                            for prop2, value2 in [[prop2, value2] for prop2, value2 in
914
                                                  connector.connectedItem.owner.getAttributes().items() if
915
                                                  prop2.Attribute in specBreakAttrs and prop2.UID == prop.UID]:
916
                                if str(prop.UID) == str(prop2.UID) and value != value2:
917
                                    if not match:
918
                                        spec_break.extend([line_end, connector.connectedItem])
919
                                        match = True
920
                                    spec_break.append([prop.Attribute, value, value2])
921
                        if match:
922
                            spec_breaks.append(spec_break)
923

    
924
            if spec_breaks:
925
                # check duplication
926
                dupl = set()
927
                for i in range(len(spec_breaks)):
928
                    for j in range(len(spec_breaks)):
929
                        if i == j:
930
                            continue
931
                        else:
932
                            setI = set([spec_breaks[i][0], spec_breaks[i][1]])
933
                            setJ = set([spec_breaks[j][0], spec_breaks[j][1]])
934
                            if not (setI - setJ):
935
                                index = [i, j]
936
                                index.sort()
937
                                index = tuple(index)
938
                                dupl.add(index)
939
                dupl = list(set([(indexSet[1]) for indexSet in list(dupl)]))
940
                dupl.sort(reverse=True)
941
                for index in dupl:
942
                    spec_breaks.pop(index)
943
                # up to here
944

    
945
                spec_break_items = []
946
                for spec in spec_breaks:
947
                    dupl = False
948
                    for freezed in freezed_spec_breaks:
949
                        freezed_attrs = freezed.getAttributes()
950
                        up = [attr.AssocItem for attr in freezed_attrs if attr.Attribute == 'UpStream']
951
                        down = [attr.AssocItem for attr in freezed_attrs if attr.Attribute == 'DownStream']
952
                        if up and down:
953
                            if (up[0] is spec[0] and down[0] is spec[1]) or (
954
                                    up[0] is spec[1] and down[0] is spec[0]):
955
                                dupl = True
956
                                break
957
                    if dupl:
958
                        continue
959

    
960
                    for connector in spec[0].connectors:
961
                        if connector.connectedItem is spec[1]:
962
                            spec_break = SymbolSvgItem.createItem(symbol.getType(), None, svgFilePath)
963
                            pt = [40 + connector.center()[0] - float(symbol.getOriginalPoint().split(',')[0]),
964
                                  60 + connector.center()[1] - float(symbol.getOriginalPoint().split(',')[1])]
965
                            origin = [0, 0]
966
                            if 2 == len(symbol.getOriginalPoint().split(',')):
967
                                tokens = symbol.getOriginalPoint().split(',')
968
                                origin = [pt[0] + float(tokens[0]), pt[1] + float(tokens[1])]
969
                            spec_break.buildItem(svgFileName, symbol.getType(), 3.14, pt,
970
                                                 [spec_break.boundingRect().width(),
971
                                                  spec_break.boundingRect().height()], origin, [],
972
                                                 symbol.getBaseSymbol(), symbol.getAdditionalSymbol(),
973
                                                 symbol.getHasInstrumentLabel())
974

    
975
                            attrs = spec_break.getAttributes()
976
                            for key in attrs.keys():
977
                                if key.Attribute == 'UpStream':
978
                                    attrs[key] = str(spec[0])
979
                                    spec_break.add_assoc_item(spec[0], key.AttrAt, force=True)
980
                                    key.AssocItem = spec[0]
981
                                elif key.Attribute == 'DownStream':
982
                                    attrs[key] = str(spec[1])
983
                                    spec_break.add_assoc_item(spec[1], key.AttrAt, force=True)
984
                                    key.AssocItem = spec[1]
985

    
986
                            for attr, value, value2 in spec[2:]:
987
                                for full in specBreakAttrsFull:
988
                                    if full.Attribute == attr:
989
                                        attrs[full] = [value, value2]
990

    
991
                            # find label text for spec break line
992
                            stream_line = [spec[0], spec[1]]
993
                            stream_track = [spec[1], spec[0]]
994
                            stream_res = [False, False]
995
                            for index in range(len(stream_line)):
996
                                while True:
997
                                    if type(stream_line[index]) is QEngineeringLineItem:
998
                                        stream_res[index] = True
999
                                        break
1000
                                    else:
1001
                                        find_next = False
1002
                                        connected_count = 0
1003
                                        for connectorr in stream_line[index].connectors:
1004
                                            connected_count += 1
1005
                                            if connectorr.connectedItem and stream_track[
1006
                                                index] is not connectorr.connectedItem and stream_line[
1007
                                                index].next_connected(stream_track[index],
1008
                                                                      connectorr.connectedItem):
1009
                                                stream_track[index] = stream_line[index]
1010
                                                stream_line[index] = connectorr.connectedItem
1011
                                                find_next = True
1012
                                                break
1013

    
1014
                                        if not find_next:
1015
                                            # prevent infinite loop
1016
                                            if connected_count == 2:
1017
                                                for connectorr in stream_line[index].connectors:
1018
                                                    if connectorr.connectedItem and not connectorr.connectedItem is \
1019
                                                                                        stream_track[index]:
1020
                                                        stream_line[index] = connectorr.connectedItem
1021
                                                        stream_track[index] = stream_line[index]
1022
                                                        find_next = True
1023
                                                        break
1024
                                                if not find_next:
1025
                                                    break
1026
                                            else:
1027
                                                break
1028

    
1029
                            if stream_res[0] and stream_res[1]:
1030
                                texts = [item for item in worker.scene.items() if
1031
                                         type(item) is QEngineeringTextItem and item.owner is None]
1032
                                positioning = False
1033

    
1034
                                for attr, value, value2 in spec[2:]:
1035
                                    up_texts = [text for text in texts if text.text() == value]
1036
                                    down_texts = [text for text in texts if text.text() == value2]
1037
                                    up_down_texts = [up_texts, down_texts]
1038
                                    up_down_find = [None, None]
1039

    
1040
                                    for index in range(len(up_down_texts)):
1041
                                        minDist = sys.maxsize
1042

    
1043
                                        for up_down_text in up_down_texts[index]:
1044
                                            dx = connector.center()[0] - up_down_text.center().x()
1045
                                            dy = connector.center()[1] - up_down_text.center().y()
1046
                                            dist = (
1047
                                                           up_down_text.sceneBoundingRect().height() + up_down_text.sceneBoundingRect().width()) * ratio / 2
1048
                                            length = math.sqrt(dx * dx + dy * dy)
1049
                                            if length < dist and length < minDist:
1050
                                                up_down_find[index] = up_down_text
1051

    
1052
                                    if up_down_find[0] and up_down_find[1]:
1053
                                        for index in range(len(stream_line)):
1054
                                            attrs = stream_line[index].getAttributes()
1055
                                            for key in attrs.keys():
1056
                                                if key.Attribute == attr:
1057
                                                    attrs[key] = up_down_find[index].text()
1058
                                                    key.AssocItem = up_down_find[index]
1059
                                                    stream_line[index].add_assoc_item(up_down_find[index],
1060
                                                                                      key.AttrAt, force=True)
1061
                                                    up_down_find[index].owner = stream_line[index]
1062
                                                    break
1063

    
1064
                                        if not positioning:
1065
                                            # set spec break position between
1066
                                            positioning = True
1067
                                            new_x = round(
1068
                                                (up_down_find[0].center().x() + up_down_find[1].center().x()) / 2)
1069
                                            new_y = round(
1070
                                                (up_down_find[0].center().y() + up_down_find[1].center().y()) / 2)
1071
                                            spec_break.loc = [new_x - spec_break.symbolOrigin[0],
1072
                                                              new_y - spec_break.symbolOrigin[1]]
1073
                                            spec_break.origin = [new_x, new_y]
1074

    
1075
                                            pivot = None
1076
                                            for connector in spec[0].connectors:
1077
                                                if connector.connectedItem is spec[1]:
1078
                                                    pivot = connector.sceneBoundingRect().center()
1079
                                                    break
1080

    
1081
                                            if abs(up_down_find[0].center().x() - up_down_find[
1082
                                                1].center().x()) < abs(
1083
                                                up_down_find[0].center().y() - up_down_find[1].center().y()):
1084
                                                if new_x > pivot.x():
1085
                                                    spec_break.angle = 1.57
1086
                                                else:
1087
                                                    spec_break.angle = 4.71239
1088
                                            else:
1089
                                                if new_y > pivot.y():
1090
                                                    spec_break.angle = 3.14
1091
                                                else:
1092
                                                    spec_break.angle = 0
1093

    
1094
                                            # make show prop true
1095
                                            spec_break.set_property('Show', True)
1096

    
1097
                            spec_break_items.append(spec_break)
1098

    
1099
                for spec_break_item in spec_break_items:
1100
                    spec_break_item.transfer.onRemoved.connect(App.mainWnd().itemRemoved)
1101
                    spec_break_item.addSvgItemToScene(worker.scene)
1102

    
1103
                spec_break_items.extend(freezed_spec_breaks)
1104
    except Exception as ex:
1105
        message = 'error occurred({}) in {}:{}'.format(repr(ex), sys.exc_info()[-1].tb_frame.f_code.co_filename,
1106
                                                       sys.exc_info()[-1].tb_lineno)
1107
        worker.display_message.emit(message)
1108

    
1109

    
1110
def make_flow_mark(worker, lines):
1111
    ''' make flow mark '''
1112

    
1113
    try:
1114
        docdata = AppDocData.instance()
1115

    
1116
        for line in lines:
1117
            line.flowMark = None
1118
            # line.update_arrow()
1119

    
1120
        configs = docdata.getConfigs('Flow Mark', 'Position')
1121
        position = int(configs[0].value) if 1 == len(configs) else 100
1122
        configs = docdata.getConfigs('Flow Mark', 'Length')
1123
        length = int(configs[0].value) if 1 == len(configs) else 200
1124

    
1125
        for line in [line for line in lines if line.is_piping(True)]:
1126
            line.update_flow_mark(position, length)
1127
            line.update_arrow()
1128
        # for lineNo in docdata.tracerLineNos:
1129
        #    lineNo.update_flow_mark(position, length)
1130

    
1131
    except Exception as ex:
1132
        message = 'error occurred({}) in {}:{}'.format(repr(ex), sys.exc_info()[-1].tb_frame.f_code.co_filename,
1133
                                                       sys.exc_info()[-1].tb_lineno)
1134
        worker.display_message.emit(message)
1135

    
1136

    
1137
def sort_run_flow(worker):
1138
    ''' sort runs '''
1139

    
1140
    from EngineeringLineTracerRunItem import QEngineeringLineTracerRunItem
1141

    
1142
    try:
1143
        docdata = AppDocData.instance()
1144

    
1145
        fixed_run_infos = []  # QEngineeringLineTracerRunItem s
1146
        waiting_run_infos = []  # QEngineeringLineTracerRunItem s
1147
        runs = []
1148
        # first step : make fixed run using symbol info
1149
        for lineNo in [lineNo for lineNo in docdata.tracerLineNos if len(lineNo.runs) > 0]:
1150
            not_trim = True if type(lineNo) is QEngineeringLineNoTextItem else False
1151
            run_index = 0
1152
            for run in lineNo.runs:
1153
                not_secondary = True if run_index is 0 else False
1154

    
1155
                # if from and to info already was entered, fix run flow
1156
                if hasattr(lineNo, '_fixed') and lineNo._fixed and not_secondary:
1157
                    fixed_run_infos.append(QEngineeringLineTracerRunItem(run, lineNo, not_trim, not_secondary))
1158
                    run_index += 1
1159
                    continue
1160

    
1161
                reference_symbols = [item for item in run.items if
1162
                                     issubclass(type(item), SymbolSvgItem) and item.has_in_out_connector()]
1163
                # runs can know flow directly
1164
                if len(run.items) > 1 and len(reference_symbols) > 0:
1165
                    for reference_symbol in reference_symbols:
1166
                        # place at first
1167
                        if reference_symbol is run.items[0]:
1168
                            if len([connector_index for connector_index in reference_symbol.in_out_connector[0] \
1169
                                    if reference_symbol.connectors[connector_index].connectedItem is run.items[1]]) > 0:
1170
                                info = QEngineeringLineTracerRunItem(run, lineNo, not_trim, not_secondary)
1171
                                info.reverse()
1172
                                fixed_run_infos.append(info)
1173
                                break
1174
                            elif len([connector_index for connector_index in reference_symbol.in_out_connector[1] \
1175
                                      if
1176
                                      reference_symbol.connectors[connector_index].connectedItem is run.items[1]]) > 0:
1177
                                info = QEngineeringLineTracerRunItem(run, lineNo, not_trim, not_secondary)
1178
                                fixed_run_infos.append(info)
1179
                                break
1180
                        # place at last
1181
                        elif reference_symbol is run.items[-1]:
1182
                            if len([connector_index for connector_index in reference_symbol.in_out_connector[1] \
1183
                                    if
1184
                                    reference_symbol.connectors[connector_index].connectedItem is run.items[-2]]) > 0:
1185
                                info = QEngineeringLineTracerRunItem(run, lineNo, not_trim, not_secondary)
1186
                                info.reverse()
1187
                                fixed_run_infos.append(info)
1188
                                break
1189
                            elif len([connector_index for connector_index in reference_symbol.in_out_connector[0] \
1190
                                      if
1191
                                      reference_symbol.connectors[connector_index].connectedItem is run.items[-2]]) > 0:
1192
                                info = QEngineeringLineTracerRunItem(run, lineNo, not_trim, not_secondary)
1193
                                fixed_run_infos.append(info)
1194
                                break
1195
                        # place at middle
1196
                        else:
1197
                            in_items = [reference_symbol.connectors[connector_index].connectedItem for connector_index
1198
                                        in reference_symbol.in_out_connector[0] \
1199
                                        if reference_symbol.connectors[connector_index].connectedItem in run.items]
1200
                            out_items = [reference_symbol.connectors[connector_index].connectedItem for connector_index
1201
                                         in reference_symbol.in_out_connector[1] \
1202
                                         if reference_symbol.connectors[connector_index].connectedItem in run.items]
1203
                            in_item = in_items[0] if in_items else None
1204
                            out_item = out_items[0] if out_items else None
1205
                            if in_item and out_item:
1206
                                in_item_index = run.items.index(in_item)
1207
                                out_item_index = run.items.index(out_item)
1208
                                if out_item_index < in_item_index:
1209
                                    info = QEngineeringLineTracerRunItem(run, lineNo, not_trim, not_secondary)
1210
                                    info.reverse()
1211
                                    fixed_run_infos.append(info)
1212
                                    break
1213
                                else:
1214
                                    info = QEngineeringLineTracerRunItem(run, lineNo, not_trim, not_secondary)
1215
                                    fixed_run_infos.append(info)
1216
                                    break
1217
                # only symbol runs doesn't need flow
1218
                elif len(run.items) is 1 and issubclass(type(run.items[0]), SymbolSvgItem):
1219
                    runs.append(QEngineeringLineTracerRunItem(run, lineNo, not_trim, not_secondary))
1220
                # runs can't know flow directly
1221
                else:
1222
                    waiting_run_infos.append(QEngineeringLineTracerRunItem(run, lineNo, not_trim, not_secondary))
1223

    
1224
                run_index += 1
1225

    
1226
        QApplication.processEvents()
1227
        # second step : determine waiting run flow, connected by point
1228
        remain_count_past = len(waiting_run_infos)
1229
        while True:
1230
            remain_count = 0
1231
            for run_index in reversed(range(len(waiting_run_infos))):
1232
                waiting_run_info = waiting_run_infos[run_index]
1233
                waiting_run = waiting_run_info.run
1234

    
1235
                find = False
1236
                for fixed_run_info in fixed_run_infos:
1237
                    fixed_run = fixed_run_info.run
1238
                    if len(waiting_run.items) > 1 and len(fixed_run.items) > 1:
1239
                        # waiting_run and fix_run have items more than 2
1240
                        if waiting_run.items[0].is_connected(fixed_run.items[0]):
1241
                            waiting_run_info.reverse()
1242
                            fixed_run_infos.append(waiting_run_info)
1243
                            waiting_run_infos.pop(run_index)
1244
                            find = True
1245
                            break
1246
                        elif waiting_run.items[0].is_connected(fixed_run.items[-1]):
1247
                            fixed_run_infos.append(waiting_run_info)
1248
                            waiting_run_infos.pop(run_index)
1249
                            find = True
1250
                            break
1251
                        elif waiting_run.items[-1].is_connected(fixed_run.items[-1]):
1252
                            waiting_run_info.reverse()
1253
                            fixed_run_infos.append(waiting_run_info)
1254
                            waiting_run_infos.pop(run_index)
1255
                            find = True
1256
                            break
1257
                        elif waiting_run.items[-1].is_connected(fixed_run.items[0]):
1258
                            fixed_run_infos.append(waiting_run_info)
1259
                            waiting_run_infos.pop(run_index)
1260
                            find = True
1261
                            break
1262
                    elif len(fixed_run.items) > 1:
1263
                        # waiting_run is single line
1264
                        if waiting_run.items[0].connectors[0].connectedItem is fixed_run.items[0]:
1265
                            waiting_run_info.reverse()
1266
                            fixed_run_infos.append(waiting_run_info)
1267
                            waiting_run_infos.pop(run_index)
1268
                            find = True
1269
                            break
1270
                        elif waiting_run.items[0].connectors[0].connectedItem is fixed_run.items[-1]:
1271
                            fixed_run_infos.append(waiting_run_info)
1272
                            waiting_run_infos.pop(run_index)
1273
                            find = True
1274
                            break
1275
                        elif waiting_run.items[0].connectors[1].connectedItem is fixed_run.items[-1]:
1276
                            waiting_run_info.reverse()
1277
                            fixed_run_infos.append(waiting_run_info)
1278
                            waiting_run_infos.pop(run_index)
1279
                            find = True
1280
                            break
1281
                        elif waiting_run.items[0].connectors[1].connectedItem is fixed_run.items[0]:
1282
                            fixed_run_infos.append(waiting_run_info)
1283
                            waiting_run_infos.pop(run_index)
1284
                            find = True
1285
                            break
1286
                    else:
1287
                        if waiting_run.items[0].is_connected(fixed_run.items[0]) and fixed_run.items[0].connectors[
1288
                            0].connectedItem is waiting_run.items[0]:
1289
                            waiting_run.reverse()
1290
                            fixed_run_infos.append(waiting_run_info)
1291
                            waiting_run_infos.pop(run_index)
1292
                            find = True
1293
                            break
1294
                        elif waiting_run.items[0].is_connected(fixed_run.items[0]) and fixed_run.items[0].connectors[
1295
                            1].connectedItem is waiting_run.items[0]:
1296
                            fixed_run_infos.append(waiting_run_info)
1297
                            waiting_run_infos.pop(run_index)
1298
                            find = True
1299
                            break
1300
                        elif waiting_run.items[0].is_connected(fixed_run.items[0]) and fixed_run.items[0].connectors[
1301
                            1].connectedItem is waiting_run.items[0]:
1302
                            waiting_run.reverse()
1303
                            fixed_run_infos.append(waiting_run_info)
1304
                            waiting_run_infos.pop(run_index)
1305
                            find = True
1306
                            break
1307
                        elif waiting_run.items[0].is_connected(fixed_run.items[0]) and fixed_run.items[0].connectors[
1308
                            0].connectedItem is waiting_run.items[0]:
1309
                            fixed_run_infos.append(waiting_run_info)
1310
                            waiting_run_infos.pop(run_index)
1311
                            find = True
1312
                            break
1313
                if not find:
1314
                    remain_count += 1
1315

    
1316
            if remain_count_past == remain_count:
1317
                break
1318
            else:
1319
                remain_count_past = remain_count
1320

    
1321
        QApplication.processEvents()
1322
        # third step : body connected run sort, not split
1323
        remain_count_past = len(waiting_run_infos)
1324
        while True:
1325
            remain_count = 0
1326
            for run_index in reversed(range(len(waiting_run_infos))):
1327
                waiting_run_info = waiting_run_infos[run_index]
1328
                waiting_run = waiting_run_info.run
1329

    
1330
                find = False
1331
                for fixed_run_info in fixed_run_infos:
1332
                    fixed_run = fixed_run_info.run
1333
                    if len(waiting_run.items) > 1 and len(fixed_run.items) > 1 and type(
1334
                            waiting_run.items[0]) is QEngineeringLineItem and type(
1335
                        waiting_run.items[-1]) is QEngineeringLineItem:
1336
                        if waiting_run.items[0].connectors[0].connectedItem in fixed_run.items and \
1337
                                waiting_run.items[-1].connectors[1].connectedItem in fixed_run.items:
1338
                            if fixed_run.items.index(
1339
                                    waiting_run.items[0].connectors[0].connectedItem) > fixed_run.items.index(
1340
                                waiting_run.items[-1].connectors[1].connectedItem):
1341
                                waiting_run.reverse()
1342
                                fixed_run_infos.append(waiting_run_info)
1343
                                waiting_run_infos.pop(run_index)
1344
                                find = True
1345
                                break
1346
                            else:
1347
                                fixed_run_infos.append(waiting_run_info)
1348
                                waiting_run_infos.pop(run_index)
1349
                                find = True
1350
                                break
1351

    
1352
                if not find:
1353
                    remain_count += 1
1354

    
1355
            if remain_count_past == remain_count:
1356
                break
1357
            else:
1358
                remain_count_past = remain_count
1359

    
1360
        # fourth step : body connected split run or split owner run sort
1361
        fixed_merged_run_infos = []  # [[run_info1, run_info2, ... in order], [merged run with items]]
1362
        waiting_merged_run_infos = []  # [[run_info1, run_info2, ... in order], [merged run with items]]
1363

    
1364
        QApplication.processEvents()
1365
        # waiting run merge and sort
1366
        consumed_count_past = 0
1367
        for index1 in range(len(waiting_run_infos)):
1368
            if waiting_run_infos[index1].consumed:
1369
                continue
1370
            for index2 in range(len(waiting_run_infos)):
1371
                if index1 == index2 or waiting_run_infos[index2].consumed:
1372
                    continue
1373

    
1374
                result, merged_run_info, header, reverse = QEngineeringLineTracerRunItem.merge_and_sort_if_possible(
1375
                    waiting_run_infos[index1], waiting_run_infos[index2])
1376
                if result:
1377
                    waiting_run_infos[index1].consumed = True
1378
                    waiting_run_infos[index2].consumed = True
1379
                    consumed_count_past += 2
1380
                    if header:
1381
                        waiting_merged_run_infos.append(
1382
                            [[waiting_run_infos[index2], waiting_run_infos[index1]], merged_run_info])
1383
                    else:
1384
                        waiting_merged_run_infos.append(
1385
                            [[waiting_run_infos[index1], waiting_run_infos[index2]], merged_run_info])
1386
                    break
1387

    
1388
        QApplication.processEvents()
1389
        while True:
1390
            consumed_count = 0
1391
            for index in range(len(waiting_run_infos)):
1392
                if waiting_run_infos[index].consumed:
1393
                    consumed_count += 1
1394
                    continue
1395

    
1396
                for waiting_merged_run_info in waiting_merged_run_infos:
1397
                    result, merged_run_info, header, reverse = QEngineeringLineTracerRunItem.merge_and_sort_if_possible(
1398
                        waiting_merged_run_info[1], waiting_run_infos[index])
1399
                    if result:
1400
                        waiting_run_infos[index].consumed = True
1401
                        consumed_count += 1
1402
                        if header:
1403
                            waiting_merged_run_info[0].insert(0, waiting_run_infos[index])
1404
                            waiting_merged_run_info[1] = merged_run_info
1405
                        else:
1406
                            waiting_merged_run_info[0].append(waiting_run_infos[index])
1407
                            waiting_merged_run_info[1] = merged_run_info
1408
                        break
1409

    
1410
            if consumed_count_past == consumed_count:
1411
                break
1412
            else:
1413
                consumed_count_past = consumed_count
1414

    
1415
        QApplication.processEvents()
1416
        while True:
1417
            merged = False
1418
            for index1 in range(len(waiting_merged_run_infos)):
1419
                waiting_merged_run_info1 = waiting_merged_run_infos[index1]
1420
                for index2 in range(len(waiting_merged_run_infos)):
1421
                    if index1 == index2:
1422
                        continue
1423
                    waiting_merged_run_info2 = waiting_merged_run_infos[index2]
1424
                    result, merged_run_info, header, reverse = QEngineeringLineTracerRunItem.merge_and_sort_if_possible(
1425
                        waiting_merged_run_info1[1], waiting_merged_run_info2[1], sort_connect_info=False)
1426
                    if result:
1427
                        if header:
1428
                            if reverse:
1429
                                for waiting_run_info in waiting_merged_run_info2[0]:
1430
                                    waiting_run_info.reverse()
1431
                                waiting_merged_run_info2[0].reverse()
1432
                                waiting_merged_run_info2[0].extend(waiting_merged_run_info1[0])
1433
                            waiting_merged_run_info1[0] = waiting_merged_run_info2[0]
1434
                            waiting_merged_run_info1[1] = merged_run_info
1435
                        else:
1436
                            if reverse:
1437
                                for waiting_run_info in waiting_merged_run_info2[0]:
1438
                                    waiting_run_info.reverse()
1439
                                waiting_merged_run_info2[0].reverse()
1440
                            waiting_merged_run_info1[0].extend(waiting_merged_run_info2[0])
1441
                            waiting_merged_run_info1[1] = merged_run_info
1442
                        merged = True
1443
                        break
1444
                if merged:
1445
                    waiting_merged_run_infos.pop(index2)
1446
                    break
1447
            if not merged:
1448
                break
1449

    
1450
        QApplication.processEvents()
1451
        # fixed run merge
1452
        consumed_count_past = 0
1453
        for index1 in range(len(fixed_run_infos)):
1454
            if fixed_run_infos[index1].consumed:
1455
                continue
1456
            for index2 in range(len(fixed_run_infos)):
1457
                if index1 == index2 or fixed_run_infos[index2].consumed:
1458
                    continue
1459

    
1460
                result, merged_run_info, header, reverse = QEngineeringLineTracerRunItem.merge_and_sort_if_possible(
1461
                    fixed_run_infos[index1], fixed_run_infos[index2], sort=False)
1462
                if result:
1463
                    fixed_run_infos[index1].consumed = True
1464
                    fixed_run_infos[index2].consumed = True
1465
                    consumed_count_past += 2
1466
                    if header:
1467
                        fixed_merged_run_infos.append(
1468
                            [[fixed_run_infos[index2], fixed_run_infos[index1]], merged_run_info])
1469
                    else:
1470
                        fixed_merged_run_infos.append(
1471
                            [[fixed_run_infos[index1], fixed_run_infos[index2]], merged_run_info])
1472
                    break
1473

    
1474
        QApplication.processEvents()
1475
        while True:
1476
            consumed_count = 0
1477
            for index in range(len(fixed_run_infos)):
1478
                if fixed_run_infos[index].consumed:
1479
                    consumed_count += 1
1480
                    continue
1481

    
1482
                for fixed_merged_run_info in fixed_merged_run_infos:
1483
                    result, merged_run_info, header, reverse = QEngineeringLineTracerRunItem.merge_and_sort_if_possible(
1484
                        fixed_merged_run_info[1], fixed_run_infos[index], sort=False)
1485
                    if result:
1486
                        fixed_run_infos[index].consumed = True
1487
                        consumed_count += 1
1488
                        if header:
1489
                            fixed_merged_run_info[0].insert(0, fixed_run_infos[index])
1490
                            fixed_merged_run_info[1] = merged_run_info
1491
                        else:
1492
                            fixed_merged_run_info[0].append(fixed_run_infos[index])
1493
                            fixed_merged_run_info[1] = merged_run_info
1494
                        break
1495

    
1496
            if consumed_count_past == consumed_count:
1497
                break
1498
            else:
1499
                consumed_count_past = consumed_count
1500

    
1501
        QApplication.processEvents()
1502
        while True:
1503
            merged = False
1504
            for index1 in range(len(fixed_merged_run_infos)):
1505
                fixed_merged_run_info1 = fixed_merged_run_infos[index1]
1506
                for index2 in range(len(fixed_merged_run_infos)):
1507
                    if index1 == index2:
1508
                        continue
1509
                    fixed_merged_run_info2 = fixed_merged_run_infos[index2]
1510
                    result, merged_run_info, header, reverse = QEngineeringLineTracerRunItem.merge_and_sort_if_possible(
1511
                        fixed_merged_run_info1[1], fixed_merged_run_info2[1], sort=False)
1512
                    if result:
1513
                        if header:
1514
                            fixed_merged_run_info1[0] = fixed_merged_run_info2[0]
1515
                            fixed_merged_run_info1[1] = merged_run_info
1516
                        else:
1517
                            fixed_merged_run_info1[0].extend(fixed_merged_run_info2[0])
1518
                            fixed_merged_run_info1[1] = merged_run_info
1519
                        merged = True
1520
                        break
1521
                if merged:
1522
                    fixed_merged_run_infos.pop(index2)
1523
                    break
1524
            if not merged:
1525
                break
1526

    
1527
        for fixed_run_info in fixed_run_infos:
1528
            if fixed_run_info.consumed:
1529
                continue
1530
            else:
1531
                fixed_merged_run_infos.append([[fixed_run_info], fixed_run_info])
1532

    
1533
        QApplication.processEvents()
1534
        # sort merged waiting runs by using merged fixed runs
1535
        remain_count_past = len(waiting_merged_run_infos)
1536
        while True:
1537
            remain_count = 0
1538
            for run_index in reversed(range(len(waiting_merged_run_infos))):
1539
                waiting_run_info = waiting_merged_run_infos[run_index][0]
1540
                waiting_merged_run = waiting_merged_run_infos[run_index][1].run
1541

    
1542
                find = False
1543
                for fixed_merged_run_info in fixed_merged_run_infos:
1544
                    fixed_merged_run = fixed_merged_run_info[1].run
1545
                    if len(waiting_merged_run.items) > 1 and len(fixed_merged_run.items) > 1 and type(
1546
                            waiting_merged_run.items[0]) is QEngineeringLineItem and type(
1547
                        waiting_merged_run.items[-1]) is QEngineeringLineItem:
1548
                        if waiting_merged_run.items[0].connectors[0].connectedItem in fixed_merged_run.items and \
1549
                                waiting_merged_run.items[-1].connectors[1].connectedItem in fixed_merged_run.items:
1550
                            if fixed_merged_run.items.index(waiting_merged_run.items[0].connectors[
1551
                                                                0].connectedItem) > fixed_merged_run.items.index(
1552
                                waiting_merged_run.items[-1].connectors[1].connectedItem):
1553
                                for waiting_run_info in waiting_merged_run_infos[run_index][0]:
1554
                                    waiting_run_info.reverse()
1555
                                waiting_merged_run_infos[run_index][0].reverse()
1556
                                reverse_order = []
1557
                                for index in reversed(range(len(waiting_merged_run_infos[run_index][1].run.items))):
1558
                                    reverse_order.append(waiting_merged_run_infos[run_index][1].run.items[index])
1559
                                waiting_merged_run_infos[run_index][1].run.items = reverse_order
1560
                                fixed_merged_run_infos.append(waiting_merged_run_infos[run_index])
1561
                                waiting_merged_run_infos.pop(run_index)
1562
                                find = True
1563
                                break
1564
                            else:
1565
                                fixed_merged_run_infos.append(waiting_merged_run_infos[run_index])
1566
                                waiting_merged_run_infos.pop(run_index)
1567
                                find = True
1568
                                break
1569

    
1570
                if not find:
1571
                    remain_count += 1
1572

    
1573
            if remain_count_past == remain_count:
1574
                break
1575
            else:
1576
                remain_count_past = remain_count
1577
    except Exception as ex:
1578
        message = 'error occurred({}) in {}:{}'.format(repr(ex), sys.exc_info()[-1].tb_frame.f_code.co_filename,
1579
                                                       sys.exc_info()[-1].tb_lineno)
1580
        worker.display_message.emit(message)
1581

    
1582
async def connectAttrImpl_inst(worker, update_line_type, update_flow_mark, update_spec, update_stream_no):
1583
    from App import App
1584
    import uuid
1585
    from LineNoTracer import LineNoTracer
1586
    from AppDocData import AppDocData
1587
    from EngineeringAbstractItem import QEngineeringAbstractItem
1588
    from EngineeringSpecBreakItem import QEngineeringSpecBreakItem
1589
    from EngineeringInstrumentItem import QEngineeringInstrumentItem
1590
    from EngineeringReducerItem import QEngineeringReducerItem
1591
    from EngineeringEquipmentItem import QEngineeringEquipmentItem
1592
    from QEngineeringOPCItem import QEngineeringOPCItem
1593
    from EngineeringSpecBreakItem import QEngineeringSpecBreakItem
1594
    from EngineeringVendorItem import QEngineeringVendorItem
1595
    from EngineeringEndBreakItem import QEngineeringEndBreakItem
1596
    from EngineeringFlowMarkItem import QEngineeringFlowMarkItem
1597
    from EngineeringReservedWordTextItem import QEngineeringReservedWordTextItem
1598
    from QEngineeringSizeTextItem import QEngineeringSizeTextItem
1599
    from EngineeringValveOperCodeTextItem import QEngineeringValveOperCodeTextItem
1600
    from QEngineeringTrimLineNoTextItem import QEngineeringTrimLineNoTextItem
1601
    from QEngineeringTagNoTextItem import QEngineeringTagNoTextItem
1602
    from EngineeringErrorItem import QEngineeringErrorItem
1603
    from EngineeringTextItem import QEngineeringTextItem
1604
    from SpecialItemTypesDialog import SpecialItemTracer
1605
    from QEngineeringInstLineNoTextItem import QEngineeringInstLineNoTextItem
1606
    from EngineeringRunItem import QEngineeringRunItem
1607

    
1608
    try:
1609
        docdata = AppDocData.instance()
1610
        worker.display_message.emit('Initializing...')
1611

    
1612
        ALL_ITEM = [item for item in worker.scene.items() if issubclass(type(item), QEngineeringAbstractItem)]
1613
        for item in ALL_ITEM:
1614
            item.setVisible(False)
1615
        QApplication.processEvents()
1616

    
1617
        symbols = []
1618
        lines = [item for item in worker.scene.items() if type(item) is QEngineeringLineItem]
1619
        lineNos = []
1620
        equip_packages = []
1621
        end_breaks = []
1622

    
1623
        for error_item in [item for item in worker.scene.items() if type(item) is QEngineeringErrorItem]:
1624
            error_item.transfer.onRemoved.emit(error_item)
1625

    
1626
        for end_break in [item for item in worker.scene.items() if type(item) is QEngineeringEndBreakItem]:
1627
            if not end_break.prop('Freeze'):
1628
                end_break.transfer.onRemoved.emit(end_break)
1629
            else:
1630
                end_breaks.append(end_break)
1631

    
1632
        QApplication.processEvents()
1633

    
1634
        for item in worker.scene.items():
1635
            if issubclass(type(item), SymbolSvgItem) and not (type(item) is QEngineeringErrorItem) and not (
1636
                    type(item) is QEngineeringUnknownItem) and item.type != 'Notes' and not (
1637
                    type(item) is QEngineeringEndBreakItem):
1638
                symbols.append(item)
1639
            elif type(item) is QEngineeringLineNoTextItem:
1640
                if not item.runs:
1641
                    lineNos.append(item)
1642
            elif issubclass(type(item), QEngineeringTextItem):
1643
                item.owner = None
1644

    
1645
        lineNo_run = {}
1646
        for lineNo in lineNos:
1647
            lineNo_run[lineNo] = []
1648

    
1649
        QApplication.processEvents()
1650

    
1651
        # trace connected items
1652
        docdata._connected_items_lists = QEngineeringInstLineNoTextItem()
1653
        connected_items_lists = docdata._connected_items_lists
1654

    
1655
        items = symbols + lines
1656

    
1657
        ## find onwer line no
1658
        for item in symbols:
1659
            if item.owner is not None:
1660
                continue
1661
            
1662
            selected = None
1663
            minDist = None
1664
            for lineNo in lineNos:
1665
                dx = item.sceneBoundingRect().center().x() - lineNo.sceneBoundingRect().center().x()
1666
                dy = item.sceneBoundingRect().center().y() - lineNo.sceneBoundingRect().center().y()
1667
                length = math.sqrt(dx * dx + dy * dy)
1668

    
1669
                if minDist is None or length < minDist:
1670
                    minDist = length
1671
                    selected = lineNo
1672

    
1673
            #if selected:
1674
            #    lineNo_run[selected].append(item)
1675

    
1676
        for lineNo, run in lineNo_run.items():
1677
            for item in run:
1678
                item.owner = lineNo
1679

    
1680
            line_run = QEngineeringRunItem()
1681
            line_run.items = run
1682
            if line_run.items is not None and len(line_run.items) > 0:
1683
                line_run.owner = lineNo
1684
                lineNo.runs.append(line_run)
1685

    
1686
        ## find connected runs
1687
        while items:
1688
            connected_items_list = [items[0]]
1689
            connected_items_count = 0
1690
            while True:
1691
                if connected_items_count == len(connected_items_list):
1692
                    break
1693
                else:
1694
                    connected_items_count = len(connected_items_list)
1695

    
1696
                for item in items:
1697
                    if item in connected_items_list:
1698
                        matches = [conn.connectedItem for conn in item.connectors if conn.connectedItem and conn.connectedItem not in connected_items_list]
1699
                        if matches:
1700
                            connected_items_list.extend(matches)
1701
                            break
1702
                    else:
1703
                        matches = [conn for conn in item.connectors if conn.connectedItem and conn.connectedItem in connected_items_list]
1704
                        if matches:
1705
                            connected_items_list.append(item)
1706
                            break
1707

    
1708
            for item in connected_items_list:
1709
                items.remove(item)
1710
            
1711
            line_run = QEngineeringRunItem()
1712
            for run_item in connected_items_list:
1713
                line_run.items.append(run_item)
1714

    
1715
            line_run.owner = connected_items_lists
1716
            connected_items_lists.runs.append(line_run)
1717
        # up to here
1718

    
1719
        # connect attribute
1720
        worker.display_message.emit('Connecting Attribute...')
1721
        QApplication.processEvents()
1722
        texts = [item for item in worker.scene.items() if issubclass(type(item), QEngineeringTextItem)]
1723
        for symbol in symbols:
1724
            try:
1725
                symbol.connectAttribute(texts)
1726
            except Exception as ex:
1727
                message = 'error occurred({}) in {}:{}'.format(repr(ex), sys.exc_info()[-1].tb_frame.f_code.co_filename,
1728
                                                               sys.exc_info()[-1].tb_lineno)
1729
                worker.display_message.emit(message)
1730

    
1731
        """ try to connect label to valve """
1732
        labels = [symbol for symbol in symbols if symbol.iType == 19]  # Labels - Symbol => Instrument
1733
        valves = [symbol for symbol in symbols if
1734
                  symbol.iType == 34 or symbol.iType == 17 or symbol.iType == 22]  # Specialty Components, In-Line, Relief Devices
1735
        for label in labels:
1736
            label.connectAttribute(valves, clear=False)
1737

    
1738
        # for slope, etc.., symbol to line
1739
        labels = [symbol for symbol in symbols if symbol.iType == 30]  # Labels - Line => Piping
1740
        for label in labels:
1741
            label.connectAttribute(lines, clear=False)
1742

    
1743
        QApplication.processEvents()
1744
        for symbol in symbols:
1745
            for assoc in symbol.associations():
1746
                if assoc.owner is None and not issubclass(type(assoc), SymbolSvgItem):
1747
                    assoc.owner = symbol
1748

    
1749
        """ try to find text item's owner """
1750
        texts = [item for item in worker.scene.items() if type(item) is QEngineeringReservedWordTextItem]
1751
        for text in texts:
1752
            text.findOwner(lines)
1753

    
1754
        QApplication.processEvents()
1755
        # restore and save manual edited attr's text item
1756
        texts = [item for item in worker.scene.items() if issubclass(type(item), QEngineeringTextItem)]
1757
        targetText = []
1758
        for text in texts:
1759
            if text.owner:
1760
                continue
1761
            found = False
1762
            for symbol in symbols + lines:
1763
                for attr in list(symbol.attrs.keys()):
1764
                    # skip freezed attr or already consumed by symbol
1765
                    if attr.AssocItem == text:
1766
                        text.owner = symbol
1767
                        found = True
1768
                        break
1769
                    # restore missing attr
1770
                    elif type(attr.AssocItem) is str or type(attr.AssocItem) is uuid.UUID:
1771
                        if str(attr.AssocItem) == str(text.uid):
1772
                            symbol.add_assoc_item(text)
1773
                            attr.AssocItem = text
1774
                            text.owner = symbol
1775
                            found = True
1776
                        break
1777
                if found: break
1778
            if not found and (
1779
                    type(text) is QEngineeringSizeTextItem or type(text) is QEngineeringValveOperCodeTextItem or \
1780
                    type(text) is QEngineeringTagNoTextItem or type(text) is QEngineeringTextItem):
1781
                targetText.append(text)
1782

    
1783
        worker.need_update_texts = []
1784
        targetText = sorted(targetText, key=lambda param: len(param.text()), reverse=True)
1785
        for symbol in symbols + equip_packages:
1786
            symbol._skip = False
1787
        for text in targetText:
1788
            ret = text.findOwner(symbols) if type(text) is not QEngineeringTagNoTextItem else text.findOwner(
1789
                symbols + equip_packages)
1790
            if ret:
1791
                worker.need_update_texts.append([text, ret])
1792

    
1793
        QApplication.processEvents()
1794

    
1795
        ALL_ITEM = [item for item in worker.scene.items() if issubclass(type(item), QEngineeringAbstractItem)]
1796
        for item in ALL_ITEM:
1797
            item.setVisible(True)
1798

    
1799
    except Exception as ex:
1800
        message = 'error occurred({}) in {}:{}'.format(repr(ex), sys.exc_info()[-1].tb_frame.f_code.co_filename,
1801
                                                       sys.exc_info()[-1].tb_lineno)
1802
        worker.display_message.emit(message)
1803
    except:
1804
        (type1, value, traceback) = sys.exc_info()
1805
        sys.excepthook(type1, value, traceback)
클립보드 이미지 추가 (최대 크기: 500 MB)