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