프로젝트

일반

사용자정보

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

hytos / DTI_PID / DTI_PID / Shapes / EngineeringAbstractItem.py @ 6e800d2b

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

1
# coding: utf-8
2
""" This is engineering abstract item module """
3

    
4
import sys
5
#import random
6

    
7

    
8
class QEngineeringAbstractItem:
9
    '''
10
        @history    2018.05.15  Jeongwoo    Remove call super
11
                    2018.05.17  Jeongwoo    Add DEFAULT_COLOR Variable
12
    '''
13
    DEFAULT_COLOR = '#0000FF'
14
    HOVER_COLOR = '#BC4438'
15
    SELECTED_COLOR = '#FF00BF'
16

    
17
    CONNECTED_AT_PT = 0
18
    CONNECTED_AT_BODY = 1
19

    
20
    HOVER_ZVALUE = 200
21

    
22
    def __init__(self, parent=None):
23
        self._color = self.DEFAULT_COLOR  # default color
24
        self._owner = None
25
        self.conns = []
26
        self.special_item_type = None  # UID for special item type
27
        self._hover = False
28
        self._area = None
29
        self.connectors = []
30
        self.attrs = {}  # attributes
31
        self._associations = {'Text Item': [], 'Symbol Item': []}  # associated items
32

    
33
        #self.refresh_count = random.randint(0, 9)
34

    
35
    @property
36
    def hover(self):
37
        """ return hover """
38
        return self._hover
39

    
40
    @hover.setter
41
    def hover(self, value):
42
        """ set hover """
43
        self._hover = value
44

    
45
    def change_color(self, value):
46
        """ change item's color """
47
        self._color = value
48

    
49
    def highlight(self, flag):
50
        pass
51

    
52
    '''
53
        @brief      Abstract method. Variable [color] is RGB hex code
54
        @author     Jeongwoo
55
        @date       2018.05.11
56
    '''
57

    
58
    def setColor(self, color):
59
        raise NotImplementedError
60

    
61
    '''
62
        @brief  return color
63
        @author Jeongwoo
64
        @date   2018.05.11
65
    '''
66

    
67
    def getColor(self):
68
        from SymbolSvgItem import SymbolSvgItem
69
        from EngineeringEquipmentItem import QEngineeringEquipmentItem
70
        from EngineeringInstrumentItem import QEngineeringInstrumentItem
71
        from AppDocData import AppDocData
72
        from DisplayColors import DisplayColors
73
        from DisplayColors import DisplayOptions
74
        from EngineeringAbstractItem import QEngineeringAbstractItem
75
        from EngineeringLineItem import QEngineeringLineItem
76

    
77
        def check_stream_no_attribute():
78
            """ return stream no if item has stream no attribute else return False """
79
            _attrs = self.getAttributes(findOwner=True)
80
            for key, value in _attrs.items():
81
                if key.Attribute == 'Stream No':
82
                    if value:
83
                        return value
84
                    elif value == '' or value == None:
85
                        return None
86
                    else:
87
                        return False
88

    
89
        app_doc_data = AppDocData.instance()
90

    
91
        if DisplayOptions.DisplayByStreamNo == DisplayColors.instance().option and \
92
                (issubclass(type(self), SymbolSvgItem) or type(self) is QEngineeringLineItem):
93
            res = check_stream_no_attribute()
94
            if res and res in app_doc_data._hmbColors:
95
                return app_doc_data._hmbColors[res]
96
            else:
97
                return QEngineeringAbstractItem.DEFAULT_COLOR
98

    
99
        if type(self) is QEngineeringEquipmentItem:
100
            # if DisplayOptions.DisplayByLineType == DisplayColors.instance().option:
101
            if self.hover:
102
                return SymbolSvgItem.HOVER_COLOR
103
            elif not QEngineeringEquipmentItem.EQUIP_COLOR:
104
                app_doc_data = AppDocData.instance()
105
                configs = app_doc_data.getConfigs('Equipment', 'Color')
106
                QEngineeringEquipmentItem.EQUIP_COLOR = configs[
107
                    0].value if configs else QEngineeringAbstractItem.DEFAULT_COLOR
108

    
109
            return QEngineeringEquipmentItem.EQUIP_COLOR
110

    
111
        elif type(self) is QEngineeringInstrumentItem:
112
            if DisplayOptions.DisplayByLineType == DisplayColors.instance().option:
113
                if self.hover:
114
                    return SymbolSvgItem.HOVER_COLOR
115
                elif not QEngineeringInstrumentItem.INST_COLOR:
116
                    app_doc_data = AppDocData.instance()
117
                    configs = app_doc_data.getConfigs('Instrument', 'Color')
118
                    QEngineeringInstrumentItem.INST_COLOR = configs[
119
                        0].value if configs else QEngineeringAbstractItem.DEFAULT_COLOR
120

    
121
                return QEngineeringInstrumentItem.INST_COLOR
122
            else:
123
                return SymbolSvgItem.HOVER_COLOR if self.hover else ( \
124
                    self.owner._color if self.owner and hasattr(self.owner, '_color') else self._color)
125

    
126
        elif type(self) is SymbolSvgItem:
127
            return SymbolSvgItem.HOVER_COLOR if self.hover else ( \
128
                self.owner._color if self.owner and hasattr(self.owner, '_color') else self._color)
129

    
130
        elif type(self) is QEngineeringLineItem:
131
            if DisplayOptions.DisplayByLineType == DisplayColors.instance().option:
132
                if self.hover:
133
                    return QEngineeringAbstractItem.HOVER_COLOR
134
                elif self.isSelected():
135
                    return QEngineeringAbstractItem.SELECTED_COLOR
136
                else:
137
                    if self.lineType in QEngineeringLineItem.LINE_TYPE_COLORS:
138
                        return QEngineeringLineItem.LINE_TYPE_COLORS[self.lineType]
139
                    else:
140
                        app_doc_data = AppDocData.instance()
141
                        configs = app_doc_data.getConfigs('LineTypes', self.lineType)
142
                        if configs:
143
                            tokens = configs[0].value.split(',')
144
                            QEngineeringLineItem.LINE_TYPE_COLORS[self.lineType] = tokens[0] if len(tokens) == 4 else \
145
                                QEngineeringAbstractItem.DEFAULT_COLOR
146
                            return QEngineeringLineItem.LINE_TYPE_COLORS[self.lineType]
147
                        else:
148
                            return QEngineeringAbstractItem.DEFAULT_COLOR
149
            else:
150
                if self.owner is None:
151
                    if self.isSelected():
152
                        return QEngineeringAbstractItem.SELECTED_COLOR
153
                    else:
154
                        return  QEngineeringAbstractItem.HOVER_COLOR if self.hover else (
155
                            self.owner.getColor() if (self.owner and hasattr(self.owner, '_color')) else self._color)
156
                else:
157
                    if self.isSelected():
158
                        return QEngineeringAbstractItem.SELECTED_COLOR
159
                    else:
160
                        return self.owner.getColor()
161

    
162

    
163
        return QEngineeringAbstractItem.HOVER_COLOR if self.hover else (
164
            self.owner.getColor() if (self.owner and hasattr(self.owner, '_color')) else self._color)
165

    
166
    '''
167
        @brief  getter of owner
168
        @author humkyung
169
        @date   2018.05.12
170
    '''
171

    
172
    @property
173
    def owner(self):
174
        return self._owner
175

    
176
    '''
177
        @brief  setter of owner
178
        @author humkyung
179
        @date   2018.05.12
180
    '''
181

    
182
    @owner.setter
183
    def owner(self, value):
184
        self._owner = value
185

    
186
    @property
187
    def has_connection(self):
188
        """ check this is connected to other """
189
        for connector in self.connectors:
190
            if connector.connectedItem: return True
191

    
192
        return False
193

    
194
    def validate(self):
195
        """ validate this """
196
        raise NotImplementedError('To be implemented')
197

    
198
    '''
199
        @brief  getter of area
200
        @author humkyung
201
        @date   2018.09.06
202
    '''
203

    
204
    @property
205
    def area(self):
206
        return self._area if self._area is not None else 'None'
207

    
208
    '''
209
        @brief  setter of area
210
        @author humkyung
211
        @date   2018.09.06
212
    '''
213

    
214
    @area.setter
215
    def area(self, value):
216
        self._area = value
217

    
218
    '''
219
        @brief  write to xml
220
        @author humkyung
221
        @date   2018.05.16
222
    '''
223

    
224
    def toXml(self):
225
        pass
226

    
227
    def to_svg(self, parent=None) -> list:
228
        pass
229

    
230
    '''
231
        @brief  write attribute to xml
232
        @author humkyung
233
        @date   2018.05.16
234
    '''
235

    
236
    def toXmlAsAttribute(self, parent):
237
        pass
238

    
239
    def toSql(self):
240
        """convert to sql query"""
241
        pass
242

    
243
    def isOverlap(self, rect1, rect2):
244
        """
245
        @brief  return true if rects have intersection, rect is QRect
246
        @author euisung
247
        @date   2019.09.02
248
        """
249
        lt1, rb1 = (rect1.left(), rect1.top()), (rect1.right(), rect1.bottom())
250
        lt2, tb2 = (rect2.left(), rect2.top()), (rect2.right(), rect2.bottom())
251
        if rect1.left() > rect2.right() or rect2.left() > rect1.right():
252
            return False
253
        if rect1.bottom() < rect2.top() or rect2.bottom() < rect1.top():
254
            return False
255

    
256
        return True
257

    
258
    def associations(self):
259
        """ return associated instance """
260
        # move to abstractitem
261
        import uuid
262

    
263
        try:
264
            res = []
265
            for key in self._associations.keys():
266
                index = 0
267
                for assoc in list(self._associations[key]):
268
                    # find owner with uid if self.scene() is valid
269
                    if self.scene() and assoc and type(assoc) is uuid.UUID:
270
                        matches = [x for x in self.scene().items() if hasattr(x, 'uid') and str(x.uid) == str(assoc)]
271
                        if matches:
272
                            res.append(matches[0])
273
                            self._associations[key][index] = matches[0]
274
                    # up to here
275
                    elif assoc:
276
                        res.append(assoc)
277
                    index += 1
278

    
279
            for key in self.attrs.keys():
280
                if type(key.AssocItem) is uuid.UUID:
281
                    for assoc in res:
282
                        if str(key.AssocItem) == str(assoc.uid):
283
                            key.AssocItem = assoc
284

    
285
            return res
286
        except Exception as ex:
287
            from App import App
288
            from AppDocData import MessageType
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
            return []
294

    
295
    def get_assoc_item(self, assoc):
296
        """ get associated item of given object """
297
        import uuid
298

    
299
        if assoc and type(assoc) is uuid.UUID:
300
            matches = [x for x in self.scene().items() if hasattr(x, 'uid') and str(x.uid) == str(assoc)]
301
            if matches: return matches[0]
302

    
303
        return assoc
304

    
305
    def texts(self):
306
        """ return text type of associations """
307
        res = []
308

    
309
        for text in self.texts_order():
310
            consumed = False
311
            for key in list(self.attrs.keys()):
312
                if key.AssocItem and key.AssocItem is text:
313
                    consumed = True
314
            if not consumed:
315
                res.append(text)
316

    
317
        return res
318

    
319
    def texts_order(self):
320
        from EngineeringTextItem import QEngineeringTextItem
321
        
322
        return sorted([x for x in self.associations() if issubclass(type(x), QEngineeringTextItem)],
323
                           key=lambda attr: attr.loc[1])
324

    
325
    def symbols(self, symbol_attr_number):
326
        """ return symbol type of associations """
327
        from SymbolSvgItem import SymbolSvgItem
328
        from EngineeringVendorItem import QEngineeringVendorItem
329
        from EngineeringLineItem import QEngineeringLineItem
330
        from EngineeringLineNoTextItem import QEngineeringLineNoTextItem
331

    
332
        res = []
333
        for symbol in [x for x in self.associations() if
334
                       issubclass(type(x), SymbolSvgItem) or type(x) is QEngineeringVendorItem or type(x) is QEngineeringLineItem]:
335
            if symbol_attr_number > 1:
336
                consumed = False
337
                for key in list(self.attrs.keys()):
338
                    if key.AssocItem and key.AssocItem is symbol:
339
                        consumed = True
340
                if not consumed:
341
                    res.append(symbol)
342
            elif type(self) is not QEngineeringLineNoTextItem:
343
                res.append(symbol)
344

    
345
        return res
346

    
347
    @property
348
    def Size(self):
349
        """ return symbol's size """
350
        from QEngineeringSizeTextItem import QEngineeringSizeTextItem
351

    
352
        matches = [assoc for assoc in self.associations() if type(assoc) is QEngineeringSizeTextItem]
353
        if matches:
354
            return matches[0].mainSize
355
        else:
356
            return None
357

    
358
    @property
359
    def EvaluatedSize(self):
360
        from EngineeringReducerItem import QEngineeringReducerItem
361
        from EngineeringLineNoTextItem import QEngineeringLineNoTextItem
362
        from AppDocData import AppDocData
363

    
364
        try:
365
            if self.Size: return self.Size
366
            if self.owner and issubclass(type(self.owner), QEngineeringLineNoTextItem):
367
                matches = [run for run in self.owner.runs if self in run.items]
368
                if matches:
369
                    at = matches[0].items.index(self)
370
                    upstream = matches[0].items[:at]
371
                    upstream.reverse()
372
                    prev = self
373
                    for item in upstream:
374
                        if type(item) is QEngineeringReducerItem:
375
                            if item.connectors[0].connectedItem is prev:  ### Main Size
376
                                if item.mainSubSize: return item.mainSubSize[0]
377
                            elif item.connectors[1].connectedItem is prev:  ### Sub Size
378
                                if item.mainSubSize: return item.mainSubSize[1]
379
                        else:
380
                            if item.Size: return item.Size
381
                        prev = item
382

    
383
                    downstream = matches[0].items[at:]
384
                    prev = self
385
                    for item in downstream:
386
                        if type(item) is QEngineeringReducerItem:
387
                            if item.connectors[0].connectedItem is prev:  ### Main Size
388
                                if item.mainSubSize: return item.mainSubSize[0]
389
                            elif item.connectors[1].connectedItem is prev:  ### Sub Size
390
                                if item.mainSubSize: return item.mainSubSize[1]
391
                        else:
392
                            if item.Size: return item.Size
393
                        prev = item
394

    
395
                    if 'Drain' == matches[0].Type:
396
                        return None
397
                        #return AppDocData.instance().drain_size
398

    
399
                return self.owner.Size
400

    
401
            return None
402
        except Exception as ex:
403
            from App import App
404
            from AppDocData import MessageType
405

    
406
            message = 'error occurred({}) in {}:{}'.format(ex, sys.exc_info()[-1].tb_frame.f_code.co_filename,
407
                                                          sys.exc_info()[-1].tb_lineno)
408
            #App.mainWnd().addMessage.emit(MessageType.Error, str(self.uid) + self.name + message)
409
            App.mainWnd().addMessage.emit(MessageType.Error, message)
410

    
411
    def EvaluatedTable(self, old_code, table_name):
412
        """ return new attribute code """
413
        from AppDocData import AppDocData
414
        from CodeTables import CodeTable
415

    
416
        try:
417
            found = CodeTable.instance(table_name).find_match_exactly(old_code)
418

    
419
            return found if found else ''
420
        except Exception as ex:
421
            from App import App
422
            from AppDocData import MessageType
423

    
424
            message = 'error occurred({}) in {}:{}'.format(ex, sys.exc_info()[-1].tb_frame.f_code.co_filename,
425
                                                          sys.exc_info()[-1].tb_lineno)
426
            App.mainWnd().addMessage.emit(MessageType.Error, message)
427

    
428
    def EvaluatedLineNo(self, prop):
429
        """ return line no attr """
430
        from EngineeringLineNoTextItem import QEngineeringLineNoTextItem
431

    
432
        if self.owner and type(self.owner) is QEngineeringLineNoTextItem:
433
            attrs = self.owner.getAttributes()
434
            for attr, value in attrs.items():
435
                if prop == attr.Attribute:
436
                    return value
437

    
438
        return None
439

    
440
    def EvaluatedDrawing(self, prop):
441
        """ return text item that is in prop"""
442
        from EngineeringTextItem import QEngineeringTextItem
443

    
444
        scene = self.scene()
445
        if scene:
446
            items = [item for item in scene.items() if issubclass(type(item), QEngineeringTextItem) and item.area == prop]
447
            if items:
448
                return items[0]
449
        
450
        return QEngineeringTextItem()
451

    
452
    def EvaluatedAttribute(self, prop, cache=False):
453
        """ return item's attribute """
454
        attrs = self.getAttributes(findOwner=cache)
455
        if attrs:
456
            for key, value in attrs.items():
457
                if key.Attribute == prop:
458
                    return value
459

    
460
        return ''
461

    
462
    @property
463
    def stream_no(self):
464
        matches = [attr for attr in self.attrs if attr.Attribute.upper() == 'STREAM NO']
465
        if matches:
466
            return self.attrs[matches[0]]
467

    
468
        return None
469

    
470
    @stream_no.setter
471
    def stream_no(self, value):
472
        from AppDocData import AppDocData
473

    
474
        matches = [attr for attr in self.attrs if attr.Attribute.upper() == 'STREAM NO']
475
        if matches:
476
            self.attrs[matches[0]] = value
477
            """reset attributes for hmb with given stream no"""
478

    
479
            app_doc_data = AppDocData.instance()
480
            stream_data = app_doc_data.hmbTable.dataOfStreamNo(value)
481
            for attr in self.attrs:
482
                if attr.AttributeType == 'HMB':
483
                    matches = [data for data in stream_data if data.name == attr.Attribute]
484
                    if matches:
485
                        self.attrs[attr] = matches[0].value
486
                    else:
487
                        self.attrs[attr] = ''
488

    
489
    def try_eval(self, item, expression):
490
        try:
491
            return eval(expression)
492
        except Exception as ex:
493
            from App import App
494
            from AppDocData import MessageType
495

    
496
            message = 'error occurred({}) in {}:{}'.format(ex, sys.exc_info()[-1].tb_frame.f_code.co_filename,
497
                                                           sys.exc_info()[-1].tb_lineno) + ' Item UID : ' + str(self.uid)
498
            App.mainWnd().addMessage.emit(MessageType.Error, message)
499
        
500
        return ''
501

    
502

    
503
    def getAttributes(self, findOwner=False):
504
        """calculate all attributes of item"""
505
        import re
506

    
507
        if findOwner and not hasattr(self, '_skip'):
508
            self._skip = False
509
        elif findOwner and self._skip:
510
            return self.attrs
511
        elif findOwner:
512
            self._skip = True
513
        else:
514
            self._skip = False
515

    
516
        _attrs = {}
517
        try:
518
            from AppDocData import AppDocData
519
            from SymbolSvgItem import SymbolSvgItem
520
            from EngineeringTextItem import QEngineeringTextItem
521
            from EngineeringValveOperCodeTextItem import QEngineeringValveOperCodeTextItem
522
            from EngineeringLineItem import QEngineeringLineItem
523
            from EngineeringVendorItem import QEngineeringVendorItem
524
            from EngineeringLineNoTextItem import QEngineeringLineNoTextItem
525
            from EngineeringSpecBreakItem import QEngineeringSpecBreakItem
526
            from QEngineeringTagNoTextItem import QEngineeringTagNoTextItem
527

    
528
            """ get attributes of item from database """
529
            app_doc_data = AppDocData.instance()
530
            if type(self) is QEngineeringLineItem:
531
                symbolAttrs = app_doc_data.getSymbolAttribute('Line')
532
            elif type(self) is QEngineeringVendorItem:
533
                symbolAttrs = app_doc_data.getSymbolAttribute('Package')
534
            elif type(self) is QEngineeringLineNoTextItem:
535
                symbolAttrs = app_doc_data.getSymbolAttribute('Line No')
536
                self.getLineNoAttributes(_attrs)
537
            elif type(self) is QEngineeringTagNoTextItem:
538
                self.getTagNoAttributes(_attrs)
539
                self.attrs = _attrs
540
                return self.attrs
541
            else:
542
                symbolAttrs = app_doc_data.getSymbolAttribute(self.type)
543

    
544
            targetAttrs = []
545
            symbol_attr_number = 0
546
            if not (type(self) is QEngineeringLineItem or type(self) is QEngineeringVendorItem or
547
                    type(self) is QEngineeringLineNoTextItem or type(self) is QEngineeringTagNoTextItem):
548
                for attr in symbolAttrs:
549
                    if not attr.Target and not type(self) is QEngineeringSpecBreakItem:
550
                        continue
551
                    if attr.Target is None or attr.Target == 'ALL' or \
552
                            type(self) is QEngineeringSpecBreakItem or \
553
                                [target for target in attr.Target.split(',') if self.dbUid is int(target)]:
554
                        targetAttrs.append(attr)
555
                        if attr.AttributeType == 'Symbol Item' or attr.AttributeType == 'Line Item' or attr.AttributeType == 'EQ Item' or attr.AttributeType == 'Comp Item':
556
                            symbol_attr_number = max(symbol_attr_number, int(attr.AttrAt))
557
            else:
558
                targetAttrs = symbolAttrs
559

    
560
            _texts = self.texts()
561
            _symbols = self.symbols(symbol_attr_number + 1)
562

    
563
            # copy old values
564
            for attr in targetAttrs:
565
                matches = [_attr for _attr, _ in self.attrs.items() if _attr.UID == attr.UID]
566
                if matches:
567
                    if matches[0].AttributeType == 'Spec' and not self.attrs[matches[0]]:
568
                        continue
569
                    attr.Freeze = matches[0].Freeze  # update freeze value
570
                    attr.AssocItem = matches[0].AssocItem
571
                    _attrs[attr] = self.attrs[matches[0]]  # copy attribute value
572
                else:
573
                    if attr.AttributeType != 'Spec':
574
                        _attrs[attr] = ''
575
            self.attrs = _attrs
576

    
577
            for attr in [_attr for _attr in sorted(self.attrs.keys(), key=lambda param:int(param.Index)) \
578
                            if _attr.AttributeType != 'Combined' and _attr.AttributeType != 'Reference']:
579
                # if attr.Freeze: continue    # do not evaluate value if attribute is frozen
580
                if attr.AttributeType == 'Text Item' or attr.AttributeType == 'Valve Oper Code':
581
                    at = int(attr.AttrAt)
582

    
583
                    # Text Item can contain Valve Oper Code
584
                    if attr.AttributeType == 'Text Item':
585
                        items = _texts
586
                    else:
587
                        items = [text for text in _texts if
588
                                 QEngineeringAbstractItem.assoc_type(text) == attr.AttributeType]
589

    
590
                    if not attr.AssocItem and len(items) > at and not attr.Codes.values:
591
                        attr.AssocItem = items[at]
592
                        item = attr.AssocItem
593
                        _attrs[attr] = self.try_eval(item, attr.Expression) if attr.Expression else ''
594
                    elif attr.AssocItem:
595
                        item = attr.AssocItem = self.get_assoc_item(attr.AssocItem)
596
                        _attrs[attr] = self.try_eval(item, attr.Expression) if attr.Expression else ''
597
                    else:
598
                        _attrs[attr] = ''
599
                elif attr.AttributeType == 'Size Text Item' or attr.AttributeType == 'Tag No':
600
                    at = int(attr.AttrAt)
601
                    items = [text for text in _texts if QEngineeringAbstractItem.assoc_type(text) == attr.AttributeType]
602
                    if not attr.AssocItem and len(items) > at:
603
                        attr.AssocItem = items[at]
604
                        item = attr.AssocItem
605
                        _attrs[attr] = self.try_eval(item, attr.Expression) if attr.Expression else ''
606
                    else:
607
                        item = attr.AssocItem = self.get_assoc_item(attr.AssocItem)
608
                        _attrs[attr] = self.try_eval(item, attr.Expression) if attr.Expression and (
609
                                (item and 'item' in attr.Expression) or 'self' in attr.Expression) else ''
610
                elif attr.AttributeType == 'Symbol Item' or attr.AttributeType == 'Line Item' or \
611
                        attr.AttributeType == 'Comp Item' or attr.AttributeType == 'EQ Item':
612
                    at = int(attr.AttrAt)
613
                    if not attr.AssocItem and len(_symbols) > at:
614
                        attr.AssocItem = _symbols[at]
615
                        item = attr.AssocItem
616
                        _attrs[attr] = self.try_eval(item, attr.Expression) if attr.Expression else ''
617
                    elif attr.AssocItem:
618
                        item = attr.AssocItem = self.get_assoc_item(attr.AssocItem)
619
                        _attrs[attr] = self.try_eval(item, attr.Expression) if attr.Expression else ''
620
                    else:
621
                        _attrs[attr] = ''
622
                elif attr.AttributeType == 'String':
623
                    #_attrs[attr] = attr.Expression if attr.Expression and not _attrs[attr] else _attrs[attr]
624
                    _attrs[attr] = self.try_eval(None, attr.Expression) if attr.Expression else _attrs[attr]
625

    
626
            """calculate attribute value for combined type"""
627
            p = re.compile('{[A-Za-z0-9_ ]+}')
628
            for attr in [_attr for _attr in targetAttrs if _attr.AttributeType == 'Combined']:
629
                value, pos = '', 0
630

    
631
                matches = p.finditer(attr.Expression)
632
                for match in matches:
633
                    attr_name = attr.Expression[(match.start() + 1):(match.end() - 1)]
634
                    values = [value for key, value in _attrs.items() if key.Attribute == attr_name]
635
                    if not values:
636
                        values = ['\'\'']
637
                    value += attr.Expression[pos:match.start()] + values[0]
638
                    pos = match.end()
639

    
640
                value += attr.Expression[pos:len(attr.Expression)]
641
                _attrs[attr] = value
642
            """up to here"""
643

    
644
            """calculate attribute value for Reference type"""
645
            for attr in [_attr for _attr in targetAttrs if _attr.AttributeType == 'Reference']:
646
                value, pos = '', 0
647

    
648
                matches = p.finditer(attr.Expression)
649
                for match in matches:
650
                    attr_name = attr.Expression[(match.start() + 1):(match.end() - 1)]
651
                    values = [value for key, value in _attrs.items() if key.Attribute == attr_name]
652
                    if not values:
653
                        values = []
654
                    value += attr.Expression[pos:match.start()] + '\'' + values[0] + '\''
655
                    pos = match.end()
656

    
657
                value += attr.Expression[pos:len(attr.Expression)]
658
                _attrs[attr] = self.try_eval(None, value) if attr.Expression else ''
659
            """up to here"""
660

    
661
            for _attr, _value in _attrs.items():
662
                if _value is None or _value == '':
663
                    _attr.AssocItem = None
664
        except Exception as ex:
665
            from App import App
666
            from AppDocData import MessageType
667

    
668
            message = 'error occurred({}) in {}:{}'.format(ex, sys.exc_info()[-1].tb_frame.f_code.co_filename,
669
                                                           sys.exc_info()[-1].tb_lineno) + ' Item UID : ' + str(self.uid)
670
            App.mainWnd().addMessage.emit(MessageType.Error, message)
671

    
672
        return self.attrs
673

    
674
    def attrib(self, name):
675
        """ return the value of given attribute with name """
676
        matches = [(attr, value) for attr, value in self.getAttributes().items() if attr.Attribute == name]
677
        if matches: return matches[0][1]
678

    
679
        return None
680

    
681
    def set_attrib(self, attrib, value):
682
        """ set attribute with given value """
683
        matches = [attr for attr, _ in self.attrs.items() if attr.UID == attrib.UID]
684
        if len(matches) == 1: self.attrs[matches[0]] = value
685

    
686
    @staticmethod
687
    def assoc_type(item):
688
        """ return association type of given item """
689
        from EngineeringTextItem import QEngineeringTextItem
690
        from SymbolSvgItem import SymbolSvgItem
691
        from EngineeringValveOperCodeTextItem import QEngineeringValveOperCodeTextItem
692
        from QEngineeringSizeTextItem import QEngineeringSizeTextItem
693
        from QEngineeringTagNoTextItem import QEngineeringTagNoTextItem
694
        from EngineeringLineItem import QEngineeringLineItem
695
        from EngineeringEquipmentItem import QEngineeringEquipmentItem
696
        from EngineeringVendorItem import QEngineeringVendorItem
697

    
698
        _type = None
699

    
700
        if type(item) is QEngineeringSizeTextItem:
701
            _type = 'Size Text Item'
702
        elif type(item) is QEngineeringValveOperCodeTextItem:
703
            _type = 'Valve Oper Code'
704
        elif type(item) is QEngineeringTagNoTextItem:
705
            _type = 'Tag No'
706
        elif type(item) is QEngineeringTextItem or issubclass(type(item), QEngineeringTextItem):
707
            _type = 'Text Item'
708
        elif type(item) is QEngineeringEquipmentItem or type(item) is QEngineeringVendorItem:
709
            _type = 'EQ Item'
710
        elif type(item) is SymbolSvgItem or issubclass(type(item), SymbolSvgItem):
711
            _type = 'Symbol Item'
712
        elif type(item) is QEngineeringLineItem:
713
            _type = 'Line Item'
714
        elif issubclass(type(item), SymbolSvgItem) or type(item) is QEngineeringLineItem:
715
            _type = 'Comp Item'
716

    
717
        return _type
718

    
719
    def clear_attr_and_assoc_item(self, force=False):
720
        """ clear attrs, return true if clear attrs """
721
        if force:
722
            self.attrs.clear()
723
            self._associations.clear()
724
            return True
725
        else:
726
            freeze = False
727
            for key in self.attrs.keys():
728
                if key.Freeze:
729
                    freeze = True
730
                    break
731
            if freeze:
732
                return False
733
            else:
734
                self.attrs.clear()
735
                self._associations.clear()
736
                return True
737

    
738
    def add_assoc_item(self, item, at=None, force=False):
739
        """ add given item to association """
740

    
741
        from EngineeringTextItem import QEngineeringTextItem
742
        from SymbolSvgItem import SymbolSvgItem
743
        from EngineeringValveOperCodeTextItem import QEngineeringValveOperCodeTextItem
744
        from QEngineeringSizeTextItem import QEngineeringSizeTextItem
745

    
746
        if not force:
747
            for key in self.attrs.keys():
748
                if key.Freeze:
749
                    return False
750

    
751
        _type = QEngineeringAbstractItem.assoc_type(item)
752
        if _type is not None:
753
            if not _type in self._associations:
754
                self._associations[_type] = []
755

    
756
            if item in self._associations[_type]: return True
757

    
758
            if at is None:
759
                self._associations[_type].append(item)
760
            else:
761
                while len(self._associations[_type]) <= at: self._associations[_type].append(None)
762
                # if len(self._associations[_type]) > at and self._associations[_type][at] is not None:
763
                #    self._associations[_type][at].owner = None
764
                self._associations[_type][at] = item
765

    
766
            return True
767

    
768
        return False
769

    
770
    def remove_assoc_item(self, item):
771
        """ remove given item from association """
772
        _type = QEngineeringAbstractItem.assoc_type(item)
773
        if _type is not None:
774
            if _type in self._associations and item in self._associations[_type]:
775
                index = self._associations[_type].index(item)
776
                self._associations[_type].pop(index)
777

    
778
    @property
779
    def properties(self):
780
        """ getter of properties """
781
        import uuid
782
        from SymbolSvgItem import SymbolSvgItem
783
        from EngineeringLineItem import QEngineeringLineItem
784
        from EngineeringLineNoTextItem import QEngineeringLineNoTextItem
785
        from EngineeringVendorItem import QEngineeringVendorItem
786

    
787
        if type(self) is QEngineeringLineNoTextItem:
788
            for prop, value in self._properties.items():
789
                if prop.is_selectable and type(value) is uuid.UUID and self.scene():
790
                    matches = [x for x in self.scene().items() if hasattr(x, 'uid') and str(x.uid) == str(value)]
791
                    if matches: self._properties[prop] = matches[0]
792

    
793
        elif type(self) is QEngineeringLineItem:
794
            for prop, value in self._properties.items():
795
                if prop.is_selectable and type(value) is uuid.UUID and self.scene():
796
                    matches = [x for x in self.scene().items() if hasattr(x, 'uid') and str(x.uid) == str(value)]
797
                    if matches: self._properties[prop] = matches[0]
798

    
799
                if prop.Expression: self._properties[prop] = eval(prop.Expression)
800

    
801
        elif issubclass(type(self), SymbolSvgItem):
802
            for prop, value in self._properties.items():
803
                try:
804
                    if prop.is_selectable and type(value) is uuid.UUID and self.scene():
805
                        matches = [x for x in self.scene().items() if hasattr(x, 'uid') and str(x.uid) == str(value)]
806
                        if matches: self._properties[prop] = matches[0]
807

    
808
                    if prop.Expression:
809
                        item = self._properties[prop]  # assign item
810
                        self._properties[prop] = eval(prop.Expression)
811
                except Exception as ex:
812
                    from App import App
813
                    from AppDocData import MessageType
814
                    message = 'error occurred({}) in {}:{}'.format(ex, sys.exc_info()[-1].tb_frame.f_code.co_filename,
815
                                                                   sys.exc_info()[-1].tb_lineno)
816
                    App.mainWnd().addMessage.emit(MessageType.Error, message)
817

    
818
        elif type(self) is QEngineeringVendorItem:
819
            for prop, value in self._properties.items():
820
                try:
821
                    if prop.is_selectable and type(value) is uuid.UUID and self.scene():
822
                        matches = [x for x in self.scene().items() if hasattr(x, 'uid') and str(x.uid) == str(value)]
823
                        if matches: self._properties[prop] = matches[0]
824

    
825
                    if prop.Expression:
826
                        item = self._properties[prop]  # assign item
827
                        self._properties[prop] = eval(prop.Expression)
828
                except Exception as ex:
829
                    from App import App
830
                    from AppDocData import MessageType
831
                    message = 'error occurred({}) in {}:{}'.format(ex, sys.exc_info()[-1].tb_frame.f_code.co_filename,
832
                                                                   sys.exc_info()[-1].tb_lineno)
833
                    App.mainWnd().addMessage.emit(MessageType.Error, message)
834

    
835
        return self._properties
836

    
837
    @properties.setter
838
    def properties(self, value):
839
        """ setter of properties """
840
        self._properties = value
841

    
842
    def prop(self, name):
843
        """ return property with given value """
844
        from SymbolSvgItem import SymbolSvgItem
845
        from EngineeringLineItem import QEngineeringLineItem
846
        from EngineeringLineNoTextItem import QEngineeringLineNoTextItem
847
        from EngineeringVendorItem import QEngineeringVendorItem
848

    
849
        if type(self) is QEngineeringLineNoTextItem:
850
            matches = [prop for prop, _ in self.properties.items() if prop.Attribute == name]
851
            return self.properties[matches[0]] if matches else None
852

    
853
        elif type(self) is QEngineeringLineItem:
854
            matches = [(prop, value) for prop, value in self.properties.items() if prop.Attribute == name]
855
            if matches: return matches[0][1]
856

    
857
            return None
858

    
859
        elif issubclass(type(self), SymbolSvgItem):
860
            matches = [(prop, value) for prop, value in self.properties.items() if prop.Attribute == name]
861
            if matches: return matches[0][1]
862

    
863
            return None
864

    
865
        elif type(self) is QEngineeringVendorItem:
866
            matches = [(prop, value) for prop, value in self.properties.items() if prop.Attribute == name]
867
            if matches: return matches[0][1]
868

    
869
    def set_property(self, property, value):
870
        """ set property with given value """
871
        from SymbolSvgItem import SymbolSvgItem
872
        from EngineeringLineItem import QEngineeringLineItem
873
        from EngineeringLineNoTextItem import QEngineeringLineNoTextItem
874
        from EngineeringVendorItem import QEngineeringVendorItem
875

    
876
        if type(self) is QEngineeringLineNoTextItem:
877
            matches = [prop for prop, _ in self._properties.items() if prop.Attribute == property]
878
            if matches: self._properties[matches[0]] = value
879

    
880
        elif type(self) is QEngineeringLineItem:
881
            if issubclass(type(value), QEngineeringAbstractItem): self.add_assoc_item(value, 0)
882
            matches = [prop for prop, _ in self._properties.items() if prop.Attribute == property]
883
            if matches: self._properties[matches[0]] = value
884

    
885
        elif issubclass(type(self), SymbolSvgItem):
886
            if issubclass(type(value), QEngineeringAbstractItem): self.add_assoc_item(value, 0)
887
            matches = [prop for prop, _ in self._properties.items() if prop.Attribute == property]
888
            if matches: self._properties[matches[0]] = value
889

    
890
        elif type(self) is QEngineeringVendorItem:
891
            if issubclass(type(value), QEngineeringAbstractItem):
892
                self.add_assoc_item(value, 0)
893
            matches = [prop for prop, _ in self._properties.items() if prop.Attribute == property]
894
            if matches: self._properties[matches[0]] = value
895

    
896
    def center(self):
897
        return self.sceneBoundingRect().center()
898

    
899

    
900
if __name__ == '__main__':
901
    import re
902

    
903
    p = re.compile('{[A-Za-z0-9]+}')
904
    value, pos = '', 0
905

    
906
    _attrs = {'a': '~', 'b': '!', 'C': '+'}
907
    expression = 'XXXXXXX{a}-{b}-{C}----'
908
    matches = p.finditer(expression)
909
    for match in matches:
910
        attr_name = expression[(match.start() + 1):(match.end() - 1)]
911
        value += expression[pos:match.start()] + _attrs[attr_name]
912
        pos = match.end()
913

    
914
    value += expression[pos:len(expression)]
915
    print(value)
클립보드 이미지 추가 (최대 크기: 500 MB)