프로젝트

일반

사용자정보

통계
| 개정판:

hytos / DTI_PID / DTI_PID / CodeTableDialog.py @ d221ad0d

이력 | 보기 | 이력해설 | 다운로드 (38.9 KB)

1
# coding: utf-8
2
"""
3
    This is code table dialog module
4
"""
5
import os
6
import sys, io
7
from PyQt5.QtCore import *
8
from PyQt5.QtGui import *
9
from PyQt5.QtWidgets import *
10
from AppDocData import AppDocData, MessageType
11
from App import App
12
from openpyxl import *
13
from openpyxl.styles import *
14

    
15
from PIL import Image
16
import tesseract_ocr_module as TOCR
17
import numpy as np
18

    
19
import CodeTable_UI
20
import FenceCommand
21
from GraphicsBoundingBoxItem import QGraphicsBoundingBoxItem
22

    
23
class QCodeTableDialog(QDialog):
24
    """ This code table dialog class """
25

    
26
    CODE_TABLES = (
27
    'Nominal Diameter', 'Fluid Code', 'Insulation Purpose', 'PnID Number', 'Piping Materials Class', 'Unit Number',
28
    'ValveOperCodes', 'EqpTagNames', 'ReservedWords', 'Dictionary')
29

    
30
    def __init__(self, parent, child_dialog=''):
31
        QDialog.__init__(self, parent)
32

    
33
        self.currentCode = {}
34

    
35
        self.code_area = None
36
        self.desc_area = None
37

    
38
        self.child_dialog = child_dialog
39
        if not child_dialog:
40
            self.ui = CodeTable_UI.Ui_CodeTableDialog()
41
            self.ui.setupUi(self)
42

    
43
            # unused : valve oper code, eq tag, reserved table
44
            self.ui.tabWidget.removeTab(8)
45
            self.ui.tabWidget.removeTab(7)
46
            self.ui.tabWidget.removeTab(6)
47

    
48
            self.ui.spinBoxHeight.setValue(50)
49

    
50
            self.ui.tableWidgetNominalDiameter.setSortingEnabled(True)
51
            self.ui.tableWidgetFluidCode.setSortingEnabled(True)
52
            self.ui.tableWidgetInsulationPurpose.setSortingEnabled(True)
53
            self.ui.tableWidgetPnIDNumber.setSortingEnabled(True)
54
            self.ui.tableWidgetPipingMaterialsClass.setSortingEnabled(True)
55
            self.ui.tableWidgetUnitNumber.setSortingEnabled(True)
56
            self.ui.tableWidgetValveOperCodes.setSortingEnabled(True)
57
            self.ui.tableWidgetEqpTagNames.setSortingEnabled(True)
58
            self.ui.tableWidgetReservedWords.setSortingEnabled(True)
59

    
60
            # DB Table명 기준으로 작성
61
            for table in QCodeTableDialog.CODE_TABLES:
62
                self.settingTable(table)
63

    
64
            # connect signals
65
            self.ui.pushButtonImport.clicked.connect(self.import_code_table)
66
            self.ui.pushButtonExport.clicked.connect(self.export_code_table)
67
            self.ui.pushButtonRead.clicked.connect(self.read_from_legend)
68

    
69
        self.graphicsView = App.mainWnd().graphicsView
70
        self.fence_cmd = FenceCommand.FenceCommand(self.graphicsView)
71
        self.fence_cmd.onSuccess.connect(self.onAreaCreated)
72

    
73
    def getTabText(self):
74
        """ get current tab name text """
75
        if not self.child_dialog:
76
            _tabWidget = self.ui.tabWidget
77
            currentTabIndex = _tabWidget.currentIndex()
78
            tabText = self.replaceText(_tabWidget.tabText(currentTabIndex))
79
        else:
80
            tabText = self.child_dialog
81
        return tabText
82

    
83
    def read_from_legend(self):
84
        """ read code data from legend drawing """
85
        if self.ui.pushButtonRead.text() == 'Read from Legend':
86
            self.graphicsView.command = self.fence_cmd
87
            self.ui.pushButtonRead.setText('Draw Code Area')
88
        elif self.ui.pushButtonRead.text() == 'Read' and self.code_area and self.code_area.scene() and self.desc_area and self.desc_area.scene():
89
            # read ocr
90
            code_rect = self.code_area.sceneBoundingRect()
91
            desc_rect = self.desc_area.sceneBoundingRect()
92
            code_img = self.graphicsView.image().copy(code_rect.x(), code_rect.y(), code_rect.width(), code_rect.height())
93
            desc_img = self.graphicsView.image().copy(desc_rect.x(), desc_rect.y(), desc_rect.width(), desc_rect.height())
94
            code_texts = self.detectText(code_img, code_rect)
95
            desc_texts = self.detectText(desc_img, desc_rect)
96

    
97
            # check validate
98
            for code_text in code_texts:
99
                code_text.desc = []
100

    
101
            if desc_texts:
102
                for desc_index in reversed(range(len(desc_texts))):
103
                    for code_index in range(len(code_texts)):
104
                        if abs(desc_texts[desc_index].center[1] - code_texts[code_index].center[1]) < round(self.ui.spinBoxHeight.value() / 2):
105
                            code_texts[code_index].desc.append(desc_texts[desc_index])
106
                            desc_texts.pop(desc_index)
107
                            break
108

    
109
                for desc_index in reversed(range(len(desc_texts))):
110
                    min_distance = sys.maxsize
111
                    min_code = None
112
                    for code_index in range(len(code_texts)):
113
                        distance = desc_texts[desc_index].center[1] - code_texts[code_index].center[1]
114
                        if distance > 0 and distance < min_distance:
115
                            min_distance = distance
116
                            min_code = code_texts[code_index]
117

    
118
                    if min_code:
119
                        min_code.desc.append(desc_texts[desc_index])
120
                        desc_texts.pop(desc_index)
121
                    
122

    
123
                #QMessageBox.warning(self, self.tr('Notice'), self.tr('Please check text area.'))
124
                #return  
125

    
126
            desc_texts = []
127
            for code_text in code_texts:
128
                desc = ' '.join([desc.getText() for desc in sorted(code_text.desc, key=lambda desc: desc.center[1])])
129
                desc_texts.append(desc)
130

    
131
            # fill table
132
            tabText = self.getTabText()
133

    
134
            if tabText == 'NominalDiameter':
135
                return
136
            table = self.findTableWidget(tabText)
137

    
138
            table.cellChanged.disconnect(self.cellValueChanged)
139
            
140
            past_count = table.rowCount()
141
            for row_index in range(past_count):
142
                for code_index in reversed(range(len(code_texts))):
143
                    if table.isRowHidden(row_index): continue
144
                    if table.item(row_index, 1) and table.item(row_index, 1).text() == code_texts[code_index].getText():
145
                        table.setItem(row_index, 2, QTableWidgetItem(desc_texts[code_index]))
146
                        code_texts.pop(code_index)
147
                        desc_texts.pop(code_index)
148
                        break
149
            table.setRowCount(past_count + len(code_texts))
150
            for code_index in range(len(code_texts)):
151
                table.setItem(past_count + code_index - 1, 0, QTableWidgetItem(''))
152
                table.setItem(past_count + code_index - 1, 1, QTableWidgetItem(code_texts[code_index].getText()))
153
                table.setItem(past_count + code_index - 1, 2, QTableWidgetItem(desc_texts[code_index]))
154
                if self.ui.checkBoxAllowable.isChecked():
155
                    table.setItem(past_count + code_index - 1, 3, QTableWidgetItem(self.makeAllowable(code_texts[code_index].getText())))
156

    
157
            last_empty_row = table.rowCount()
158
            table.setItem(last_empty_row - 1, 0, QTableWidgetItem(''))
159
            table.setItem(last_empty_row - 1, 1, QTableWidgetItem(''))
160
            table.setItem(last_empty_row - 1, 2, QTableWidgetItem(''))
161

    
162
            table.cellChanged.connect(self.cellValueChanged)
163

    
164
            if self.code_area:
165
                if self.code_area.scene():
166
                    self.graphicsView.scene().removeItem(self.code_area)
167
                self.code_area = None
168
            if self.desc_area:
169
                if self.desc_area.scene():
170
                    self.graphicsView.scene().removeItem(self.desc_area)
171
                self.desc_area = None
172
            self.ui.pushButtonRead.setText('Read from Legend')
173
        else:
174
            if self.code_area:
175
                if self.code_area.scene():
176
                    self.graphicsView.scene().removeItem(self.code_area)
177
                self.code_area = None
178
            if self.desc_area:
179
                if self.desc_area.scene():
180
                    self.graphicsView.scene().removeItem(self.desc_area)
181
                self.desc_area = None
182
            self.ui.pushButtonRead.setText('Read from Legend')
183

    
184
    def onAreaCreated(self, x, y , width, height):
185
        import uuid
186
        THICKNESS = 5
187

    
188
        if self.ui.pushButtonRead.text() == 'Draw Code Area':
189
            item = QGraphicsBoundingBoxItem(x, y, width, height)
190
            item.setPen(QPen(Qt.red, THICKNESS, Qt.SolidLine))
191
            self.graphicsView.scene().addItem(item)
192
            self.code_area = item
193
            self.ui.pushButtonRead.setText('Draw Description Area')
194
        elif self.ui.pushButtonRead.text() == 'Draw Description Area' and self.code_area and self.code_area.scene():
195
            item = QGraphicsBoundingBoxItem(x, y, width, height)
196
            item.setPen(QPen(Qt.blue, THICKNESS, Qt.SolidLine))
197
            self.graphicsView.scene().addItem(item)
198
            self.desc_area = item
199
            self.ui.pushButtonRead.setText('Read')
200
            self.graphicsView.command = None
201

    
202
    def detectText(self, image, rect):
203
        """ detect text from image, come from OcrResultDialog and modified """
204
        try:
205
            buffer = QBuffer()
206
            buffer.open(QBuffer.ReadWrite)
207
            image.save(buffer, "PNG")
208
            pyImage = Image.open(io.BytesIO(buffer.data()))
209
            img = np.array(pyImage)
210
            
211
            docData = AppDocData.instance()
212
            configs = docData.getConfigs('Text Recognition', 'OCR Data')
213
            ocr_data = configs[0].value if 1 == len(configs) else 'eng'
214

    
215
            whiteCharList = docData.getConfigs('Text Recognition', 'White Character List')
216
            if len(whiteCharList) is 0:
217
                textInfoList = TOCR.getTextInfo(img, (round(rect.x()), round(rect.y())), 0, language=ocr_data)
218
            else:
219
                textInfoList = TOCR.getTextInfo(img, (round(rect.x()), round(rect.y())), 0, language=ocr_data, conf = whiteCharList[0].value)
220

    
221
            if textInfoList is not None and len(textInfoList) > 0:
222
                return textInfoList
223
        except Exception as ex:
224
            from App import App 
225
            message = 'error occurred({}) in {}:{}'.format(ex, sys.exc_info()[-1].tb_frame.f_code.co_filename, sys.exc_info()[-1].tb_lineno)
226
            App.mainWnd().addMessage.emit(MessageType.Error, message)
227

    
228
    '''
229
        @brief      Setting Table
230
        @author     kyouho
231
        @date       2018.07.10
232
    '''
233

    
234
    def settingTable(self, tableName, symbol_attribute_uid=None, custom_table_uid=None, tableDatas=None):
235
        try:
236
            tableName = self.replaceText(tableName)
237
            docData = AppDocData.instance()
238
            table = self.findTableWidget(tableName)
239
            if table: table.horizontalHeader().setStretchLastSection(True)
240
            if tableName == "NominalDiameter":
241
                tableDatas = docData.getNomialPipeSizeData()
242
            elif tableName == "SymbolAttributeCodeTable":
243
                if tableDatas is None:
244
                    tableDatas = docData.getCodeTable(tableName, forCheckLineNumber=False, symbol_attribute_uid=symbol_attribute_uid)
245
                else:
246
                    pass
247
            elif tableName == 'CustomCodes':
248
                if tableDatas is None:
249
                    tableDatas = docData.getCodeTable(tableName, forCheckLineNumber=False, custom_table_uid=symbol_attribute_uid)
250
                else:
251
                    pass
252
            else:
253
                tableDatas = docData.getCodeTable(tableName)
254

    
255
            if tableName == "NominalDiameter":
256
                self.fill_nominal_pipe_sizes(tableDatas)
257

    
258
                table.cellChanged.connect(self.cellValueChanged)
259
                self.checkRowAndAddRow(tableName, table)
260
            else:
261
                table.setColumnCount(4)
262
                table.setHorizontalHeaderLabels(['UID', 'Code', 'Desc.', 'Allowables'])
263
                table.hideColumn(0)
264

    
265
                self.fill_codes(table, tableDatas)
266

    
267
                table.horizontalHeaderItem(1).setSizeHint(QSize(30, 30))
268
                table.cellChanged.connect(self.cellValueChanged)
269
                self.checkRowAndAddRow(tableName, table)
270
                self.setCurrentCode(table, tableName)
271
        except Exception as ex:
272
            print('error occurred({}) in {}:{}'.format(ex, sys.exc_info()[-1].tb_frame.f_code.co_filename,
273
                                                       sys.exc_info()[-1].tb_lineno))
274

    
275
    '''
276
        @brief      Insert row NominalPipeSzie Tablewidget
277
        @author     kyouho
278
        @date       2018.07.10
279
    '''
280

    
281
    def fill_nominal_pipe_sizes(self, pipeSizes):
282
        try:
283
            self.ui.tableWidgetNominalDiameter.setColumnCount(8)
284
            self.ui.tableWidgetNominalDiameter.setHorizontalHeaderLabels(
285
                ['UID', 'Code', 'Metric', 'Inch', 'InchStr', 'Inch Allowables', 'MetricStr', 'Metric Allowables'])
286
            self.ui.tableWidgetNominalDiameter.hideColumn(0)
287
            self.ui.tableWidgetNominalDiameter.setRowCount(len(pipeSizes))
288
            row = 0
289
            for pipeSize in pipeSizes:
290
                item = QTableWidgetItem(pipeSize.uid)
291
                item.setData(Qt.UserRole, pipeSize)
292
                self.ui.tableWidgetNominalDiameter.setItem(row, 0, item)
293
                self.ui.tableWidgetNominalDiameter.setItem(row, 1, QTableWidgetItem(pipeSize.code))
294
                self.ui.tableWidgetNominalDiameter.setItem(row, 2, QTableWidgetItem(
295
                    '' if pipeSize.metric is None else str(pipeSize.metric)))
296
                self.ui.tableWidgetNominalDiameter.setItem(row, 3, QTableWidgetItem(
297
                    '' if pipeSize.inch is None else str(pipeSize.inch)))
298
                self.ui.tableWidgetNominalDiameter.setItem(row, 4, QTableWidgetItem(
299
                    '' if pipeSize.inchStr is None else pipeSize.inchStr))
300
                self.ui.tableWidgetNominalDiameter.setItem(row, 5, QTableWidgetItem(
301
                    '' if pipeSize.allowable_inch_str is None else pipeSize.allowable_inch_str))
302
                self.ui.tableWidgetNominalDiameter.setItem(row, 6, QTableWidgetItem(
303
                    '' if pipeSize.metricStr is None else pipeSize.metricStr))
304
                self.ui.tableWidgetNominalDiameter.setItem(row, 7, QTableWidgetItem(
305
                    '' if pipeSize.allowable_metric_str is None else pipeSize.allowable_metric_str))
306
                row += 1
307

    
308
            self.ui.tableWidgetNominalDiameter.horizontalHeaderItem(0).setSizeHint(QSize(30, 30))
309
        except Exception as ex:
310
            from App import App
311

    
312
            message = 'error occurred({}) in {}:{}'.format(ex, sys.exc_info()[-1].tb_frame.f_code.co_filename,
313
                                                           sys.exc_info()[-1].tb_lineno)
314
            App.mainWnd().addMessage.emit(MessageType.Error, message)
315

    
316
    '''
317
        @brief      Insert row Common Tablewidget
318
        @author     kyouho
319
        @date       2018.07.10
320
    '''
321

    
322
    def fill_codes(self, table, tableDatas):
323
        try:
324
            table.setRowCount(len(tableDatas))
325
            row = 0
326
            for tableData in tableDatas:
327
                table.setItem(row, 0, QTableWidgetItem(tableData[0]))  # UID
328
                table.setItem(row, 1, QTableWidgetItem(tableData[1]))  # Name
329
                table.setItem(row, 2, QTableWidgetItem(tableData[2] if tableData[2] else ''))  # Description
330
                table.setItem(row, 3, QTableWidgetItem((tableData[3] if type(tableData[3]) is str else ','.join(tableData[3])) \
331
                                                                            if tableData[3] else ''))  # Allowables
332
                row += 1
333
        except Exception as ex:
334
            from App import App
335

    
336
            message = 'error occurred({}) in {}:{}'.format(ex, sys.exc_info()[-1].tb_frame.f_code.co_filename,
337
                                                           sys.exc_info()[-1].tb_lineno)
338
            App.mainWnd().addMessage.emit(MessageType.Error, message)
339

    
340
    '''
341
        @brief      Find TableWidget with Name
342
        @author     kyouhokyouho
343
        @date       2018.07.10
344
    '''
345

    
346
    def findTableWidget(self, tableName):
347
        tableName = self.replaceText(tableName)
348
        return self.findChild(QTableWidget, 'tableWidget' + tableName)
349

    
350
    '''
351
        @brief      key press event
352
        @author     kyouho
353
        @date       2018.07.10
354
    '''
355

    
356
    def keyPressEvent(self, e):
357
        try:
358
            if e.key() == Qt.Key_Delete:
359
                tabText = self.getTabText()
360
                
361
                table = self.findTableWidget(tabText)
362
                if table:
363
                    selectedIndexes = table.selectedIndexes()
364
                    selectedRows = [item.row() for item in selectedIndexes]
365
                    model = table.model()
366

    
367
                    rowsIndex = []
368
                    for row in selectedRows:
369
                        rowsIndex.append(row)
370

    
371
                    # 중복 제거
372
                    rowsIndex = list(set(rowsIndex))
373
                    rowsIndex.reverse()
374

    
375
                    if tabText != "NominalDiameter":
376
                        for row in rowsIndex:
377
                            table.hideRow(row)
378
                            """
379
                            uid = table.item(row, 0).text()
380
                            self.removeUID[uid] = tabText
381
                            model.removeRow(row)
382
                            """
383

    
384
                        self.checkRowAndAddRow(tabText, table)
385
            elif (e.key() == Qt.Key_C) and (e.modifiers() & Qt.ControlModifier):
386
                tabText = self.getTabText()
387
                
388
                table = self.findTableWidget(tabText)
389
                if table:
390
                    self.copy_selection(table)
391
            elif (e.key() == Qt.Key_V) and (e.modifiers() & Qt.ControlModifier):
392
                tabText = self.getTabText()
393
                '''
394
                table = self.findTableWidget(tabText)
395
                tab = self.ui.tabWidget.widget(self.ui.tabWidget.currentIndex())
396
                table = tab.findChild(QTableWidget)
397
                '''
398
                table = self.findTableWidget(tabText)
399
                if table:
400
                    self.paste_selection(table)
401
        except Exception as ex:
402
            from App import App
403
            message = 'error occurred({}) in {}:{}'.format(repr(ex), sys.exc_info()[-1].tb_frame.f_code.co_filename,
404
                                                           sys.exc_info()[-1].tb_lineno)
405
            App.mainWnd().addMessage.emit(MessageType.Error, message)
406

    
407
    def copy_selection(self, table_widget):
408
        """copy selected text to clipboard"""
409

    
410
        import io
411
        import csv
412

    
413
        selection = table_widget.selectedIndexes()
414
        if selection:
415
            rows = sorted(index.row() for index in selection)
416
            columns = sorted(index.column() for index in selection)
417
            rowcount = rows[-1] - rows[0] + 1
418
            colcount = columns[-1] - columns[0] + 1
419
            table = [[''] * colcount for _ in range(rowcount)]
420
            for index in selection:
421
                row = index.row() - rows[0]
422
                column = index.column() - columns[0]
423
                table[row][column] = index.data()
424
            stream = io.StringIO()
425
            csv.writer(stream, delimiter='\t').writerows(table)
426
            QApplication.clipboard().setText(stream.getvalue())
427

    
428
    def paste_selection(self, table_widget):
429
        """paste text of clipboard to table widget"""
430

    
431
        import io
432
        import csv
433

    
434
        selection = table_widget.selectedIndexes()
435
        if selection:
436
            model = table_widget.model()
437

    
438
            buffer = QApplication.clipboard().text()
439
            rows = sorted(index.row() for index in selection)
440
            columns = sorted(index.column() for index in selection)
441
            reader = csv.reader(io.StringIO(buffer), delimiter='\t')
442
            if len(rows) == 1 and len(columns) == 1:
443
                for i, line in enumerate(reader):
444
                    for j, cell in enumerate(line):
445
                        model.setData(model.index(rows[0] + i, columns[0] + j), cell)
446
            else:
447
                arr = [[cell for cell in row] for row in reader]
448
                for index in selection:
449
                    row = index.row() - rows[0]
450
                    column = index.column() - columns[0]
451
                    model.setData(model.index(index.row(), index.column()), arr[row][column])
452

    
453
    '''
454
        @brief      Add new row
455
        @author     kyouho
456
        @date       2018.07.10
457
    '''
458

    
459
    def checkRowAndAddRow(self, tableName, table):
460
        try:
461
            rowCount = table.rowCount()
462
            result = True
463
            if tableName != "NominalDiameter":
464
                for row in range(rowCount):
465
                    if table.isRowHidden(row): continue
466
                    code = table.item(row, 1).text()
467
                    if not code:
468
                        result = False
469
                if result:
470
                    table.cellChanged.disconnect(self.cellValueChanged)
471
                    table.setRowCount(rowCount + 1)
472
                    table.setItem(rowCount, 0, QTableWidgetItem(''))
473
                    table.setItem(rowCount, 1, QTableWidgetItem(''))
474
                    table.setItem(rowCount, 2, QTableWidgetItem(''))
475
                    table.setItem(rowCount, 3, QTableWidgetItem(''))
476
                    table.cellChanged.connect(self.cellValueChanged)
477
            else:
478
                columnCount = table.columnCount()
479

    
480
                for row in range(rowCount):
481
                    if not result:
482
                        break
483
                    for columnIndex in range(columnCount):
484
                        if not table.item(row, columnIndex).text():
485
                            result = False
486
                            break
487

    
488
                if result:
489
                    table.setRowCount(rowCount + 1)
490
                    table.cellChanged.disconnect(self.cellValueChanged)
491
                    for columnIndex in range(columnCount):
492
                        table.setItem(rowCount, columnIndex, QTableWidgetItem(''))
493
                    table.cellChanged.connect(self.cellValueChanged)
494

    
495
        except Exception as ex:
496
            print('error occurred({}) in {}:{}'.format(ex, sys.exc_info()[-1].tb_frame.f_code.co_filename,
497
                                                       sys.exc_info()[-1].tb_lineno))
498

    
499
    def makeAllowable(self, code):
500
        ''' make allowable for code '''
501
        import re
502

    
503
        founds = []
504
        code_ori = code
505
        app_doc_data = AppDocData.instance()
506
        configs = app_doc_data.getConfigs('Text Recognition', 'Allowable Pair')
507

    
508
        pair = configs[0].value if 1 == len(configs) else "1Il, 0OD, 8B, 2Z, Ss5"
509
        pair = pair.replace(' ', '').split(',')
510
        allowable_list = [list(text) for text in pair]
511
        for allowables in allowable_list:                
512
            f = '(' + '|'.join(allowables) + ')'
513
            for chars in re.finditer(f, code):
514
                founds.append((chars.start(), chars.end(), f))
515

    
516
        founds = sorted(founds, key=lambda param:param[0], reverse=True)
517
        for found in founds:
518
            code = code[:found[0]] + found[2] + code[found[0] + 1:]
519

    
520
        if code_ori != code:
521
            return code
522
        else:
523
            return ''
524

    
525
    '''
526
        @brief      cellValueChange event
527
        @author     kyouho
528
        @date       2018.07.10
529
    '''
530
    def cellValueChanged(self, row, column):
531
        try:
532
            tabText = self.getTabText()
533

    
534
            table = self.findTableWidget(tabText)
535

    
536
            if tabText != "NominalDiameter":
537
                item = table.item(row, 1)
538
                code = item.text()
539
                if column == 1:
540
                    result = self.isExistCode(table, code)
541
                    if result:
542
                        self.checkRowAndAddRow(tabText, table)
543
                        self.setCurrentCode(table, tabText)
544

    
545
                        # make allowable
546
                        if self.ui.checkBoxAllowable.isChecked():
547
                            table.setItem(row, 3, QTableWidgetItem(self.makeAllowable(code)))                            
548
                    else:
549
                        QMessageBox.warning(self, self.tr('Notice'),
550
                                            self.tr('The same code already exists in the table.'))
551
                        table.cellChanged.disconnect(self.cellValueChanged)
552
                        item.setText(self.currentCode[tabText][row])
553
                        table.cellChanged.connect(self.cellValueChanged)
554
                elif column == 2:
555
                    table.resizeColumnToContents(2)
556
                else:
557
                    table.resizeColumnToContents(3)
558
            else:
559
                self.checkRowAndAddRow(tabText, table)
560
        except Exception as ex:
561
            print('error occurred({}) in {}:{}'.format(ex, sys.exc_info()[-1].tb_frame.f_code.co_filename,
562
                                                       sys.exc_info()[-1].tb_lineno))
563

    
564
    '''
565
        @brief      Check Duplicate Code 
566
        @author     kyouho
567
        @date       2018.07.10
568
    '''
569

    
570
    def isExistCode(self, table, editCode):
571
        try:
572
            if not editCode:
573
                return False
574

    
575
            rowCount = table.rowCount()
576
            codes = []
577
            for row in range(rowCount):
578
                if table.isRowHidden(row): continue
579
                code = table.item(row, 1).text()
580
                codes.append(code)
581

    
582
            count = codes.count(editCode)
583

    
584
            if count >= 2:
585
                return False
586
            else:
587
                return True
588

    
589
        except Exception as ex:
590
            print('error occurred({}) in {}:{}'.format(ex, sys.exc_info()[-1].tb_frame.f_code.co_filename,
591
                                                       sys.exc_info()[-1].tb_lineno))
592

    
593
    '''
594
        @brief      save current Code (self.currentCode)
595
        @author     kyouho
596
        @date       2018.07.10
597
    '''
598

    
599
    def setCurrentCode(self, table, tabText):
600
        try:
601
            self.currentCode[tabText] = {}
602
            rowCount = table.rowCount()
603

    
604
            res = {}
605
            for row in range(rowCount):
606
                code = table.item(row, 1).text()
607
                res[row] = code
608

    
609
            self.currentCode[tabText] = res
610

    
611
        except Exception as ex:
612
            print('error occurred({}) in {}:{}'.format(ex, sys.exc_info()[-1].tb_frame.f_code.co_filename,
613
                                                       sys.exc_info()[-1].tb_lineno))
614

    
615
    '''
616
        @brief      replaceTextForCodeTable
617
        @author     kyouho
618
        @date       2018.07.12
619
    '''
620

    
621
    def replaceText(self, text):
622
        return text.replace(' ', '').replace('&&', 'n')
623

    
624
    def import_code_table(self):
625
        """import code table excel file"""
626

    
627
        options = QFileDialog.Options()
628
        options |= QFileDialog.DontUseNativeDialog
629
        file_name, _ = QFileDialog.getOpenFileName(self, "Import code table", os.getcwd(), "xlsx files(*.xlsx)",
630
                                                   options=options)
631
        if file_name:
632
            QApplication.setOverrideCursor(Qt.WaitCursor)
633
            try:
634
                app_doc_data = AppDocData.instance()
635
                book = load_workbook(file_name)
636
                for sheet in book.worksheets:
637
                    matches = [index for index in range(self.ui.tabWidget.count())
638
                               if sheet.title == self.ui.tabWidget.tabText(index)]
639
                    if matches:
640
                        table = self.ui.tabWidget.widget(matches[0]).findChild(QTableWidget)
641
                        self.fill_table_with_sheet(sheet, table)
642
            except Exception as ex:
643
                from App import App
644
                message = 'error occurred({}) in {}:{}'.format(repr(ex), sys.exc_info()[-1].tb_frame.f_code.co_filename,
645
                                                               sys.exc_info()[-1].tb_lineno)
646
                App.mainWnd().addMessage.emit(MessageType.Error, message)
647
            finally:
648
                QApplication.restoreOverrideCursor()
649

    
650

    
651
    def export_code_table(self):
652
        """export code table to excel file"""
653

    
654
        app_doc_data = AppDocData.instance()
655
        project = app_doc_data.getCurrentProject()
656

    
657
        options = QFileDialog.Options()
658
        options |= QFileDialog.DontUseNativeDialog
659
        file_name, _ = QFileDialog.getSaveFileName(self, "Export code table", project.path, "xlsx files(*.xlsx)",
660
                                                   options=options)
661
        if not file_name:
662
            return
663

    
664
        QApplication.setOverrideCursor(Qt.WaitCursor)
665

    
666
        try:
667
            wb = Workbook()
668
            wb.active.title = self.tr(self.ui.tabWidget.tabText(0))
669
            for index in range(1, self.ui.tabWidget.count()):
670
                wb.create_sheet(self.tr(self.ui.tabWidget.tabText(index)))
671

    
672
            for index in range(self.ui.tabWidget.count()):
673
                tab = self.ui.tabWidget.widget(index)
674
                table = tab.findChild(QTableWidget)
675
                if table:
676
                    sheet = wb.worksheets[index]
677
                    self.set_sheet_header(table, sheet)
678
                    self.fill_sheet_with_table(table, sheet)
679
                    self.auto_resize_columns(sheet)
680

    
681
            file_name, ext = os.path.splitext(file_name)
682
            save_file_name = file_name + ext if ext.upper() == '.XLSX' else file_name + '.xlsx'
683
            wb.save(save_file_name)
684

    
685
            QMessageBox.about(self, self.tr("Information"), self.tr('Successfully saved.'))
686

    
687
            os.startfile(save_file_name)
688
        except Exception as ex:
689
            from App import App
690
            from AppDocData import MessageType
691

    
692
            message = 'error occurred({}) in {}:{}'.format(repr(ex), sys.exc_info()[-1].tb_frame.f_code.co_filename,
693
                                                           sys.exc_info()[-1].tb_lineno)
694
            App.mainWnd().addMessage.emit(MessageType.Error, message)
695
        finally:
696
            QApplication.restoreOverrideCursor()
697

    
698
    def set_sheet_header(self, table, sheet):
699
        """ set list header """
700

    
701
        try:
702
            thin = Side(border_style='thin', color='000000')
703
            border = Border(left=thin, right=thin, top=thin, bottom=thin)
704
            _col = 1
705
            for col in range(table.columnCount()):
706
                logical_index = table.horizontalHeader().logicalIndex(col)
707
                col_name = table.horizontalHeaderItem(logical_index).text()
708
                sheet.cell(1, _col, col_name)
709
                sheet.cell(row=1, column=_col).alignment = Alignment(horizontal='center', vertical='center',
710
                                                                     wrapText=True)
711
                sheet.cell(row=1, column=_col).fill = PatternFill(patternType='solid', fill_type='solid',
712
                                                                  fgColor=Color('8DB4E2'))
713
                sheet.cell(row=1, column=_col).border = border
714
                _col += 1
715
        except Exception as ex:
716
            from App import App
717
            from AppDocData import MessageType
718

    
719
            message = 'error occurred({}) in {}:{}'.format(ex, sys.exc_info()[-1].tb_frame.f_code.co_filename,
720
                                                           sys.exc_info()[-1].tb_lineno)
721
            App.mainWnd().addMessage.emit(MessageType.Error, message)
722

    
723
    def fill_table_with_sheet(self, sheet, table):
724
        """fill table with sheet"""
725
        from NominalPipeSize import NominalPipeSize
726

    
727
        try:
728
            row_index = 0
729
            headers = {}
730
            if sheet.title == 'Nominal Diameter':
731
                pipe_sizes = []
732
                for row in sheet.rows:
733
                    if row_index == 0:
734
                        for col in range(sheet.max_column):
735
                            value = row[col].value
736
                            headers[col] = value
737
                    else:
738
                        pipe_size = NominalPipeSize(None, None, None, None, None, None, None, None)
739
                        for col in range(sheet.max_column):
740
                            value = row[col].value
741
                            if 'UID' == headers[col]:
742
                                pipe_size.uid = value
743
                            elif 'Code' == headers[col]:
744
                                pipe_size.code = value
745
                            elif 'Metric' == headers[col]:
746
                                pipe_size.metric = value
747
                            elif 'Inch' == headers[col]:
748
                                pipe_size.inch = value
749
                            elif 'InchStr' == headers[col]:
750
                                pipe_size.inchStr = value
751
                            elif 'Inch Allowables' == headers[col]:
752
                                pipe_size.allowable_inch_str = value
753
                            elif 'MetricStr' == headers[col]:
754
                                pipe_size.metricStr = value
755
                            elif 'Metric Allowables' == headers[col]:
756
                                pipe_size.allowable_metric_str = value
757

    
758
                        pipe_sizes.append(pipe_size)
759

    
760
                    row_index += 1
761

    
762
                self.fill_nominal_pipe_sizes(pipe_sizes)
763
            else:
764
                codes = []
765
                for row in sheet.rows:
766
                    if row_index == 0:
767
                        for col in range(sheet.max_column):
768
                            value = row[col].value
769
                            headers[col] = value
770
                    else:
771
                        code = [row[col].value for col in range(sheet.max_column)]
772
                        codes.append(code)
773

    
774
                    row_index += 1
775

    
776
                self.fill_codes(table, codes)
777
        except Exception as ex:
778
            from App import App
779
            from AppDocData import MessageType
780

    
781
            message = 'error occurred({}) in {}:{}'.format(ex, sys.exc_info()[-1].tb_frame.f_code.co_filename,
782
                                                           sys.exc_info()[-1].tb_lineno)
783
            App.mainWnd().addMessage.emit(MessageType.Error, message)
784

    
785
    def fill_sheet_with_table(self, table, sheet):
786
        """fill sheet with table"""
787

    
788
        try:
789
            thin = Side(border_style='thin', color='000000')
790
            border = Border(left=thin, right=thin, top=thin, bottom=thin)
791

    
792
            for col in range(table.columnCount()):
793
                for row in range(table.rowCount()):
794
                    try:
795
                        text = str(table.item(row, col).text())
796
                        sheet.cell(row + 2, col + 1, text)
797
                        sheet.cell(row=row + 2, column=col + 1).border = border
798
                    except AttributeError:
799
                        pass
800
        except Exception as ex:
801
            from App import App
802
            from AppDocData import MessageType
803

    
804
            message = 'error occurred({}) in {}:{}'.format(ex, sys.exc_info()[-1].tb_frame.f_code.co_filename,
805
                                                           sys.exc_info()[-1].tb_lineno)
806
            App.mainWnd().addMessage.emit(MessageType.Error, message)
807

    
808
    def auto_resize_columns(self, sheet):
809
        """ auto resize columns with contents """
810

    
811
        from openpyxl.utils import get_column_letter
812
        try:
813
            for col in sheet.columns:
814
                max_length = 0
815
                column = col[0].column  # Get the column name
816
                for cell in col:
817
                    try:  # Necessary to avoid error on empty cells
818
                        if len(str(cell.value)) > max_length:
819
                            max_length = len(cell.value)
820
                    except:
821
                        pass
822

    
823
                adjusted_width = (max_length + 2) * 1.2
824
                sheet.column_dimensions[
825
                    get_column_letter(column) if type(column) is int else column].width = adjusted_width
826
        except Exception as ex:
827
            from App import App
828
            from AppDocData import MessageType
829

    
830
            message = 'error occurred({}) in {}:{}'.format(repr(ex), sys.exc_info()[-1].tb_frame.f_code.co_filename,
831
                                                           sys.exc_info()[-1].tb_lineno)
832
            App.mainWnd().addMessage.emit(MessageType.Error, message)
833

    
834
    '''
835
        @brief      save codes
836
        @author     kyouho
837
        @date       2018.07.12
838
    '''
839

    
840
    def accept(self):
841
        from CodeTables import CodeTable
842
        for table in QCodeTableDialog.CODE_TABLES:
843
            if table != 'Nominal Diameter':
844
                self.saveCommonCodeData(table)
845

    
846
        self.saveNomialPipeSize()
847
        CodeTable.clearTables()
848

    
849
        QDialog.accept(self)
850

    
851
    '''
852
        @brief      save common code data
853
        @author     kyouho
854
        @date       2018.07.12
855
    '''
856

    
857
    def saveCommonCodeData(self, tableName):
858
        datas = []
859
        try:
860
            tableName = self.replaceText(tableName)
861
            table = self.findTableWidget(tableName)
862
            rowCount = table.rowCount()
863
            for row in range(rowCount):
864
                if table.isRowHidden(row):
865
                    uid, code, description, allowables = '-1', table.item(row, 1).text(), '', table.item(row, 0).text()
866
                elif table.item(row, 0):
867
                    uid = table.item(row, 0).text()
868
                    code = table.item(row, 1).text()
869
                    description = table.item(row, 2).text() if table.item(row, 2) is not None else ''
870
                    allowables = table.item(row, 3).text() if table.item(row, 3) is not None else ''
871

    
872
                if code:
873
                    datas.append((uid, code, description, allowables))
874

    
875
            docData = AppDocData.instance()
876
            docData.saveCommonCodeData(tableName.replace(' ', ''), datas)
877
        except Exception as ex:
878
            from App import App
879

    
880
            message = 'error occurred({}) in {}:{}'.format(ex, sys.exc_info()[-1].tb_frame.f_code.co_filename,
881
                                                           sys.exc_info()[-1].tb_lineno)
882
            App.mainWnd().addMessage.emit(MessageType.Error, message)
883

    
884
    '''
885
        @brief      save common code data
886
        @author     kyouho
887
        @date       2018.07.16
888
    '''
889

    
890
    def saveNomialPipeSize(self):
891
        pipeSizes = []
892
        try:
893
            docData = AppDocData.instance()
894

    
895
            from NominalPipeSize import NominalPipeSize
896

    
897
            table = self.ui.tableWidgetNominalDiameter
898
            rowCount = table.rowCount()
899
            for row in range(rowCount):
900
                pipe_size = table.item(row, 0).data(Qt.UserRole)
901
                pipe_size.code = table.item(row, 1).text()
902
                pipe_size.metric = float(table.item(row, 2).text()) if table.item(row, 2).text() != '' else None
903
                pipe_size.inch = float(table.item(row, 3).text()) if table.item(row, 3).text() != '' else None
904
                pipe_size.inchStr = table.item(row, 4).text()
905
                pipe_size.allowable_inch_str = table.item(row, 5).text()
906
                pipe_size.metricStr = table.item(row, 6).text()
907
                pipe_size.allowable_metric_str = table.item(row, 7).text()
908
                pipeSizes.append(pipe_size)
909

    
910
            docData.insertNomialPipeSize(pipeSizes)
911

    
912
        except Exception as ex:
913
            from App import App
914

    
915
            message = 'error occurred({}) in {}:{}'.format(ex, sys.exc_info()[-1].tb_frame.f_code.co_filename,
916
                                                           sys.exc_info()[-1].tb_lineno)
917
            App.mainWnd().addMessage.emit(MessageType.Error, message)
클립보드 이미지 추가 (최대 크기: 500 MB)