프로젝트

일반

사용자정보

통계
| 개정판:

hytos / DTI_PID / DTI_PID / Shapes / EngineeringTextItem.py @ 78ca21fd

이력 | 보기 | 이력해설 | 다운로드 (29.2 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 event.key() == Qt.Key_R:
171
            # degree 0
172
            if 0 == self.angle:
173
                self.angle = 1.57
174
            # degree 90
175
            elif (1.57 == self.angle):
176
                self.angle = 3.14
177
            # degree 180
178
            elif 3.14 == self.angle:
179
                self.angle = 4.71
180
            # degree 270
181
            elif 4.71 == self.angle:
182
                self.angle = 0
183

    
184
            width = self.size[0]
185
            height = self.size[1]
186
            self.size = [height, width]
187

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

    
202
        # QGraphicsTextItem.keyPressEvent(self, event)
203

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

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

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

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

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

    
233
        painter.setFont(self.font())
234
        color = self.defaultTextColor()
235

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

    
245
        painter.setPen(QPen(color))
246
        painter.drawText(rect, Qt.AlignCenter, self.text())
247

    
248
        if self.isSelected():
249
            self.drawFocusRect(painter)
250

    
251
    '''
252
        @brief      Delete text item
253
        @author     Jeongwoo
254
        @date       2018.05.25
255
    '''
256

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

    
262
    '''
263
        @brief      Return real item position
264
        @author     Jeongwoo
265
        @date       2018.05.25
266
    '''
267

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

    
273
    '''
274
        @brief      Double click event, Show QOcrResultDialog
275
        @author     Jeongwoo
276
        @date       18.04.23
277
        @history    18.06.20    Jeongwoo    Resize QRect added 1
278
    '''
279

    
280
    def mouseDoubleClickEvent(self, event, isDataList=False):
281
        from TextItemFactory import TextItemFactory
282
        if event.buttons() == Qt.LeftButton:
283
            from OcrResultDialog import QOcrResultDialog
284
            # dialog = QOcrResultDialog(None, AppDocData.instance().getCurrentPidSource().getQImageOnRect(
285
            #    QRect(self.loc[0] - 3, self.loc[1] - 3, self.size[0] + 6, self.size[1] + 6)), 
286
            #    QRect(self.loc[0], self.loc[1], self.size[0], self.size[1]), True, self.text())
287
            dialog = QOcrResultDialog(None, self.scene().parent().image().copy(self.loc[0] - 3, self.loc[1] - 3,
288
                                                                               self.size[0] + 6, self.size[1] + 6),
289
                                      QRect(self.loc[0], self.loc[1], self.size[0], self.size[1]), True, self.text())
290
            (isAccept, textInfoList) = dialog.showDialog()
291

    
292
            if isAccept:
293
                scene = self.scene()
294

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

    
311
                    self.transfer.onRemoved.emit(self)
312
                    if isDataList:
313
                        return item
314
                else:
315
                    message = 'error occurred({}) in {}:{}'.format('텍스트 생성에 실패했습니다.',
316
                                                                   sys.exc_info()[-1].tb_frame.f_code.co_filename,
317
                                                                   sys.exc_info()[-1].tb_lineno)
318
                    self.addMessage.emit(MessageType.Normal, message)
319

    
320
    '''
321
        @brief      rotate text
322
        @author     humkyung
323
        @date       2018.08.18
324
    '''
325

    
326
    def rotate(self):
327
        sx = 1
328
        sy = 1
329
        width = self.size[0]
330
        height = self.size[1]
331
        x = self.loc[0]
332
        y = self.loc[1]
333

    
334
        transform = QTransform()
335
        if (1.57 == self.angle) or (4.71 == self.angle):
336
            rect = self.boundingRect()
337
            sx = width / rect.height()
338
            sy = height / rect.width()
339

    
340
            transform.translate(x, y)
341
            transform.translate(width * 0.5, height * 0.5)
342
            transform.scale(1, sy)
343
            transform.rotateRadians(-self.angle)
344
            transform.translate(-rect.width() * 0.5, -rect.height() * 0.5)
345
        elif 3.14 == self.angle:
346
            rect = self.boundingRect()
347
            sx = width / rect.width()
348
            sy = height / rect.height()
349

    
350
            transform.translate(x, y - round((rect.height() - height) * 0.5))
351
            transform.scale(sx, 1)
352
            transform.rotateRadians(-self.angle)
353
            transform.translate(-width * 0.5, -height * 0.5)
354
        else:
355
            rect = self.boundingRect()
356
            sx = width / rect.width()
357
            sy = height / rect.height()
358

    
359
            # if '\n' not in text:
360
            transform.translate(x, y - round((rect.height() - height) * 0.5))
361
            transform.scale(sx, 1)
362

    
363
        self.setTransform(transform)
364
        self.update()
365

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

    
380
            sx = 1
381
            sy = 1
382
            width = self.size[0]
383
            height = self.size[1]
384
            x = self.loc[0]
385
            y = self.loc[1]
386
            rect = None
387
            lineCount = self.text().count('\n') if self.text().count('\n') is not 0 else 1
388
            transform = QTransform()
389

    
390
            allowed_error = 0.001
391
            if abs(self.angle - 1.57) < allowed_error:
392
                self.angle = 1.57
393
            elif abs(self.angle - 4.71) < allowed_error:
394
                self.angle = 4.71
395
            elif abs(self.angle - 3.14) < allowed_error:
396
                self.angle = 3.14
397
            else:
398
                self.angle = 0
399

    
400
            if abs(self.angle - 1.57) < allowed_error or abs(self.angle - 4.71) < allowed_error:
401
                font = QFont(fontName, width if fontSize == -1 else fontSize)
402

    
403
                x_factor = width / QFontMetricsF(font).height()
404
                y_factor = height / (QFontMetricsF(font).width(self.text()) / lineCount)
405
                factor = min(x_factor, y_factor)
406
                font.setPointSizeF(font.pointSizeF() * factor)
407

    
408
                self.setFont(font)
409
                rect = self.boundingRect()
410
                sx = width / rect.height()
411
                sy = height / rect.width()
412

    
413
                transform.translate(x, y)
414
                transform.translate(width * 0.5, height * 0.5)
415
                transform.scale(1, sy)
416
                transform.rotateRadians(-self.angle)
417
                transform.translate(-rect.width() * 0.5, -rect.height() * 0.5)
418
            elif abs(self.angle - 3.14) < allowed_error:
419
                font = QFont(fontName, height if fontSize == -1 else fontSize)
420

    
421
                x_factor = width / (QFontMetricsF(font).width(self.text()) / lineCount)
422
                y_factor = height / QFontMetricsF(font).height()
423
                factor = min(x_factor, y_factor)
424
                font.setPointSizeF(font.pointSizeF() * factor)
425

    
426
                self.setFont(font)
427
                rect = self.boundingRect()
428
                sx = width / rect.width()
429
                sy = height / rect.height()
430

    
431
                transform.translate(x, y - round((rect.height() - height) * 0.5))
432
                transform.scale(sx, 1)
433
                transform.rotateRadians(-self.angle)
434
                transform.translate(-width * 0.5, -height * 0.5)
435
            else:
436
                font = QFont(fontName, height if fontSize == -1 else fontSize)
437

    
438
                x_factor = width / (QFontMetricsF(font).width(self.text()) / lineCount)
439
                y_factor = height / QFontMetricsF(font).height()
440
                factor = min(x_factor, y_factor)
441
                font.setPointSizeF(font.pointSizeF() * factor)
442

    
443
                self.setFont(font)
444
                rect = self.boundingRect()
445

    
446
                """
447
                doc = self.document()
448
                doc.setDocumentMargin(0)
449
                doc.adjustSize()
450
                doc_size = doc.size()
451

452
                sx = rect.width() / doc_size.width()
453
                sy = rect.height() / doc_size.height()
454
                """
455

    
456
                sx = width / rect.width()
457
                sy = height / rect.height()
458

    
459
                # if '\n' not in text:
460
                transform.translate(x, y)
461
                # transform.scale(sx, 1)
462

    
463
            self.setTransform(transform)
464

    
465
            scene.addItem(self)
466
        except Exception as ex:
467
            from App import App
468
            from AppDocData import MessageType
469

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

    
475
    '''
476
        @brief  get connected items
477
        @author humkyung
478
        @date   2018.04.23
479
        @history    2018.11.22      euisung     fix note road
480
    '''
481

    
482
    def getConnectedItems(self):
483
        visited = []
484

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

    
501
        return visited
502

    
503
    @staticmethod
504
    def from_database(component):
505
        """ get text item from database """
506
        import uuid
507
        from AppDocData import AppDocData
508
        from TextItemFactory import TextItemFactory
509
        from SymbolAttr import SymbolAttr
510

    
511
        item = None
512

    
513
        try:
514
            x = float(component['X'])
515
            y = float(component['Y'])
516
            width = float(component['Width']) if component['Width'] is not None else 0
517
            height = float(component['Height']) if component['Height'] is not None else 0
518
            angle = float(component['Rotation']) if component['Rotation'] is not None else 0
519
            text = component['Value']
520
            textInfo = TextInfo(text, x, y, width, height, angle)
521
            connline = component['Connected'] if component['Connected'] is not None else None
522

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

    
532
                if component['Owner'] and component['Owner'] != 'None':
533
                    item._owner = uuid.UUID(component['Owner'])
534

    
535
                ## assign area
536
                if not component['Area']:
537
                    app_doc_data = AppDocData.instance()
538
                    for area in app_doc_data.getAreaList():
539
                        if area.contains([x, y]):
540
                            item.area = area.name
541
                            break
542
                else:
543
                    item.area = component['Area']
544
                ## up to here
545

    
546
                """ apply freeze value """
547
                # item.freeze_item.update_freeze(item.prop('Freeze'))
548

    
549
                if connline is not None:
550
                    item.conns.append(connline)
551
        except Exception as ex:
552
            from App import App
553
            from AppDocData import MessageType
554

    
555
            message = 'error occurred({}) in {}:{}'.format(ex, sys.exc_info()[-1].tb_frame.f_code.co_filename,
556
                                                           sys.exc_info()[-1].tb_lineno)
557
            App.mainWnd().addMessage.emit(MessageType.Error, message)
558
            return None
559

    
560
        return item
561

    
562
    '''
563
        @brief      parse xml code
564
        @author     humkyung
565
        @date       2018.09.15
566
    '''
567

    
568
    @staticmethod
569
    def fromXml(node):
570
        import uuid
571
        from TextItemFactory import TextItemFactory
572
        from AppDocData import AppDocData
573
        from EngineeringNoteItem import QEngineeringNoteItem
574
        from QEngineeringSizeTextItem import QEngineeringSizeTextItem
575
        from EngineeringValveOperCodeTextItem import QEngineeringValveOperCodeTextItem
576

    
577
        item = None
578

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

    
593
            item = TextItemFactory.instance().createTextItem(textInfo)
594
            if item is not None:
595
                item.loc = [x, y]
596
                item.size = [width, height]
597
                item.angle = angle
598

    
599
            # set uid and owner of item
600
            if item is not None:
601
                item.uid = uuid.UUID(node.find('UID').text)
602
                item.setVisible(False)
603

    
604
                if node.find('OWNER') is not None and node.find('OWNER').text != 'None':
605
                    item._owner = uuid.UUID(node.find('OWNER').text)
606

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

    
622
            message = 'error occurred({}) in {}:{}'.format(ex, sys.exc_info()[-1].tb_frame.f_code.co_filename,
623
                                                           sys.exc_info()[-1].tb_lineno)
624
            App.mainWnd().addMessage.emit(MessageType.Error, message)
625

    
626
        return item
627

    
628
    '''
629
        @brief      generate xml code
630
        @author     humkyung
631
        @date       2018.04.23
632
        @history    humkyung 2018.04.27 move to QEngineeringLineNoTextItem
633
                    humkyung 2018.05.02 add name as parameter
634
                    Jeongwoo 2018.05.30 Change variable [owner] is nullable and Add/Modify attributes
635
    '''
636

    
637
    def toXml(self, owner=None):
638
        from xml.etree.ElementTree import Element, SubElement, dump, ElementTree
639
        from EngineeringLineItem import QEngineeringLineItem
640
        from SymbolSvgItem import SymbolSvgItem
641

    
642
        try:
643
            node = Element('ATTRIBUTE')
644
            uidNode = Element('UID')
645
            uidNode.text = str(self.uid)
646
            node.append(uidNode)
647

    
648
            # write owner's uid to xml
649
            ownerNode = Element('OWNER')
650
            if self.owner is not None:
651
                ownerNode.text = str(self.owner)
652
            else:
653
                ownerNode.text = 'None'
654
            node.append(ownerNode)
655
            # up to here
656

    
657
            attributeValueNode = Element('ATTRIBUTEVALUE')
658
            attributeValueNode.text = self.attribute
659
            node.append(attributeValueNode)
660

    
661
            nameNode = Element('NAME')
662
            nameNode.text = self.type
663
            node.append(nameNode)
664

    
665
            locNode = Element('LOCATION')
666
            locNode.text = '{},{}'.format(self.loc[0], self.loc[1])
667
            node.append(locNode)
668

    
669
            valueNode = Element('VALUE')
670
            valueNode.text = self.text()
671
            node.append(valueNode)
672

    
673
            angleNode = Element('ANGLE')
674
            angleNode.text = str(self.angle)
675
            node.append(angleNode)
676

    
677
            widthNode = Element('WIDTH')
678
            widthNode.text = str(self.size[0])
679
            node.append(widthNode)
680

    
681
            heightNode = Element('HEIGHT')
682
            heightNode.text = str(self.size[1])
683
            node.append(heightNode)
684

    
685
            areaNode = Element('AREA')
686
            areaNode.text = self.area
687
            node.append(areaNode)
688

    
689
            sceneNode = Element('SCENE')
690
            rect = self.sceneBoundingRect()
691
            sceneNode.text = '{},{},{},{}'.format(rect.x(), rect.y(), rect.width(), rect.height())
692
            node.append(sceneNode)
693

    
694
        except Exception as ex:
695
            from App import App
696
            from AppDocData import MessageType
697

    
698
            message = 'error occurred({}) in {}:{}'.format(ex, sys.exc_info()[-1].tb_frame.f_code.co_filename,
699
                                                           sys.exc_info()[-1].tb_lineno)
700
            App.mainWnd().addMessage.emit(MessageType.Error, message)
701

    
702
            return None
703

    
704
        return node
705

    
706
    def findOwner(self, symbols):
707
        import math
708

    
709
        try:
710
            minDist = None
711
            selected = None
712

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

    
716
            dist = (self.sceneBoundingRect().height() + self.sceneBoundingRect().width()) * ratio / 2
717
            center = self.sceneBoundingRect().center()
718

    
719
            target_symbols = []
720
            for symbol in symbols:
721
                attrs = symbol.getAttributes()
722

    
723
                freeze = False
724
                for attr in attrs:
725
                    if attr.Freeze:
726
                        freeze = True
727
                        break
728
                if freeze: continue
729
                for attr in attrs:
730
                    ret = attr.Codes.find_match_exactly(self.text())
731
                    if ret:
732
                        target_symbols.append(symbol)
733
                        break
734

    
735
            for symbol in target_symbols:
736
                if issubclass(type(symbol), SymbolSvgItem):
737
                    dx = symbol.origin[0] - center.x()
738
                    dy = symbol.origin[1] - center.y()
739

    
740
                    offset = (symbol.sceneBoundingRect().width() + symbol.sceneBoundingRect().height()) / 4
741
                    length = math.sqrt(dx * dx + dy * dy) - offset
742

    
743
                    if (length < dist) and (minDist is None or length < minDist):
744
                        minDist = length
745
                        selected = symbol
746

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

    
767
    '''
768
        @brief      Set Color. Override QEngineeringAbstractItem's
769
        @author     Jeongwoo
770
        @date       2018.05.11
771
        @history    humkyung 2018.05.13 update after change color
772
    '''
773

    
774
    def setColor(self, color):
775
        if QColor.isValidColor(color):
776
            c = QColor()
777
            c.setNamedColor(color)
778
            self.setDefaultTextColor(c)
779
            self.update()
780

    
781
    def toSql(self):
782
        """ convert text data to sql query for components and title block """
783
        from AppDocData import AppDocData
784

    
785
        res = []
786

    
787
        appDocData = AppDocData.instance()
788
        cols = ['UID', 'Drawings_UID', 'Symbol_UID', 'X', 'Y', 'Width', 'Height', 'Rotation', 'Area', 'Value', 'Owner',
789
                'Connected', 'SpecialItemTypes_UID']
790
        values = ['?', '?', "(select UID from Symbol where Name='Text' and SymbolType_UID=-1)", '?', '?', '?', '?', '?',
791
                  '?', '?', '?', '?', '?']
792

    
793
        param = [
794
            (str(self.uid), str(appDocData.activeDrawing.UID), self.loc[0], self.loc[1], self.size[0], self.size[1],
795
             str(self.angle),
796
             self.area, self.text(), \
797
             str(self.owner) if self.owner else None, \
798
             str(self.conns[0]) if self.conns else None, \
799
             str(self.special_item_type) if self.special_item_type else None)]
800
        sql = 'insert into Components({}) values({})'.format(','.join(cols), ','.join(values))
801
        res.append((sql, tuple(param)))
802

    
803
        titleBlockProps = appDocData.getTitleBlockProperties()
804
        if titleBlockProps:
805
            cols = ['UID', 'Drawings_UID', 'TitleBlockProperties_UID', 'VALUE']
806
            values = ['?', '?', '?', '?']
807
            params = []
808
            for titleBlockProp in titleBlockProps:
809
                if self.area == titleBlockProp[0]:
810
                    params.append((str(self.uid), appDocData.activeDrawing.UID, self.area, self.text()))
811

    
812
            sql = 'insert into TitleBlockValues({}) values({})'.format(','.join(cols), ','.join(values))
813
            if params: res.append((sql, tuple(params)))
814

    
815
        return res
816

    
817

    
818
'''
819
    @brief      The class transfer pyqtSignal Event. Cause Subclass of QGraphicsRectItem can't use pyqtSignal
820
    @author     Jeongwoo
821
    @date       2018.06.18
822
'''
823

    
824

    
825
class Transfer(QObject):
826
    onRemoved = pyqtSignal(QGraphicsItem)
827

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