프로젝트

일반

사용자정보

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

hytos / DTI_PID / DTI_PID / Shapes / EngineeringTextItem.py @ 19d19912

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

1
# coding: utf-8
2
import os.path
3
import copy
4
import sys
5
try:
6
    from PyQt5.QtCore import Qt, QPointF, QRectF, pyqtSignal, QObject, QT_VERSION_STR, QRect
7
    from PyQt5.QtGui import QImage, QPixmap, QPainterPath, QBrush, QPen, QTransform, QFont, QColor, QFontMetrics
8
    from PyQt5.QtWidgets import QGraphicsView, QGraphicsScene, QFileDialog, QGraphicsItem, QAbstractGraphicsShapeItem, QGraphicsTextItem
9
except ImportError:
10
    try:
11
        from PyQt4.QtCore import Qt, QRectF, pyqtSignal, QRect, QObject, QT_VERSION_STR
12
        from PyQt4.QtGui import QGraphicsView, QGraphicsScene, QImage, QPixmap, QPainterPath, QFileDialog, QFont, QColor, QFontMetrics
13
    except ImportError:
14
        raise ImportError("ImageViewerQt: Requires PyQt5 or PyQt4.")
15

    
16
from EngineeringPolylineItem import QEngineeringPolylineItem
17
from GraphicsBoundingBoxItem import QGraphicsBoundingBoxItem
18
from AppDocData import *
19
from EngineeringAbstractItem import QEngineeringAbstractItem
20

    
21
class QEngineeringTextItem(QGraphicsTextItem, QEngineeringAbstractItem):
22
    HIGHLIGHT = '#BC4438'
23

    
24
    '''
25
        @history    2018.05.17  Jeongwoo    Add self._owner variable
26
    '''
27
    def __init__(self, uid=None, parent=None):
28
        import uuid
29

    
30
        QGraphicsTextItem.__init__(self, parent)
31
        QEngineeringAbstractItem.__init__(self)
32

    
33
        self.uid = uuid.uuid4() if uid is None else uid
34
        self.loc = None
35
        self.size = None
36
        self.angle = 0  # angle in radian
37
        self.conns = []
38
        self._owner = None
39
        self.setFlags(QGraphicsItem.ItemIsSelectable|QGraphicsItem.ItemIsFocusable)
40
        self.setAcceptHoverEvents(True)
41
        self.setAcceptTouchEvents(True)
42

    
43
        self.setColor(self._color)
44
        self._savedColor = None        
45

    
46
        self.delimiter = '"'
47

    
48
        self.attribute = ''
49

    
50
        self.transfer = Transfer()
51
        
52
    '''
53
        @brief      Get owner
54
        @author     Jeongwoo
55
        @date       2018.05.17
56
    '''
57
    @property
58
    def owner(self):
59
        return self._owner
60

    
61
    '''
62
        @brief      Set owner
63
        @author     Jeongwoo
64
        @date       2018.05.17
65
        @history    2018.05.17  Jeongwoo    Add Calling setColor if self._owner is None or not
66
    '''
67
    @owner.setter
68
    def owner(self, value):
69
        self._owner = value
70

    
71
        if self._owner is None:
72
            self._color = self.DEFAULT_COLOR
73
        self.setColor(self._color)
74

    
75
    '''
76
        @brief  return text string
77
        @author humkyung
78
        @date   2018.04.16
79
    '''
80
    def text(self):
81
        return self.toPlainText()
82
    
83
    '''
84
        @brief  return center position of text
85
        @author humkyung
86
        @date   2018.04.16
87
    '''
88
    def center(self):
89
        return self.sceneBoundingRect().center()
90

    
91
    '''
92
        @brief      hover event
93
        @authro     humkyung
94
        @date       
95
    '''
96
    def hoverEnterEvent(self, event):
97
        self.setHightlight()
98

    
99
    def hoverLeaveEvent(self, event):
100
        self.unsetHightlight()
101

    
102
    '''
103
        @brief      set highlight
104
        @author     kyouho
105
        @date       2018.08.27
106
    '''
107
    def setHightlight(self):
108
        if self._savedColor is None:
109
            self._savedColor = self.getColor()
110
        self.setColor(QEngineeringTextItem.HIGHLIGHT)
111

    
112
        self.update()
113

    
114
    '''
115
        @brief      unset highlight
116
        @author     kyouho
117
        @date       2018.08.27
118
    '''
119
    def unsetHightlight(self):
120
        self.setColor(self._savedColor)
121
        self.update()
122

    
123
    def hoverMoveEvent(self, event):
124
        pass
125

    
126
    '''
127
        @brief      remove item when user press delete key
128
        @author     humkyung
129
        @date       2018.04.23
130
        @history    2018.05.25  Jeongwoo    Seperate delete item method
131
                    humkyung 2018.08.18 rotate text when user press 'R'
132
    '''
133
    def keyPressEvent(self, event): 
134
        if event.key() == Qt.Key_Delete:
135
            self.deleteTextItemFromScene()
136
        elif event.key() == Qt.Key_R:
137
            #degree 0
138
            if 0 == self.angle:
139
                self.angle = 1.57
140
            #degree 90
141
            elif (1.57 == self.angle):
142
                self.angle = 3.14
143
            #degree 180
144
            elif 3.14 == self.angle:
145
                self.angle = 4.71
146
            #degree 270
147
            elif 4.71 == self.angle :
148
                self.angle = 0
149

    
150
            width = self.size[0]
151
            height = self.size[1]
152
            self.size = (height, width)
153

    
154
            self.rotate()
155

    
156
        QGraphicsTextItem.keyPressEvent(self, event)
157

    
158
    '''
159
        @brief  draw rect when item is selected
160
        @author humkyung
161
        @date   2018.07.08
162
    '''
163
    def drawFocusRect(self, painter):
164
        self.focuspen = QPen(Qt.DotLine)
165
        self.focuspen.setColor(Qt.black)
166
        self.focuspen.setWidthF(1.5)
167
        hilightColor = QColor(255, 0, 0, 127)
168
        painter.setBrush(QBrush(hilightColor))
169
        painter.setPen(self.focuspen)
170
        painter.drawRect(self.boundingRect())
171

    
172
    '''
173
        @brief  override paint(draw connection points)
174
        @author humkyung
175
        @date   2018.07.08
176
    '''
177
    def paint(self, painter, options=None, widget=None):
178
        QGraphicsTextItem.paint(self, painter, options, widget)
179
        if self.isSelected():
180
            self.drawFocusRect(painter)
181

    
182
    '''
183
        @brief      Delete text item
184
        @author     Jeongwoo
185
        @date       2018.05.25
186
    '''
187
    def deleteTextItemFromScene(self):
188
        self.transfer.onRemoved.emit(self)
189
        self.scene().removeItem(self)
190

    
191
    '''
192
        @brief      Return real item position
193
        @author     Jeongwoo
194
        @date       2018.05.25
195
    '''
196
    def boundingRectOnScene(self):
197
        rect = self.boundingRect()
198
        rect.moveTo(self.loc[0], self.loc[1])
199
        return rect
200

    
201
    '''
202
        @brief      Double click event, Show QOcrResultDialog
203
        @author     Jeongwoo
204
        @date       18.04.23
205
        @history    18.06.20    Jeongwoo    Resize QRect added 1
206
    '''
207
    def mouseDoubleClickEvent(self, event):
208
        if event.buttons() == Qt.LeftButton:
209
            from OcrResultDialog import QOcrResultDialog
210
            dialog = QOcrResultDialog(None, AppDocData.instance().getCurrentPidSource().getQImageOnRect(QRect(self.loc[0], self.loc[1], self.size[0]+1, self.size[1]))
211
                                                       , QRect(self.loc[0], self.loc[1], self.size[0]+1, self.size[1]), True, self.text())
212
            (isAccept, textInfoList) = dialog.showDialog()
213

    
214
            if isAccept:
215
                scene = self.scene()
216
                scene.removeItem(self)
217
                text = textInfoList[0].getText()
218
                self.setPlainText(text)
219
                self.setDefaultTextColor(Qt.blue)
220
                self.addTextItemToScene(scene)
221

    
222
    '''
223
        @brief      rotate text
224
        @author     humkyung
225
        @date       2018.08.18
226
    '''
227
    def rotate(self):
228
        sx = 1
229
        sy = 1
230
        width = self.size[0]
231
        height = self.size[1]
232
        x = self.loc[0]
233
        y = self.loc[1]
234

    
235
        transform = QTransform()
236
        if (1.57 == self.angle) or (4.71 == self.angle):
237
            rect = self.boundingRect()
238
            sx = width/rect.height()
239
            sy = height/rect.width()
240
                                        
241
            transform.translate(x, y)
242
            transform.translate(width*0.5, height*0.5)
243
            transform.scale(1, sy)
244
            transform.rotateRadians(-self.angle)
245
            transform.translate(-rect.width()*0.5, -rect.height()*0.5)
246
        elif 3.14 == self.angle:
247
            rect = self.boundingRect()
248
            sx = width/rect.width()
249
            sy = height/rect.height()
250

    
251
            transform.translate(x, y - round((rect.height()-height)*0.5))
252
            transform.scale(sx, 1)
253
            transform.rotateRadians(-self.angle)
254
            transform.translate(-width*0.5, -height*0.5)
255
        else:
256
            rect = self.boundingRect()
257
            sx = width/rect.width()
258
            sy = height/rect.height()
259

    
260
            #if '\n' not in text:
261
            transform.translate(x, y - round((rect.height()-height)*0.5))
262
            transform.scale(sx, 1)
263

    
264
        self.setTransform(transform)
265
        self.update()
266

    
267
    '''
268
        @brief      Put text on scene
269
        @author     Jeongwoo
270
        @date       18.04.23
271
        @history    humkyung 2018.06.30 apply font configuration
272
    '''
273
    def addTextItemToScene(self, scene):
274
        try:
275
            docData = AppDocData.instance()
276
            configs = docData.getConfigs('Text Style', 'Font Name')
277
            fontName = configs[0].value if configs else 'Arial'
278
            configs = docData.getConfigs('Text Style', 'Font Size')
279
            fontSize = int(configs[0].value) if configs else -1
280

    
281
            sx = 1
282
            sy = 1
283
            width = self.size[0]
284
            height = self.size[1]
285
            x = self.loc[0]
286
            y = self.loc[1]
287
            rect = None
288
            transform = QTransform()
289
            if (1.57 == self.angle) or (4.71 == self.angle):
290
                font = QFont(fontName, width*1.2 if fontSize == -1 else fontSize)
291
                
292
                x_factor = width / QFontMetrics(font).height()
293
                y_factor = height / QFontMetrics(font).width(self.text())
294
                factor = min(x_factor, y_factor)
295
                font.setPointSizeF(font.pointSizeF()*factor)
296

    
297
                self.setFont(font)
298
                rect = self.boundingRect()
299
                sx = width/rect.height()
300
                sy = height/rect.width()
301
                                            
302
                transform.translate(x, y)
303
                transform.translate(width*0.5, height*0.5)
304
                transform.scale(1, sy)
305
                transform.rotateRadians(-self.angle)
306
                transform.translate(-rect.width()*0.5, -rect.height()*0.5)
307
            elif 3.14 == self.angle:
308
                font = QFont(fontName, height*1.2 if fontSize == -1 else fontSize)
309

    
310
                x_factor = width / QFontMetrics(font).width(self.text())
311
                y_factor = height / QFontMetrics(font).height()
312
                factor = min(x_factor, y_factor)
313
                font.setPointSizeF(font.pointSizeF()*factor)
314

    
315
                self.setFont(font)
316
                rect = self.boundingRect()
317
                sx = width/rect.width()
318
                sy = height/rect.height()
319

    
320
                transform.translate(x, y - round((rect.height()-height)*0.5))
321
                transform.scale(sx, 1)
322
                transform.rotateRadians(-self.angle)
323
                transform.translate(-width*0.5, -height*0.5)
324
            else:
325
                font = QFont(fontName, height*1.2 if fontSize == -1 else fontSize)
326

    
327
                x_factor = width / QFontMetrics(font).width(self.text())
328
                y_factor = height / QFontMetrics(font).height()
329
                factor = min(x_factor, y_factor)
330
                font.setPointSizeF(font.pointSizeF()*factor)
331

    
332
                self.setFont(font)
333
                rect = self.boundingRect()
334
                sx = width/rect.width()
335
                sy = height/rect.height()
336

    
337
                #if '\n' not in text:
338
                transform.translate(x, y - round((rect.height()-height)*0.5))
339
                transform.scale(sx, 1)
340

    
341
            self.setTransform(transform)
342
                    
343
            scene.addItem(self)
344
        except Exception as ex:
345
            print('error occured({}) in {}:{}'.format(ex, sys.exc_info()[-1].tb_frame.f_code.co_filename, sys.exc_info()[-1].tb_lineno))
346

    
347
    '''
348
        @brief  get connected items
349
        @author humkyung
350
        @date   2018.04.23
351
    '''
352
    def getConnectedItems(self):
353
        visited = []
354

    
355
        try:
356
            if 1 == len(self.conns):
357
                # iterate connected items
358
                pool = []
359
                visited = []
360
                pool.append(self.conns[0])
361
                while len(pool) > 0:
362
                    it = pool.pop()
363
                    visited.append(it)
364
                    for conn in it.conns:
365
                        if (conn is not None) and (conn not in visited): pool.append(conn)
366
                # up to here
367
        except Exception as ex:
368
            print('error occured({}) in {}:{}'.format(ex, sys.exc_info()[-1].tb_frame.f_code.co_filename, sys.exc_info()[-1].tb_lineno))
369

    
370
        return visited
371
    
372
    '''
373
        @brief      parse xml code
374
        @author     humkyung
375
        @date       2018.09.15
376
    '''
377
    @staticmethod 
378
    def fromXml(node):
379
        from TextItemFactory import TextItemFactory
380
        from AppDocData import AppDocData
381
        from QEngineeringNoteItem import QEngineeringNoteItem
382

    
383
        item = None
384

    
385
        try:
386
            location = node.find('LOCATION').text if node.find('LOCATION') is not None else '0,0'
387
            x = float(location.split(',')[0])
388
            y = float(location.split(',')[1])
389
            width = float(node.find('WIDTH').text) if node.find('WIDTH') is not None else 0
390
            height = float(node.find('HEIGHT').text) if node.find('HEIGHT') is not None else 0
391
            angle = float(node.find('ANGLE').text) if node.find('ANGLE') is not None else 0
392
            value = node.find('VALUE').text
393
            uid = node.find('UID')
394
            attributeValue = node.find('ATTRIBUTEVALUE')
395
            name = node.find('NAME').text
396
            if name == 'TEXT':
397
                item = TextItemFactory.instance().createTextItem(value)
398
                if item is not None:
399
                    item.loc = (x, y)
400
                    item.size = (width, height)
401
                    item.angle = angle
402
                    item.setPlainText(value)
403
            elif name == 'NOTE':
404
                item = QEngineeringNoteItem()
405
                if item is not None:
406
                    item.loc = (x, y)
407
                    item.size = (width, height)
408
                    item.angle = angle
409
                    item.setPlainText(value)
410

    
411
            ## assign area
412
            if item is not None:
413
                if node.find('AREA') is None:
414
                    appDocData = AppDocData.instance()
415
                    for area in appDocData.getAreaList():
416
                        if area.contains([x, y]):
417
                            item.area = area.name
418
                            break
419
                else:
420
                    item.area = node.find('AREA').text  
421
            ## up to here
422
        except Exception as ex:
423
            from App import App
424
            from AppDocData import MessageType
425

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

    
429
        return item
430

    
431
    '''
432
        @brief      generate xml code
433
        @author     humkyung
434
        @date       2018.04.23
435
        @history    humkyung 2018.04.27 move to QEngineeringLineNoTextItem
436
                    humkyung 2018.05.02 add name as parameter
437
                    Jeongwoo 2018.05.30 Change variable [owner] is nullable and Add/Modify attributes
438
    '''
439
    def toXml(self, owner = None, name='TEXT'):
440
        from xml.etree.ElementTree import Element, SubElement, dump, ElementTree
441
        from EngineeringLineItem import QEngineeringLineItem
442
        from SymbolSvgItem import SymbolSvgItem
443

    
444
        try:
445
            node = Element('ATTRIBUTE')
446
            #if owner is not None:
447
            uidNode = Element('UID')
448
            uidNode.text = str(self.uid)
449
            node.append(uidNode)
450

    
451
            attributeValueNode = Element('ATTRIBUTEVALUE')
452
            attributeValueNode.text = self.attribute
453
            node.append(attributeValueNode)
454

    
455
            nameNode = Element('NAME')
456
            nameNode.text = name
457
            node.append(nameNode)
458
            
459
            locNode = Element('LOCATION')
460
            locNode.text = '{},{}'.format(self.loc[0], self.loc[1])
461
            node.append(locNode)
462

    
463
            valueNode = Element('VALUE')
464
            valueNode.text = self.text()
465
            node.append(valueNode)
466

    
467
            angleNode = Element('ANGLE')
468
            angleNode.text = str(self.angle)
469
            node.append(angleNode)
470

    
471
            widthNode = Element('WIDTH')
472
            widthNode.text = str(self.size[0])
473
            node.append(widthNode)
474

    
475
            heightNode = Element('HEIGHT')
476
            heightNode.text = str(self.size[1])
477
            node.append(heightNode)
478

    
479
            areaNode = Element('AREA')
480
            areaNode.text = self.area
481
            node.append(areaNode)
482
        except Exception as ex:
483
            print('error occured({}) in {}:{}'.format(ex, sys.exc_info()[-1].tb_frame.f_code.co_filename, sys.exc_info()[-1].tb_lineno))
484
            return str(self.uid)
485

    
486
        return node 
487
    
488
    '''
489
        @brief      Set Color. Override QEngineeringAbstractItem's
490
        @author     Jeongwoo
491
        @date       2018.05.11
492
        @history    humkyung 2018.05.13 update after change color
493
    '''
494
    def setColor(self, color):
495
        self._color = color
496
        c = QColor()
497
        c.setNamedColor(color)
498
        self.setDefaultTextColor(c)
499
        self.update()
500

    
501
    def getColor(self):
502
        return self._color
503

    
504
'''
505
    @brief      The class transfer pyqtSignal Event. Cause Subclass of QGraphicsRectItem can't use pyqtSignal
506
    @author     Jeongwoo
507
    @date       2018.06.18
508
'''
509
class Transfer(QObject):
510
    onRemoved = pyqtSignal(QGraphicsItem)
511

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