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)
|