hytos / DTI_PID / DTI_PID / CodeTableDialog.py @ 7e2d59db
이력 | 보기 | 이력해설 | 다운로드 (37.1 KB)
1 |
# coding: utf-8
|
---|---|
2 |
"""
|
3 |
This is code table dialog module
|
4 |
"""
|
5 |
import os |
6 |
import sys, io |
7 |
from PyQt5.QtCore import * |
8 |
from PyQt5.QtGui import * |
9 |
from PyQt5.QtWidgets import * |
10 |
from AppDocData import AppDocData, MessageType |
11 |
from App import App |
12 |
from openpyxl import * |
13 |
from openpyxl.styles import * |
14 |
|
15 |
from PIL import Image |
16 |
import tesseract_ocr_module as TOCR |
17 |
import numpy as np |
18 |
|
19 |
import CodeTable_UI |
20 |
import FenceCommand |
21 |
from GraphicsBoundingBoxItem import QGraphicsBoundingBoxItem |
22 |
|
23 |
class QCodeTableDialog(QDialog): |
24 |
""" This code table dialog class """
|
25 |
|
26 |
CODE_TABLES = ( |
27 |
'Nominal Diameter', 'Fluid Code', 'Insulation Purpose', 'PnID Number', 'Piping Materials Class', 'Unit Number', |
28 |
'ValveOperCodes', 'EqpTagNames', 'ReservedWords', 'Dictionary') |
29 |
|
30 |
def __init__(self, parent, child_dialog=''): |
31 |
QDialog.__init__(self, parent)
|
32 |
|
33 |
self.currentCode = {}
|
34 |
|
35 |
self.code_area = None |
36 |
self.desc_area = None |
37 |
|
38 |
self.child_dialog = child_dialog
|
39 |
if not child_dialog: |
40 |
self.ui = CodeTable_UI.Ui_CodeTableDialog()
|
41 |
self.ui.setupUi(self) |
42 |
|
43 |
self.ui.spinBoxHeight.setValue(50) |
44 |
|
45 |
self.ui.tableWidgetNominalDiameter.setSortingEnabled(True) |
46 |
self.ui.tableWidgetFluidCode.setSortingEnabled(True) |
47 |
self.ui.tableWidgetInsulationPurpose.setSortingEnabled(True) |
48 |
self.ui.tableWidgetPnIDNumber.setSortingEnabled(True) |
49 |
self.ui.tableWidgetPipingMaterialsClass.setSortingEnabled(True) |
50 |
self.ui.tableWidgetUnitNumber.setSortingEnabled(True) |
51 |
self.ui.tableWidgetValveOperCodes.setSortingEnabled(True) |
52 |
self.ui.tableWidgetEqpTagNames.setSortingEnabled(True) |
53 |
self.ui.tableWidgetReservedWords.setSortingEnabled(True) |
54 |
|
55 |
# DB Table명 기준으로 작성
|
56 |
for table in QCodeTableDialog.CODE_TABLES: |
57 |
self.settingTable(table)
|
58 |
|
59 |
# connect signals
|
60 |
self.ui.pushButtonImport.clicked.connect(self.import_code_table) |
61 |
self.ui.pushButtonExport.clicked.connect(self.export_code_table) |
62 |
self.ui.pushButtonRead.clicked.connect(self.read_from_legend) |
63 |
|
64 |
self.graphicsView = App.mainWnd().graphicsView
|
65 |
self.fence_cmd = FenceCommand.FenceCommand(self.graphicsView) |
66 |
self.fence_cmd.onSuccess.connect(self.onAreaCreated) |
67 |
|
68 |
def getTabText(self): |
69 |
""" get current tab name text """
|
70 |
if not self.child_dialog: |
71 |
_tabWidget = self.ui.tabWidget
|
72 |
currentTabIndex = _tabWidget.currentIndex() |
73 |
tabText = self.replaceText(_tabWidget.tabText(currentTabIndex))
|
74 |
else:
|
75 |
tabText = self.child_dialog
|
76 |
return tabText
|
77 |
|
78 |
def read_from_legend(self): |
79 |
""" read code data from legend drawing """
|
80 |
if self.ui.pushButtonRead.text() == 'Read from Legend': |
81 |
self.graphicsView.command = self.fence_cmd |
82 |
self.ui.pushButtonRead.setText('Draw Code Area') |
83 |
elif self.ui.pushButtonRead.text() == 'Read' and self.code_area and self.code_area.scene() and self.desc_area and self.desc_area.scene(): |
84 |
# read ocr
|
85 |
code_rect = self.code_area.sceneBoundingRect()
|
86 |
desc_rect = self.desc_area.sceneBoundingRect()
|
87 |
code_img = self.graphicsView.image().copy(code_rect.x(), code_rect.y(), code_rect.width(), code_rect.height())
|
88 |
desc_img = self.graphicsView.image().copy(desc_rect.x(), desc_rect.y(), desc_rect.width(), desc_rect.height())
|
89 |
code_texts = self.detectText(code_img, code_rect)
|
90 |
desc_texts = self.detectText(desc_img, desc_rect)
|
91 |
|
92 |
# check validate
|
93 |
for code_text in code_texts: |
94 |
code_text.desc = [] |
95 |
|
96 |
if desc_texts:
|
97 |
for desc_index in reversed(range(len(desc_texts))): |
98 |
for code_index in range(len(code_texts)): |
99 |
if abs(desc_texts[desc_index].center[1] - code_texts[code_index].center[1]) < round(self.ui.spinBoxHeight.value() / 2): |
100 |
code_texts[code_index].desc.append(desc_texts[desc_index]) |
101 |
desc_texts.pop(desc_index) |
102 |
break
|
103 |
|
104 |
for desc_index in reversed(range(len(desc_texts))): |
105 |
min_distance = sys.maxsize |
106 |
min_code = None
|
107 |
for code_index in range(len(code_texts)): |
108 |
distance = desc_texts[desc_index].center[1] - code_texts[code_index].center[1] |
109 |
if distance > 0 and distance < min_distance: |
110 |
min_distance = distance |
111 |
min_code = code_texts[code_index] |
112 |
|
113 |
if min_code:
|
114 |
min_code.desc.append(desc_texts[desc_index]) |
115 |
desc_texts.pop(desc_index) |
116 |
|
117 |
|
118 |
#QMessageBox.warning(self, self.tr('Notice'), self.tr('Please check text area.'))
|
119 |
#return
|
120 |
|
121 |
desc_texts = [] |
122 |
for code_text in code_texts: |
123 |
desc = ' '.join([desc.getText() for desc in sorted(code_text.desc, key=lambda desc: desc.center[1])]) |
124 |
desc_texts.append(desc) |
125 |
|
126 |
# fill table
|
127 |
tabText = self.getTabText()
|
128 |
|
129 |
if tabText == 'NominalDiameter': |
130 |
return
|
131 |
table = self.findTableWidget(tabText)
|
132 |
|
133 |
table.cellChanged.disconnect(self.cellValueChanged)
|
134 |
|
135 |
past_count = table.rowCount() |
136 |
for row_index in range(past_count): |
137 |
for code_index in reversed(range(len(code_texts))): |
138 |
if table.isRowHidden(row_index): continue |
139 |
if table.item(row_index, 1) and table.item(row_index, 1).text() == code_texts[code_index].getText(): |
140 |
table.setItem(row_index, 2, QTableWidgetItem(desc_texts[code_index]))
|
141 |
code_texts.pop(code_index) |
142 |
desc_texts.pop(code_index) |
143 |
break
|
144 |
table.setRowCount(past_count + len(code_texts))
|
145 |
for code_index in range(len(code_texts)): |
146 |
table.setItem(past_count + code_index - 1, 0, QTableWidgetItem('')) |
147 |
table.setItem(past_count + code_index - 1, 1, QTableWidgetItem(code_texts[code_index].getText())) |
148 |
table.setItem(past_count + code_index - 1, 2, QTableWidgetItem(desc_texts[code_index])) |
149 |
|
150 |
last_empty_row = table.rowCount() |
151 |
table.setItem(last_empty_row - 1, 0, QTableWidgetItem('')) |
152 |
table.setItem(last_empty_row - 1, 1, QTableWidgetItem('')) |
153 |
table.setItem(last_empty_row - 1, 2, QTableWidgetItem('')) |
154 |
|
155 |
table.cellChanged.connect(self.cellValueChanged)
|
156 |
|
157 |
if self.code_area: |
158 |
if self.code_area.scene(): |
159 |
self.graphicsView.scene.removeItem(self.code_area) |
160 |
self.code_area = None |
161 |
if self.desc_area: |
162 |
if self.desc_area.scene(): |
163 |
self.graphicsView.scene.removeItem(self.desc_area) |
164 |
self.desc_area = None |
165 |
self.ui.pushButtonRead.setText('Read from Legend') |
166 |
else:
|
167 |
if self.code_area: |
168 |
if self.code_area.scene(): |
169 |
self.graphicsView.scene.removeItem(self.code_area) |
170 |
self.code_area = None |
171 |
if self.desc_area: |
172 |
if self.desc_area.scene(): |
173 |
self.graphicsView.scene.removeItem(self.desc_area) |
174 |
self.desc_area = None |
175 |
self.ui.pushButtonRead.setText('Read from Legend') |
176 |
|
177 |
def onAreaCreated(self, x, y , width, height): |
178 |
import uuid |
179 |
THICKNESS = 5
|
180 |
|
181 |
if self.ui.pushButtonRead.text() == 'Draw Code Area': |
182 |
item = QGraphicsBoundingBoxItem(x, y, width, height) |
183 |
item.setPen(QPen(Qt.red, THICKNESS, Qt.SolidLine)) |
184 |
self.graphicsView.scene.addItem(item)
|
185 |
self.code_area = item
|
186 |
self.ui.pushButtonRead.setText('Draw Description Area') |
187 |
elif self.ui.pushButtonRead.text() == 'Draw Description Area' and self.code_area and self.code_area.scene(): |
188 |
item = QGraphicsBoundingBoxItem(x, y, width, height) |
189 |
item.setPen(QPen(Qt.blue, THICKNESS, Qt.SolidLine)) |
190 |
self.graphicsView.scene.addItem(item)
|
191 |
self.desc_area = item
|
192 |
self.ui.pushButtonRead.setText('Read') |
193 |
self.graphicsView.command = None |
194 |
|
195 |
def detectText(self, image, rect): |
196 |
""" detect text from image, come from OcrResultDialog and modified """
|
197 |
try:
|
198 |
buffer = QBuffer() |
199 |
buffer.open(QBuffer.ReadWrite)
|
200 |
image.save(buffer, "PNG") |
201 |
pyImage = Image.open(io.BytesIO(buffer.data()))
|
202 |
img = np.array(pyImage) |
203 |
|
204 |
docData = AppDocData.instance() |
205 |
configs = docData.getConfigs('Text Recognition', 'OCR Data') |
206 |
ocr_data = configs[0].value if 1 == len(configs) else 'eng' |
207 |
|
208 |
whiteCharList = docData.getConfigs('Text Recognition', 'White Character List') |
209 |
if len(whiteCharList) is 0: |
210 |
textInfoList = TOCR.getTextInfo(img, (round(rect.x()), round(rect.y())), 0, language=ocr_data) |
211 |
else:
|
212 |
textInfoList = TOCR.getTextInfo(img, (round(rect.x()), round(rect.y())), 0, language=ocr_data, conf = whiteCharList[0].value) |
213 |
|
214 |
if textInfoList is not None and len(textInfoList) > 0: |
215 |
return textInfoList
|
216 |
except Exception as ex: |
217 |
from App import App |
218 |
message = 'error occurred({}) in {}:{}'.format(ex, sys.exc_info()[-1].tb_frame.f_code.co_filename, sys.exc_info()[-1].tb_lineno) |
219 |
App.mainWnd().addMessage.emit(MessageType.Error, message) |
220 |
|
221 |
'''
|
222 |
@brief Setting Table
|
223 |
@author kyouho
|
224 |
@date 2018.07.10
|
225 |
'''
|
226 |
|
227 |
def settingTable(self, tableName, symbol_attribute_uid=None, tableDatas=None): |
228 |
try:
|
229 |
tableName = self.replaceText(tableName)
|
230 |
docData = AppDocData.instance() |
231 |
table = self.findTableWidget(tableName)
|
232 |
if table: table.horizontalHeader().setStretchLastSection(True) |
233 |
if tableName == "NominalDiameter": |
234 |
tableDatas = docData.getNomialPipeSizeData() |
235 |
elif tableName == "SymbolAttributeCodeTable": |
236 |
if tableDatas is None: |
237 |
tableDatas = docData.getCodeTable(tableName, forCheckLineNumber=False, symbol_attribute_uid=symbol_attribute_uid)
|
238 |
else:
|
239 |
pass
|
240 |
else:
|
241 |
tableDatas = docData.getCodeTable(tableName) |
242 |
|
243 |
if tableName == "NominalDiameter": |
244 |
self.fill_nominal_pipe_sizes(tableDatas)
|
245 |
|
246 |
table.cellChanged.connect(self.cellValueChanged)
|
247 |
self.checkRowAndAddRow(tableName, table)
|
248 |
else:
|
249 |
table.setColumnCount(4)
|
250 |
table.setHorizontalHeaderLabels(['UID', 'Code', 'Desc.', 'Allowables']) |
251 |
table.hideColumn(0)
|
252 |
|
253 |
self.fill_codes(table, tableDatas)
|
254 |
|
255 |
table.horizontalHeaderItem(1).setSizeHint(QSize(30, 30)) |
256 |
table.cellChanged.connect(self.cellValueChanged)
|
257 |
self.checkRowAndAddRow(tableName, table)
|
258 |
self.setCurrentCode(table, tableName)
|
259 |
except Exception as ex: |
260 |
print('error occurred({}) in {}:{}'.format(ex, sys.exc_info()[-1].tb_frame.f_code.co_filename, |
261 |
sys.exc_info()[-1].tb_lineno))
|
262 |
|
263 |
'''
|
264 |
@brief Insert row NominalPipeSzie Tablewidget
|
265 |
@author kyouho
|
266 |
@date 2018.07.10
|
267 |
'''
|
268 |
|
269 |
def fill_nominal_pipe_sizes(self, pipeSizes): |
270 |
try:
|
271 |
self.ui.tableWidgetNominalDiameter.setColumnCount(8) |
272 |
self.ui.tableWidgetNominalDiameter.setHorizontalHeaderLabels(
|
273 |
['UID', 'Code', 'Metric', 'Inch', 'InchStr', 'Inch Allowables', 'MetricStr', 'Metric Allowables']) |
274 |
self.ui.tableWidgetNominalDiameter.hideColumn(0) |
275 |
self.ui.tableWidgetNominalDiameter.setRowCount(len(pipeSizes)) |
276 |
row = 0
|
277 |
for pipeSize in pipeSizes: |
278 |
item = QTableWidgetItem(pipeSize.uid) |
279 |
item.setData(Qt.UserRole, pipeSize) |
280 |
self.ui.tableWidgetNominalDiameter.setItem(row, 0, item) |
281 |
self.ui.tableWidgetNominalDiameter.setItem(row, 1, QTableWidgetItem(pipeSize.code)) |
282 |
self.ui.tableWidgetNominalDiameter.setItem(row, 2, QTableWidgetItem( |
283 |
'' if pipeSize.metric is None else str(pipeSize.metric))) |
284 |
self.ui.tableWidgetNominalDiameter.setItem(row, 3, QTableWidgetItem( |
285 |
'' if pipeSize.inch is None else str(pipeSize.inch))) |
286 |
self.ui.tableWidgetNominalDiameter.setItem(row, 4, QTableWidgetItem( |
287 |
'' if pipeSize.inchStr is None else pipeSize.inchStr)) |
288 |
self.ui.tableWidgetNominalDiameter.setItem(row, 5, QTableWidgetItem( |
289 |
'' if pipeSize.allowable_inch_str is None else pipeSize.allowable_inch_str)) |
290 |
self.ui.tableWidgetNominalDiameter.setItem(row, 6, QTableWidgetItem( |
291 |
'' if pipeSize.metricStr is None else pipeSize.metricStr)) |
292 |
self.ui.tableWidgetNominalDiameter.setItem(row, 7, QTableWidgetItem( |
293 |
'' if pipeSize.allowable_metric_str is None else pipeSize.allowable_metric_str)) |
294 |
row += 1
|
295 |
|
296 |
self.ui.tableWidgetNominalDiameter.horizontalHeaderItem(0).setSizeHint(QSize(30, 30)) |
297 |
except Exception as ex: |
298 |
from App import App |
299 |
|
300 |
message = 'error occurred({}) in {}:{}'.format(ex, sys.exc_info()[-1].tb_frame.f_code.co_filename, |
301 |
sys.exc_info()[-1].tb_lineno)
|
302 |
App.mainWnd().addMessage.emit(MessageType.Error, message) |
303 |
|
304 |
'''
|
305 |
@brief Insert row Common Tablewidget
|
306 |
@author kyouho
|
307 |
@date 2018.07.10
|
308 |
'''
|
309 |
|
310 |
def fill_codes(self, table, tableDatas): |
311 |
try:
|
312 |
table.setRowCount(len(tableDatas))
|
313 |
row = 0
|
314 |
for tableData in tableDatas: |
315 |
table.setItem(row, 0, QTableWidgetItem(tableData[0])) # UID |
316 |
table.setItem(row, 1, QTableWidgetItem(tableData[1])) # Name |
317 |
table.setItem(row, 2, QTableWidgetItem(tableData[2] if tableData[2] else '')) # Description |
318 |
table.setItem(row, 3, QTableWidgetItem((tableData[3] if type(tableData[3]) is str else ','.join(tableData[3])) \ |
319 |
if tableData[3] else '')) # Allowables |
320 |
row += 1
|
321 |
except Exception as ex: |
322 |
from App import App |
323 |
|
324 |
message = 'error occurred({}) in {}:{}'.format(ex, sys.exc_info()[-1].tb_frame.f_code.co_filename, |
325 |
sys.exc_info()[-1].tb_lineno)
|
326 |
App.mainWnd().addMessage.emit(MessageType.Error, message) |
327 |
|
328 |
'''
|
329 |
@brief Find TableWidget with Name
|
330 |
@author kyouhokyouho
|
331 |
@date 2018.07.10
|
332 |
'''
|
333 |
|
334 |
def findTableWidget(self, tableName): |
335 |
tableName = self.replaceText(tableName)
|
336 |
return self.findChild(QTableWidget, 'tableWidget' + tableName) |
337 |
|
338 |
'''
|
339 |
@brief key press event
|
340 |
@author kyouho
|
341 |
@date 2018.07.10
|
342 |
'''
|
343 |
|
344 |
def keyPressEvent(self, e): |
345 |
try:
|
346 |
if e.key() == Qt.Key_Delete:
|
347 |
tabText = self.getTabText()
|
348 |
|
349 |
table = self.findTableWidget(tabText)
|
350 |
if table:
|
351 |
selectedIndexes = table.selectedIndexes() |
352 |
selectedRows = [item.row() for item in selectedIndexes] |
353 |
model = table.model() |
354 |
|
355 |
rowsIndex = [] |
356 |
for row in selectedRows: |
357 |
rowsIndex.append(row) |
358 |
|
359 |
# 중복 제거
|
360 |
rowsIndex = list(set(rowsIndex)) |
361 |
rowsIndex.reverse() |
362 |
|
363 |
if tabText != "NominalDiameter": |
364 |
for row in rowsIndex: |
365 |
table.hideRow(row) |
366 |
"""
|
367 |
uid = table.item(row, 0).text()
|
368 |
self.removeUID[uid] = tabText
|
369 |
model.removeRow(row)
|
370 |
"""
|
371 |
|
372 |
self.checkRowAndAddRow(tabText, table)
|
373 |
elif (e.key() == Qt.Key_C) and (e.modifiers() & Qt.ControlModifier): |
374 |
tabText = self.getTabText()
|
375 |
|
376 |
table = self.findTableWidget(tabText)
|
377 |
if table:
|
378 |
self.copy_selection(table)
|
379 |
elif (e.key() == Qt.Key_V) and (e.modifiers() & Qt.ControlModifier): |
380 |
tabText = self.getTabText()
|
381 |
'''
|
382 |
table = self.findTableWidget(tabText)
|
383 |
tab = self.ui.tabWidget.widget(self.ui.tabWidget.currentIndex())
|
384 |
table = tab.findChild(QTableWidget)
|
385 |
'''
|
386 |
table = self.findTableWidget(tabText)
|
387 |
if table:
|
388 |
self.paste_selection(table)
|
389 |
except Exception as ex: |
390 |
from App import App |
391 |
message = 'error occurred({}) in {}:{}'.format(repr(ex), sys.exc_info()[-1].tb_frame.f_code.co_filename, |
392 |
sys.exc_info()[-1].tb_lineno)
|
393 |
App.mainWnd().addMessage.emit(MessageType.Error, message) |
394 |
|
395 |
def copy_selection(self, table_widget): |
396 |
"""copy selected text to clipboard"""
|
397 |
|
398 |
import io |
399 |
import csv |
400 |
|
401 |
selection = table_widget.selectedIndexes() |
402 |
if selection:
|
403 |
rows = sorted(index.row() for index in selection) |
404 |
columns = sorted(index.column() for index in selection) |
405 |
rowcount = rows[-1] - rows[0] + 1 |
406 |
colcount = columns[-1] - columns[0] + 1 |
407 |
table = [[''] * colcount for _ in range(rowcount)] |
408 |
for index in selection: |
409 |
row = index.row() - rows[0]
|
410 |
column = index.column() - columns[0]
|
411 |
table[row][column] = index.data() |
412 |
stream = io.StringIO() |
413 |
csv.writer(stream, delimiter='\t').writerows(table)
|
414 |
QApplication.clipboard().setText(stream.getvalue()) |
415 |
|
416 |
def paste_selection(self, table_widget): |
417 |
"""paste text of clipboard to table widget"""
|
418 |
|
419 |
import io |
420 |
import csv |
421 |
|
422 |
selection = table_widget.selectedIndexes() |
423 |
if selection:
|
424 |
model = table_widget.model() |
425 |
|
426 |
buffer = QApplication.clipboard().text() |
427 |
rows = sorted(index.row() for index in selection) |
428 |
columns = sorted(index.column() for index in selection) |
429 |
reader = csv.reader(io.StringIO(buffer), delimiter='\t') |
430 |
if len(rows) == 1 and len(columns) == 1: |
431 |
for i, line in enumerate(reader): |
432 |
for j, cell in enumerate(line): |
433 |
model.setData(model.index(rows[0] + i, columns[0] + j), cell) |
434 |
else:
|
435 |
arr = [[cell for cell in row] for row in reader] |
436 |
for index in selection: |
437 |
row = index.row() - rows[0]
|
438 |
column = index.column() - columns[0]
|
439 |
model.setData(model.index(index.row(), index.column()), arr[row][column]) |
440 |
|
441 |
'''
|
442 |
@brief Add new row
|
443 |
@author kyouho
|
444 |
@date 2018.07.10
|
445 |
'''
|
446 |
|
447 |
def checkRowAndAddRow(self, tableName, table): |
448 |
try:
|
449 |
rowCount = table.rowCount() |
450 |
result = True
|
451 |
if tableName != "NominalDiameter": |
452 |
for row in range(rowCount): |
453 |
if table.isRowHidden(row): continue |
454 |
code = table.item(row, 1).text()
|
455 |
if not code: |
456 |
result = False
|
457 |
if result:
|
458 |
table.cellChanged.disconnect(self.cellValueChanged)
|
459 |
table.setRowCount(rowCount + 1)
|
460 |
table.setItem(rowCount, 0, QTableWidgetItem('')) |
461 |
table.setItem(rowCount, 1, QTableWidgetItem('')) |
462 |
table.setItem(rowCount, 2, QTableWidgetItem('')) |
463 |
table.setItem(rowCount, 3, QTableWidgetItem('')) |
464 |
table.cellChanged.connect(self.cellValueChanged)
|
465 |
else:
|
466 |
columnCount = table.columnCount() |
467 |
|
468 |
for row in range(rowCount): |
469 |
if not result: |
470 |
break
|
471 |
for columnIndex in range(columnCount): |
472 |
if not table.item(row, columnIndex).text(): |
473 |
result = False
|
474 |
break
|
475 |
|
476 |
if result:
|
477 |
table.setRowCount(rowCount + 1)
|
478 |
table.cellChanged.disconnect(self.cellValueChanged)
|
479 |
for columnIndex in range(columnCount): |
480 |
table.setItem(rowCount, columnIndex, QTableWidgetItem(''))
|
481 |
table.cellChanged.connect(self.cellValueChanged)
|
482 |
|
483 |
except Exception as ex: |
484 |
print('error occurred({}) in {}:{}'.format(ex, sys.exc_info()[-1].tb_frame.f_code.co_filename, |
485 |
sys.exc_info()[-1].tb_lineno))
|
486 |
|
487 |
'''
|
488 |
@brief cellValueChange event
|
489 |
@author kyouho
|
490 |
@date 2018.07.10
|
491 |
'''
|
492 |
|
493 |
def cellValueChanged(self, row, column): |
494 |
try:
|
495 |
tabText = self.getTabText()
|
496 |
|
497 |
table = self.findTableWidget(tabText)
|
498 |
|
499 |
if tabText != "NominalDiameter": |
500 |
item = table.item(row, 1)
|
501 |
code = item.text() |
502 |
if column == 1: |
503 |
result = self.isExistCode(table, code)
|
504 |
if result:
|
505 |
self.checkRowAndAddRow(tabText, table)
|
506 |
self.setCurrentCode(table, tabText)
|
507 |
else:
|
508 |
QMessageBox.warning(self, self.tr('Notice'), |
509 |
self.tr('The same code already exists in the table.')) |
510 |
table.cellChanged.disconnect(self.cellValueChanged)
|
511 |
item.setText(self.currentCode[tabText][row])
|
512 |
table.cellChanged.connect(self.cellValueChanged)
|
513 |
elif column == 2: |
514 |
table.resizeColumnToContents(2)
|
515 |
else:
|
516 |
table.resizeColumnToContents(3)
|
517 |
else:
|
518 |
self.checkRowAndAddRow(tabText, table)
|
519 |
except Exception as ex: |
520 |
print('error occurred({}) in {}:{}'.format(ex, sys.exc_info()[-1].tb_frame.f_code.co_filename, |
521 |
sys.exc_info()[-1].tb_lineno))
|
522 |
|
523 |
'''
|
524 |
@brief Check Duplicate Code
|
525 |
@author kyouho
|
526 |
@date 2018.07.10
|
527 |
'''
|
528 |
|
529 |
def isExistCode(self, table, editCode): |
530 |
try:
|
531 |
if not editCode: |
532 |
return False |
533 |
|
534 |
rowCount = table.rowCount() |
535 |
codes = [] |
536 |
for row in range(rowCount): |
537 |
if table.isRowHidden(row): continue |
538 |
code = table.item(row, 1).text()
|
539 |
codes.append(code) |
540 |
|
541 |
count = codes.count(editCode) |
542 |
|
543 |
if count >= 2: |
544 |
return False |
545 |
else:
|
546 |
return True |
547 |
|
548 |
except Exception as ex: |
549 |
print('error occurred({}) in {}:{}'.format(ex, sys.exc_info()[-1].tb_frame.f_code.co_filename, |
550 |
sys.exc_info()[-1].tb_lineno))
|
551 |
|
552 |
'''
|
553 |
@brief save current Code (self.currentCode)
|
554 |
@author kyouho
|
555 |
@date 2018.07.10
|
556 |
'''
|
557 |
|
558 |
def setCurrentCode(self, table, tabText): |
559 |
try:
|
560 |
self.currentCode[tabText] = {}
|
561 |
rowCount = table.rowCount() |
562 |
|
563 |
res = {} |
564 |
for row in range(rowCount): |
565 |
code = table.item(row, 1).text()
|
566 |
res[row] = code |
567 |
|
568 |
self.currentCode[tabText] = res
|
569 |
|
570 |
except Exception as ex: |
571 |
print('error occurred({}) in {}:{}'.format(ex, sys.exc_info()[-1].tb_frame.f_code.co_filename, |
572 |
sys.exc_info()[-1].tb_lineno))
|
573 |
|
574 |
'''
|
575 |
@brief replaceTextForCodeTable
|
576 |
@author kyouho
|
577 |
@date 2018.07.12
|
578 |
'''
|
579 |
|
580 |
def replaceText(self, text): |
581 |
return text.replace(' ', '').replace('&&', 'n') |
582 |
|
583 |
def import_code_table(self): |
584 |
"""import code table excel file"""
|
585 |
|
586 |
options = QFileDialog.Options() |
587 |
options |= QFileDialog.DontUseNativeDialog |
588 |
file_name, _ = QFileDialog.getOpenFileName(self, "Import code table", os.getcwd(), "xlsx files(*.xlsx)", |
589 |
options=options) |
590 |
if file_name:
|
591 |
QApplication.setOverrideCursor(Qt.WaitCursor) |
592 |
try:
|
593 |
app_doc_data = AppDocData.instance() |
594 |
book = load_workbook(file_name) |
595 |
for sheet in book.worksheets: |
596 |
matches = [index for index in range(self.ui.tabWidget.count()) |
597 |
if sheet.title == self.ui.tabWidget.tabText(index)] |
598 |
if matches:
|
599 |
table = self.ui.tabWidget.widget(matches[0]).findChild(QTableWidget) |
600 |
self.fill_table_with_sheet(sheet, table)
|
601 |
except Exception as ex: |
602 |
from App import App |
603 |
message = 'error occurred({}) in {}:{}'.format(repr(ex), sys.exc_info()[-1].tb_frame.f_code.co_filename, |
604 |
sys.exc_info()[-1].tb_lineno)
|
605 |
App.mainWnd().addMessage.emit(MessageType.Error, message) |
606 |
finally:
|
607 |
QApplication.restoreOverrideCursor() |
608 |
|
609 |
|
610 |
def export_code_table(self): |
611 |
"""export code table to excel file"""
|
612 |
|
613 |
app_doc_data = AppDocData.instance() |
614 |
project = app_doc_data.getCurrentProject() |
615 |
|
616 |
options = QFileDialog.Options() |
617 |
options |= QFileDialog.DontUseNativeDialog |
618 |
file_name, _ = QFileDialog.getSaveFileName(self, "Export code table", project.path, "xlsx files(*.xlsx)", |
619 |
options=options) |
620 |
if not file_name: |
621 |
return
|
622 |
|
623 |
QApplication.setOverrideCursor(Qt.WaitCursor) |
624 |
|
625 |
try:
|
626 |
wb = Workbook() |
627 |
wb.active.title = self.tr(self.ui.tabWidget.tabText(0)) |
628 |
for index in range(1, self.ui.tabWidget.count()): |
629 |
wb.create_sheet(self.tr(self.ui.tabWidget.tabText(index))) |
630 |
|
631 |
for index in range(self.ui.tabWidget.count()): |
632 |
tab = self.ui.tabWidget.widget(index)
|
633 |
table = tab.findChild(QTableWidget) |
634 |
if table:
|
635 |
sheet = wb.worksheets[index] |
636 |
self.set_sheet_header(table, sheet)
|
637 |
self.fill_sheet_with_table(table, sheet)
|
638 |
self.auto_resize_columns(sheet)
|
639 |
|
640 |
file_name, ext = os.path.splitext(file_name) |
641 |
save_file_name = file_name + ext if ext.upper() == '.XLSX' else file_name + '.xlsx' |
642 |
wb.save(save_file_name) |
643 |
|
644 |
QMessageBox.about(self, self.tr("Information"), self.tr('Successfully saved.')) |
645 |
|
646 |
os.startfile(save_file_name) |
647 |
except Exception as ex: |
648 |
from App import App |
649 |
from AppDocData import MessageType |
650 |
|
651 |
message = 'error occurred({}) in {}:{}'.format(repr(ex), sys.exc_info()[-1].tb_frame.f_code.co_filename, |
652 |
sys.exc_info()[-1].tb_lineno)
|
653 |
App.mainWnd().addMessage.emit(MessageType.Error, message) |
654 |
finally:
|
655 |
QApplication.restoreOverrideCursor() |
656 |
|
657 |
def set_sheet_header(self, table, sheet): |
658 |
""" set list header """
|
659 |
|
660 |
try:
|
661 |
thin = Side(border_style='thin', color='000000') |
662 |
border = Border(left=thin, right=thin, top=thin, bottom=thin) |
663 |
_col = 1
|
664 |
for col in range(table.columnCount()): |
665 |
logical_index = table.horizontalHeader().logicalIndex(col) |
666 |
col_name = table.horizontalHeaderItem(logical_index).text() |
667 |
sheet.cell(1, _col, col_name)
|
668 |
sheet.cell(row=1, column=_col).alignment = Alignment(horizontal='center', vertical='center', |
669 |
wrapText=True)
|
670 |
sheet.cell(row=1, column=_col).fill = PatternFill(patternType='solid', fill_type='solid', |
671 |
fgColor=Color('8DB4E2'))
|
672 |
sheet.cell(row=1, column=_col).border = border
|
673 |
_col += 1
|
674 |
except Exception as ex: |
675 |
from App import App |
676 |
from AppDocData import MessageType |
677 |
|
678 |
message = 'error occurred({}) in {}:{}'.format(ex, sys.exc_info()[-1].tb_frame.f_code.co_filename, |
679 |
sys.exc_info()[-1].tb_lineno)
|
680 |
App.mainWnd().addMessage.emit(MessageType.Error, message) |
681 |
|
682 |
def fill_table_with_sheet(self, sheet, table): |
683 |
"""fill table with sheet"""
|
684 |
from NominalPipeSize import NominalPipeSize |
685 |
|
686 |
try:
|
687 |
row_index = 0
|
688 |
headers = {} |
689 |
if sheet.title == 'Nominal Diameter': |
690 |
pipe_sizes = [] |
691 |
for row in sheet.rows: |
692 |
if row_index == 0: |
693 |
for col in range(sheet.max_column): |
694 |
value = row[col].value |
695 |
headers[col] = value |
696 |
else:
|
697 |
pipe_size = NominalPipeSize(None, None, None, None, None, None, None, None) |
698 |
for col in range(sheet.max_column): |
699 |
value = row[col].value |
700 |
if 'UID' == headers[col]: |
701 |
pipe_size.uid = value |
702 |
elif 'Code' == headers[col]: |
703 |
pipe_size.code = value |
704 |
elif 'Metric' == headers[col]: |
705 |
pipe_size.metric = value |
706 |
elif 'Inch' == headers[col]: |
707 |
pipe_size.inch = value |
708 |
elif 'InchStr' == headers[col]: |
709 |
pipe_size.inchStr = value |
710 |
elif 'Inch Allowables' == headers[col]: |
711 |
pipe_size.allowable_inch_str = value |
712 |
elif 'MetricStr' == headers[col]: |
713 |
pipe_size.metricStr = value |
714 |
elif 'Metric Allowables' == headers[col]: |
715 |
pipe_size.allowable_metric_str = value |
716 |
|
717 |
pipe_sizes.append(pipe_size) |
718 |
|
719 |
row_index += 1
|
720 |
|
721 |
self.fill_nominal_pipe_sizes(pipe_sizes)
|
722 |
else:
|
723 |
codes = [] |
724 |
for row in sheet.rows: |
725 |
if row_index == 0: |
726 |
for col in range(sheet.max_column): |
727 |
value = row[col].value |
728 |
headers[col] = value |
729 |
else:
|
730 |
code = [row[col].value for col in range(sheet.max_column)] |
731 |
codes.append(code) |
732 |
|
733 |
row_index += 1
|
734 |
|
735 |
self.fill_codes(table, codes)
|
736 |
except Exception as ex: |
737 |
from App import App |
738 |
from AppDocData import MessageType |
739 |
|
740 |
message = 'error occurred({}) in {}:{}'.format(ex, sys.exc_info()[-1].tb_frame.f_code.co_filename, |
741 |
sys.exc_info()[-1].tb_lineno)
|
742 |
App.mainWnd().addMessage.emit(MessageType.Error, message) |
743 |
|
744 |
def fill_sheet_with_table(self, table, sheet): |
745 |
"""fill sheet with table"""
|
746 |
|
747 |
try:
|
748 |
thin = Side(border_style='thin', color='000000') |
749 |
border = Border(left=thin, right=thin, top=thin, bottom=thin) |
750 |
|
751 |
for col in range(table.columnCount()): |
752 |
for row in range(table.rowCount()): |
753 |
try:
|
754 |
text = str(table.item(row, col).text())
|
755 |
sheet.cell(row + 2, col + 1, text) |
756 |
sheet.cell(row=row + 2, column=col + 1).border = border |
757 |
except AttributeError: |
758 |
pass
|
759 |
except Exception as ex: |
760 |
from App import App |
761 |
from AppDocData import MessageType |
762 |
|
763 |
message = 'error occurred({}) in {}:{}'.format(ex, sys.exc_info()[-1].tb_frame.f_code.co_filename, |
764 |
sys.exc_info()[-1].tb_lineno)
|
765 |
App.mainWnd().addMessage.emit(MessageType.Error, message) |
766 |
|
767 |
def auto_resize_columns(self, sheet): |
768 |
""" auto resize columns with contents """
|
769 |
|
770 |
from openpyxl.utils import get_column_letter |
771 |
try:
|
772 |
for col in sheet.columns: |
773 |
max_length = 0
|
774 |
column = col[0].column # Get the column name |
775 |
for cell in col: |
776 |
try: # Necessary to avoid error on empty cells |
777 |
if len(str(cell.value)) > max_length: |
778 |
max_length = len(cell.value)
|
779 |
except:
|
780 |
pass
|
781 |
|
782 |
adjusted_width = (max_length + 2) * 1.2 |
783 |
sheet.column_dimensions[ |
784 |
get_column_letter(column) if type(column) is int else column].width = adjusted_width |
785 |
except Exception as ex: |
786 |
from App import App |
787 |
from AppDocData import MessageType |
788 |
|
789 |
message = 'error occurred({}) in {}:{}'.format(repr(ex), sys.exc_info()[-1].tb_frame.f_code.co_filename, |
790 |
sys.exc_info()[-1].tb_lineno)
|
791 |
App.mainWnd().addMessage.emit(MessageType.Error, message) |
792 |
|
793 |
'''
|
794 |
@brief save codes
|
795 |
@author kyouho
|
796 |
@date 2018.07.12
|
797 |
'''
|
798 |
|
799 |
def accept(self): |
800 |
from CodeTables import CodeTable |
801 |
for table in QCodeTableDialog.CODE_TABLES: |
802 |
if table != 'Nominal Diameter': |
803 |
self.saveCommonCodeData(table)
|
804 |
|
805 |
self.saveNomialPipeSize()
|
806 |
CodeTable.clearTables() |
807 |
|
808 |
QDialog.accept(self)
|
809 |
|
810 |
'''
|
811 |
@brief save common code data
|
812 |
@author kyouho
|
813 |
@date 2018.07.12
|
814 |
'''
|
815 |
|
816 |
def saveCommonCodeData(self, tableName): |
817 |
datas = [] |
818 |
try:
|
819 |
tableName = self.replaceText(tableName)
|
820 |
table = self.findTableWidget(tableName)
|
821 |
rowCount = table.rowCount() |
822 |
for row in range(rowCount): |
823 |
if table.isRowHidden(row):
|
824 |
uid, code, description, allowables = '-1', table.item(row, 1).text(), '', table.item(row, 0).text() |
825 |
elif table.item(row, 0): |
826 |
uid = table.item(row, 0).text()
|
827 |
code = table.item(row, 1).text()
|
828 |
description = table.item(row, 2).text() if table.item(row, 2) is not None else '' |
829 |
allowables = table.item(row, 3).text() if table.item(row, 3) is not None else '' |
830 |
|
831 |
if code:
|
832 |
datas.append((uid, code, description, allowables)) |
833 |
|
834 |
docData = AppDocData.instance() |
835 |
docData.saveCommonCodeData(tableName.replace(' ', ''), datas) |
836 |
except Exception as ex: |
837 |
from App import App |
838 |
|
839 |
message = 'error occurred({}) in {}:{}'.format(ex, sys.exc_info()[-1].tb_frame.f_code.co_filename, |
840 |
sys.exc_info()[-1].tb_lineno)
|
841 |
App.mainWnd().addMessage.emit(MessageType.Error, message) |
842 |
|
843 |
'''
|
844 |
@brief save common code data
|
845 |
@author kyouho
|
846 |
@date 2018.07.16
|
847 |
'''
|
848 |
|
849 |
def saveNomialPipeSize(self): |
850 |
pipeSizes = [] |
851 |
try:
|
852 |
docData = AppDocData.instance() |
853 |
|
854 |
from NominalPipeSize import NominalPipeSize |
855 |
|
856 |
table = self.ui.tableWidgetNominalDiameter
|
857 |
rowCount = table.rowCount() |
858 |
for row in range(rowCount): |
859 |
pipe_size = table.item(row, 0).data(Qt.UserRole)
|
860 |
pipe_size.code = table.item(row, 1).text()
|
861 |
pipe_size.metric = float(table.item(row, 2).text()) if table.item(row, 2).text() != '' else None |
862 |
pipe_size.inch = float(table.item(row, 3).text()) if table.item(row, 3).text() != '' else None |
863 |
pipe_size.inchStr = table.item(row, 4).text()
|
864 |
pipe_size.allowable_inch_str = table.item(row, 5).text()
|
865 |
pipe_size.metricStr = table.item(row, 6).text()
|
866 |
pipe_size.allowable_metric_str = table.item(row, 7).text()
|
867 |
pipeSizes.append(pipe_size) |
868 |
|
869 |
docData.insertNomialPipeSize(pipeSizes) |
870 |
|
871 |
except Exception as ex: |
872 |
from App import App |
873 |
|
874 |
message = 'error occurred({}) in {}:{}'.format(ex, sys.exc_info()[-1].tb_frame.f_code.co_filename, |
875 |
sys.exc_info()[-1].tb_lineno)
|
876 |
App.mainWnd().addMessage.emit(MessageType.Error, message) |