hytos / DTI_PID / DTI_PID / SymbolTreeWidget.py @ db2dcb47
이력 | 보기 | 이력해설 | 다운로드 (14.9 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 Display")) |
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 = app_doc_data.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 = app_doc_data.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 |
symbol.pixmap = QPixmap() |
216 |
symbol.pixmap.loadFromData(svg if isinstance(svg, bytes) else svg.encode()) |
217 |
icon = QIcon(symbol.pixmap) |
218 |
symbolItem.setIcon(0, icon)
|
219 |
symbolItem.svgFilePath = None # save svg file path |
220 |
else:
|
221 |
svgPath = symbol.getSvgFileFullPath() |
222 |
symbol.pixmap = QPixmap(svgPath) |
223 |
icon = QIcon(symbol.pixmap) |
224 |
symbolItem.setIcon(0, icon)
|
225 |
symbolItem.svgFilePath = svgPath # save svg file path
|
226 |
|
227 |
parent.sortChildren(0, Qt.AscendingOrder)
|
228 |
except Exception as ex: |
229 |
from App import App |
230 |
|
231 |
message = 'error occurred({}) in {}:{}'.format(repr(ex), sys.exc_info()[-1].tb_frame.f_code.co_filename, |
232 |
sys.exc_info()[-1].tb_lineno)
|
233 |
App.mainWnd().addMessage.emit(MessageType.Error, message) |
234 |
|
235 |
'''
|
236 |
@brief Make Directory
|
237 |
@author Jeongwoo
|
238 |
@date 18.04.??
|
239 |
@history 18.04.12 Jeongwoo Add output, temp Directory
|
240 |
'''
|
241 |
|
242 |
def makeChildDir(self): |
243 |
project = AppDocData.instance().getCurrentProject() |
244 |
dbDir = project.getDbFilePath() |
245 |
if not os.path.exists(dbDir): |
246 |
os.makedirs(dbDir) |
247 |
imgDir = project.getImageFilePath() |
248 |
if not os.path.exists(imgDir): |
249 |
os.makedirs(imgDir) |
250 |
svgDir = project.getSvgFilePath() |
251 |
if not os.path.exists(svgDir): |
252 |
os.makedirs(svgDir) |
253 |
outputDir = project.getOutputPath() |
254 |
if not os.path.exists(outputDir): |
255 |
os.makedirs(outputDir) |
256 |
tempDir = project.getTempPath() |
257 |
if not os.path.exists(tempDir): |
258 |
os.makedirs(tempDir) |
259 |
|
260 |
def showSymbolEditorDialog(self, item, columnNo, display=False): |
261 |
"""pop up symbol editor dialog"""
|
262 |
|
263 |
try:
|
264 |
sym = self.getSymbolByItemName(item, columnNo)
|
265 |
if sym and display: |
266 |
# for symbol image for display
|
267 |
path = os.path.splitext(sym.getPath()) |
268 |
path = path[0] + '_display' + path[1] |
269 |
if os.path.exists(path):
|
270 |
image = QImage(path, "PNG")
|
271 |
else:
|
272 |
path = sym.getPath() |
273 |
image = QImage(path, "PNG")
|
274 |
symbolEditorDialog = SymbolEditorDialog.QSymbolEditorDialog(self, image,
|
275 |
AppDocData.instance().getCurrentProject(), |
276 |
sym, True)
|
277 |
(isAccepted, isImmediateInsert, offsetX, offsetY, newSym) = symbolEditorDialog.showDialog() |
278 |
self.initDirTreeWidget()
|
279 |
elif sym:
|
280 |
# for symbol data and detection image
|
281 |
path = sym.getPath() |
282 |
image = QImage(path, "PNG")
|
283 |
symbolEditorDialog = SymbolEditorDialog.QSymbolEditorDialog(self, image,
|
284 |
AppDocData.instance().getCurrentProject(), |
285 |
sym, False)
|
286 |
(isAccepted, isImmediateInsert, offsetX, offsetY, newSym) = symbolEditorDialog.showDialog() |
287 |
self.initDirTreeWidget()
|
288 |
else:
|
289 |
QMessageBox.about(self, self.tr('Error'), self.tr('Error occurs during loading symbol data.')) |
290 |
except Exception as ex: |
291 |
from App import App |
292 |
from AppDocData import MessageType |
293 |
|
294 |
message = 'error occurred({}) in {}:{}'.format(ex, sys.exc_info()[-1].tb_frame.f_code.co_filename, |
295 |
sys.exc_info()[-1].tb_lineno)
|
296 |
App.mainWnd().addMessage.emit(MessageType.Error, message) |
297 |
|
298 |
def select_symbol(self, symbol): |
299 |
"""select a tree with given symbol"""
|
300 |
|
301 |
founds = self.findItems(symbol.name, Qt.MatchExactly | Qt.MatchRecursive, 0) |
302 |
if founds:
|
303 |
self.setCurrentItem(founds[0]) |
304 |
|
305 |
def itemDoubleClickEvent(self, item, columnNo): |
306 |
self.isDoubleClicked = True |
307 |
sym = self.getSymbolByItemName(item, columnNo)
|
308 |
itemName = item.text(columnNo) |
309 |
if sym is not None: |
310 |
self.showSymbolEditorDialog(item, columnNo)
|
311 |
self.isDoubleClicked = False |
312 |
|
313 |
'''
|
314 |
@brief Get Symbol data by symbol name
|
315 |
@author Jeongwoo
|
316 |
@date 18.04.20
|
317 |
'''
|
318 |
|
319 |
def getSymbolByItemName(self, item, columnNo): |
320 |
itemName = item.text(columnNo) |
321 |
|
322 |
name = itemName |
323 |
sym = AppDocData.instance().getSymbolByQuery("name", name)
|
324 |
return sym
|
325 |
|
326 |
'''
|
327 |
@breif show symbol's property when selection changed
|
328 |
@author humkyung
|
329 |
@date 2018.07.30
|
330 |
'''
|
331 |
|
332 |
def onCurrentItemChanged(self, current, previous): |
333 |
item = self.currentItem()
|
334 |
if item is not None: |
335 |
data = item.data(0, self.TREE_DATA_ROLE) |
336 |
if data is not None and type(data) is symbol.SymbolBase: |
337 |
self.singleClicked.emit(data)
|
338 |
|
339 |
def startDrag(self, dropAction): |
340 |
"""start drag"""
|
341 |
try:
|
342 |
items = self.selectedItems()
|
343 |
if items and hasattr(items[0], 'svgFilePath'): |
344 |
symData = items[0].data(0, self.TREE_DATA_ROLE) |
345 |
|
346 |
mime = QMimeData() |
347 |
mime.setText(symData.getName()) |
348 |
mime.tag = symData |
349 |
|
350 |
drag = QDrag(self)
|
351 |
drag.setMimeData(mime) |
352 |
originalPoint = symData.getOriginalPoint() |
353 |
drag.setHotSpot( |
354 |
QPoint(int(float(originalPoint.split(",")[0])), int(float(originalPoint.split(",")[1])))) |
355 |
drag.setPixmap(symData.pixmap) |
356 |
drag.exec(Qt.CopyAction) |
357 |
except Exception as ex: |
358 |
from App import App |
359 |
|
360 |
message = 'error occurred({}) in {}:{}'.format(ex, sys.exc_info()[-1].tb_frame.f_code.co_filename, |
361 |
sys.exc_info()[-1].tb_lineno)
|
362 |
App.mainWnd().addMessage.emit(MessageType.Error, message) |