hytos / DTI_PID / DTI_PID / SymbolTreeWidget.py @ 8701ed58
이력 | 보기 | 이력해설 | 다운로드 (15.2 KB)
1 |
# coding: utf-8
|
---|---|
2 |
""" This is Symbol Tree Widget module """
|
3 |
|
4 |
try:
|
5 |
from PyQt5.QtCore import * |
6 |
from PyQt5.QtGui import * |
7 |
from PyQt5.QtWidgets import * |
8 |
except ImportError: |
9 |
try:
|
10 |
from PyQt4.QtCore import * |
11 |
from PyQt4.QtGui import * |
12 |
except ImportError: |
13 |
raise ImportError("ImageViewerQt: Requires PyQt5 or PyQt4.") |
14 |
from AppDocData import * |
15 |
import os |
16 |
import sys |
17 |
import SymbolBase |
18 |
import symbol |
19 |
import SymbolEditorDialog |
20 |
import QSymbolDisplayDialog |
21 |
|
22 |
|
23 |
class QSymbolTreeWidget(QTreeWidget): |
24 |
# Add signal
|
25 |
singleClicked = pyqtSignal(SymbolBase.SymbolBase) |
26 |
TREE_DATA_ROLE = Qt.UserRole |
27 |
|
28 |
def __init__(self): |
29 |
QTreeWidget.__init__(self)
|
30 |
self.setIconSize(QSize(32, 32)) |
31 |
|
32 |
self.setDragEnabled(True) # enable drag |
33 |
self.initDirTreeWidget()
|
34 |
self.isDoubleClicked = False |
35 |
self.itemDoubleClicked.connect(self.itemDoubleClickEvent) |
36 |
self.setContextMenuPolicy(Qt.CustomContextMenu)
|
37 |
self.customContextMenuRequested.connect(self.openContextMenu) |
38 |
self.currentItemChanged.connect(self.onCurrentItemChanged) |
39 |
|
40 |
'''
|
41 |
@brief Show Context Menu
|
42 |
@author Jeongwoo
|
43 |
@date 18.04.??
|
44 |
@history Jeongwoo 2018.04.23 Symbol object Null Check when show context menu
|
45 |
humkyung 2018.08.14 add menu for symbol type
|
46 |
'''
|
47 |
|
48 |
def openContextMenu(self, position): |
49 |
indexes = self.selectedIndexes()
|
50 |
itemPosition = self.mapTo(self, position) |
51 |
item = self.itemAt(itemPosition)
|
52 |
data = item.data(0, self.TREE_DATA_ROLE) |
53 |
|
54 |
advanced = False
|
55 |
app_doc_data = AppDocData.instance() |
56 |
configs = app_doc_data.getAppConfigs('app', 'mode') |
57 |
if configs and 1 == len(configs) and 'advanced' == configs[0].value: |
58 |
advanced = True
|
59 |
|
60 |
if data is not None and type(data) is symbol.SymbolBase: |
61 |
sym = self.getSymbolByItemName(item, 0) |
62 |
text = item.text(0)
|
63 |
if len(indexes) > 0: |
64 |
level = 0
|
65 |
index = indexes[0]
|
66 |
while index.parent().isValid():
|
67 |
index = index.parent() |
68 |
level += 1
|
69 |
if sym is not None: |
70 |
menu = QMenu() |
71 |
if advanced:
|
72 |
editSymbolAction = QAction(self.tr("Edit Symbol")) |
73 |
editSymbolAction.triggered.connect(lambda: self.editSymbolActionClickEvent(item, 0)) |
74 |
menu.addAction(editSymbolAction) |
75 |
editDisplaySymbolAction = QAction(self.tr("Edit Symbol for Dispay")) |
76 |
editDisplaySymbolAction.triggered.connect(lambda: self.editDisplaySymbolActionClickEvent(item, 0)) |
77 |
menu.addAction(editDisplaySymbolAction) |
78 |
displaySymbolAction = QAction(self.tr("Display Symbol")) |
79 |
displaySymbolAction.triggered.connect(lambda: self.displaySymbolActionClickEvent(item, 0)) |
80 |
menu.addAction(displaySymbolAction) |
81 |
if advanced:
|
82 |
deleteSymbolAction = QAction(self.tr("Delete Symbol")) |
83 |
deleteSymbolAction.triggered.connect(lambda: self.deleteSymbolActionClickEvent(sym.getType(), text)) |
84 |
menu.addAction(deleteSymbolAction) |
85 |
menu.exec_(self.viewport().mapToGlobal(position))
|
86 |
else:
|
87 |
if advanced:
|
88 |
menu = QMenu() |
89 |
editAttrAction = QAction(self.tr("Edit Attribute")) |
90 |
editAttrAction.triggered.connect(lambda: self.onEditAttrClicked(item, 0)) |
91 |
menu.addAction(editAttrAction) |
92 |
menu.exec_(self.viewport().mapToGlobal(position))
|
93 |
|
94 |
def editSymbolActionClickEvent(self, item, columNo): |
95 |
self.showSymbolEditorDialog(item, columNo)
|
96 |
|
97 |
def editDisplaySymbolActionClickEvent(self, item, columNo): |
98 |
self.showSymbolEditorDialog(item, columNo, True) |
99 |
|
100 |
'''
|
101 |
@brief popup attribute editor dialog
|
102 |
@author humkyung
|
103 |
@date 2018.08.13
|
104 |
'''
|
105 |
|
106 |
def onEditAttrClicked(self, item, columnNo): |
107 |
from SymbolAttrEditorDialog import QSymbolAttrEditorDialog |
108 |
|
109 |
try:
|
110 |
data = item.data(0, self.TREE_DATA_ROLE) |
111 |
|
112 |
dlg = QSymbolAttrEditorDialog(self, data)
|
113 |
dlg.show() |
114 |
dlg.exec_() |
115 |
except Exception as ex: |
116 |
from App import App |
117 |
|
118 |
message = 'error occurred({}) in {}:{}'.format(ex, sys.exc_info()[-1].tb_frame.f_code.co_filename, |
119 |
sys.exc_info()[-1].tb_lineno)
|
120 |
App.mainWnd().addMessage.emit(MessageType.Error, message) |
121 |
|
122 |
def displaySymbolActionClickEvent(self, item, columnNo): |
123 |
# project = AppDocData.instance().getCurrentProject()
|
124 |
# image = QImage(os.path.join(project.getImageFilePath(), itemType, itemName, "PNG")) #itemName includes ".png"
|
125 |
try:
|
126 |
sym = self.getSymbolByItemName(item, columnNo)
|
127 |
if sym is not None: |
128 |
# origin symbol image
|
129 |
path = sym.getPath() |
130 |
image = QImage(path, "PNG")
|
131 |
# symbol image for display
|
132 |
path = os.path.splitext(path) |
133 |
path = path[0] + '_display' + path[1] |
134 |
image2 = QImage(path, "PNG") if os.path.exists(path) else None |
135 |
dialog = QSymbolDisplayDialog.QSymbolDisplayDialog(image, image2) |
136 |
dialog.showDialog() |
137 |
else:
|
138 |
QMessageBox.about(self, self.tr('Error'), self.tr('Error occurs during loading symbol data.')) |
139 |
except Exception as ex: |
140 |
from App import App |
141 |
from AppDocData import MessageType |
142 |
|
143 |
message = 'error occurred({}) in {}:{}'.format(ex, sys.exc_info()[-1].tb_frame.f_code.co_filename, |
144 |
sys.exc_info()[-1].tb_lineno)
|
145 |
App.mainWnd().addMessage.emit(MessageType.Error, message) |
146 |
|
147 |
def deleteSymbolActionClickEvent(self, itemType, itemName): |
148 |
msg = QMessageBox() |
149 |
msg.setIcon(QMessageBox.Critical) |
150 |
msg.setText(self.tr('Are you sure you want to delete selected symbol?\nData can not be restored!')) |
151 |
msg.setWindowTitle(self.tr('Delete symbol')) |
152 |
msg.setStandardButtons(QMessageBox.Ok | QMessageBox.Cancel) |
153 |
result = msg.exec_() |
154 |
self.handleDeleteSymbolAction(result, itemType, itemName)
|
155 |
|
156 |
'''
|
157 |
@history 2018.05.03 Jeongwoo Modify file path with ".png" and ".svg"
|
158 |
Use project object when making svgPath
|
159 |
'''
|
160 |
|
161 |
def handleDeleteSymbolAction(self, result, itemType, itemName): |
162 |
if result == QMessageBox.Ok:
|
163 |
project = AppDocData.instance().getCurrentProject() |
164 |
imagePath = os.path.join(project.getImageFilePath(), itemType, |
165 |
itemName + '.png') # itemName DOESN'T includes ".png" |
166 |
if os.path.exists(imagePath):
|
167 |
os.remove(imagePath) |
168 |
|
169 |
svgPath = os.path.join(project.getSvgFilePath(), itemType, itemName + '.svg')
|
170 |
if os.path.exists(svgPath):
|
171 |
os.remove(svgPath) |
172 |
|
173 |
AppDocData.instance().deleteSymbol(itemName) |
174 |
self.initDirTreeWidget()
|
175 |
else:
|
176 |
pass
|
177 |
|
178 |
'''
|
179 |
@history 2018.05.02 Jeongwoo Change return value of QSymbolEditorDialog (Single variable → Tuple)
|
180 |
'''
|
181 |
|
182 |
def initDirTreeWidget(self): |
183 |
project = AppDocData.instance().getCurrentProject() |
184 |
if project is not None: |
185 |
self.clear()
|
186 |
projectPath = project.getPath().replace("\\", "/") |
187 |
self.makeChildDir()
|
188 |
self.load_symbol_info()
|
189 |
self.expandAll()
|
190 |
|
191 |
'''
|
192 |
@brief Load Symbol Info and add TreeItem with DB
|
193 |
@author Jeongwoo
|
194 |
@date 18.04.20
|
195 |
@history Jeongwoo 2018.05.03 Get Svg File Path by SymbolBase.getSvgFileFullPath()
|
196 |
humkyung 2018.07.30 sort child items
|
197 |
'''
|
198 |
|
199 |
def load_symbol_info(self): |
200 |
try:
|
201 |
app_doc_data = AppDocData.instance() |
202 |
|
203 |
symbolTypeList = AppDocData.instance().getSymbolTypeList() |
204 |
for symbolType in symbolTypeList: |
205 |
if not symbolType[1]: continue # skip if category is empty |
206 |
parent = QTreeWidgetItem(self, [symbolType[2]]) |
207 |
parent.setData(0, self.TREE_DATA_ROLE, symbolType) |
208 |
symbolList = AppDocData.instance().getSymbolListByType('UID', symbolType[0]) |
209 |
for symbol in symbolList: |
210 |
symbolItem = QTreeWidgetItem(parent, [symbol.getName()]) |
211 |
symbolItem.setData(0, self.TREE_DATA_ROLE, symbol) |
212 |
|
213 |
_, svg = app_doc_data.read_symbol_shape(symbol.sName) |
214 |
if svg:
|
215 |
pixmap = QPixmap(QSize(32, 32)) |
216 |
pixmap.loadFromData(svg if isinstance(svg, bytes) else svg.encode()) |
217 |
icon = QIcon(pixmap) |
218 |
symbolItem.setIcon(0, icon)
|
219 |
symbolItem.svgFilePath = None # save svg file path |
220 |
else:
|
221 |
svgPath = symbol.getSvgFileFullPath() |
222 |
icon = QIcon(svgPath) |
223 |
symbolItem.setIcon(0, icon)
|
224 |
symbolItem.svgFilePath = svgPath # save svg file path
|
225 |
|
226 |
parent.sortChildren(0, Qt.AscendingOrder)
|
227 |
except Exception as ex: |
228 |
from App import App |
229 |
|
230 |
message = 'error occurred({}) in {}:{}'.format(repr(ex), sys.exc_info()[-1].tb_frame.f_code.co_filename, |
231 |
sys.exc_info()[-1].tb_lineno)
|
232 |
App.mainWnd().addMessage.emit(MessageType.Error, message) |
233 |
|
234 |
'''
|
235 |
@brief Make Directory
|
236 |
@author Jeongwoo
|
237 |
@date 18.04.??
|
238 |
@history 18.04.12 Jeongwoo Add output, temp Directory
|
239 |
'''
|
240 |
|
241 |
def makeChildDir(self): |
242 |
project = AppDocData.instance().getCurrentProject() |
243 |
dbDir = project.getDbFilePath() |
244 |
if not os.path.exists(dbDir): |
245 |
os.makedirs(dbDir) |
246 |
imgDir = project.getImageFilePath() |
247 |
if not os.path.exists(imgDir): |
248 |
os.makedirs(imgDir) |
249 |
svgDir = project.getSvgFilePath() |
250 |
if not os.path.exists(svgDir): |
251 |
os.makedirs(svgDir) |
252 |
outputDir = project.getOutputPath() |
253 |
if not os.path.exists(outputDir): |
254 |
os.makedirs(outputDir) |
255 |
tempDir = project.getTempPath() |
256 |
if not os.path.exists(tempDir): |
257 |
os.makedirs(tempDir) |
258 |
|
259 |
def showSymbolEditorDialog(self, item, columnNo, display=False): |
260 |
try:
|
261 |
sym = self.getSymbolByItemName(item, columnNo)
|
262 |
if sym and display: |
263 |
# for symbol image for display
|
264 |
path = os.path.splitext(sym.getPath()) |
265 |
path = path[0] + '_display' + path[1] |
266 |
if os.path.exists(path):
|
267 |
image = QImage(path, "PNG")
|
268 |
else:
|
269 |
path = sym.getPath() |
270 |
image = QImage(path, "PNG")
|
271 |
symbolEditorDialog = SymbolEditorDialog.QSymbolEditorDialog(self, image,
|
272 |
AppDocData.instance().getCurrentProject(), |
273 |
sym, True)
|
274 |
(isAccepted, isImmediateInsert, offsetX, offsetY, newSym) = symbolEditorDialog.showDialog() |
275 |
self.initDirTreeWidget()
|
276 |
elif sym:
|
277 |
# for symbol data and detection image
|
278 |
path = sym.getPath() |
279 |
image = QImage(path, "PNG")
|
280 |
symbolEditorDialog = SymbolEditorDialog.QSymbolEditorDialog(self, image,
|
281 |
AppDocData.instance().getCurrentProject(), |
282 |
sym, False)
|
283 |
(isAccepted, isImmediateInsert, offsetX, offsetY, newSym) = symbolEditorDialog.showDialog() |
284 |
self.initDirTreeWidget()
|
285 |
else:
|
286 |
QMessageBox.about(self, self.tr('Error'), self.tr('Error occurs during loading symbol data.')) |
287 |
except Exception as ex: |
288 |
from App import App |
289 |
from AppDocData import MessageType |
290 |
|
291 |
message = 'error occurred({}) in {}:{}'.format(ex, sys.exc_info()[-1].tb_frame.f_code.co_filename, |
292 |
sys.exc_info()[-1].tb_lineno)
|
293 |
App.mainWnd().addMessage.emit(MessageType.Error, message) |
294 |
|
295 |
def itemDoubleClickEvent(self, item, columnNo): |
296 |
self.isDoubleClicked = True |
297 |
sym = self.getSymbolByItemName(item, columnNo)
|
298 |
itemName = item.text(columnNo) |
299 |
if sym is not None: |
300 |
self.showSymbolEditorDialog(item, columnNo)
|
301 |
self.isDoubleClicked = False |
302 |
|
303 |
'''
|
304 |
@brief Get Symbol data by symbol name
|
305 |
@author Jeongwoo
|
306 |
@date 18.04.20
|
307 |
'''
|
308 |
|
309 |
def getSymbolByItemName(self, item, columnNo): |
310 |
itemName = item.text(columnNo) |
311 |
|
312 |
name = itemName |
313 |
sym = AppDocData.instance().getSymbolByQuery("name", name)
|
314 |
return sym
|
315 |
|
316 |
'''
|
317 |
@breif show symbol's property when selection changed
|
318 |
@author humkyung
|
319 |
@date 2018.07.30
|
320 |
'''
|
321 |
|
322 |
def onCurrentItemChanged(self, current, previous): |
323 |
item = self.currentItem()
|
324 |
if item is not None: |
325 |
data = item.data(0, self.TREE_DATA_ROLE) |
326 |
if data is not None and type(data) is symbol.SymbolBase: |
327 |
self.singleClicked.emit(data)
|
328 |
|
329 |
'''
|
330 |
@brief start drag
|
331 |
@author humkyung
|
332 |
@date 2018.04.17
|
333 |
@history 18.04.20 Jeongwoo Change Path in QPixmap
|
334 |
18.06.21 Jeongwoo Casting string to float and int
|
335 |
'''
|
336 |
|
337 |
def startDrag(self, dropAction): |
338 |
try:
|
339 |
items = self.selectedItems()
|
340 |
if items and hasattr(items[0], 'svgFilePath'): |
341 |
symData = items[0].data(0, self.TREE_DATA_ROLE) |
342 |
if items[0].svgFilePath: |
343 |
pixmap = QPixmap(items[0].svgFilePath)
|
344 |
else:
|
345 |
app_doc_data = AppDocData.instance() |
346 |
_, svg = app_doc_data.read_symbol_shape(symData.getName()) |
347 |
if svg:
|
348 |
pixmap = QPixmap() |
349 |
pixmap.loadFromData(svg if isinstance(svg, bytes) else svg.encode()) |
350 |
|
351 |
mime = QMimeData() |
352 |
mime.setText(symData.getName()) |
353 |
|
354 |
drag = QDrag(self)
|
355 |
drag.setMimeData(mime) |
356 |
originalPoint = symData.getOriginalPoint() |
357 |
drag.setHotSpot( |
358 |
QPoint(int(float(originalPoint.split(",")[0])), int(float(originalPoint.split(",")[1])))) |
359 |
drag.setPixmap(pixmap) |
360 |
drag.exec(Qt.CopyAction) |
361 |
except Exception as ex: |
362 |
from App import App |
363 |
|
364 |
message = 'error occurred({}) in {}:{}'.format(ex, sys.exc_info()[-1].tb_frame.f_code.co_filename, |
365 |
sys.exc_info()[-1].tb_lineno)
|
366 |
App.mainWnd().addMessage.emit(MessageType.Error, message) |