1
|
|
2
|
|
3
|
|
4
|
import sys
|
5
|
import os
|
6
|
import math
|
7
|
import numpy as np
|
8
|
from PyQt5.QtGui import *
|
9
|
from PyQt5.QtCore import *
|
10
|
from PyQt5.QtSvg import *
|
11
|
from PyQt5.QtWidgets import (QApplication, QGraphicsItem)
|
12
|
from PyQt5.QtXml import *
|
13
|
|
14
|
from AppDocData import *
|
15
|
from EngineeringConnectorItem import QEngineeringConnectorItem
|
16
|
from EngineeringAbstractItem import QEngineeringAbstractItem
|
17
|
from EngineeringConnectorItem import QEngineeringConnectorItem
|
18
|
from UserInputAttribute import UserInputAttribute
|
19
|
import SelectAttributeCommand
|
20
|
|
21
|
|
22
|
class SymbolSvgItem(QGraphicsSvgItem, QEngineeringAbstractItem):
|
23
|
""" This is symbolsvgitem class """
|
24
|
|
25
|
clicked = pyqtSignal(QGraphicsSvgItem)
|
26
|
ZVALUE = 50
|
27
|
HOVER_COLOR = 'url(#hover)'
|
28
|
|
29
|
DOCUMENTS = {}
|
30
|
|
31
|
'''
|
32
|
@history 18.04.11 Jeongwoo Add Variable (Name, Type)
|
33
|
18.05.11 Jeongwoo Declare variable self.color
|
34
|
18.05.25 Jeongwoo Call setColor() method
|
35
|
18.05.30 Jeongwoo Add self variables (parentSymbol, childSymbol)
|
36
|
'''
|
37
|
|
38
|
def __init__(self, name, path, uid=None, flip=0):
|
39
|
import uuid
|
40
|
from SymbolAttr import SymbolProp
|
41
|
|
42
|
QGraphicsSvgItem.__init__(self)
|
43
|
QEngineeringAbstractItem.__init__(self)
|
44
|
|
45
|
self.setFlags(
|
46
|
QGraphicsItem.ItemIsSelectable | QGraphicsItem.ItemIsFocusable | QGraphicsItem.ItemSendsGeometryChanges)
|
47
|
|
48
|
self.dbUid = None
|
49
|
self.uid = uuid.uuid4() if uid is None else uuid.UUID(uid)
|
50
|
self.name = name
|
51
|
self.type = ''
|
52
|
self.iType = -2
|
53
|
self.text_area = None
|
54
|
self.angle = 0
|
55
|
self.origin = None
|
56
|
self.loc = None
|
57
|
self.size = None
|
58
|
self._owner = None
|
59
|
self.parentSymbol = ''
|
60
|
self.childSymbol = ''
|
61
|
self.hasInstrumentLabel = 0
|
62
|
self.flip = flip
|
63
|
self.hit_ratio = None
|
64
|
|
65
|
self.attribute = ''
|
66
|
self._properties = {SymbolProp(None, 'Supplied By', 'String'): None}
|
67
|
|
68
|
self.setAcceptDrops(True)
|
69
|
self.setAcceptHoverEvents(True)
|
70
|
self.setAcceptedMouseButtons(Qt.LeftButton)
|
71
|
self.setAcceptTouchEvents(True)
|
72
|
|
73
|
self.currentCursor = 0
|
74
|
self.transfer = Transfer()
|
75
|
|
76
|
self._angle = 0
|
77
|
|
78
|
self.in_out_connector = [[], []]
|
79
|
self.break_connector = []
|
80
|
self.conn_type = []
|
81
|
|
82
|
try:
|
83
|
app_doc_data = AppDocData.instance()
|
84
|
svg = None
|
85
|
|
86
|
if path not in SymbolSvgItem.DOCUMENTS:
|
87
|
if self.name:
|
88
|
_, svg = app_doc_data.read_symbol_shape(self.name)
|
89
|
|
90
|
if not svg and path and os.path.isfile(path):
|
91
|
f = QFile(path)
|
92
|
f.open(QIODevice.ReadOnly)
|
93
|
svg = f.readAll()
|
94
|
f.close()
|
95
|
|
96
|
self._document = QDomDocument()
|
97
|
self._document.setContent(svg)
|
98
|
self._renderer = QSvgRenderer(self._document.toByteArray())
|
99
|
SymbolSvgItem.DOCUMENTS[path] = [self._document, self._renderer]
|
100
|
else:
|
101
|
self._document, self._renderer = SymbolSvgItem.DOCUMENTS[path]
|
102
|
|
103
|
self.setSharedRenderer(self._renderer)
|
104
|
self.setCacheMode(QGraphicsItem.ItemCoordinateCache)
|
105
|
|
106
|
|
107
|
except Exception as ex:
|
108
|
from App import App
|
109
|
|
110
|
message = 'error occurred({}) in {}:{}'.format(repr(ex), sys.exc_info()[-1].tb_frame.f_code.co_filename,
|
111
|
sys.exc_info()[-1].tb_lineno)
|
112
|
App.mainWnd().addMessage.emit(MessageType.Error, message)
|
113
|
|
114
|
self.setZValue(SymbolSvgItem.ZVALUE)
|
115
|
|
116
|
app_doc_data = AppDocData.instance()
|
117
|
configs = app_doc_data.getConfigs('Symbol Style', 'Opacity')
|
118
|
self.setOpacity(float(configs[0].value) / 100 if configs else 0.5)
|
119
|
|
120
|
def has_in_out_connector(self):
|
121
|
""" return True if item has in or out connector """
|
122
|
if len(self.in_out_connector[0]) > 0 and len(self.in_out_connector[1]) > 0:
|
123
|
return True
|
124
|
else:
|
125
|
return False
|
126
|
|
127
|
def has_break_connector(self):
|
128
|
""" return True if item has break connector """
|
129
|
if len(self.break_connector) > 0:
|
130
|
return True
|
131
|
else:
|
132
|
return False
|
133
|
|
134
|
def __str__(self):
|
135
|
""" return string represent uuid """
|
136
|
return str(self.uid)
|
137
|
|
138
|
@property
|
139
|
def owner(self):
|
140
|
"""get owner"""
|
141
|
import uuid
|
142
|
|
143
|
if self._owner and type(self._owner) is uuid.UUID:
|
144
|
matches = [x for x in self.scene().items() if hasattr(x, 'uid') and str(x.uid) == str(self._owner)]
|
145
|
if matches:
|
146
|
self._owner = matches[0]
|
147
|
|
148
|
if type(self._owner) is not uuid.UUID and type(self._owner) is not str:
|
149
|
return self._owner
|
150
|
else:
|
151
|
self._owner = None
|
152
|
return None
|
153
|
|
154
|
'''
|
155
|
@brief setter owner
|
156
|
@author humkyung
|
157
|
@date 2018.05.10
|
158
|
@history 2018.05.17 Jeongwoo Add Calling setColor if self._owner is None or not
|
159
|
'''
|
160
|
|
161
|
@owner.setter
|
162
|
def owner(self, value):
|
163
|
self._owner = value
|
164
|
|
165
|
if self._owner is None:
|
166
|
self._color = self.DEFAULT_COLOR
|
167
|
self.setColor(self._color)
|
168
|
|
169
|
'''
|
170
|
@property
|
171
|
def properties(self):
|
172
|
""" getter of properties """
|
173
|
import uuid
|
174
|
|
175
|
for prop, value in self._properties.items():
|
176
|
try:
|
177
|
if prop.is_selectable and type(value) is uuid.UUID and self.scene():
|
178
|
matches = [x for x in self.scene().items() if hasattr(x, 'uid') and str(x.uid) == str(value)]
|
179
|
if matches: self._properties[prop] = matches[0]
|
180
|
|
181
|
if prop.Expression:
|
182
|
item = self._properties[prop] # assign item
|
183
|
self._properties[prop] = eval(prop.Expression)
|
184
|
except Exception as ex:
|
185
|
from App import App
|
186
|
|
187
|
message = 'error occurred({}) in {}:{}'.format(ex, sys.exc_info()[-1].tb_frame.f_code.co_filename,
|
188
|
sys.exc_info()[-1].tb_lineno)
|
189
|
App.mainWnd().addMessage.emit(MessageType.Error, message)
|
190
|
|
191
|
return self._properties
|
192
|
|
193
|
def set_property(self, property, value):
|
194
|
""" set property with given value """
|
195
|
if issubclass(type(value), QEngineeringAbstractItem): self.add_assoc_item(value, 0)
|
196
|
matches = [prop for prop, _ in self._properties.items() if prop.Attribute == property]
|
197
|
if matches: self._properties[matches[0]] = value
|
198
|
|
199
|
def prop(self, name):
|
200
|
""" return the value of given property with name """
|
201
|
matches = [(prop, value) for prop, value in self.properties.items() if prop.Attribute == name]
|
202
|
if matches: return matches[0][1]
|
203
|
|
204
|
return None
|
205
|
'''
|
206
|
|
207
|
@property
|
208
|
def Size(self):
|
209
|
""" return valve's size """
|
210
|
from QEngineeringSizeTextItem import QEngineeringSizeTextItem
|
211
|
|
212
|
matches = [assoc for assoc in self.associations() if type(assoc) is QEngineeringSizeTextItem]
|
213
|
if matches:
|
214
|
return matches[0].text()
|
215
|
else:
|
216
|
return None
|
217
|
|
218
|
@property
|
219
|
def EvaluatedSize(self):
|
220
|
from EngineeringReducerItem import QEngineeringReducerItem
|
221
|
from EngineeringLineNoTextItem import QEngineeringLineNoTextItem
|
222
|
|
223
|
try:
|
224
|
if self.Size: return self.Size
|
225
|
if self.owner and issubclass(type(self.owner), QEngineeringLineNoTextItem):
|
226
|
matches = [run for run in self.owner.runs if self in run.items]
|
227
|
if matches:
|
228
|
at = matches[0].items.index(self)
|
229
|
upstream = matches[0].items[:at]
|
230
|
upstream.reverse()
|
231
|
prev = self
|
232
|
for item in upstream:
|
233
|
if type(item) is QEngineeringReducerItem:
|
234
|
if item.connectors[0].connectedItem is prev:
|
235
|
if item.MainSubSize: return item.MainSubSize[0]
|
236
|
elif item.connectors[1].connectedItem is prev:
|
237
|
if item.MainSubSize: return item.MainSubSize[1]
|
238
|
else:
|
239
|
if item.Size: return item.Size
|
240
|
prev = item
|
241
|
|
242
|
downstream = matches[0].items[at:]
|
243
|
prev = self
|
244
|
for item in downstream:
|
245
|
if type(item) is QEngineeringReducerItem:
|
246
|
if item.connectors[0].connectedItem is prev:
|
247
|
if item.MainSubSize: return item.MainSubSize[0]
|
248
|
elif item.connectors[1].connectedItem is prev:
|
249
|
if item.MainSubSize: return item.MainSubSize[1]
|
250
|
else:
|
251
|
if item.Size: return item.Size
|
252
|
prev = item
|
253
|
|
254
|
if 'Drain' == matches[0].Type: return AppDocData.instance().drain_size
|
255
|
|
256
|
return self.owner.Size
|
257
|
|
258
|
return None
|
259
|
except Exception as ex:
|
260
|
from App import App
|
261
|
from AppDocData import MessageType
|
262
|
|
263
|
message = 'error occurred({}) in {}:{}'.format(ex, sys.exc_info()[-1].tb_frame.f_code.co_filename,
|
264
|
sys.exc_info()[-1].tb_lineno)
|
265
|
App.mainWnd().addMessage.emit(MessageType.Error, str(self.uid) + self.name + message)
|
266
|
|
267
|
def EvaluatedLineNo(self, prop):
|
268
|
from EngineeringLineNoTextItem import QEngineeringLineNoTextItem
|
269
|
|
270
|
if self.owner and type(self.owner) is QEngineeringLineNoTextItem:
|
271
|
attrs = self.owner.getAttributes()
|
272
|
for attr, value in attrs.items():
|
273
|
if prop == attr.Attribute:
|
274
|
return value
|
275
|
|
276
|
return None
|
277
|
|
278
|
def validate(self):
|
279
|
"""validation check"""
|
280
|
|
281
|
from EngineeringAbstractItem import QEngineeringAbstractItem
|
282
|
from EngineeringLineItem import QEngineeringLineItem
|
283
|
from EngineeringSpecBreakItem import QEngineeringSpecBreakItem
|
284
|
from EngineeringTextItem import QEngineeringTextItem
|
285
|
from EngineeringEquipmentItem import QEngineeringEquipmentItem
|
286
|
errors = []
|
287
|
|
288
|
try:
|
289
|
app_doc_data = AppDocData.instance()
|
290
|
dataPath = app_doc_data.getErrorItemSvgPath()
|
291
|
|
292
|
|
293
|
for connector in self.connectors:
|
294
|
errors.extend(connector.validate())
|
295
|
|
296
|
|
297
|
if len(self.connectors) is 2:
|
298
|
if (type(self.connectors[0].connectedItem) is QEngineeringLineItem and
|
299
|
self.connectors[0]._connected_at == QEngineeringAbstractItem.CONNECTED_AT_PT) and \
|
300
|
(type(self.connectors[1].connectedItem) is QEngineeringLineItem and
|
301
|
self.connectors[1]._connected_at == QEngineeringAbstractItem.CONNECTED_AT_PT):
|
302
|
indices = [0, 0]
|
303
|
|
304
|
center = self.connectors[0].center()
|
305
|
dx, dy = [0, 0], [0, 0]
|
306
|
dx[0] = center[0] - self.connectors[0].connectedItem.line().p1().x()
|
307
|
dy[0] = center[1] - self.connectors[0].connectedItem.line().p1().y()
|
308
|
dx[1] = center[0] - self.connectors[0].connectedItem.line().p2().x()
|
309
|
dy[1] = center[1] - self.connectors[0].connectedItem.line().p2().y()
|
310
|
indices[0] = 1 if (dx[0] * dx[0] + dy[0] * dy[0]) < (dx[1] * dx[1]) + (dy[1] * dy[1]) else 2
|
311
|
|
312
|
center = self.connectors[1].center()
|
313
|
dx[0] = center[0] - self.connectors[1].connectedItem.line().p1().x()
|
314
|
dy[0] = center[1] - self.connectors[1].connectedItem.line().p1().y()
|
315
|
dx[1] = center[0] - self.connectors[1].connectedItem.line().p2().x()
|
316
|
dy[1] = center[1] - self.connectors[1].connectedItem.line().p2().y()
|
317
|
indices[1] = 1 if (dx[0] * dx[0] + dy[0] * dy[0]) < (dx[1] * dx[1]) + (dy[1] * dy[1]) else 2
|
318
|
|
319
|
if indices[0] == indices[1]:
|
320
|
error = SymbolSvgItem.createItem('Error', None, dataPath)
|
321
|
error.parent = self
|
322
|
error.msg = self.tr('flow direction error')
|
323
|
error.setToolTip(error.msg)
|
324
|
error.area = 'Drawing'
|
325
|
error.name = 'Error'
|
326
|
errors.append(error)
|
327
|
|
328
|
|
329
|
attrs = self.getAttributes()
|
330
|
matches = [(attr, value) for attr, value in attrs.items() if attr.Attribute == 'OWNERSYMBOL']
|
331
|
if matches:
|
332
|
if not matches[0][1]:
|
333
|
error = SymbolSvgItem.createItem('Error', None, dataPath)
|
334
|
error.parent = self
|
335
|
error.msg = 'not combined'
|
336
|
error.setToolTip(error.msg)
|
337
|
error.area = 'Drawing'
|
338
|
error.name = 'Error'
|
339
|
errors.append(error)
|
340
|
else:
|
341
|
disconnect = False
|
342
|
if len(self.connectors) is not 0:
|
343
|
disconnect = True
|
344
|
for connector in self.connectors:
|
345
|
if connector.connectedItem is not None:
|
346
|
disconnect = False
|
347
|
break
|
348
|
|
349
|
if disconnect:
|
350
|
error = SymbolSvgItem.createItem('Error', None, dataPath)
|
351
|
error.parent = self
|
352
|
error.msg = 'disconnected'
|
353
|
error.setToolTip(error.msg)
|
354
|
error.area = 'Drawing'
|
355
|
error.name = 'Error'
|
356
|
errors.append(error)
|
357
|
|
358
|
|
359
|
if self.size[0] == 0 or self.size[1] == 0:
|
360
|
error = SymbolSvgItem.createItem('Error', None, dataPath)
|
361
|
error.parent = self
|
362
|
error.msg = self.tr('size error')
|
363
|
error.setToolTip(error.msg)
|
364
|
error.area = 'Drawing'
|
365
|
error.name = 'Error'
|
366
|
errors.append(error)
|
367
|
|
368
|
|
369
|
for assoc in self.associations():
|
370
|
if issubclass(type(assoc), QEngineeringTextItem) and not assoc.owner:
|
371
|
error = SymbolSvgItem.createItem('Error', None, dataPath)
|
372
|
error.parent = self
|
373
|
error.msg = self.tr('association error')
|
374
|
error.setToolTip(error.msg)
|
375
|
error.area = self.area
|
376
|
error.name = 'Error'
|
377
|
errors.append(error)
|
378
|
|
379
|
|
380
|
for error in errors:
|
381
|
error.setPosition([self.sceneBoundingRect().center().x(), self.sceneBoundingRect().center().y()])
|
382
|
|
383
|
connectedUid = []
|
384
|
for connector in self.connectors:
|
385
|
|
386
|
if connector.connectedItem and issubclass(type(connector.connectedItem), QEngineeringAbstractItem):
|
387
|
connectedUid.append(str(connector.connectedItem.uid))
|
388
|
|
389
|
if (issubclass(type(connector.connectedItem), SymbolSvgItem) and \
|
390
|
type(connector.connectedItem) is not QEngineeringEquipmentItem) or \
|
391
|
type(connector.connectedItem) is QEngineeringLineItem:
|
392
|
matches = [conn for conn in connector.connectedItem.connectors if conn.connectedItem is self]
|
393
|
|
394
|
if not matches:
|
395
|
error = SymbolSvgItem.createItem('Error', None, dataPath)
|
396
|
error.setPosition(connector.center())
|
397
|
error.parent = self
|
398
|
error.msg = self.tr('disconnected from opposite side')
|
399
|
error.setToolTip(error.msg)
|
400
|
error.area = self.area
|
401
|
error.name = 'Error'
|
402
|
errors.append(error)
|
403
|
|
404
|
|
405
|
if len(connectedUid) is not len(set(connectedUid)):
|
406
|
error = SymbolSvgItem.createItem('Error', None, dataPath)
|
407
|
error.setPosition([self.sceneBoundingRect().center().x(), self.sceneBoundingRect().center().y()])
|
408
|
error.parent = self
|
409
|
error.msg = self.tr('duplicated connection')
|
410
|
error.setToolTip(error.msg)
|
411
|
error.area = self.area
|
412
|
error.name = 'Error'
|
413
|
errors.append(error)
|
414
|
|
415
|
|
416
|
if self.conn_type:
|
417
|
for index in range(len(self.conn_type)):
|
418
|
item = self.connectors[index].connectedItem
|
419
|
if item and type(item) is QEngineeringLineItem:
|
420
|
if ((self.conn_type[index] == 'Primary' or self.conn_type[index] == 'Secondary') and not item.is_piping()) or \
|
421
|
(not (self.conn_type[index] == 'Primary' or self.conn_type[index] == 'Secondary') and item.is_piping(True)):
|
422
|
error = SymbolSvgItem.createItem('Error', None, dataPath)
|
423
|
error.setPosition(self.connectors[index].center())
|
424
|
error.parent = self
|
425
|
error.msg = self.tr('line type error')
|
426
|
error.setToolTip(error.msg)
|
427
|
error.area = self.area
|
428
|
error.name = 'Error'
|
429
|
errors.append(error)
|
430
|
|
431
|
except Exception as ex:
|
432
|
from App import App
|
433
|
message = 'error occurred({}) in {}:{}'.format(ex, sys.exc_info()[-1].tb_frame.f_code.co_filename,
|
434
|
sys.exc_info()[-1].tb_lineno)
|
435
|
App.mainWnd().addMessage.emit(MessageType.Error, message)
|
436
|
|
437
|
return errors
|
438
|
|
439
|
def includes(self, pt, margin=0):
|
440
|
"""return True if symbol contains given point else return False"""
|
441
|
rect = self.sceneBoundingRect()
|
442
|
allowed_error = 0.1
|
443
|
|
444
|
if abs(rect.x() - 0) <= allowed_error and abs(rect.y() - 0) <= allowed_error:
|
445
|
|
446
|
minX = self.loc[0] - margin
|
447
|
minY = self.loc[1] - margin
|
448
|
maxX = minX + self.size[0] + margin
|
449
|
maxY = minY + self.size[1] + margin
|
450
|
else:
|
451
|
minX = rect.x() - margin
|
452
|
minY = rect.y() - margin
|
453
|
maxX = minX + rect.width() + margin
|
454
|
maxY = minY + rect.height() + margin
|
455
|
|
456
|
return True if (pt[0] >= minX and pt[0] <= maxX and pt[1] >= minY and pt[1] <= maxY) else False
|
457
|
|
458
|
'''
|
459
|
def associations(self):
|
460
|
""" return associated instance """
|
461
|
# move to abstractitem
|
462
|
import uuid
|
463
|
|
464
|
res = []
|
465
|
for key in self._associations.keys():
|
466
|
index = 0
|
467
|
for assoc in self._associations[key]:
|
468
|
# find owner with uid
|
469
|
if assoc and type(assoc) is uuid.UUID:
|
470
|
matches = [x for x in self.scene().items() if hasattr(x, 'uid') and str(x.uid) == str(assoc)]
|
471
|
if matches:
|
472
|
res.append(matches[0]) # TODO: need to update association with instance
|
473
|
self._associations[key][index] = matches[0]
|
474
|
index += 1
|
475
|
# up to here
|
476
|
elif assoc:
|
477
|
res.append(assoc)
|
478
|
|
479
|
for key in self.attrs.keys():
|
480
|
if type(key.AssocItem) is uuid.UUID:
|
481
|
for assoc in res:
|
482
|
if str(key.AssocItem) == str(assoc.uid):
|
483
|
key.AssocItem = assoc
|
484
|
|
485
|
return res
|
486
|
|
487
|
def texts(self):
|
488
|
""" return text type of associations """
|
489
|
from EngineeringTextItem import QEngineeringTextItem
|
490
|
|
491
|
res = []
|
492
|
for text in [x for x in self.associations() if issubclass(type(x), QEngineeringTextItem)]:
|
493
|
consumed = False
|
494
|
for key in list(self.attrs.keys()):
|
495
|
if key.AssocItem and key.AssocItem is text:
|
496
|
consumed = True
|
497
|
if not consumed:
|
498
|
res.append(text)
|
499
|
|
500
|
return res
|
501
|
|
502
|
def symbols(self):
|
503
|
""" return symbol type of associations """
|
504
|
res = []
|
505
|
for symbol in [x for x in self.associations() if issubclass(type(x), SymbolSvgItem)]:
|
506
|
consumed = False
|
507
|
for key in list(self.attrs.keys()):
|
508
|
if key.AssocItem and key.AssocItem is symbol:
|
509
|
consumed = True
|
510
|
if not consumed:
|
511
|
res.append(symbol)
|
512
|
|
513
|
return res
|
514
|
'''
|
515
|
|
516
|
def itemChange(self, change, value):
|
517
|
""" call signals when item's position or rotation is changed """
|
518
|
if not self.scene(): return super().itemChange(change, value)
|
519
|
|
520
|
if change == QGraphicsItem.ItemPositionHasChanged or change == QGraphicsItem.ItemRotationChange:
|
521
|
from EngineeringLineItem import QEngineeringLineItem
|
522
|
for connector in self.connectors:
|
523
|
if connector.connectedItem is not None and type(connector.connectedItem) == QEngineeringLineItem:
|
524
|
line = connector.connectedItem
|
525
|
line.reDrawLine(self, connector.center())
|
526
|
line.update_arrow()
|
527
|
|
528
|
self.size[0], self.size[1] = round(self.sceneBoundingRect().width()), round(
|
529
|
self.sceneBoundingRect().height())
|
530
|
|
531
|
self.scene().contents_changed.emit()
|
532
|
|
533
|
return value
|
534
|
|
535
|
return super().itemChange(change, value)
|
536
|
|
537
|
def toSql_Components(self):
|
538
|
""" convert Components data to sql query """
|
539
|
from AppDocData import AppDocData
|
540
|
|
541
|
cols = ['UID', 'Drawings_UID', 'Symbol_UID', 'X', 'Y', 'Width', 'Height', 'Rotation', 'Area', 'Owner',
|
542
|
'Connected', '[Supplied By]', \
|
543
|
'SpecialItemTypes_UID', 'OriginIndex', '[From]', '[To]', '[Freeze]', '[Connected Item]', '[Flip]', 'SceneOriginPoint']
|
544
|
values = ['?', '?', '?', '?', '?', '?', '?', '?', '?', '?', '?', '?', '?', '?', '?', '?', '?', '?', '?', '?']
|
545
|
param = [(str(self.uid), str(AppDocData.instance().activeDrawing.UID), self.dbUid, self.loc[0], self.loc[1],
|
546
|
self.size[0], self.size[1], self.angle,
|
547
|
self.area, str(self.owner) if self.owner else None, \
|
548
|
str(self.conns[0]) if self.conns else None, \
|
549
|
self.prop('Supplied By'), \
|
550
|
str(self.special_item_type) if self.special_item_type else None, \
|
551
|
self.currentPointModeIndex, \
|
552
|
None, \
|
553
|
None, \
|
554
|
self.prop('Freeze') if self.prop('Freeze') else 0, \
|
555
|
str(self.prop('Connected Item')) if self.prop('Connected Item') else None, \
|
556
|
self.flip, \
|
557
|
'{},{}'.format(self.origin[0], self.origin[1]))]
|
558
|
sql = 'insert into Components({}) values({})'.format(','.join(cols), ','.join(values))
|
559
|
|
560
|
return (sql, tuple(param))
|
561
|
|
562
|
def toSql_return_separately(self):
|
563
|
""" convert valve data to sql query """
|
564
|
import uuid
|
565
|
|
566
|
res = []
|
567
|
resLater = []
|
568
|
|
569
|
res.append(self.toSql_Components())
|
570
|
|
571
|
_attrs = self.getAttributes()
|
572
|
if _attrs:
|
573
|
cols = ['UID', 'Components_UID', 'SymbolAttribute_UID', 'Value', 'Association_UID', 'Freeze']
|
574
|
values = ['?', '?', '?', '?', '?', '?']
|
575
|
params = []
|
576
|
for key in _attrs.keys():
|
577
|
if key.AttributeType != 'Spec':
|
578
|
params.append((str(uuid.uuid4()), str(self.uid), str(key.UID), str(_attrs[key]), str(key.AssocItem),
|
579
|
str(key.Freeze)))
|
580
|
elif key.AttributeType == 'Spec':
|
581
|
if type(_attrs[key]) is not list: continue
|
582
|
params.append((str(uuid.uuid4()), str(self.uid), str(key.UID), (str(_attrs[key][0]) + ',' + str(_attrs[key][1])), str(key.AssocItem),
|
583
|
str(key.Freeze)))
|
584
|
sql = 'insert into Attributes({}) values({})'.format(','.join(cols), ','.join(values))
|
585
|
res.append((sql, tuple(params)))
|
586
|
|
587
|
if self.associations():
|
588
|
cols = ['UID', '[Type]', 'Components_UID', 'Association']
|
589
|
values = ['?', '?', '?', '?']
|
590
|
params = []
|
591
|
for assoc in self.associations():
|
592
|
params.append(
|
593
|
(str(uuid.uuid4()), QEngineeringAbstractItem.assoc_type(assoc), str(self.uid), str(assoc.uid)))
|
594
|
sql = 'insert into Associations({}) values({})'.format(','.join(cols), ','.join(values))
|
595
|
resLater.append((sql, tuple(params)))
|
596
|
|
597
|
|
598
|
if self.connectors:
|
599
|
cols = ['Components_UID', '[Index]', 'X', 'Y', 'Connected', 'Connected_At']
|
600
|
values = ['?', '?', '?', '?', '?', '?']
|
601
|
params = []
|
602
|
index = 1
|
603
|
for connector in self.connectors:
|
604
|
params.append( \
|
605
|
(
|
606
|
str(self.uid), index, connector.center()[0], connector.center()[1], \
|
607
|
str(connector.connectedItem.uid) if connector.connectedItem else None, \
|
608
|
str(connector._connected_at)) \
|
609
|
)
|
610
|
index += 1
|
611
|
sql = 'insert into Points({}) values({})'.format(','.join(cols), ','.join(values))
|
612
|
resLater.append((sql, tuple(params)))
|
613
|
|
614
|
|
615
|
return res, resLater
|
616
|
|
617
|
'''
|
618
|
@brief build symbol item
|
619
|
@author humkyung
|
620
|
@date 2018.05.02
|
621
|
@history 2018.05.09 Jeongwoo Clear self.connectors
|
622
|
2018.05.30 Jeongwoo Add parameters (parentSymbol, childSymbol)
|
623
|
'''
|
624
|
|
625
|
def buildItem(self, name, _type, angle, loc, size, origin, connPts, parentSymbol, childSymbol, hasInstrumentLabel,
|
626
|
dbUid=None):
|
627
|
from SpecialItemTypesDialog import SpecialItemTypes
|
628
|
|
629
|
try:
|
630
|
app_doc_data = AppDocData.instance()
|
631
|
self.name = name
|
632
|
self.type = _type
|
633
|
self.angle = angle
|
634
|
self.loc = loc
|
635
|
self.size = size if size else [0, 0]
|
636
|
self.origin = origin
|
637
|
if dbUid is None:
|
638
|
symbolInfo = app_doc_data.getSymbolByQuery('name', name)
|
639
|
else:
|
640
|
symbolInfo = app_doc_data.getSymbolByQuery('UID', dbUid)
|
641
|
self.dbUid = symbolInfo.uid
|
642
|
self.iType = symbolInfo.iType
|
643
|
self.text_area = symbolInfo.text_area
|
644
|
self._class = symbolInfo.baseSymbol
|
645
|
originalPoint = symbolInfo.getOriginalPoint().split(',')
|
646
|
self.symbolOrigin = [float(originalPoint[0]), float(originalPoint[1])]
|
647
|
|
648
|
|
649
|
connectionPoints = symbolInfo.getConnectionPoint().split('/')
|
650
|
for index in range(len(connectionPoints)):
|
651
|
if connectionPoints[index] == '':
|
652
|
break
|
653
|
tokens = connectionPoints[index].split(',')
|
654
|
|
655
|
direction = 'AUTO'
|
656
|
symbol_idx = '0'
|
657
|
if len(tokens) == 2:
|
658
|
x = float(tokens[0])
|
659
|
y = float(tokens[1])
|
660
|
elif len(tokens) >= 3:
|
661
|
direction = connPts[index][0] if index < len(connPts) else tokens[0]
|
662
|
x = float(tokens[1])
|
663
|
y = float(tokens[2])
|
664
|
if len(tokens) >= 4:
|
665
|
symbol_idx = tokens[3]
|
666
|
if len(tokens) >= 6:
|
667
|
if tokens[4] == 'In':
|
668
|
self.in_out_connector[0].append(index)
|
669
|
elif tokens[4] == 'Out':
|
670
|
self.in_out_connector[1].append(index)
|
671
|
if tokens[5] == 'O':
|
672
|
self.break_connector.append(index)
|
673
|
if len(tokens) >= 7:
|
674
|
self.conn_type.append(tokens[6])
|
675
|
|
676
|
self.setConnector(index + 1)
|
677
|
self.connectors[index].direction = direction
|
678
|
self.connectors[index].symbol_idx = symbol_idx
|
679
|
self.connectors[index].setPos((x, y))
|
680
|
self.connectors[index].connectPoint = (x, y)
|
681
|
|
682
|
self.connectors[index].recognized_pt = (connPts[index][0], connPts[index][1]) if \
|
683
|
len(connPts[index]) == 2 else (connPts[index][1], connPts[index][2]) if \
|
684
|
len(connPts[index]) == 3 else (connPts[index][1], connPts[index][2]) if \
|
685
|
len(connPts[index]) == 4 else None
|
686
|
|
687
|
self.parentSymbol = parentSymbol
|
688
|
self.childSymbol = childSymbol
|
689
|
self.hasInstrumentLabel = hasInstrumentLabel
|
690
|
self.currentPointModeIndex = 0
|
691
|
self.special_item_type = SpecialItemTypes.instance().find_match_exactly(self)
|
692
|
|
693
|
tooltip = f"<b>{str(self.uid)}</b><br>{self.type}={self.name}"
|
694
|
if self.hit_ratio:
|
695
|
tooltip += f"<br><li>recognition ratio={self.hit_ratio}"
|
696
|
self.setToolTip(tooltip)
|
697
|
|
698
|
return True
|
699
|
except Exception as ex:
|
700
|
from App import App
|
701
|
|
702
|
message = 'error occurred({}) in {}:{}'.format(ex, sys.exc_info()[-1].tb_frame.f_code.co_filename,
|
703
|
sys.exc_info()[-1].tb_lineno)
|
704
|
App.mainWnd().addMessage.emit(MessageType.Error, message)
|
705
|
|
706
|
return False
|
707
|
|
708
|
'''
|
709
|
@brief return bounding box of symbol
|
710
|
@author humkyung
|
711
|
@date 2018.04.08
|
712
|
'''
|
713
|
|
714
|
def rect(self):
|
715
|
return self.sceneBoundingRect()
|
716
|
|
717
|
def is_connectable(self, item, toler=10):
|
718
|
"""return true if line is able to connect symbol"""
|
719
|
|
720
|
for connector in self.connectors:
|
721
|
for iConnector in item.connectors:
|
722
|
dx = connector.center()[0] - iConnector.center()[0]
|
723
|
dy = connector.center()[1] - iConnector.center()[1]
|
724
|
if math.sqrt(dx * dx + dy * dy) < toler:
|
725
|
return True
|
726
|
|
727
|
return False
|
728
|
|
729
|
'''
|
730
|
@author humkyung
|
731
|
@date 2018.07.03
|
732
|
'''
|
733
|
|
734
|
def is_connected(self, item, at=QEngineeringAbstractItem.CONNECTED_AT_PT):
|
735
|
""" check if given item is connected to self """
|
736
|
|
737
|
_connectors = [connector for connector in self.connectors if
|
738
|
(connector.connectedItem == item and (connector._connected_at == at if at else True))]
|
739
|
return len(_connectors) > 0
|
740
|
|
741
|
def next_connected(self, lhs, rhs):
|
742
|
""" check given two item's are next connected(ex: 0-1, 2-3) """
|
743
|
|
744
|
lhs_matches = [at for at in range(len(self.connectors)) if self.connectors[at].connectedItem == lhs]
|
745
|
rhs_matches = [at for at in range(len(self.connectors)) if self.connectors[at].connectedItem == rhs]
|
746
|
if lhs_matches and rhs_matches:
|
747
|
return (lhs_matches[0] in [0, 1] and rhs_matches[0] in [0, 1]) or (
|
748
|
lhs_matches[0] in [2, 3] and rhs_matches[0] in [2, 3])
|
749
|
|
750
|
return False
|
751
|
|
752
|
def canBeSecondary(self, line):
|
753
|
""" check given line is not connected(ex: 0-1, 2-3) """
|
754
|
preItem = None
|
755
|
|
756
|
item = [item.connectedItem for item in self.connectors if
|
757
|
item.connectedItem is not None and item.connectedItem.owner is not None]
|
758
|
if item:
|
759
|
preItem = item[0]
|
760
|
|
761
|
if preItem is not None and not self.next_connected(line, preItem):
|
762
|
return True
|
763
|
else:
|
764
|
return False
|
765
|
|
766
|
'''
|
767
|
@brief connect line and symbol is able to be connected and return line
|
768
|
@author humkyung
|
769
|
@date 2018.04.16
|
770
|
@history humkyung 2018.05.08 check if symbol is possible to be connected
|
771
|
Jeongwoo 2018.05.15 Connect each symbol and line
|
772
|
'''
|
773
|
|
774
|
def connect_if_possible(self, obj, toler=10):
|
775
|
""" this method not update item's position """
|
776
|
|
777
|
from shapely.geometry import Point
|
778
|
from EngineeringLineItem import QEngineeringLineItem
|
779
|
|
780
|
res = []
|
781
|
try:
|
782
|
if type(obj) is QEngineeringLineItem:
|
783
|
startPt = obj.start_point()
|
784
|
endPt = obj.end_point()
|
785
|
for i in range(len(self.connectors)):
|
786
|
if (Point(startPt[0], startPt[1]).distance(Point(self.connectors[i].center()[0],
|
787
|
self.connectors[i].center()[1])) < toler):
|
788
|
if self.connectors[i].connectedItem is None and obj.connectors[0].connectedItem is None:
|
789
|
self.connectors[i].connect(obj)
|
790
|
obj.connectors[0].connect(self)
|
791
|
|
792
|
res.append(obj)
|
793
|
res.append(self.connectors[i].center())
|
794
|
res.append(endPt)
|
795
|
if (Point(endPt[0], endPt[1]).distance(Point(self.connectors[i].center()[0],
|
796
|
self.connectors[i].center()[1])) < toler):
|
797
|
if self.connectors[i].connectedItem is None and obj.connectors[1].connectedItem is None:
|
798
|
self.connectors[i].connect(obj)
|
799
|
obj.connectors[1].connect(self)
|
800
|
|
801
|
res.append(obj)
|
802
|
res.append(startPt)
|
803
|
res.append(self.connectors[i].center())
|
804
|
elif issubclass(type(obj), SymbolSvgItem):
|
805
|
for i in range(len(self.connectors)):
|
806
|
if i > 3: break
|
807
|
for j in range(len(obj.connectors)):
|
808
|
if j > 3: break
|
809
|
_pt = Point(obj.connectors[j].center()[0], obj.connectors[j].center()[1])
|
810
|
if (_pt.distance(Point(self.connectors[i].center()[0],
|
811
|
self.connectors[i].center()[1])) < toler):
|
812
|
if self.connectors[i].connectedItem is None:
|
813
|
self.connectors[i].connect(obj)
|
814
|
if obj.connectors[j].connectedItem is None:
|
815
|
obj.connectors[j].connect(self)
|
816
|
|
817
|
res.append(obj)
|
818
|
except Exception as ex:
|
819
|
from App import App
|
820
|
message = 'error occurred({}) in {}:{}'.format(ex, sys.exc_info()[-1].tb_frame.f_code.co_filename,
|
821
|
sys.exc_info()[-1].tb_lineno)
|
822
|
App.mainWnd().addMessage.emit(MessageType.Error, message)
|
823
|
|
824
|
return res
|
825
|
|
826
|
'''
|
827
|
@brief disconnect connector item
|
828
|
@author kyouho
|
829
|
@date 2018.08.30
|
830
|
'''
|
831
|
|
832
|
def disconnectedItemAtConnector(self, connector):
|
833
|
for conn in self.connectors:
|
834
|
if conn.isOverlapConnector(connector):
|
835
|
conn.connectedItem = None
|
836
|
|
837
|
'''
|
838
|
@brief get connection point close to given point in tolerance
|
839
|
@author humkyung
|
840
|
@dat
|
841
|
'''
|
842
|
|
843
|
def getConnectionPointCloseTo(self, pt, toler=10):
|
844
|
import math
|
845
|
|
846
|
for connector in self.connectors:
|
847
|
dx = connector.center()[0] - pt[0]
|
848
|
dy = connector.center()[1] - pt[1]
|
849
|
|
850
|
if math.sqrt(dx * dx + dy * dy) < toler:
|
851
|
return connPt
|
852
|
|
853
|
return None
|
854
|
|
855
|
'''
|
856
|
@brief return center of symbol
|
857
|
@author humkyung
|
858
|
@date 2018.04.08
|
859
|
'''
|
860
|
|
861
|
def center(self):
|
862
|
return self.sceneBoundingRect().center()
|
863
|
|
864
|
'''
|
865
|
@brief highlight connector and attribute
|
866
|
@authro humkyung
|
867
|
@date 2018.05.02
|
868
|
'''
|
869
|
|
870
|
def hoverEnterEvent(self, event):
|
871
|
self.highlight(True)
|
872
|
|
873
|
'''
|
874
|
@brief unhighlight connector and attribute
|
875
|
@author humkyung
|
876
|
@date 2018.05.02
|
877
|
@history kyouho 2018.07.18 edit ArrowCursor
|
878
|
'''
|
879
|
|
880
|
def hoverLeaveEvent(self, event):
|
881
|
self.highlight(False)
|
882
|
|
883
|
def highlight(self, flag):
|
884
|
""" highlight/unhighlight the symbol """
|
885
|
|
886
|
try:
|
887
|
self.hover = flag
|
888
|
self.setZValue(QEngineeringAbstractItem.HOVER_ZVALUE) if flag else self.setZValue(SymbolSvgItem.ZVALUE)
|
889
|
self.update()
|
890
|
|
891
|
for assoc in self.associations():
|
892
|
assoc.highlight(flag)
|
893
|
|
894
|
for connector in self.connectors:
|
895
|
connector.highlight(flag)
|
896
|
except Exception as ex:
|
897
|
from App import App
|
898
|
message = 'error occurred({}) in {}:{}'.format(ex, sys.exc_info()[-1].tb_frame.f_code.co_filename,
|
899
|
sys.exc_info()[-1].tb_lineno)
|
900
|
App.mainWnd().addMessage.emit(MessageType.Error, message)
|
901
|
|
902
|
'''
|
903
|
@brief set highlight
|
904
|
@author kyouho
|
905
|
@date 2018.08.27
|
906
|
'''
|
907
|
|
908
|
def setHightlight(self):
|
909
|
self.setColor('url(#hover)')
|
910
|
self.update()
|
911
|
|
912
|
'''
|
913
|
@brief unset highlight
|
914
|
@author kyouho
|
915
|
@date 2018.08.27
|
916
|
'''
|
917
|
|
918
|
def unsetHightlight(self):
|
919
|
self.setColor('url(#normal)')
|
920
|
self.update()
|
921
|
|
922
|
'''
|
923
|
@brief change cursor to CrossCursor if mouse point is close to connection point
|
924
|
@author humkyung
|
925
|
@date 2018.04.28
|
926
|
'''
|
927
|
|
928
|
def hoverMoveEvent(self, event):
|
929
|
pass
|
930
|
|
931
|
'''
|
932
|
@brief Mouse Press Event
|
933
|
@author Jeongwoo
|
934
|
@date 18.04.11
|
935
|
@history kyouho 2018.07.18 add isClick logic
|
936
|
'''
|
937
|
|
938
|
def mousePressEvent(self, event):
|
939
|
if event.buttons() == Qt.LeftButton:
|
940
|
self.clicked.emit(self)
|
941
|
|
942
|
'''
|
943
|
@brief Mouse Release Event
|
944
|
@author kyouho
|
945
|
@date 18.07.17
|
946
|
'''
|
947
|
|
948
|
def mouseReleaseEvent(self, event):
|
949
|
if hasattr(self, '_rotating') and event.button() == Qt.RightButton:
|
950
|
self.angle = -self._angle if self._angle > -math.pi and self._angle < 0 else 2 * math.pi - self._angle
|
951
|
self.ungrabMouse()
|
952
|
del self._rotating
|
953
|
|
954
|
super().mouseReleaseEvent(event)
|
955
|
|
956
|
def mouseMoveEvent(self, event):
|
957
|
""" rotate symbol accroding to current mouse point """
|
958
|
if hasattr(self, '_rotating'):
|
959
|
|
960
|
origin = self.origin
|
961
|
|
962
|
|
963
|
dx = (event.scenePos().x() - origin[0])
|
964
|
dy = (event.scenePos().y() - origin[1])
|
965
|
length = math.sqrt(dx * dx + dy * dy)
|
966
|
|
967
|
self._angle = 0
|
968
|
if length > 0:
|
969
|
self._angle = math.acos(dx / length)
|
970
|
cross = int(np.cross([1, 0], [dx, dy]))
|
971
|
self._angle = -self._angle if cross < 0 else self._angle
|
972
|
|
973
|
self.rotate(self.getCurrentPoint(), -self._angle)
|
974
|
|
975
|
def removeSelfAttr(self, attributeName):
|
976
|
target = None
|
977
|
for attr in self.attrs:
|
978
|
if attr.Attribute == attributeName:
|
979
|
target = attr
|
980
|
break
|
981
|
|
982
|
if target:
|
983
|
del self.attrs[attr]
|
984
|
|
985
|
'''
|
986
|
@brief Find TextItem contain Point
|
987
|
@author kyouho
|
988
|
@date 18.07.17
|
989
|
'''
|
990
|
|
991
|
def findTextItemInPoint(self, point):
|
992
|
from EngineeringTextItem import QEngineeringTextItem
|
993
|
|
994
|
scene = self.scene()
|
995
|
|
996
|
for item in scene.items():
|
997
|
if type(item) is QEngineeringTextItem:
|
998
|
if self.isOverlapItemAndPoint(item, point):
|
999
|
return (True, item)
|
1000
|
|
1001
|
return (False,)
|
1002
|
|
1003
|
'''
|
1004
|
@brief Check Overlap
|
1005
|
@author kyouho
|
1006
|
@date 18.07.17
|
1007
|
'''
|
1008
|
|
1009
|
def isOverlapItemAndPoint(self, item, point):
|
1010
|
x = point.x()
|
1011
|
y = point.y()
|
1012
|
loc = item.loc
|
1013
|
size = item.size
|
1014
|
|
1015
|
if loc[0] <= x and loc[0] + size[0] >= x and loc[1] <= y and loc[1] + size[1] >= y:
|
1016
|
return True
|
1017
|
else:
|
1018
|
return False
|
1019
|
|
1020
|
'''
|
1021
|
@brief remove item when user press delete key
|
1022
|
@author humkyung
|
1023
|
@date 2018.04.23
|
1024
|
@history 2018.05.17 Jeongwoo Add if-statement and move 'break'
|
1025
|
2018.05.25 Jeongwoo Seperate delete item method
|
1026
|
'''
|
1027
|
def keyPressEvent(self, event):
|
1028
|
from EngineeringErrorItem import QEngineeringErrorItem
|
1029
|
from RotateSymbolDialog import QRotateSymbolDialog
|
1030
|
|
1031
|
if not self.isSelected():
|
1032
|
return
|
1033
|
if event.key() == Qt.Key_B:
|
1034
|
self.bind_close_items()
|
1035
|
elif event.key() == Qt.Key_R and type(self) is not QEngineeringErrorItem:
|
1036
|
self.rotateSymbol()
|
1037
|
elif event.key() == Qt.Key_O and type(self) is not QEngineeringErrorItem:
|
1038
|
pass
|
1039
|
elif event.key() == Qt.Key_C and type(self) is not QEngineeringErrorItem:
|
1040
|
self.changeConnPoint()
|
1041
|
elif event.key() == Qt.Key_F and type(self) is not QEngineeringErrorItem:
|
1042
|
self.flipSymbol()
|
1043
|
elif event.key() == Qt.Key_Return:
|
1044
|
dialog = QRotateSymbolDialog(None, self.angle, self.origin, self.zValue())
|
1045
|
(isAccept, angle, x, y, z) = dialog.showDialog()
|
1046
|
|
1047
|
if isAccept:
|
1048
|
self.angle = angle
|
1049
|
self.loc = [x - self.symbolOrigin[0], y - self.symbolOrigin[1]]
|
1050
|
self.origin = [x, y]
|
1051
|
self.rotate(self.getCurrentPoint(), self.angle)
|
1052
|
self.setZValue(z)
|
1053
|
elif event.key() == Qt.Key_Escape:
|
1054
|
if hasattr(self, '_rotating'):
|
1055
|
self.ungrabMouse()
|
1056
|
|
1057
|
transform = QTransform()
|
1058
|
transform.translate((self.loc[0] + self.symbolOrigin[0]), (self.loc[1] + self.symbolOrigin[1]))
|
1059
|
transform.rotateRadians(self.angle)
|
1060
|
transform.translate(-self.symbolOrigin[0], -self.symbolOrigin[1])
|
1061
|
self.setTransform(transform)
|
1062
|
|
1063
|
del self._rotating
|
1064
|
elif event.key() == Qt.Key_Up:
|
1065
|
modifiers = QApplication.keyboardModifiers()
|
1066
|
delta = 10 if modifiers == Qt.ControlModifier else 1
|
1067
|
|
1068
|
self.loc[1] = self.loc[1] - delta
|
1069
|
self.origin[1] = self.origin[1] - delta
|
1070
|
self.rotate(self.getCurrentPoint(), self.angle)
|
1071
|
elif event.key() == Qt.Key_Down:
|
1072
|
modifiers = QApplication.keyboardModifiers()
|
1073
|
delta = 10 if modifiers == Qt.ControlModifier else 1
|
1074
|
|
1075
|
self.loc[1] = self.loc[1] + delta
|
1076
|
self.origin[1] = self.origin[1] + delta
|
1077
|
self.rotate(self.getCurrentPoint(), self.angle)
|
1078
|
elif event.key() == Qt.Key_Left:
|
1079
|
modifiers = QApplication.keyboardModifiers()
|
1080
|
delta = 10 if modifiers == Qt.ControlModifier else 1
|
1081
|
|
1082
|
self.loc[0] = self.loc[0] - delta
|
1083
|
self.origin[0] = self.origin[0] - delta
|
1084
|
self.rotate(self.getCurrentPoint(), self.angle)
|
1085
|
elif event.key() == Qt.Key_Right:
|
1086
|
modifiers = QApplication.keyboardModifiers()
|
1087
|
delta = 10 if modifiers == Qt.ControlModifier else 1
|
1088
|
|
1089
|
self.loc[0] = self.loc[0] + delta
|
1090
|
self.origin[0] = self.origin[0] + delta
|
1091
|
self.rotate(self.getCurrentPoint(), self.angle)
|
1092
|
elif event.key() == Qt.Key_I or event.key() == Qt.Key_X:
|
1093
|
from App import App
|
1094
|
App.mainWnd().keyPressEvent(event)
|
1095
|
|
1096
|
def bind_close_items(self):
|
1097
|
""" connect close item by pressing B """
|
1098
|
from EngineeringLineItem import QEngineeringLineItem
|
1099
|
|
1100
|
scene = self.scene()
|
1101
|
if scene:
|
1102
|
configs = AppDocData.instance().getConfigs('Line Detector', 'Length to connect line')
|
1103
|
toler = int(configs[0].value) if configs else 20
|
1104
|
for item in [item for item in scene.items() if hasattr(item, 'connectors')]:
|
1105
|
if item is not self:
|
1106
|
res = self.connect_if_possible(item, toler)
|
1107
|
if res and type(item) is QEngineeringLineItem:
|
1108
|
item.set_line([res[1], res[2]])
|
1109
|
|
1110
|
'''
|
1111
|
@brief connect attribute
|
1112
|
@author humkyung
|
1113
|
@date 2018.05.02
|
1114
|
@history humkyung 2018.05.09 append only nearest size attribute
|
1115
|
'''
|
1116
|
def connectAttribute(self, attributes, clear=True):
|
1117
|
import math
|
1118
|
from EngineeringTextItem import QEngineeringTextItem
|
1119
|
from QEngineeringSizeTextItem import QEngineeringSizeTextItem
|
1120
|
from EngineeringInstrumentItem import QEngineeringInstrumentItem
|
1121
|
from EngineeringValveOperCodeTextItem import QEngineeringValveOperCodeTextItem
|
1122
|
|
1123
|
try:
|
1124
|
if clear:
|
1125
|
if not self.clear_attr_and_assoc_item():
|
1126
|
return
|
1127
|
|
1128
|
configs = AppDocData.instance().getConfigs('Range', 'Detection Ratio')
|
1129
|
ratio = float(configs[0].value) if 1 == len(configs) else 1.5
|
1130
|
|
1131
|
rect = self.sceneBoundingRect()
|
1132
|
dist = max(self.sceneBoundingRect().height(), self.sceneBoundingRect().width()) * ratio
|
1133
|
center = self.sceneBoundingRect().center()
|
1134
|
|
1135
|
minDist = None
|
1136
|
selected = None
|
1137
|
for attr in attributes:
|
1138
|
|
1139
|
if False:
|
1140
|
dx = attr.center().x() - center.x()
|
1141
|
dy = attr.center().y() - center.y()
|
1142
|
length = math.sqrt(dx * dx + dy * dy)
|
1143
|
if (length < dist) and (minDist is None or length < minDist):
|
1144
|
minDist = length
|
1145
|
selected = attr
|
1146
|
elif False:
|
1147
|
if not attr.is_connected():
|
1148
|
dx = attr.center().x() - center.x()
|
1149
|
dy = attr.center().y() - center.y()
|
1150
|
if math.sqrt(dx * dx + dy * dy) < dist:
|
1151
|
if self.add_assoc_item(attr):
|
1152
|
attr.owner = self
|
1153
|
elif issubclass(type(attr), QEngineeringTextItem):
|
1154
|
if rect.contains(attr.center()):
|
1155
|
if self.add_assoc_item(attr):
|
1156
|
attr.owner = self
|
1157
|
|
1158
|
if selected is not None:
|
1159
|
if self.add_assoc_item(selected):
|
1160
|
selected.owner = self
|
1161
|
|
1162
|
except Exception as ex:
|
1163
|
from App import App
|
1164
|
message = 'error occurred({}) in {}:{}'.format(ex, sys.exc_info()[-1].tb_frame.f_code.co_filename,
|
1165
|
sys.exc_info()[-1].tb_lineno)
|
1166
|
App.mainWnd().addMessage.emit(MessageType.Error, message)
|
1167
|
|
1168
|
'''
|
1169
|
@brief start rotating
|
1170
|
@author euisung
|
1171
|
@date 2019.04.16
|
1172
|
'''
|
1173
|
|
1174
|
def mouseDoubleClickEvent(self, event):
|
1175
|
if not hasattr(self, '_rotating'):
|
1176
|
self._rotating = True
|
1177
|
self.grabMouse()
|
1178
|
|
1179
|
'''
|
1180
|
@brief generate xml code
|
1181
|
@author humkyung
|
1182
|
@date 2018.04.23
|
1183
|
@history humkyung 2018.04.25 add angle xml node
|
1184
|
humkyung 2018.04.27 add originalpoint xml node
|
1185
|
humkyung 2018.05.02 add attribute of symbol
|
1186
|
Jeongwoo 2018.05.30 add attribute of symbol (parentSymbol, childSymbol, type, connectionPoint)
|
1187
|
yecheol 2018.07.11 add attribute of symbol (hasInstrumentLabel)
|
1188
|
humkyung 2018.07.20 write owner's uid to xml
|
1189
|
humkyung 2018.07.23 write connected item's uid to xml
|
1190
|
kyouho 2018.07.31
|
1191
|
humkyung 2018.09.06 write area to xml
|
1192
|
'''
|
1193
|
|
1194
|
def toXml(self):
|
1195
|
import uuid
|
1196
|
from xml.etree.ElementTree import Element, SubElement, dump, ElementTree
|
1197
|
from EngineeringAbstractItem import QEngineeringAbstractItem
|
1198
|
from EngineeringTextItem import QEngineeringTextItem
|
1199
|
from EngineeringSpecBreakItem import QEngineeringSpecBreakItem
|
1200
|
from SymbolAttr import SymbolAttr
|
1201
|
|
1202
|
try:
|
1203
|
node = Element('SYMBOL')
|
1204
|
uidNode = Element('UID')
|
1205
|
uidNode.text = str(self.uid)
|
1206
|
node.append(uidNode)
|
1207
|
|
1208
|
dbUidNode = Element('DBUID')
|
1209
|
dbUidNode.text = str(self.dbUid)
|
1210
|
node.append(dbUidNode)
|
1211
|
|
1212
|
nameNode = Element('NAME')
|
1213
|
nameNode.text = self.name
|
1214
|
node.append(nameNode)
|
1215
|
|
1216
|
attributeValueNode = Element('ASSOCIATIONS')
|
1217
|
for key, value in self._associations.items():
|
1218
|
for assoc in value:
|
1219
|
assoc_node = Element('ASSOCIATION')
|
1220
|
assoc_node.attrib['TYPE'] = str(key)
|
1221
|
assoc_node.text = str(assoc)
|
1222
|
attributeValueNode.append(assoc_node)
|
1223
|
node.append(attributeValueNode)
|
1224
|
|
1225
|
typeNode = Element('TYPE')
|
1226
|
typeNode.text = self.type
|
1227
|
node.append(typeNode)
|
1228
|
|
1229
|
|
1230
|
ownerNode = Element('OWNER')
|
1231
|
if self.owner is not None:
|
1232
|
ownerNode.text = str(self.owner)
|
1233
|
else:
|
1234
|
ownerNode.text = 'None'
|
1235
|
node.append(ownerNode)
|
1236
|
|
1237
|
|
1238
|
originNode = Element('ORIGINALPOINT')
|
1239
|
originNode.text = '{},{}'.format(self.origin[0], self.origin[1])
|
1240
|
node.append(originNode)
|
1241
|
|
1242
|
connectorsNode = Element('CONNECTORS')
|
1243
|
for connector in self.connectors:
|
1244
|
connectorsNode.append(connector.toXml())
|
1245
|
node.append(connectorsNode)
|
1246
|
|
1247
|
connectionNode = Element('CONNECTIONPOINT')
|
1248
|
connection_point = []
|
1249
|
if self.connectors is not None:
|
1250
|
for connector in self.connectors:
|
1251
|
connection_point.append(repr(connector))
|
1252
|
connectionNode.text = '/'.join(connection_point)
|
1253
|
node.append(connectionNode)
|
1254
|
|
1255
|
locNode = Element('LOCATION')
|
1256
|
locNode.text = '{},{}'.format(self.loc[0], self.loc[1])
|
1257
|
'''
|
1258
|
# calculate symbol's left-top corner
|
1259
|
transform = QTransform()
|
1260
|
transform.translate(self.scenePos().x(), self.scenePos().y())
|
1261
|
transform.rotateRadians(-self.angle)
|
1262
|
loc = transform.map(QPointF(self.symbolOrigin[0], self.symbolOrigin[1]))
|
1263
|
# up to here
|
1264
|
locNode.text = '{},{}'.format(loc.x() - self.symbolOrigin[0], loc.y() - self.symbolOrigin[1])
|
1265
|
'''
|
1266
|
node.append(locNode)
|
1267
|
|
1268
|
sizeNode = Element('SIZE')
|
1269
|
sizeNode.text = '{},{}'.format(self.size[0], self.size[1])
|
1270
|
node.append(sizeNode)
|
1271
|
|
1272
|
angleNode = Element('ANGLE')
|
1273
|
angleNode.text = str(self.angle)
|
1274
|
node.append(angleNode)
|
1275
|
|
1276
|
parentSymbolNode = Element('PARENT')
|
1277
|
parentSymbolNode.text = str(self.parentSymbol)
|
1278
|
node.append(parentSymbolNode)
|
1279
|
|
1280
|
childSymbolNode = Element('CHILD')
|
1281
|
childSymbolNode.text = str(self.childSymbol)
|
1282
|
node.append(childSymbolNode)
|
1283
|
|
1284
|
hasInstrumentLabelNode = Element('HASINSTRUMENTLABEL')
|
1285
|
hasInstrumentLabelNode.text = str(self.hasInstrumentLabel)
|
1286
|
node.append(hasInstrumentLabelNode)
|
1287
|
|
1288
|
areaNode = Element('AREA')
|
1289
|
areaNode.text = self.area
|
1290
|
node.append(areaNode)
|
1291
|
|
1292
|
flipNode = Element('FLIP')
|
1293
|
flipNode.text = str(self.flip)
|
1294
|
node.append(flipNode)
|
1295
|
|
1296
|
properties_node = Element('PROPERTIES')
|
1297
|
for prop, value in self.properties.items():
|
1298
|
prop_node = prop.toXml()
|
1299
|
prop_node.text = str(value) if value else ''
|
1300
|
properties_node.append(prop_node)
|
1301
|
node.append(properties_node)
|
1302
|
|
1303
|
attributesNode = Element('SYMBOLATTRIBUTES')
|
1304
|
_attrs = self.getAttributes()
|
1305
|
for attr in _attrs:
|
1306
|
if type(attr) is SymbolAttr:
|
1307
|
_node = attr.toXml()
|
1308
|
if attr.AttributeType != 'Spec':
|
1309
|
_node.text = str(_attrs[attr])
|
1310
|
elif attr.AttributeType == 'Spec':
|
1311
|
_node.text = str(self.attrs[attr][0]) + ',' + str(self.attrs[attr][1])
|
1312
|
attributesNode.append(_node)
|
1313
|
|
1314
|
node.append(attributesNode)
|
1315
|
|
1316
|
currentPointModeIndexNode = Element('CURRENTPOINTMODEINDEX')
|
1317
|
currentPointModeIndexNode.text = str(self.currentPointModeIndex)
|
1318
|
node.append(currentPointModeIndexNode)
|
1319
|
except Exception as ex:
|
1320
|
from App import App
|
1321
|
message = 'error occurred({}) in {}:{}'.format(ex, sys.exc_info()[-1].tb_frame.f_code.co_filename,
|
1322
|
sys.exc_info()[-1].tb_lineno)
|
1323
|
App.mainWnd().addMessage.emit(MessageType.Error, message)
|
1324
|
|
1325
|
return None
|
1326
|
|
1327
|
return node
|
1328
|
|
1329
|
@staticmethod
|
1330
|
def from_database(component):
|
1331
|
""" create a item related to given component from database """
|
1332
|
import uuid
|
1333
|
from EngineeringSpecBreakItem import QEngineeringSpecBreakItem
|
1334
|
from EngineeringEndBreakItem import QEngineeringEndBreakItem
|
1335
|
from SymbolAttr import SymbolAttr
|
1336
|
item = None
|
1337
|
|
1338
|
try:
|
1339
|
app_doc_data = AppDocData.instance()
|
1340
|
|
1341
|
uid = component['UID']
|
1342
|
pt = [float(component['X']), float(component['Y'])]
|
1343
|
size = [float(component['Width']), float(component['Height'])]
|
1344
|
|
1345
|
dbUid = int(component['Symbol_UID'])
|
1346
|
dbData = app_doc_data.getSymbolByQuery('UID', dbUid)
|
1347
|
name = dbData.sName
|
1348
|
_type = dbData.sType
|
1349
|
angle = float(component['Rotation'])
|
1350
|
origin = [float(x) for x in component['SceneOriginPoint'].split(',')] if component['SceneOriginPoint'] is not None else pt
|
1351
|
connPts = []
|
1352
|
if component['ConnectionPoint']:
|
1353
|
if dbData:
|
1354
|
db_conn = dbData.connectionPoint.split('/')
|
1355
|
db_symbol_num = [conn.split(',')[3] for conn in db_conn]
|
1356
|
index = 0
|
1357
|
for conn_pt in component['ConnectionPoint'].split('/'):
|
1358
|
tokens = conn_pt.split(',')
|
1359
|
connPts.append(('AUTO', float(tokens[0]), float(tokens[1]), '0') if len(tokens) == 2 else
|
1360
|
(tokens[0], float(tokens[1]), float(tokens[2]), '0') if len(tokens) == 3 else
|
1361
|
(tokens[0], float(tokens[1]), float(tokens[2]), tokens[3] if dbData is None else db_symbol_num[index]))
|
1362
|
index += 1
|
1363
|
|
1364
|
baseSymbol = dbData.baseSymbol
|
1365
|
|
1366
|
childSymbolNode = component['AdditionalSymbol']
|
1367
|
childSymbol = childSymbolNode if childSymbolNode is not None else ''
|
1368
|
|
1369
|
owner = component['Owner'] if component['Owner'] is not None and component['Owner'] != 'None' else None
|
1370
|
|
1371
|
hasInstrumentLabel = dbData.hasInstrumentLabel
|
1372
|
|
1373
|
flipLabelNode = component['Flip']
|
1374
|
flipLabel = int(flipLabelNode) if flipLabelNode is not None else 0
|
1375
|
|
1376
|
project = app_doc_data.getCurrentProject()
|
1377
|
svgFilePath = os.path.join(project.getSvgFilePath(), _type, name + '.svg')
|
1378
|
if os.path.isfile(svgFilePath):
|
1379
|
item = SymbolSvgItem.createItem(_type, name, svgFilePath, uid, owner=owner, flip=flipLabel)
|
1380
|
item.setVisible(False)
|
1381
|
|
1382
|
|
1383
|
symbolInfo = None
|
1384
|
if dbUid is None:
|
1385
|
symbolInfo = app_doc_data.getSymbolByQuery('name', name)
|
1386
|
else:
|
1387
|
symbolInfo = app_doc_data.getSymbolByQuery('UID', dbUid)
|
1388
|
if symbolInfo:
|
1389
|
childSymbol = symbolInfo.additionalSymbol
|
1390
|
|
1391
|
if item.buildItem(name, _type, angle, pt, size, origin, connPts, baseSymbol, childSymbol,
|
1392
|
hasInstrumentLabel, dbUid=dbUid):
|
1393
|
pass
|
1394
|
else:
|
1395
|
return None
|
1396
|
|
1397
|
for key in item._properties.keys():
|
1398
|
for compo in component.keys():
|
1399
|
if key.Attribute == compo:
|
1400
|
item._properties[key] = key.parse_value(component[key.Attribute]) if component[
|
1401
|
key.Attribute] else ''
|
1402
|
|
1403
|
|
1404
|
areaNode = component['Area']
|
1405
|
if areaNode is None:
|
1406
|
for area in app_doc_data.getAreaList():
|
1407
|
if area.contains(pt):
|
1408
|
item.area = area.name
|
1409
|
break
|
1410
|
else:
|
1411
|
item.area = areaNode
|
1412
|
|
1413
|
|
1414
|
connectors = app_doc_data.get_component_connectors(uid)
|
1415
|
if connectors:
|
1416
|
iterIndex = 0
|
1417
|
for connector in connectors:
|
1418
|
item.connectors[iterIndex].parse_record(connector)
|
1419
|
iterIndex += 1
|
1420
|
|
1421
|
|
1422
|
associations = app_doc_data.get_component_associations(uid)
|
1423
|
if associations:
|
1424
|
for assoc in associations:
|
1425
|
_attrType = assoc['Type']
|
1426
|
if not _attrType in item._associations:
|
1427
|
item._associations[_attrType] = []
|
1428
|
item._associations[_attrType].append(
|
1429
|
uuid.UUID(assoc['Association']) if assoc['Association'] != 'None' else None)
|
1430
|
|
1431
|
|
1432
|
attributes = app_doc_data.get_component_attributes(uid)
|
1433
|
if attributes:
|
1434
|
for attr in attributes:
|
1435
|
_attr = SymbolAttr.from_record(attr)
|
1436
|
if type(item) is not QEngineeringSpecBreakItem and type(item) is not QEngineeringEndBreakItem:
|
1437
|
item.attrs[_attr] = attr['Value']
|
1438
|
else:
|
1439
|
if _attr.AttributeType == 'Spec':
|
1440
|
item.attrs[_attr] = [attr['Value'].split(',')[0], attr['Value'].split(',')[1]]
|
1441
|
else:
|
1442
|
item.attrs[_attr] = attr['Value']
|
1443
|
'''
|
1444
|
elif _attr.Attribute == 'UpStream':
|
1445
|
for initKey in item.attrs.keys():
|
1446
|
if initKey.Attribute == 'UpStream':
|
1447
|
item.attrs[initKey] = attr['Value']
|
1448
|
elif _attr.Attribute == 'DownStream':
|
1449
|
for initKey in item.attrs.keys():
|
1450
|
if initKey.Attribute == 'DownStream':
|
1451
|
item.attrs[initKey] = attr['Value']
|
1452
|
'''
|
1453
|
|
1454
|
currentPointModeIndex = component['OriginIndex']
|
1455
|
if currentPointModeIndex is not None:
|
1456
|
item.currentPointModeIndex = int(currentPointModeIndex)
|
1457
|
except Exception as ex:
|
1458
|
from App import App
|
1459
|
message = 'error occurred({}) in {}:{}'.format(ex, sys.exc_info()[-1].tb_frame.f_code.co_filename,
|
1460
|
sys.exc_info()[-1].tb_lineno)
|
1461
|
App.mainWnd().addMessage.emit(MessageType.Error, message)
|
1462
|
|
1463
|
return None
|
1464
|
|
1465
|
return item
|
1466
|
|
1467
|
'''
|
1468
|
@brief parse xml code
|
1469
|
@author humkyung
|
1470
|
@date 2018.07.20
|
1471
|
@history humkyung 2018.07.20 parse uid from xml node
|
1472
|
humkyung 2018.07.23 parse connected item's uid from xml node
|
1473
|
kyouho 2018.07.31
|
1474
|
humkyung 2018.09.06 assign area to item
|
1475
|
'''
|
1476
|
|
1477
|
@staticmethod
|
1478
|
def fromXml(node):
|
1479
|
import uuid
|
1480
|
from EngineeringSpecBreakItem import QEngineeringSpecBreakItem
|
1481
|
from EngineeringEndBreakItem import QEngineeringEndBreakItem
|
1482
|
from SymbolAttr import SymbolAttr
|
1483
|
item = None
|
1484
|
|
1485
|
try:
|
1486
|
appDocData = AppDocData.instance()
|
1487
|
|
1488
|
uidNode = node.find('UID')
|
1489
|
uid = uidNode.text if uidNode is not None else uuid.uuid4()
|
1490
|
|
1491
|
pt = [float(x) for x in node.find('LOCATION').text.split(',')]
|
1492
|
size = [float(x) for x in node.find('SIZE').text.split(',')]
|
1493
|
|
1494
|
dbUidNode = node.find('DBUID')
|
1495
|
dbUid = int(dbUidNode.text) if dbUidNode is not None else None
|
1496
|
dbData = None
|
1497
|
if dbUid:
|
1498
|
dbData = appDocData.getSymbolByQuery('UID', dbUid)
|
1499
|
name = node.find('NAME').text if dbData is None else dbData.sName
|
1500
|
|
1501
|
angle = float(node.find('ANGLE').text)
|
1502
|
_type = node.find('TYPE').text if dbData is None else dbData.sType
|
1503
|
origin = [float(x) for x in node.find('ORIGINALPOINT').text.split(',')]
|
1504
|
connPts = []
|
1505
|
if node.find('CONNECTIONPOINT').text is not None:
|
1506
|
if dbData:
|
1507
|
db_conn = dbData.connectionPoint.split('/')
|
1508
|
db_symbol_num = [conn.split(',')[3] for conn in db_conn]
|
1509
|
index = 0
|
1510
|
for conn_pt in node.find('CONNECTIONPOINT').text.split('/'):
|
1511
|
tokens = conn_pt.split(',')
|
1512
|
connPts.append(('AUTO', float(tokens[0]), float(tokens[1]), '0') if len(tokens) == 2 else
|
1513
|
(tokens[0], float(tokens[1]), float(tokens[2]), '0') if len(tokens) == 3 else
|
1514
|
(tokens[0], float(tokens[1]), float(tokens[2]), tokens[3] if dbData is None else db_symbol_num[index]))
|
1515
|
index += 1
|
1516
|
baseSymbol = node.find('PARENT').text if dbData is None else dbData.baseSymbol
|
1517
|
childSymbolNode = node.find('CHILD')
|
1518
|
childSymbol = ''
|
1519
|
if childSymbolNode is not None:
|
1520
|
childSymbol = childSymbolNode.text
|
1521
|
|
1522
|
ownerNode = node.find('OWNER')
|
1523
|
owner = ownerNode.text if ownerNode is not None and ownerNode.text != 'None' else None
|
1524
|
|
1525
|
hasInstrumentLabelNode = node.find('HASINSTRUMENTLABEL')
|
1526
|
hasInstrumentLabel = hasInstrumentLabelNode.text if dbData is None else dbData.hasInstrumentLabel
|
1527
|
|
1528
|
flipLabelNode = node.find('FLIP')
|
1529
|
flipLabel = int(flipLabelNode.text) if flipLabelNode is not None else 0
|
1530
|
|
1531
|
project = appDocData.getCurrentProject()
|
1532
|
svgFilePath = os.path.join(project.getSvgFilePath(), _type, name + '.svg')
|
1533
|
if os.path.isfile(svgFilePath):
|
1534
|
item = SymbolSvgItem.createItem(_type, name, svgFilePath, uid, owner=owner, flip=flipLabel)
|
1535
|
item.setVisible(False)
|
1536
|
|
1537
|
|
1538
|
symbolInfo = None
|
1539
|
if dbUid is None:
|
1540
|
symbolInfo = appDocData.getSymbolByQuery('name', name)
|
1541
|
else:
|
1542
|
symbolInfo = appDocData.getSymbolByQuery('UID', dbUid)
|
1543
|
if symbolInfo:
|
1544
|
childSymbol = symbolInfo.additionalSymbol
|
1545
|
|
1546
|
if item.buildItem(name, _type, angle, pt, size, origin, connPts, baseSymbol, childSymbol,
|
1547
|
hasInstrumentLabel, dbUid=dbUid):
|
1548
|
pass
|
1549
|
else:
|
1550
|
return None
|
1551
|
|
1552
|
for prop_node in node.iter('PROPERTY'):
|
1553
|
matches = [prop for prop in item._properties.keys() if
|
1554
|
prop.Attribute == prop_node.attrib['Attribute']]
|
1555
|
if matches:
|
1556
|
item._properties[matches[0]] = matches[0].parse_value(prop_node.text) if prop_node.text else ''
|
1557
|
|
1558
|
|
1559
|
areaNode = node.find('AREA')
|
1560
|
if areaNode is None:
|
1561
|
for area in appDocData.getAreaList():
|
1562
|
if area.contains(pt):
|
1563
|
item.area = area.name
|
1564
|
break
|
1565
|
else:
|
1566
|
item.area = areaNode.text
|
1567
|
|
1568
|
|
1569
|
connectors = node.find('CONNECTORS')
|
1570
|
if connectors is not None:
|
1571
|
iterIndex = 0
|
1572
|
for connector in connectors.iter('CONNECTOR'):
|
1573
|
item.connectors[iterIndex].parse_xml(connector)
|
1574
|
iterIndex += 1
|
1575
|
|
1576
|
|
1577
|
attributeValue = node.find('ASSOCIATIONS')
|
1578
|
if attributeValue is not None:
|
1579
|
for assoc in attributeValue.iter('ASSOCIATION'):
|
1580
|
_attrType = assoc.attrib['TYPE']
|
1581
|
if not _attrType in item._associations:
|
1582
|
item._associations[_attrType] = []
|
1583
|
item._associations[_attrType].append(uuid.UUID(assoc.text) if assoc.text != 'None' else None)
|
1584
|
|
1585
|
|
1586
|
attributes = node.find('SYMBOLATTRIBUTES')
|
1587
|
if attributes is not None:
|
1588
|
'''
|
1589
|
## for old spec break item that has not uid currectly, may not necessary new data
|
1590
|
if _type == 'Segment Breaks':
|
1591
|
specBreakAttrs = appDocData.getSymbolAttribute('Segment Breaks')
|
1592
|
## up to here 1
|
1593
|
'''
|
1594
|
for attr in attributes.iter('ATTRIBUTE'):
|
1595
|
_attr = SymbolAttr.fromXml(attr)
|
1596
|
if type(item) is not QEngineeringSpecBreakItem and type(item) is not QEngineeringEndBreakItem:
|
1597
|
item.attrs[_attr] = attr.text
|
1598
|
else:
|
1599
|
'''
|
1600
|
## for old spec break item that has not uid currectly, may not necessary new data
|
1601
|
matchAttr = [cAttr for cAttr in specBreakAttrs if _attr.Attribute == cAttr.Attribute]
|
1602
|
matchAttr = matchAttr[0] if matchAttr else None
|
1603
|
if matchAttr:
|
1604
|
_attr.UID = matchAttr.UID
|
1605
|
_attr.DisplayAttribute = matchAttr.DisplayAttribute
|
1606
|
_attr.AttributeType = matchAttr.AttributeType
|
1607
|
_attr.AttrAt = matchAttr.AttrAt
|
1608
|
_attr.Expression = matchAttr.Expression
|
1609
|
_attr.Length = matchAttr.Length
|
1610
|
# up to here 2
|
1611
|
'''
|
1612
|
if _attr.AttributeType == 'Spec':
|
1613
|
item.attrs[_attr] = [attr.text.split(',')[0], attr.text.split(',')[1]]
|
1614
|
else:
|
1615
|
'''
|
1616
|
# for old spec break item that has not uid currectly, may not necessary new data
|
1617
|
_attr.AssocItem = uuid.UUID(attr.text) if attr.text and attr.text != 'None' else None
|
1618
|
# up to here 3
|
1619
|
'''
|
1620
|
item.attrs[_attr] = attr.text
|
1621
|
'''
|
1622
|
elif _attr.Attribute == 'UpStream':
|
1623
|
for initKey in item.attrs.keys():
|
1624
|
if initKey.Attribute == 'UpStream':
|
1625
|
item.attrs[initKey] = attr.text
|
1626
|
elif _attr.Attribute == 'DownStream':
|
1627
|
for initKey in item.attrs.keys():
|
1628
|
if initKey.Attribute == 'DownStream':
|
1629
|
item.attrs[initKey] = attr.text
|
1630
|
'''
|
1631
|
|
1632
|
currentPointModeIndex = node.find('CURRENTPOINTMODEINDEX')
|
1633
|
if currentPointModeIndex is not None:
|
1634
|
item.currentPointModeIndex = int(currentPointModeIndex.text)
|
1635
|
except Exception as ex:
|
1636
|
from App import App
|
1637
|
message = 'error occurred({}) in {}:{}'.format(ex, sys.exc_info()[-1].tb_frame.f_code.co_filename,
|
1638
|
sys.exc_info()[-1].tb_lineno)
|
1639
|
App.mainWnd().addMessage.emit(MessageType.Error, message)
|
1640
|
|
1641
|
return None
|
1642
|
|
1643
|
return item
|
1644
|
|
1645
|
def to_svg(self, parent) -> list:
|
1646
|
"""convert symbol svg item to svg"""
|
1647
|
import re
|
1648
|
from xml.etree.ElementTree import Element, SubElement, dump, ElementTree
|
1649
|
from App import App
|
1650
|
|
1651
|
res = []
|
1652
|
try:
|
1653
|
app_doc_data = AppDocData.instance()
|
1654
|
prj = app_doc_data.getCurrentProject()
|
1655
|
|
1656
|
node = Element('g')
|
1657
|
node.attrib['id'] = str(self.uid)
|
1658
|
node.attrib['class'] = self._class
|
1659
|
|
1660
|
except_pattern = re.compile('[^a-zA-Z0-9-_]')
|
1661
|
for attr, value in self.getAttributes().items():
|
1662
|
node.attrib[re.sub(except_pattern, '_', attr.Attribute)] = str(value) if value else ''
|
1663
|
trans = self.sceneTransform()
|
1664
|
node.attrib['transform'] = f"matrix(" \
|
1665
|
f"{trans.m11()},{trans.m12()}," \
|
1666
|
f"{trans.m21()},{trans.m22()}," \
|
1667
|
f"{trans.m31()},{trans.m32()}" \
|
1668
|
f")"
|
1669
|
|
1670
|
node_list = self._document.elementsByTagName('path')
|
1671
|
for at in range(node_list.count()):
|
1672
|
path = Element('path')
|
1673
|
path.attrib['d'] = node_list.item(at).attributes().namedItem('d').nodeValue()
|
1674
|
path.attrib['transform'] = self._document.elementsByTagName('g').item(0).attributes().namedItem('transform').nodeValue()
|
1675
|
node.append(path)
|
1676
|
|
1677
|
for assoc in self.associations():
|
1678
|
assoc_node = assoc.to_svg(parent=self)
|
1679
|
node.extend(assoc_node)
|
1680
|
|
1681
|
res.append(node)
|
1682
|
except Exception as ex:
|
1683
|
from App import App
|
1684
|
message = 'error occurred({}) in {}:{}'.format(ex, sys.exc_info()[-1].tb_frame.f_code.co_filename,
|
1685
|
sys.exc_info()[-1].tb_lineno)
|
1686
|
App.mainWnd().addMessage.emit(MessageType.Error, message)
|
1687
|
|
1688
|
return res
|
1689
|
|
1690
|
'''
|
1691
|
@brief create item corresponding to given type
|
1692
|
@author humkyung
|
1693
|
@date 2018.05.02
|
1694
|
@history 2018.05.08 Jeongwoo Change type name (Piping OPC''S → Piping OPC's)
|
1695
|
humkyung 2018.05.10 change symbol's color to blue
|
1696
|
humkyung 2018.07.19 create nozzle instance if type is 'Nozzles'
|
1697
|
'''
|
1698
|
|
1699
|
@staticmethod
|
1700
|
def createItem(type, name, path, uid=None, owner=None, flip=0):
|
1701
|
from QEngineeringOPCItem import QEngineeringOPCItem
|
1702
|
from EngineeringEquipmentItem import QEngineeringEquipmentItem
|
1703
|
from EngineeringInstrumentItem import QEngineeringInstrumentItem
|
1704
|
from EngineeringNozzleItem import QEngineeringNozzleItem
|
1705
|
from EngineeringSpecBreakItem import QEngineeringSpecBreakItem
|
1706
|
from EngineeringReducerItem import QEngineeringReducerItem
|
1707
|
from EngineeringErrorItem import QEngineeringErrorItem
|
1708
|
from EngineeringEndBreakItem import QEngineeringEndBreakItem
|
1709
|
from EngineeringFlowMarkItem import QEngineeringFlowMarkItem
|
1710
|
from AppDocData import AppDocData
|
1711
|
import uuid
|
1712
|
|
1713
|
app_doc_data = AppDocData.instance()
|
1714
|
|
1715
|
item = None
|
1716
|
try:
|
1717
|
cateogry = app_doc_data.getSymbolCategoryByType(type)
|
1718
|
if type == "Piping OPC's":
|
1719
|
item = QEngineeringOPCItem(path, uid, flip=flip)
|
1720
|
elif type == 'Nozzles':
|
1721
|
item = QEngineeringNozzleItem(path, uid, flip=flip)
|
1722
|
elif cateogry == 'Equipment' or cateogry == 'Equipment Components':
|
1723
|
item = QEngineeringEquipmentItem(path, uid, flip=flip)
|
1724
|
elif cateogry == 'Instrumentation':
|
1725
|
item = QEngineeringInstrumentItem(path, uid, flip=flip)
|
1726
|
elif type == 'Segment Breaks':
|
1727
|
item = QEngineeringSpecBreakItem(path, uid, flip=flip)
|
1728
|
elif type == 'Reducers':
|
1729
|
item = QEngineeringReducerItem(path, uid, flip=flip)
|
1730
|
elif type == 'Error':
|
1731
|
item = QEngineeringErrorItem(path, uid, flip=flip)
|
1732
|
elif type == 'End Break':
|
1733
|
item = QEngineeringEndBreakItem(path, uid, flip=flip)
|
1734
|
|
1735
|
|
1736
|
else:
|
1737
|
item = SymbolSvgItem(name, path, uid, flip=flip)
|
1738
|
|
1739
|
if owner is not None:
|
1740
|
item.owner = uuid.UUID(owner)
|
1741
|
|
1742
|
except Exception as ex:
|
1743
|
from App import App
|
1744
|
from AppDocData import MessageType
|
1745
|
|
1746
|
message = 'error occurred({}) in {}:{}'.format(repr(ex), sys.exc_info()[-1].tb_frame.f_code.co_filename,
|
1747
|
sys.exc_info()[-1].tb_lineno)
|
1748
|
App.mainWnd().addMessage.emit(MessageType.Error, message)
|
1749
|
|
1750
|
return item
|
1751
|
|
1752
|
'''
|
1753
|
@brief change svg's color
|
1754
|
@author humkyung
|
1755
|
@date 2018.05.10
|
1756
|
@history 2018.05.11 Jeongwoo Override QEngineeringAbstractItem's
|
1757
|
humkyung 2018.05.13 update after change color
|
1758
|
'''
|
1759
|
|
1760
|
def setColor(self, color):
|
1761
|
if self._document:
|
1762
|
self.changeAttributes('fill', color)
|
1763
|
self.changeAttributes('stroke', color)
|
1764
|
self.renderer().load(self._document.toByteArray())
|
1765
|
self.update()
|
1766
|
|
1767
|
def getColor(self):
|
1768
|
""" return hover color if mouse is over otherwise reutrn owner's color if owner exist else this color """
|
1769
|
return SymbolSvgItem.HOVER_COLOR if self.hover else (
|
1770
|
self.owner._color if self.owner and hasattr(self.owner, '_color') else self._color)
|
1771
|
|
1772
|
'''
|
1773
|
@brief get attributes from svg file
|
1774
|
@author humkyung
|
1775
|
@date 2019.03.08
|
1776
|
'''
|
1777
|
|
1778
|
def get_attribute(self, attName):
|
1779
|
root = self._document.documentElement()
|
1780
|
node = root.firstChild()
|
1781
|
while not node.isNull():
|
1782
|
if node.isElement():
|
1783
|
element = node.toElement()
|
1784
|
if element.hasAttribute(attName):
|
1785
|
return element.attribute(attName)
|
1786
|
|
1787
|
if element.hasChildNodes():
|
1788
|
att_val = self.recursive_get_attribute(element.firstChild(), attName)
|
1789
|
if att_val is not None: return att_val
|
1790
|
|
1791
|
node = node.nextSibling()
|
1792
|
|
1793
|
return None
|
1794
|
|
1795
|
'''
|
1796
|
@brief get recursively attribute
|
1797
|
@author humkyung
|
1798
|
@date 2019.03.08
|
1799
|
'''
|
1800
|
|
1801
|
def recursive_get_attribute(self, node, attName):
|
1802
|
while not node.isNull():
|
1803
|
if node.isElement():
|
1804
|
element = node.toElement()
|
1805
|
if element.hasAttribute(attName):
|
1806
|
return element.attribute(attName)
|
1807
|
|
1808
|
if node.hasChildNodes():
|
1809
|
att_val = self.recursive_get_attribute(node.firstChild(), attName)
|
1810
|
if att_val is not None: return att_val
|
1811
|
|
1812
|
node = node.nextSibling()
|
1813
|
|
1814
|
return None
|
1815
|
|
1816
|
'''
|
1817
|
@brief change attributes
|
1818
|
@author humkyung
|
1819
|
@date 2018.05.10
|
1820
|
'''
|
1821
|
|
1822
|
def changeAttributes(self, attName, attValue):
|
1823
|
root = self._document.documentElement()
|
1824
|
node = root.firstChild()
|
1825
|
while not node.isNull():
|
1826
|
if node.isElement():
|
1827
|
element = node.toElement()
|
1828
|
if element.hasAttribute(attName):
|
1829
|
element.setAttribute(attName, attValue)
|
1830
|
|
1831
|
if element.hasChildNodes():
|
1832
|
recursiveChangeAttributes(element.firstChild(), attName, attValue)
|
1833
|
|
1834
|
node = node.nextSibling()
|
1835
|
|
1836
|
'''
|
1837
|
@brief change attribute
|
1838
|
@author humkyung
|
1839
|
@date 2018.05.10
|
1840
|
'''
|
1841
|
|
1842
|
def recursiveChangeAttributes(self, node, attName, attValue):
|
1843
|
while not node.isNull():
|
1844
|
if node.isElement():
|
1845
|
element = node.toElement()
|
1846
|
if element.hasAttribute(attName):
|
1847
|
element.setAttribute(attName, attValue)
|
1848
|
|
1849
|
if node.hasChildNodes():
|
1850
|
recursiveChangeAttributes(node.firstChild(), attName, attValue)
|
1851
|
|
1852
|
node = node.nextSibling()
|
1853
|
|
1854
|
'''
|
1855
|
@brief draw rect when item is selected
|
1856
|
@author humkyung
|
1857
|
@date 2018.07.07
|
1858
|
'''
|
1859
|
|
1860
|
def drawFocusRect(self, painter):
|
1861
|
self.focuspen = QPen(Qt.DotLine)
|
1862
|
self.focuspen.setColor(Qt.black)
|
1863
|
self.focuspen.setWidthF(1.5)
|
1864
|
hilightColor = QColor(255, 0, 0, 127)
|
1865
|
painter.setBrush(QBrush(hilightColor))
|
1866
|
painter.setPen(self.focuspen)
|
1867
|
painter.drawRect(self.boundingRect())
|
1868
|
|
1869
|
'''
|
1870
|
@brief override paint(draw connection points)
|
1871
|
@author humkyung
|
1872
|
@date 2018.04.21
|
1873
|
'''
|
1874
|
|
1875
|
def paint(self, painter, options=None, widget=None):
|
1876
|
from EngineeringAbstractItem import QEngineeringAbstractItem
|
1877
|
from EngineeringTextItem import QEngineeringTextItem
|
1878
|
|
1879
|
self.setColor(self.getColor())
|
1880
|
|
1881
|
painter.setClipRect(options.exposedRect)
|
1882
|
QGraphicsSvgItem.paint(self, painter, options, widget)
|
1883
|
'''
|
1884
|
# not used
|
1885
|
for attr in self.attrs:
|
1886
|
if issubclass(type(attr), QEngineeringTextItem):
|
1887
|
color = QEngineeringAbstractItem.HOVER_COLOR if self.hover else (
|
1888
|
self._owner._color if self._owner else QEngineeringAbstractItem.DEFAULT_COLOR)
|
1889
|
attr.setColor(color)
|
1890
|
elif issubclass(type(attr), SymbolSvgItem):
|
1891
|
attr.setColor(self.getColor())
|
1892
|
attr.update()
|
1893
|
'''
|
1894
|
|
1895
|
if self.isSelected():
|
1896
|
self.drawFocusRect(painter)
|
1897
|
|
1898
|
'''
|
1899
|
@brief Add Svg Item into ImageViewer's Scene
|
1900
|
@author Jeongwoo
|
1901
|
@date 2018.05.03
|
1902
|
@history add connectors which's parent is symbol
|
1903
|
kyouho 2018.07.30 remove connectors logic
|
1904
|
'''
|
1905
|
|
1906
|
def addSvgItemToScene(self, scene):
|
1907
|
self.rotate(self.getCurrentPoint(), self.angle)
|
1908
|
scene.addItem(self)
|
1909
|
self.size[0], self.size[1] = round(self.sceneBoundingRect().width()), round(self.sceneBoundingRect().height())
|
1910
|
trans = self.transform()
|
1911
|
|
1912
|
'''
|
1913
|
@brief
|
1914
|
@author humkyung
|
1915
|
@date 2018.07.27
|
1916
|
'''
|
1917
|
|
1918
|
def onConnectorPosChaned(self, connector):
|
1919
|
pass
|
1920
|
|
1921
|
'''
|
1922
|
@brief set connector
|
1923
|
@author kyouho
|
1924
|
@date 2018.07.26
|
1925
|
'''
|
1926
|
|
1927
|
def setConnector(self, index):
|
1928
|
connector = QEngineeringConnectorItem(parent=self, index=index)
|
1929
|
connector.setParentItem(self)
|
1930
|
self.connectors.append(connector)
|
1931
|
|
1932
|
'''
|
1933
|
'''
|
1934
|
|
1935
|
def refreshConnector(self):
|
1936
|
for connector in self.connectors:
|
1937
|
connector.buildItem()
|
1938
|
|
1939
|
'''
|
1940
|
@brief Delete svg item
|
1941
|
@author Jeongwoo
|
1942
|
@date 2018.05.25
|
1943
|
'''
|
1944
|
|
1945
|
def deleteSvgItemFromScene(self):
|
1946
|
''' not used '''
|
1947
|
for connector in self.connectors:
|
1948
|
if connector.connectedItem is not None:
|
1949
|
try:
|
1950
|
connector.connectedItem.removeSymbol(self)
|
1951
|
except Exception as ex:
|
1952
|
from App import App
|
1953
|
from AppDocData import MessageType
|
1954
|
|
1955
|
message = 'error occurred({}) in {}:{}'.format(ex, sys.exc_info()[-1].tb_frame.f_code.co_filename,
|
1956
|
sys.exc_info()[-1].tb_lineno)
|
1957
|
App.mainWnd().addMessage.emit(MessageType.Error, message)
|
1958
|
break
|
1959
|
|
1960
|
self.transfer.onRemoved.emit(self)
|
1961
|
|
1962
|
'''
|
1963
|
@brief Return real item position
|
1964
|
@author Jeongwoo
|
1965
|
@date 2018.05.25
|
1966
|
'''
|
1967
|
|
1968
|
def boundingRectOnScene(self):
|
1969
|
rect = self.boundingRect()
|
1970
|
rect.moveTo(self.loc[0], self.loc[1])
|
1971
|
return rect
|
1972
|
|
1973
|
def flipSymbol(self):
|
1974
|
'''
|
1975
|
@brief remove item when user press delete key
|
1976
|
@author humkyung
|
1977
|
@date 2018.04.23
|
1978
|
'''
|
1979
|
if self.flip is 0:
|
1980
|
self.flip = 1
|
1981
|
else:
|
1982
|
self.flip = 0
|
1983
|
|
1984
|
currentPoint = self.getCurrentPoint()
|
1985
|
self.rotate(currentPoint, self.angle)
|
1986
|
|
1987
|
'''
|
1988
|
@brief rotate Symbol
|
1989
|
@author kyouho
|
1990
|
@date 2018.07.24
|
1991
|
'''
|
1992
|
|
1993
|
def rotateSymbol(self, angle=None):
|
1994
|
if angle is None:
|
1995
|
|
1996
|
if 0 == self.angle:
|
1997
|
self.angle = 1.57
|
1998
|
|
1999
|
elif (1.57 == self.angle):
|
2000
|
self.angle = 3.14
|
2001
|
|
2002
|
elif 3.14 == self.angle:
|
2003
|
self.angle = 4.71
|
2004
|
|
2005
|
elif 4.71 == self.angle:
|
2006
|
self.angle = 0
|
2007
|
else:
|
2008
|
self.angle = 0
|
2009
|
else:
|
2010
|
self.angle = angle
|
2011
|
|
2012
|
currentPoint = self.getCurrentPoint()
|
2013
|
self.rotate(currentPoint, self.angle)
|
2014
|
|
2015
|
def get_transform(self, pt, angle):
|
2016
|
""" return a transform """
|
2017
|
transform = QTransform()
|
2018
|
transform.translate(self.loc[0] + self.symbolOrigin[0], self.loc[1] + self.symbolOrigin[1])
|
2019
|
transform.rotateRadians(-angle)
|
2020
|
transform.translate(-pt[0], -pt[1])
|
2021
|
|
2022
|
if self.flip is 1:
|
2023
|
transform.scale(-1.0, 1.0)
|
2024
|
transform.translate(-2 * self.symbolOrigin[0], 0)
|
2025
|
|
2026
|
return transform
|
2027
|
|
2028
|
'''
|
2029
|
@brief resetting rotate Symbol
|
2030
|
@author kyouho
|
2031
|
@date 2018.07.24
|
2032
|
'''
|
2033
|
|
2034
|
def rotate(self, standardPoint, angle):
|
2035
|
self.setTransform(self.get_transform(standardPoint, angle))
|
2036
|
self.setRotation(0)
|
2037
|
|
2038
|
'''
|
2039
|
@brief change Conn point
|
2040
|
@author kyouho
|
2041
|
@date 2018.07.25
|
2042
|
'''
|
2043
|
|
2044
|
def changeConnPoint(self):
|
2045
|
if len(self.connectors) == 2:
|
2046
|
conn1Item = self.connectors[0].connectedItem
|
2047
|
conn2Item = self.connectors[1].connectedItem
|
2048
|
self.connectors[0].connectedItem = conn2Item
|
2049
|
self.connectors[1].connectedItem = conn1Item
|
2050
|
|
2051
|
currentPoint = self.getCurrentPoint()
|
2052
|
|
2053
|
|
2054
|
'''
|
2055
|
@brief change standard point
|
2056
|
@author kyouho
|
2057
|
@date 2018.07.24
|
2058
|
'''
|
2059
|
|
2060
|
def changeStandardPoint(self):
|
2061
|
connPtsCount = len(self.connectors)
|
2062
|
|
2063
|
if self.currentPointModeIndex < connPtsCount:
|
2064
|
self.currentPointModeIndex += 1
|
2065
|
else:
|
2066
|
self.currentPointModeIndex = 0
|
2067
|
|
2068
|
currentPoint = self.getCurrentPoint()
|
2069
|
|
2070
|
|
2071
|
'''
|
2072
|
@brief get standard point
|
2073
|
@author kyouho
|
2074
|
@date 2018.07.25
|
2075
|
'''
|
2076
|
|
2077
|
def getCurrentPoint(self):
|
2078
|
pointList = []
|
2079
|
pointList.append(self.symbolOrigin)
|
2080
|
for connector in self.connectors:
|
2081
|
pointList.append(connector.connectPoint)
|
2082
|
|
2083
|
return pointList[self.currentPointModeIndex]
|
2084
|
|
2085
|
'''
|
2086
|
@brief 심볼 회전 시 서로 다른 기준점으로 회전하기 때문에 기준점을 이후 개발한 SymbolSvgItem 기준의 회전좌표로 이동하기 위해서 만듬 (loc 기준으로 회전해야함)
|
2087
|
@author kyouho
|
2088
|
@date 18.08.06
|
2089
|
'''
|
2090
|
|
2091
|
def reCalculationRotatedItem(self):
|
2092
|
goPoint = self.get_transform(self.getCurrentPoint(), self.angle).map(
|
2093
|
QPoint(self.symbolOrigin[0], self.symbolOrigin[1]))
|
2094
|
self.loc = [self.loc[0] + self.origin[0] - goPoint.x(), self.loc[1] + self.origin[1] - goPoint.y()]
|
2095
|
|
2096
|
|
2097
|
def recursiveChangeAttributes(node, attName, attValue):
|
2098
|
while not node.isNull():
|
2099
|
if node.isElement():
|
2100
|
element = node.toElement()
|
2101
|
if element.hasAttribute(attName):
|
2102
|
element.setAttribute(attName, attValue)
|
2103
|
|
2104
|
if node.hasChildNodes():
|
2105
|
recursiveChangeAttributes(node.firstChild(), attName, attValue)
|
2106
|
|
2107
|
node = node.nextSibling()
|
2108
|
|
2109
|
|
2110
|
'''
|
2111
|
@brief The class transfer pyqtSignal Event. Cause Subclass of QGraphicsRectItem can't use pyqtSignal
|
2112
|
@author Jeongwoo
|
2113
|
@date 2018.06.18
|
2114
|
'''
|
2115
|
|
2116
|
|
2117
|
class Transfer(QObject):
|
2118
|
on_pos_changed = pyqtSignal(QGraphicsItem)
|
2119
|
onRemoved = pyqtSignal(QGraphicsItem)
|
2120
|
|
2121
|
def __init__(self, parent=None):
|
2122
|
QObject.__init__(self, parent)
|
2123
|
|
2124
|
|
2125
|
if __name__ == '__main__':
|
2126
|
f = QFile('d:/Projects/DTIPID/DTI_PID/DTI_PID/SG_TEST/svg/ANGLE VALVE.svg')
|
2127
|
f.open(QIODevice.ReadOnly)
|
2128
|
array = f.readAll()
|
2129
|
document = QDomDocument()
|
2130
|
document.setContent(array)
|
2131
|
|
2132
|
root = document.documentElement()
|
2133
|
node = root.firstChild()
|
2134
|
while not node.isNull():
|
2135
|
if node.isElement():
|
2136
|
element = node.toElement()
|
2137
|
if element.hasAttribute('fill'):
|
2138
|
element.setAttribute('fill', '#FFFFF')
|
2139
|
|
2140
|
if element.hasChildNodes():
|
2141
|
recursiveChangeAttributes(element.firstChild(), 'fill', '#FFFFF')
|
2142
|
|
2143
|
node = node.nextSibling()
|