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