프로젝트

일반

사용자정보

통계
| 브랜치(Branch): | 개정판:

hytos / DTI_PID / DTI_PID / MainWindow.py @ 58bf9dec

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

1
# coding: utf-8
2
""" This is MainWindow module """
3

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

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

    
20
import cv2
21
import numpy as np
22

    
23
from PyQt5.QtCore import *
24
from PyQt5.QtGui import *
25
from PyQt5.QtWidgets import *
26
from PyQt5.QtSvg import *
27

    
28
from PIL import Image
29

    
30
import MainWindow_UI
31
import QtImageViewer
32
from SingletonInstance import SingletonInstane
33

    
34
sys.path.insert(0, os.path.dirname(os.path.realpath(__file__)) + '\\Shapes')
35
from EngineeringPolylineItem import QEngineeringPolylineItem
36
from EngineeringLineItem import QEngineeringLineItem
37
from SymbolSvgItem import SymbolSvgItem
38
from GraphicsBoundingBoxItem import QGraphicsBoundingBoxItem
39
from EngineeringTextItem import QEngineeringTextItem
40
from EngineeringLineNoTextItem import QEngineeringLineNoTextItem
41
from EngineeringNoteItem import QEngineeringNoteItem
42
from QEngineeringSizeTextItem import QEngineeringSizeTextItem
43
from EngineeringUnknownItem import QEngineeringUnknownItem
44
from EngineeringEquipmentItem import QEngineeringEquipmentItem
45
from EngineeringInstrumentItem import QEngineeringInstrumentItem
46
from EngineeringSpecBreakItem import QEngineeringSpecBreakItem
47
from EngineeringErrorItem import QEngineeringErrorItem
48
from EngineeringVendorItem import QEngineeringVendorItem
49
from EngineeringEndBreakItem import QEngineeringEndBreakItem
50
from EngineeringReducerItem import QEngineeringReducerItem
51
from EngineeringFlowMarkItem import QEngineeringFlowMarkItem
52
from AppDocData import *
53
import SymbolTreeWidget, SymbolPropertyTableWidget
54
import SymbolEditorDialog
55
import ItemTreeWidget
56
import ItemPropertyTableWidget
57
from UserInputAttribute import UserInputAttribute
58
from TextItemFactory import TextItemFactory
59
from TrainingImageListDialog import QTrainingImageListDialog
60
from TextDataListDialog import QTextDataListDialog
61
from ImportTextFromCADDialog import QImportTextFromCADDialog
62
from DisplayColors import DisplayColors
63
from DisplayColors import DisplayOptions
64
import uuid
65

    
66
class MainWindow(QMainWindow, MainWindow_UI.Ui_MainWindow, SingletonInstane):
67
    """ This is MainWindow class """
68
    addMessage = pyqtSignal(Enum, str)
69

    
70
    '''
71
        @brief      initialize
72
        @author 
73
        @date   
74
        @history    humkyung 2018.04.12 add splitter widget
75
                    Jeongwoo 2018.04.27 Add Signal/Slot Connection 'noteNoSingleClicked'
76
                    Jeongwoo 2018.05.09 Initialize Action group
77
                    Jeongwoo 2018.05.10 Add Signal/Slot Connection 'lineNoSingleClicked'
78
                                        Add QActionGroup for managing checkable action
79
                    Jeongwoo 2018.06.27 Add Action [Zoom, Fit Window] and Add new actions into ActionGroup
80
                    humkyung 2018.08.23 add labelStatus to statusbar
81
                    Euisung 2018.09.27 add OCR Training , Signal/Slot Connection 'oCRTrainingClicked'
82
                    Euisung 2018.10.05 add OCR Editor , Signal/Slot Connection 'oCRTrainingEdidorClicked'
83
                    Euisung 2018.10.22 delete Signal/Slot Connection 'oCRTrainingEdidorClicked'
84
    '''
85
    def __init__(self):
86
        from LineTypeConditions import LineTypeConditions
87

    
88
        super(self.__class__, self).__init__()
89
        self.setupUi(self)
90
        self._label_mouse = QLabel(self.statusbar)
91
        self._label_mouse.setText(self.tr('mouse pos : ({},{})'.format(0,0)))
92
        self.labelStatus = QLabel(self.statusbar)
93
        self.labelStatus.setText(self.tr('Unrecognition : '))
94
        self.labelSymbolStatus = QLabel(self.statusbar)
95
        self.labelSymbolStatus.setText(self.tr('Symbol : '))
96
        self.labelLineStatus = QLabel(self.statusbar)
97
        self.labelLineStatus.setText(self.tr('Line : '))
98
        self.labelTextStatus = QLabel(self.statusbar)
99
        self.labelTextStatus.setText(self.tr('Text : '))
100
        self.statusbar.addWidget(self._label_mouse)
101
        self.statusbar.addPermanentWidget(self.labelSymbolStatus)
102
        self.statusbar.addPermanentWidget(self.labelLineStatus)
103
        self.statusbar.addPermanentWidget(self.labelTextStatus)
104
        self.statusbar.addPermanentWidget(self.labelStatus) 
105

    
106
        docData = AppDocData.instance()
107
        docData.clear()
108
        project = docData.getCurrentProject()
109
        _translate = QCoreApplication.translate
110
        version = QCoreApplication.applicationVersion()
111
        self.setWindowTitle(_translate("Digital P&ID({}) - {}".format(version, project.name), "Digital P&ID({}) - {}".format(version, project.name)))
112

    
113
        self.lineComboBox = QComboBox(self.toolBar)
114
        for condition in LineTypeConditions.items():
115
            self.lineComboBox.addItem(condition.name)
116
        self.lineComboBox.currentIndexChanged.connect(self.onLineTypeChanged)
117

    
118
        self.toolBar.insertWidget(self.actionOCR, self.lineComboBox)
119
        self.toolBar.insertSeparator(self.actionOCR)
120
        
121
        self.graphicsView = QtImageViewer.QtImageViewer(self)
122
        self.graphicsView.setParent(self.centralwidget)
123
        self.graphicsView.useDefaultCommand() ##### USE DEFAULT COMMAND
124
        self.graphicsView.setMouseTracking(True)
125
        self.graphicsView.viewport().installEventFilter(self)
126

    
127
        self._display_widget = QWidget()
128
        layout = QVBoxLayout()
129
        self._by_line_no = QRadioButton()
130
        self._by_line_no.setChecked(True)
131
        self._by_line_no.setText('By Group')
132
        self._by_line_no.toggled.connect(self.display_colors)
133
        layout.addWidget(self._by_line_no)
134
        self._by_line_type = QRadioButton()
135
        self._by_line_type.setText('By Type')
136
        layout.addWidget(self._by_line_type)
137
        self._display_widget.setLayout(layout)
138
        self.EditToolbar.insertWidget(None, self._display_widget)
139
        self._by_line_no.setChecked(True) if DisplayColors.instance().option == DisplayOptions.DisplayByLineNo else self._by_line_type.setChecked(True)
140

    
141
        self.verticalLayout.addWidget(self.graphicsView)
142

    
143
        # Add Custom TreeWidget
144
        self.dirTreeWidget = SymbolTreeWidget.QSymbolTreeWidget()
145
        self.dirTreeWidget.header().hide()
146
        self.symbolTabVerticalLayout.addWidget(self.dirTreeWidget)
147

    
148
        # Add Custom Property TableWidget
149
        self.propertyTableWidget = SymbolPropertyTableWidget.QSymbolPropertyTableWidget()
150
        self.symbolTabVerticalLayout.addWidget(self.propertyTableWidget)
151
        self.dirTreeWidget.singleClicked.connect(self.propertyTableWidget.getClickedSymbol)
152
        # add splitter widget
153
        splitter = QSplitter(Qt.Vertical)
154
        splitter.addWidget(self.dirTreeWidget)
155
        splitter.addWidget(self.propertyTableWidget)
156
        self.symbolTabVerticalLayout.addWidget(splitter)
157
        # up to here
158

    
159
        # Add Custom Result Tree Widget (Symbol Explorer)
160
        self.itemTreeWidget = ItemTreeWidget.QItemTreeWidget(self.graphicsView)
161
        self.itemTreeWidget.header().hide()
162
        self.symbolExplorerVerticalLayout.addWidget(self.itemTreeWidget)
163

    
164
        # Add Empty Widget
165
        self.resultPropertyTableWidget = ItemPropertyTableWidget.QItemPropertyTableWidget(self)
166
        self.symbolExplorerVerticalLayout.addWidget(self.resultPropertyTableWidget)
167
        self.itemTreeWidget.singleClicked.connect(self.resultPropertyTableWidget.onSymbolClicked)
168
        self.itemTreeWidget.noteNoSingleClicked.connect(self.resultPropertyTableWidget.onNoteClicked)
169
        self.itemTreeWidget.lineNoSingleClicked.connect(self.resultPropertyTableWidget.onLineNoClicked)
170
        self.itemTreeWidget.drawingClicked.connect(self.resultPropertyTableWidget.onDrawingClicked)
171
        # add splitter widget
172
        splitter = QSplitter(Qt.Vertical)
173
        splitter.addWidget(self.itemTreeWidget)
174
        splitter.addWidget(self.resultPropertyTableWidget)
175
        self.symbolExplorerVerticalLayout.addWidget(splitter)
176
        # up to here
177

    
178
        # Initialize Action group
179
        self.actionGroup = QActionGroup(self)
180
        self.actionGroup.addAction(self.actionRecognition)
181
        self.actionGroup.addAction(self.actionLineRecognition)
182
        self.actionGroup.addAction(self.actionLine)
183
        self.actionGroup.addAction(self.actionGenerateOutput)
184
        self.actionGroup.addAction(self.actionOCR)
185
        self.actionGroup.addAction(self.actionZoom)
186
        self.actionGroup.addAction(self.actionFitWindow)
187
        self.actionGroup.addAction(self.actionSave)
188
        self.actionGroup.addAction(self.actionValidate)
189
        self.actionGroup.addAction(self.actionVendor)
190
        self.actionGroup.triggered.connect(self.actionGroupTriggered)
191

    
192
        # connect signals and slots
193
        self.actionClose.triggered.connect(self.close)
194
        self.actionOpen.triggered.connect(self.onOpenImageDrawing)
195
        self.actionLine.triggered.connect(self.onPlaceLine)
196
        self.actionRecognition.triggered.connect(self.recognize)
197
        self.pushButtonBatchRecognition.clicked.connect(self.recognizeBatch)
198
        self.pushButtonRefreshDrawings.clicked.connect(self.load_drawing_list)
199
        self.actionLineRecognition.triggered.connect(self.connect_attributes)
200
        self.actionArea.triggered.connect(self.areaConfiguration)
201
        self.actionConfiguration.triggered.connect(self.configuration)
202
        self.actionOCR.triggered.connect(self.onAreaOcr)
203
        self.actionGenerateOutput.triggered.connect(self.generateOutput)
204
        self.pushButtonCreateSymbol.clicked.connect(self.onCreateSymbolClicked)
205
        self.pushButtonClearLog.clicked.connect(self.onClearLog)
206
        self.actionHMB_DATA.triggered.connect(self.onHMBData)
207
        self.actionItem_Data_List.triggered.connect(self.showItemDataList)
208
        self.actionText_Data_List.triggered.connect(self.showTextDataList)
209
        self.actionSpecialItemTypes.triggered.connect(self.on_show_special_item_types)  ### show special item types dialog
210
        self.actionDataTransfer.triggered.connect(self.on_show_data_transfer)  ### show data transfer dialog
211
        self.actionDataExport.triggered.connect(self.on_show_data_export)
212
        self.actionOPCRelation.triggered.connect(self.on_show_opc_relation)     ### show OPC Relation dialog
213
        self.actionCodeTable.triggered.connect(self.onShowCodeTable)
214
        self.actionImage_Drawing.triggered.connect(self.onViewImageDrawing)
215
        self.actionDrawing_Only.triggered.connect(self.onViewDrawingOnly)
216
        self.actionValidate.triggered.connect(self.onValidation)
217
        self.actionViewText.triggered.connect(self.onViewText)
218
        self.actionViewSymbol.triggered.connect(self.onViewSymbol)
219
        self.actionViewLine.triggered.connect(self.onViewLine)
220
        self.actionViewUnknown.triggered.connect(self.onViewUnknown)
221
        self.actionViewInconsistency.triggered.connect(self.onViewInconsistency)
222
        self.actionViewVendor_Area.triggered.connect(self.onViewVendorArea)
223
        self.actionRotate.triggered.connect(self.onRotate)
224
        self.actionZoom.triggered.connect(self.onAreaZoom)
225
        self.actionVendor.triggered.connect(self.onVendor)
226
        self.actionFitWindow.triggered.connect(self.fitWindow)
227
        self.actionpdf_to_image.triggered.connect(self.onConvertPDFToImage)
228
        self.actionImport_Text_From_CAD.triggered.connect(self.onImportTextFromCAD)
229
        self.actionHelp.triggered.connect(self.on_help)
230
        self.graphicsView.scene.contents_changed.connect(self.onSceneChanged)
231
        self.graphicsView.scene.selectionChanged.connect(self.onSelectionChanged)
232
        self.actionInitialize.triggered.connect(self.onInitializeScene)
233
        self.actionSave.triggered.connect(self.actionSaveCliked)
234
        self.addMessage.connect(self.onAddMessage)
235
        self.actionFindReplaceText.triggered.connect(self.findReplaceTextClicked)
236
        self.pushButtonDetectSymbol.clicked.connect(self.onShowDetectSymbol)
237

    
238
        configs = docData.getAppConfigs('app', 'mode')
239
        if configs and 1 == len(configs) and 'advanced' == configs[0].value:
240
            self.actionOCR_Training.triggered.connect(self.oCRTrainingClicked)
241
            self.pushButtonBatchRecognition
242
        else:
243
            self.actionOCR_Training.setVisible(False)
244
            self.pushButtonBatchRecognition.setVisible(False)
245

    
246
        self.delimiter = '"'
247
    
248
        self.resizeDocks({self.dockWidget}, {self.dockWidgetObjectExplorer.sizeHint().width()}, Qt.Horizontal)
249

    
250
        self.treeWidgetDrawingList.setHeaderHidden(False)
251
        self.treeWidgetDrawingList.header().setStretchLastSection(False)
252
        self.treeWidgetDrawingList.setHeaderLabels([self.tr('Name'), self.tr('DateTime')])
253
        self.treeWidgetDrawingList.header().setSectionResizeMode(0, QHeaderView.ResizeToContents)
254
        self.treeWidgetDrawingList.header().setSectionResizeMode(1, QHeaderView.ResizeToContents)
255
        self.treeWidgetDrawingList.itemDoubleClicked.connect(self.open_selected_drawing)
256
        self.load_drawing_list()
257

    
258
        # load stylesheet file list
259
        stylesheet_name = QtWidgets.qApp.stylesheet_name
260
        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']
261
        for file in files:
262
            action = self.menuTheme.addAction(file)
263
            action.setCheckable(True)
264
            action.setChecked(True) if stylesheet_name == file else action.setChecked(False)
265
            action.triggered.connect(partial(self.load_stylesheet, file))
266
        # up to here
267

    
268
        # load language files
269
        language_name = QtWidgets.qApp.language_name
270
        files = ['en_us'] # englisgh is default language
271
        files.extend([os.path.splitext(file)[0] for file in os.listdir(os.path.join(os.path.dirname(os.path.realpath(__file__)), 'translate')) if os.path.splitext(file)[1] == '.qm'])
272
        for file in files:
273
            action = self.menuLanguage.addAction(file)
274
            action.setCheckable(True)
275
            action.setChecked(True) if language_name.lower() == file.lower() else action.setChecked(False)
276
            action.triggered.connect(partial(self.load_language, file))
277
        # up to here
278

    
279
        # inconsistency table
280
        self.tableWidgetInconsistency.setColumnCount(3)
281
        self.tableWidgetInconsistency.setHorizontalHeaderLabels(['Owner', 'Type', 'Message'])
282
        self.tableWidgetInconsistency.setEditTriggers(QAbstractItemView.NoEditTriggers)
283
        self.tableWidgetInconsistency.itemClicked.connect(self.inconsistencyItemClickEvent)
284
        self.tableWidgetInconsistency.keyPressEvent = self.inconsistencyTableKeyPressEvent
285
        self.tableWidgetInconsistency.setSortingEnabled(True)
286

    
287
    def eventFilter(self, source, event):
288
        """
289
        display mouse position of graphics view
290
        """
291
        if (event.type() == QEvent.MouseMove):
292
            pos = self.graphicsView.mapToScene(event.pos())
293
            self._label_mouse.setText('mouse pos : ({},{})'.format(round(pos.x()), round(pos.y())))
294

    
295
        return QWidget.eventFilter(self, source, event)
296

    
297
    def closeEvent(self, event):
298
        AppDocData.instance().clear()
299

    
300
    def inconsistencyTableKeyPressEvent(self, event):
301
        try:
302
            row = self.tableWidgetInconsistency.selectedIndexes()[0].row()
303
            col = self.tableWidgetInconsistency.selectedIndexes()[0].column()
304
            from HighlightCommand import HighlightCommand
305
            if event.key() == Qt.Key_Up:
306
                if row is not 0:
307
                    errorItem = self.tableWidgetInconsistency.item(row - 1, 1).tag
308
                    HighlightCommand(self.graphicsView).execute(errorItem)
309
            elif event.key() == Qt.Key_Down:
310
                if row is not self.tableWidgetInconsistency.rowCount() - 1:
311
                    errorItem = self.tableWidgetInconsistency.item(row + 1, 1).tag
312
                    HighlightCommand(self.graphicsView).execute(errorItem)
313
            elif event.key() == Qt.Key_Delete:
314
                item = self.tableWidgetInconsistency.item(row, 0).tag
315
                if item and item.scene(): item.scene().removeItem(item)
316
                self.tableWidgetInconsistency.removeRow(row)
317
        except Exception as ex:
318
            message = 'error occured({}) in {}:{}'.format(ex, sys.exc_info()[-1].tb_frame.f_code.co_filename, sys.exc_info()[-1].tb_lineno)
319
            self.addMessage.emit(MessageType.Error, message)
320
        #finally:
321
        #    return QTableView.keyPressEvent(self.tableWidgetInconsistency, event)
322

    
323
    def onValidation(self):
324
        """
325
        @brief  validation check
326
        @author euisung
327
        @date   2019.04.01
328
        """
329
        from ValidateCommand import ValidateCommand
330

    
331
        if not self.graphicsView.hasImage():
332
            self.showImageSelectionMessageBox()
333
            return
334

    
335
        try:
336
            # remove error items
337
            for item in self.graphicsView.scene.items():
338
                if type(item) is QEngineeringErrorItem:
339
                    item.transfer.onRemoved.emit(item)
340
            # up to here
341

    
342
            cmd = ValidateCommand(self.graphicsView)
343
            errors = cmd.execute(self.graphicsView.scene.items())
344
            for error in errors:
345
                error.transfer.onRemoved.connect(self.itemRemoved)
346
                self.graphicsView.scene.addItem(error)
347

    
348
            self.tableWidgetInconsistency.clearContents()
349
            self.tableWidgetInconsistency.setRowCount(len(errors))
350
            for index in range(len(errors)):
351
                self.makeInconsistencyTableRow(index, errors[index])
352
        except Exception as ex:
353
            message = 'error occured({}) in {}:{}'.format(ex, sys.exc_info()[-1].tb_frame.f_code.co_filename, sys.exc_info()[-1].tb_lineno)
354
            self.addMessage.emit(MessageType.Error, message)
355

    
356
    def makeInconsistencyTableRow(self, row, errorItem):
357
        '''
358
            @brief  make row data for inconsistency widget
359
            @author euisung
360
            @date   2019.04.16
361
        '''
362

    
363
        item = QTableWidgetItem(str(errorItem.parent))
364
        item.tag = errorItem
365
        self.tableWidgetInconsistency.setItem(row, 0, item)
366

    
367
        item = QTableWidgetItem(str(type(errorItem.parent)))
368
        item.tag = errorItem
369
        self.tableWidgetInconsistency.setItem(row, 1, item)
370

    
371
        item = QTableWidgetItem(errorItem.msg)
372
        item.tag = errorItem
373
        self.tableWidgetInconsistency.setItem(row, 2, item)
374

    
375
    def inconsistencyItemClickEvent(self, item):
376
        """
377
        @brief  inconsistency table item clicked
378
        @author euisung
379
        @date   2019.04.02
380
        """
381
        from HighlightCommand import HighlightCommand
382

    
383
        HighlightCommand(self.graphicsView).execute(item.tag)
384

    
385
    def load_stylesheet(self, file):
386
        """
387
        @brief  load stylesheets
388
        @author humkyung
389
        @date   2018.10.29
390
        """
391

    
392
        QtWidgets.qApp.loadStyleSheet(os.path.join(os.path.dirname(os.path.realpath(__file__)), file))
393

    
394
        app_doc_data = AppDocData.instance()
395
        configs = [Config('app', 'stylesheet', file)]
396
        app_doc_data.saveAppConfigs(configs)
397
        
398
        for action in self.menuTheme.actions():
399
            if action.text() == file: continue
400
            action.setChecked(False)
401

    
402
    def load_language(self, file):
403
        """
404
        load language file and then apply selected language 
405
        """
406
        try:
407
            qm_file = os.path.join(os.path.dirname(os.path.realpath(__file__)), 'translate', '{0}.qm'.format(file))
408
            QtWidgets.qApp.load_language(qm_file)
409

    
410
            app_doc_data = AppDocData.instance()
411
            configs = [Config('app', 'language', file)]
412
            app_doc_data.saveAppConfigs(configs)
413
            
414
            for action in self.menuLanguage.actions():
415
                if action.text().lower() == file.lower(): continue
416
                action.setChecked(False)
417
        finally:
418
            self.retranslateUi(self)
419
            self.propertyTableWidget.retranslateUi()
420

    
421
    '''
422
        @brief      Clear TreeWidget and Set Current PID
423
        @author     Jeongwoo
424
        @date       18.04.11
425
        @history    2018.04.26  Jeongwoo    Add Child [SYMBOLS, NOTES] into root item
426
                    2018.05.09  Jeongwoo    Change method to add default tree items
427
                    humkyung 2018.06.10 add tree item for Line No and Unknown Item
428
    '''
429
    def load_drawing_list(self):
430
        """
431
        @brief      load p&id drawing list
432
        @author     humkyung
433
        @date       18.11.02
434
        """
435
        from Drawing import Drawing
436

    
437
        try:
438
            appDocData = AppDocData.instance()
439
            drawings = appDocData.getDrawings()
440

    
441
            self.treeWidgetDrawingList.clear()
442
            self.treeWidgetDrawingList.root = QTreeWidgetItem(self.treeWidgetDrawingList, [self.tr('P&ID Drawings'), ''])
443
            self.treeWidgetDrawingList.root.setFlags(self.treeWidgetDrawingList.root.flags() | Qt.ItemIsTristate | Qt.ItemIsUserCheckable)
444
            self.treeWidgetDrawingList.root.setCheckState(0, Qt.Unchecked)
445
            files = appDocData.getDrawingFileList()
446
            for file in files:
447
                drawing = [drawing for drawing in drawings if drawing.name == file]
448
                if not drawing or not drawing[0].UID:
449
                    drawings.append(Drawing(None, file, None))
450

    
451
                item = QTreeWidgetItem(self.treeWidgetDrawingList.root, [file, drawing[0].datetime if drawing else None])
452
                item.setIcon(0, QIcon(':newPrefix/image.png'))
453
                item.setFlags(item.flags() | Qt.ItemIsUserCheckable)
454
                item.setCheckState(0, Qt.Unchecked)
455
            
456
            self.treeWidgetDrawingList.root.setText(0, self.tr('P&ID Drawings')+'({})'.format(self.treeWidgetDrawingList.root.childCount()))
457
            self.treeWidgetDrawingList.expandItem(self.treeWidgetDrawingList.root)
458
            self.treeWidgetDrawingList.root.sortChildren(0, Qt.AscendingOrder)
459
            self.treeWidgetDrawingList.resizeColumnToContents(0)
460

    
461
            appDocData.saveDrawings(drawings)
462
        except Exception as ex:
463
            message = 'error occured({}) in {}:{}'.format(ex, sys.exc_info()[-1].tb_frame.f_code.co_filename, sys.exc_info()[-1].tb_lineno)
464
            self.addMessage.emit(MessageType.Error, message)
465

    
466
    def open_selected_drawing(self, item, column):
467
        """
468
        @brief      open selected p&id drawing
469
        @author     humkyung
470
        @date       18.11.02
471
        """
472
        appDocData = AppDocData.instance()
473
        drawing = os.path.join(appDocData.getCurrentProject().getDrawingFilePath(), item.text(0))
474
        self.onOpenImageDrawing(drawing)
475

    
476
    def onShowDetectSymbol(self):
477
        from DetectSymbolDialog import QDetectSymbolDialog
478

    
479
        dlgDetectSymbol = QDetectSymbolDialog(self)
480
        dlgDetectSymbol.show()
481
        dlgDetectSymbol.exec_()
482
        
483
    '''
484
        @brief      OCR Editor
485
        @author     euisung
486
        @date       2018.10.05
487
        @history    2018.10.16 euisung      no more used, Integrated with oCRTrainingClicked
488
    '''
489
    def oCRTrainingEdidorClicked(self):
490
        from TrainingEditorDialog import QTrainingEditorDialog
491

    
492
        try:
493
            dialog = QTrainingEditorDialog(self)
494
            dialog.exec_()
495
        except Exception as ex:
496
            message = 'error occured({}) in {}:{}'.format(ex, sys.exc_info()[-1].tb_frame.f_code.co_filename, sys.exc_info()[-1].tb_lineno)
497
            self.addMessage.emit(MessageType.Error, message)
498
            
499
        return
500

    
501
    '''
502
        @brief      OCR Training
503
        @author     euisung
504
        @date       2018.09.27
505
        @history    euisung 2018.10.16 TrainingListDialog -> TrainingImageListDialog
506
    '''
507
    def oCRTrainingClicked(self):
508
        try:
509
            dialog = QTrainingImageListDialog(self)
510
            dialog.exec_()
511
        except Exception as ex:
512
            message = 'error occured({}) in {}:{}'.format(ex, sys.exc_info()[-1].tb_frame.f_code.co_filename, sys.exc_info()[-1].tb_lineno)
513
            self.addMessage.emit(MessageType.Error, message)
514

    
515
    '''
516
        @brief      show unknownitem's count
517
        @author     kyouho
518
        @date       2018.08.27
519
    '''
520
    def findReplaceTextClicked(self):
521
        if not self.graphicsView.hasImage():
522
            self.showImageSelectionMessageBox()
523
            return
524

    
525
        from TextItemEditDialog import QTextItemEditDialog
526

    
527
        self.dlgTextItemEdit = QTextItemEditDialog(self)
528
        self.dlgTextItemEdit.show()
529
        self.dlgTextItemEdit.exec_()
530

    
531
    '''
532
        @brief      show unknownitem's count
533
        @author     humkyung
534
        @date       2018.08.23
535
        @history    humkyung 2018.08.30 display count of symbol, line, text
536
    '''
537
    def onSceneChanged(self):
538
        items = [item for item in self.graphicsView.scene.items() if type(item) is QEngineeringUnknownItem]
539
        if len(items) > 0:
540
            self.labelStatus.setText("<font color='red'>" + self.tr('Unrecognition') + " : {}</font>".format(len(items)))
541
        else:
542
            self.labelStatus.setText("<font color='black'>" + self.tr('Unrecognition') + " : {}</font>".format(len(items)))
543

    
544
        items = [item for item in self.graphicsView.scene.items() if issubclass(type(item), SymbolSvgItem) and type(item) is not QEngineeringErrorItem]
545
        self.labelSymbolStatus.setText("<font color='blue'>" + self.tr('Symbol') + " : {}</font>".format(len(items)))
546

    
547
        items = [item for item in self.graphicsView.scene.items() if type(item) is QEngineeringLineItem]
548
        self.labelLineStatus.setText("<font color='blue'>" + self.tr('Line') + " : {}</font>".format(len(items)))
549

    
550
        items = [item for item in self.graphicsView.scene.items() if issubclass(type(item), QEngineeringTextItem)]
551
        self.labelTextStatus.setText("<font color='blue'>" + self.tr('Text') + " : {}</font>".format(len(items)))
552

    
553
        self.itemTreeWidget.sceneChanged(self.graphicsView.scene.items())
554

    
555
    def dbUpdate(self):
556
        '''
557
            @brief      db update when save or recognition
558
            @author     euisung
559
            @date       2018.11.12
560
            @history    2018.11.02      euisung     remove scene dependency
561
        '''
562
        from AppDocData import AppDocData
563

    
564
        try:
565
            appDocData = AppDocData.instance()
566

    
567
            titleBlockProps = appDocData.getTitleBlockProperties()
568
            #items = self.graphicsView.scene.items()
569
            items = appDocData.allItems
570
            titleBlockItems = []
571
            for item in items:
572
                #if type(item) is QEngineeringLineNoTextItem:
573
                #    item.saveLineData()
574
                if type(item) is QEngineeringTextItem:
575
                    for titleBlockProp in titleBlockProps:
576
                        if item.area == titleBlockProp[0]:
577
                            titleBlockItems.append(item)
578

    
579
            dbItems = [item for item in items if type(item) is QEngineeringInstrumentItem or type(item) is QEngineeringEquipmentItem or type(item) is QEngineeringReducerItem or\
580
            type(item) is QEngineeringNoteItem or type(item) is SymbolSvgItem or type(item) is QEngineeringLineNoTextItem or type(item) is QEngineeringVendorItem] + titleBlockItems
581
            appDocData.saveToDatabase(dbItems)
582
        except Exception as ex:
583
            message = 'error occured({}) in {}:{}'.format(ex, sys.exc_info()[-1].tb_frame.f_code.co_filename, sys.exc_info()[-1].tb_lineno)
584
            self.addMessage.emit(MessageType.Error, message)
585

    
586
    '''
587
        @brief      action save click event
588
        @author     kyouho
589
        @date       2018.08.09
590
        @history    2018.11.02      euisung     add line data list db update
591
                    humkyung save saved time to database
592
                    2018.11.05      euisung     add note data list db update
593
                    2018.11.05      euisung     add db delete process before save
594
                    2018.11.12      euisung     db part move new method to dbUpdate
595
    '''
596
    def actionSaveCliked(self):
597
        from datetime import datetime
598
        from AppDocData import AppDocData
599
        from EngineeringAbstractItem import QEngineeringAbstractItem
600
        from SaveWorkCommand import SaveWorkCommand 
601

    
602
        try:
603
            appDocData = AppDocData.instance()
604
            if appDocData.imgName is None:
605
                self.showImageSelectionMessageBox()
606
                return
607

    
608
            appDocData.clearItemList(False)
609

    
610
            items = self.graphicsView.scene.items()
611
            for item in items:
612
                if issubclass(type(item), QEngineeringAbstractItem):
613
                    appDocData.allItems.append(item)
614
                    if issubclass(type(item), QEngineeringTextItem):
615
                        appDocData.texts.append(item)
616
            ##
617

    
618
            itemTypes = []
619
            for item in items:
620
                typeExist = False
621
                for itemType in itemTypes:
622
                    if type(item) is itemType:
623
                        typeExist = True
624
                        break
625
                if not typeExist:
626
                    itemTypes.append(type(item))
627
            ##
628

    
629
            self._save_work_cmd = SaveWorkCommand()
630
            self._save_work_cmd.display_message.connect(self.onAddMessage)
631
            self._save_work_cmd.finished.connect(self.save_finished)
632

    
633
            """ show spinner gif animation """
634
            self.label_spinner.setWindowFlags(Qt.WindowStaysOnTopHint)
635
            if not hasattr(self, '_movie'):
636
                self._movie = QMovie(':/newPrefix/spinner.gif')
637
                self.label_spinner.setMovie(self._movie)
638
            self.label_spinner.show()
639
            self._movie.start()
640

    
641
            self._save_work_cmd.start()
642

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

    
647
    def save_finished(self):
648
        """ stop movie and hide label after finishing save """
649
        self._movie.stop()
650
        self.label_spinner.hide()
651
        QMessageBox.about(self.graphicsView, self.tr('Notice'), self._save_work_cmd.resultStr)
652
        self.load_drawing_list()
653

    
654
    '''
655
        @brief      refresh resultPropertyTableWidget
656
        @author     kyouho
657
        @date       2018.07.19
658
    '''
659
    def refreshResultPropertyTableWidget(self):
660
        items = self.graphicsView.scene.selectedItems()
661
        if len(items) == 1:
662
            self.resultPropertyTableWidget.show_item_property(items[0])
663
    
664
    '''
665
        @brief  add message listwidget
666
        @author humkyung
667
        @date   2018.07.31
668
    '''
669
    def onAddMessage(self, messageType, message):
670
        from AppDocData import MessageType
671

    
672
        try:
673
            current = QDateTime.currentDateTime()
674

    
675
            item = QListWidgetItem('{}: {}'.format(current.toString('hh:mm:ss'), message))
676
            item.setFlags(item.flags() | Qt.ItemIsEditable)
677
            if messageType == MessageType.Error:
678
                item.setBackground(Qt.red)
679

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

    
684
    '''
685
        @brief      clear log
686
        @author     humkyung
687
        @date       2018.08.01
688
    '''
689
    def onClearLog(self):
690
        self.listWidgetLog.clear()
691

    
692
    '''
693
        @brief      rotate selected symbol
694
        @author     humkyung
695
        @date       2018.08.15
696
    '''
697
    def onRotate(self, action):
698
        selected = [item for item in self.graphicsView.scene.selectedItems() if issubclass(type(item), SymbolSvgItem)]
699
        if len(selected) == 1:
700
            selected[0].rotateSymbol()
701

    
702
    '''
703
        @brief      Area Zoom
704
        @author     Jeongwoo
705
        @date       2018.06.27
706
        @history    connect command's rejected signal
707
    '''
708
    def onAreaZoom(self, action):
709
        if self.actionZoom.isChecked():
710
            cmd = AreaZoomCommand.AreaZoomCommand(self.graphicsView)
711
            cmd.onRejected.connect(self.onCommandRejected)
712
            self.graphicsView.command = cmd
713

    
714
    def onVendor(self, action):
715
        '''
716
            @brief      make vendor package area
717
            @author     euisung
718
            @date       2019.04.29
719
        '''
720
        if not self.graphicsView.hasImage():
721
            self.actionVendor.setChecked(False)
722
            self.showImageSelectionMessageBox()
723
            return
724

    
725
        self.actionVendor.setChecked(True)
726
        if not hasattr(self.actionVendor, 'tag'):
727
            self.actionVendor.tag = PlacePolygonCommand.PlacePolygonCommand(self.graphicsView)
728
            self.actionVendor.tag.onSuccess.connect(self.onVendorCreated)
729
            self.actionVendor.tag.onRejected.connect(self.onCommandRejected)
730

    
731
        self.graphicsView.command = self.actionVendor.tag
732

    
733
    def onVendorCreated(self):
734
        '''
735
            @brief      add created vendor polygon area to scene
736
            @author     euisung
737
            @date       2019.04.29
738
        '''
739
        try:
740
            count = len(self.actionVendor.tag._polyline._vertices)
741
            if count > 2:
742
                qPoints = []
743
                points = []
744
                for point in self.actionVendor.tag._polyline._vertices:
745
                    points.append([round(point[0]), round(point[1])])
746
                    qPoints.append(QPoint(round(point[0]), round(point[1])))
747
                vendorArea = QPolygonF(qPoints)
748
                vendorItem = QEngineeringVendorItem(vendorArea, points)
749
                vendorItem.area = 'Drawing'
750
                vendorItem.transfer.onRemoved.connect(self.itemRemoved)
751
                self.graphicsView.scene.addItem(vendorItem)
752
        finally:
753
            self.graphicsView.scene.removeItem(self.actionVendor.tag._polyline)
754
            self.actionVendor.tag.reset()
755

    
756
    '''
757
        @brief      Fit Window
758
        @author     Jeongwoo
759
        @date       2018.06.27
760
        @history    2018.06.27  Jeongwoo    Chnage method to initialize command [Set None → DefaultCommand]
761
    '''
762
    def fitWindow(self, action):
763
        self.graphicsView.useDefaultCommand()
764
        self.graphicsView.zoomImageInit()
765

    
766
    def onConvertPDFToImage(self):
767
        """
768
        @brief      convert to selected pdf to image
769
        @author     humkyung 
770
        @date       2018.07.09
771
        @history    Euisung 2018.10.11 hide shell
772
        """
773
        try: 
774
            filePath = os.path.join(os.path.dirname(os.path.realpath(__file__)) , 'bin64', 'PDF_TO_IMAGE.exe')
775
            subprocess.call(filePath, shell = False)
776
        except Exception as ex:
777
            message = 'error occured({}) in {}:{}'.format(ex, sys.exc_info()[-1].tb_frame.f_code.co_filename, sys.exc_info()[-1].tb_lineno)
778
            self.addMessage.emit(MessageType.Error, message)
779

    
780
    def onImportTextFromCAD(self):
781
        ''' import text from cad '''
782
        try:
783
            self.onCommandRejected()
784
            dialog = QImportTextFromCADDialog(self)
785
            dialog.show()
786
            dialog.exec_()
787
        except Exception as ex:
788
            message = 'error occured({}) in {}:{}'.format(ex, sys.exc_info()[-1].tb_frame.f_code.co_filename, sys.exc_info()[-1].tb_lineno)
789
            self.addMessage.emit(MessageType.Error, message)
790
        
791
    def on_help(self):
792
        """ open help file """
793
        import os
794

    
795
        try: 
796
            help_file_path = os.path.join(os.path.dirname(os.path.realpath(__file__)) , 'ID2 User Manual.pdf')
797
            os.system('"{}"'.format(help_file_path))
798
        except Exception as ex:
799
            message = 'error occured({}) in {}:{}'.format(ex, sys.exc_info()[-1].tb_frame.f_code.co_filename, sys.exc_info()[-1].tb_lineno)
800
            self.addMessage.emit(MessageType.Error, message)
801

    
802
    '''
803
        @brief      selection changed
804
        @author     humkyung
805
        @date       2018.06.27
806
        @history    humkung 2018.07.08 call tree widget's findItem
807
    '''
808
    def onSelectionChanged(self):
809
        items = [item for item in self.graphicsView.scene.selectedItems() if issubclass(type(item), SymbolSvgItem) or \
810
            type(item) is QEngineeringLineItem or issubclass(type(item), QEngineeringTextItem) or type(item) is QEngineeringUnknownItem or type(item) is QEngineeringVendorItem]
811
        if items:
812
            item = items[-1]
813
            self.itemTreeWidget.findItem(item)
814
            self.resultPropertyTableWidget.show_item_property(item)
815
            if type(item) is QEngineeringErrorItem:
816
                for index in range(self.tableWidgetInconsistency.rowCount()):
817
                    if self.tableWidgetInconsistency.item(index, 1).tag is item:
818
                        self.tableWidgetInconsistency.selectRow(index)
819
                        break
820
        else:
821
            self.resultPropertyTableWidget.show_item_property(None)
822
        
823
    '''
824
        @brief      Initialize scene and itemTreeWidget
825
        @author     Jeongwoo
826
        @date       2018.06.14
827
        @history    humkyung 2018.08.16 ask to delete recognized items before remove
828
    '''
829
    def onInitializeScene(self, action):
830
        if not self.graphicsView.hasImage():
831
            self.actionEquipment.setChecked(False)
832
            self.showImageSelectionMessageBox()
833

    
834
            return
835

    
836
        try:
837
            msg = QMessageBox()
838
            msg.setIcon(QMessageBox.Critical)
839
            msg.setText(self.tr('Do you want to remove all items?\nThis work cannot be recovered.'))
840
            msg.setWindowTitle(self.tr("Initialize"))
841
            msg.setStandardButtons(QMessageBox.Ok|QMessageBox.Cancel)
842
            if QMessageBox.Ok == msg.exec_():
843

    
844
                appDocData = AppDocData.instance()
845
                appDocData.clearItemList(True)
846
            
847
                items = self.graphicsView.scene.items()
848
                for item in items:
849
                    if type(item) is not QGraphicsPixmapItem and item.scene() is not None:
850
                        #if hasattr(item, 'tranfer'):
851
                        #    item.tranfer.onRemoved.emit(item)
852
                        #else:
853
                        #    self.graphicsView.scene.removeItem(item)
854
                        self.graphicsView.scene.removeItem(item)
855

    
856
                        '''
857
                        if type(item) is QEngineeringLineNoTextItem:
858
                            self.removedItems['LINE'].append(str(item.uid))
859
                        elif type(item) is QEngineeringInstrumentItem:
860
                            self.removedItems['INST'].append(str(item.uid))
861
                        elif type(item) is QEngineeringEquipmentItem:
862
                            self.removedItems['EQUIP'].append(str(item.uid))
863
                        elif type(item) is QEngineeringNoteItem:
864
                            self.removedItems['NOTE'].append(str(item.uid))
865
                        '''
866
                    
867
                if self.path is not None:
868
                    baseName = os.path.basename(self.path)
869
                    self.itemTreeWidget.setCurrentPID(baseName)
870

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

    
875
    '''
876
        @brief      Manage Checkable Action statement
877
        @author     Jeongwoo
878
        @date       2018.05.10
879
        @history    2018.06.27  Jeongwoo    Chnage method to initialize command [Set None → DefaultCommand]
880
    '''
881
    def actionGroupTriggered(self, action):
882
        if hasattr(self.actionLine, 'tag'):
883
            self.actionLine.tag.onRejected.emit(None)
884

    
885
        if hasattr(self.actionVendor, 'tag'):
886
            self.actionVendor.tag.onRejected.emit(None)
887

    
888
        if self.graphicsView.command is not None:
889
            self.graphicsView.useDefaultCommand()
890

    
891
        for _action in self.actionGroup.actions():
892
            _action.setChecked(False)
893

    
894
        action.setChecked(True)
895

    
896
    '''
897
        @brief      Create Equipment
898
        @author     Jeongwoo
899
        @date       18.05.03
900
        @history    2018.05.04  Jeongwoo    Add Parameter on CreateSymbolCommand
901
    '''
902
    def createEquipment(self):
903
        if not self.graphicsView.hasImage():
904
            self.actionEquipment.setChecked(False)
905
            self.showImageSelectionMessageBox()
906
            return
907
        if self.actionEquipment.isChecked():
908
            self.graphicsView.command = CreateSymbolCommand.CreateSymbolCommand(self.graphicsView, self.itemTreeWidget, self.dirTreeWidget)
909
        else:
910
            self.graphicsView.useDefaultCommand()
911

    
912

    
913
    '''
914
        @brief      Create Nozzle
915
        @author     Jeongwoo
916
        @date       2018.05.03
917
        @history    2018.05.04  Jeongwoo    Add Parameter on CreateSymbolCommand
918
    '''
919
    def createNozzle(self):
920
        if not self.graphicsView.hasImage():
921
            self.actionNozzle.setChecked(False)
922
            self.showImageSelectionMessageBox()
923
            return
924
        if self.actionNozzle.isChecked():
925
            self.graphicsView.command = CreateSymbolCommand.CreateSymbolCommand(self.graphicsView, self.itemTreeWidget, self.dirTreeWidget)
926
        else:
927
            self.graphicsView.useDefaultCommand()
928

    
929
    '''
930
        @brief      Area OCR
931
        @author     Jeongwoo
932
        @date       18.04.18
933
        @history    2018.05.02  Jeongwoo    Change graphicsView.command by actionOCR checked state
934
                                            Show MessageBox when imageviewer doesn't have image
935
    '''
936
    def onAreaOcr(self):
937
        if not self.graphicsView.hasImage():
938
            self.actionOCR.setChecked(False)
939
            self.showImageSelectionMessageBox()
940
            return
941

    
942
        if self.actionOCR.isChecked():
943
            cmd = AreaOcrCommand.AreaOcrCommand(self.graphicsView)
944
            cmd.onSuccess.connect(self.onRecognizeText)
945
            cmd.onRejected.connect(self.onCommandRejected)
946
            self.graphicsView.command = cmd
947
        else:
948
            self.graphicsView.useDefaultCommand()
949
    
950
    '''
951
        @brief      show text recognition dialog
952
        @author     humkyung
953
        @date       2018.08.08
954
    '''
955
    def onRecognizeText(self, x, y, width, height):
956
        from OcrResultDialog import QOcrResultDialog
957

    
958
        try:
959
            image = self.graphicsView.image().copy(x, y, width, height)
960
            dialog = QOcrResultDialog(self.graphicsView, image, QRectF(x, y, width, height))
961
            (isAccept, textInfoList) = dialog.showDialog()
962
            if isAccept:
963
                if textInfoList is not None and len(textInfoList) > 0:
964
                    docData = AppDocData.instance()
965
                    for textInfo in textInfoList:
966
                        x = textInfo.getX()
967
                        y = textInfo.getY()
968
                        angle = textInfo.getAngle()
969
                        text = textInfo.getText()
970
                        width = textInfo.getW()
971
                        height = textInfo.getH()
972
                        item = TextItemFactory.instance().createTextItem(textInfo)
973
                        if item is not None:
974
                            item.loc = [x, y]
975
                            item.size = (width, height)
976
                            item.angle = angle
977
                            item.setDefaultTextColor(Qt.blue)
978
                            item.addTextItemToScene(self.graphicsView.scene)
979
                            item.transfer.onRemoved.connect(self.itemRemoved)
980
                        else:
981
                            message = 'error occured({}) in {}:{}'.format('텍스트 생성에 실패했습니다.', sys.exc_info()[-1].tb_frame.f_code.co_filename, sys.exc_info()[-1].tb_lineno)
982
                            self.addMessage.emit(MessageType.Normal, message)
983
                else:
984
                    QMessageBox.about(self.graphicsView, self.tr("Notice"), self.tr("Fail to recognize text"))
985
        except Exception as ex:
986
            message = 'error occured({}) in {}:{}'.format(ex, sys.exc_info()[-1].tb_frame.f_code.co_filename, sys.exc_info()[-1].tb_lineno)
987
            self.addMessage.emit(MessageType.Error, message)
988

    
989
    '''
990
        @brief  area configuration
991
    '''
992
    def areaConfiguration(self):
993
        from ConfigurationAreaDialog import QConfigurationAreaDialog
994
        if not self.graphicsView.hasImage():
995
            self.showImageSelectionMessageBox()
996
            return
997
        self.onCommandRejected()
998
        self.dlgConfigurationArea = QConfigurationAreaDialog(self)
999
        self.dlgConfigurationArea.show()
1000
        self.dlgConfigurationArea.exec_()
1001

    
1002
    '''
1003
        @brief  configuration
1004
    '''
1005
    def configuration(self):
1006
        from ConfigurationDialog import QConfigurationDialog
1007

    
1008
        self.dlgConfiguration = QConfigurationDialog(self)
1009
        #self.dlgConfiguration.show()
1010
        if QDialog.Accepted == self.dlgConfiguration.exec_():
1011
            QEngineeringLineItem.LINE_TYPE_COLORS.clear()
1012
            QEngineeringInstrumentItem.INST_COLOR = None
1013

    
1014
    '''
1015
        @brief  show special item types dialog 
1016
        @author humkyung
1017
        @date   2019.08.10
1018
    '''
1019
    def on_show_special_item_types(self):
1020
        from SpecialItemTypesDialog import QSpecialItemTypesDialog
1021

    
1022
        dlg = QSpecialItemTypesDialog(self)
1023
        dlg.exec_()
1024

    
1025
    def on_show_data_transfer(self):
1026
        """ show data transfer dialog """
1027
        from DataTransferDialog import QDataTransferDialog
1028

    
1029
        dlg = QDataTransferDialog(self)
1030
        dlg.exec_()
1031

    
1032
    def on_show_data_export(self):
1033
        """ show data export dialog """
1034
        from DataExportDialog import QDataExportDialog
1035

    
1036
        dlg = QDataExportDialog(self)
1037
        dlg.exec_()
1038

    
1039
    def on_show_opc_relation(self):
1040
        """ show opc relation dialog """
1041
        from OPCRelationDialog import QOPCRelationDialog
1042

    
1043
        dlg = QOPCRelationDialog(self)
1044
        dlg.exec_()
1045

    
1046
    '''
1047
        @brief  show nominal diameter dialog 
1048
        @author humkyung
1049
        @date   2018.06.28
1050
    '''
1051
    def onShowCodeTable(self):
1052
        from CodeTableDialog import QCodeTableDialog
1053

    
1054
        dlg = QCodeTableDialog(self)
1055
        dlg.exec_()
1056

    
1057
    '''
1058
        @brief  show HMB data
1059
        @author humkyung
1060
        @date   2018.07.11
1061
    '''
1062
    def onHMBData(self):
1063
        from HMBDialog import QHMBDialog
1064

    
1065
        dlg = QHMBDialog(self)
1066
        dlg.show()
1067
        dlg.exec_()
1068

    
1069
    '''
1070
        @brief  show line data list 
1071
        @author humkyung
1072
        @date   2018.05.03
1073
    '''
1074
    def showItemDataList(self):
1075
        from ItemDataExportDialog import QItemDataExportDialog
1076

    
1077
        self.dlgLineDataList = QItemDataExportDialog(self)
1078
        self.dlgLineDataList.exec_()
1079

    
1080
    def showTextDataList(self):
1081
        '''
1082
            @brief      show all text item in scene
1083
            @author     euisung
1084
            @date       2019.04.18
1085
        '''
1086
        try:
1087
            if not self.graphicsView.hasImage():
1088
                self.showImageSelectionMessageBox()
1089
                return
1090

    
1091
            self.onCommandRejected()
1092
            dialog = QTextDataListDialog(self)
1093
            dialog.show()
1094
            dialog.exec_()
1095
        except Exception as ex:
1096
            message = 'error occured({}) in {}:{}'.format(ex, sys.exc_info()[-1].tb_frame.f_code.co_filename, sys.exc_info()[-1].tb_lineno)
1097
            self.addMessage.emit(MessageType.Error, message)
1098

    
1099
    '''
1100
        @brief  Show Image Selection Guide MessageBox
1101
        @author Jeongwoo
1102
        @date   2018.05.02
1103
    '''
1104
    def showImageSelectionMessageBox(self):
1105
        QMessageBox.about(self.graphicsView, self.tr("Notice"), self.tr("First select image drawing"))
1106
        
1107
    '''
1108
        @brief  change selected lines' type by selected line type
1109
        @author humkyung
1110
        @date   2018.06.27
1111
    '''
1112
    def onLineTypeChanged(self, param):
1113
        lineType = self.lineComboBox.itemText(param)
1114
        selected = [item for item in self.graphicsView.scene.selectedItems() if type(item) is QEngineeringLineItem]
1115
        if selected:
1116
            for item in selected:
1117
                item.lineType = lineType
1118

    
1119
    def display_colors(self, value):
1120
        """ display colors """
1121
        from DisplayColors import DisplayColors
1122
        from DisplayColors import DisplayOptions
1123

    
1124
        DisplayColors.instance().option = DisplayOptions.DisplayByLineNo if value == True else DisplayOptions.DisplayByLineType
1125
        if hasattr(self, 'graphicsView'):
1126
            self.graphicsView.scene.update(self.graphicsView.sceneRect())
1127
            DisplayColors.instance().save_data()
1128

    
1129
    '''
1130
        @brief      Open image drawing file and then display it
1131
        @author     humkyung
1132
        @date       2018.??.??
1133
        @history    18.04.23 Jeongwoo    Add AppDocData.instance().setCurrentPidSource
1134
                    18.04.23 Jeongwoo    Add Store Set Current Pid Image on AppDocData
1135
                    18.05.02 Jeongwoo    Add useDefaultCommand()
1136
                    humkyung 2018.05.24 load recognition result file if exists
1137
                    Jeongwoo 2018.05.29 load data on xml if xml file exist
1138
                    humkyung 2018.08.22 clear scene before loading xml file
1139
    '''
1140
    def onOpenImageDrawing(self, path=None):
1141
        from Drawing import Drawing
1142
        from xml.etree.ElementTree import Element, SubElement, dump, ElementTree, parse
1143

    
1144
        try:
1145
            appDocData = AppDocData.instance()
1146
            project = appDocData.getCurrentProject()
1147
            
1148
            self.path = self.graphicsView.loadImageFromFile(project.getDrawingFilePath(), path if type(path) is str else '')
1149
            if os.path.isfile(self.path):
1150
                self.onCommandRejected()
1151
                appDocData.clear()
1152

    
1153
                appDocData.setImgFilePath(self.path)
1154
                appDocData.activeDrawing = Drawing(None, appDocData.imgName, None)
1155
                if not appDocData.set_occupying_drawing(appDocData.activeDrawing.UID):
1156
                    QMessageBox.about(self.graphicsView, self.tr("Notice"), self.tr("The drawing is locked for editing by another user"))
1157
                    return
1158
                appDocData.activeDrawing.set_pid_source(Image.open(self.path))
1159
                self.itemTreeWidget.setCurrentPID(appDocData.activeDrawing.name)
1160

    
1161
                drawingList = self.treeWidgetDrawingList.topLevelItem(0)
1162
                for childIdex in range(drawingList.childCount()):
1163
                    drawingList.child(childIdex).setCheckState(0, Qt.Unchecked)
1164
                for childIdex in range(drawingList.childCount()):
1165
                    child = drawingList.child(childIdex)
1166
                    if child.text(0).replace('.png', '') == appDocData.activeDrawing.name:
1167
                        child.setCheckState(0, Qt.Checked)
1168
                        break
1169

    
1170
                try:
1171
                    self.progress = QProgressDialog(self.tr("Please wait for a while"), self.tr("Cancel"), 0, 100, self) if not hasattr(self, 'progress') else self.progress
1172
                    self.progress.setWindowModality(Qt.WindowModal)
1173
                    self.progress.setAutoReset(True)
1174
                    self.progress.setAutoClose(True)
1175
                    self.progress.setMinimum(0)
1176
                    self.progress.setMaximum(100)
1177
                    self.progress.resize(600,100)
1178
                    self.progress.setWindowTitle(self.tr("Reading file..."))
1179
                    self.progress.show()
1180
                    ## Load data
1181
                    path = os.path.join(appDocData.getCurrentProject().getTempPath(), appDocData.imgName + '.xml')
1182
                    configs = appDocData.getConfigs('Data Load', 'Xml First')
1183
                    if configs and int(configs[0].value) is 1 and os.path.isfile(path):
1184
                        self.loadRecognitionResultFromXml(path)
1185
                    else:
1186
                        self.load_drawing(appDocData.activeDrawing)
1187
                finally:
1188
                    self.progress.setValue(self.progress.maximum())
1189
                    self.progress.hide()
1190

    
1191
                self.changeViewCheckedState(True)
1192
        except Exception as ex:
1193
            message = 'error occured({}) in {}:{}'.format(ex, sys.exc_info()[-1].tb_frame.f_code.co_filename, sys.exc_info()[-1].tb_lineno)
1194
            self.addMessage.emit(MessageType.Error, message)
1195

    
1196
        return self.path
1197

    
1198
    def changeViewCheckedState(self, checked, clear=True):
1199
        '''
1200
            @brief      change view checked state
1201
            @author     euisung
1202
            @date       2019.03.06
1203
        '''
1204
        #self.actionImage_Drawing.setChecked(checked)
1205
        self.actionViewText.setChecked(checked)
1206
        self.actionViewSymbol.setChecked(checked)
1207
        self.actionViewLine.setChecked(checked)
1208
        self.actionViewUnknown.setChecked(checked)
1209
        self.actionViewInconsistency.setChecked(checked)
1210
        self.actionViewVendor_Area.setChecked(not checked)
1211
        self.actionDrawing_Only.setChecked(not checked)
1212
        if clear:
1213
            self.tableWidgetInconsistency.clearContents()
1214
            self.tableWidgetInconsistency.setRowCount(0)
1215

    
1216
    def onViewDrawingOnly(self, isChecked):
1217
        '''
1218
            @brief  visible/invisible except image drawing
1219
            @author euisung
1220
            @date   2019.04.22
1221
        '''
1222
        self.changeViewCheckedState(not isChecked, False)
1223
        for item in self.graphicsView.scene.items():
1224
            if type(item) is not QGraphicsPixmapItem:
1225
                item.setVisible(not isChecked)
1226

    
1227
    '''
1228
        @brief  visible/invisible image drawing
1229
        @author humkyung
1230
        @date   2018.06.25
1231
    '''
1232
    def onViewImageDrawing(self, isChecked):
1233
        for item in self.graphicsView.scene.items():
1234
            if type(item) is QGraphicsPixmapItem:
1235
                item.setVisible(isChecked)
1236
                break
1237

    
1238
    '''
1239
        @brief  visible/invisible Text 
1240
        @author humkyung
1241
        @date   2018.06.28
1242
    '''
1243
    def onViewText(self, isChecked):
1244
        selected = [item for item in self.graphicsView.scene.items() if issubclass(type(item), QEngineeringTextItem)]
1245
        for item in selected:
1246
            item.setVisible(isChecked)
1247

    
1248
    '''
1249
        @brief  visible/invisible Symbol 
1250
        @author humkyung
1251
        @date   2018.06.28
1252
    '''
1253
    def onViewSymbol(self, isChecked):
1254
        selected = [item for item in self.graphicsView.scene.items() if (issubclass(type(item), SymbolSvgItem) and type(item) is not QEngineeringErrorItem)]
1255
        for item in selected:
1256
            item.setVisible(isChecked)
1257

    
1258
    '''
1259
        @brief  visible/invisible Line
1260
        @author humkyung
1261
        @date   2018.06.28
1262
    '''
1263
    def onViewLine(self, isChecked):
1264
        selected = [item for item in self.graphicsView.scene.items() if type(item) is QEngineeringLineItem]
1265
        for item in selected:
1266
            item.setVisible(isChecked)
1267

    
1268
    def onViewInconsistency(self, isChecked):
1269
        '''
1270
            @brief  visible/invisible Inconsistency
1271
            @author euisung
1272
            @date   2019.04.03
1273
        '''
1274
        selected = [item for item in self.graphicsView.scene.items() if type(item) is QEngineeringErrorItem]
1275
        for item in selected:
1276
            item.setVisible(isChecked)
1277

    
1278
    '''
1279
        @brief  visible/invisible Unknown 
1280
        @author humkyung
1281
        @date   2018.06.28
1282
    '''
1283
    def onViewUnknown(self, isChecked):
1284
        selected = [item for item in self.graphicsView.scene.items() if type(item) is QEngineeringUnknownItem]
1285
        for item in selected:
1286
            item.setVisible(isChecked)
1287

    
1288
    def onViewVendorArea(self, isChecked):
1289
        '''
1290
            @brief  visible/invisible Vendor Area
1291
            @author euisung
1292
            @date   2019.04.29
1293
        '''
1294
        selected = [item for item in self.graphicsView.scene.items() if type(item) is QEngineeringVendorItem]
1295
        for item in selected:
1296
            item.setVisible(isChecked)
1297

    
1298
    '''
1299
        @brief  create a symbol
1300
        @history    2018.05.02  Jeongwoo    Change return value of QSymbolEditorDialog (Single variable → Tuple)
1301
                                            Add SymbolSvgItem
1302
                    2018.05.03  Jeongwoo    Change method to draw Svg Item on Scene (svg.addSvgItemToScene)
1303
                                            Change method to make svg and image path
1304
                    2018.06.08  Jeongwoo    Add Paramter on SymbolSvgItem.buildItem()
1305
    '''
1306
    def onCreateSymbolClicked(self):
1307
        cmd = FenceCommand.FenceCommand(self.graphicsView)
1308
        cmd.onSuccess.connect(self.onAreaSelected)
1309
        self.graphicsView.command = cmd
1310
        QApplication.setOverrideCursor(Qt.CrossCursor)
1311

    
1312
    '''
1313
        @brief      show SymbolEditorDialog with image selected by user
1314
        @author     humkyung
1315
        @date       2018.07.20
1316
    '''
1317
    def onAreaSelected(self, x, y, width, height):
1318
        try:
1319
            image = self.graphicsView.image()
1320
            if image is not None:
1321
                symbolEditorDialog = SymbolEditorDialog.QSymbolEditorDialog(self, image.copy(x, y, width, height), AppDocData.instance().getCurrentProject())
1322
                (isAccepted, isImmediateInsert, offsetX, offsetY, newSym) = symbolEditorDialog.showDialog()
1323
                self.dirTreeWidget.initDirTreeWidget()
1324
                if isAccepted:
1325
                    if isImmediateInsert:
1326
                        svgPath = newSym.getSvgFileFullPath()
1327
                        img = cv2.imread(newSym.getImageFileFullPath(), 1)
1328
                        w, h = (0, 0)
1329
                        if len(img.shape[::-1]) == 2:
1330
                            w, h = img.shape[::-1]
1331
                        else:
1332
                            _chan, w, h = img.shape[::-1]
1333
                        svg = SymbolSvgItem(svgPath)
1334
                        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)
1335

    
1336
                        svg.transfer.onRemoved.connect(self.itemTreeWidget.itemRemoved)
1337
                        svg.addSvgItemToScene(self.graphicsView.scene)
1338
                        for connector in svg.connectors:
1339
                            self.graphicsView.scene.addItem(connector)
1340
        finally:
1341
            self.onCommandRejected()
1342
            QApplication.restoreOverrideCursor()
1343
    
1344
    '''
1345
        @brief      create a line
1346
        @author     humkyung
1347
        @history    Jeongwoo 2018.05.10 Change method for Checkable action
1348
    '''
1349
    def onPlaceLine(self):        
1350
        if not self.graphicsView.hasImage():
1351
            self.actionLine.setChecked(False)
1352
            self.showImageSelectionMessageBox()
1353
            return
1354

    
1355
        self.actionLine.setChecked(True)
1356
        if not hasattr(self.actionLine, 'tag'):
1357
            self.actionLine.tag = PlaceLineCommand.PlaceLineCommand(self.graphicsView)
1358
            self.actionLine.tag.onSuccess.connect(self.onLineCreated)
1359
            self.actionLine.tag.onRejected.connect(self.onCommandRejected)
1360

    
1361
        self.graphicsView.command = self.actionLine.tag
1362

    
1363
    '''
1364
        @brief      add created lines to scene
1365
        @author     humkyung
1366
        @date       2018.07.23
1367
    '''
1368
    def onLineCreated(self):
1369
        from EngineeringConnectorItem import QEngineeringConnectorItem
1370

    
1371
        try:
1372
            count = len(self.actionLine.tag._polyline._vertices)
1373
            if count > 1:
1374
                items = []
1375

    
1376
                lineType = self.lineComboBox.currentText()
1377
                for index in range(count - 1):
1378
                    start = self.actionLine.tag._polyline._vertices[index]
1379
                    end  = self.actionLine.tag._polyline._vertices[index + 1]
1380
                    
1381
                    lineItem = QEngineeringLineItem(vertices=[start, end])
1382
                    lineItem.transfer.onRemoved.connect(self.itemRemoved)
1383
                    lineItem.lineType = lineType
1384
                    if items:
1385
                        lineItem.connect_if_possible(items[-1], 5)
1386
                    else:
1387
                        pt = lineItem.startPoint()
1388
                        selected = [item for item in self.graphicsView.scene.items(QPointF(pt[0], pt[1])) if type(item) is QEngineeringConnectorItem or type(item) is QEngineeringLineItem]
1389
                        if selected:
1390
                            lineItem.connect_if_possible(selected[0].parent if type(selected[0]) is QEngineeringConnectorItem else selected[0], 5)
1391
                    
1392
                    items.append(lineItem)
1393
                    self.graphicsView.scene.addItem(lineItem)
1394

    
1395
                pt = items[-1].endPoint()
1396
                selected = [item for item in self.graphicsView.scene.items(QPointF(pt[0], pt[1])) if type(item) is QEngineeringConnectorItem and item.parent is not items[-1]]
1397
                if selected:
1398
                    items[-1].connect_if_possible(selected[0].parent, 5)
1399

    
1400
        finally:
1401
            self.graphicsView.scene.removeItem(self.actionLine.tag._polyline)
1402
            self.actionLine.tag.reset()
1403

    
1404
    '''
1405
        @brief      refresh scene
1406
        @author     humkyung
1407
        @date       2018.07.23
1408
    '''
1409
    def onCommandRejected(self, cmd=None):
1410
        try:
1411
            if type(cmd) is PlaceLineCommand.PlaceLineCommand:
1412
                if self.actionLine.tag._polyline:
1413
                    self.graphicsView.scene.removeItem(self.actionLine.tag._polyline)
1414
                self.graphicsView.scene.update()
1415
                self.actionLine.tag.reset()
1416

    
1417
                self.actionLine.setChecked(False)
1418
            elif type(cmd) is AreaZoomCommand.AreaZoomCommand:
1419
                self.actionZoom.setChecked(False)
1420
            elif type(cmd) is AreaOcrCommand.AreaOcrCommand:
1421
                self.actionOCR.setChecked(False)
1422
            elif type(cmd) is PlacePolygonCommand.PlacePolygonCommand:
1423
                self.actionVendor.setChecked(False)
1424
            else:
1425
                if hasattr(self.actionLine, 'tag') and self.actionLine.tag._polyline:
1426
                    self.graphicsView.scene.removeItem(self.actionLine.tag._polyline)
1427
                    self.graphicsView.scene.update()
1428
                    self.actionLine.tag.reset()
1429
                if hasattr(self.actionVendor, 'tag') and self.actionVendor.tag._polyline:
1430
                    self.graphicsView.scene.removeItem(self.actionVendor.tag._polyline)
1431
                    self.graphicsView.scene.update()
1432
                    self.actionVendor.tag.reset()
1433
                self.actionLine.setChecked(False)
1434
                self.actionZoom.setChecked(False)
1435
                self.actionOCR.setChecked(False)
1436
                self.actionVendor.setChecked(False)
1437
        finally:
1438
            self.graphicsView.useDefaultCommand()
1439
     
1440
    '''
1441
        @brief      restore to default command when user press Escape key
1442
        @author     humkyung 
1443
        @date       2018.08.09
1444
        
1445
    '''
1446
    def keyPressEvent(self, event):
1447
        try:
1448
            if event.key() == Qt.Key_Escape:
1449
                # already catched in command
1450
                pass
1451
                #checked = self.actionGroup.checkedAction()
1452
                #if checked:
1453
                #    checked.setChecked(False)
1454
                #    self.graphicsView.useDefaultCommand()
1455
            elif event.key() == Qt.Key_1:
1456
                if self.actionImage_Drawing.isChecked():
1457
                    self.onViewImageDrawing(False)
1458
                    self.actionImage_Drawing.setChecked(False)
1459
                else:
1460
                    self.onViewImageDrawing(True)
1461
                    self.actionImage_Drawing.setChecked(True)
1462
            elif event.key() == Qt.Key_2:
1463
                if self.actionViewText.isChecked():
1464
                    self.onViewText(False)
1465
                    self.actionViewText.setChecked(False)
1466
                else:
1467
                    self.onViewText(True)
1468
                    self.actionViewText.setChecked(True)
1469
            elif event.key() == Qt.Key_3:
1470
                if self.actionViewSymbol.isChecked():
1471
                    self.onViewSymbol(False)
1472
                    self.actionViewSymbol.setChecked(False)
1473
                else:
1474
                    self.onViewSymbol(True)
1475
                    self.actionViewSymbol.setChecked(True)
1476
            elif event.key() == Qt.Key_4:
1477
                if self.actionViewLine.isChecked():
1478
                    self.onViewLine(False)
1479
                    self.actionViewLine.setChecked(False)
1480
                else:
1481
                    self.onViewLine(True)
1482
                    self.actionViewLine.setChecked(True)
1483
            elif event.key() == Qt.Key_5:
1484
                if self.actionViewUnknown.isChecked():
1485
                    self.onViewUnknown(False)
1486
                    self.actionViewUnknown.setChecked(False)
1487
                else:
1488
                    self.onViewUnknown(True)
1489
                    self.actionViewUnknown.setChecked(True)
1490
            elif event.key() == Qt.Key_6:
1491
                if self.actionViewInconsistency.isChecked():
1492
                    self.onViewInconsistency(False)
1493
                    self.actionViewInconsistency.setChecked(False)
1494
                else:
1495
                    self.onViewInconsistency(True)
1496
                    self.actionViewInconsistency.setChecked(True)
1497
            elif event.key() == Qt.Key_7:
1498
                if self.actionViewVendor_Area.isChecked():
1499
                    self.onViewVendorArea(False)
1500
                    self.actionViewVendor_Area.setChecked(False)
1501
                else:
1502
                    self.onViewVendorArea(True)
1503
                    self.actionViewVendor_Area.setChecked(True)
1504
            elif event.key() == 96: # '`' key
1505
                if self.actionDrawing_Only.isChecked():
1506
                    self.onViewDrawingOnly(False)
1507
                    self.actionDrawing_Only.setChecked(False)
1508
                else:
1509
                    self.onViewDrawingOnly(True)
1510
                    self.actionDrawing_Only.setChecked(True)
1511
            elif event.key() == Qt.Key_M: # merge text as vertical
1512
                from TextInfo import TextInfo
1513

    
1514
                textItems = [text for text in self.graphicsView.scene.selectedItems() if type(text) is QEngineeringTextItem and text.angle == 0]
1515
                textItems = sorted(textItems, key=lambda text: text.loc[1])
1516
                minX = sys.maxsize
1517
                minY = sys.maxsize
1518
                maxX = 0
1519
                maxY = 0
1520
                newText = ''
1521
                for text in textItems:
1522
                    if text.loc[0] < minX: minX = text.loc[0]
1523
                    if text.loc[1] < minY: minY = text.loc[1]
1524
                    if text.loc[0] + text.size[0] > maxX: maxX = text.loc[0] + text.size[0]
1525
                    if text.loc[1] + text.size[1] > maxY: maxY = text.loc[1] + text.size[1]
1526
                    newText = newText + text.text() + "\n"
1527
                    text.transfer.onRemoved.emit(text)
1528
                newText = newText[:-1]
1529
                
1530
                textInfo = TextInfo(newText, minX, minY, maxX - minX, maxY - minY, 0)
1531
                x = textInfo.getX()
1532
                y = textInfo.getY()
1533
                angle = textInfo.getAngle()
1534
                text = textInfo.getText()
1535
                width = textInfo.getW()
1536
                height = textInfo.getH()
1537
                item = TextItemFactory.instance().createTextItem(textInfo)
1538
                if item is not None:
1539
                    item.loc = [x, y]
1540
                    item.size = (width, height)
1541
                    item.angle = angle
1542
                    item.setDefaultTextColor(Qt.blue)
1543
                    item.addTextItemToScene(self.graphicsView.scene)
1544
                    item.transfer.onRemoved.connect(self.itemRemoved)
1545
                
1546
            QMainWindow.keyPressEvent(self, event)
1547
        except Exception as ex:
1548
            message = 'error occured({}) in {}:{}'.format(ex, sys.exc_info()[-1].tb_frame.f_code.co_filename, sys.exc_info()[-1].tb_lineno)
1549
            self.addMessage.emit(MessageType.Error, message)
1550
    
1551
    def recognizeBatch(self, MainWindow):
1552
        '''
1553
            @brief      batch recognize symbol, text and line
1554
            @author     euisung
1555
            @date       2018.11.23
1556
        
1557
        '''
1558
        from datetime import datetime
1559
        from RecognitionDialog import QRecognitionDialog
1560

    
1561
        appDocData = AppDocData.instance()
1562
        project = appDocData.getCurrentProject()
1563
        appDocData.needReOpening = None
1564
        currentPid = None
1565
        
1566
        if self.graphicsView.hasImage():
1567
            currentPid = appDocData.activeDrawing.name
1568

    
1569
        drawingTop = self.treeWidgetDrawingList.topLevelItem(0)
1570
        drawingCount = drawingTop.childCount()
1571
        checkedTreeItems = []
1572
        checkedDrawingPath = []
1573
        for drawing in range(drawingCount):
1574
            drawingChild = drawingTop.child(drawing)
1575
            if drawingChild.checkState(0) == 2:
1576
                checkedTreeItems.append(drawingChild)
1577
                checkedDrawingPath.append(os.path.join(project.getDrawingFilePath(), drawingChild.data(0, 0)))
1578
                if currentPid is not None and drawingChild.data(0, 0).find(currentPid) is 0:
1579
                    appDocData.needReOpening = False # later check need reopening at drawUnknownItems()
1580
                    currentPid = drawingChild.data(0, 0)
1581

    
1582
        if len(checkedDrawingPath) == 0:
1583
            self.showImageSelectionMessageBox()
1584
            return
1585

    
1586
        try:
1587
            self.onClearLog()
1588
            self.dlg = QRecognitionDialog(self, checkedDrawingPath, True)
1589
            self.dlg.exec_()
1590
            if self.dlg.isAccepted == True:
1591
                pass
1592

    
1593
            if appDocData.needReOpening == True:
1594
                drawing = os.path.join(appDocData.getCurrentProject().getDrawingFilePath(), currentPid)
1595
                self.onOpenImageDrawing(drawing)
1596

    
1597
            # save working date-time
1598
            drawings = appDocData.getDrawings()
1599
            checkedDrawings = []
1600
            for checkedTreeItem in checkedTreeItems:
1601
                for drawing in drawings:
1602
                    if checkedTreeItem.data(0, 0) == drawing[1]:
1603
                        if drawing[0]:
1604
                            drawing[2] = datetime.now().strftime('%Y-%m-%d %H:%M:%S')
1605
                            checkedDrawings.append(drawing)
1606
                            checkedTreeItem.setText(1, datetime.now().strftime('%Y-%m-%d %H:%M:%S'))
1607
            appDocData.saveDrawings(checkedDrawings)
1608
            self.changeViewCheckedState(True)
1609
            # up to here
1610
        except Exception as ex:
1611
            message = 'error occured({}) in {}:{}'.format(ex, sys.exc_info()[-1].tb_frame.f_code.co_filename, sys.exc_info()[-1].tb_lineno)
1612
            self.addMessage.emit(MessageType.Error, message)
1613

    
1614
    '''
1615
        @brief      recognize symbol and text
1616
        @author     humkyung
1617
        @date       2018.04.??
1618
        @history    2018.04.16  humkyung    execute line no tracing
1619
                    2018.05.02  Jeongwoo    Show MessageBox when imageviewer doesn't have image
1620
                    2018.05.25  Jeongwoo    Add parameter on QRecognitionDialog.__init__() and Move thread to QRecognitionDialog
1621
                                            Remove codes below if self.dlg.isAccepted == True
1622
                    2018.05.29  Jeongwoo    Remove connects and comments
1623
                    humkyung 2018.11.05 save working date-time
1624
    '''
1625
    def recognize(self, MainWindow):
1626
        from datetime import datetime
1627
        from RecognitionDialog import QRecognitionDialog
1628

    
1629
        if not self.graphicsView.hasImage():
1630
            self.showImageSelectionMessageBox()
1631
            return
1632

    
1633
        try:
1634
            appDocData = AppDocData.instance()
1635

    
1636
            self.onClearLog()
1637
            appDocData.needReOpening = False
1638
            drawingList = []
1639
            drawingList.append(self.path)
1640
            self.dlg = QRecognitionDialog(self, drawingList, False)
1641
            self.dlg.exec_()
1642

    
1643
            if appDocData.needReOpening == True:
1644
                self.itemTreeWidget.setCurrentPID(appDocData.activeDrawing.name)
1645
                self.drawDetectedItemsToScene()
1646
                
1647
                # save working date-time
1648
                drawings = appDocData.getDrawings()
1649
                drawing = [drawing for drawing in drawings if appDocData.imgName == os.path.splitext(drawing.name)[0]]
1650
                if drawing[0]:
1651
                    drawing[0].datetime = datetime.now().strftime('%Y-%m-%d %H:%M:%S')
1652
                    appDocData.saveDrawings(drawing)
1653

    
1654
                currentPid = appDocData.activeDrawing.name
1655

    
1656
                drawingTop = self.treeWidgetDrawingList.topLevelItem(0)
1657
                drawingCount = drawingTop.childCount()
1658
                
1659
                for drawing in range(drawingCount):
1660
                    drawingChild = drawingTop.child(drawing)
1661
                    if drawingChild.data(0, 0).find(currentPid) is 0:
1662
                        drawingChild.setText(1, datetime.now().strftime('%Y-%m-%d %H:%M:%S'))
1663
                self.changeViewCheckedState(True)
1664
                # up to here
1665
        except Exception as ex:
1666
            message = 'error occured({}) in {}:{}'.format(ex, sys.exc_info()[-1].tb_frame.f_code.co_filename, sys.exc_info()[-1].tb_lineno)
1667
            self.addMessage.emit(MessageType.Error, message)
1668

    
1669
    '''
1670
        @brief      remove item from tree widget and then remove from scene
1671
        @date       2018.05.25
1672
        @author     Jeongwoo
1673
    '''
1674
    def itemRemoved(self, item):
1675
        try:
1676
            self.itemTreeWidget.itemRemoved(item)
1677

    
1678
            matches = [_item for _item in self.graphicsView.scene.items() if hasattr(_item, 'connectors') and [connector for connector in _item.connectors if connector.connectedItem is item]]
1679
            for match in matches:
1680
                for connector in match.connectors:
1681
                    if connector.connectedItem is item: connector.connectedItem = None
1682

    
1683
            #matches = [_item for _item in self.graphicsView.scene.items() if hasattr(_item, 'remove_assoc_item')]
1684
            #for _item in matches:
1685
            #    _item.remove_assoc_item(item)
1686

    
1687
            matches = [_item for _item in self.graphicsView.scene.items() if type(_item) is QEngineeringLineNoTextItem]
1688
            for match in matches:
1689
                if item is match.prop('From'):
1690
                    match.set_property('From', None)
1691
                elif item is match.prop('To'):
1692
                    match.set_property('To', None)
1693

    
1694
                for run in match.runs:
1695
                    if item in run.items:
1696
                        index = run.items.index(item)
1697
                        run.items.pop(index)
1698

    
1699
            matches = [_item for _item in self.graphicsView.scene.items() if hasattr(_item, 'owner')]
1700
            for match in matches:
1701
                if match.owner is item:
1702
                    match.owner = None
1703

    
1704
            matches = [_item for _item in self.graphicsView.scene.items() if hasattr(_item, 'attrs')]
1705
            #done = False
1706
            for match in matches:
1707
                for assoc in match.associations():
1708
                    if item is assoc:
1709
                        for attr in match.attrs.keys():
1710
                            if attr.AssocItem and str(item.uid) == str(attr.AssocItem.uid):
1711
                                attr.AssocItem = None
1712
                                match.attrs[attr] = ''
1713
                                #done = True
1714
                        match.remove_assoc_item(item)
1715
                        break
1716
                #if done: break
1717

    
1718
            # remove error item from inconsistency list
1719
            if type(item) is QEngineeringErrorItem:
1720
                for row in range(self.tableWidgetInconsistency.rowCount()):
1721
                    if item is self.tableWidgetInconsistency.item(row, 0).tag:
1722
                        self.tableWidgetInconsistency.removeRow(row)
1723
                        break
1724

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

    
1730
    '''
1731
        @brief      recognize line
1732
        @author     humkyung
1733
        @date       2018.04.19
1734
        @history    Jeongwoo 2018.04.26 Variable name changed (texts → lineNos)
1735
                                        TextItem type changed (QEngineeringTextItem → QEngineeringLineNoTextItem)
1736
                    humkyung 2018.04.26 remove small objects before recognizing line
1737
                    Jeongwoo 2018.05.02 Show MessageBox when imageviewer doesn't have image
1738
                    Jeongwoo 2018.05.25 Move codes about LineDetector
1739
                    humkyung 2018.06.17 show progress dialog
1740
    '''
1741
    def connect_attributes(self, MainWindow):
1742
        from LineNoTracer import LineNoTracer
1743
        from ConnectAttrDialog import QConnectAttrDialog
1744

    
1745
        if not self.graphicsView.hasImage():
1746
            self.showImageSelectionMessageBox()
1747
            return
1748

    
1749
        try:
1750
            self.dlgConnectAttr = QConnectAttrDialog(self, self.graphicsView)
1751
            self.dlgConnectAttr.exec_()
1752
            if self.dlgConnectAttr.isRunned:
1753
                self.itemTreeWidget.InitLineNoItems()
1754

    
1755
                # construct line no item
1756
                line_nos = AppDocData.instance().tracerLineNos
1757
                for line_no in line_nos:
1758
                    item = self.itemTreeWidget.addTreeItem(self.itemTreeWidget.root, line_no)
1759
                    connectedItems = line_no.getConnectedItems()
1760
                    for connectedItem in connectedItems:
1761
                        if issubclass(type(connectedItem), SymbolSvgItem): 
1762
                            self.itemTreeWidget.addTreeItem(item, connectedItem)
1763
                # up to here
1764

    
1765
                self.tableWidgetInconsistency.clearContents()
1766
                if self.dlgConnectAttr.ui.checkBoxValidation.isChecked():
1767
                    self.onValidation()
1768

    
1769
                self.graphicsView.invalidateScene()
1770
        except Exception as ex:
1771
            message = 'error occured({}) in {}:{}'.format(ex, sys.exc_info()[-1].tb_frame.f_code.co_filename, sys.exc_info()[-1].tb_lineno)
1772
            self.addMessage.emit(MessageType.Error, message)
1773

    
1774
    '''
1775
        @history    2018.05.25  Jeongwoo    Moved from MainWindow
1776
                                            SvgItem and TextItem Connect with method in this class
1777
                                            Change method to add GraphicsItem
1778
                    2018.05.28  Jeongwoo    Make QGraphicsItem by symbol, text object. Not xml
1779
                    2018.05.29  Jeongwoo    Change method name and Moved from QRecognitionDialog
1780
                    2018.05.30  Jeongwoo    Add parameters on SymbolSvgItem.__init__() (parentSymbol, childSymbol)
1781
                                            Change Method name and seperate each item
1782
                    humkyung 2018.06.11     display difference between original and recognized image
1783
                    Jeongwoo 2018.06.18     Update Scene after all item added
1784
                    2018.11.05  euisung     add save note item because of dependency
1785
                    2018.11.05  euisung     add db delete process before save
1786
                    2018.11.12  euisung     add title block properties
1787
                    2018.11.12  euisung     db part move new method to dbUpdate
1788
                    2018.11.26  euisung     isolate scene adding part -> drawDetectedItemsToScene()
1789
                    2018.11.29  euisung     change name drawDetectedItems() -> createDetectedItems
1790
    '''
1791
    def createDetectedItems(self, symbolList, textInfoList, otherTextInfoList, titleBlockTextInfoList):
1792
        try:
1793
            appDocData = AppDocData.instance()
1794

    
1795
            QApplication.processEvents()
1796
            self.createDetectedSymbolItem(symbolList)
1797
            QApplication.processEvents()
1798
            self.createDetectedTextItem(textInfoList)
1799
            QApplication.processEvents()
1800
            self.createDetectedOtherTextItem(otherTextInfoList)
1801
            QApplication.processEvents()
1802
            self.createDetectedTitleBlockTextItem(titleBlockTextInfoList)
1803

    
1804
            self.dbUpdate()
1805

    
1806
            # update scene
1807
            #self.graphicsView.scene.update(self.graphicsView.sceneRect())
1808
        except Exception as ex:
1809
            message = 'error occured({}) in {}:{}'.format(ex, sys.exc_info()[-1].tb_frame.f_code.co_filename, sys.exc_info()[-1].tb_lineno)
1810
            self.addMessage.emit(MessageType.Error, message)
1811

    
1812
    def drawDetectedItemsToScene(self):
1813
        '''
1814
            @brief  add detected items to scene
1815
            @author euisung
1816
            @date   2018.11.26
1817
        '''
1818
        appDocData = AppDocData.instance()
1819

    
1820
        try:
1821
            for symbol in appDocData.symbols:
1822
                if issubclass(type(symbol), SymbolSvgItem):
1823
                    self.addSvgItemToScene(symbol)
1824
                else:
1825
                    self.graphicsView.scene.addItem(symbol)
1826

    
1827
            for text in appDocData.texts:
1828
                self.addTextItemToScene(text)
1829

    
1830
            for lineNo in appDocData.tracerLineNos:
1831
                self.addTextItemToScene(lineNo)
1832

    
1833
            for line in appDocData.lines:
1834
                self.graphicsView.scene.addItem(line)
1835
                line.transfer.onRemoved.connect(self.itemRemoved)
1836
                for conn in line.connectors:
1837
                    conn.transfer.onPosChanged.connect(line.onConnectorPosChaned)
1838

    
1839
            for unknown in appDocData.unknowns + appDocData.lineIndicators:
1840
                self.graphicsView.scene.addItem(unknown)
1841
        finally:
1842
            # update scene
1843
            self.graphicsView.scene.update(self.graphicsView.sceneRect())
1844

    
1845
    def postDetectLineProcess(self):
1846
        '''
1847
            @brief  check allowables among undetected items
1848
            @author euisung
1849
            @date   2018.11.15
1850
            @history    2018.11.15  euisung    no more used, moved to TextItemFactoy isLineNo()
1851
        '''
1852
        from AppDocData import AppDocData
1853
        from TextItemFactory import TextItemFactory
1854

    
1855
        appDocData = AppDocData.instance()
1856

    
1857
        tableNames = ["Fluid Code", "Insulation Purpose", "PnID Number", "Piping Materials Class", "Unit Number"]
1858
        tableDatas = []
1859
        for tableName in tableNames:
1860
            tableNameFormat = tableName.replace(' ','').replace('&&', 'n')
1861
            tableDatas.append(appDocData.getCodeTable(tableNameFormat))
1862

    
1863
        items = self.graphicsView.scene.items()
1864
        for item in items:
1865
            if type(item) is not QEngineeringTextItem:
1866
                continue
1867
            text = item.text()
1868
            for tableData in tableDatas:
1869
                for data in tableData:
1870
                    if data[3] == '':
1871
                        continue
1872
                    else:
1873
                        allows = data[3].split(',')
1874
                        for allow in allows:
1875
                            text = text.replace(allow, data[1])
1876

    
1877
            lineItem = TextItemFactory.instance().createTextItem(text)
1878
            if type(lineItem) is QEngineeringLineNoTextItem:
1879
                lineItem.loc = item.loc
1880
                lineItem.size = item.size
1881
                lineItem.angle = item.angle
1882
                lineItem.area = item.area
1883
                #lineItem.addTextItemToScene(self.graphicsView.scene)
1884
                lineItem.transfer.onRemoved.connect(self.itemRemoved)
1885
                item.transfer.onRemoved.emit(item)
1886
                appDocData.lineNos.append(lineItem)
1887
                
1888
    def createDetectedTitleBlockTextItem(self, textInfoList):
1889
        '''
1890
            @brief  draw title block
1891
            @author euisung
1892
            @date   2018.11.12
1893
            @history    2018.11.26  euisung     remove scene dependency
1894
                        2018.11.29  euisung     change name drawDetectedTitleBlockTextItem() -> createDetectedTitleBlockTextItem
1895
        '''
1896
        from TextItemFactory import TextItemFactory
1897
        import math
1898

    
1899
        try:
1900
            appDocData = AppDocData.instance()
1901

    
1902
            # parse texts
1903
            for textInfo in textInfoList:
1904
                if len(textInfo[1]) is 0:
1905
                    continue
1906
                x = textInfo[1][0].getX()
1907
                y = textInfo[1][0].getY()
1908
                width = textInfo[1][0].getW()
1909
                height = textInfo[1][0].getH()
1910
                angle = round(math.radians(textInfo[1][0].getAngle()), 2)
1911
                text = textInfo[1][0].getText()
1912
                item = TextItemFactory.instance().createTextItem(textInfo)
1913

    
1914
                if item is not None:
1915
                    item.loc = [x, y]
1916
                    item.size = (width, height)
1917
                    item.angle = angle
1918
                    item.area = textInfo[0]
1919
                    #self.addTextItemToScene(item)
1920
                    #appDocData.texts.append(item)
1921
                    appDocData.allItems.append(item)
1922
        except Exception as ex:
1923
            message = 'error occured({}) in {}:{}'.format(ex, sys.exc_info()[-1].tb_frame.f_code.co_filename, sys.exc_info()[-1].tb_lineno)
1924
            self.addMessage.emit(MessageType.Error, message)
1925

    
1926
    '''
1927
        @brief      
1928
        @author     humkyung
1929
        @date       2018.08.23
1930
        @history    2018.11.26  euisung     remove scene dependency
1931
                    2018.11.26  euisung     isolate scene adding part -> drawDetectedItemsToScene()
1932
                    2018.11.    euisung     no more used
1933
                    2018.11.29  euisung     change name drawDetectedLines() -> createDetectedLines
1934
    '''
1935
    def createDetectedLines(self, lineList, worker):
1936
        appDocData = AppDocData.instance()
1937
        area = appDocData.getArea('Drawing')
1938

    
1939
        for pts in lineList:
1940
            processLine = QEngineeringLineItem(vertices=[(area.x + param[0], area.y + param[1]) for param in pts])
1941
            processLine.area = 'Drawing'
1942
            #self.graphicsView.scene.addItem(processLine)
1943
            appDocData.lines.append(processLine)
1944
            appDocData.allItems.append(processLine)
1945

    
1946
            #if processLine.length() > 100: # TODO: check critical length
1947
            #    processLine.addFlowArrow()
1948
        
1949
        # re-order process line's start,end according to flow mark
1950
        #worker.arrangeLinePosition(lines, symbols, listWidget)
1951
        # up to here
1952

    
1953
    '''
1954
        history     2018.06.09  humkyung    check length of original and connection point is 2 while parsing
1955
                    2018.11.26  euisung     remove scene dependency
1956
                    2018.11.29  euisung     change name drawDetectedSymbolItem() -> createDetectedSymbolItem
1957
    '''
1958
    def createDetectedSymbolItem(self, symbolList):
1959
        from GraphicsBoundingBoxItem import QGraphicsBoundingBoxItem
1960
        from SymbolSvgItem import SymbolSvgItem
1961
        import math
1962

    
1963
        try:
1964
            appDocData = AppDocData.instance()
1965
            project = appDocData.getCurrentProject()
1966

    
1967
            searchedMap = []
1968
            for symbol in symbolList:
1969
                pt = [float(x) for x in symbol.getSp()]
1970
                size = [symbol.getWidth(), symbol.getHeight()]
1971
                name = symbol.getName()
1972
                angle = round(math.radians(symbol.getRotatedAngle()), 2)
1973
                _type = symbol.getType()
1974
                flip = symbol.getDetectFlip()
1975
                origin = [0,0]
1976
                if 2 == len(symbol.getOriginalPoint().split(',')):
1977
                    tokens = symbol.getOriginalPoint().split(',')
1978
                    origin = [pt[0] + float(tokens[0]), pt[1] + float(tokens[1])]
1979
                connPts = []
1980
                if symbol.getConnectionPoint() is not None and symbol.getConnectionPoint() != '':
1981
                    for param in symbol.getConnectionPoint().split('/'):
1982
                        tokens = param.split(',')
1983
                        connPts.append(('AUTO', pt[0] + float(tokens[0]), pt[1] + float(tokens[1]), '0') if len(tokens) == 2 else \
1984
                                       (tokens[0], pt[0] + float(tokens[1]), pt[1] + float(tokens[2]), '0') if len(tokens) == 3 else \
1985
                                       (tokens[0], pt[0] + float(tokens[1]), pt[1] + float(tokens[2]), tokens[3]) if len(tokens) == 4 else None)
1986

    
1987
                parentSymbol = symbol.getBaseSymbol()
1988
                childSymbol = symbol.getAdditionalSymbol()
1989
                hasInstrumentLabel = symbol.getHasInstrumentLabel()
1990

    
1991
                svgFilePath = os.path.join(project.getSvgFilePath(), _type, name + '.svg')
1992
                if os.path.isfile(svgFilePath):
1993
                    svg = SymbolSvgItem.createItem(_type, svgFilePath, owner=None, flip=flip)
1994
                    #print(pt)
1995
                    #print(origin)
1996
                    svg.buildItem(name, _type, angle, pt, size, origin, connPts, parentSymbol, childSymbol, hasInstrumentLabel)
1997
                    svg.reCalculationRotatedItem()
1998
                    svg.area = 'Drawing'
1999

    
2000
                    # set owner - 2018.07.20 added by humkyung                   
2001
                    matches = [searched for searched in searchedMap if searched[0] == symbol.owner]
2002
                    if len(matches) == 1:
2003
                        svg.owner = matches[0][1]
2004
                    searchedMap.append((symbol, svg))
2005
                    # up to here
2006

    
2007
                    svg.transfer.onRemoved.connect(self.itemRemoved)
2008
                    #self.addSvgItemToScene(svg)
2009
                    appDocData.symbols.append(svg)
2010
                    appDocData.allItems.append(svg)
2011
                else:
2012
                    item = QGraphicsBoundingBoxItem(pt[0], pt[1], size[0], size[1])
2013
                    item.isSymbol = True
2014
                    item.angle = angle
2015
                    item.setPen(QPen(Qt.red, 5, Qt.SolidLine))
2016
                    #self.graphicsView.scene.addItem(item)
2017
                    #appDocData.symbols.append(item)
2018
                    appDocData.allItems.append(item)
2019
            # up to here
2020
        except Exception as ex:
2021
            message = 'error occured({}) in {}:{}'.format(ex, sys.exc_info()[-1].tb_frame.f_code.co_filename, sys.exc_info()[-1].tb_lineno)
2022
            self.addMessage.emit(MessageType.Error, message)
2023

    
2024
    '''
2025
        @history    2018.06.08  Jeongwoo    Add parameter on round method
2026
        @history    2018.11.02  euisung     Add save note text item
2027
        @history    2018.11.05  euisung     delete save note text item and move to drawDetectedItems()
2028
                    2018.11.26  euisung     remove scene dependency
2029
                    2018.11.29  euisung     change name drawDetectedTextItem() -> createDetectedTextItem
2030
    '''
2031
    def createDetectedTextItem(self, textInfoList):
2032
        from TextItemFactory import TextItemFactory
2033
        import math
2034

    
2035
        try:
2036
            appDocData = AppDocData.instance()
2037

    
2038
            # parse texts
2039
            for textInfo in textInfoList:
2040
                x = textInfo.getX()
2041
                y = textInfo.getY()
2042
                width = textInfo.getW()
2043
                height = textInfo.getH()
2044
                angle = round(math.radians(textInfo.getAngle()), 2)
2045
                text = textInfo.getText()
2046
                if not text: continue
2047

    
2048
                item = TextItemFactory.instance().createTextItem(textInfo)
2049
                if item is not None:
2050
                    item.loc = [x, y]
2051
                    item.size = (width, height)
2052
                    item.angle = angle
2053
                    item.area = 'Drawing'
2054
                    item.transfer.onRemoved.connect(self.itemRemoved)
2055
                    #self.addTextItemToScene(item)
2056
                    #appDocData.texts.append(item)
2057
                    appDocData.allItems.append(item)
2058
        except Exception as ex:
2059
            message = 'error occured({}) in {}:{}'.format(ex, sys.exc_info()[-1].tb_frame.f_code.co_filename, sys.exc_info()[-1].tb_lineno)
2060
            self.addMessage.emit(MessageType.Error, message)
2061

    
2062
    '''
2063
        @brief      draw detected texts except which in drawing area
2064
        @history    2018.11.29  euisung     change name drawDetectedOtherTextItem() -> createDetectedOtherTextItem
2065
    '''
2066
    def createDetectedOtherTextItem(self, otherTextInfoList):
2067
        from TextItemFactory import TextItemFactory
2068
        import math
2069

    
2070
        try:
2071
            appDocData = AppDocData.instance()
2072

    
2073
            # parse notes
2074
            for textInfoMap in otherTextInfoList:
2075
                if textInfoMap[0]=='Note' or textInfoMap[1] is None:
2076
                    pass
2077

    
2078
                for textInfo in textInfoMap[1]:
2079
                    x = textInfo.getX()
2080
                    y = textInfo.getY()
2081
                    width = textInfo.getW()
2082
                    height = textInfo.getH()
2083
                    angle = round(math.radians(textInfo.getAngle()))
2084
                    text = textInfo.getText()
2085

    
2086
                    item = TextItemFactory.instance().createTextItem(textInfo)
2087

    
2088
                    item.loc = [x, y]
2089
                    item.size = (width, height)
2090
                    item.angle = angle
2091
                    item.area = textInfoMap[0]
2092
                    item.transfer.onRemoved.connect(self.itemRemoved)
2093
                    #appDocData.texts.append(item)
2094
                    appDocData.allItems.append(item)
2095
        except Exception as ex:
2096
            message = 'error occured({}) in {}:{}'.format(ex, sys.exc_info()[-1].tb_frame.f_code.co_filename, sys.exc_info()[-1].tb_lineno)
2097
            self.addMessage.emit(MessageType.Error, message)
2098

    
2099
    '''
2100
        @brief  draw unknown items 
2101
        @author humkyung
2102
        @date   2018.06.12
2103
        @history    2018.06.14  Jeongwoo    Change method to add unknown item
2104
                    2018.06.18  Jeongwoo    Add connect on unknown item
2105
                                            Add [transfer] for using pyqtSignal
2106
                    2018.11.26  euisung     remove scene dependency
2107
                    2018.11.26  euisung     isolate scene adding part -> drawDetectedItemsToScene()
2108
                    2018.11.27  euisung     add save to xml
2109
                    2018.11.29  euisung     change name drawUnknownItems() -> createUnknownItems
2110
    '''
2111
    def createUnknownItems(self, path):
2112
        from QEngineeringFlowArrowItem import QEngineeringFlowArrowItem 
2113
        from EngineeringLineItem import QEngineeringLineItem
2114
        from EngineeringUnknownItem import QEngineeringUnknownItem
2115
        from SaveWorkCommand import SaveWorkCommand
2116

    
2117
        try:
2118
            docData = AppDocData.instance()
2119
            project = docData.getCurrentProject()
2120
            windowSize = docData.getSlidingWindowSize()
2121

    
2122
            thickness = int(windowSize[1])
2123

    
2124
            if docData.needReOpening is not None:
2125
                docData.needReOpening = True
2126

    
2127
            diffFilePath = os.path.join(project.getTempPath(), "DIFF_" + os.path.basename(path))
2128
            if os.path.isfile(diffFilePath):
2129
                imgDiff = cv2.threshold(cv2.cvtColor(cv2.imread(diffFilePath, 1), cv2.COLOR_BGR2GRAY), 127, 255, cv2.THRESH_BINARY)[1]
2130

    
2131
                ## remove line
2132
                lines = docData.lines
2133
                for line in lines:
2134
                    line.drawToImage(imgDiff, 255, thickness) if line.thickness is None else line.drawToImage(imgDiff, 255, line.thickness)
2135
                cv2.imwrite(diffFilePath, imgDiff)
2136
                ## up to here
2137

    
2138
                imgNot = np.ones(imgDiff.shape, np.uint8)
2139
                cv2.bitwise_not(imgDiff, imgNot)
2140
                imgNot = cv2.dilate(imgNot, np.ones((8,8), np.uint8))
2141

    
2142
                contours, hierarchy = cv2.findContours(imgNot, cv2.RETR_EXTERNAL, cv2.CHAIN_APPROX_SIMPLE)
2143

    
2144
                ##
2145
                idx = 0
2146
                ##
2147
                smallContours = []
2148
                minimumSize = docData.getConfigs('Filter', 'MinimumSize')
2149
                for contour in contours:
2150
                    [x, y, w, h] = cv2.boundingRect(contour)
2151

    
2152
                    # remove too small one
2153
                    if len(minimumSize) is 1:
2154
                        if (w * h < int(minimumSize[0].value) * int(minimumSize[0].value)):
2155
                            smallContours.append(contour)
2156
                            idx += 1
2157
                            continue
2158

    
2159
                    '''
2160
                    rect = QRectF(x, y, w, h)
2161
                    items = [item for item in diffItems if item.boundingRect().contains(rect)]
2162
                    if len(items) > 0: continue
2163
                    
2164
                    items = [item for item in diffItems if rect.contains(item.boundingRect())]
2165
                    for item in items:
2166
                        diffItems.remove(item)
2167
                    '''
2168

    
2169
                    # create unknown item
2170
                    epsilon = cv2.arcLength(contour, True)*0.001
2171
                    approx = cv2.approxPolyDP(contour, epsilon, True)
2172
                    approx = [pt[0] for pt in approx]
2173
                    resultStr, resultList = self.determineRemainObject(idx, contours, imgNot)
2174
                    if resultStr == 'LineIndicator':
2175
                        item = QEngineeringUnknownItem(approx, 'True', resultList[0], resultList[1])
2176
                        docData.lineIndicators.append(item)
2177
                    elif resultStr == 'MissingLine':
2178
                        pass
2179
                    elif resultStr == 'Unknown':
2180
                        item = QEngineeringUnknownItem(approx, 'False')
2181
                        docData.unknowns.append(item)
2182
                    item.area = 'Drawing'
2183
                    docData.allItems.append(item)
2184
                    item.transfer.onRemoved.connect(self.itemRemoved)
2185
                    idx += 1
2186
                    # up to here                    
2187

    
2188
                imgNotRemoveSmall = cv2.drawContours(imgNot, smallContours, -1, 0, -1)
2189
                notFilePath = os.path.join(project.getTempPath(), "NOT_" + os.path.basename(path))
2190
                cv2.imwrite(notFilePath, imgNotRemoveSmall)
2191
            else:
2192
                message = 'can\'t found {}'.format(diffFilePath)
2193
                self.addMessage.emit(MessageType.Normal, message)
2194

    
2195
            SaveWorkCommand.save_to_xml()
2196
        except Exception as ex:
2197
            message = 'error occured({}) in {}:{}'.format(ex, sys.exc_info()[-1].tb_frame.f_code.co_filename, sys.exc_info()[-1].tb_lineno)
2198
            self.addMessage.emit(MessageType.Error, message)
2199

    
2200
    def determineRemainObject(self, idx, contours, imgNot):
2201
        '''
2202
            @brief      determine remain objects -> line no indicator or unknown
2203
            @author     euisung
2204
            @date       2018.12.26
2205
            @history    2019.03.25  euisung    Change name isLineNoIndicator -> determineRemainObject
2206
        '''
2207
        import math
2208
        [x, y, w, h] = cv2.boundingRect(contours[idx])
2209
        
2210
        if (w < 250 and h < 250):
2211
            return ('Unknown', [])
2212
        
2213
        fLines = []
2214
        maxDifAngle = 3
2215
        mask = np.zeros_like(imgNot)
2216
        cv2.drawContours(mask, contours, idx, 123, -1) # Draw filled contour in mask
2217
        out = np.zeros_like(imgNot) # Extract out the object and place into output image
2218
        out[mask == 123] = imgNot[mask == 123]
2219

    
2220
        # Now crop
2221
        ##print(out)
2222
        (x, y) = np.where(mask == 123)
2223
        (topx, topy) = (np.min(x), np.min(y))
2224
        (bottomx, bottomy) = (np.max(x), np.max(y))
2225
        out = out[topx:bottomx+1, topy:bottomy+1]
2226
        h, w = out.shape[0], out.shape[1]
2227
        maxDifH, maxDifW = math.ceil(math.tan(4 * math.pi / 180) / 2 * w), math.ceil(math.tan(4 * math.pi / 180) / 2 * h)
2228

    
2229
        # detection lines
2230
        edged2 = cv2.Canny(out, 100, 200)
2231
        lines = cv2.HoughLinesP(image=edged2, rho=1, theta=np.pi/180, threshold=25, minLineLength=30, maxLineGap=25)
2232
        #lines = cv2.HoughLines(edged2, 1, np.pi/180, 60)
2233
        if lines is None:
2234
            return ('Unknown', [])
2235
        for line in lines:
2236
            #r, theta = line[0]
2237
            #a, b = np.cos(theta), np.sin(theta)
2238
            #x0, y0 = a * r, b * r
2239
            #x1, y1 = int(x0 + 1000 * (-b)), int(y0 + 1000 * a)
2240
            #x2, y2 = int(x0 - 1000 * (-b)), int(y0 - 1000 * a)
2241
            #cv2.line(out, (x1, y1), (x2, y2), (0, 255, 0), 3)
2242
            x1, y1, x2, y2 = line[0]
2243
            degree = math.atan2(y2 - y1, x2 - x1) * 180 / math.pi
2244
            fLine = [x1, y1, x2, y2, degree]
2245
            #print(fLine)
2246
            fLines.append(fLine)
2247
        
2248
        horLines = []
2249
        verLines = []
2250
        otherLines = []
2251
        isVH = None
2252
        for fLine in fLines:
2253
            degree = math.fabs(fLine[4])
2254
            if degree >= 90 - maxDifAngle:
2255
                verLines.append(fLine)
2256
            elif degree <= maxDifAngle:
2257
                horLines.append(fLine)
2258
            else:
2259
                otherLines.append(fLine)
2260

    
2261
        baseLines = []
2262
        baseDifV = 0
2263
        if len(horLines):
2264
            x, y = w / 2, 0
2265
            baseDifV = maxDifH
2266
            for horLine in horLines:
2267
                x1, y1, x2, y2 = horLine[0], horLine[1], horLine[2], horLine[3]
2268
                y = ((y2-y1)/(x2-x1))*x + y1 - ((y2-y1)/(x2-x1))*x1
2269
                horLine.append(y)
2270
            baseLines = horLines
2271
            isVH = 'H'
2272
        if len(verLines):
2273
            x, y = 0, h / 2
2274
            baseDifV = maxDifW
2275
            for verLine in verLines:
2276
                x1, y1, x2, y2 = verLine[0], verLine[1], verLine[2], verLine[3]
2277
                x = ((x2-x1)/(y2-y1))*y + x1 - ((x2-x1)/(y2-y1))*y1
2278
                verLine.append(x)
2279
            baseLines = verLines
2280
            isVH = 'V'
2281

    
2282
        for otherLine in otherLines:
2283
            x, y = w / 2, 0
2284
            x1, y1, x2, y2 = otherLine[0], otherLine[1], otherLine[2], otherLine[3]
2285
            y = ((y2-y1)/(x2-x1))*x + y1 - ((y2-y1)/(x2-x1))*x1
2286
            otherLine.append(y)
2287

    
2288
        # determine line no indicator 
2289
        if not ((len(horLines) > 0 and len(verLines) > 0) or len(otherLines) is 0 or (len(horLines) == 0 and len(verLines) == 0)):    
2290
            result, mergedOtherLine = self.isLineNoIndicator(w, h, maxDifAngle, baseDifV, baseLines, otherLines)
2291
            if result:
2292
                #print(fLines)
2293
                return ('LineIndicator', [isVH, mergedOtherLine])
2294

    
2295
        return ('Unknown', [])
2296

    
2297
    def isLineNoIndicator(self, w, h, maxDifAngle, baseDifV, baseLines, otherLines):
2298
        '''
2299
            @brief      determine line no indicator
2300
            @author     euisung
2301
            @date       2019.03.25
2302
        '''
2303
        import math
2304

    
2305
        if (w < 250 and h < 250):
2306
            return (False, None)
2307

    
2308
        isSameLine = True
2309
        i = 0
2310
        for baseLine in baseLines:
2311
            if not isSameLine: break
2312
            j = 0
2313
            for baseLinee in baseLines:
2314
                if i == j:
2315
                    j += 1
2316
                    continue
2317
                difV = math.fabs(baseLine[5] - baseLinee[5])
2318
                if difV > baseDifV:
2319
                   isSameLine = False
2320
                   break
2321
                j += 1
2322
            i += 1
2323
        if not isSameLine:
2324
            return (False, None)
2325

    
2326
        isSameLine = True
2327
        i = 0
2328
        maxY = 0
2329
        for otherLine in otherLines:
2330
            y = otherLine[5]
2331
            if math.fabs(y) > maxY:
2332
                maxY = math.fabs(y)
2333
            if not isSameLine: break
2334
            j = 0
2335
            for otherLinee in otherLines:
2336
                if i == j:
2337
                    j += 1
2338
                    continue
2339
                difV = math.fabs(otherLine[4] - otherLinee[4])
2340
                if difV > maxDifAngle:
2341
                   isSameLine = False
2342
                   break
2343
                j += 1
2344
            i += 1
2345
        if not isSameLine:
2346
            return (False, None)
2347
                
2348
        isSameLine = True
2349
        mergedOtherLine = [0, 0, 0, 0]
2350
        i = 0
2351
        maxDif = math.ceil(math.tan(4 * math.pi / 180) * maxY)
2352
        for otherLine in otherLines:
2353
            if not isSameLine: break
2354
            j = 0
2355
            for otherLinee in otherLines:
2356
                if i == j:
2357
                    j += 1
2358
                    continue
2359
                angle = math.fabs(otherLine[4] + otherLinee[4]) / 2
2360
                difV = math.fabs(otherLine[5] - otherLinee[5])
2361
                dist = math.sin((90 - angle) * math.pi / 180) * difV 
2362
                if dist > maxDif:
2363
                   isSameLine = False
2364
                   break
2365
                j += 1
2366
            i += 1
2367
            mergedOtherLine[0] += otherLine[0]
2368
            mergedOtherLine[1] += otherLine[1]
2369
            mergedOtherLine[2] += otherLine[2]
2370
            mergedOtherLine[3] += otherLine[3]
2371
        if not isSameLine:
2372
            (False, None)
2373
                        
2374
        # Show the output image
2375
        #print('line no indicator')
2376
        mergedOtherLine[0] = round(mergedOtherLine[0] / len(otherLines))
2377
        mergedOtherLine[1] = round(mergedOtherLine[1] / len(otherLines))
2378
        mergedOtherLine[2] = round(mergedOtherLine[2] / len(otherLines))
2379
        mergedOtherLine[3] = round(mergedOtherLine[3] / len(otherLines))
2380
        #cv2.line(out, (mergedOtherLine[0], mergedOtherLine[1]), (mergedOtherLine[2], mergedOtherLine[3]), (255, 255, 255), 3)
2381
        #cv2.imshow('Output', out)
2382
        #cv2.waitKey(0)
2383
        #cv2.destroyAllWindows()
2384
        return (True, mergedOtherLine)
2385

    
2386
    def load_drawing(self, drawing):
2387
        """ load drawing """
2388
        from EngineeringRunItem import QEngineeringRunItem
2389
        from QEngineeringTrimLineNoTextItem import QEngineeringTrimLineNoTextItem
2390

    
2391
        app_doc_data = AppDocData.instance()
2392
        try:
2393
            symbols = []
2394
            lines = []
2395

    
2396
            components = app_doc_data.get_components(drawing.UID)
2397
            maxValue = len(components)
2398
            self.progress.setMaximum(maxValue)
2399

    
2400
            """ parsing all symbols """
2401
            for symbol in [component for component in components if int(component['SymbolType_UID']) != -1]:
2402
                item = SymbolSvgItem.from_database(symbol)
2403
                if item is not None:
2404
                    item.transfer.onRemoved.connect(self.itemRemoved)
2405
                    symbols.append(item)
2406
                    app_doc_data.symbols.append(item)
2407
                    self.addSvgItemToScene(item)
2408
                else:
2409
                    pt = [float(symbol['X']), float(symbol['Y'])]
2410
                    size = [float(symbol['Width']), float(symbol['Height'])]
2411
                    angle = float(symbol['Rotation'])
2412
                    item = QGraphicsBoundingBoxItem(pt[0], pt[1], size[0], size[1])
2413
                    item.isSymbol = True
2414
                    item.angle = angle
2415
                    item.setPen(QPen(Qt.red, 5, Qt.SolidLine))
2416
                    self.graphicsView.scene.addItem(item)
2417
                    item.transfer.onRemoved.connect(self.itemRemoved)
2418

    
2419
                self.progress.setValue(self.progress.value() + 1)
2420
                
2421
            QApplication.processEvents()
2422

    
2423
            # parse texts
2424
            for text in [component for component in components if component['Name'] == 'Text' and component['SymbolType_UID'] == -1]:
2425
                item = QEngineeringTextItem.from_database(text)
2426
                if item is not None:
2427
                    item.uid = text['UID']
2428
                    item.attribute = text['Value']
2429
                    name = text['Name']
2430
                    item.transfer.onRemoved.connect(self.itemRemoved)
2431
                    self.addTextItemToScene(item)
2432

    
2433
                self.progress.setValue(self.progress.value() + 1)
2434
                
2435
            QApplication.processEvents()
2436

    
2437
            # note
2438
            for note in [component for component in components if component['Name'] == 'Note' and component['SymbolType_UID'] == -1]:
2439
                item = QEngineeringTextItem.from_database(note)
2440
                if item is not None:
2441
                    item.uid = note['UID']
2442
                    attributeValue = note['Value']
2443
                    name = note['Name']
2444
                    item.transfer.onRemoved.connect(self.itemRemoved)
2445
                    self.addTextItemToScene(item)
2446

    
2447
                self.progress.setValue(self.progress.value() + 1)
2448
                
2449
            QApplication.processEvents()
2450

    
2451
            for line in [component for component in components if component['Name'] == 'Line' and component['SymbolType_UID'] == -1]:
2452
                item = QEngineeringLineItem.from_database(line)
2453
                if item:
2454
                    item.transfer.onRemoved.connect(self.itemRemoved)
2455
                    self.graphicsView.scene.addItem(item)
2456
                    lines.append(item)
2457

    
2458
                self.progress.setValue(self.progress.value() + 1)
2459
                
2460
            QApplication.processEvents()
2461

    
2462
            for unknown in [component for component in components if component['Name'] == 'Unknown' and component['SymbolType_UID'] == -1]:
2463
                item = QEngineeringUnknownItem.from_database(unknown)
2464
                item.transfer.onRemoved.connect(self.itemRemoved)
2465
                if item is not None:
2466
                    item.transfer.onRemoved.connect(self.itemRemoved)
2467
                    self.graphicsView.scene.addItem(item)
2468

    
2469
                self.progress.setValue(self.progress.value() + 1)
2470
                
2471
            QApplication.processEvents()
2472

    
2473
            for component in [component for component in components if component['Name'] == 'Line NO' and component['SymbolType_UID'] == -1]:
2474
                line_no = QEngineeringLineNoTextItem.from_database(component)
2475
                if type(line_no) is QEngineeringLineNoTextItem:
2476
                    line_no.transfer.onRemoved.connect(self.itemRemoved)
2477
                    self.addTextItemToScene(line_no)
2478
                    line_no_tree_item = self.itemTreeWidget.addTreeItem(self.itemTreeWidget.root, line_no)
2479

    
2480
                    runs = app_doc_data.get_pipe_runs(str(line_no.uid))
2481
                    if not runs: continue
2482
                    for run in runs:
2483
                        line_run = QEngineeringRunItem()
2484
                        run_items = app_doc_data.get_pipe_run_items(run['UID'])
2485
                        for record in run_items:
2486
                            uid = record['Components_UID']
2487
                            run_item = self.graphicsView.findItemByUid(uid)
2488
                            if run_item is not None:
2489
                                run_item._owner = line_no
2490
                                line_run.items.append(run_item)
2491
                        line_run.owner = line_no
2492
                        line_no.runs.append(line_run)
2493

    
2494
                        for run_item in line_run.items:
2495
                            if issubclass(type(run_item), SymbolSvgItem): self.itemTreeWidget.addTreeItem(line_no_tree_item, run_item)
2496

    
2497
                self.progress.setValue(self.progress.value() + 1)
2498
            QApplication.processEvents()
2499

    
2500
            for component in [component for component in components if component['Name'] == 'Trim Line NO' and component['SymbolType_UID'] == -1]:
2501
                line_no = QEngineeringTrimLineNoTextItem()
2502
                line_no.uid = uuid.UUID(component['UID'])
2503

    
2504
                runs = app_doc_data.get_pipe_runs(str(line_no.uid))
2505
                if not runs: continue
2506
                for run in runs:
2507
                    line_run = QEngineeringRunItem()
2508
                    run_items = app_doc_data.get_pipe_run_items(run['UID'])
2509
                    for record in run_items:
2510
                        uid = record['Components_UID']
2511
                        run_item = self.graphicsView.findItemByUid(uid)
2512
                        if run_item is not None:
2513
                            run_item.owner = line_no
2514
                            line_run.items.append(run_item)
2515
                line_no.runs.append(line_run)
2516
                line_no_tree_item = self.itemTreeWidget.addTreeItem(self.itemTreeWidget.root, line_no)
2517
                
2518
                for run_item in line_run.items:
2519
                    if issubclass(type(run_item), SymbolSvgItem): self.itemTreeWidget.addTreeItem(line_no_tree_item, run_item)
2520

    
2521
                app_doc_data.tracerLineNos.append(line_no)
2522

    
2523
                self.progress.setValue(self.progress.value() + 1)
2524

    
2525
            for component in [component for component in components if component['Name'] == 'VendorPackage' and component['SymbolType_UID'] == -1]:
2526
                item = QEngineeringVendorItem.from_database(component)
2527
                item.transfer.onRemoved.connect(self.itemRemoved)
2528
                self.graphicsView.scene.addItem(item)
2529

    
2530
            # connect flow item to line
2531
            for line in lines:
2532
                line.update_arrow()
2533
            #for flowMark in [item for item in symbols if type(item) is QEngineeringFlowMarkItem]:
2534
            #    for line in lines:
2535
            #        if flowMark.owner is line:
2536
            #            line._flowMark.append(flowMark)
2537
            #            flowMark.setParentItem(line)
2538
            # up to here
2539

    
2540
            """ update scene """
2541
            self.graphicsView.scene.update(self.graphicsView.sceneRect())
2542
            for item in self.graphicsView.scene.items():
2543
                item.setVisible(True)
2544
                
2545
                # binding items
2546
                if hasattr(item, 'owner'):
2547
                    item.owner
2548
                if hasattr(item, 'connectors'):
2549
                    for connector in item.connectors:
2550
                        connector.connectedItem
2551

    
2552
        except Exception as ex:
2553
            message = 'error occured({}) in {}:{}'.format(ex, sys.exc_info()[-1].tb_frame.f_code.co_filename, sys.exc_info()[-1].tb_lineno)
2554
            self.addMessage.emit(MessageType.Error, message)
2555
        finally:
2556
            app_doc_data.clearTempDBData
2557
            #self.graphicsView.scene.blockSignals(False)
2558

    
2559
    '''
2560
        @brief      load recognition result
2561
        @author     humkyung
2562
        @date       2018.04.??
2563
        @history    humkyung 2018.01.12 parse originalpoint and connectionpoint
2564
                    Jeongwoo 2018.04.17 add QGraphicItem with Rotated text
2565
                    Jeongwoo 2018.04.23 Change to Draw texts on QEngineeringTextItem
2566
                    humkyung 2018.04.23 connect item remove slot to result tree
2567
                    Jeongwoo 2018.04.25 Add if state with QEngineeringNoteItem
2568
                    Jeongwoo 2018.04.26 Change method to create TextItem object with TextItemFactory
2569
                    Jeongwoo 2018.05.03 Change method to draw Svg Item on Scene (svg.addSvgItemToScene)
2570
                    Jeongwoo 2018.05.29 Change method name / Change method to add item / Add Line item
2571
                    Jeongwoo 2018.05.30 Add parameters on SymbolSvgItem.__init__() (parentSymbol, childSymbol) / Change method name / Change XML NODE NAMES
2572
                    Jeongwoo 2018.06.12 Add LineNoTextItem from LINE_NO
2573
                    Jeongwoo 2018.06.14 Add UnknownItem from UNKNOWN
2574
                    Jeongwoo 2018.06.18 Update Scene after all item added
2575
                                        Add connect on unknown item
2576
                                        Add [transfer] for using pyqtSignal
2577
                    kyouho  2018.07.12  Add line property logic
2578
                    humkyung 2018.08.22 show progress while loading xml file
2579
                    2018.11.22      euisung     fix note road
2580
    '''
2581
    def loadRecognitionResultFromXml(self, xmlPath):
2582
        docData = AppDocData.instance()
2583
        from xml.etree.ElementTree import Element, SubElement, dump, ElementTree, parse
2584
        from EngineeringRunItem import QEngineeringRunItem
2585
        from QEngineeringTrimLineNoTextItem import QEngineeringTrimLineNoTextItem
2586

    
2587
        try:
2588
            #self.graphicsView.scene.blockSignals(True)
2589

    
2590
            symbols = []
2591
            lines = []
2592

    
2593
            xml = parse(xmlPath)
2594
            root = xml.getroot()
2595
            
2596
            maxValue = 0
2597
            maxValue = maxValue + len(list(root.iter('SYMBOL'))) - len(list(root.iterfind('LINENOS/LINE_NO/RUN/SYMBOL'))) - len(list(root.iterfind('TRIMLINENOS/TRIM_LINE_NO/RUN/SYMBOL')))
2598
            maxValue = maxValue + len(list(root.iterfind('TEXTINFOS/ATTRIBUTE')))
2599
            maxValue = maxValue + len(list(root.iterfind('NOTES/ATTRIBUTE')))
2600
            maxValue = maxValue + len(list(root.iter('LINE_NO')))
2601
            maxValue = maxValue + len(list(root.iter('LINE'))) - len(list(root.iterfind('LINENOS/LINE_NO/RUN/LINE'))) - len(list(root.iterfind('TRIMLINENOS/TRIM_LINE_NO/RUN/LINE')))
2602
            maxValue = maxValue + len(list(root.iter('UNKNOWN')))
2603
            #maxValue = maxValue + len(list(root.iter('SIZETEXT')))
2604
            maxValue = maxValue + len(list(root.iter('TRIM_LINE_NO')))
2605
            self.progress.setMaximum(maxValue)
2606

    
2607
            """ parsing all symbols """
2608
            for symbol in root.find('SYMBOLS').iter('SYMBOL'):
2609
                item = SymbolSvgItem.fromXml(symbol)
2610
                if item is not None:
2611
                    item.transfer.onRemoved.connect(self.itemRemoved)
2612
                    symbols.append(item)
2613
                    docData.symbols.append(item)
2614
                    self.addSvgItemToScene(item)
2615
                else:
2616
                    pt = [float(x) for x in symbol.find('LOCATION').text.split(',')]
2617
                    size = [float(x) for x in symbol.find('SIZE').text.split(',')]
2618
                    angle = float(symbol.find('ANGLE').text)
2619
                    item = QGraphicsBoundingBoxItem(pt[0], pt[1], size[0], size[1])
2620
                    item.isSymbol = True
2621
                    item.angle = angle
2622
                    item.setPen(QPen(Qt.red, 5, Qt.SolidLine))
2623
                    self.graphicsView.scene.addItem(item)
2624
                    item.transfer.onRemoved.connect(self.itemRemoved)
2625

    
2626
                self.progress.setValue(self.progress.value() + 1)
2627
                
2628
            QApplication.processEvents()
2629

    
2630
            # parse texts
2631
            for text in root.find('TEXTINFOS').iter('ATTRIBUTE'):
2632
                item = QEngineeringTextItem.fromXml(text)
2633
                if item is not None:
2634
                    uid = text.find('UID')
2635
                    attributeValue = text.find('ATTRIBUTEVALUE')
2636
                    name = text.find('NAME').text
2637
                    item.transfer.onRemoved.connect(self.itemRemoved)
2638
                    self.addTextItemToScene(item)
2639
                    #docData.texts.append(item)
2640

    
2641
                    if name == 'TEXT':
2642
                        if uid is not None and attributeValue is not None:
2643
                            item.uid = uid.text
2644
                            item.attribute = attributeValue.text
2645

    
2646
                self.progress.setValue(self.progress.value() + 1)
2647
                
2648
            QApplication.processEvents()
2649

    
2650
            # note
2651
            for text in root.find('NOTES').iter('ATTRIBUTE'):
2652
                item = QEngineeringTextItem.fromXml(text)
2653
                if item is not None:
2654
                    uid = text.find('UID')
2655
                    attributeValue = text.find('ATTRIBUTEVALUE')
2656
                    name = text.find('NAME').text
2657
                    item.transfer.onRemoved.connect(self.itemRemoved)
2658
                    self.addTextItemToScene(item)
2659

    
2660
                    if name == 'NOTE':
2661
                        if uid is not None:
2662
                            item.uid = uid.text
2663

    
2664
                self.progress.setValue(self.progress.value() + 1)
2665
                
2666
            QApplication.processEvents()
2667

    
2668
            for line in root.find('LINEINFOS').iter('LINE'):
2669
                item = QEngineeringLineItem.fromXml(line)
2670
                if item:
2671
                    item.transfer.onRemoved.connect(self.itemRemoved)
2672
                    self.graphicsView.scene.addItem(item)
2673
                    lines.append(item)
2674

    
2675
                self.progress.setValue(self.progress.value() + 1)
2676
                
2677
            QApplication.processEvents()
2678

    
2679
            for unknown in root.iter('UNKNOWN'):
2680
                item = QEngineeringUnknownItem.fromXml(unknown)
2681
                item.transfer.onRemoved.connect(self.itemRemoved)
2682
                if item is not None:
2683
                    item.transfer.onRemoved.connect(self.itemRemoved)
2684
                    self.graphicsView.scene.addItem(item)
2685

    
2686
                self.progress.setValue(self.progress.value() + 1)
2687
                
2688
            QApplication.processEvents()
2689

    
2690
            #""" add tree widget """
2691
            #for item in symbols:
2692
            #    docData.symbols.append(item)
2693
            #    self.addSvgItemToScene(item)
2694
            #    self.itemTreeWidget.addTreeItem(self.itemTreeWidget.root, item)
2695

    
2696
            for line_no_node in root.find('LINENOS').iter('LINE_NO'):
2697
                line_no = QEngineeringLineNoTextItem.fromXml(line_no_node)
2698
                if line_no is None: continue
2699
                line_no.transfer.onRemoved.connect(self.itemRemoved)
2700
                self.addTextItemToScene(line_no)
2701
                line_no_tree_item = self.itemTreeWidget.addTreeItem(self.itemTreeWidget.root, line_no)
2702
                if type(line_no) is not QEngineeringLineNoTextItem: continue
2703

    
2704
                runs_node = line_no_node.findall('RUN')
2705
                if runs_node is None: continue
2706

    
2707
                for run_node in runs_node:
2708
                    line_run = QEngineeringRunItem()
2709
                    for child_node in run_node:
2710
                        uidElement = child_node.find('UID')
2711
                        if uidElement is not None:
2712
                            uid = uidElement.text
2713
                            run_item = self.graphicsView.findItemByUid(uid)
2714
                            if run_item is not None:
2715
                                run_item._owner = line_no
2716
                                line_run.items.append(run_item)
2717
                    line_run.owner = line_no
2718
                    line_no.runs.append(line_run)
2719

    
2720
                    for run_item in line_run.items:
2721
                        if issubclass(type(run_item), SymbolSvgItem): self.itemTreeWidget.addTreeItem(line_no_tree_item, run_item)
2722

    
2723
                #docData.tracerLineNos.append(line_no)
2724

    
2725
                self.progress.setValue(self.progress.value() + 1)
2726
            QApplication.processEvents()
2727

    
2728
            for trimLineNo in root.iter('TRIM_LINE_NO'):
2729
                line_no = QEngineeringTrimLineNoTextItem()
2730
                line_no.uid = uuid.UUID(trimLineNo.find('UID').text)
2731

    
2732
                run = trimLineNo.find('RUN')
2733
                if run is not None:
2734
                    line_run = QEngineeringRunItem()
2735
                    for child in run:
2736
                        uidElement = child.find('UID')
2737
                        if uidElement is not None:
2738
                            uid = uidElement.text
2739
                            run_item = self.graphicsView.findItemByUid(uid)
2740
                            if run_item is not None:
2741
                                run_item.owner = line_no
2742
                                line_run.items.append(run_item)
2743
                    line_no.runs.append(line_run)
2744
                    line_no_tree_item = self.itemTreeWidget.addTreeItem(self.itemTreeWidget.root, line_no)
2745
                    
2746
                    for run_item in line_run.items:
2747
                        if issubclass(type(run_item), SymbolSvgItem): self.itemTreeWidget.addTreeItem(line_no_tree_item, run_item)
2748

    
2749
                    docData.tracerLineNos.append(line_no)
2750

    
2751
                self.progress.setValue(self.progress.value() + 1)
2752
            QApplication.processEvents()
2753

    
2754
            if root.find('VENDORS') is not None:
2755
                for vendor in root.find('VENDORS').iter('VENDOR'):
2756
                    item = QEngineeringVendorItem.fromXml(vendor)
2757
                    item.transfer.onRemoved.connect(self.itemRemoved)
2758
                    self.graphicsView.scene.addItem(item)
2759

    
2760
            # connect flow item to line
2761
            for line in lines:
2762
                line.update_arrow()
2763
            #for flowMark in [item for item in symbols if type(item) is QEngineeringFlowMarkItem]:
2764
            #    for line in lines:
2765
            #        if flowMark.owner is line:
2766
            #            line._flowMark.append(flowMark)
2767
            #            flowMark.setParentItem(line)
2768
            # up to here
2769

    
2770
            """ update scene """
2771
            self.graphicsView.scene.update(self.graphicsView.sceneRect())
2772
            for item in self.graphicsView.scene.items():
2773
                item.setVisible(True)
2774
                
2775
                # binding items
2776
                if hasattr(item, 'owner'):
2777
                    item.owner
2778
                if hasattr(item, 'connectors'):
2779
                    for connector in item.connectors:
2780
                        connector.connectedItem
2781

    
2782
        except Exception as ex:
2783
            message = 'error occured({}) in {}:{}'.format(ex, sys.exc_info()[-1].tb_frame.f_code.co_filename, sys.exc_info()[-1].tb_lineno)
2784
            self.addMessage.emit(MessageType.Error, message)
2785
        finally:
2786
            pass
2787
            #self.graphicsView.scene.blockSignals(False)
2788

    
2789
    '''
2790
        @brief      Remove added item on same place and Add GraphicsItem
2791
        @author     Jeongwoo
2792
        @date       2018.05.25
2793
        @history    2018.05.29  Jeongwoo    Moved from QRecognitionDialog
2794
                    2018.06.18  Jeongwoo    Set Z-index
2795
    '''
2796
    def addSvgItemToScene(self, svgItem):
2797
        svgItem.addSvgItemToScene(self.graphicsView.scene)
2798
        
2799
    '''
2800
        @brief      Remove added item on same place and Add GraphicsItem
2801
        @author     Jeongwoo
2802
        @date       2018.05.25
2803
        @history    2018.05.29  Jeongwoo    Moved from QRecognitionDialog
2804
                    2018.06.05  Jeongwoo    Remove Size condition
2805
                    2018.06.18  Jeongwoo    Set Z-index
2806
    '''
2807
    def addTextItemToScene(self, textItem):
2808
        textItem.addTextItemToScene(self.graphicsView.scene)
2809
        
2810
    '''
2811
        @brief      Remove added item on same place and Add GraphicsItem
2812
        @author     Jeongwoo
2813
        @date       2018.05.29
2814
        @history    2018.06.18  Jeongwoo    Set Z-index
2815
    '''
2816
    def addLineItemToScene(self, lineItem):
2817
        self.graphicsView.scene.addItem(lineItem)
2818

    
2819
    '''
2820
        @brief      generate output xml file
2821
        @author     humkyung
2822
        @date       2018.04.23
2823
        @history    2018.05.02  Jeongwoo    Show MessageBox when imageviewer doesn't have image
2824
    '''
2825
    def generateOutput(self):
2826
        import XmlGenerator as xg
2827

    
2828
        if not self.graphicsView.hasImage():
2829
            self.showImageSelectionMessageBox()
2830
            return
2831

    
2832
        try:
2833
            appDocData = AppDocData.instance()
2834

    
2835
            ## collect items
2836
            appDocData.lines.clear()
2837
            appDocData.lines = [item for item in self.graphicsView.scene.items() if type(item) is QEngineeringLineItem and item.owner is None]
2838

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

    
2842
            appDocData.equipments.clear()
2843
            for item in self.graphicsView.scene.items():
2844
                if type(item) is QEngineeringEquipmentItem:
2845
                    appDocData.equipments.append(item)
2846

    
2847
            appDocData.texts.clear()
2848
            appDocData.texts = [item for item in self.graphicsView.scene.items() if issubclass(type(item), QEngineeringTextItem) and type(item) is not QEngineeringLineNoTextItem]
2849
            ## up to here
2850

    
2851
            appDocData.imgOutput = np.ones((appDocData.activeDrawing.height, appDocData.activeDrawing.width), np.uint8)*255
2852
            xg.writeOutputXml(appDocData.imgName, appDocData.activeDrawing.width, appDocData.activeDrawing.height) # TODO: check
2853
            project = appDocData.getCurrentProject()
2854
            cv2.imwrite(os.path.join(project.getTempPath() , 'OUTPUT.png') , appDocData.imgOutput)
2855
        except Exception as ex:
2856
            message = 'error occured({}) in {}:{}'.format(ex, sys.exc_info()[-1].tb_frame.f_code.co_filename, sys.exc_info()[-1].tb_lineno)
2857
            self.addMessage.emit(MessageType.Error, message)
2858

    
2859
    '''
2860
        @brief      resetting attribute at secne
2861
        @author     kyoyho
2862
        @date       2018.08.21
2863
    '''
2864
    """
2865
    def checkAttribute(self):
2866
        try:
2867

2868
            docData = AppDocData.instance()
2869
            if not self.graphicsView.hasImage():
2870
                return
2871

2872
            # symbol 경우
2873
            items = [item for item in self.graphicsView.scene.items() if issubclass(type(item), SymbolSvgItem) and type(item) is not QEngineeringSpecBreakItem and type(item) is not QEngineeringEndBreakItem]
2874
            for item in items:
2875
                attrs = item.attrs
2876
                
2877
                removeAttrList = []
2878
                for attr in attrs:
2879
                    if type(attr) is tuple:
2880
                        continue
2881

2882
                    if attr is None:
2883
                        removeAttrList.append(attr)
2884
                        continue
2885

2886
                    attrInfo = docData.getSymbolAttributeByUID(attr.UID)
2887
                    if attrInfo is None:
2888
                        removeAttrList.append(attr)
2889
                    # 해당 attribute가 맞는지 확인
2890
                    else:
2891
                        attrType = attrInfo.AttributeType
2892
                        _type = type(attr)
2893
                        if attrType == 'Symbol Item':
2894
                            if not issubclass(_type, SymbolSvgItem):
2895
                                removeAttrList.append(attr)
2896
                        elif attrType == 'Text Item':
2897
                            if _type is not QEngineeringTextItem:
2898
                                removeAttrList.append(attr)
2899
                        elif attrType == 'Int':
2900
                            if _type is not UserInputAttribute and self.isNumber(attr.text):
2901
                                removeAttrList.append(attr)
2902
                        elif attrType == 'String':
2903
                            if _type is not UserInputAttribute:
2904
                                removeAttrList.append(attr)
2905

2906
                for attr in removeAttrList:
2907
                    del attrs[attr]
2908

2909
            # Line No Text Item의 경우
2910
            items = [item for item in self.graphicsView.scene.items() if issubclass(type(item), QEngineeringLineNoTextItem)]
2911
            for item in items:
2912
                attrs = item.attrs
2913
                
2914
                removeAttrList = []
2915
                for attr in attrs:
2916
                    if type(attr) is UserInputAttribute:
2917
                        attrInfo = docData.getLinePropertiesByUID(attr.attribute)
2918
                        if attrInfo is None:
2919
                            removeAttrList.append(attr)
2920

2921
                for attr in removeAttrList:
2922
                    del attrs[attr]
2923

2924
        except Exception as ex:
2925
                message = 'error occured({}) in {}:{}'.format(ex, sys.exc_info()[-1].tb_frame.f_code.co_filename, sys.exc_info()[-1].tb_lineno)
2926
                self.addMessage.emit(MessageType.Error, message)
2927
    """
2928
    '''
2929
        @brief      Check Number
2930
        @author     kyouho
2931
        @date       2018.08.20
2932
    '''
2933
    def isNumber(self, num):
2934
        p = re.compile('(^[0-9]+$)')
2935
        result = p.match(num)
2936

    
2937
        if result:
2938
            return True
2939
        else:
2940
            return False
2941

    
2942
    '''
2943
        @brief      find overlap Connector
2944
        @author     kyouho
2945
        @date       2018.08.28
2946
    '''
2947
    def findOverlapConnector(self, connectorItem):
2948
        from shapely.geometry import Point
2949
        from EngineeringConnectorItem import QEngineeringConnectorItem
2950
        itemList = []
2951
        
2952
        x = connectorItem.center()[0]
2953
        y = connectorItem.center()[1]
2954

    
2955
        connectors = [item for item in self.graphicsView.scene.items() if type(item) is QEngineeringConnectorItem and item != connectorItem]
2956
        for connector in connectors:
2957
            if Point(x, y).distance(Point(connector.center()[0], connector.center()[1])) < 5:
2958
                itemList.append(connector.parent)
2959

    
2960
        return itemList
2961

    
2962
if __name__ == '__main__':
2963
    import locale
2964
    from PyQt5.QtCore import QTranslator
2965
    from License import QLicenseDialog
2966
    from ProjectDialog import Ui_Dialog
2967
    from App import App 
2968

    
2969
    app = App(sys.argv)
2970
    try:
2971
        if True == QLicenseDialog.check_license_key():
2972
            dlg = Ui_Dialog()
2973
            selectedProject = dlg.showDialog()
2974
            if selectedProject is not None:
2975
                AppDocData.instance().setCurrentProject(selectedProject)
2976
                app._mainWnd = MainWindow.instance()
2977
                app._mainWnd.show()
2978
                sys.exit(app.exec_())
2979
    except Exception as ex:
2980
        print('error occured({}) in {}:{}'.format(ex, sys.exc_info()[-1].tb_frame.f_code.co_filename, sys.exc_info()[-1].tb_lineno))
2981
    finally:
2982
        pass
클립보드 이미지 추가 (최대 크기: 500 MB)