프로젝트

일반

사용자정보

통계
| 개정판:

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)
클립보드 이미지 추가 (최대 크기: 500 MB)