프로젝트

일반

사용자정보

통계
| 개정판:

hytos / DTI_PID / DTI_PID / MainWindow.py @ ae19dabd

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

1
# coding: utf-8
2

    
3
import sys
4
import os
5
import subprocess
6
from functools import partial
7

    
8
sys.path.insert(0, os.path.dirname(os.path.realpath(__file__)))
9
sys.path.insert(0, os.path.dirname(os.path.realpath(__file__)) + '\\Commands')
10
import CreateCommand
11
import CropCommand
12
import AreaOcrCommand
13
import CreateSymbolCommand
14
import AreaZoomCommand
15
import FenceCommand
16
import PlaceLineCommand
17

    
18
import cv2
19
import numpy as np
20

    
21
from PyQt5.QtCore import *
22
from PyQt5.QtGui import *
23
from PyQt5.QtWidgets import *
24
from PyQt5.QtSvg import *
25

    
26
from PIL import Image
27

    
28
import MainWindow_UI
29
import QtImageViewer
30
from SingletonInstance import SingletonInstane
31

    
32
sys.path.insert(0, os.path.dirname(os.path.realpath(__file__)) + '\\Shapes')
33
from EngineeringPolylineItem import QEngineeringPolylineItem
34
from EngineeringLineItem import QEngineeringLineItem
35
from SymbolSvgItem import SymbolSvgItem
36
from GraphicsBoundingBoxItem import QGraphicsBoundingBoxItem
37
from EngineeringTextItem import QEngineeringTextItem
38
from EngineeringLineNoTextItem import QEngineeringLineNoTextItem
39
from EngineeringTextItem import QEngineeringTextItem
40
from EngineeringNoteItem import QEngineeringNoteItem
41
from QEngineeringSizeTextItem import QEngineeringSizeTextItem
42
from EngineeringUnknownItem import QEngineeringUnknownItem
43
from EngineeringEquipmentItem import QEngineeringEquipmentItem
44
from EngineeringInstrumentItem import QEngineeringInstrumentItem
45
from EngineeringSpecBreakItem import QEngineeringSpecBreakItem
46
from AppDocData import *
47
import SymbolTreeWidget, SymbolPropertyTableWidget
48
import SymbolEditorDialog
49
import ItemTreeWidget
50
import ItemPropertyTableWidget
51
from UserInputAttribute import UserInputAttribute
52
from TextItemFactory import TextItemFactory
53
from TrainingImageListDialog import QTrainingImageListDialog
54

    
55
class MainWindow(QMainWindow, MainWindow_UI.Ui_MainWindow, SingletonInstane):
56
    """
57
    This is MainWindow class
58
    """
59
    addMessage = pyqtSignal(Enum, str)
60

    
61
    '''
62
        @brief      initialize
63
        @author 
64
        @date   
65
        @history    humkyung 2018.04.12 add splitter widget
66
                    Jeongwoo 2018.04.27 Add Signal/Slot Connection 'noteNoSingleClicked'
67
                    Jeongwoo 2018.05.09 Initialize Action group
68
                    Jeongwoo 2018.05.10 Add Signal/Slot Connection 'lineNoSingleClicked'
69
                                        Add QActionGroup for managing checkable action
70
                    Jeongwoo 2018.06.27 Add Action [Zoom, Fit Window] and Add new actions into ActionGroup
71
                    humkyung 2018.08.23 add labelStatus to statusbar
72
                    Euisung 2018.09.27 add OCR Training , Signal/Slot Connection 'oCRTrainingClicked'
73
                    Euisung 2018.10.05 add OCR Editor , Signal/Slot Connection 'oCRTrainingEdidorClicked'
74
                    Euisung 2018.10.22 delete Signal/Slot Connection 'oCRTrainingEdidorClicked'
75
    '''
76
    def __init__(self):
77
        super(self.__class__, self).__init__()
78
        self.setupUi(self)
79
        self.labelStatus = QLabel(self.statusbar)
80
        self.labelStatus.setText('미인식 : ')
81
        self.labelSymbolStatus = QLabel(self.statusbar)
82
        self.labelSymbolStatus.setText('심볼 : ')
83
        self.labelLineStatus = QLabel(self.statusbar)
84
        self.labelLineStatus.setText('라인 : ')
85
        self.labelTextStatus = QLabel(self.statusbar)
86
        self.labelTextStatus.setText('텍스트 : ')
87
        self.statusbar.addPermanentWidget(self.labelSymbolStatus)
88
        self.statusbar.addPermanentWidget(self.labelLineStatus)
89
        self.statusbar.addPermanentWidget(self.labelTextStatus)
90
        self.statusbar.addPermanentWidget(self.labelStatus) 
91

    
92
        docData = AppDocData.instance()
93
        project = docData.getCurrentProject()
94
        _translate = QCoreApplication.translate
95
        self.setWindowTitle(_translate("Digital P&ID - {}".format(project.name), "Digital P&ID - {}".format(project.name)))
96

    
97
        self.lineComboBox = QComboBox(self.toolBar)
98
        lineTypes = docData.getLineTypes()
99
        for lineType in lineTypes:
100
            self.lineComboBox.addItem(lineType)
101
        self.lineComboBox.currentIndexChanged.connect(self.onLineTypeChanged)
102

    
103
        self.toolBar.insertWidget(self.actionOCR, self.lineComboBox)
104
        self.toolBar.insertSeparator(self.actionOCR)
105
        self.graphicsView = QtImageViewer.QtImageViewer(self)
106
        self.graphicsView.setParent(self.centralwidget)
107
        self.graphicsView.useDefaultCommand() ##### USE DEFAULT COMMAND
108

    
109
        self.verticalLayout.addWidget(self.graphicsView)
110

    
111
        # Add Custom TreeWidget
112
        self.dirTreeWidget = SymbolTreeWidget.QSymbolTreeWidget()
113
        self.dirTreeWidget.header().hide()
114
        self.symbolTabVerticalLayout.addWidget(self.dirTreeWidget)
115

    
116
        # Add Custom Property TableWidget
117
        self.propertyTableWidget = SymbolPropertyTableWidget.QSymbolPropertyTableWidget()
118
        self.symbolTabVerticalLayout.addWidget(self.propertyTableWidget)
119
        self.dirTreeWidget.singleClicked.connect(self.propertyTableWidget.getClickedSymbol)
120
        # add splitter widget
121
        splitter = QSplitter(Qt.Vertical)
122
        splitter.addWidget(self.dirTreeWidget)
123
        splitter.addWidget(self.propertyTableWidget)
124
        self.symbolTabVerticalLayout.addWidget(splitter)
125
        # up to here
126

    
127
        # Add Custom Result Tree Widget (Symbol Explorer)
128
        self.resultTreeWidget = ItemTreeWidget.QItemTreeWidget(self.graphicsView)
129
        self.resultTreeWidget.header().hide()
130
        self.symbolExplorerVerticalLayout.addWidget(self.resultTreeWidget)
131

    
132
        # Add Empty Widget
133
        self.resultPropertyTableWidget = ItemPropertyTableWidget.QItemPropertyTableWidget(self)
134
        self.symbolExplorerVerticalLayout.addWidget(self.resultPropertyTableWidget)
135
        self.resultTreeWidget.singleClicked.connect(self.resultPropertyTableWidget.onSymbolClicked)
136
        self.resultTreeWidget.noteNoSingleClicked.connect(self.resultPropertyTableWidget.onNoteClicked)
137
        self.resultTreeWidget.lineNoSingleClicked.connect(self.resultPropertyTableWidget.onLineNoClicked)
138
        self.resultTreeWidget.drawingClicked.connect(self.resultPropertyTableWidget.onDrawingClicked)
139
        # add splitter widget
140
        splitter = QSplitter(Qt.Vertical)
141
        splitter.addWidget(self.resultTreeWidget)
142
        splitter.addWidget(self.resultPropertyTableWidget)
143
        self.symbolExplorerVerticalLayout.addWidget(splitter)
144
        # up to here
145

    
146
        # Initialize Action group
147
        self.actionGroup = QActionGroup(self)
148
        self.actionGroup.addAction(self.actionRecognition)
149
        self.actionGroup.addAction(self.actionLineRecognition)
150
        self.actionGroup.addAction(self.actionLine)
151
        self.actionGroup.addAction(self.actionGenerateOutput)
152
        self.actionGroup.addAction(self.actionOCR)
153
        self.actionGroup.addAction(self.actionZoom)
154
        self.actionGroup.addAction(self.actionFitWindow)
155
        self.actionGroup.addAction(self.actionSave)
156
        self.actionGroup.triggered.connect(self.actionGroupTriggered)
157

    
158
        # connect signals and slots
159
        self.actionClose.triggered.connect(self.close)
160
        self.actionOpen.triggered.connect(self.onOpenImageDrawing)
161
        self.actionLine.triggered.connect(self.onPlaceLine)
162
        self.actionRecognition.triggered.connect(self.recognize)
163
        self.pushButtonBatchRecognition.clicked.connect(self.recognizeBatch)
164
        self.actionLineRecognition.triggered.connect(self.recognizeLine)
165
        self.actionArea.triggered.connect(self.areaConfiguration)
166
        self.actionConfiguration.triggered.connect(self.configuration)
167
        self.actionOCR.triggered.connect(self.onAreaOcr)
168
        self.actionGenerateOutput.triggered.connect(self.generateOutput)
169
        self.pushButtonCreateSymbol.clicked.connect(self.onCreateSymbolClicked)
170
        self.pushButtonClearLog.clicked.connect(self.onClearLog)
171
        self.actionHMB_DATA.triggered.connect(self.onHMBData)
172
        self.actionItem_Data_List.triggered.connect(self.showItemDataList)
173
        self.actionCodeTable.triggered.connect(self.onShowCodeTable)
174
        self.actionImage_Drawing.triggered.connect(self.onViewImageDrawing)
175
        self.actionViewText.triggered.connect(self.onViewText)
176
        self.actionViewSymbol.triggered.connect(self.onViewSymbol)
177
        self.actionViewLine.triggered.connect(self.onViewLine)
178
        self.actionViewUnknown.triggered.connect(self.onViewUnknown)
179
        self.actionRotate.triggered.connect(self.onRotate)
180
        self.actionZoom.triggered.connect(self.onAreaZoom)
181
        self.actionFitWindow.triggered.connect(self.fitWindow)
182
        self.actionpdf_to_image.triggered.connect(self.onConvertPDFToImage)
183
        self.graphicsView.scene.changed.connect(self.onSceneChanged)
184
        self.graphicsView.scene.selectionChanged.connect(self.onSelectionChanged)
185
        self.actionInitialize.triggered.connect(self.onInitializeScene)
186
        self.resultPropertyTableWidget.cellDoubleClicked.connect(self.resultPropertyTableWidget.cellDoubleClickedEvent)
187
        self.resultPropertyTableWidget.cellClicked.connect(self.cellClickedEvent)
188
        self.actionSave.triggered.connect(self.actionSaveCliked)
189
        self.addMessage.connect(self.onAddMessage)
190
        self.actionFindReplaceText.triggered.connect(self.findReplaceTextClicked)
191
        self.pushButtonDetectSymbol.clicked.connect(self.onShowDetectSymbol)
192
        self.actionOCR_Training.triggered.connect(self.oCRTrainingClicked)
193

    
194
        # removedItems
195
        self.removedItems = {}
196
        self.removedItems['LINE'] = []
197
        self.removedItems['EQUIP'] = []
198
        self.removedItems['INST'] = []
199
        self.removedItems['NOTE'] = []
200

    
201
        self.delimiter = '"'
202
    
203
        self.resizeDocks({self.dockWidget}, {self.dockWidgetObjectExplorer.sizeHint().width()}, Qt.Horizontal)
204

    
205
        self.treeWidgetDrawingList.setHeaderHidden(False)
206
        self.treeWidgetDrawingList.header().setStretchLastSection(False)
207
        self.treeWidgetDrawingList.setHeaderLabels(['Name', 'DateTime'])
208
        self.treeWidgetDrawingList.header().setSectionResizeMode(0, QHeaderView.ResizeToContents)
209
        self.treeWidgetDrawingList.header().setSectionResizeMode(1, QHeaderView.ResizeToContents)
210
        self.treeWidgetDrawingList.itemDoubleClicked.connect(self.open_selected_drawing)
211
        self.load_drawing_list()
212

    
213
        # load stylesheet file list
214
        stylesheet_name = QtWidgets.qApp.stylesheet_name
215
        files = [os.path.splitext(file)[0] for file in os.listdir(os.path.dirname(os.path.realpath(__file__))) if os.path.splitext(file)[1] == '.qss']
216
        for file in files:
217
            action = self.menuTheme.addAction(file)
218
            action.setCheckable(True)
219
            action.setChecked(True) if stylesheet_name == file else action.setChecked(False)
220
            action.triggered.connect(partial(self.load_stylesheet, file))
221
        # up to here
222

    
223
    def load_stylesheet(self, file):
224
        """
225
        @brief  load stylesheets
226
        @author humkyung
227
        @date   2018.10.29
228
        """
229

    
230
        QtWidgets.qApp.loadStyleSheet(os.path.join(os.path.dirname(os.path.realpath(__file__)), file))
231

    
232
        app_doc_data = AppDocData.instance()
233
        configs = [Config('app', 'stylesheet', file)]
234
        app_doc_data.saveAppConfigs(configs)
235
        
236
        for action in self.menuTheme.actions():
237
            if action.text() == file: continue
238
            action.setChecked(False)
239

    
240
    '''
241
        @brief      Clear TreeWidget and Set Current PID
242
        @author     Jeongwoo
243
        @date       18.04.11
244
        @history    2018.04.26  Jeongwoo    Add Child [SYMBOLS, NOTES] into root item
245
                    2018.05.09  Jeongwoo    Change method to add default tree items
246
                    humkyung 2018.06.10 add tree item for Line No and Unknown Item
247
    '''
248
    def load_drawing_list(self):
249
        """
250
        @brief      load p&id drawing list
251
        @author     humkyung
252
        @date       18.11.02
253
        """
254

    
255
        try:
256
            appDocData = AppDocData.instance()
257
            drawings = appDocData.getDrawings()
258

    
259
            self.treeWidgetDrawingList.clear()
260
            self.treeWidgetDrawingList.root = QTreeWidgetItem(self.treeWidgetDrawingList, ['P&ID Drawings', ''])
261
            files = appDocData.getDrawingFileList()
262
            for file in files:
263
                drawing = [drawing for drawing in drawings if drawing[1] == file]
264
                if not drawing or not drawing[0]:
265
                    drawings.append([None, file, None])
266

    
267
                item = QTreeWidgetItem(self.treeWidgetDrawingList.root, [file, drawing[0][2] if drawing and drawing[0] else ''])
268
                item.setIcon(0, QIcon(':newPrefix/image.png'))
269
                item.setFlags(item.flags() | Qt.ItemIsUserCheckable)
270
                item.setCheckState(0, Qt.Unchecked)
271
            
272
            self.treeWidgetDrawingList.root.setText(0, 'P&ID Drawings({})'.format(self.treeWidgetDrawingList.root.childCount()))
273
            self.treeWidgetDrawingList.expandItem(self.treeWidgetDrawingList.root)
274
            self.treeWidgetDrawingList.root.sortChildren(0, Qt.AscendingOrder)
275
            self.treeWidgetDrawingList.resizeColumnToContents(0)
276

    
277
            appDocData.saveDrawings(drawings)
278
        except Exception as ex:
279
            message = 'error occured({}) in {}:{}'.format(ex, sys.exc_info()[-1].tb_frame.f_code.co_filename, sys.exc_info()[-1].tb_lineno)
280
            self.addMessage.emit(MessageType.Error, message)
281

    
282
    def open_selected_drawing(self, item, column):
283
        """
284
        @brief      open selected p&id drawing
285
        @author     humkyung
286
        @date       18.11.02
287
        """
288
        appDocData = AppDocData.instance()
289
        drawing = os.path.join(appDocData.getCurrentProject().getDrawingFilePath(), item.text(column))
290
        self.onOpenImageDrawing(drawing)
291

    
292
    def onShowDetectSymbol(self):
293
        from DetectSymbolDialog import QDetectSymbolDialog
294

    
295
        dlgDetectSymbol = QDetectSymbolDialog(self)
296
        dlgDetectSymbol.show()
297
        dlgDetectSymbol.exec_()
298
        
299
    '''
300
        @brief      OCR Editor
301
        @author     euisung
302
        @date       2018.10.05
303
        @history    2018.10.16 euisung      no more used, Integrated with oCRTrainingClicked
304
    '''
305
    def oCRTrainingEdidorClicked(self):
306
        from TrainingEditorDialog import QTrainingEditorDialog
307

    
308
        try:
309
            dialog = QTrainingEditorDialog(self)
310
            dialog.exec_()
311
        except Exception as ex:
312
            message = 'error occured({}) in {}:{}'.format(ex, sys.exc_info()[-1].tb_frame.f_code.co_filename, sys.exc_info()[-1].tb_lineno)
313
            self.addMessage.emit(MessageType.Error, message)
314
            
315
        return
316

    
317
    '''
318
        @brief      OCR Training
319
        @author     euisung
320
        @date       2018.09.27
321
        @history    euisung 2018.10.16 TrainingListDialog -> TrainingImageListDialog
322
    '''
323
    def oCRTrainingClicked(self):
324
        try:
325
            dialog = QTrainingImageListDialog(self)
326
            dialog.exec_()
327
        except Exception as ex:
328
            message = 'error occured({}) in {}:{}'.format(ex, sys.exc_info()[-1].tb_frame.f_code.co_filename, sys.exc_info()[-1].tb_lineno)
329
            self.addMessage.emit(MessageType.Error, message)
330

    
331
    '''
332
        @brief      show unknownitem's count
333
        @author     kyouho
334
        @date       2018.08.27
335
    '''
336
    def findReplaceTextClicked(self):
337
        if not self.graphicsView.hasImage():
338
            self.showImageSelectionMessageBox()
339
            return
340

    
341
        from TextItemEditDialog import QTextItemEditDialog
342

    
343
        self.dlgTextItemEdit = QTextItemEditDialog(self)
344
        self.dlgTextItemEdit.show()
345
        self.dlgTextItemEdit.exec_()
346

    
347
    '''
348
        @brief      show unknownitem's count
349
        @author     humkyung
350
        @date       2018.08.23
351
        @history    humkyung 2018.08.30 display count of symbol, line, text
352
    '''
353
    def onSceneChanged(self):
354
        items = [item for item in self.graphicsView.scene.items() if type(item) is QEngineeringUnknownItem]
355
        if len(items) > 0:
356
            self.labelStatus.setText("<font color='red'>미인식 : {}</font>".format(len(items)))
357
        else:
358
            self.labelStatus.setText("<font color='black'>미인식 : {}</font>".format(len(items)))
359

    
360
        items = [item for item in self.graphicsView.scene.items() if issubclass(type(item), SymbolSvgItem)]
361
        self.labelSymbolStatus.setText("<font color='blue'>심볼 : {}</font>".format(len(items)))
362

    
363
        items = [item for item in self.graphicsView.scene.items() if type(item) is QEngineeringLineItem]
364
        self.labelLineStatus.setText("<font color='blue'>라인 : {}</font>".format(len(items)))
365

    
366
        items = [item for item in self.graphicsView.scene.items() if issubclass(type(item), QEngineeringTextItem)]
367
        self.labelTextStatus.setText("<font color='blue'>텍스트 : {}</font>".format(len(items)))
368

    
369
        self.resultTreeWidget.sceneChanged(self.graphicsView.scene.items())
370

    
371
    def dbUpdate(self):
372
        '''
373
            @brief      db update when save or recognition
374
            @author     euisung
375
            @date       2018.11.12
376
            @history    2018.11.02      euisung     remove scene dependency
377
        '''
378
        from AppDocData import AppDocData
379

    
380
        try:
381
            appDocData = AppDocData.instance()
382

    
383
            appDocData.deleteDataListBeforeSave()
384
            
385
            titleBlockProps = appDocData.getTitleBlockProperties()
386
            #items = self.graphicsView.scene.items()
387
            items = appDocData.allItems
388
            titleBlockItems = []
389
            for item in items:
390
                if type(item) is QEngineeringLineNoTextItem:
391
                    item.saveLineData()
392

    
393
                elif type(item) is QEngineeringTextItem:
394
                    for titleBlockProp in titleBlockProps:
395
                        if item.area == titleBlockProp[0]:
396
                            titleBlockItems.append(item)
397

    
398
            dbItems = [item for item in items if type(item) is QEngineeringInstrumentItem or type(item) is QEngineeringEquipmentItem or\
399
            type(item) is QEngineeringNoteItem or type(item) is SymbolSvgItem] + titleBlockItems
400
            appDocData.saveToDatabase(dbItems)
401
        except Exception as ex:
402
            message = 'error occured({}) in {}:{}'.format(ex, sys.exc_info()[-1].tb_frame.f_code.co_filename, sys.exc_info()[-1].tb_lineno)
403
            self.addMessage.emit(MessageType.Error, message)
404

    
405
    '''
406
        @brief      action save click event
407
        @author     kyouho
408
        @date       2018.08.09
409
        @history    2018.11.02      euisung     add line data list db update
410
                    humkyung save saved time to database
411
                    2018.11.05      euisung     add note data list db update
412
                    2018.11.05      euisung     add db delete process before save
413
                    2018.11.12      euisung     db part move new method to dbUpdate
414
    '''
415
    def actionSaveCliked(self):
416
        from datetime import datetime
417
        from AppDocData import AppDocData
418

    
419
        appDocData = AppDocData.instance()
420
        if appDocData.imgName is None:
421
            self.showImageSelectionMessageBox()
422
            return
423

    
424
        appDocData.clearItemList()
425

    
426
        items = self.graphicsView.scene.items()
427
        for item in items:
428
            if type(item) is not QGraphicsPixmapItem:
429
                appDocData.allItems.append(item)
430
        
431
        ##
432
        itemTypes = []
433
        for item in items:
434
            typeExist = False
435
            for itemType in itemTypes:
436
                if type(item) is itemType:
437
                    typeExist = True
438
                    break
439
            if not typeExist:
440
                itemTypes.append(type(item))
441
        ##
442

    
443
        self.dbUpdate()
444
        self.saveToXml(True)
445

    
446
        drawings = appDocData.getDrawings()
447
        drawing = [drawing for drawing in drawings if appDocData.imgName == os.path.splitext(drawing[1])[0]]
448
        if drawing[0]:
449
            drawing[0][2] = datetime.now().strftime('%Y-%m-%d %H:%M:%S')
450
            appDocData.saveDrawings(drawing)
451

    
452
    '''
453
        @brief      save items to xml
454
        @author     kyouho
455
        @date       2018.07.31
456
    '''
457
    def saveToXml(self, alert = True):
458
        import XmlGenerator as xg
459
        from AppDocData import AppDocData
460
        docData = AppDocData.instance()
461
        if docData.imgName is None:
462
            self.showImageSelectionMessageBox()
463
            return
464
        result = xg.writeXmlOnScene(docData.imgName, docData.imgWidth, docData.imgHeight)
465
        
466
        if len(self.removedItems['LINE']):
467
            docData.deleteLineDataList_LineNo(self.removedItems['LINE'])
468
            self.removedItems['LINE'] = []
469

    
470
        if len(self.removedItems['EQUIP']):
471
            docData.deleteEquipDataList(self.removedItems['EQUIP'])
472
            self.removedItems['EQUIP'] = []
473

    
474
        if len(self.removedItems['INST']):
475
            docData.deleteInstDataList(self.removedItems['INST'])
476
            self.removedItems['INST'] = []
477

    
478
        if len(self.removedItems['NOTE']):
479
            docData.deleteNoteDataList(self.removedItems['NOTE'])
480
            self.removedItems['NOTE'] = []
481

    
482

    
483
        if alert:
484
            resultStr = '[저장 결과]'
485

    
486
            for item in result.items():
487
                itemName = str(item[0])
488
                itemSuccessCount = str(item[1][0])
489
                itemFailUidList = item[1][1]
490
                resultStr += "\r\n" + itemName + " Save Count : " + itemSuccessCount
491
                if len(itemFailUidList) > 0:
492
                    resultStr += "\r\n" + itemName + " Error List(UID)"
493
                    for uid in itemFailUidList:
494
                        resultStr += "\r\n" + uid
495

    
496
            QMessageBox.about(self.graphicsView, "알림", resultStr)
497

    
498
    '''
499
        @brief      refresh resultPropertyTableWidget
500
        @author     kyouho
501
        @date       2018.07.19
502
    '''
503
    def refreshResultPropertyTableWidget(self):
504
        items = self.graphicsView.scene.selectedItems()
505
        if len(items) == 1:
506
            self.resultPropertyTableWidget.onSymbolClicked(items[0])
507
    
508
    '''
509
        @brief      resultPropertyTableWidget Cell Click Event
510
        @author     kyouho
511
        @date       2018.08.23
512
    '''
513
    def cellClickedEvent(self, row, column):
514
        item = self.graphicsView.scene.selectedItems()
515
        if len(item) != 1:
516
            return
517
        item = item[0]
518

    
519
        cell = self.resultPropertyTableWidget.item(row, column)
520
        for valueCell, uid in self.resultPropertyTableWidget.attrValueList:
521
            if valueCell == cell and issubclass(type(item), SymbolSvgItem):
522
                for attr in item.attrs:
523
                    if attr.attribute == uid and (issubclass(type(attr), SymbolSvgItem) or type(attr) is QEngineeringTextItem):
524
                        prevItem = item
525
                        currentItem = attr
526

    
527
                        rect = currentItem.sceneBoundingRect()
528
                        self.graphicsView.centerOn(rect.center())
529
                        self.graphicsView.zoomImage(True, QMouseEvent(QEvent.MouseButtonPress, self.graphicsView.mapFromScene(QPointF(rect.left(), rect.top())), Qt.LeftButton, Qt.LeftButton, Qt.NoModifier), 3)
530
                        prevItem.setSelected(True)
531

    
532
                        currentItem.setHightlight()
533
                    elif (issubclass(type(attr), SymbolSvgItem) or type(attr) is QEngineeringTextItem):
534
                        attr.unsetHightlight()
535

    
536

    
537
    '''
538
        @brief  add message listwidget
539
        @author humkyung
540
        @date   2018.07.31
541
    '''
542
    def onAddMessage(self, messageType, message):
543
        from AppDocData import MessageType
544

    
545
        try:
546
            current = QDateTime.currentDateTime()
547

    
548
            item = QListWidgetItem('{}: {}'.format(current.toString('hh:mm:ss'), message))
549
            if messageType == MessageType.Error:
550
                item.setBackground(Qt.red)
551

    
552
            self.listWidgetLog.insertItem(0, item)
553
        except Exception as ex:
554
            print('error occured({}) in {}:{}'.format(ex, sys.exc_info()[-1].tb_frame.f_code.co_filename, sys.exc_info()[-1].tb_lineno))
555

    
556
    '''
557
        @brief      clear log
558
        @author     humkyung
559
        @date       2018.08.01
560
    '''
561
    def onClearLog(self):
562
        self.listWidgetLog.clear()
563

    
564
    '''
565
        @brief      rotate selected symbol
566
        @author     humkyung
567
        @date       2018.08.15
568
    '''
569
    def onRotate(self, action):
570
        selected = [item for item in self.graphicsView.scene.selectedItems() if issubclass(type(item), SymbolSvgItem)]
571
        if len(selected) == 1:
572
            selected[0].rotateSymbol()
573

    
574
    '''
575
        @brief      Area Zoom
576
        @author     Jeongwoo
577
        @date       2018.06.27
578
        @history    connect command's rejected signal
579
    '''
580
    def onAreaZoom(self, action):
581
        if self.actionZoom.isChecked():
582
            cmd = AreaZoomCommand.AreaZoomCommand(self.graphicsView)
583
            cmd.onRejected.connect(self.onCommandRejected)
584
            self.graphicsView.command = cmd
585

    
586
    '''
587
        @brief      Fit Window
588
        @author     Jeongwoo
589
        @date       2018.06.27
590
        @history    2018.06.27  Jeongwoo    Chnage method to initialize command [Set None → DefaultCommand]
591
    '''
592
    def fitWindow(self, action):
593
        self.graphicsView.useDefaultCommand()
594
        self.graphicsView.zoomImageInit()
595

    
596
    def onConvertPDFToImage(self):
597
        """
598
        @brief      convert to selected pdf to image
599
        @author     humkyung 
600
        @date       2018.07.09
601
        @history    Euisung 2018.10.11 hide shell
602
        """
603
        try: 
604
            filePath = os.path.join(os.path.dirname(os.path.realpath(__file__)) , 'bin64', 'PDF_TO_IMAGE.exe')
605
            subprocess.call(filePath, shell = False)
606
        except Exception as ex:
607
            print('error occured({}) in {}:{}'.format(ex, sys.exc_info()[-1].tb_frame.f_code.co_filename, sys.exc_info()[-1].tb_lineno))
608

    
609
    '''
610
        @brief      selection changed
611
        @author     humkyung
612
        @date       2018.06.27
613
        @history    humkung 2018.07.08 call tree widget's findItem
614
    '''
615
    def onSelectionChanged(self):
616
        items = [item for item in self.graphicsView.scene.selectedItems() if issubclass(type(item), SymbolSvgItem) or \
617
            type(item) is QEngineeringLineItem or type(item) is QEngineeringLineNoTextItem or type(item) is QEngineeringNoteItem or type(item) is QEngineeringUnknownItem]
618
        if items:
619
            item = items[-1]
620
            self.resultTreeWidget.findItem(item)
621
            self.resultPropertyTableWidget.showItemProperty(item)
622
        else:
623
            self.resultPropertyTableWidget.showItemProperty(None)
624
        
625
    '''
626
        @brief      Initialize scene and ResultTreeWidget
627
        @author     Jeongwoo
628
        @date       2018.06.14
629
        @history    humkyung 2018.08.16 ask to delete recognized items before remove
630
    '''
631
    def onInitializeScene(self, action):
632
        if not self.graphicsView.hasImage():
633
            self.actionEquipment.setChecked(False)
634
            self.showImageSelectionMessageBox()
635

    
636
            return
637

    
638
        msg = QMessageBox()
639
        msg.setIcon(QMessageBox.Critical)
640
        msg.setText("선택한 인식한 항목들을 삭제하시겠습니까?\n삭제된 항목들은 복구할 수 없습니다.")
641
        msg.setWindowTitle("항목 삭제")
642
        msg.setStandardButtons(QMessageBox.Ok|QMessageBox.Cancel)
643
        if QMessageBox.Ok == msg.exec_():
644
            items = self.graphicsView.scene.items()
645
            for item in items:
646
                if type(item) is not QGraphicsPixmapItem:
647
                    self.graphicsView.scene.removeItem(item)
648

    
649
                    if type(item) is QEngineeringLineNoTextItem:
650
                        self.removedItems['LINE'].append(str(item.uid))
651
                    elif type(item) is QEngineeringInstrumentItem:
652
                        self.removedItems['INST'].append(str(item.uid))
653
                    elif type(item) is QEngineeringEquipmentItem:
654
                        self.removedItems['EQUIP'].append(str(item.uid))
655
                    elif type(item) is QEngineeringNoteItem:
656
                        self.removedItems['NOTE'].append(str(item.uid))
657
                    
658
            if self.path is not None:
659
                baseName = os.path.basename(self.path)
660
                self.resultTreeWidget.setCurrentPID(baseName)
661

    
662
    '''
663
        @brief      Manage Checkable Action statement
664
        @author     Jeongwoo
665
        @date       2018.05.10
666
        @history    2018.06.27  Jeongwoo    Chnage method to initialize command [Set None → DefaultCommand]
667
    '''
668
    def actionGroupTriggered(self, action):
669
        if self.graphicsView.command is not None:
670
            self.graphicsView.useDefaultCommand()
671

    
672
        for _action in self.actionGroup.actions():
673
            _action.setChecked(False)
674

    
675
        action.setChecked(True)
676

    
677
    '''
678
        @brief      Create Equipment
679
        @author     Jeongwoo
680
        @date       18.05.03
681
        @history    2018.05.04  Jeongwoo    Add Parameter on CreateSymbolCommand
682
    '''
683
    def createEquipment(self):
684
        if not self.graphicsView.hasImage():
685
            self.actionEquipment.setChecked(False)
686
            self.showImageSelectionMessageBox()
687
            return
688
        if self.actionEquipment.isChecked():
689
            self.graphicsView.command = CreateSymbolCommand.CreateSymbolCommand(self.graphicsView, self.resultTreeWidget, self.dirTreeWidget)
690
        else:
691
            self.graphicsView.useDefaultCommand()
692

    
693

    
694
    '''
695
        @brief      Create Nozzle
696
        @author     Jeongwoo
697
        @date       2018.05.03
698
        @history    2018.05.04  Jeongwoo    Add Parameter on CreateSymbolCommand
699
    '''
700
    def createNozzle(self):
701
        if not self.graphicsView.hasImage():
702
            self.actionNozzle.setChecked(False)
703
            self.showImageSelectionMessageBox()
704
            return
705
        if self.actionNozzle.isChecked():
706
            self.graphicsView.command = CreateSymbolCommand.CreateSymbolCommand(self.graphicsView, self.resultTreeWidget, self.dirTreeWidget)
707
        else:
708
            self.graphicsView.useDefaultCommand()
709

    
710
    '''
711
        @brief      Area OCR
712
        @author     Jeongwoo
713
        @date       18.04.18
714
        @history    2018.05.02  Jeongwoo    Change graphicsView.command by actionOCR checked state
715
                                            Show MessageBox when imageviewer doesn't have image
716
    '''
717
    def onAreaOcr(self):
718
        if not self.graphicsView.hasImage():
719
            self.actionOCR.setChecked(False)
720
            self.showImageSelectionMessageBox()
721
            return
722

    
723
        if self.actionOCR.isChecked():
724
            cmd = AreaOcrCommand.AreaOcrCommand(self.graphicsView)
725
            cmd.onSuccess.connect(self.onRecognizeText)
726
            cmd.onRejected.connect(self.onCommandRejected)
727
            self.graphicsView.command = cmd
728
        else:
729
            self.graphicsView.useDefaultCommand()
730
    
731
    '''
732
        @brief      show text recognition dialog
733
        @author     humkyung
734
        @date       2018.08.08
735
    '''
736
    def onRecognizeText(self, x, y, width, height):
737
        from OcrResultDialog import QOcrResultDialog
738

    
739
        try:
740
            image = self.graphicsView.image().copy(x, y, width, height)
741
            dialog = QOcrResultDialog(self.graphicsView, image, QRectF(x, y, width, height))
742
            (isAccept, textInfoList) = dialog.showDialog()
743
            if isAccept:
744
                if textInfoList is not None and len(textInfoList) > 0:
745
                    docData = AppDocData.instance()
746
                    for textInfo in textInfoList:
747
                        x = textInfo.getX()
748
                        y = textInfo.getY()
749
                        angle = textInfo.getAngle()
750
                        text = textInfo.getText()
751
                        width = textInfo.getW()
752
                        height = textInfo.getH()
753
                        item = TextItemFactory.instance().createTextItem(text)
754
                        if item is not None:
755
                            item.loc = (x, y)
756
                            item.size = (width, height)
757
                            item.angle = angle
758
                            item.setDefaultTextColor(Qt.blue)
759
                            item.addTextItemToScene(self.graphicsView.scene)
760
                            item.transfer.onRemoved.connect(self.itemRemoved)
761
                        else:
762
                            message = 'error occured({}) in {}:{}'.format('텍스트 생성에 실패했습니다.', sys.exc_info()[-1].tb_frame.f_code.co_filename, sys.exc_info()[-1].tb_lineno)
763
                            self.addMessage.emit(MessageType.Normal, message)
764
                else:
765
                    QMessageBox.about(self.graphicsView, "알림", "텍스트 검출 실패")
766
        except Exception as ex:
767
            message = 'error occured({}) in {}:{}'.format(ex, sys.exc_info()[-1].tb_frame.f_code.co_filename, sys.exc_info()[-1].tb_lineno)
768
            self.addMessage.emit(MessageType.Error, message)
769

    
770
    '''
771
        @brief  area configuration
772
    '''
773
    def areaConfiguration(self):
774
        from ConfigurationAreaDialog import QConfigurationAreaDialog
775
        if not self.graphicsView.hasImage():
776
            self.showImageSelectionMessageBox()
777
            return
778
        self.dlgConfigurationArea = QConfigurationAreaDialog(self)
779
        self.dlgConfigurationArea.show()
780
        self.dlgConfigurationArea.exec_()
781

    
782
    '''
783
        @brief  configuration
784
    '''
785
    def configuration(self):
786
        from ConfigurationDialog import QConfigurationDialog
787

    
788
        self.dlgConfiguration = QConfigurationDialog(self)
789
        self.dlgConfiguration.show()
790
        self.dlgConfiguration.exec_()
791

    
792
    '''
793
        @brief  show nominal diameter dialog 
794
        @author humkyung
795
        @date   2018.06.28
796
    '''
797
    def onShowCodeTable(self):
798
        from CodeTableDialog import QCodeTableDialog
799

    
800
        dlg = QCodeTableDialog(self)
801
        dlg.exec_()
802

    
803
    '''
804
        @brief  show HMB data
805
        @author humkyung
806
        @date   2018.07.11
807
    '''
808
    def onHMBData(self):
809
        from HMBDialog import QHMBDialog
810

    
811
        dlg = QHMBDialog(self)
812
        dlg.show()
813
        dlg.exec_()
814

    
815
    '''
816
        @brief  show line data list 
817
        @author humkyung
818
        @date   2018.05.03
819
    '''
820
    def showItemDataList(self):
821
        from ItemDataExportDialog import QItemDataExportDialog
822

    
823
        self.dlgLineDataList = QItemDataExportDialog(self)
824
        self.dlgLineDataList.exec_()
825

    
826
    '''
827
        @brief  Show Image Selection Guide MessageBox
828
        @author Jeongwoo
829
        @date   2018.05.02
830
    '''
831
    def showImageSelectionMessageBox(self):
832
        QMessageBox.about(self.graphicsView, "알림", "이미지를 선택하신 후 시도해주세요.")
833
        
834
    '''
835
        @brief  change selected lines' type by selected line type
836
        @author humkyung
837
        @date   2018.06.27
838
    '''
839
    def onLineTypeChanged(self, param):
840
        lineType = self.lineComboBox.itemText(param)
841
        selected = [item for item in self.graphicsView.scene.selectedItems() if type(item) is QEngineeringLineItem]
842
        if selected:
843
            for item in selected:
844
                item.lineType = lineType
845

    
846
    '''
847
        @brief      Open image drawing file and then display it
848
        @author     humkyung
849
        @date       2018.??.??
850
        @history    18.04.23 Jeongwoo    Add AppDocData.instance().setCurrentPidSource
851
                    18.04.23 Jeongwoo    Add Store Set Current Pid Image on AppDocData
852
                    18.05.02 Jeongwoo    Add useDefaultCommand()
853
                    humkyung 2018.05.24 load recognition result file if exists
854
                    Jeongwoo 2018.05.29 load data on xml if xml file exist
855
                    humkyung 2018.08.22 clear scene before loading xml file
856
    '''
857
    def onOpenImageDrawing(self, path=None):
858
        from Drawing import Drawing
859

    
860
        try:
861
            appDocData = AppDocData.instance()
862
            project = appDocData.getCurrentProject()
863
            
864
            for item in self.graphicsView.scene.items():
865
                self.graphicsView.scene.removeItem(item)
866

    
867
            self.path = self.graphicsView.loadImageFromFile(project.getDrawingFilePath(), path if type(path) is str else '')
868
            if os.path.isfile(self.path):
869
                appDocData.clear()
870
                self.graphicsView.useDefaultCommand()
871

    
872
                appDocData.setImgFilePath(self.path)
873
                appDocData.activeDrawing = Drawing(appDocData.imgName)
874
                appDocData.setCurrentPidSource(Image.open(self.path))
875
                self.resultTreeWidget.setCurrentPID(appDocData.activeDrawing.name)
876

    
877
                drawingList = self.treeWidgetDrawingList.topLevelItem(0)
878
                for childIdex in range(drawingList.childCount()):
879
                    drawingList.child(childIdex).setCheckState(0, Qt.Unchecked)
880
                for childIdex in range(drawingList.childCount()):
881
                    child = drawingList.child(childIdex)
882
                    if child.text(0).replace('.png', '') == appDocData.activeDrawing.name:
883
                        child.setCheckState(0, Qt.Checked)
884
                        break
885

    
886
                ## Load data on xml
887
                path = os.path.join(appDocData.getCurrentProject().getTempPath(), appDocData.imgName + '.xml')
888
                if os.path.isfile(path):
889
                    try:
890
                        self.progress = QProgressDialog("잠시만 기다려주세요", "Cancel", 0, 100, self) if not hasattr(self, 'progress') else self.progress
891
                        self.progress.setWindowModality(Qt.WindowModal)
892
                        self.progress.setAutoReset(True)
893
                        self.progress.setAutoClose(True)
894
                        self.progress.setMinimum(0)
895
                        self.progress.resize(600,100)
896
                        self.progress.setWindowTitle("파일 읽는 중...")
897
                        self.progress.show()
898

    
899
                        self.loadRecognitionResultFromXml(path)
900
                        self.checkAttribute()
901
                    finally:
902
                        self.progress.setValue(self.progress.maximum())
903
                        self.progress.hide()
904
                self.actionImage_Drawing.setChecked(True)
905
                self.actionViewText.setChecked(True)
906
                self.actionViewSymbol.setChecked(True)
907
                self.actionViewLine.setChecked(True)
908
                self.actionViewUnknown.setChecked(True)
909
        except Exception as ex:
910
            message = 'error occured({}) in {}:{}'.format(ex, sys.exc_info()[-1].tb_frame.f_code.co_filename, sys.exc_info()[-1].tb_lineno)
911
            self.addMessage.emit(MessageType.Error, message)
912

    
913
        return self.path
914

    
915
    '''
916
        @brief  visible/invisible image drawing
917
        @author humkyung
918
        @date   2018.06.25
919
    '''
920
    def onViewImageDrawing(self, isChecked):
921
        for item in self.graphicsView.scene.items():
922
            if type(item) is QGraphicsPixmapItem:
923
                item.setVisible(isChecked)
924
                break
925

    
926
    '''
927
        @brief  visible/invisible Text 
928
        @author humkyung
929
        @date   2018.06.28
930
    '''
931
    def onViewText(self, isChecked):
932
        selected = [item for item in self.graphicsView.scene.items() if issubclass(type(item), QEngineeringTextItem)]
933
        for item in selected:
934
            item.setVisible(isChecked)
935

    
936
    '''
937
        @brief  visible/invisible Symbol 
938
        @author humkyung
939
        @date   2018.06.28
940
    '''
941
    def onViewSymbol(self, isChecked):
942
        selected = [item for item in self.graphicsView.scene.items() if issubclass(type(item), SymbolSvgItem)]
943
        for item in selected:
944
            item.setVisible(isChecked)
945

    
946
    '''
947
        @brief  visible/invisible Line
948
        @author humkyung
949
        @date   2018.06.28
950
    '''
951
    def onViewLine(self, isChecked):
952
        selected = [item for item in self.graphicsView.scene.items() if type(item) is QEngineeringLineItem]
953
        for item in selected:
954
            item.setVisible(isChecked)
955

    
956
    '''
957
        @brief  visible/invisible Unknown 
958
        @author humkyung
959
        @date   2018.06.28
960
    '''
961
    def onViewUnknown(self, isChecked):
962
        selected = [item for item in self.graphicsView.scene.items() if type(item) is QEngineeringUnknownItem]
963
        for item in selected:
964
            item.setVisible(isChecked)
965

    
966
    '''
967
        @brief  create a symbol
968
        @history    2018.05.02  Jeongwoo    Change return value of QSymbolEditorDialog (Single variable → Tuple)
969
                                            Add SymbolSvgItem
970
                    2018.05.03  Jeongwoo    Change method to draw Svg Item on Scene (svg.addSvgItemToScene)
971
                                            Change method to make svg and image path
972
                    2018.06.08  Jeongwoo    Add Paramter on SymbolSvgItem.buildItem()
973
    '''
974
    def onCreateSymbolClicked(self):
975
        cmd = FenceCommand.FenceCommand(self.graphicsView)
976
        cmd.onSuccess.connect(self.onAreaSelected)
977
        self.graphicsView.command = cmd
978
        QApplication.setOverrideCursor(Qt.CrossCursor)
979

    
980
    '''
981
        @brief      show SymbolEditorDialog with image selected by user
982
        @author     humkyung
983
        @date       2018.07.20
984
    '''
985
    def onAreaSelected(self, x, y, width, height):
986
        try:
987
            image = self.graphicsView.image()
988
            if image is not None:
989
                symbolEditorDialog = SymbolEditorDialog.QSymbolEditorDialog(self, image.copy(x, y, width, height), AppDocData.instance().getCurrentProject())
990
                (isAccepted, isImmediateInsert, offsetX, offsetY, newSym) = symbolEditorDialog.showDialog()
991
                self.dirTreeWidget.initDirTreeWidget()
992
                if isAccepted:
993
                    if isImmediateInsert:
994
                        svgPath = newSym.getSvgFileFullPath()
995
                        img = cv2.imread(newSym.getImageFileFullPath(), 1)
996
                        w, h = (0, 0)
997
                        if len(img.shape[::-1]) == 2:
998
                            w, h = img.shape[::-1]
999
                        else:
1000
                            _chan, w, h = img.shape[::-1]
1001
                        svg = SymbolSvgItem(svgPath)
1002
                        svg.buildItem(newSym.getName(), newSym.getType(), 0, [offsetX, offsetY], [w, h], [float(x) for x in newSym.getOriginalPoint().split(',')], [(float(x.split(',')[0]), float(x.split(',')[1])) for x in newSym.getConnectionPoint().split('/')], newSym.getBaseSymbol(), newSym.getAdditionalSymbol(), newSym.getHasInstrumentLabel)
1003

    
1004
                        svg.transfer.onRemoved.connect(self.resultTreeWidget.itemRemoved)
1005
                        svg.addSvgItemToScene(self.graphicsView.scene)
1006
                        for connector in svg.connectors:
1007
                            self.graphicsView.scene.addItem(connector)
1008
        finally:
1009
            self.graphicsView.useDefaultCommand()
1010
            QApplication.restoreOverrideCursor()
1011
    
1012
    '''
1013
        @brief      create a line
1014
        @author     humkyung
1015
        @history    Jeongwoo 2018.05.10 Change method for Checkable action
1016
    '''
1017
    def onPlaceLine(self):        
1018
        if not self.graphicsView.hasImage():
1019
            self.actionLine.setChecked(False)
1020
            self.showImageSelectionMessageBox()
1021
            return
1022

    
1023
        self.actionLine.setChecked(True)
1024
        if not hasattr(self.actionLine, 'tag'):
1025
            self.actionLine.tag = PlaceLineCommand.PlaceLineCommand(self.graphicsView)
1026
            self.actionLine.tag.onSuccess.connect(self.onLineCreated)
1027
            self.actionLine.tag.onRejected.connect(self.onCommandRejected)
1028

    
1029
        self.graphicsView.command = self.actionLine.tag
1030

    
1031
    '''
1032
        @brief      add created lines to scene
1033
        @author     humkyung
1034
        @date       2018.07.23
1035
    '''
1036
    def onLineCreated(self):
1037
        from EngineeringConnectorItem import QEngineeringConnectorItem
1038

    
1039
        try:
1040
            count = len(self.actionLine.tag._polyline._vertices)
1041
            if count > 1:
1042
                items = []
1043

    
1044
                lineType = self.lineComboBox.currentText()
1045
                for index in range(count - 1):
1046
                    start = self.actionLine.tag._polyline._vertices[index]
1047
                    end  = self.actionLine.tag._polyline._vertices[index + 1]
1048
                    
1049
                    lineItem = QEngineeringLineItem(vertices=[start, end])
1050
                    lineItem.transfer.onRemoved.connect(self.itemRemoved)
1051
                    lineItem.lineType = lineType
1052
                    if items:
1053
                        lineItem.connectIfPossible(items[-1], 5)
1054
                    else:
1055
                        pt = lineItem.startPoint()
1056
                        selected = self.graphicsView.scene.itemAt(QPointF(pt[0], pt[1]), QTransform())
1057
                        if selected is not None and type(selected) is QEngineeringConnectorItem:
1058
                            lineItem.connectIfPossible(selected.parent, 5)
1059
                    
1060
                    items.append(lineItem)
1061
                    self.graphicsView.scene.addItem(lineItem)
1062

    
1063
                pt = items[-1].endPoint()
1064
                selected = self.graphicsView.scene.itemAt(QPointF(pt[0], pt[1]), QTransform())
1065
                if selected is not None and type(selected) is QEngineeringConnectorItem:
1066
                    items[-1].connectIfPossible(selected.parent, 5)
1067
        finally:
1068
            self.graphicsView.scene.removeItem(self.actionLine.tag._polyline)
1069
            self.actionLine.tag.reset()
1070

    
1071
    '''
1072
        @brief      refresh scene
1073
        @author     humkyung
1074
        @date       2018.07.23
1075
    '''
1076
    def onCommandRejected(self, cmd):
1077
        try:
1078
            if type(cmd) is PlaceLineCommand.PlaceLineCommand:
1079
                self.graphicsView.scene.removeItem(self.actionLine.tag._polyline)
1080
                self.graphicsView.scene.update()
1081
                self.actionLine.tag.reset()
1082

    
1083
                self.actionLine.setChecked(False)
1084
            elif type(cmd) is AreaZoomCommand.AreaZoomCommand:
1085
                self.actionZoom.setChecked(False)
1086
            elif type(cmd) is AreaOcrCommand.AreaOcrCommand:
1087
                self.actionOCR.setChecked(False)
1088
        finally:
1089
            self.graphicsView.useDefaultCommand()
1090
     
1091
    '''
1092
        @brief      restore to default command when user press Escape key
1093
        @author     humkyung 
1094
        @date       2018.08.09
1095
    '''
1096
    def keyPressEvent(self, event):
1097
        try:
1098
            if event.key() == Qt.Key_Escape:
1099
                checked = self.actionGroup.checkedAction()
1100
                if checked:
1101
                    checked.setChecked(False)
1102
                    self.graphicsView.useDefaultCommand()
1103

    
1104
            QMainWindow.keyPressEvent(self, event)
1105
        except Exception as ex:
1106
            message = 'error occured({}) in {}:{}'.format(ex, sys.exc_info()[-1].tb_frame.f_code.co_filename, sys.exc_info()[-1].tb_lineno)
1107
            self.addMessage.emit(MessageType.Error, message)
1108
    
1109
    def recognizeBatch(self, MainWindow):
1110
        '''
1111
            @brief      batch recognize symbol, text and line
1112
            @author     euisung
1113
            @date       2018.11.23
1114
        
1115
        '''
1116
        from datetime import datetime
1117
        from RecognitionDialog import QRecognitionDialog
1118

    
1119
        appDocData = AppDocData.instance()
1120
        project = appDocData.getCurrentProject()
1121
        appDocData.needReOpening = None
1122
        currentPid = None
1123
        
1124
        if self.graphicsView.hasImage():
1125
            currentPid = appDocData.activeDrawing.name
1126

    
1127
        drawingTop = self.treeWidgetDrawingList.topLevelItem(0)
1128
        drawingCount = drawingTop.childCount()
1129
        checkedTreeItems = []
1130
        checkedDrawingPath = []
1131
        for drawing in range(drawingCount):
1132
            drawingChild = drawingTop.child(drawing)
1133
            if drawingChild.checkState(0) == 2:
1134
                checkedTreeItems.append(drawingChild)
1135
                checkedDrawingPath.append(os.path.join(project.getDrawingFilePath(), drawingChild.data(0, 0)))
1136
                if currentPid is not None and drawingChild.data(0, 0).find(currentPid) is 0:
1137
                    appDocData.needReOpening = False # later check need reopening at drawUnknownItems()
1138
                    currentPid = drawingChild.data(0, 0)
1139

    
1140
        if len(checkedDrawingPath) == 0:
1141
            self.showImageSelectionMessageBox()
1142
            return
1143

    
1144
        try:
1145
            self.onClearLog()
1146
            self.dlg = QRecognitionDialog(self, checkedDrawingPath, True)
1147
            self.dlg.exec_()
1148
            if self.dlg.isAccepted == True:
1149
                pass
1150

    
1151
            if appDocData.needReOpening == True:
1152
                drawing = os.path.join(appDocData.getCurrentProject().getDrawingFilePath(), currentPid)
1153
                self.onOpenImageDrawing(drawing)
1154

    
1155
                
1156
            # save working date-time
1157
            drawings = appDocData.getDrawings()
1158
            checkedDrawings = []
1159
            for checkedTreeItem in checkedTreeItems:
1160
                for drawing in drawings:
1161
                    if checkedTreeItem.data(0, 0) == drawing[1]:
1162
                        if drawing[0]:
1163
                            drawing[2] = datetime.now().strftime('%Y-%m-%d %H:%M:%S')
1164
                            checkedDrawings.append(drawing)
1165
                            checkedTreeItem.setText(1, datetime.now().strftime('%Y-%m-%d %H:%M:%S'))
1166
            appDocData.saveDrawings(checkedDrawings)
1167
            # up to here
1168
        except Exception as ex:
1169
            message = 'error occured({}) in {}:{}'.format(ex, sys.exc_info()[-1].tb_frame.f_code.co_filename, sys.exc_info()[-1].tb_lineno)
1170
            self.addMessage.emit(MessageType.Error, message)
1171

    
1172
    '''
1173
        @brief      recognize symbol and text
1174
        @author     humkyung
1175
        @date       2018.04.??
1176
        @history    2018.04.16  humkyung    execute line no tracing
1177
                    2018.05.02  Jeongwoo    Show MessageBox when imageviewer doesn't have image
1178
                    2018.05.25  Jeongwoo    Add parameter on QRecognitionDialog.__init__() and Move thread to QRecognitionDialog
1179
                                            Remove codes below if self.dlg.isAccepted == True
1180
                    2018.05.29  Jeongwoo    Remove connects and comments
1181
                    humkyung 2018.11.05 save working date-time
1182
    '''
1183
    def recognize(self, MainWindow):
1184
        from datetime import datetime
1185
        from RecognitionDialog import QRecognitionDialog
1186

    
1187
        if not self.graphicsView.hasImage():
1188
            self.showImageSelectionMessageBox()
1189
            return
1190

    
1191
        try:
1192
            self.removedItems['LINE'] = []
1193
            self.removedItems['EQUIP'] = []
1194
            self.removedItems['INST'] = []
1195
            self.removedItems['NOTE'] = []
1196

    
1197
            appDocData = AppDocData.instance()
1198
            self.resultTreeWidget.setCurrentPID(appDocData.activeDrawing.name)
1199
            ## up to here
1200

    
1201
            self.onClearLog()
1202
            appDocData.needReOpening = False
1203
            drawingList = []
1204
            drawingList.append(self.path)
1205
            self.dlg = QRecognitionDialog(self, drawingList, False)
1206
            self.dlg.exec_()
1207
            if self.dlg.isAccepted == True:
1208
                self.drawDetectedItemsToScene()
1209
                '''DO NOTHING'''
1210
                
1211
            # save working date-time
1212
            drawings = appDocData.getDrawings()
1213
            drawing = [drawing for drawing in drawings if appDocData.imgName == os.path.splitext(drawing[1])[0]]
1214
            if drawing[0]:
1215
                drawing[0][2] = datetime.now().strftime('%Y-%m-%d %H:%M:%S')
1216
                appDocData.saveDrawings(drawing)
1217

    
1218
            currentPid = appDocData.activeDrawing.name
1219

    
1220
            drawingTop = self.treeWidgetDrawingList.topLevelItem(0)
1221
            drawingCount = drawingTop.childCount()
1222

    
1223
            if appDocData.needReOpening == True:
1224
                for drawing in range(drawingCount):
1225
                    drawingChild = drawingTop.child(drawing)
1226
                    if drawingChild.data(0, 0).find(currentPid) is 0:
1227
                        drawingChild.setText(1, datetime.now().strftime('%Y-%m-%d %H:%M:%S'))
1228
            # up to here
1229
        except Exception as ex:
1230
            message = 'error occured({}) in {}:{}'.format(ex, sys.exc_info()[-1].tb_frame.f_code.co_filename, sys.exc_info()[-1].tb_lineno)
1231
            self.addMessage.emit(MessageType.Error, message)
1232

    
1233
    '''
1234
        @brief      remove item from tree widget and then remove from scene
1235
        @date       2018.05.25
1236
        @author     Jeongwoo
1237
    '''
1238
    def itemRemoved(self, item):
1239
        try:
1240
            self.resultTreeWidget.itemRemoved(item)
1241

    
1242
            if type(item) is QEngineeringLineNoTextItem:
1243
                self.removedItems['LINE'].append(str(item.uid))
1244
            elif type(item) is QEngineeringInstrumentItem:
1245
                self.removedItems['INST'].append(str(item.uid))
1246
            elif type(item) is QEngineeringEquipmentItem:
1247
                self.removedItems['EQUIP'].append(str(item.uid))
1248
            elif type(item) is QEngineeringNoteItem:
1249
                self.removedItems['NOTE'].append(str(item.uid))
1250

    
1251
            if hasattr(item, 'connectors'):
1252
                for sceneItem in self.graphicsView.scene.items():
1253
                    if hasattr(sceneItem, 'connectors'):
1254
                        for sceneConnector in sceneItem.connectors:
1255
                            if sceneConnector.connectedItem is not None and item.uid == sceneConnector.connectedItem.uid:
1256
                                sceneConnector.connectedItem = None
1257

    
1258
            if item.scene() is not None: item.scene().removeItem(item)
1259
        except Exception as ex:
1260
            message = 'error occured({}) in {}:{}'.format(ex, sys.exc_info()[-1].tb_frame.f_code.co_filename, sys.exc_info()[-1].tb_lineno)
1261
            self.addMessage.emit(MessageType.Error, message)
1262

    
1263
    '''
1264
        @brief      recognize line
1265
        @author     humkyung
1266
        @date       2018.04.19
1267
        @history    Jeongwoo 2018.04.26 Variable name changed (texts → lineNos)
1268
                                        TextItem type changed (QEngineeringTextItem → QEngineeringLineNoTextItem)
1269
                    humkyung 2018.04.26 remove small objects before recognizing line
1270
                    Jeongwoo 2018.05.02 Show MessageBox when imageviewer doesn't have image
1271
                    Jeongwoo 2018.05.25 Move codes about LineDetector
1272
                    humkyung 2018.06.17 show progress dialog
1273
    '''
1274
    def recognizeLine(self, MainWindow):
1275
        from LineNoTracer import LineNoTracer
1276
        from ConnectAttrDialog import QConnectAttrDialog
1277

    
1278
        if not self.graphicsView.hasImage():
1279
            self.showImageSelectionMessageBox()
1280
            return
1281

    
1282
        try:
1283
            self.dlgConnectAttr = QConnectAttrDialog(self, self.graphicsView)
1284
            self.dlgConnectAttr.exec_()
1285

    
1286
            self.resultTreeWidget.InitLineNoItems()
1287

    
1288
            # construct line no item
1289
            docData = AppDocData.instance()
1290
            for lineno in docData.lineNos:
1291
                item = self.resultTreeWidget.addTreeItem(self.resultTreeWidget.root, lineno)
1292
                connectedItems = lineno.getConnectedItems()
1293
                for connectedItem in connectedItems:
1294
                    if issubclass(type(connectedItem), SymbolSvgItem): 
1295
                        self.resultTreeWidget.addTreeItem(item, connectedItem)
1296
            # up to here
1297
        except Exception as ex:
1298
            message = 'error occured({}) in {}:{}'.format(ex, sys.exc_info()[-1].tb_frame.f_code.co_filename, sys.exc_info()[-1].tb_lineno)
1299
            self.addMessage.emit(MessageType.Error, message)
1300

    
1301
    '''
1302
        @history    2018.05.25  Jeongwoo    Moved from MainWindow
1303
                                            SvgItem and TextItem Connect with method in this class
1304
                                            Change method to add GraphicsItem
1305
                    2018.05.28  Jeongwoo    Make QGraphicsItem by symbol, text object. Not xml
1306
                    2018.05.29  Jeongwoo    Change method name and Moved from QRecognitionDialog
1307
                    2018.05.30  Jeongwoo    Add parameters on SymbolSvgItem.__init__() (parentSymbol, childSymbol)
1308
                                            Change Method name and seperate each item
1309
                    humkyung 2018.06.11     display difference between original and recognized image
1310
                    Jeongwoo 2018.06.18     Update Scene after all item added
1311
                    2018.11.05  euisung     add save note item because of dependency
1312
                    2018.11.05  euisung     add db delete process before save
1313
                    2018.11.12  euisung     add title block properties
1314
                    2018.11.12  euisung     db part move new method to dbUpdate
1315
                    2018.11.26  euisung     isolate scene adding part -> drawDetectedItemsToScene()
1316
                    2018.11.29  euisung     change name drawDetectedItems() -> createDetectedItems
1317
    '''
1318
    def createDetectedItems(self, symbolList, textInfoList, otherTextInfoList, titleBlockTextInfoList):
1319
        try:
1320
            appDocData = AppDocData.instance()
1321
            #appDocData.deleteDataListBeforeSave()
1322

    
1323
            QApplication.processEvents()
1324
            self.createDetectedSymbolItem(symbolList)
1325
            QApplication.processEvents()
1326
            self.createDetectedTextItem(textInfoList)
1327
            QApplication.processEvents()
1328
            self.createDetectedOtherTextItem(otherTextInfoList)
1329
            QApplication.processEvents()
1330
            self.createDetectedTitleBlockTextItem(titleBlockTextInfoList)
1331

    
1332
            self.dbUpdate()
1333
            #self.saveToXml(False)
1334

    
1335
            # update scene
1336
            #self.graphicsView.scene.update(self.graphicsView.sceneRect())
1337
        except Exception as ex:
1338
            message = 'error occured({}) in {}:{}'.format(ex, sys.exc_info()[-1].tb_frame.f_code.co_filename, sys.exc_info()[-1].tb_lineno)
1339
            self.addMessage.emit(MessageType.Error, message)
1340

    
1341
    def drawDetectedItemsToScene(self):
1342
        '''
1343
            @brief  add detected items to scene
1344
            @author euisung
1345
            @date   2018.11.26
1346
        '''
1347
        appDocData = AppDocData.instance()
1348

    
1349
        try:
1350
            for symbol in appDocData.symbols:
1351
                if issubclass(type(symbol), SymbolSvgItem):
1352
                    self.addSvgItemToScene(symbol)
1353
                else:
1354
                    self.graphicsView.scene.addItem(symbol)
1355

    
1356
            for text in appDocData.texts:
1357
                self.addTextItemToScene(text)
1358

    
1359
            for line in appDocData.lines:
1360
                self.graphicsView.scene.addItem(line)
1361

    
1362
            for unknown in appDocData.unknowns:
1363
                self.addUnknownItemToScene(unknown)
1364
        finally:
1365
            # update scene
1366
            self.graphicsView.scene.update(self.graphicsView.sceneRect())
1367

    
1368
    def postDetectLineProcess(self):
1369
        '''
1370
            @brief  check allowables among undetected items
1371
            @author euisung
1372
            @date   2018.11.15
1373
            @history    2018.11.15  euisung    no more used, moved to TextItemFactoy isLineNo()
1374
        '''
1375
        from AppDocData import AppDocData
1376
        from TextItemFactory import TextItemFactory
1377

    
1378
        appDocData = AppDocData.instance()
1379

    
1380
        tableNames = ["Fluid Code", "Insulation Purpose", "PnID Number", "Piping Materials Class", "Unit Number"]
1381
        tableDatas = []
1382
        for tableName in tableNames:
1383
            tableNameFormat = tableName.replace(' ','').replace('&&', 'n')
1384
            tableDatas.append(appDocData.getCodeTable(tableNameFormat))
1385

    
1386
        items = self.graphicsView.scene.items()
1387
        for item in items:
1388
            if type(item) is not QEngineeringTextItem:
1389
                continue
1390
            text = item.text()
1391
            for tableData in tableDatas:
1392
                for data in tableData:
1393
                    if data[3] == '':
1394
                        continue
1395
                    else:
1396
                        allows = data[3].split(',')
1397
                        for allow in allows:
1398
                            text = text.replace(allow, data[1])
1399

    
1400
            lineItem = TextItemFactory.instance().createTextItem(text)
1401
            if type(lineItem) is QEngineeringLineNoTextItem:
1402
                lineItem.loc = item.loc
1403
                lineItem.size = item.size
1404
                lineItem.angle = item.angle
1405
                lineItem.area = item.area
1406
                #lineItem.addTextItemToScene(self.graphicsView.scene)
1407
                lineItem.transfer.onRemoved.connect(self.itemRemoved)
1408
                item.transfer.onRemoved.emit(item)
1409
                appDocData.lineNos.append(lineItem)
1410
                
1411
    def createDetectedTitleBlockTextItem(self, textInfoList):
1412
        '''
1413
            @brief  draw title block
1414
            @author euisung
1415
            @date   2018.11.12
1416
            @history    2018.11.26  euisung     remove scene dependency
1417
                        2018.11.29  euisung     change name drawDetectedTitleBlockTextItem() -> createDetectedTitleBlockTextItem
1418
        '''
1419
        from TextItemFactory import TextItemFactory
1420
        import math
1421

    
1422
        try:
1423
            appDocData = AppDocData.instance()
1424

    
1425
            # parse texts
1426
            for textInfo in textInfoList:
1427
                x = textInfo[1][0].getX()
1428
                y = textInfo[1][0].getY()
1429
                width = textInfo[1][0].getW()
1430
                height = textInfo[1][0].getH()
1431
                angle = round(math.radians(textInfo[1][0].getAngle()), 2)
1432
                text = textInfo[1][0].getText()
1433
                item = TextItemFactory.instance().createTextItem(text)
1434

    
1435
                if item is not None:
1436
                    item.loc = (x, y)
1437
                    item.size = (width, height)
1438
                    item.angle = angle
1439
                    item.area = textInfo[0]
1440
                    #self.addTextItemToScene(item)
1441
                    appDocData.texts.append(item)
1442
                    appDocData.allItems.append(item)
1443
        except Exception as ex:
1444
            message = 'error occured({}) in {}:{}'.format(ex, sys.exc_info()[-1].tb_frame.f_code.co_filename, sys.exc_info()[-1].tb_lineno)
1445
            self.addMessage.emit(MessageType.Error, message)
1446

    
1447
    '''
1448
        @brief      
1449
        @author     humkyung
1450
        @date       2018.08.23
1451
        @history    2018.11.26  euisung     remove scene dependency
1452
                    2018.11.26  euisung     isolate scene adding part -> drawDetectedItemsToScene()
1453
                    2018.11.    euisung     no more used
1454
                    2018.11.29  euisung     change name drawDetectedLines() -> createDetectedLines
1455
    '''
1456
    def createDetectedLines(self, lineList, worker):
1457
        appDocData = AppDocData.instance()
1458
        area = appDocData.getArea('Drawing')
1459

    
1460
        for pts in lineList:
1461
            processLine = QEngineeringLineItem(vertices=[(area.x + param[0], area.y + param[1]) for param in pts])
1462
            processLine.area = 'Drawing'
1463
            #self.graphicsView.scene.addItem(processLine)
1464
            appDocData.lines.append(processLine)
1465
            appDocData.allItems.append(processLine)
1466

    
1467
            if processLine.length() > 100: # TODO: check critical length
1468
                processLine.addFlowArrow()
1469
        
1470
        # re-order process line's start,end according to flow mark
1471
        #worker.arrangeLinePosition(lines, symbols, listWidget)
1472
        # up to here
1473

    
1474
    '''
1475
        history     2018.06.09  humkyung    check length of original and connection point is 2 while parsing
1476
                    2018.11.26  euisung     remove scene dependency
1477
                    2018.11.29  euisung     change name drawDetectedSymbolItem() -> createDetectedSymbolItem
1478
    '''
1479
    def createDetectedSymbolItem(self, symbolList):
1480
        from GraphicsBoundingBoxItem import QGraphicsBoundingBoxItem
1481
        from SymbolSvgItem import SymbolSvgItem
1482
        import math
1483

    
1484
        try:
1485
            appDocData = AppDocData.instance()
1486
            project = appDocData.getCurrentProject()
1487

    
1488
            searchedMap = []
1489
            for symbol in symbolList:
1490
                pt = [float(x) for x in symbol.getSp()]
1491
                size = [symbol.getWidth(), symbol.getHeight()]
1492
                name = symbol.getName()
1493
                angle = round(math.radians(symbol.getRotatedAngle()), 2)
1494
                _type = symbol.getType()
1495
                origin = [0,0]
1496
                if 2 == len(symbol.getOriginalPoint().split(',')):
1497
                    tokens = symbol.getOriginalPoint().split(',')
1498
                    origin = [pt[0] + float(tokens[0]), pt[1] + float(tokens[1])]
1499
                connPts = []
1500
                if symbol.getConnectionPoint() is not None:
1501
                    connPts = [(param.split(',')[0], pt[0] + float(param.split(',')[1]), pt[1] + float(param.split(',')[2])) for param in symbol.getConnectionPoint().split('/') if 3 == len(param.split(','))]
1502
                parentSymbol = symbol.getBaseSymbol()
1503
                childSymbol = symbol.getAdditionalSymbol()
1504
                hasInstrumentLabel = symbol.getHasInstrumentLabel()
1505

    
1506
                svgFilePath = os.path.join(project.getSvgFilePath(), _type, name + '.svg')
1507
                if os.path.isfile(svgFilePath):
1508
                    svg = SymbolSvgItem.createItem(_type, svgFilePath)
1509
                    svg.buildItem(name, _type, angle, pt, size, origin, connPts, parentSymbol, childSymbol, hasInstrumentLabel)
1510
                    svg.reCalculationRotatedItem()
1511
                    svg.area = 'Drawing'
1512

    
1513
                    # set owner - 2018.07.20 added by humkyung                   
1514
                    matches = [searched for searched in searchedMap if searched[0] == symbol.owner]
1515
                    if len(matches) == 1:
1516
                        svg.owner = matches[0][1]
1517
                    searchedMap.append((symbol, svg))
1518
                    # up to here
1519

    
1520
                    svg.transfer.onRemoved.connect(self.itemRemoved)
1521
                    #self.addSvgItemToScene(svg)
1522
                    appDocData.symbols.append(svg)
1523
                    appDocData.allItems.append(svg)
1524
                else:
1525
                    item = QGraphicsBoundingBoxItem(pt[0], pt[1], size[0], size[1])
1526
                    item.isSymbol = True
1527
                    item.angle = angle
1528
                    item.setPen(QPen(Qt.red, 5, Qt.SolidLine))
1529
                    #self.graphicsView.scene.addItem(item)
1530
                    appDocData.symbols.append(item)
1531
                    appDocData.allItems.append(item)
1532
            # up to here
1533
        except Exception as ex:
1534
            message = 'error occured({}) in {}:{}'.format(ex, sys.exc_info()[-1].tb_frame.f_code.co_filename, sys.exc_info()[-1].tb_lineno)
1535
            self.addMessage.emit(MessageType.Error, message)
1536

    
1537
    '''
1538
        @history    2018.06.08  Jeongwoo    Add parameter on round method
1539
        @history    2018.11.02  euisung     Add save note text item
1540
        @history    2018.11.05  euisung     delete save note text item and move to drawDetectedItems()
1541
                    2018.11.26  euisung     remove scene dependency
1542
                    2018.11.29  euisung     change name drawDetectedTextItem() -> createDetectedTextItem
1543
    '''
1544
    def createDetectedTextItem(self, textInfoList):
1545
        from TextItemFactory import TextItemFactory
1546
        import math
1547

    
1548
        try:
1549
            appDocData = AppDocData.instance()
1550

    
1551
            # parse texts
1552
            for textInfo in textInfoList:
1553
                x = textInfo.getX()
1554
                y = textInfo.getY()
1555
                width = textInfo.getW()
1556
                height = textInfo.getH()
1557
                angle = round(math.radians(textInfo.getAngle()), 2)
1558
                text = textInfo.getText()
1559
                if not text: continue
1560

    
1561
                item = TextItemFactory.instance().createTextItem(text)
1562
                if item is not None:
1563
                    item.loc = (x, y)
1564
                    item.size = (width, height)
1565
                    item.angle = angle
1566
                    item.area = 'Drawing'
1567
                    item.transfer.onRemoved.connect(self.itemRemoved)
1568
                    #self.addTextItemToScene(item)
1569
                    appDocData.texts.append(item)
1570
                    appDocData.allItems.append(item)
1571
        except Exception as ex:
1572
            message = 'error occured({}) in {}:{}'.format(ex, sys.exc_info()[-1].tb_frame.f_code.co_filename, sys.exc_info()[-1].tb_lineno)
1573
            self.addMessage.emit(MessageType.Error, message)
1574

    
1575
    '''
1576
        @brief      draw detected texts except which in drawing area
1577
        @history    2018.11.29  euisung     change name drawDetectedOtherTextItem() -> createDetectedOtherTextItem
1578
    '''
1579
    def createDetectedOtherTextItem(self, otherTextInfoList):
1580
        from TextItemFactory import TextItemFactory
1581
        import math
1582

    
1583
        try:
1584
            appDocData = AppDocData.instance()
1585

    
1586
            # parse notes
1587
            for textInfoMap in otherTextInfoList:
1588
                if textInfoMap[0]=='Note':
1589
                    pass
1590

    
1591
                for textInfo in textInfoMap[1]:
1592
                    x = textInfo.getX()
1593
                    y = textInfo.getY()
1594
                    width = textInfo.getW()
1595
                    height = textInfo.getH()
1596
                    angle = round(math.radians(textInfo.getAngle()))
1597
                    text = textInfo.getText()
1598

    
1599
                    item = TextItemFactory.instance().createTextItem(text)
1600

    
1601
                    item.loc = (x, y)
1602
                    item.size = (width, height)
1603
                    item.angle = angle
1604
                    item.area = textInfoMap[0]
1605
                    item.transfer.onRemoved.connect(self.itemRemoved)
1606
                    appDocData.texts.append(item)
1607
                    appDocData.allItems.append(item)
1608
        except Exception as ex:
1609
            message = 'error occured({}) in {}:{}'.format(ex, sys.exc_info()[-1].tb_frame.f_code.co_filename, sys.exc_info()[-1].tb_lineno)
1610
            self.addMessage.emit(MessageType.Error, message)
1611

    
1612
    '''
1613
        @brief  draw unknown items 
1614
        @author humkyung
1615
        @date   2018.06.12
1616
        @history    2018.06.14  Jeongwoo    Change method to add unknown item
1617
                    2018.06.18  Jeongwoo    Add connect on unknown item
1618
                                            Add [transfer] for using pyqtSignal
1619
                    2018.11.26  euisung     remove scene dependency
1620
                    2018.11.26  euisung     isolate scene adding part -> drawDetectedItemsToScene()
1621
                    2018.11.27  euisung     add save to xml
1622
                    2018.11.29  euisung     change name drawUnknownItems() -> createUnknownItems
1623
    '''
1624
    def createUnknownItems(self, path):
1625
        from QEngineeringFlowArrowItem import QEngineeringFlowArrowItem 
1626
        from EngineeringLineItem import QEngineeringLineItem
1627
        from EngineeringUnknownItem import QEngineeringUnknownItem
1628

    
1629
        try:
1630
            docData = AppDocData.instance()
1631
            project = docData.getCurrentProject()
1632
            windowSize = docData.getSlidingWindowSize()
1633
            thickness = int(windowSize[1])
1634

    
1635
            if docData.needReOpening is not None:
1636
                docData.needReOpening = True
1637

    
1638
            diffFilePath = os.path.join(project.getTempPath(), "DIFF_" + os.path.basename(path))
1639
            if os.path.isfile(diffFilePath):
1640
                imgDiff = cv2.threshold(cv2.cvtColor(cv2.imread(diffFilePath, 1), cv2.COLOR_BGR2GRAY), 127, 255, cv2.THRESH_BINARY)[1]
1641

    
1642
                ## remove line
1643
                lines = docData.lines
1644
                for line in lines:
1645
                    line.drawToImage(imgDiff, 255, thickness)
1646
                cv2.imwrite(diffFilePath, imgDiff)
1647
                ## up to here
1648

    
1649
                imgNot = np.ones(imgDiff.shape, np.uint8)
1650
                cv2.bitwise_not(imgDiff, imgNot)
1651
                imgNot = cv2.dilate(imgNot, np.ones((8,8), np.uint8))
1652

    
1653
                diffItems = []
1654

    
1655
                image, contours, hierarchy = cv2.findContours(imgNot, cv2.RETR_EXTERNAL, cv2.CHAIN_APPROX_SIMPLE)
1656
                for contour in contours:
1657
                    [x, y, w, h] = cv2.boundingRect(contour)
1658

    
1659
                    # remove too small one
1660
                    if (w < 10 or h < 10): continue
1661

    
1662
                    '''
1663
                    rect = QRectF(x, y, w, h)
1664
                    items = [item for item in diffItems if item.boundingRect().contains(rect)]
1665
                    if len(items) > 0: continue
1666
                    
1667
                    items = [item for item in diffItems if rect.contains(item.boundingRect())]
1668
                    for item in items:
1669
                        diffItems.remove(item)
1670
                    '''
1671

    
1672
                    # create unknown item
1673
                    epsilon = cv2.arcLength(contour, True)*0.001
1674
                    approx = cv2.approxPolyDP(contour, epsilon, True)
1675
                    approx = [pt[0] for pt in approx]
1676
                    item = QEngineeringUnknownItem(approx)
1677
                    item.area = 'Drawing'
1678
                    diffItems.append(item)
1679
                    # up to here
1680

    
1681
                for item in diffItems:
1682
                    item.transfer.onRemoved.connect(self.itemRemoved)
1683
                    #self.addUnknownItemToScene(item)
1684
                    docData.unknowns.append(item)
1685
                    docData.allItems.append(item)
1686

    
1687
                notFilePath = os.path.join(project.getTempPath(), "NOT_" + os.path.basename(path))
1688
                cv2.imwrite(notFilePath, imgNot)
1689
            else:
1690
                message = 'can\'t found {}'.format(diffFilePath)
1691
                self.addMessage.emit(MessageType.Normal, message)
1692

    
1693
            self.saveToXml(False)
1694
        except Exception as ex:
1695
            message = 'error occured({}) in {}:{}'.format(ex, sys.exc_info()[-1].tb_frame.f_code.co_filename, sys.exc_info()[-1].tb_lineno)
1696
            self.addMessage.emit(MessageType.Error, message)
1697

    
1698
    '''
1699
        @brief      load recognition result
1700
        @author     humkyung
1701
        @date       2018.04.??
1702
        @history    humkyung 2018.01.12 parse originalpoint and connectionpoint
1703
                    Jeongwoo 2018.04.17 add QGraphicItem with Rotated text
1704
                    Jeongwoo 2018.04.23 Change to Draw texts on QEngineeringTextItem
1705
                    humkyung 2018.04.23 connect item remove slot to result tree
1706
                    Jeongwoo 2018.04.25 Add if state with QEngineeringNoteItem
1707
                    Jeongwoo 2018.04.26 Change method to create TextItem object with TextItemFactory
1708
                    Jeongwoo 2018.05.03 Change method to draw Svg Item on Scene (svg.addSvgItemToScene)
1709
                    Jeongwoo 2018.05.29 Change method name / Change method to add item / Add Line item
1710
                    Jeongwoo 2018.05.30 Add parameters on SymbolSvgItem.__init__() (parentSymbol, childSymbol) / Change method name / Change XML NODE NAMES
1711
                    Jeongwoo 2018.06.12 Add LineNoTextItem from LINE_NO
1712
                    Jeongwoo 2018.06.14 Add UnknownItem from UNKNOWN
1713
                    Jeongwoo 2018.06.18 Update Scene after all item added
1714
                                        Add connect on unknown item
1715
                                        Add [transfer] for using pyqtSignal
1716
                    kyouho  2018.07.12  Add line property logic
1717
                    humkyung 2018.08.22 show progress while loading xml file
1718
                    2018.11.22      euisung     fix note road
1719
    '''
1720
    def loadRecognitionResultFromXml(self, xmlPath):
1721
        docData = AppDocData.instance()
1722
        from xml.etree.ElementTree import Element, SubElement, dump, ElementTree, parse
1723
        from EngineeringRunItem import QEngineeringRunItem
1724
        from QEngineeringTrimLineNoTextItem import QEngineeringTrimLineNoTextItem
1725

    
1726
        try:
1727
            symbols = []
1728

    
1729
            xml = parse(xmlPath)
1730
            root = xml.getroot()
1731
            
1732
            maxValue = 0
1733
            maxValue = maxValue + len(list(root.iter('SYMBOL')))
1734
            maxValue = maxValue + len(list(root.iter('ATTRIBUTE')))
1735
            maxValue = maxValue + len(list(root.iter('LINE_NO')))
1736
            maxValue = maxValue + len(list(root.iter('LINE')))
1737
            maxValue = maxValue + len(list(root.iter('UNKNOWN')))
1738
            maxValue = maxValue + len(list(root.iter('SIZETEXT')))
1739
            self.progress.setMaximum(maxValue)
1740

    
1741
            for symbol in root.find('SYMBOLS').iter('SYMBOL'):
1742
                item = SymbolSvgItem.fromXml(symbol)
1743
                if item[0] is not None:
1744
                    item[0].transfer.onRemoved.connect(self.itemRemoved)
1745
                    symbols.append(item)
1746
                else:
1747
                    pt = [float(x) for x in symbol.find('LOCATION').text.split(',')]
1748
                    size = [float(x) for x in symbol.find('SIZE').text.split(',')]
1749
                    angle = float(symbol.find('ANGLE').text)
1750
                    item = QGraphicsBoundingBoxItem(pt[0], pt[1], size[0], size[1])
1751
                    item.isSymbol = True
1752
                    item.angle = angle
1753
                    item.setPen(QPen(Qt.red, 5, Qt.SolidLine))
1754
                    self.graphicsView.scene.addItem(item)
1755

    
1756
                self.progress.setValue(self.progress.value() + 1)
1757
                
1758
            QApplication.processEvents()
1759

    
1760
            # set symbol's owner
1761
            childItems = [item for item in symbols if item[1] is not None]
1762
            for item in childItems:
1763
                matches = [param for param in symbols if str(param[0].uid) == item[1]]
1764
                if len(matches) == 1:
1765
                    item[0].owner = matches[0][0]
1766
            # up to here
1767
           
1768
            for item in symbols:
1769
                self.addSvgItemToScene(item[0])
1770

    
1771
            # parse texts
1772
            for text in root.find('TEXTINFOS').iter('ATTRIBUTE'):
1773
                item = QEngineeringTextItem.fromXml(text)
1774
                if item is not None:
1775
                    uid = text.find('UID')
1776
                    attributeValue = text.find('ATTRIBUTEVALUE')
1777
                    name = text.find('NAME').text
1778
                    item.transfer.onRemoved.connect(self.itemRemoved)
1779
                    self.addTextItemToScene(item)
1780

    
1781
                    if name == 'TEXT':
1782
                        if uid is not None and attributeValue is not None:
1783
                            item.uid = uid.text
1784
                            item.attribute = attributeValue.text
1785

    
1786
                self.progress.setValue(self.progress.value() + 1)
1787
                
1788
            QApplication.processEvents()
1789

    
1790
            # note
1791
            for text in root.find('NOTES').iter('ATTRIBUTE'):
1792
                item = QEngineeringTextItem.fromXml(text)
1793
                if item is not None:
1794
                    uid = text.find('UID')
1795
                    attributeValue = text.find('ATTRIBUTEVALUE')
1796
                    name = text.find('NAME').text
1797
                    item.transfer.onRemoved.connect(self.itemRemoved)
1798
                    self.addTextItemToScene(item)
1799

    
1800
                    if name == 'NOTE':
1801
                        if uid is not None:
1802
                            item.uid = uid.text
1803

    
1804
                self.progress.setValue(self.progress.value() + 1)
1805
                
1806
            QApplication.processEvents()
1807
            
1808
            # SIZE TEXT
1809
            for text in root.find('SIZETEXT').iter('ATTRIBUTE'):
1810
                item = QEngineeringTextItem.fromXml(text)
1811
                if item is not None:
1812
                    uid = text.find('UID')
1813
                    attributeValue = text.find('ATTRIBUTEVALUE')
1814
                    name = text.find('NAME').text
1815
                    item.transfer.onRemoved.connect(self.itemRemoved)
1816
                    self.addTextItemToScene(item)
1817

    
1818
                self.progress.setValue(self.progress.value() + 1)
1819
                
1820
            QApplication.processEvents()
1821

    
1822
            for line in root.find('LINEINFOS').iter('LINE'):
1823
                item = QEngineeringLineItem.fromXml(line)
1824
                item.transfer.onRemoved.connect(self.itemRemoved)
1825
                if item: self.addLineItemToScene(item)
1826

    
1827
                self.progress.setValue(self.progress.value() + 1)
1828
                
1829
            QApplication.processEvents()
1830

    
1831
            for unknown in root.iter('UNKNOWN'):
1832
                item = QEngineeringUnknownItem.fromXml(unknown)
1833
                item.transfer.onRemoved.connect(self.itemRemoved)
1834
                if item is not None:
1835
                    item.transfer.onRemoved.connect(self.itemRemoved)
1836
                    self.addUnknownItemToScene(item)
1837

    
1838
                self.progress.setValue(self.progress.value() + 1)
1839
                
1840
            QApplication.processEvents()
1841

    
1842
            for line_no in root.find('LINENOS').iter('LINE_NO'):
1843
                item = QEngineeringLineNoTextItem.fromXml(line_no)
1844
                if item is not None:
1845
                    item.transfer.onRemoved.connect(self.itemRemoved)
1846
                    self.addTextItemToScene(item)
1847

    
1848
                connLine = line_no.find('CONNLINE')
1849
                if connLine is not None:
1850
                    lineUID = connLine.text
1851
                    connLine = self.graphicsView.findItemByUid(lineUID)
1852
                    if connLine is not None:
1853
                        item.conns.append(connLine)
1854

    
1855
                run = line_no.find('RUN')
1856
                if run is not None:
1857
                    lineRunItem = QEngineeringRunItem()
1858
                    for child in run:
1859
                        uidElement = child.find('UID')
1860
                        if uidElement is not None:
1861
                            uid = uidElement.text
1862
                            runItem = self.graphicsView.findItemByUid(uid)
1863
                            if runItem is not None:
1864
                                lineRunItem.items.append(runItem)
1865

    
1866
                    item.runs.append(lineRunItem)
1867
                    treeItem = self.resultTreeWidget.addTreeItem(self.resultTreeWidget.root, item)
1868
                    for connectedItem in lineRunItem.items:
1869
                        if issubclass(type(connectedItem), SymbolSvgItem): self.resultTreeWidget.addTreeItem(treeItem, connectedItem)
1870
                    docData.lineNos.append(item)
1871

    
1872
                self.progress.setValue(self.progress.value() + 1)
1873
            QApplication.processEvents()
1874

    
1875
            for trimLineNo in root.iter('TRIM_LINE_NO'):
1876
                item = QEngineeringTrimLineNoTextItem()
1877
                item.uid = trimLineNo.find('UID')
1878

    
1879
                run = trimLineNo.find('RUN')
1880
                if run is not None:
1881
                    lineRunItem = QEngineeringRunItem()
1882
                    for child in run:
1883
                        uidElement = child.find('UID')
1884
                        if uidElement is not None:
1885
                            uid = uidElement.text
1886
                            runItem = self.graphicsView.findItemByUid(uid)
1887
                            if runItem is not None:
1888
                                lineRunItem.items.append(runItem)
1889

    
1890
                    item.runs.append(lineRunItem)
1891
                    treeItem = self.resultTreeWidget.addTreeItem(self.resultTreeWidget.root, item)
1892
                    for connectedItem in lineRunItem.items:
1893
                        if issubclass(type(connectedItem), SymbolSvgItem): self.resultTreeWidget.addTreeItem(treeItem, connectedItem)
1894
                    docData.lineNos.append(item)
1895
            # up to here
1896

    
1897
            # set symbol's connectItem
1898
            from EngineeringConnectorItem import QEngineeringConnectorItem
1899
            connectors = [item for item in self.graphicsView.scene.items() if type(item) == QEngineeringConnectorItem and item.connectedItem is not None]
1900
            for connector in connectors:
1901
                # 처음에는 UID가 connectedItem에 String으로 들어가있기 때문에
1902
                connector.connectedItem = self.graphicsView.findItemByUid(connector.connectedItem)
1903

    
1904
            symbols = [item for item in self.graphicsView.scene.items() if issubclass(type(item), SymbolSvgItem) and len(item.attrs) > 0]
1905
            for symbol in symbols:
1906
                # 처음에는 attrs의 uid가 connectedItem에 String으로 들어가있기 때문에
1907
                for index in range(len(symbol.attrs)):
1908
                    if type(symbol.attrs[index]) is not UserInputAttribute and type(symbol.attrs[index]) is not tuple:
1909
                        symbol.attrs[index] = self.graphicsView.findItemByUid(symbol.attrs[index])
1910
                        
1911
            # Update Scene
1912
            self.graphicsView.scene.update(self.graphicsView.sceneRect())
1913

    
1914
        except Exception as ex:
1915
            message = 'error occured({}) in {}:{}'.format(ex, sys.exc_info()[-1].tb_frame.f_code.co_filename, sys.exc_info()[-1].tb_lineno)
1916
            self.addMessage.emit(MessageType.Error, message)
1917

    
1918
    '''
1919
        @brief      Remove added item on same place and Add GraphicsItem
1920
        @author     Jeongwoo
1921
        @date       2018.05.25
1922
        @history    2018.05.29  Jeongwoo    Moved from QRecognitionDialog
1923
                    2018.06.18  Jeongwoo    Set Z-index
1924
    '''
1925
    def addSvgItemToScene(self, svgItem):
1926
        svgItem.addSvgItemToScene(self.graphicsView.scene)
1927
        
1928
    '''
1929
        @brief      Remove added item on same place and Add GraphicsItem
1930
        @author     Jeongwoo
1931
        @date       2018.05.25
1932
        @history    2018.05.29  Jeongwoo    Moved from QRecognitionDialog
1933
                    2018.06.05  Jeongwoo    Remove Size condition
1934
                    2018.06.18  Jeongwoo    Set Z-index
1935
    '''
1936
    def addTextItemToScene(self, textItem):
1937
        textItem.addTextItemToScene(self.graphicsView.scene)
1938
        
1939
    '''
1940
        @brief      Remove added item on same place and Add GraphicsItem
1941
        @author     Jeongwoo
1942
        @date       2018.05.29
1943
        @history    2018.06.18  Jeongwoo    Set Z-index
1944
    '''
1945
    def addLineItemToScene(self, lineItem):
1946
        lineItem.addLineItemToScene(self.graphicsView.scene)
1947

    
1948
    '''
1949
        @brief      Remove added item on same place and Add Unknown Item
1950
        @author     Jeongwoo
1951
        @date       2018.06.14
1952
        @history    2018.06.18  Jeongwoo    Set Z-index
1953
    '''
1954
    def addUnknownItemToScene(self, unknownItem):
1955
        try:
1956
            unknownItem.addUnknownItemToScene(self.graphicsView.scene)
1957
        except Exception as ex:
1958
            message = 'error occured({}) in {}:{}'.format(ex, sys.exc_info()[-1].tb_frame.f_code.co_filename, sys.exc_info()[-1].tb_lineno)
1959
            self.addMessage.emit(MessageType.Error, message)
1960

    
1961
    '''
1962
        @brief      generate output xml file
1963
        @author     humkyung
1964
        @date       2018.04.23
1965
        @history    2018.05.02  Jeongwoo    Show MessageBox when imageviewer doesn't have image
1966
    '''
1967
    def generateOutput(self):
1968
        import XmlGenerator as xg
1969

    
1970
        if not self.graphicsView.hasImage():
1971
            self.showImageSelectionMessageBox()
1972
            return
1973

    
1974
        try:
1975
            appDocData = AppDocData.instance()
1976

    
1977
            ## collect items
1978
            appDocData.lines.clear()
1979
            appDocData.lines = [item for item in self.graphicsView.scene.items() if type(item) is QEngineeringLineItem and item.owner is None]
1980

    
1981
            appDocData.symbols.clear()
1982
            appDocData.symbols = [item for item in self.graphicsView.scene.items() if issubclass(type(item), SymbolSvgItem) and item.owner is None]
1983

    
1984
            appDocData.equipments.clear()
1985
            for item in self.graphicsView.scene.items():
1986
                if type(item) is QEngineeringEquipmentItem:
1987
                    appDocData.equipments.append(item)
1988

    
1989
            appDocData.texts.clear()
1990
            appDocData.texts = [item for item in self.graphicsView.scene.items() if issubclass(type(item), QEngineeringTextItem) and type(item) is not QEngineeringLineNoTextItem]
1991
            ## up to here
1992

    
1993
            appDocData.imgOutput = np.ones((appDocData.imgHeight, appDocData.imgWidth), np.uint8)*255
1994
            xg.writeOutputXml(appDocData.imgName, appDocData.imgWidth, appDocData.imgHeight) # TODO: check
1995
            project = appDocData.getCurrentProject()
1996
            cv2.imwrite(os.path.join(project.getTempPath() , 'OUTPUT.png') , appDocData.imgOutput)
1997
        except Exception as ex:
1998
            message = 'error occured({}) in {}:{}'.format(ex, sys.exc_info()[-1].tb_frame.f_code.co_filename, sys.exc_info()[-1].tb_lineno)
1999
            self.addMessage.emit(MessageType.Error, message)
2000

    
2001
    '''
2002
        @brief      resetting attribute at secne
2003
        @author     kyoyho
2004
        @date       2018.08.21
2005
    '''
2006
    def checkAttribute(self):
2007
        try:
2008

    
2009
            docData = AppDocData.instance()
2010
            if not self.graphicsView.hasImage():
2011
                return
2012

    
2013
            # symbol 경우
2014
            items = [item for item in self.graphicsView.scene.items() if issubclass(type(item), SymbolSvgItem)]
2015
            for item in items:
2016
                attrs = item.attrs
2017
                
2018
                removeAttrList = []
2019
                for attr in attrs:
2020
                    if type(attr) is tuple:
2021
                        continue
2022

    
2023
                    if attr is None:
2024
                        removeAttrList.append(attr)
2025
                        continue
2026

    
2027
                    attrInfo = docData.getSymbolAttributeByUID(attr.attribute)
2028
                    if attrInfo is None:
2029
                        removeAttrList.append(attr)
2030
                    # 해당 attribute가 맞는지 확인
2031
                    else:
2032
                        attrType = attrInfo[2]
2033
                        _type = type(attr)
2034
                        if attrType == 'Symbol Item':
2035
                            if not issubclass(_type, SymbolSvgItem):
2036
                                removeAttrList.append(attr)
2037
                        elif attrType == 'Text Item':
2038
                            if _type is not QEngineeringTextItem:
2039
                                removeAttrList.append(attr)
2040
                        elif attrType == 'Int':
2041
                            if _type is not UserInputAttribute and self.isNumber(attr.text):
2042
                                removeAttrList.append(attr)
2043
                        elif attrType == 'String':
2044
                            if _type is not UserInputAttribute:
2045
                                removeAttrList.append(attr)
2046

    
2047
                for attr in removeAttrList:
2048
                    attrs.remove(attr)
2049

    
2050
            # Line No Text Item의 경우
2051
            items = [item for item in self.graphicsView.scene.items() if issubclass(type(item), QEngineeringLineNoTextItem)]
2052
            for item in items:
2053
                attrs = item.attrs
2054
                
2055
                removeAttrList = []
2056
                for attr in attrs:
2057
                    if type(attr) is UserInputAttribute:
2058
                        attrInfo = docData.getLinePropertiesByUID(attr.attribute)
2059
                        if attrInfo is None:
2060
                            removeAttrList.append(attr)
2061

    
2062
                for attr in removeAttrList:
2063
                    attrs.remove(attr)
2064

    
2065
        except Exception as ex:
2066
                message = 'error occured({}) in {}:{}'.format(ex, sys.exc_info()[-1].tb_frame.f_code.co_filename, sys.exc_info()[-1].tb_lineno)
2067
                self.addMessage.emit(MessageType.Error, message)
2068
    '''
2069
        @brief      Check Number
2070
        @author     kyouho
2071
        @date       2018.08.20
2072
    '''
2073
    def isNumber(self, num):
2074
        p = re.compile('(^[0-9]+$)')
2075
        result = p.match(num)
2076

    
2077
        if result:
2078
            return True
2079
        else:
2080
            return False
2081

    
2082
    '''
2083
        @brief      find overlap Connector
2084
        @author     kyouho
2085
        @date       2018.08.28
2086
    '''
2087
    def findOverlapConnector(self, connectorItem):
2088
        from shapely.geometry import Point
2089
        from EngineeringConnectorItem import QEngineeringConnectorItem
2090
        itemList = []
2091
        
2092
        x = connectorItem.center()[0]
2093
        y = connectorItem.center()[1]
2094

    
2095
        connectors = [item for item in self.graphicsView.scene.items() if type(item) is QEngineeringConnectorItem and item != connectorItem]
2096
        for connector in connectors:
2097
            if Point(x, y).distance(Point(connector.center()[0], connector.center()[1])) < 5:
2098
                itemList.append(connector.parent)
2099

    
2100
        return itemList
2101

    
2102
if __name__ == '__main__':
2103
    from License import QLicenseDialog
2104
    from ProjectDialog import Ui_Dialog
2105
    from App import App 
2106

    
2107
    app = App(sys.argv)
2108
    try:
2109
        if True == QLicenseDialog.check_license_key():
2110
            dlg = Ui_Dialog()
2111
            selectedProject = dlg.showDialog()
2112
            if selectedProject is not None:
2113
                AppDocData.instance().setCurrentProject(selectedProject)
2114
                app._mainWnd = MainWindow.instance()
2115
                app._mainWnd.show()
2116
                sys.exit(app.exec_())
2117
    except Exception as ex:
2118
        print('error occured({}) in {}:{}'.format(ex, sys.exc_info()[-1].tb_frame.f_code.co_filename, sys.exc_info()[-1].tb_lineno))
2119
    finally:
2120
        pass
클립보드 이미지 추가 (최대 크기: 500 MB)