프로젝트

일반

사용자정보

통계
| 개정판:

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

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

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

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

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

    
25

    
26
class Highlighter(QSyntaxHighlighter):
27
    err_format = QTextCharFormat()
28
    err_format.setUnderlineColor(Qt.red)
29
    err_format.setUnderlineStyle(QTextCharFormat.SpellCheckUnderline)
30

    
31
    def __init__(self, *args):
32
        QSyntaxHighlighter.__init__(self, *args)
33

    
34
        self.white_char_list = None
35

    
36
    def highlightBlock(self, text):
37
        pos = 0
38
        for word in text.split():
39
            if self.white_char_list and any((c not in self.white_char_list) for c in word):
40
                self.setFormat(pos, len(word), self.err_format)
41
            pos += len(word) + 1
42

    
43

    
44
class QEngineeringTextItem(QGraphicsTextItem, QEngineeringAbstractItem):
45
    HIGHLIGHT = '#BC4438'
46
    ZVALUE = 210
47

    
48
    '''
49
        @history    2018.05.17  Jeongwoo    Add self._owner variable
50
    '''
51

    
52
    def __init__(self, uid=None, parent=None):
53
        import uuid
54

    
55
        QGraphicsTextItem.__init__(self, parent)
56
        QEngineeringAbstractItem.__init__(self)
57

    
58
        self.uid = uuid.uuid4() if uid is None else uuid.UUID(uid)
59
        self.type = 'TEXT'
60
        self.loc = None
61
        self.size = None
62
        self.angle = 0  # angle in radian
63
        self._owner = None
64
        self.setFlags(QGraphicsItem.ItemIsSelectable | QGraphicsItem.ItemIsFocusable | QGraphicsItem.ItemIsMovable | QGraphicsItem.ItemSendsGeometryChanges)
65
        #self.setFlags(QGraphicsItem.ItemIsSelectable | QGraphicsItem.ItemIsFocusable | QGraphicsItem.ItemIsMovable)
66
        self.setAcceptHoverEvents(True)
67
        self.setAcceptTouchEvents(True)
68

    
69
        self.setColor(self._color)
70
        self._savedColor = None
71

    
72
        self.delimiter = '"'
73
        self.lineNoDelimiter = '!-!'
74

    
75
        self.attribute = ''
76
        self._properties = {}
77

    
78
        self.highlighter = None
79

    
80
        self.transfer = Transfer()
81
        self.setZValue(QEngineeringTextItem.ZVALUE)
82

    
83
    def __str__(self):
84
        """ return string represent uuid """
85
        return str(self.uid)
86

    
87
    '''
88
        @brief      Get owner
89
        @author     Jeongwoo
90
        @date       2018.05.17
91
    '''
92
    @property
93
    def owner(self):
94
        import uuid
95

    
96
        # find owner with uid
97
        if self.scene() and self._owner and type(self._owner) is uuid.UUID:
98
            #matches = [x for x in self.scene().items() if hasattr(x, 'uid') and str(x.uid) == str(self._owner)]
99
            matches = []
100
            for x in self.scene().items():
101
                if hasattr(x, 'uid') and str(x.uid) == str(self._owner):
102
                    matches = [x]
103
                    break
104
            if matches:
105
                self._owner = matches[0]
106
                
107
            return matches[0] if matches else None
108
        # up to here
109

    
110
        if type(self._owner) is not uuid.UUID and type(self._owner) is not str:
111
            return self._owner
112
        else:
113
            self._owner = None
114
            return None
115

    
116
    '''
117
        @brief      Set owner
118
        @author     Jeongwoo
119
        @date       2018.05.17
120
        @history    2018.05.17  Jeongwoo    Add Calling setColor if self._owner is None or not
121
    '''
122
    @owner.setter
123
    def owner(self, value):
124
        self._owner = value
125

    
126
        if self._owner is None:
127
            self._color = self.DEFAULT_COLOR
128
        self.setColor(self._color)
129

    
130
    '''
131
        @brief  return text string
132
        @author humkyung
133
        @date   2018.04.16
134
    '''
135
    def text(self):
136
        return self.toPlainText()
137

    
138
    '''
139
        @brief  return center position of text
140
        @author humkyung
141
        @date   2018.04.16
142
    '''
143
    def center(self):
144
        return self.sceneBoundingRect().center()
145

    
146
    @property
147
    def text_size(self):
148
        if self.angle == 1.57 or self.angle == 4.71:
149
            return QRectF(0, 0, self.size[1], self.size[0])
150
        else:
151
            return QRectF(0, 0, self.size[0], self.size[1])
152

    
153
    def boundingRect(self) -> QRectF:
154
        return self.text_size
155

    
156
    '''
157
        @brief      hover event
158
        @authro     humkyung
159
        @date       
160
    '''
161
    def hoverEnterEvent(self, event):
162
        self.highlight(True)
163

    
164
    def hoverLeaveEvent(self, event):
165
        self.highlight(False)
166

    
167
    '''
168
        @brief      set highlight
169
        @author     kyouho
170
        @date       2018.08.27
171
    '''
172
    def highlight(self, flag):
173
        self.hover = flag
174
        if flag:
175
            if self._savedColor is None:
176
                self._savedColor = self.getColor()
177
            self.setColor(QEngineeringTextItem.HIGHLIGHT)
178
        elif hasattr(self, '_savedColor'):
179
            self.setColor(self._savedColor)
180

    
181
        self.update()
182

    
183
    def hoverMoveEvent(self, event):
184
        pass
185

    
186
    def validate(self):
187
        """ validation check """
188

    
189
        from EngineeringLineItem import QEngineeringLineItem
190

    
191
        errors = []
192

    
193
        try:
194
            app_doc_data = AppDocData.instance()
195
            dataPath = app_doc_data.getErrorItemSvgPath()
196

    
197
            # check overlapping
198
            texts = [item for item in self.scene().items() if item is not self and issubclass(type(item), QEngineeringTextItem)]
199
            for text in texts:
200
                textRect = text.sceneBoundingRect()
201
                rect1 = QRectF(textRect.left() - 3, textRect.top() - 3, textRect.width() + 6, textRect.height() + 6)
202
                rect2 = QRectF(textRect.left() + 3, textRect.top() + 3, textRect.width() - 6, textRect.height() - 6)
203
                if rect1.contains(self.sceneBoundingRect()) or rect2.contains(self.sceneBoundingRect().center()):
204
                    error = SymbolSvgItem.createItem('Error', None, dataPath)
205
                    error.parent = self
206
                    error.msg = self.tr('Text overlapping warning')
207
                    error.setToolTip(error.msg)
208
                    error.area = self.area
209
                    error.name = 'Warning'
210
                    error.items = [ text ]
211
                    errors.append(error)
212

    
213
                    error.setPosition([self.sceneBoundingRect().center().x(), self.sceneBoundingRect().center().y()])
214

    
215
            lines = [item for item in self.scene().items() if item is not self and issubclass(type(item), QEngineeringLineItem)]
216
            for line in lines:
217
                lineRect = line.sceneBoundingRect()
218
                if lineRect.intersects(self.sceneBoundingRect()):
219
                    error = SymbolSvgItem.createItem('Error', None, dataPath)
220
                    error.parent = self
221
                    error.msg = self.tr('Text overlapping waring')
222
                    error.setToolTip(error.msg)
223
                    error.area = self.area
224
                    error.name = 'Warning'
225
                    error.items = [ line ]
226
                    errors.append(error)
227

    
228
                    error.setPosition([self.sceneBoundingRect().center().x(), self.sceneBoundingRect().center().y()])
229

    
230
            if self.owner:
231
                if self not in self.owner.associations():
232
                    error = SymbolSvgItem.createItem('Error', None, dataPath)
233
                    error.parent = self
234
                    error.msg = self.tr('Association error')
235
                    error.setToolTip(error.msg)
236
                    error.area = self.area
237
                    error.name = 'Error'
238
                    error.items = [ self.owner ]
239
                    errors.append(error)
240

    
241
                    error.setPosition([self.sceneBoundingRect().center().x(), self.sceneBoundingRect().center().y()])
242
                            
243
        except Exception as ex:
244
            from App import App
245
            message = 'error occurred({}) in {}:{}'.format(ex, sys.exc_info()[-1].tb_frame.f_code.co_filename,
246
                                                          sys.exc_info()[-1].tb_lineno)
247
            App.mainWnd().addMessage.emit(MessageType.Error, message)
248

    
249
        return errors
250

    
251
    def contextMenuEvent(self, event):
252
        items = self.scene().selectedItems()
253
        if len(items) > 0 and self in items:
254
            menu = QMenu()
255

    
256
            if len(items) > 1:
257
                mergeAction = QAction('Merge(M)', None)
258
                mergeAction.triggered.connect(self.contextMerge)
259
                menu.addAction(mergeAction)
260

    
261
            if len(items) == 2:
262
                switchAction = QAction('Switch(S)', None)
263
                switchAction.triggered.connect(self.contextSwitch)
264
                menu.addAction(switchAction)
265

    
266
            if len(items) > 1:
267
                alignAction = QAction('Resize Selected Texts with This ', None)
268
                alignAction.triggered.connect(self.contextResizeText)
269
                menu.addAction(alignAction)
270

    
271
            if len(items) == 1:
272
                allAction = QAction('Select All in View(A)', None)
273
                allAction.triggered.connect(self.contextSelectAll)
274
                menu.addAction(allAction)
275

    
276
                editAction = QAction('Edit(Return)', None)
277
                editAction.triggered.connect(self.contextEdit)
278
                menu.addAction(editAction)
279

    
280
                rotateAction = QAction('Rotate(R)', None)
281
                rotateAction.triggered.connect(self.contextRotate)
282
                menu.addAction(rotateAction)
283

    
284
            if len(items) >= 1:
285
                trimAction = QAction('Remove Space', None)
286
                trimAction.triggered.connect(self.contextTrim)
287
                menu.addAction(trimAction)
288

    
289
            deleteAction = QAction('Delete(E)', None)
290
            deleteAction.triggered.connect(self.contextDelete)
291
            menu.addAction(deleteAction)
292

    
293
            menu.exec_(event.screenPos())
294

    
295
    def contextSelectAll(self):
296
        from QEngineeringSizeTextItem import QEngineeringSizeTextItem
297
        from App import App
298
        
299
        rect = App.mainWnd().graphicsView.viewport().rect()
300
        view_rect = App.mainWnd().graphicsView.mapToScene(rect).boundingRect()
301
        lineNos = [item for item in self.scene().items() if type(item) is type(self) and view_rect.contains(item.sceneBoundingRect().center())]
302
        for lineNo in lineNos:
303
            lineNo.setSelected(True)
304

    
305
    def contextSwitch(self):
306
        textItems = [item for item in self.scene().selectedItems() if issubclass(type(item), QEngineeringTextItem)]
307
        if len(textItems) != 2:
308
            return
309
        
310
        text1 = textItems[0]
311
        text2 = textItems[1]
312

    
313
        loc1 = [text1.center().x(), text1.center().y()]
314
        loc2 = [text2.center().x(), text2.center().y()]
315

    
316
        text1.moveText(1, 0, round(loc2[0] - loc1[0]))
317
        text1.moveText(0, 1, round(loc2[1] - loc1[1]))
318
        text2.moveText(1, 0, round(loc1[0] - loc2[0]))
319
        text2.moveText(0, 1, round(loc1[1] - loc2[1]))
320

    
321
    def contextResizeText(self):
322
        from QEngineeringTrimLineNoTextItem import QEngineeringLineNoTextItem
323

    
324
        textItems = [item for item in self.scene().selectedItems() if item is not self and issubclass(type(item), QEngineeringTextItem) and type(item) is not QEngineeringLineNoTextItem]
325
        allowed_error = 0.01
326

    
327
        for text in textItems:
328
            if abs(self.angle - text.angle) < allowed_error:
329
                dx = round(self.size[0] - text.size[0])
330
                dy = round(self.size[1] - text.size[1])
331
            else:
332
                dx = round(self.size[1] - text.size[0])
333
                dy = round(self.size[0] - text.size[1])
334

    
335
            text.size[1] = text.size[1] + dy
336
            if abs(text.angle - 1.57) < allowed_error or abs(text.angle - 3.14) < allowed_error:
337
                text.loc[1] = text.loc[1] - dy
338

    
339
            text.size[0] = text.size[0] + dx
340
            if abs(text.angle - 4.71) < allowed_error or abs(text.angle - 4.71) < allowed_error or abs(text.angle - 3.14) < allowed_error:
341
                text.loc[0] = text.loc[0] - dx
342

    
343
            text.update_font()
344
            text.update()
345

    
346
    def contextTrim(self):
347
        textItems = [item for item in self.scene().selectedItems() if type(item) is QEngineeringTextItem]
348

    
349
        for text in textItems:
350
            text.setPlainText(text.text().replace(' ', ''))
351

    
352
    def contextMerge(self):
353
        event = QKeyEvent(QEvent.KeyPress, Qt.Key_M, Qt.NoModifier)
354
        self.keyPressEvent(event)
355

    
356
    def contextDelete(self):
357
        event = QKeyEvent(QEvent.KeyPress, Qt.Key_Delete, Qt.NoModifier)
358
        self.scene().keyPressEvent(event)
359

    
360
    def contextEdit(self):
361
        event = QKeyEvent(QEvent.KeyPress, Qt.Key_Return, Qt.NoModifier)
362
        self.keyPressEvent(event)
363

    
364
    def contextRotate(self):
365
        self.textRotate()
366

    
367
    def textRotate(self):
368
        # degree 0
369
        if 0 == self.angle:
370
            self.angle = 1.57
371
        # degree 90
372
        elif 1.57 == self.angle:
373
            self.angle = 3.14
374
        # degree 180
375
        elif 3.14 == self.angle:
376
            self.angle = 4.71
377
        # degree 270
378
        elif 4.71 == self.angle:
379
            self.angle = 0
380

    
381
        width = self.size[0]
382
        height = self.size[1]
383
        self.size = [height, width]
384

    
385
        self.rotate()
386

    
387
    def keyPressEvent(self, event):
388
        #print('item :' + str(event.key()))
389
        if Qt.Key_Return == event.key():
390
            self.edit_text()
391
        elif event.key() == Qt.Key_Up:  # translate up/down/left/right
392
            modifiers = QApplication.keyboardModifiers()
393
            delta = 10 if modifiers == Qt.ControlModifier else 1
394

    
395
            self.moveText(0, -1, delta)
396
        elif event.key() == Qt.Key_Down:
397
            modifiers = QApplication.keyboardModifiers()
398
            delta = 10 if modifiers == Qt.ControlModifier else 1
399

    
400
            self.moveText(0, 1, delta)
401
        elif event.key() == Qt.Key_Left:
402
            modifiers = QApplication.keyboardModifiers()
403
            delta = 10 if modifiers == Qt.ControlModifier else 1
404

    
405
            self.moveText(-1, 0, delta)
406
        elif event.key() == Qt.Key_Right:
407
            modifiers = QApplication.keyboardModifiers()
408
            delta = 10 if modifiers == Qt.ControlModifier else 1
409

    
410
            self.moveText(1, 0, delta)
411
        elif event.key() == Qt.Key_Plus or event.key() == 61:
412
            pass
413
            '''
414
            allowed_error = 0.01
415
            modifiers = QApplication.keyboardModifiers()
416
            delta = False if modifiers != Qt.ControlModifier else True
417
            if delta:
418
                self.size[1] = self.size[1] + 5
419
                if abs(self.angle - 1.57) < allowed_error or abs(self.angle - 3.14) < allowed_error:
420
                    self.loc[1] = self.loc[1] - 5
421
                    #self.moveText(0, 1, 5)
422
            else:
423
                self.size[0] = self.size[0] + 5
424
                if abs(self.angle - 4.71) < allowed_error or abs(self.angle - 4.71) < allowed_error or abs(self.angle - 3.14) < allowed_error:
425
                    self.loc[0] = self.loc[0] - 5
426
                    #self.moveText(1, 0, 5)
427

428
            self.update_font()
429
            self.update()
430
            '''
431
        elif event.key() == Qt.Key_Minus:
432
            pass
433
            '''
434
            allowed_error = 0.01
435
            modifiers = QApplication.keyboardModifiers()
436
            delta = False if modifiers != Qt.ControlModifier else True
437
            if delta:
438
                if self.size[1] - 5 > 10:
439
                    self.size[1] = self.size[1] - 5
440
                    if abs(self.angle - 1.57) < allowed_error or abs(self.angle - 3.14) < allowed_error:
441
                        self.loc[1] = self.loc[1] + 5
442
                        #self.moveText(0, -1, 5)
443
            else:
444
                if self.size[0] - 5 > 10:
445
                    self.size[0] = self.size[0] - 5
446
                    if abs(self.angle - 4.71) < allowed_error or abs(self.angle - 4.71) < allowed_error or abs(self.angle - 3.14) < allowed_error:
447
                        self.loc[0] = self.loc[0] + 5
448
                        #self.moveText(-1, 0, 5)
449
            self.update_font()
450
            self.update()
451
            '''
452
        elif event.key() == Qt.Key_M:
453
            from App import App
454

    
455
            App.mainWnd().keyPressEvent(event)
456
        elif event.key() == Qt.Key_A:
457
            self.contextSelectAll()
458
        elif event.key() == Qt.Key_S:
459
            self.contextSwitch()
460

    
461
        # QGraphicsTextItem.keyPressEvent(self, event)
462
            
463
    def moveText(self, _dx, _dy, delta):
464
        trans = QTransform()
465
        trans.rotateRadians(self.angle)
466
        dx, dy = trans.map(_dx, _dy)
467
        if dx:
468
            if dx > 0:
469
                self.loc[0] = self.loc[0] + delta
470
            else:
471
                self.loc[0] = self.loc[0] - delta
472
        else:
473
            if dy > 0:
474
                self.loc[1] = self.loc[1] + delta
475
            else:
476
                self.loc[1] = self.loc[1] - delta
477

    
478
        trans = self.transform()
479
        trans.translate(dx * delta, dy * delta)
480
        self.setTransform(trans)
481

    
482
    def mouseMoveEvent(self, event):
483
        modifiers = QApplication.keyboardModifiers()
484
        if modifiers == Qt.ShiftModifier:
485
            super().mouseMoveEvent(event)
486
    
487
    def itemChange(self, change, value):
488
        """ call signals when item's position or rotation is changed """
489
        if not self.scene(): return super().itemChange(change, value)
490

    
491
        if change == QGraphicsItem.ItemPositionHasChanged:
492

    
493
            scene_origin = self.sceneBoundingRect()
494
            configs = AppDocData.instance().getConfigs('Data', 'Grid')
495
            grid = int(configs[0].value) if 1 == len(configs) else -1
496
            if grid == 1:
497
                self.loc = [round(scene_origin.x()), round(scene_origin.y())]
498
            else:
499
                self.loc = [round(scene_origin.x(), 1), round(scene_origin.y(), 1)]
500

    
501
            if hasattr(self.scene(), 'contents_changed'):
502
                self.scene().contents_changed.emit()
503

    
504
            return value
505

    
506
        return super().itemChange(change, value)
507

    
508
    '''
509
        @brief  draw rect when item is selected
510
        @author humkyung
511
        @date   2018.07.08
512
    '''
513
    def drawFocusRect(self, painter):
514
        if not hasattr(self, '_focus_pen'):
515
            self._focus_pen = QPen(Qt.DotLine)
516
            self._focus_pen.setColor(Qt.black)
517
            self._focus_pen.setWidthF(1.5)
518

    
519
        if not hasattr(self, '_hilight_color'):
520
            self._hilight_color = QColor(255, 0, 0, 127)
521
        painter.setBrush(QBrush(self._hilight_color))
522

    
523
        painter.setPen(self._focus_pen)
524
        painter.drawRect(self.text_size)
525

    
526
    '''
527
        @brief  override paint(draw connection points)
528
        @author humkyung
529
        @date   2018.07.08
530
    '''
531
    def paint(self, painter, options=None, widget=None):
532
        import math
533

    
534
        painter.setClipRect(options.exposedRect)
535

    
536
        self.setColor(self.getColor())
537

    
538
        #if self.angle == 1.57 or self.angle == 4.71:
539
        #    rect = QRectF(0, 0, self.size[1], self.size[0])
540
        #else:
541
        #    rect = QRectF(0, 0, self.size[0], self.size[1])
542

    
543
        # draw onwer indicator
544
        if self.owner and issubclass(type(self.owner), QEngineeringAbstractItem):
545
            painter.setPen(Qt.magenta)
546
            rect = self.text_size
547
            center = self.sceneBoundingRect().center()
548
            center2 = self.owner.sceneBoundingRect().center()
549
            dx = center2.x() - center.x()
550
            dy = center2.y() - center.y()
551
            if self.angle == 1.57:
552
                rad = 90 * (math.pi / 180.0)
553
                nx = math.cos(rad) * dx - math.sin(rad) * dy
554
                ny = math.sin(rad) * dx + math.cos(rad) * dy
555
                dx, dy = nx, ny
556
            painter.drawLine(rect.center().x(), rect.center().y(), rect.center().x() + dx, rect.center().y() + dy)
557

    
558
        painter.setFont(self.font())
559
        color = self.defaultTextColor()
560

    
561
        # draw white background during hover
562
        if self.hover:
563
            configs = AppDocData.instance().getConfigs('Text', 'Background')
564
            if not configs or not int(configs[0].value) != 1:
565
                painter.setPen(Qt.NoPen)
566
                painter.setBrush(Qt.white)
567
                painter.drawRect(self.text_size)
568
        # up to here
569

    
570
        painter.setPen(QPen(color))
571

    
572
        if self.isSelected():
573
            self.drawFocusRect(painter)
574

    
575
        #painter.drawText(rect, Qt.AlignCenter, self.text())
576
        QGraphicsTextItem.paint(self, painter, options, widget)
577

    
578
    '''
579
        @brief      Return real item position
580
        @author     Jeongwoo
581
        @date       2018.05.25
582
    '''
583

    
584
    def boundingRectOnScene(self):
585
        rect = self.text_size
586
        rect.moveTo(self.loc[0], self.loc[1])
587
        return rect
588

    
589
    @staticmethod
590
    def create_text_with(scene, text_info):
591
        """create a text using text_info"""
592
        from TextItemFactory import TextItemFactory
593

    
594
        x = text_info.getX()
595
        y = text_info.getY()
596
        angle = text_info.getAngle()
597
        text = text_info.getText()
598
        if not text.replace(' ', '').replace('\n', ''):
599
            return None
600
        width = text_info.getW()
601
        height = text_info.getH()
602

    
603
        configs = AppDocData.instance().getConfigs('Text Style', 'Font Size')
604
        fontSize = int(configs[0].value) if configs else -1
605
        if fontSize != -1:
606
            textItems = [item for item in scene.items() if issubclass(type(item), QEngineeringTextItem)]
607
            if textItems:
608
                _height = textItems[0].size[1] if textItems[0].angle == 0 else textItems[0].size[0]
609
                if angle == 0:
610
                    height = _height
611
                else:
612
                    width = _height
613

    
614
        item = TextItemFactory.instance().createTextItem(text_info)
615
        if item is not None:
616
            item.loc = [x, y]
617
            item.size = [width, height]
618
            item.angle = angle
619
            item.addTextItemToScene(scene)
620

    
621
        return item
622

    
623
    def edit_text(self):
624
        """edit text by using ocr dialog"""
625
        from TextItemFactory import TextItemFactory
626
        from OcrResultDialog import QOcrResultDialog
627

    
628
        item = None
629
        try:
630
            dialog = QOcrResultDialog(None, self.scene().views()[0].image().copy(self.loc[0], self.loc[1],
631
                                                                               self.size[0], self.size[1]),
632
                                      QRect(self.loc[0], self.loc[1], self.size[0], self.size[1]), text_item=self)
633
            (res, textInfoList) = dialog.showDialog()
634

    
635
            if QDialog.Accepted == res and textInfoList:
636
                # create new texts
637
                for text_info in textInfoList:
638
                    item = QEngineeringTextItem.create_text_with(self.scene(), text_info)
639
                    if item:
640
                        item.area = self.area
641
                        item.transfer.onRemoved.connect(self.transfer.onRemoved)
642
                        #item.transfer.onRemoved.connect(App.mainWnd().itemRemoved)
643

    
644
                self.transfer.onRemoved.emit(self)
645
        except Exception as ex:
646
            from App import App
647
            from AppDocData import MessageType
648

    
649
            message = 'error occurred({}-{}) in {}:{}'.format(repr(ex), self.text(),
650
                                                              sys.exc_info()[-1].tb_frame.f_code.co_filename,
651
                                                              sys.exc_info()[-1].tb_lineno)
652
            App.mainWnd().addMessage.emit(MessageType.Error, message)
653

    
654
        return item
655

    
656
    def focusOutEvent(self, event: QFocusEvent) -> None:
657
        self.setTextInteractionFlags(Qt.NoTextInteraction)
658
        super(QEngineeringTextItem, self).focusOutEvent(event)
659

    
660
    '''
661
        @brief      Double click event, Show QOcrResultDialog
662
        @author     Jeongwoo
663
        @date       18.04.23
664
        @history    18.06.20    Jeongwoo    Resize QRect added 1
665
    '''
666

    
667
    def mouseDoubleClickEvent(self, event):
668
        if event.buttons() == Qt.LeftButton:
669
            """
670
            if self.textInteractionFlags() == Qt.NoTextInteraction:
671
                self.setTextInteractionFlags(Qt.TextEditorInteraction)
672
                self.setFocus()
673
            """
674
            self.edit_text()
675
        super(QGraphicsTextItem, self).mouseDoubleClickEvent(event)
676

    
677
    '''
678
        @brief      rotate text
679
        @author     humkyung
680
        @date       2018.08.18
681
    '''
682

    
683
    def rotate(self):
684
        sx = 1
685
        sy = 1
686
        width = self.size[0]
687
        height = self.size[1]
688
        x = self.loc[0]
689
        y = self.loc[1]
690

    
691
        transform = QTransform()
692
        if (1.57 == self.angle) or (4.71 == self.angle):
693
            rect = self.text_size
694
            sx = width / rect.height()
695
            sy = height / rect.width()
696

    
697
            transform.translate(x, y)
698
            transform.translate(width * 0.5, height * 0.5)
699
            transform.scale(1, sy)
700
            transform.rotateRadians(-self.angle)
701
            transform.translate(-rect.width() * 0.5, -rect.height() * 0.5)
702
        elif 3.14 == self.angle:
703
            rect = self.text_size
704
            sx = width / rect.width()
705
            sy = height / rect.height()
706

    
707
            transform.translate(x, y - round((rect.height() - height) * 0.5))
708
            transform.scale(sx, 1)
709
            transform.rotateRadians(-self.angle)
710
            transform.translate(-width * 0.5, -height * 0.5)
711
        else:
712
            rect = self.text_size
713
            sx = width / rect.width()
714
            sy = height / rect.height()
715

    
716
            # if '\n' not in text:
717
            transform.translate(x, y - round((rect.height() - height) * 0.5))
718
            transform.scale(sx, 1)
719

    
720
        self.setTransform(transform)
721
        self.update()
722

    
723
    def text_width(self, font):
724
        """return text width"""
725
        text_width = 0
726
        for _text in self.text().split('\n'):
727
            """
728
            rect = QFontMetricsF(font).tightBoundingRect(_text)
729
            text_width = max(rect.width(), text_width)
730
            """
731
            text_width = max(QFontMetricsF(font).width(_text), text_width)
732

    
733
        return text_width
734
    
735
    def update_font(self):
736
        app_doc_data = AppDocData.instance()
737
        configs = app_doc_data.getConfigs('Text Style', 'Font Name')
738
        fontName = configs[0].value if configs else 'Arial'
739
        configs = app_doc_data.getConfigs('Text Style', 'Font Size')
740
        fontSize = int(configs[0].value) if configs else -1
741

    
742
        width = self.size[0]
743
        height = self.size[1]
744

    
745
        allowed_error = 0.01
746
        if abs(self.angle - 1.57) < allowed_error or abs(self.angle - 4.71) < allowed_error:
747
            font = QFont(fontName, width if fontSize == -1 else fontSize)
748
            font.setBold(True)
749

    
750
            x_factor = width / QFontMetricsF(font).height() #self.text()).height() / line_count)
751
            y_factor = height / self.text_width(font)
752
            factor = min(x_factor, y_factor)
753
            font.setPointSizeF(font.pointSizeF() * factor)
754
            self.setFont(font)
755
        elif abs(self.angle - 3.14) < allowed_error:
756
            font = QFont(fontName, height if fontSize == -1 else fontSize)
757
            font.setBold(True)
758

    
759
            x_factor = width / self.text_width(font)
760
            y_factor = height / QFontMetricsF(font).height() #self.text()).height() / line_count)
761
            factor = min(x_factor, y_factor)
762
            font.setPointSizeF(font.pointSizeF() * factor)
763
            self.setFont(font)
764
        else:
765
            font = QFont(fontName, height if fontSize == -1 else fontSize)
766
            font.setBold(True)
767

    
768
            x_factor = width / self.text_width(font)
769
            y_factor = height / QFontMetricsF(font).height() #.boun(self.text()).height() / line_count)
770
            factor = min(x_factor, y_factor)
771
            font.setPointSizeF(font.pointSizeF() * factor)
772
            self.setFont(font)
773

    
774
    def update_shape(self):
775
        """update text shape"""
776

    
777
        try:
778
            app_doc_data = AppDocData.instance()
779
            configs = app_doc_data.getConfigs('Text Style', 'Font Name')
780
            fontName = configs[0].value if configs else 'Arial'
781
            configs = app_doc_data.getConfigs('Text Style', 'Font Size')
782
            fontSize = int(configs[0].value) if configs else -1
783

    
784
            sx = 1
785
            sy = 1
786
            width = self.size[0]
787
            height = self.size[1]
788
            x = self.loc[0]
789
            y = self.loc[1]
790
            rect = None
791
            line_count = self.text().count('\n') if self.text().count('\n') is not 0 else 1
792

    
793
            allowed_error = 0.01
794
            if abs(self.angle - 1.57) < allowed_error:
795
                self.angle = 1.57
796
            elif abs(self.angle - 4.71) < allowed_error:
797
                self.angle = 4.71
798
            elif abs(self.angle - 3.14) < allowed_error:
799
                self.angle = 3.14
800
            else:
801
                self.angle = 0
802

    
803
            transform = QTransform()
804
            if abs(self.angle - 1.57) < allowed_error or abs(self.angle - 4.71) < allowed_error:
805
                font = QFont(fontName, width if fontSize == -1 else fontSize)
806
                font.setBold(True)
807

    
808
                x_factor = width / QFontMetricsF(font).height() #self.text()).height() / line_count)
809
                y_factor = height / self.text_width(font)
810
                factor = min(x_factor, y_factor)
811
                font.setPointSizeF(font.pointSizeF() * factor)
812
                self.setFont(font)
813

    
814
                rect = self.text_size
815
                sx = rect.height() / QFontMetricsF(font).tightBoundingRect(self.text()).height()
816
                sy = rect.width() / self.text_width(font)
817

    
818
                transform.translate(x + width * 0.5, y + height * 0.5)
819
                transform.rotateRadians(-self.angle)
820
                #transform.scale(1, sy)
821
                transform.translate(-rect.width() * 0.5, -rect.height() * 0.5)
822
            elif abs(self.angle - 3.14) < allowed_error:
823
                font = QFont(fontName, height if fontSize == -1 else fontSize)
824
                font.setBold(True)
825

    
826
                x_factor = width / self.text_width(font)
827
                y_factor = height / QFontMetricsF(font).height() #self.text()).height() / line_count)
828
                factor = min(x_factor, y_factor)
829
                font.setPointSizeF(font.pointSizeF() * factor)
830
                self.setFont(font)
831

    
832
                rect = self.text_size
833
                sx = width / self.text_width(font)
834
                sy = height / QFontMetricsF(font).tightBoundingRect(self.text()).height()
835

    
836
                transform.translate(x, y - round((rect.height() - height) * 0.5))
837
                #transform.scale(sx, 1)
838
                transform.rotateRadians(-self.angle)
839
                transform.translate(-width * 0.5, -height * 0.5)
840
            else:
841
                font = QFont(fontName, height if fontSize == -1 else fontSize)
842
                font.setBold(True)
843

    
844
                x_factor = width / self.text_width(font)
845
                y_factor = height / QFontMetricsF(font).height() #.boun(self.text()).height() / line_count)
846
                factor = min(x_factor, y_factor)
847
                font.setPointSizeF(font.pointSizeF() * factor)
848
                self.setFont(font)
849

    
850
                sx = width / self.text_width(font)
851
                sy = height / QFontMetricsF(font).tightBoundingRect(self.text()).height()
852

    
853
                transform.translate(x, y)
854

    
855
            self.setTransform(transform)
856

    
857
            self.document().setDocumentMargin(0)
858
        except Exception as ex:
859
            from App import App
860
            from AppDocData import MessageType
861

    
862
            message = 'error occurred({}-{}) in {}:{}'.format(ex, self.text(),
863
                                                              sys.exc_info()[-1].tb_frame.f_code.co_filename,
864
                                                              sys.exc_info()[-1].tb_lineno)
865
            App.mainWnd().addMessage.emit(MessageType.Error, message)
866

    
867
    '''
868
        @brief      Put text on scene
869
        @author     Jeongwoo
870
        @date       18.04.23
871
        @history    humkyung 2018.06.30 apply font configuration
872
    '''
873
    def addTextItemToScene(self, scene):
874
        try:
875
            self.update_shape()
876
            """
877
            white_char_list = app_doc_data.getConfigs('Text Recognition', 'White Character List')
878
            self.highlighter = Highlighter(self.document())
879
            self.highlighter.white_char_list = '‘' #white_char_list[0].value if white_char_list else None
880
            """
881

    
882
            scene.addItem(self)
883
        except Exception as ex:
884
            from App import App
885
            from AppDocData import MessageType
886

    
887
            message = 'error occurred({}-{}) in {}:{}'.format(ex, self.text(),
888
                                                              sys.exc_info()[-1].tb_frame.f_code.co_filename,
889
                                                              sys.exc_info()[-1].tb_lineno)
890
            App.mainWnd().addMessage.emit(MessageType.Error, message)
891

    
892
    '''
893
        @brief  get connected items
894
        @author humkyung
895
        @date   2018.04.23
896
        @history    2018.11.22      euisung     fix note road
897
    '''
898

    
899
    def getConnectedItems(self):
900
        visited = []
901

    
902
        try:
903
            if 1 == len(self.conns):
904
                # iterate connected items
905
                pool = []
906
                visited = []
907
                pool.append(self.conns[0])
908
                while len(pool) > 0:
909
                    it = pool.pop()
910
                    visited.append(it)
911
                    for conn in it.conns:
912
                        if (conn is not None) and (conn not in visited): pool.append(conn)
913
                # up to here
914
        except Exception as ex:
915
            print('error occurred({}) in {}:{}'.format(ex, sys.exc_info()[-1].tb_frame.f_code.co_filename,
916
                                                       sys.exc_info()[-1].tb_lineno))
917

    
918
        return visited
919

    
920
    @staticmethod
921
    def from_database(component):
922
        """ get text item from database """
923
        import uuid
924
        from AppDocData import AppDocData
925
        from TextItemFactory import TextItemFactory
926
        from SymbolAttr import SymbolAttr
927

    
928
        item = None
929

    
930
        try:
931
            x = float(component['X'])
932
            y = float(component['Y'])
933
            width = float(component['Width']) if component['Width'] is not None else 0
934
            height = float(component['Height']) if component['Height'] is not None else 0
935
            if height < 10:
936
                height = 10
937
            if width < 10:
938
                width = 10
939
            angle = float(component['Rotation']) if component['Rotation'] is not None else 0
940
            text = component['Value']
941

    
942
            configs = AppDocData.instance().getConfigs('Data', 'Grid')
943
            grid = int(configs[0].value) if 1 == len(configs) else -1
944
            if grid == 1:
945
                x = round(x)
946
                y = round(y)
947
                width = round(width)
948
                height = round(height)
949
                
950
            textInfo = TextInfo(text, x, y, width, height, angle)
951
            connline = component['Connected'] if component['Connected'] is not None else None
952

    
953
            item = TextItemFactory.instance().createTextItem(textInfo)
954
            if item is not None:
955
                item.setVisible(False)
956
                item.uid = uuid.UUID(component['UID'])
957
                item.loc = [x, y]
958
                item.size = [width, height]
959
                item.angle = angle
960
                #item.setToolTip('<b>{}</b><br>LINE NO={}'.format(str(item.uid), text))
961

    
962
                if component['Owner'] and component['Owner'] != 'None':
963
                    item._owner = uuid.UUID(component['Owner'])
964

    
965
                # assign area
966
                if not component['Area']:
967
                    app_doc_data = AppDocData.instance()
968
                    for area in app_doc_data.getAreaList():
969
                        if area.contains([x, y]):
970
                            item.area = area.name
971
                            break
972
                else:
973
                    item.area = component['Area']
974
                ## up to here
975

    
976
                """ apply freeze value """
977
                # item.freeze_item.update_freeze(item.prop('Freeze'))
978

    
979
                if connline is not None:
980
                    item.conns.append(connline)
981
        except Exception as ex:
982
            from App import App
983
            from AppDocData import MessageType
984

    
985
            message = 'error occurred({}) in {}:{}'.format(ex, sys.exc_info()[-1].tb_frame.f_code.co_filename,
986
                                                           sys.exc_info()[-1].tb_lineno)
987
            App.mainWnd().addMessage.emit(MessageType.Error, message)
988
            return None
989

    
990
        return item
991

    
992
    '''
993
        @brief      parse xml code
994
        @author     humkyung
995
        @date       2018.09.15
996
    '''
997

    
998
    @staticmethod
999
    def fromXml(node):
1000
        import uuid
1001
        from TextItemFactory import TextItemFactory
1002
        from AppDocData import AppDocData
1003
        from EngineeringNoteItem import QEngineeringNoteItem
1004
        from QEngineeringSizeTextItem import QEngineeringSizeTextItem
1005
        from EngineeringValveOperCodeTextItem import QEngineeringValveOperCodeTextItem
1006

    
1007
        item = None
1008

    
1009
        try:
1010
            location = node.find('LOCATION').text if node.find('LOCATION') is not None else '0,0'
1011
            x = float(location.split(',')[0])
1012
            y = float(location.split(',')[1])
1013
            width = float(node.find('WIDTH').text) if node.find('WIDTH') is not None else 0
1014
            height = float(node.find('HEIGHT').text) if node.find('HEIGHT') is not None else 0
1015
            if height < 10:
1016
                height = 10
1017
            if width < 10:
1018
                width = 10
1019
            angle = float(node.find('ANGLE').text) if node.find('ANGLE') is not None else 0
1020
            value = node.find('VALUE').text
1021
            if not value or len(value.replace('\n', '').replace(' ', '')) == 0:
1022
                return None
1023
            # attributeValue = node.find('ATTRIBUTEVALUE')
1024
            name = node.find('NAME').text
1025

    
1026
            configs = AppDocData.instance().getConfigs('Data', 'Grid')
1027
            grid = int(configs[0].value) if 1 == len(configs) else -1
1028
            if grid == 1:
1029
                x = round(x)
1030
                y = round(y)
1031
                width = round(width)
1032
                height = round(height)
1033

    
1034
            textInfo = TextInfo(value, x, y, width, height, angle)
1035

    
1036
            item = TextItemFactory.instance().createTextItem(textInfo)
1037
            if item is not None:
1038
                item.loc = [x, y]
1039
                item.size = [width, height]
1040
                item.angle = angle
1041

    
1042
            # set uid and owner of item
1043
            if item is not None:
1044
                item.uid = uuid.UUID(node.find('UID').text)
1045
                item.setVisible(False)
1046

    
1047
                if node.find('OWNER') is not None and node.find('OWNER').text != 'None':
1048
                    item._owner = uuid.UUID(node.find('OWNER').text)
1049

    
1050
            ## assign area
1051
            if item is not None:
1052
                if node.find('AREA') is None:
1053
                    appDocData = AppDocData.instance()
1054
                    for area in appDocData.getAreaList():
1055
                        if area.contains([x, y]):
1056
                            item.area = area.name
1057
                            break
1058
                else:
1059
                    item.area = node.find('AREA').text
1060
                    ## up to here
1061
        except Exception as ex:
1062
            from App import App
1063
            from AppDocData import MessageType
1064

    
1065
            message = 'error occurred({}) in {}:{}'.format(ex, sys.exc_info()[-1].tb_frame.f_code.co_filename,
1066
                                                           sys.exc_info()[-1].tb_lineno)
1067
            App.mainWnd().addMessage.emit(MessageType.Error, message)
1068

    
1069
        return item
1070

    
1071
    '''
1072
        @brief      generate xml code
1073
        @author     humkyung
1074
        @date       2018.04.23
1075
        @history    humkyung 2018.04.27 move to QEngineeringLineNoTextItem
1076
                    humkyung 2018.05.02 add name as parameter
1077
                    Jeongwoo 2018.05.30 Change variable [owner] is nullable and Add/Modify attributes
1078
    '''
1079

    
1080
    def toXml(self, owner=None):
1081
        from xml.etree.ElementTree import Element, SubElement, dump, ElementTree
1082
        from EngineeringLineItem import QEngineeringLineItem
1083
        from SymbolSvgItem import SymbolSvgItem
1084

    
1085
        try:
1086
            node = Element('ATTRIBUTE')
1087
            uidNode = Element('UID')
1088
            uidNode.text = str(self.uid)
1089
            node.append(uidNode)
1090

    
1091
            # write owner's uid to xml
1092
            ownerNode = Element('OWNER')
1093
            if self.owner is not None:
1094
                ownerNode.text = str(self.owner)
1095
            else:
1096
                ownerNode.text = 'None'
1097
            node.append(ownerNode)
1098
            # up to here
1099

    
1100
            attributeValueNode = Element('ATTRIBUTEVALUE')
1101
            attributeValueNode.text = self.attribute
1102
            node.append(attributeValueNode)
1103

    
1104
            nameNode = Element('NAME')
1105
            nameNode.text = self.type
1106
            node.append(nameNode)
1107

    
1108
            locNode = Element('LOCATION')
1109
            locNode.text = '{},{}'.format(self.loc[0], self.loc[1])
1110
            node.append(locNode)
1111

    
1112
            valueNode = Element('VALUE')
1113
            valueNode.text = self.text()
1114
            node.append(valueNode)
1115

    
1116
            angleNode = Element('ANGLE')
1117
            angleNode.text = str(self.angle)
1118
            node.append(angleNode)
1119

    
1120
            widthNode = Element('WIDTH')
1121
            widthNode.text = str(self.size[0])
1122
            node.append(widthNode)
1123

    
1124
            heightNode = Element('HEIGHT')
1125
            heightNode.text = str(self.size[1])
1126
            node.append(heightNode)
1127

    
1128
            areaNode = Element('AREA')
1129
            areaNode.text = self.area
1130
            node.append(areaNode)
1131

    
1132
            sceneNode = Element('SCENE')
1133
            rect = self.sceneBoundingRect()
1134
            sceneNode.text = '{},{},{},{}'.format(rect.x(), rect.y(), rect.width(), rect.height()) if self.scene() else \
1135
                            '{},{},{},{}'.format(self.loc[0], self.loc[1], self.size[0], self.size[1])
1136
            node.append(sceneNode)
1137

    
1138
        except Exception as ex:
1139
            from App import App
1140
            from AppDocData import MessageType
1141

    
1142
            message = 'error occurred({}) in {}:{}'.format(ex, sys.exc_info()[-1].tb_frame.f_code.co_filename,
1143
                                                           sys.exc_info()[-1].tb_lineno)
1144
            App.mainWnd().addMessage.emit(MessageType.Error, message)
1145

    
1146
            return None
1147

    
1148
        return node
1149

    
1150
    def to_svg(self, parent) -> list:
1151
        """convert text item to svg"""
1152
        from xml.etree.ElementTree import Element, SubElement, dump, ElementTree
1153
        from App import App
1154

    
1155
        res = []
1156
        try:
1157
            node = None
1158
            if parent is None or str(self.owner) == str(parent):
1159
                app_doc_data = AppDocData.instance()
1160
                prj = app_doc_data.getCurrentProject()
1161

    
1162
                node = Element('g')
1163
                node.attrib['id'] = str(self.uid)
1164
                node.attrib['font-family'] = self.font().family()
1165
                node.attrib['font-size'] = str(self.boundingRect().height())  # str(self.font().pointSizeF())
1166
                node.attrib['font-weight'] = str(self.font().weight())
1167

    
1168
                inverted = QTransform()
1169
                if parent:
1170
                    trans = parent.sceneTransform()
1171
                    inverted, _ = trans.inverted()
1172

    
1173
                trans = self.sceneTransform()
1174

    
1175
                trans = trans*inverted
1176
                node.attrib['transform'] = f"matrix(" \
1177
                                           f"{trans.m11()},{trans.m12()}," \
1178
                                           f"{trans.m21()},{trans.m22()}," \
1179
                                           f"{trans.m31()},{trans.m32()}" \
1180
                                           f")"
1181
                text = Element('text')
1182
                text.attrib['textLength'] = str(self.boundingRect().width())
1183
                text.attrib['lengthAdjust'] = 'spacingAndGlyphs'
1184
                text.text = self.toPlainText()
1185
                text.attrib['alignment-baseline'] = 'hanging'  # align left-top corner
1186
                node.append(text)
1187

    
1188
                res.append(node)
1189
        except Exception as ex:
1190
            from App import App
1191
            message = 'error occurred({}) in {}:{}'.format(ex, sys.exc_info()[-1].tb_frame.f_code.co_filename,
1192
                                                          sys.exc_info()[-1].tb_lineno)
1193
            App.mainWnd().addMessage.emit(MessageType.Error, message)
1194

    
1195
        return res
1196

    
1197
    def findOwner(self, symbols, force=False):
1198
        import math
1199

    
1200
        try:
1201
            minDist = None
1202
            selected = None
1203

    
1204
            configs = AppDocData.instance().getConfigs('Range', 'Detection Ratio')
1205
            if not force:
1206
                ratio = float(configs[0].value) if 1 == len(configs) else 1.5
1207
            else:
1208
                ratio = 50
1209

    
1210
            if len(self.text()) > 3:
1211
                width = self.sceneBoundingRect().width()
1212
            elif len(self.text()) == 3:
1213
                width = self.sceneBoundingRect().width() * 4 / 3
1214
            elif len(self.text()) == 2:
1215
                width = self.sceneBoundingRect().width() * 2
1216
            else:
1217
                width = self.sceneBoundingRect().width() * 4
1218
            dist = (self.sceneBoundingRect().height() + width) * ratio / 2
1219
            center = self.sceneBoundingRect().center()
1220

    
1221
            target_symbols = []
1222
            for symbol in symbols:
1223
                attrs = symbol.getAttributes(findOwner=True)
1224

    
1225
                freeze = False
1226
                for attr in attrs:
1227
                    if attr.Freeze:
1228
                        freeze = True
1229
                        break
1230
                if freeze and not force: continue
1231

    
1232
                for attr in attrs:
1233
                    ret = attr.Codes.find_match_exactly(self.text())
1234
                    if ret:
1235
                        target_symbols.append(symbol)
1236
                        break
1237

    
1238
            for symbol in target_symbols:
1239
                if issubclass(type(symbol), SymbolSvgItem):
1240
                    dx = symbol.origin[0] - center.x()
1241
                    dy = symbol.origin[1] - center.y()
1242

    
1243
                    #offset = (symbol.sceneBoundingRect().width() + symbol.sceneBoundingRect().height()) / 4
1244
                    length = math.sqrt(dx * dx + dy * dy)# - offset
1245

    
1246
                    if (length < dist) and (minDist is None or length < minDist):
1247
                        minDist = length
1248
                        selected = symbol
1249

    
1250
            if selected is not None:
1251
                attrs = selected.getAttributes(findOwner=True)
1252
                target_attrs = []
1253
                for attr in attrs:
1254
                    ret = attr.Codes.find_match_exactly(self.text())
1255
                    if ret:
1256
                        target_attrs.append(attr)
1257

    
1258
                for target_attr in sorted(target_attrs, key=lambda param:int(param.AttrAt)):
1259
                    if target_attr.AssocItem is None and selected.add_assoc_item(self, at=int(target_attr.AttrAt), force=force):
1260
                        target_attr.AssocItem = self
1261
                        self.owner = selected
1262
                        if force:
1263
                            selected.getAttributes()
1264
                            for neyKey in selected.attrs.keys():
1265
                                if neyKey.Attribute == target_attr.Attribute:
1266
                                    neyKey.Freeze = True
1267
                                    break
1268
                        return ret
1269

    
1270
            return False
1271
        except Exception as ex:
1272
            from App import App
1273
            message = 'error occurred({}) in {}:{}'.format(ex, sys.exc_info()[-1].tb_frame.f_code.co_filename,
1274
                                                           sys.exc_info()[-1].tb_lineno)
1275
            App.mainWnd().addMessage.emit(MessageType.Error, message)
1276

    
1277
    def setColor(self, color):
1278
        """change text color with given color"""
1279
        if QColor.isValidColor(color) and color.upper() != self.defaultTextColor().name().upper():
1280
            c = QColor()
1281
            c.setNamedColor(color)
1282
            self.setDefaultTextColor(c)
1283
            #self.update()
1284

    
1285
    def toSql(self):
1286
        """ convert text data to sql query for components and title block """
1287
        from AppDocData import AppDocData
1288

    
1289
        res = []
1290

    
1291
        appDocData = AppDocData.instance()
1292
        cols = ['UID', 'Drawings_UID', 'Symbol_UID', 'X', 'Y', 'Width', 'Height', 'Rotation', 'Area', 'Value', 'Owner',
1293
                'Connected', 'SpecialItemTypes_UID']
1294
        values = ['?', '?', "(select UID from Symbol where Name='Text' and SymbolType_UID=-1)", '?', '?', '?', '?', '?',
1295
                  '?', '?', '?', '?', '?']
1296

    
1297
        param = [
1298
            (str(self.uid), str(appDocData.activeDrawing.UID), self.loc[0], self.loc[1], self.size[0], self.size[1],
1299
             str(self.angle),
1300
             self.area, self.text(), \
1301
             str(self.owner) if self.owner else None, \
1302
             str(self.conns[0]) if self.conns else None, \
1303
             str(self.special_item_type) if self.special_item_type else None)]
1304
        sql = 'insert into Components({}) values({})'.format(','.join(cols), ','.join(values))
1305
        res.append((sql, tuple(param)))
1306

    
1307
        titleBlockProps = appDocData.getTitleBlockProperties()
1308
        if titleBlockProps:
1309
            cols = ['UID', 'Drawings_UID', 'TitleBlockProperties_UID', 'VALUE']
1310
            values = ['?', '?', '?', '?']
1311
            params = []
1312
            for titleBlockProp in titleBlockProps:
1313
                if self.area == titleBlockProp[0]:
1314
                    params.append((str(self.uid), appDocData.activeDrawing.UID, self.area, self.text()))
1315

    
1316
            sql = 'insert into TitleBlockValues({}) values({})'.format(','.join(cols), ','.join(values))
1317
            if params: res.append((sql, tuple(params)))
1318

    
1319
        return res
1320

    
1321

    
1322
'''
1323
    @brief      The class transfer pyqtSignal Event. Cause Subclass of QGraphicsRectItem can't use pyqtSignal
1324
    @author     Jeongwoo
1325
    @date       2018.06.18
1326
'''
1327

    
1328

    
1329
class Transfer(QObject):
1330
    onRemoved = pyqtSignal(QGraphicsItem)
1331

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