프로젝트

일반

사용자정보

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

hytos / DTI_PID / DTI_PID / Shapes / EngineeringTextItem.py @ b069732d

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

1
# coding: utf-8
2
import os.path
3
import copy
4
import sys
5

    
6
try:
7
    from PyQt5.QtCore import Qt, QPointF, QRectF, pyqtSignal, QObject, QT_VERSION_STR, QRect
8
    from PyQt5.QtGui import QImage, QPixmap, QPainterPath, QBrush, QPen, QTransform, QFont, QColor, QFontMetricsF
9
    from PyQt5.QtWidgets import QGraphicsView, QGraphicsScene, QFileDialog, QGraphicsItem, QAbstractGraphicsShapeItem, \
10
        QGraphicsTextItem
11
except ImportError:
12
    try:
13
        from PyQt4.QtCore import Qt, QRectF, pyqtSignal, QRect, QObject, QT_VERSION_STR
14
        from PyQt4.QtGui import QGraphicsView, QGraphicsScene, QImage, QPixmap, QPainterPath, QFileDialog, QFont, \
15
            QColor, QFontMetricsF
16
    except ImportError:
17
        raise ImportError("ImageViewerQt: Requires PyQt5 or PyQt4.")
18

    
19
from EngineeringPolylineItem import QEngineeringPolylineItem
20
from GraphicsBoundingBoxItem import QGraphicsBoundingBoxItem
21
from AppDocData import *
22
from EngineeringAbstractItem import QEngineeringAbstractItem
23
from TextInfo import TextInfo
24
from SymbolSvgItem import SymbolSvgItem
25

    
26

    
27
class QEngineeringTextItem(QGraphicsTextItem, QEngineeringAbstractItem):
28
    HIGHLIGHT = '#BC4438'
29
    ZVALUE = 210
30

    
31
    '''
32
        @history    2018.05.17  Jeongwoo    Add self._owner variable
33
    '''
34

    
35
    def __init__(self, uid=None, parent=None):
36
        import uuid
37

    
38
        QGraphicsTextItem.__init__(self, parent)
39
        QEngineeringAbstractItem.__init__(self)
40

    
41
        self.uid = uuid.uuid4() if uid is None else uuid.UUID(uid)
42
        self.type = 'TEXT'
43
        self.loc = None
44
        self.size = None
45
        self.angle = 0  # angle in radian
46
        self._owner = None
47
        self.setFlags(QGraphicsItem.ItemIsSelectable | QGraphicsItem.ItemIsFocusable)
48
        self.setAcceptHoverEvents(True)
49
        self.setAcceptTouchEvents(True)
50

    
51
        self.setColor(self._color)
52
        self._savedColor = None
53

    
54
        self.delimiter = '"'
55
        self.lineNoDelimiter = '!-!'
56

    
57
        self.attribute = ''
58
        self._properties = {}
59

    
60
        self.transfer = Transfer()
61
        self.setZValue(QEngineeringTextItem.ZVALUE)
62

    
63
    def __str__(self):
64
        """ return string represent uuid """
65
        return str(self.uid)
66

    
67
    '''
68
        @brief      Get owner
69
        @author     Jeongwoo
70
        @date       2018.05.17
71
    '''
72

    
73
    @property
74
    def owner(self):
75
        import uuid
76

    
77
        # find owner with uid
78
        if self.scene() and self._owner is not None and type(self._owner) is uuid.UUID:
79
            matches = [x for x in self.scene().items() if hasattr(x, 'uid') and str(x.uid) == str(self._owner)]
80
            if matches: self._owner = matches[0]
81
            return matches[0] if matches else None
82
        # up to here
83

    
84
        if type(self._owner) is not uuid.UUID and type(self._owner) is not str:
85
            return self._owner
86
        else:
87
            self._owner = None
88
            return None
89

    
90
    '''
91
        @brief      Set owner
92
        @author     Jeongwoo
93
        @date       2018.05.17
94
        @history    2018.05.17  Jeongwoo    Add Calling setColor if self._owner is None or not
95
    '''
96

    
97
    @owner.setter
98
    def owner(self, value):
99
        self._owner = value
100

    
101
        if self._owner is None:
102
            self._color = self.DEFAULT_COLOR
103
        self.setColor(self._color)
104

    
105
    '''
106
        @brief  return text string
107
        @author humkyung
108
        @date   2018.04.16
109
    '''
110

    
111
    def text(self):
112
        return self.toPlainText()
113

    
114
    '''
115
        @brief  return center position of text
116
        @author humkyung
117
        @date   2018.04.16
118
    '''
119

    
120
    def center(self):
121
        return self.sceneBoundingRect().center()
122

    
123
    def boundingRect(self):
124
        if self.angle == 1.57 or self.angle == 4.71:
125
            return QRectF(0, 0, self.size[1], self.size[0])
126
        else:
127
            return QRectF(0, 0, self.size[0], self.size[1])
128

    
129
    '''
130
        @brief      hover event
131
        @authro     humkyung
132
        @date       
133
    '''
134

    
135
    def hoverEnterEvent(self, event):
136
        self.highlight(True)
137

    
138
    def hoverLeaveEvent(self, event):
139
        self.highlight(False)
140

    
141
    '''
142
        @brief      set highlight
143
        @author     kyouho
144
        @date       2018.08.27
145
    '''
146

    
147
    def highlight(self, flag):
148
        self.hover = flag
149
        if flag:
150
            if self._savedColor is None:
151
                self._savedColor = self.getColor()
152
            self.setColor(QEngineeringTextItem.HIGHLIGHT)
153
        elif hasattr(self, '_savedColor'):
154
            self.setColor(self._savedColor)
155

    
156
        self.update()
157

    
158
    def hoverMoveEvent(self, event):
159
        pass
160

    
161
    '''
162
        @brief      remove item when user press delete key
163
        @author     humkyung
164
        @date       2018.04.23
165
        @history    2018.05.25  Jeongwoo    Seperate delete item method
166
                    humkyung 2018.08.18 rotate text when user press 'R'
167
    '''
168

    
169
    def keyPressEvent(self, event):
170
        if Qt.Key_Return == event.key():
171
            self.edit_text()
172
        elif event.key() == Qt.Key_R:
173
            # degree 0
174
            if 0 == self.angle:
175
                self.angle = 1.57
176
            # degree 90
177
            elif 1.57 == self.angle:
178
                self.angle = 3.14
179
            # degree 180
180
            elif 3.14 == self.angle:
181
                self.angle = 4.71
182
            # degree 270
183
            elif 4.71 == self.angle:
184
                self.angle = 0
185

    
186
            width = self.size[0]
187
            height = self.size[1]
188
            self.size = [height, width]
189

    
190
            self.rotate()
191
        elif event.key() == Qt.Key_Up:  # translate up/down/left/right symbol
192
            self.loc[1] = self.loc[1] - 1
193
            self.rotate()
194
        elif event.key() == Qt.Key_Down:
195
            self.loc[1] = self.loc[1] + 1
196
            self.rotate()
197
        elif event.key() == Qt.Key_Left:
198
            self.loc[0] = self.loc[0] - 1
199
            self.rotate()
200
        elif event.key() == Qt.Key_Right:
201
            self.loc[0] = self.loc[0] + 1
202
            self.rotate()
203

    
204
        # QGraphicsTextItem.keyPressEvent(self, event)
205

    
206
    '''
207
        @brief  draw rect when item is selected
208
        @author humkyung
209
        @date   2018.07.08
210
    '''
211

    
212
    def drawFocusRect(self, painter):
213
        self.focuspen = QPen(Qt.DotLine)
214
        self.focuspen.setColor(Qt.black)
215
        self.focuspen.setWidthF(1.5)
216
        hilightColor = QColor(255, 0, 0, 127)
217
        painter.setBrush(QBrush(hilightColor))
218
        painter.setPen(self.focuspen)
219
        painter.drawRect(self.boundingRect())
220

    
221
    '''
222
        @brief  override paint(draw connection points)
223
        @author humkyung
224
        @date   2018.07.08
225
    '''
226

    
227
    def paint(self, painter, options=None, widget=None):
228
        self.setColor(self.getColor())
229

    
230
        if self.angle == 1.57 or self.angle == 4.71:
231
            rect = QRectF(0, 0, self.size[1], self.size[0])
232
        else:
233
            rect = QRectF(0, 0, self.size[0], self.size[1])
234

    
235
        painter.setFont(self.font())
236
        color = self.defaultTextColor()
237

    
238
        # draw white background during hover
239
        if self.hover:
240
            configs = AppDocData.instance().getConfigs('Text', 'Background')
241
            if not configs or not int(configs[0].value) != 1:
242
                painter.setPen(Qt.NoPen)
243
                painter.setBrush(Qt.white)
244
                painter.drawRect(self.boundingRect())
245
        # up to here
246

    
247
        painter.setPen(QPen(color))
248
        painter.drawText(rect, Qt.AlignCenter, self.text())
249

    
250
        if self.isSelected():
251
            self.drawFocusRect(painter)
252

    
253
    '''
254
        @brief      Delete text item
255
        @author     Jeongwoo
256
        @date       2018.05.25
257
    '''
258

    
259
    def deleteTextItemFromScene(self):
260
        ''' not used '''
261
        # self.transfer.onRemoved.emit(self)
262
        self.scene().removeItem(self)
263

    
264
    '''
265
        @brief      Return real item position
266
        @author     Jeongwoo
267
        @date       2018.05.25
268
    '''
269

    
270
    def boundingRectOnScene(self):
271
        rect = self.boundingRect()
272
        rect.moveTo(self.loc[0], self.loc[1])
273
        return rect
274

    
275
    def edit_text(self):
276
        """edit text by using ocr dialog"""
277
        from TextItemFactory import TextItemFactory
278
        from OcrResultDialog import QOcrResultDialog
279

    
280
        item = None
281
        try:
282
            dialog = QOcrResultDialog(None, self.scene().parent().image().copy(self.loc[0] - 3, self.loc[1] - 3,
283
                                                                               self.size[0] + 6, self.size[1] + 6),
284
                                      QRect(self.loc[0], self.loc[1], self.size[0], self.size[1]), True, self.text())
285
            (isAccept, textInfoList) = dialog.showDialog()
286

    
287
            if isAccept:
288
                scene = self.scene()
289

    
290
                textInfo = textInfoList[0]
291
                x = textInfo.getX()
292
                y = textInfo.getY()
293
                angle = textInfo.getAngle()
294
                text = textInfo.getText()
295
                width = textInfo.getW()
296
                height = textInfo.getH()
297
                item = TextItemFactory.instance().createTextItem(textInfo)
298
                if item is not None:
299
                    item.loc = [x, y]
300
                    item.size = (width, height)
301
                    item.angle = angle
302
                    item.area = self.area
303
                    item.addTextItemToScene(scene)
304
                    item.transfer.onRemoved.connect(scene.parent().parent().parent().itemRemoved)
305

    
306
                    self.transfer.onRemoved.emit(self)
307
        except Exception as ex:
308
            message = 'error occurred({}) in {}:{}'.format(self.tr('Fail to create text'),
309
                                                           sys.exc_info()[-1].tb_frame.f_code.co_filename,
310
                                                           sys.exc_info()[-1].tb_lineno)
311
            self.addMessage.emit(MessageType.Normal, message)
312

    
313
        return item
314

    
315
    '''
316
        @brief      Double click event, Show QOcrResultDialog
317
        @author     Jeongwoo
318
        @date       18.04.23
319
        @history    18.06.20    Jeongwoo    Resize QRect added 1
320
    '''
321

    
322
    def mouseDoubleClickEvent(self, event):
323
        if event.buttons() == Qt.LeftButton:
324
            self.edit_text()
325

    
326
    '''
327
        @brief      rotate text
328
        @author     humkyung
329
        @date       2018.08.18
330
    '''
331

    
332
    def rotate(self):
333
        sx = 1
334
        sy = 1
335
        width = self.size[0]
336
        height = self.size[1]
337
        x = self.loc[0]
338
        y = self.loc[1]
339

    
340
        transform = QTransform()
341
        if (1.57 == self.angle) or (4.71 == self.angle):
342
            rect = self.boundingRect()
343
            sx = width / rect.height()
344
            sy = height / rect.width()
345

    
346
            transform.translate(x, y)
347
            transform.translate(width * 0.5, height * 0.5)
348
            transform.scale(1, sy)
349
            transform.rotateRadians(-self.angle)
350
            transform.translate(-rect.width() * 0.5, -rect.height() * 0.5)
351
        elif 3.14 == self.angle:
352
            rect = self.boundingRect()
353
            sx = width / rect.width()
354
            sy = height / rect.height()
355

    
356
            transform.translate(x, y - round((rect.height() - height) * 0.5))
357
            transform.scale(sx, 1)
358
            transform.rotateRadians(-self.angle)
359
            transform.translate(-width * 0.5, -height * 0.5)
360
        else:
361
            rect = self.boundingRect()
362
            sx = width / rect.width()
363
            sy = height / rect.height()
364

    
365
            # if '\n' not in text:
366
            transform.translate(x, y - round((rect.height() - height) * 0.5))
367
            transform.scale(sx, 1)
368

    
369
        self.setTransform(transform)
370
        self.update()
371

    
372
    '''
373
        @brief      Put text on scene
374
        @author     Jeongwoo
375
        @date       18.04.23
376
        @history    humkyung 2018.06.30 apply font configuration
377
    '''
378
    def addTextItemToScene(self, scene):
379
        try:
380
            docData = AppDocData.instance()
381
            configs = docData.getConfigs('Text Style', 'Font Name')
382
            fontName = configs[0].value if configs else 'Arial'
383
            configs = docData.getConfigs('Text Style', 'Font Size')
384
            fontSize = int(configs[0].value) if configs else -1
385

    
386
            sx = 1
387
            sy = 1
388
            width = self.size[0]
389
            height = self.size[1]
390
            x = self.loc[0]
391
            y = self.loc[1]
392
            rect = None
393
            lineCount = self.text().count('\n') if self.text().count('\n') is not 0 else 1
394
            transform = QTransform()
395

    
396
            allowed_error = 0.001
397
            if abs(self.angle - 1.57) < allowed_error:
398
                self.angle = 1.57
399
            elif abs(self.angle - 4.71) < allowed_error:
400
                self.angle = 4.71
401
            elif abs(self.angle - 3.14) < allowed_error:
402
                self.angle = 3.14
403
            else:
404
                self.angle = 0
405

    
406
            if abs(self.angle - 1.57) < allowed_error or abs(self.angle - 4.71) < allowed_error:
407
                font = QFont(fontName, width if fontSize == -1 else fontSize)
408

    
409
                x_factor = width / QFontMetricsF(font).height()
410
                y_factor = height / (QFontMetricsF(font).width(self.text()) / lineCount)
411
                factor = min(x_factor, y_factor)
412
                font.setPointSizeF(font.pointSizeF() * factor)
413

    
414
                self.setFont(font)
415
                rect = self.boundingRect()
416
                sx = width / rect.height()
417
                sy = height / rect.width()
418

    
419
                transform.translate(x, y)
420
                transform.translate(width * 0.5, height * 0.5)
421
                transform.scale(1, sy)
422
                transform.rotateRadians(-self.angle)
423
                transform.translate(-rect.width() * 0.5, -rect.height() * 0.5)
424
            elif abs(self.angle - 3.14) < allowed_error:
425
                font = QFont(fontName, height if fontSize == -1 else fontSize)
426

    
427
                x_factor = width / (QFontMetricsF(font).width(self.text()) / lineCount)
428
                y_factor = height / QFontMetricsF(font).height()
429
                factor = min(x_factor, y_factor)
430
                font.setPointSizeF(font.pointSizeF() * factor)
431

    
432
                self.setFont(font)
433
                rect = self.boundingRect()
434
                sx = width / rect.width()
435
                sy = height / rect.height()
436

    
437
                transform.translate(x, y - round((rect.height() - height) * 0.5))
438
                transform.scale(sx, 1)
439
                transform.rotateRadians(-self.angle)
440
                transform.translate(-width * 0.5, -height * 0.5)
441
            else:
442
                font = QFont(fontName, height if fontSize == -1 else fontSize)
443

    
444
                x_factor = width / (QFontMetricsF(font).width(self.text()) / lineCount)
445
                y_factor = height / QFontMetricsF(font).height()
446
                factor = min(x_factor, y_factor)
447
                font.setPointSizeF(font.pointSizeF() * factor)
448

    
449
                self.setFont(font)
450
                rect = self.boundingRect()
451

    
452
                """
453
                doc = self.document()
454
                doc.setDocumentMargin(0)
455
                doc.adjustSize()
456
                doc_size = doc.size()
457

458
                sx = rect.width() / doc_size.width()
459
                sy = rect.height() / doc_size.height()
460
                """
461

    
462
                sx = width / rect.width()
463
                sy = height / rect.height()
464

    
465
                # if '\n' not in text:
466
                transform.translate(x, y)
467
                # transform.scale(sx, 1)
468

    
469
            self.setTransform(transform)
470

    
471
            scene.addItem(self)
472
        except Exception as ex:
473
            from App import App
474
            from AppDocData import MessageType
475

    
476
            message = 'error occurred({}-{}) in {}:{}'.format(ex, self.text(),
477
                                                              sys.exc_info()[-1].tb_frame.f_code.co_filename,
478
                                                              sys.exc_info()[-1].tb_lineno)
479
            App.mainWnd().addMessage.emit(MessageType.Error, message)
480

    
481
    '''
482
        @brief  get connected items
483
        @author humkyung
484
        @date   2018.04.23
485
        @history    2018.11.22      euisung     fix note road
486
    '''
487

    
488
    def getConnectedItems(self):
489
        visited = []
490

    
491
        try:
492
            if 1 == len(self.conns):
493
                # iterate connected items
494
                pool = []
495
                visited = []
496
                pool.append(self.conns[0])
497
                while len(pool) > 0:
498
                    it = pool.pop()
499
                    visited.append(it)
500
                    for conn in it.conns:
501
                        if (conn is not None) and (conn not in visited): pool.append(conn)
502
                # up to here
503
        except Exception as ex:
504
            print('error occurred({}) in {}:{}'.format(ex, sys.exc_info()[-1].tb_frame.f_code.co_filename,
505
                                                       sys.exc_info()[-1].tb_lineno))
506

    
507
        return visited
508

    
509
    @staticmethod
510
    def from_database(component):
511
        """ get text item from database """
512
        import uuid
513
        from AppDocData import AppDocData
514
        from TextItemFactory import TextItemFactory
515
        from SymbolAttr import SymbolAttr
516

    
517
        item = None
518

    
519
        try:
520
            x = float(component['X'])
521
            y = float(component['Y'])
522
            width = float(component['Width']) if component['Width'] is not None else 0
523
            height = float(component['Height']) if component['Height'] is not None else 0
524
            angle = float(component['Rotation']) if component['Rotation'] is not None else 0
525
            text = component['Value']
526
            textInfo = TextInfo(text, x, y, width, height, angle)
527
            connline = component['Connected'] if component['Connected'] is not None else None
528

    
529
            item = TextItemFactory.instance().createTextItem(textInfo)
530
            if item is not None:
531
                item.setVisible(False)
532
                item.uid = uuid.UUID(component['UID'])
533
                item.loc = [x, y]
534
                item.size = [width, height]
535
                item.angle = angle
536
                item.setToolTip('<b>{}</b><br>LINE NO={}'.format(str(item.uid), text))
537

    
538
                if component['Owner'] and component['Owner'] != 'None':
539
                    item._owner = uuid.UUID(component['Owner'])
540

    
541
                ## assign area
542
                if not component['Area']:
543
                    app_doc_data = AppDocData.instance()
544
                    for area in app_doc_data.getAreaList():
545
                        if area.contains([x, y]):
546
                            item.area = area.name
547
                            break
548
                else:
549
                    item.area = component['Area']
550
                ## up to here
551

    
552
                """ apply freeze value """
553
                # item.freeze_item.update_freeze(item.prop('Freeze'))
554

    
555
                if connline is not None:
556
                    item.conns.append(connline)
557
        except Exception as ex:
558
            from App import App
559
            from AppDocData import MessageType
560

    
561
            message = 'error occurred({}) in {}:{}'.format(ex, sys.exc_info()[-1].tb_frame.f_code.co_filename,
562
                                                           sys.exc_info()[-1].tb_lineno)
563
            App.mainWnd().addMessage.emit(MessageType.Error, message)
564
            return None
565

    
566
        return item
567

    
568
    '''
569
        @brief      parse xml code
570
        @author     humkyung
571
        @date       2018.09.15
572
    '''
573

    
574
    @staticmethod
575
    def fromXml(node):
576
        import uuid
577
        from TextItemFactory import TextItemFactory
578
        from AppDocData import AppDocData
579
        from EngineeringNoteItem import QEngineeringNoteItem
580
        from QEngineeringSizeTextItem import QEngineeringSizeTextItem
581
        from EngineeringValveOperCodeTextItem import QEngineeringValveOperCodeTextItem
582

    
583
        item = None
584

    
585
        try:
586
            location = node.find('LOCATION').text if node.find('LOCATION') is not None else '0,0'
587
            x = float(location.split(',')[0])
588
            y = float(location.split(',')[1])
589
            width = float(node.find('WIDTH').text) if node.find('WIDTH') is not None else 0
590
            height = float(node.find('HEIGHT').text) if node.find('HEIGHT') is not None else 0
591
            angle = float(node.find('ANGLE').text) if node.find('ANGLE') is not None else 0
592
            value = node.find('VALUE').text
593
            if len(value.replace('\n', '').replace(' ', '')) == 0:
594
                return None
595
            # attributeValue = node.find('ATTRIBUTEVALUE')
596
            name = node.find('NAME').text
597
            textInfo = TextInfo(value, x, y, width, height, angle)
598

    
599
            item = TextItemFactory.instance().createTextItem(textInfo)
600
            if item is not None:
601
                item.loc = [x, y]
602
                item.size = [width, height]
603
                item.angle = angle
604

    
605
            # set uid and owner of item
606
            if item is not None:
607
                item.uid = uuid.UUID(node.find('UID').text)
608
                item.setVisible(False)
609

    
610
                if node.find('OWNER') is not None and node.find('OWNER').text != 'None':
611
                    item._owner = uuid.UUID(node.find('OWNER').text)
612

    
613
            ## assign area
614
            if item is not None:
615
                if node.find('AREA') is None:
616
                    appDocData = AppDocData.instance()
617
                    for area in appDocData.getAreaList():
618
                        if area.contains([x, y]):
619
                            item.area = area.name
620
                            break
621
                else:
622
                    item.area = node.find('AREA').text
623
                    ## up to here
624
        except Exception as ex:
625
            from App import App
626
            from AppDocData import MessageType
627

    
628
            message = 'error occurred({}) in {}:{}'.format(ex, sys.exc_info()[-1].tb_frame.f_code.co_filename,
629
                                                           sys.exc_info()[-1].tb_lineno)
630
            App.mainWnd().addMessage.emit(MessageType.Error, message)
631

    
632
        return item
633

    
634
    '''
635
        @brief      generate xml code
636
        @author     humkyung
637
        @date       2018.04.23
638
        @history    humkyung 2018.04.27 move to QEngineeringLineNoTextItem
639
                    humkyung 2018.05.02 add name as parameter
640
                    Jeongwoo 2018.05.30 Change variable [owner] is nullable and Add/Modify attributes
641
    '''
642

    
643
    def toXml(self, owner=None):
644
        from xml.etree.ElementTree import Element, SubElement, dump, ElementTree
645
        from EngineeringLineItem import QEngineeringLineItem
646
        from SymbolSvgItem import SymbolSvgItem
647

    
648
        try:
649
            node = Element('ATTRIBUTE')
650
            uidNode = Element('UID')
651
            uidNode.text = str(self.uid)
652
            node.append(uidNode)
653

    
654
            # write owner's uid to xml
655
            ownerNode = Element('OWNER')
656
            if self.owner is not None:
657
                ownerNode.text = str(self.owner)
658
            else:
659
                ownerNode.text = 'None'
660
            node.append(ownerNode)
661
            # up to here
662

    
663
            attributeValueNode = Element('ATTRIBUTEVALUE')
664
            attributeValueNode.text = self.attribute
665
            node.append(attributeValueNode)
666

    
667
            nameNode = Element('NAME')
668
            nameNode.text = self.type
669
            node.append(nameNode)
670

    
671
            locNode = Element('LOCATION')
672
            locNode.text = '{},{}'.format(self.loc[0], self.loc[1])
673
            node.append(locNode)
674

    
675
            valueNode = Element('VALUE')
676
            valueNode.text = self.text()
677
            node.append(valueNode)
678

    
679
            angleNode = Element('ANGLE')
680
            angleNode.text = str(self.angle)
681
            node.append(angleNode)
682

    
683
            widthNode = Element('WIDTH')
684
            widthNode.text = str(self.size[0])
685
            node.append(widthNode)
686

    
687
            heightNode = Element('HEIGHT')
688
            heightNode.text = str(self.size[1])
689
            node.append(heightNode)
690

    
691
            areaNode = Element('AREA')
692
            areaNode.text = self.area
693
            node.append(areaNode)
694

    
695
            sceneNode = Element('SCENE')
696
            rect = self.sceneBoundingRect()
697
            sceneNode.text = '{},{},{},{}'.format(rect.x(), rect.y(), rect.width(), rect.height())
698
            node.append(sceneNode)
699

    
700
        except Exception as ex:
701
            from App import App
702
            from AppDocData import MessageType
703

    
704
            message = 'error occurred({}) in {}:{}'.format(ex, sys.exc_info()[-1].tb_frame.f_code.co_filename,
705
                                                           sys.exc_info()[-1].tb_lineno)
706
            App.mainWnd().addMessage.emit(MessageType.Error, message)
707

    
708
            return None
709

    
710
        return node
711

    
712
    def findOwner(self, symbols):
713
        import math
714

    
715
        try:
716
            minDist = None
717
            selected = None
718

    
719
            configs = AppDocData.instance().getConfigs('Range', 'Detection Ratio')
720
            ratio = float(configs[0].value) if 1 == len(configs) else 1.5
721

    
722
            dist = (self.sceneBoundingRect().height() + self.sceneBoundingRect().width()) * ratio / 2
723
            center = self.sceneBoundingRect().center()
724

    
725
            target_symbols = []
726
            for symbol in symbols:
727
                attrs = symbol.getAttributes()
728

    
729
                freeze = False
730
                for attr in attrs:
731
                    if attr.Freeze:
732
                        freeze = True
733
                        break
734
                if freeze: continue
735
                for attr in attrs:
736
                    ret = attr.Codes.find_match_exactly(self.text())
737
                    if ret:
738
                        target_symbols.append(symbol)
739
                        break
740

    
741
            for symbol in target_symbols:
742
                if issubclass(type(symbol), SymbolSvgItem):
743
                    dx = symbol.origin[0] - center.x()
744
                    dy = symbol.origin[1] - center.y()
745

    
746
                    #offset = (symbol.sceneBoundingRect().width() + symbol.sceneBoundingRect().height()) / 4
747
                    length = math.sqrt(dx * dx + dy * dy)# - offset
748

    
749
                    if (length < dist) and (minDist is None or length < minDist):
750
                        minDist = length
751
                        selected = symbol
752

    
753
            if selected is not None:
754
                attrs = selected.getAttributes()
755
                target_attr = None
756
                for attr in attrs:
757
                    ret = attr.Codes.find_match_exactly(self.text())
758
                    if ret:
759
                        target_attr = attr
760
                        break
761
                if target_attr.AssocItem is None and selected.add_assoc_item(self, at=int(target_attr.AttrAt)):
762
                    target_attr.AssocItem = self
763
                    self.owner = selected
764
                    return ret
765
                else:
766
                    return False
767
        except Exception as ex:
768
            from App import App
769
            message = 'error occurred({}) in {}:{}'.format(ex, sys.exc_info()[-1].tb_frame.f_code.co_filename,
770
                                                           sys.exc_info()[-1].tb_lineno)
771
            App.mainWnd().addMessage.emit(MessageType.Error, message)
772

    
773
    '''
774
        @brief      Set Color. Override QEngineeringAbstractItem's
775
        @author     Jeongwoo
776
        @date       2018.05.11
777
        @history    humkyung 2018.05.13 update after change color
778
    '''
779

    
780
    def setColor(self, color):
781
        if QColor.isValidColor(color):
782
            c = QColor()
783
            c.setNamedColor(color)
784
            self.setDefaultTextColor(c)
785
            self.update()
786

    
787
    def toSql(self):
788
        """ convert text data to sql query for components and title block """
789
        from AppDocData import AppDocData
790

    
791
        res = []
792

    
793
        appDocData = AppDocData.instance()
794
        cols = ['UID', 'Drawings_UID', 'Symbol_UID', 'X', 'Y', 'Width', 'Height', 'Rotation', 'Area', 'Value', 'Owner',
795
                'Connected', 'SpecialItemTypes_UID']
796
        values = ['?', '?', "(select UID from Symbol where Name='Text' and SymbolType_UID=-1)", '?', '?', '?', '?', '?',
797
                  '?', '?', '?', '?', '?']
798

    
799
        param = [
800
            (str(self.uid), str(appDocData.activeDrawing.UID), self.loc[0], self.loc[1], self.size[0], self.size[1],
801
             str(self.angle),
802
             self.area, self.text(), \
803
             str(self.owner) if self.owner else None, \
804
             str(self.conns[0]) if self.conns else None, \
805
             str(self.special_item_type) if self.special_item_type else None)]
806
        sql = 'insert into Components({}) values({})'.format(','.join(cols), ','.join(values))
807
        res.append((sql, tuple(param)))
808

    
809
        titleBlockProps = appDocData.getTitleBlockProperties()
810
        if titleBlockProps:
811
            cols = ['UID', 'Drawings_UID', 'TitleBlockProperties_UID', 'VALUE']
812
            values = ['?', '?', '?', '?']
813
            params = []
814
            for titleBlockProp in titleBlockProps:
815
                if self.area == titleBlockProp[0]:
816
                    params.append((str(self.uid), appDocData.activeDrawing.UID, self.area, self.text()))
817

    
818
            sql = 'insert into TitleBlockValues({}) values({})'.format(','.join(cols), ','.join(values))
819
            if params: res.append((sql, tuple(params)))
820

    
821
        return res
822

    
823

    
824
'''
825
    @brief      The class transfer pyqtSignal Event. Cause Subclass of QGraphicsRectItem can't use pyqtSignal
826
    @author     Jeongwoo
827
    @date       2018.06.18
828
'''
829

    
830

    
831
class Transfer(QObject):
832
    onRemoved = pyqtSignal(QGraphicsItem)
833

    
834
    def __init__(self, parent=None):
835
        QObject.__init__(self, parent)
클립보드 이미지 추가 (최대 크기: 500 MB)