1
|
|
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
|
|
56
|
for table in QCodeTableDialog.CODE_TABLES:
|
57
|
self.settingTable(table)
|
58
|
|
59
|
|
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
|
|
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
|
|
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
|
|
119
|
|
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
|
|
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]))
|
316
|
table.setItem(row, 1, QTableWidgetItem(tableData[1]))
|
317
|
table.setItem(row, 2, QTableWidgetItem(tableData[2]))
|
318
|
table.setItem(row, 3, QTableWidgetItem(tableData[3] if type(tableData[3]) is str else ','.join(tableData[3])))
|
319
|
row += 1
|
320
|
except Exception as ex:
|
321
|
from App import App
|
322
|
|
323
|
message = 'error occurred({}) in {}:{}'.format(ex, sys.exc_info()[-1].tb_frame.f_code.co_filename,
|
324
|
sys.exc_info()[-1].tb_lineno)
|
325
|
App.mainWnd().addMessage.emit(MessageType.Error, message)
|
326
|
|
327
|
'''
|
328
|
@brief Find TableWidget with Name
|
329
|
@author kyouhokyouho
|
330
|
@date 2018.07.10
|
331
|
'''
|
332
|
|
333
|
def findTableWidget(self, tableName):
|
334
|
tableName = self.replaceText(tableName)
|
335
|
return self.findChild(QTableWidget, 'tableWidget' + tableName)
|
336
|
|
337
|
'''
|
338
|
@brief key press event
|
339
|
@author kyouho
|
340
|
@date 2018.07.10
|
341
|
'''
|
342
|
|
343
|
def keyPressEvent(self, e):
|
344
|
try:
|
345
|
if e.key() == Qt.Key_Delete:
|
346
|
tabText = self.getTabText()
|
347
|
|
348
|
table = self.findTableWidget(tabText)
|
349
|
if table:
|
350
|
selectedIndexes = table.selectedIndexes()
|
351
|
selectedRows = [item.row() for item in selectedIndexes]
|
352
|
model = table.model()
|
353
|
|
354
|
rowsIndex = []
|
355
|
for row in selectedRows:
|
356
|
rowsIndex.append(row)
|
357
|
|
358
|
|
359
|
rowsIndex = list(set(rowsIndex))
|
360
|
rowsIndex.reverse()
|
361
|
|
362
|
if tabText != "NominalDiameter":
|
363
|
for row in rowsIndex:
|
364
|
table.hideRow(row)
|
365
|
"""
|
366
|
uid = table.item(row, 0).text()
|
367
|
self.removeUID[uid] = tabText
|
368
|
model.removeRow(row)
|
369
|
"""
|
370
|
|
371
|
self.checkRowAndAddRow(tabText, table)
|
372
|
elif (e.key() == Qt.Key_C) and (e.modifiers() & Qt.ControlModifier):
|
373
|
tabText = self.getTabText()
|
374
|
|
375
|
table = self.findTableWidget(tabText)
|
376
|
if table:
|
377
|
self.copy_selection(table)
|
378
|
elif (e.key() == Qt.Key_V) and (e.modifiers() & Qt.ControlModifier):
|
379
|
tabText = self.getTabText()
|
380
|
'''
|
381
|
table = self.findTableWidget(tabText)
|
382
|
tab = self.ui.tabWidget.widget(self.ui.tabWidget.currentIndex())
|
383
|
table = tab.findChild(QTableWidget)
|
384
|
'''
|
385
|
table = self.findTableWidget(tabText)
|
386
|
if table:
|
387
|
self.paste_selection(table)
|
388
|
except Exception as ex:
|
389
|
from App import App
|
390
|
message = 'error occurred({}) in {}:{}'.format(repr(ex), sys.exc_info()[-1].tb_frame.f_code.co_filename,
|
391
|
sys.exc_info()[-1].tb_lineno)
|
392
|
App.mainWnd().addMessage.emit(MessageType.Error, message)
|
393
|
|
394
|
def copy_selection(self, table_widget):
|
395
|
"""copy selected text to clipboard"""
|
396
|
|
397
|
import io
|
398
|
import csv
|
399
|
|
400
|
selection = table_widget.selectedIndexes()
|
401
|
if selection:
|
402
|
rows = sorted(index.row() for index in selection)
|
403
|
columns = sorted(index.column() for index in selection)
|
404
|
rowcount = rows[-1] - rows[0] + 1
|
405
|
colcount = columns[-1] - columns[0] + 1
|
406
|
table = [[''] * colcount for _ in range(rowcount)]
|
407
|
for index in selection:
|
408
|
row = index.row() - rows[0]
|
409
|
column = index.column() - columns[0]
|
410
|
table[row][column] = index.data()
|
411
|
stream = io.StringIO()
|
412
|
csv.writer(stream, delimiter='\t').writerows(table)
|
413
|
QApplication.clipboard().setText(stream.getvalue())
|
414
|
|
415
|
def paste_selection(self, table_widget):
|
416
|
"""paste text of clipboard to table widget"""
|
417
|
|
418
|
import io
|
419
|
import csv
|
420
|
|
421
|
selection = table_widget.selectedIndexes()
|
422
|
if selection:
|
423
|
model = table_widget.model()
|
424
|
|
425
|
buffer = QApplication.clipboard().text()
|
426
|
rows = sorted(index.row() for index in selection)
|
427
|
columns = sorted(index.column() for index in selection)
|
428
|
reader = csv.reader(io.StringIO(buffer), delimiter='\t')
|
429
|
if len(rows) == 1 and len(columns) == 1:
|
430
|
for i, line in enumerate(reader):
|
431
|
for j, cell in enumerate(line):
|
432
|
model.setData(model.index(rows[0] + i, columns[0] + j), cell)
|
433
|
else:
|
434
|
arr = [[cell for cell in row] for row in reader]
|
435
|
for index in selection:
|
436
|
row = index.row() - rows[0]
|
437
|
column = index.column() - columns[0]
|
438
|
model.setData(model.index(index.row(), index.column()), arr[row][column])
|
439
|
|
440
|
'''
|
441
|
@brief Add new row
|
442
|
@author kyouho
|
443
|
@date 2018.07.10
|
444
|
'''
|
445
|
|
446
|
def checkRowAndAddRow(self, tableName, table):
|
447
|
try:
|
448
|
rowCount = table.rowCount()
|
449
|
result = True
|
450
|
if tableName != "NominalDiameter":
|
451
|
for row in range(rowCount):
|
452
|
if table.isRowHidden(row): continue
|
453
|
code = table.item(row, 1).text()
|
454
|
if not code:
|
455
|
result = False
|
456
|
if result:
|
457
|
table.cellChanged.disconnect(self.cellValueChanged)
|
458
|
table.setRowCount(rowCount + 1)
|
459
|
table.setItem(rowCount, 0, QTableWidgetItem(''))
|
460
|
table.setItem(rowCount, 1, QTableWidgetItem(''))
|
461
|
table.setItem(rowCount, 2, QTableWidgetItem(''))
|
462
|
table.setItem(rowCount, 3, QTableWidgetItem(''))
|
463
|
table.cellChanged.connect(self.cellValueChanged)
|
464
|
else:
|
465
|
columnCount = table.columnCount()
|
466
|
|
467
|
for row in range(rowCount):
|
468
|
if not result:
|
469
|
break
|
470
|
for columnIndex in range(columnCount):
|
471
|
if not table.item(row, columnIndex).text():
|
472
|
result = False
|
473
|
break
|
474
|
|
475
|
if result:
|
476
|
table.setRowCount(rowCount + 1)
|
477
|
table.cellChanged.disconnect(self.cellValueChanged)
|
478
|
for columnIndex in range(columnCount):
|
479
|
table.setItem(rowCount, columnIndex, QTableWidgetItem(''))
|
480
|
table.cellChanged.connect(self.cellValueChanged)
|
481
|
|
482
|
except Exception as ex:
|
483
|
print('error occurred({}) in {}:{}'.format(ex, sys.exc_info()[-1].tb_frame.f_code.co_filename,
|
484
|
sys.exc_info()[-1].tb_lineno))
|
485
|
|
486
|
'''
|
487
|
@brief cellValueChange event
|
488
|
@author kyouho
|
489
|
@date 2018.07.10
|
490
|
'''
|
491
|
|
492
|
def cellValueChanged(self, row, column):
|
493
|
try:
|
494
|
tabText = self.getTabText()
|
495
|
|
496
|
table = self.findTableWidget(tabText)
|
497
|
|
498
|
if tabText != "NominalDiameter":
|
499
|
item = table.item(row, 1)
|
500
|
code = item.text()
|
501
|
if column == 1:
|
502
|
result = self.isExistCode(table, code)
|
503
|
if result:
|
504
|
self.checkRowAndAddRow(tabText, table)
|
505
|
self.setCurrentCode(table, tabText)
|
506
|
else:
|
507
|
QMessageBox.warning(self, self.tr('Notice'),
|
508
|
self.tr('The same code already exists in the table.'))
|
509
|
table.cellChanged.disconnect(self.cellValueChanged)
|
510
|
item.setText(self.currentCode[tabText][row])
|
511
|
table.cellChanged.connect(self.cellValueChanged)
|
512
|
elif column == 2:
|
513
|
table.resizeColumnToContents(2)
|
514
|
else:
|
515
|
table.resizeColumnToContents(3)
|
516
|
else:
|
517
|
self.checkRowAndAddRow(tabText, table)
|
518
|
except Exception as ex:
|
519
|
print('error occurred({}) in {}:{}'.format(ex, sys.exc_info()[-1].tb_frame.f_code.co_filename,
|
520
|
sys.exc_info()[-1].tb_lineno))
|
521
|
|
522
|
'''
|
523
|
@brief Check Duplicate Code
|
524
|
@author kyouho
|
525
|
@date 2018.07.10
|
526
|
'''
|
527
|
|
528
|
def isExistCode(self, table, editCode):
|
529
|
try:
|
530
|
if not editCode:
|
531
|
return False
|
532
|
|
533
|
rowCount = table.rowCount()
|
534
|
codes = []
|
535
|
for row in range(rowCount):
|
536
|
if table.isRowHidden(row): continue
|
537
|
code = table.item(row, 1).text()
|
538
|
codes.append(code)
|
539
|
|
540
|
count = codes.count(editCode)
|
541
|
|
542
|
if count >= 2:
|
543
|
return False
|
544
|
else:
|
545
|
return True
|
546
|
|
547
|
except Exception as ex:
|
548
|
print('error occurred({}) in {}:{}'.format(ex, sys.exc_info()[-1].tb_frame.f_code.co_filename,
|
549
|
sys.exc_info()[-1].tb_lineno))
|
550
|
|
551
|
'''
|
552
|
@brief save current Code (self.currentCode)
|
553
|
@author kyouho
|
554
|
@date 2018.07.10
|
555
|
'''
|
556
|
|
557
|
def setCurrentCode(self, table, tabText):
|
558
|
try:
|
559
|
self.currentCode[tabText] = {}
|
560
|
rowCount = table.rowCount()
|
561
|
|
562
|
res = {}
|
563
|
for row in range(rowCount):
|
564
|
code = table.item(row, 1).text()
|
565
|
res[row] = code
|
566
|
|
567
|
self.currentCode[tabText] = res
|
568
|
|
569
|
except Exception as ex:
|
570
|
print('error occurred({}) in {}:{}'.format(ex, sys.exc_info()[-1].tb_frame.f_code.co_filename,
|
571
|
sys.exc_info()[-1].tb_lineno))
|
572
|
|
573
|
'''
|
574
|
@brief replaceTextForCodeTable
|
575
|
@author kyouho
|
576
|
@date 2018.07.12
|
577
|
'''
|
578
|
|
579
|
def replaceText(self, text):
|
580
|
return text.replace(' ', '').replace('&&', 'n')
|
581
|
|
582
|
def import_code_table(self):
|
583
|
"""import code table excel file"""
|
584
|
|
585
|
options = QFileDialog.Options()
|
586
|
options |= QFileDialog.DontUseNativeDialog
|
587
|
file_name, _ = QFileDialog.getOpenFileName(self, "Import code table", os.getcwd(), "xlsx files(*.xlsx)",
|
588
|
options=options)
|
589
|
if file_name:
|
590
|
QApplication.setOverrideCursor(Qt.WaitCursor)
|
591
|
try:
|
592
|
app_doc_data = AppDocData.instance()
|
593
|
book = load_workbook(file_name)
|
594
|
for sheet in book.worksheets:
|
595
|
matches = [index for index in range(self.ui.tabWidget.count())
|
596
|
if sheet.title == self.ui.tabWidget.tabText(index)]
|
597
|
if matches:
|
598
|
table = self.ui.tabWidget.widget(matches[0]).findChild(QTableWidget)
|
599
|
self.fill_table_with_sheet(sheet, table)
|
600
|
except Exception as ex:
|
601
|
from App import App
|
602
|
message = 'error occurred({}) in {}:{}'.format(repr(ex), sys.exc_info()[-1].tb_frame.f_code.co_filename,
|
603
|
sys.exc_info()[-1].tb_lineno)
|
604
|
App.mainWnd().addMessage.emit(MessageType.Error, message)
|
605
|
finally:
|
606
|
QApplication.restoreOverrideCursor()
|
607
|
|
608
|
|
609
|
def export_code_table(self):
|
610
|
"""export code table to excel file"""
|
611
|
|
612
|
app_doc_data = AppDocData.instance()
|
613
|
project = app_doc_data.getCurrentProject()
|
614
|
|
615
|
options = QFileDialog.Options()
|
616
|
options |= QFileDialog.DontUseNativeDialog
|
617
|
file_name, _ = QFileDialog.getSaveFileName(self, "Export code table", project.path, "xlsx files(*.xlsx)",
|
618
|
options=options)
|
619
|
if not file_name:
|
620
|
return
|
621
|
|
622
|
QApplication.setOverrideCursor(Qt.WaitCursor)
|
623
|
|
624
|
try:
|
625
|
wb = Workbook()
|
626
|
wb.active.title = self.tr(self.ui.tabWidget.tabText(0))
|
627
|
for index in range(1, self.ui.tabWidget.count()):
|
628
|
wb.create_sheet(self.tr(self.ui.tabWidget.tabText(index)))
|
629
|
|
630
|
for index in range(self.ui.tabWidget.count()):
|
631
|
tab = self.ui.tabWidget.widget(index)
|
632
|
table = tab.findChild(QTableWidget)
|
633
|
if table:
|
634
|
sheet = wb.worksheets[index]
|
635
|
self.set_sheet_header(table, sheet)
|
636
|
self.fill_sheet_with_table(table, sheet)
|
637
|
self.auto_resize_columns(sheet)
|
638
|
|
639
|
file_name, ext = os.path.splitext(file_name)
|
640
|
save_file_name = file_name + ext if ext.upper() == '.XLSX' else file_name + '.xlsx'
|
641
|
wb.save(save_file_name)
|
642
|
|
643
|
QMessageBox.about(self, self.tr("Information"), self.tr('Successfully saved.'))
|
644
|
|
645
|
os.startfile(save_file_name)
|
646
|
except Exception as ex:
|
647
|
from App import App
|
648
|
from AppDocData import MessageType
|
649
|
|
650
|
message = 'error occurred({}) in {}:{}'.format(repr(ex), sys.exc_info()[-1].tb_frame.f_code.co_filename,
|
651
|
sys.exc_info()[-1].tb_lineno)
|
652
|
App.mainWnd().addMessage.emit(MessageType.Error, message)
|
653
|
finally:
|
654
|
QApplication.restoreOverrideCursor()
|
655
|
|
656
|
def set_sheet_header(self, table, sheet):
|
657
|
""" set list header """
|
658
|
|
659
|
try:
|
660
|
thin = Side(border_style='thin', color='000000')
|
661
|
border = Border(left=thin, right=thin, top=thin, bottom=thin)
|
662
|
_col = 1
|
663
|
for col in range(table.columnCount()):
|
664
|
logical_index = table.horizontalHeader().logicalIndex(col)
|
665
|
col_name = table.horizontalHeaderItem(logical_index).text()
|
666
|
sheet.cell(1, _col, col_name)
|
667
|
sheet.cell(row=1, column=_col).alignment = Alignment(horizontal='center', vertical='center',
|
668
|
wrapText=True)
|
669
|
sheet.cell(row=1, column=_col).fill = PatternFill(patternType='solid', fill_type='solid',
|
670
|
fgColor=Color('8DB4E2'))
|
671
|
sheet.cell(row=1, column=_col).border = border
|
672
|
_col += 1
|
673
|
except Exception as ex:
|
674
|
from App import App
|
675
|
from AppDocData import MessageType
|
676
|
|
677
|
message = 'error occurred({}) in {}:{}'.format(ex, sys.exc_info()[-1].tb_frame.f_code.co_filename,
|
678
|
sys.exc_info()[-1].tb_lineno)
|
679
|
App.mainWnd().addMessage.emit(MessageType.Error, message)
|
680
|
|
681
|
def fill_table_with_sheet(self, sheet, table):
|
682
|
"""fill table with sheet"""
|
683
|
from NominalPipeSize import NominalPipeSize
|
684
|
|
685
|
try:
|
686
|
row_index = 0
|
687
|
headers = {}
|
688
|
if sheet.title == 'Nominal Diameter':
|
689
|
pipe_sizes = []
|
690
|
for row in sheet.rows:
|
691
|
if row_index == 0:
|
692
|
for col in range(sheet.max_column):
|
693
|
value = row[col].value
|
694
|
headers[col] = value
|
695
|
else:
|
696
|
pipe_size = NominalPipeSize(None, None, None, None, None, None, None, None)
|
697
|
for col in range(sheet.max_column):
|
698
|
value = row[col].value
|
699
|
if 'UID' == headers[col]:
|
700
|
pipe_size.uid = value
|
701
|
elif 'Code' == headers[col]:
|
702
|
pipe_size.code = value
|
703
|
elif 'Metric' == headers[col]:
|
704
|
pipe_size.metric = value
|
705
|
elif 'Inch' == headers[col]:
|
706
|
pipe_size.inch = value
|
707
|
elif 'InchStr' == headers[col]:
|
708
|
pipe_size.inchStr = value
|
709
|
elif 'Inch Allowables' == headers[col]:
|
710
|
pipe_size.allowable_inch_str = value
|
711
|
elif 'MetricStr' == headers[col]:
|
712
|
pipe_size.metricStr = value
|
713
|
elif 'Metric Allowables' == headers[col]:
|
714
|
pipe_size.allowable_metric_str = value
|
715
|
|
716
|
pipe_sizes.append(pipe_size)
|
717
|
|
718
|
row_index += 1
|
719
|
|
720
|
self.fill_nominal_pipe_sizes(pipe_sizes)
|
721
|
else:
|
722
|
codes = []
|
723
|
for row in sheet.rows:
|
724
|
if row_index == 0:
|
725
|
for col in range(sheet.max_column):
|
726
|
value = row[col].value
|
727
|
headers[col] = value
|
728
|
else:
|
729
|
code = [row[col].value for col in range(sheet.max_column)]
|
730
|
codes.append(code)
|
731
|
|
732
|
row_index += 1
|
733
|
|
734
|
self.fill_codes(table, codes)
|
735
|
except Exception as ex:
|
736
|
from App import App
|
737
|
from AppDocData import MessageType
|
738
|
|
739
|
message = 'error occurred({}) in {}:{}'.format(ex, sys.exc_info()[-1].tb_frame.f_code.co_filename,
|
740
|
sys.exc_info()[-1].tb_lineno)
|
741
|
App.mainWnd().addMessage.emit(MessageType.Error, message)
|
742
|
|
743
|
def fill_sheet_with_table(self, table, sheet):
|
744
|
"""fill sheet with table"""
|
745
|
|
746
|
try:
|
747
|
thin = Side(border_style='thin', color='000000')
|
748
|
border = Border(left=thin, right=thin, top=thin, bottom=thin)
|
749
|
|
750
|
for col in range(table.columnCount()):
|
751
|
for row in range(table.rowCount()):
|
752
|
try:
|
753
|
text = str(table.item(row, col).text())
|
754
|
sheet.cell(row + 2, col + 1, text)
|
755
|
sheet.cell(row=row + 2, column=col + 1).border = border
|
756
|
except AttributeError:
|
757
|
pass
|
758
|
except Exception as ex:
|
759
|
from App import App
|
760
|
from AppDocData import MessageType
|
761
|
|
762
|
message = 'error occurred({}) in {}:{}'.format(ex, sys.exc_info()[-1].tb_frame.f_code.co_filename,
|
763
|
sys.exc_info()[-1].tb_lineno)
|
764
|
App.mainWnd().addMessage.emit(MessageType.Error, message)
|
765
|
|
766
|
def auto_resize_columns(self, sheet):
|
767
|
""" auto resize columns with contents """
|
768
|
|
769
|
from openpyxl.utils import get_column_letter
|
770
|
try:
|
771
|
for col in sheet.columns:
|
772
|
max_length = 0
|
773
|
column = col[0].column
|
774
|
for cell in col:
|
775
|
try:
|
776
|
if len(str(cell.value)) > max_length:
|
777
|
max_length = len(cell.value)
|
778
|
except:
|
779
|
pass
|
780
|
|
781
|
adjusted_width = (max_length + 2) * 1.2
|
782
|
sheet.column_dimensions[
|
783
|
get_column_letter(column) if type(column) is int else column].width = adjusted_width
|
784
|
except Exception as ex:
|
785
|
from App import App
|
786
|
from AppDocData import MessageType
|
787
|
|
788
|
message = 'error occurred({}) in {}:{}'.format(repr(ex), sys.exc_info()[-1].tb_frame.f_code.co_filename,
|
789
|
sys.exc_info()[-1].tb_lineno)
|
790
|
App.mainWnd().addMessage.emit(MessageType.Error, message)
|
791
|
|
792
|
'''
|
793
|
@brief save codes
|
794
|
@author kyouho
|
795
|
@date 2018.07.12
|
796
|
'''
|
797
|
|
798
|
def accept(self):
|
799
|
from CodeTables import CodeTable
|
800
|
for table in QCodeTableDialog.CODE_TABLES:
|
801
|
if table != 'Nominal Diameter':
|
802
|
self.saveCommonCodeData(table)
|
803
|
|
804
|
self.saveNomialPipeSize()
|
805
|
CodeTable.clearTables()
|
806
|
|
807
|
QDialog.accept(self)
|
808
|
|
809
|
'''
|
810
|
@brief save common code data
|
811
|
@author kyouho
|
812
|
@date 2018.07.12
|
813
|
'''
|
814
|
|
815
|
def saveCommonCodeData(self, tableName):
|
816
|
datas = []
|
817
|
try:
|
818
|
tableName = self.replaceText(tableName)
|
819
|
table = self.findTableWidget(tableName)
|
820
|
rowCount = table.rowCount()
|
821
|
for row in range(rowCount):
|
822
|
if table.isRowHidden(row):
|
823
|
uid, code, description, allowables = '-1', table.item(row, 1).text(), '', table.item(row, 0).text()
|
824
|
elif table.item(row, 0):
|
825
|
uid = table.item(row, 0).text()
|
826
|
code = table.item(row, 1).text()
|
827
|
description = table.item(row, 2).text() if table.item(row, 2) is not None else ''
|
828
|
allowables = table.item(row, 3).text() if table.item(row, 3) is not None else ''
|
829
|
|
830
|
if code:
|
831
|
datas.append((uid, code, description, allowables))
|
832
|
|
833
|
docData = AppDocData.instance()
|
834
|
docData.saveCommonCodeData(tableName.replace(' ', ''), datas)
|
835
|
except Exception as ex:
|
836
|
from App import App
|
837
|
|
838
|
message = 'error occurred({}) in {}:{}'.format(ex, sys.exc_info()[-1].tb_frame.f_code.co_filename,
|
839
|
sys.exc_info()[-1].tb_lineno)
|
840
|
App.mainWnd().addMessage.emit(MessageType.Error, message)
|
841
|
|
842
|
'''
|
843
|
@brief save common code data
|
844
|
@author kyouho
|
845
|
@date 2018.07.16
|
846
|
'''
|
847
|
|
848
|
def saveNomialPipeSize(self):
|
849
|
pipeSizes = []
|
850
|
try:
|
851
|
docData = AppDocData.instance()
|
852
|
|
853
|
from NominalPipeSize import NominalPipeSize
|
854
|
|
855
|
table = self.ui.tableWidgetNominalDiameter
|
856
|
rowCount = table.rowCount()
|
857
|
for row in range(rowCount):
|
858
|
pipe_size = table.item(row, 0).data(Qt.UserRole)
|
859
|
pipe_size.code = table.item(row, 1).text()
|
860
|
pipe_size.metric = float(table.item(row, 2).text()) if table.item(row, 2).text() != '' else None
|
861
|
pipe_size.inch = float(table.item(row, 3).text()) if table.item(row, 3).text() != '' else None
|
862
|
pipe_size.inchStr = table.item(row, 4).text()
|
863
|
pipe_size.allowable_inch_str = table.item(row, 5).text()
|
864
|
pipe_size.metricStr = table.item(row, 6).text()
|
865
|
pipe_size.allowable_metric_str = table.item(row, 7).text()
|
866
|
pipeSizes.append(pipe_size)
|
867
|
|
868
|
docData.insertNomialPipeSize(pipeSizes)
|
869
|
|
870
|
except Exception as ex:
|
871
|
from App import App
|
872
|
|
873
|
message = 'error occurred({}) in {}:{}'.format(ex, sys.exc_info()[-1].tb_frame.f_code.co_filename,
|
874
|
sys.exc_info()[-1].tb_lineno)
|
875
|
App.mainWnd().addMessage.emit(MessageType.Error, message)
|