프로젝트

일반

사용자정보

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

hytos / DTI_PID / DTI_PID / MainWindow.py @ d4f20853

이력 | 보기 | 이력해설 | 다운로드 (156 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.join(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 SingletonInstance
33

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

    
70

    
71
class QDisplayWidget(QWidget):
72
    def __init__(self):
73
        from PyQt5 import QtWidgets, uic
74

    
75
        QWidget.__init__(self)
76
        uic.loadUi(os.path.join(os.path.dirname(os.path.realpath(__file__)), 'UI', 'DisplayWidget.ui'), self)
77

    
78

    
79
class MainWindow(QMainWindow, MainWindow_UI.Ui_MainWindow, SingletonInstance):
80
    """ This is MainWindow class """
81
    addMessage = pyqtSignal(Enum, str)
82

    
83
    '''
84
        @brief      initialize
85
        @author 
86
        @date   
87
        @history    humkyung 2018.04.12 add splitter widget
88
                    Jeongwoo 2018.04.27 Add Signal/Slot Connection 'noteNoSingleClicked'
89
                    Jeongwoo 2018.05.09 Initialize Action group
90
                    Jeongwoo 2018.05.10 Add Signal/Slot Connection 'lineNoSingleClicked'
91
                                        Add QActionGroup for managing checkable action
92
                    Jeongwoo 2018.06.27 Add Action [Zoom, Fit Window] and Add new actions into ActionGroup
93
                    humkyung 2018.08.23 add labelStatus to statusbar
94
                    Euisung 2018.09.27 add OCR Training , Signal/Slot Connection 'oCRTrainingClicked'
95
                    Euisung 2018.10.05 add OCR Editor , Signal/Slot Connection 'oCRTrainingEdidorClicked'
96
                    Euisung 2018.10.22 delete Signal/Slot Connection 'oCRTrainingEdidorClicked'
97
    '''
98

    
99
    def __init__(self):
100
        from App import App
101
        from LineTypeConditions import LineTypeConditions
102

    
103
        super(self.__class__, self).__init__()
104
        self.setupUi(self)
105
        self.progress_bar = QProgressBar()
106
        self._label_mouse = QLabel(self.statusbar)
107
        self._label_mouse.setText(self.tr('mouse pos : ({},{})'.format(0, 0)))
108
        self.labelStatus = QLabel(self.statusbar)
109
        self.labelStatus.setText(self.tr('Unrecognition : '))
110
        self.labelSymbolStatus = QLabel(self.statusbar)
111
        self.labelSymbolStatus.setText(self.tr('Symbol : '))
112
        self.labelLineStatus = QLabel(self.statusbar)
113
        self.labelLineStatus.setText(self.tr('Line : '))
114
        self.labelTextStatus = QLabel(self.statusbar)
115
        self.labelTextStatus.setText(self.tr('Text : '))
116

    
117
        self.statusbar.addWidget(self._label_mouse)
118
        self.statusbar.addPermanentWidget(self.progress_bar, 1)
119
        self.statusbar.addPermanentWidget(self.labelSymbolStatus)
120
        self.statusbar.addPermanentWidget(self.labelLineStatus)
121
        self.statusbar.addPermanentWidget(self.labelTextStatus)
122
        self.statusbar.addPermanentWidget(self.labelStatus)
123

    
124
        app_doc_data = AppDocData.instance()
125
        app_doc_data.clear()
126
        project = app_doc_data.getCurrentProject()
127
        _translate = QCoreApplication.translate
128
        version = QCoreApplication.applicationVersion()
129
        # set title
130
        self.setWindowTitle(self.title)
131

    
132
        self.lineComboBox = QComboBox(self.toolBar)
133
        for condition in LineTypeConditions.items():
134
            self.lineComboBox.addItem(condition.name)
135

    
136
        configs = app_doc_data.getConfigs('Line', 'Default Type')
137
        value = configs[0].value if 1 == len(configs) else ''
138
        if value:
139
            at = self.lineComboBox.findText(value)
140
            self.lineComboBox.setCurrentIndex(at)
141
        else:
142
            at = self.lineComboBox.findText('Secondary')
143
            self.lineComboBox.setCurrentIndex(at)
144

    
145
        self.toolBar.insertWidget(self.actionOCR, self.lineComboBox)
146
        self.toolBar.insertSeparator(self.actionOCR)
147

    
148
        self.packageComboBox = QComboBox(self.toolBar)
149
        self.packageComboBox.addItems(['Vendor Package', 'Equipment Package'])
150
        self.toolBar.insertWidget(self.actionValidate, self.packageComboBox)
151

    
152
        self.graphicsView = QtImageViewer.QtImageViewer(self)
153
        self.graphicsView.setParent(self.centralwidget)
154
        self.graphicsView.useDefaultCommand()  # USE DEFAULT COMMAND
155
        self.graphicsView.setMouseTracking(True)
156
        self.graphicsView.viewport().installEventFilter(self)
157
        self.graphicsView.setScene(app_doc_data.scene)
158

    
159
        self._display_widget = QDisplayWidget()
160
        self._display_widget.radioButtonByGroup.toggled.connect(self.display_colors)
161
        self._display_widget.radioButtonByGroup.toggled.connect(self.display_colors)
162
        self.EditToolbar.addWidget(self._display_widget)
163
        self._display_widget.radioButtonByGroup.setChecked(True) \
164
            if DisplayColors.instance().option == DisplayOptions.DisplayByLineNo else \
165
            self._display_widget.radioButtonByType.setChecked(True)
166

    
167
        self.verticalLayout.addWidget(self.graphicsView)
168

    
169
        # Add Custom TreeWidget
170
        self.symbolTreeWidget = SymbolTreeWidget.QSymbolTreeWidget()
171
        self.symbolTreeWidget.header().hide()
172
        self.symbolTabVerticalLayout.addWidget(self.symbolTreeWidget)
173

    
174
        # Add Custom Property TableWidget
175
        self.propertyTableWidget = SymbolPropertyTableWidget.QSymbolPropertyTableWidget()
176
        self.symbolTabVerticalLayout.addWidget(self.propertyTableWidget)
177
        self.symbolTreeWidget.singleClicked.connect(self.propertyTableWidget.getClickedSymbol)
178
        # add splitter widget
179
        splitter = QSplitter(Qt.Vertical)
180
        splitter.addWidget(self.symbolTreeWidget)
181
        splitter.addWidget(self.propertyTableWidget)
182
        self.symbolTabVerticalLayout.addWidget(splitter)
183
        # up to here
184

    
185
        # Add Custom Result Tree Widget (Symbol Explorer)
186
        self.itemTreeWidget = ItemTreeWidget.QItemTreeWidget(self.graphicsView)
187
        self.itemTreeWidget.header().hide()
188
        self.symbolExplorerVerticalLayout.addWidget(self.itemTreeWidget)
189

    
190
        # Add Empty Widget
191
        self.resultPropertyTableWidget = ItemPropertyTableWidget.QItemPropertyTableWidget(self)
192
        self.symbolExplorerVerticalLayout.addWidget(self.resultPropertyTableWidget)
193
        #self.itemTreeWidget.singleClicked.connect(self.resultPropertyTableWidget.show_item_property)
194
        self.itemTreeWidget.noteNoSingleClicked.connect(self.resultPropertyTableWidget.onNoteClicked)
195
        #self.itemTreeWidget.lineNoSingleClicked.connect(self.resultPropertyTableWidget.onLineNoClicked)
196
        self.itemTreeWidget.drawingClicked.connect(self.resultPropertyTableWidget.onDrawingClicked)
197
        # add splitter widget
198
        splitter = QSplitter(Qt.Vertical)
199
        splitter.addWidget(self.itemTreeWidget)
200
        splitter.addWidget(self.resultPropertyTableWidget)
201
        self.symbolExplorerVerticalLayout.addWidget(splitter)
202
        # up to here
203

    
204
        # Initialize Action group
205
        self.actionGroup = QActionGroup(self)
206
        self.actionGroup.addAction(self.actionRecognition)
207
        self.actionGroup.addAction(self.actionLineRecognition)
208
        self.actionGroup.addAction(self.actionLine)
209
        self.actionGroup.addAction(self.actionGenerateOutput)
210
        self.actionGroup.addAction(self.actionOCR)
211
        self.actionGroup.addAction(self.actionZoom)
212
        self.actionGroup.addAction(self.actionFitWindow)
213
        self.actionGroup.addAction(self.actionSave)
214
        self.actionGroup.addAction(self.actionValidate)
215
        self.actionGroup.addAction(self.actionVendor)
216
        self.actionGroup.triggered.connect(self.actionGroupTriggered)
217

    
218
        # connect signals and slots
219
        self.actionClose.triggered.connect(self.close)
220
        self.actionOpen.triggered.connect(self.open_image_drawing)
221
        self.actionExportAsSVG.triggered.connect(self.export_as_svg)
222
        self.actionExportAsXML.triggered.connect(self.export_as_xml)
223
        self.actionExportAsImage.triggered.connect(self.export_as_image)
224
        self.actionLine.triggered.connect(self.onPlaceLine)
225
        self.actionRecognition.triggered.connect(self.recognize)
226
        self.pushButtonBatchRecognition.clicked.connect(self.recognizeBatch)
227
        self.pushButtonRefreshDrawings.clicked.connect(self.load_drawing_list)
228
        self.actionLineRecognition.triggered.connect(self.connect_attributes)
229
        self.actionArea.triggered.connect(self.areaConfiguration)
230
        self.actionConfiguration.triggered.connect(self.configuration)
231
        self.actionOCR.triggered.connect(self.onAreaOcr)
232
        self.actionGenerateOutput.triggered.connect(self.generateOutput)
233
        self.pushButtonCreateSymbol.clicked.connect(self.onCreateSymbolClicked)
234
        self.pushButtonClearLog.clicked.connect(self.onClearLog)
235
        self.actionHMB_DATA.triggered.connect(self.onHMBData)
236
        self.actionItem_Data_List.triggered.connect(self.showItemDataList)
237
        self.actionText_Data_List.triggered.connect(self.showTextDataList)
238
        self.actionSpecialItemTypes.triggered.connect(self.on_show_special_item_types)  # show special item types dialog
239
        self.actionDataTransfer.triggered.connect(self.on_show_data_transfer)  # show data transfer dialog
240
        self.actionDataExport.triggered.connect(self.on_show_data_export)
241
        self.actionExportEqpDatasheet.triggered.connect(self.on_show_eqp_datasheet_export)  # show eqp datasheet export dialog
242
        self.actionOPCRelation.triggered.connect(self.on_show_opc_relation)  # show OPC Relation dialog
243
        self.actionCodeTable.triggered.connect(self.onShowCodeTable)
244
        self.actionCustom_Code_Table.triggered.connect(self.onShowCustomCodeTable)
245
        self.actionImage_Drawing.triggered.connect(self.onViewImageDrawing)
246
        self.actionDrawing_Only.triggered.connect(self.onViewDrawingOnly)
247
        self.actionValidate.triggered.connect(self.onValidation)
248
        self.actionViewText.triggered.connect(self.onViewText)
249
        self.actionViewSymbol.triggered.connect(self.onViewSymbol)
250
        self.actionViewLine.triggered.connect(self.onViewLine)
251
        self.actionViewUnknown.triggered.connect(self.onViewUnknown)
252
        self.actionViewInconsistency.triggered.connect(self.onViewInconsistency)
253
        self.actionViewVendor_Area.triggered.connect(self.onViewVendorArea)
254
        self.actionRotate.triggered.connect(self.onRotate)
255
        self.actionZoom.triggered.connect(self.onAreaZoom)
256
        self.actionVendor.triggered.connect(self.onVendor)
257
        self.actionFitWindow.triggered.connect(self.fitWindow)
258
        self.actionpdf_to_image.triggered.connect(self.onConvertPDFToImage)
259
        self.actionImport_Text_From_CAD.triggered.connect(self.onImportTextFromCAD)
260
        self.actionSymbol_Thickness_Reinforcement.triggered.connect(self.onSymbolThickness)
261
        self.actionHelp.triggered.connect(self.on_help)
262
        self.graphicsView.scene().selectionChanged.connect(self.onSelectionChanged)
263
        self.actionInitialize.triggered.connect(self.onInitializeScene)
264
        self.actionSave.triggered.connect(self.actionSaveCliked)
265
        self.addMessage.connect(self.onAddMessage)
266
        self.actionFindReplaceText.triggered.connect(self.findReplaceTextClicked)
267
        self.actionEditRecognizeLine.triggered.connect(self.on_recognize_line)
268
        self.pushButtonDetectSymbol.clicked.connect(self.show_detect_symbol_dialog)
269
        # self.graphicsView.scene().contents_changed.connect(self.scene_changed)
270

    
271
        configs = app_doc_data.getAppConfigs('app', 'mode')
272
        if configs and 1 == len(configs) and 'advanced' == configs[0].value:
273
            self.actionOCR_Training.triggered.connect(self.oCRTrainingClicked)
274
            self.actionSymbol_Training.triggered.connect(self.symbolTrainingClicked)
275
        else:
276
            # self.actionOCR_Training.setVisible(False)
277
            # self.actionSymbol_Training.setVisible(False)
278
            self.menu_2.setEnabled(False)  # Data
279
            self.menu_4.setEnabled(False)  # Tool
280
            self.actionConfiguration.setVisible(False)
281
            self.pushButtonBatchRecognition.setVisible(False)
282
            self.pushButtonCreateSymbol.setVisible(False)
283
            self.pushButtonDetectSymbol.setVisible(False)
284

    
285
        self.delimiter = '"'
286

    
287
        self.resizeDocks({self.dockWidget}, {self.dockWidgetObjectExplorer.sizeHint().width()}, Qt.Horizontal)
288

    
289
        self.treeWidgetDrawingList.setHeaderHidden(False)
290
        self.treeWidgetDrawingList.header().setStretchLastSection(False)
291
        self.treeWidgetDrawingList.setHeaderLabels([self.tr('Name'), self.tr('DateTime')])
292
        self.treeWidgetDrawingList.header().setSectionResizeMode(0, QHeaderView.ResizeToContents)
293
        self.treeWidgetDrawingList.header().setSectionResizeMode(1, QHeaderView.ResizeToContents)
294
        self.treeWidgetDrawingList.itemDoubleClicked.connect(self.open_selected_drawing)
295
        self.load_drawing_list()
296

    
297
        # load stylesheet file list
298
        stylesheet_name = QtWidgets.qApp.stylesheet_name
299
        files = [os.path.splitext(file)[0] for file in os.listdir(os.path.dirname(os.path.realpath(__file__))) if
300
                 os.path.splitext(file)[1] == '.qss']
301
        for file in files:
302
            action = self.menuTheme.addAction(file)
303
            action.setCheckable(True)
304
            action.setChecked(True) if stylesheet_name == file else action.setChecked(False)
305
            action.triggered.connect(partial(self.load_stylesheet, file))
306
        # up to here
307

    
308
        # load language files
309
        language_name = QtWidgets.qApp.language_name
310
        files = ['en_us']  # english is default language
311
        files.extend([os.path.splitext(file)[0] for file in
312
                      os.listdir(os.path.join(os.path.dirname(os.path.realpath(__file__)), 'translate')) if
313
                      os.path.splitext(file)[1] == '.qm'])
314
        for file in files:
315
            action = self.menuLanguage.addAction(file)
316
            action.setCheckable(True)
317
            action.setChecked(True) if language_name.lower() == file.lower() else action.setChecked(False)
318
            action.triggered.connect(partial(self.load_language, file))
319
        # up to here
320

    
321
        # inconsistency table
322
        self.tableWidgetInconsistency.setColumnCount(3)
323
        self.tableWidgetInconsistency.setHorizontalHeaderLabels(['Owner', 'Type', 'Message'])
324
        self.tableWidgetInconsistency.setEditTriggers(QAbstractItemView.NoEditTriggers)
325
        self.tableWidgetInconsistency.itemClicked.connect(self.inconsistencyItemClickEvent)
326
        self.tableWidgetInconsistency.keyPressEvent = self.inconsistencyTableKeyPressEvent
327
        self.tableWidgetInconsistency.setSortingEnabled(True)
328

    
329
        self.read_settings()
330

    
331
    @property
332
    def title(self) -> str:
333
        """return window title"""
334

    
335
        from App import App
336

    
337
        app_doc_data = AppDocData.instance()
338
        project = app_doc_data.getCurrentProject()
339
        version = QCoreApplication.applicationVersion()
340
        title = f"{App.NAME}({version}) - {project.name}:" \
341
                f"{app_doc_data.activeDrawing.name if app_doc_data.activeDrawing else ''}"
342

    
343
        return title
344

    
345
    def eventFilter(self, source, event):
346
        """display mouse position of graphics view"""
347
        try:
348
            if event.type() == QEvent.MouseMove:
349
                self.current_pos = self.graphicsView.mapToScene(event.pos())
350
                self._label_mouse.setText(
351
                    'mouse pos : ({},{})'.format(round(self.current_pos.x()), round(self.current_pos.y())))
352
        except Exception as ex:
353
            message = 'error occurred({}) in {}:{}'.format(ex, sys.exc_info()[-1].tb_frame.f_code.co_filename,
354
                                                           sys.exc_info()[-1].tb_lineno)
355
            self.addMessage.emit(MessageType.Error, message)
356

    
357
        return QWidget.eventFilter(self, source, event)
358

    
359
    def closeEvent(self, event):
360
        """save geometry and state and ask user to save drawing which is modified"""
361

    
362
        self.settings.setValue('geometry', self.saveGeometry())
363
        self.settings.setValue('windowState', self.saveState())
364
        # TODO: need to modify
365
        # self.save_drawing_if_necessary()
366
        AppDocData.instance().clear()
367
        event.accept()
368

    
369
    def inconsistencyTableKeyPressEvent(self, event):
370
        try:
371
            row = self.tableWidgetInconsistency.selectedIndexes()[0].row()
372
            col = self.tableWidgetInconsistency.selectedIndexes()[0].column()
373
            from HighlightCommand import HighlightCommand
374
            if event.key() == Qt.Key_Up:
375
                if row is not 0:
376
                    errorItem = self.tableWidgetInconsistency.item(row - 1, 1).tag
377
                    HighlightCommand(self.graphicsView).execute(errorItem)
378
            elif event.key() == Qt.Key_Down:
379
                if row is not self.tableWidgetInconsistency.rowCount() - 1:
380
                    errorItem = self.tableWidgetInconsistency.item(row + 1, 1).tag
381
                    HighlightCommand(self.graphicsView).execute(errorItem)
382
            elif event.key() == Qt.Key_Delete:
383
                item = self.tableWidgetInconsistency.item(row, 0).tag
384
                if item and item.scene(): item.scene().removeItem(item)
385
                self.tableWidgetInconsistency.removeRow(row)
386

    
387
                self.tabWidget_2.setTabText(self.tabWidget_2.indexOf(self.tabInconsistency),
388
                                            self.tr('Inconsistency') + f"({self.tableWidgetInconsistency.rowCount()})")
389
        except Exception as ex:
390
            message = 'error occurred({}) in {}:{}'.format(ex, sys.exc_info()[-1].tb_frame.f_code.co_filename,
391
                                                           sys.exc_info()[-1].tb_lineno)
392
            self.addMessage.emit(MessageType.Error, message)
393
        # finally:
394
        #    return QTableView.keyPressEvent(self.tableWidgetInconsistency, event)
395

    
396
    def onValidation(self):
397
        """validation check"""
398
        from ValidationDialog import QValidationDialog
399
        from ValidateCommand import ValidateCommand
400

    
401
        if not self.graphicsView.hasImage():
402
            self.showImageSelectionMessageBox()
403
            return
404

    
405
        try:
406
            dlg = QValidationDialog(self)
407
            if QDialog.Accepted == dlg.exec_():
408
                # remove error items
409
                for item in self.graphicsView.scene().items():
410
                    if type(item) is QEngineeringErrorItem:
411
                        item.transfer.onRemoved.emit(item)
412
                # up to here
413

    
414
                self.progress_bar.setMaximum(len(self.graphicsView.scene().items()))
415
                self.progress_bar.setValue(0)
416

    
417
                cmd = ValidateCommand(self.graphicsView)
418
                cmd.show_progress.connect(self.progress_bar.setValue)
419
                errors = cmd.execute(self.graphicsView.scene().items())
420
                for error in errors:
421
                    error.transfer.onRemoved.connect(self.itemRemoved)
422
                    self.graphicsView.scene().addItem(error)
423

    
424
                self.tableWidgetInconsistency.clearContents()
425
                self.tableWidgetInconsistency.setRowCount(len(errors))
426
                for index, error in enumerate(errors):
427
                    self.makeInconsistencyTableRow(index, error)
428

    
429
                self.tabWidget_2.setTabText(self.tabWidget_2.indexOf(self.tabInconsistency),
430
                                            self.tr('Inconsistency') + f"({len(errors)})")
431
                if errors:
432
                    self.tabWidget_2.tabBar().setTabTextColor(self.tabWidget_2.indexOf(self.tabInconsistency), Qt.red)
433
                else:
434
                    self.tabWidget_2.tabBar().setTabTextColor(self.tabWidget_2.indexOf(self.tabInconsistency), Qt.black)
435
        except Exception as ex:
436
            message = 'error occurred({}) in {}:{}'.format(ex, sys.exc_info()[-1].tb_frame.f_code.co_filename,
437
                                                           sys.exc_info()[-1].tb_lineno)
438
            self.addMessage.emit(MessageType.Error, message)
439
        finally:
440
            self.progress_bar.setValue(self.progress_bar.maximum())
441

    
442
    def makeInconsistencyTableRow(self, row, errorItem):
443
        '''
444
            @brief  make row data for inconsistency widget
445
            @author euisung
446
            @date   2019.04.16
447
        '''
448

    
449
        item = QTableWidgetItem(str(errorItem.parent))
450
        item.tag = errorItem
451
        self.tableWidgetInconsistency.setItem(row, 0, item)
452

    
453
        item = QTableWidgetItem(str(type(errorItem.parent)))
454
        item.tag = errorItem
455
        self.tableWidgetInconsistency.setItem(row, 1, item)
456

    
457
        item = QTableWidgetItem(errorItem.msg)
458
        item.tag = errorItem
459
        self.tableWidgetInconsistency.setItem(row, 2, item)
460

    
461
    def inconsistencyItemClickEvent(self, item):
462
        """
463
        @brief  inconsistency table item clicked
464
        @author euisung
465
        @date   2019.04.02
466
        """
467
        from HighlightCommand import HighlightCommand
468

    
469
        HighlightCommand(self.graphicsView).execute(item.tag)
470

    
471
    def read_settings(self):
472
        """read geometry and state"""
473
        from App import App
474

    
475
        try:
476
            self.settings = QSettings(App.COMPANY, App.NAME)
477
            self.restoreGeometry(self.settings.value("geometry", ""))
478
            self.restoreState(self.settings.value("windowState", ""))
479
        except Exception as ex:
480
            message = 'error occurred({}) in {}:{}'.format(ex, sys.exc_info()[-1].tb_frame.f_code.co_filename,
481
                                                           sys.exc_info()[-1].tb_lineno)
482
            print(message)
483

    
484
    def load_stylesheet(self, file):
485
        """load stylesheets"""
486

    
487
        QtWidgets.qApp.loadStyleSheet(os.path.join(os.path.dirname(os.path.realpath(__file__)), file))
488

    
489
        app_doc_data = AppDocData.instance()
490
        configs = [Config('app', 'stylesheet', file)]
491
        app_doc_data.saveAppConfigs(configs)
492

    
493
        for action in self.menuTheme.actions():
494
            if action.text() == file: continue
495
            action.setChecked(False)
496

    
497
    def load_language(self, file):
498
        """load language file and then apply selected language"""
499
        try:
500
            qm_file = os.path.join(os.path.dirname(os.path.realpath(__file__)), 'translate', '{0}.qm'.format(file))
501
            QtWidgets.qApp.load_language(qm_file)
502

    
503
            app_doc_data = AppDocData.instance()
504
            configs = [Config('app', 'language', file)]
505
            app_doc_data.saveAppConfigs(configs)
506

    
507
            for action in self.menuLanguage.actions():
508
                if action.text().lower() == file.lower(): continue
509
                action.setChecked(False)
510
        finally:
511
            self.retranslateUi(self)
512
            self.propertyTableWidget.retranslateUi()
513

    
514
    def load_drawing_list(self):
515
        """load p&id drawing list"""
516
        from Drawing import Drawing
517

    
518
        try:
519
            app_doc_data = AppDocData.instance()
520
            drawings = app_doc_data.getDrawings()
521

    
522
            self.treeWidgetDrawingList.clear()
523
            self.treeWidgetDrawingList.root = QTreeWidgetItem(self.treeWidgetDrawingList,
524
                                                              [self.tr('P&ID Drawings'), ''])
525
            self.treeWidgetDrawingList.root.setFlags(
526
                self.treeWidgetDrawingList.root.flags() | Qt.ItemIsTristate | Qt.ItemIsUserCheckable)
527
            self.treeWidgetDrawingList.root.setCheckState(0, Qt.Unchecked)
528
            files = app_doc_data.getDrawingFileList()
529

    
530
            # self.progress_bar.setMaximum(len(files))
531
            count = 0
532
            # self.progress_bar.setValue(count)
533
            for file in files:
534
                x = [drawing for drawing in drawings if drawing.name == file]
535
                if not x or not x[0].UID:
536
                    drawing = Drawing(None, file, None)
537
                    drawings.append(drawing)
538
                else:
539
                    drawing = x[0]
540

    
541
                item = QTreeWidgetItem(self.treeWidgetDrawingList.root, [file, drawing.datetime])
542
                item.setIcon(0, QIcon(':newPrefix/image.png'))
543
                item.setFlags(item.flags() | Qt.ItemIsUserCheckable)
544
                item.setCheckState(0, Qt.Unchecked)
545
                item.setData(Qt.UserRole, 0, drawing)
546

    
547
                count += 1
548
                # self.progress_bar.setValue(count)
549
                # QApplication.processEvents()
550

    
551
            self.treeWidgetDrawingList.root.setText(0, self.tr('P&ID Drawings') +
552
                                                    f"({self.treeWidgetDrawingList.root.childCount()})")
553
            self.treeWidgetDrawingList.expandItem(self.treeWidgetDrawingList.root)
554
            self.treeWidgetDrawingList.root.sortChildren(0, Qt.AscendingOrder)
555
            self.treeWidgetDrawingList.resizeColumnToContents(0)
556

    
557
            app_doc_data.saveDrawings(drawings)
558
        except Exception as ex:
559
            message = 'error occurred({}) in {}:{}'.format(repr(ex), sys.exc_info()[-1].tb_frame.f_code.co_filename,
560
                                                           sys.exc_info()[-1].tb_lineno)
561
            self.addMessage.emit(MessageType.Error, message)
562
        finally:
563
            self.progress_bar.setValue(self.progress_bar.maximum())
564

    
565
    def open_selected_drawing(self, item, column):
566
        """open selected p&id drawing"""
567

    
568
        app_doc_data = AppDocData.instance()
569
        drawing = item.data(Qt.UserRole, 0)
570
        if drawing:
571
            drawing.image = None
572
            self.open_image_drawing(drawing)
573

    
574
    def show_detect_symbol_dialog(self):
575
        from DetectSymbolDialog import QDetectSymbolDialog
576

    
577
        dlg = QDetectSymbolDialog(self)
578
        dlg.exec_()
579

    
580
    '''
581
        @brief      OCR Editor
582
        @author     euisung
583
        @date       2018.10.05
584
        @history    2018.10.16 euisung      no more used, Integrated with oCRTrainingClicked
585
    '''
586

    
587
    def oCRTrainingEdidorClicked(self):
588
        from TrainingEditorDialog import QTrainingEditorDialog
589

    
590
        try:
591
            dialog = QTrainingEditorDialog(self)
592
            dialog.exec_()
593
        except Exception as ex:
594
            message = 'error occurred({}) in {}:{}'.format(ex, sys.exc_info()[-1].tb_frame.f_code.co_filename,
595
                                                           sys.exc_info()[-1].tb_lineno)
596
            self.addMessage.emit(MessageType.Error, message)
597

    
598
        return
599

    
600
    '''
601
        @brief      OCR Training
602
        @author     euisung
603
        @date       2018.09.27
604
        @history    euisung 2018.10.16 TrainingListDialog -> TrainingImageListDialog
605
    '''
606

    
607
    def oCRTrainingClicked(self):
608
        try:
609
            dialog = QTrainingImageListDialog(self)
610
            dialog.exec_()
611
        except Exception as ex:
612
            message = 'error occurred({}) in {}:{}'.format(ex, sys.exc_info()[-1].tb_frame.f_code.co_filename,
613
                                                           sys.exc_info()[-1].tb_lineno)
614
            self.addMessage.emit(MessageType.Error, message)
615

    
616
    def symbolTrainingClicked(self):
617
        try:
618
            dialog = QTrainingSymbolImageListDialog(self)
619
            dialog.exec_()
620
        except Exception as ex:
621
            message = 'error occurred({}) in {}:{}'.format(ex, sys.exc_info()[-1].tb_frame.f_code.co_filename,
622
                                                           sys.exc_info()[-1].tb_lineno)
623
            self.addMessage.emit(MessageType.Error, message)
624

    
625
    def findReplaceTextClicked(self):
626
        """pop up find and replace dialog"""
627
        if not self.graphicsView.hasImage():
628
            self.showImageSelectionMessageBox()
629
            return
630

    
631
        from TextItemEditDialog import QTextItemEditDialog
632

    
633
        self.dlgTextItemEdit = QTextItemEditDialog(self)
634
        self.dlgTextItemEdit.show()
635
        self.dlgTextItemEdit.exec_()
636

    
637
    def on_recognize_line(self):
638
        """recognize lines in selected area"""
639
        from RecognizeLineCommand import RecognizeLineCommand
640

    
641
        if not self.graphicsView.hasImage():
642
            self.actionOCR.setChecked(False)
643
            self.showImageSelectionMessageBox()
644
            return
645

    
646
        cmd = RecognizeLineCommand(self.graphicsView)
647
        cmd.onSuccess.connect(self.on_success_to_recognize_line)
648
        cmd.onRejected.connect(self.onCommandRejected)
649
        self.graphicsView.command = cmd
650

    
651
    '''
652
            @brief      show text recognition dialog
653
            @author     humkyung
654
            @date       2018.08.08
655
        '''
656

    
657
    def on_success_to_recognize_line(self, x, y, width, height):
658
        import io
659
        from LineDetector import LineDetector
660
        from EngineeringGraphicsLineItem import QEngineeringGraphicsLineItem
661

    
662
        try:
663
            image = self.graphicsView.image().copy(x, y, width, height)
664
            buffer = QBuffer()
665
            buffer.open(QBuffer.ReadWrite)
666
            image.save(buffer, "PNG")
667
            pyImage = Image.open(io.BytesIO(buffer.data()))
668
            img = np.array(pyImage)
669
            img = cv2.cvtColor(img, cv2.COLOR_BGR2GRAY)
670

    
671
            detector = LineDetector(img)
672
            lines = detector.detect_line_without_symbol()
673
            for line in lines:
674
                vertices = [[line[0][0] + x, line[0][1] + y], [line[1][0] + x, line[1][1] + y]]
675
                line_item = QEngineeringGraphicsLineItem(vertices)
676
                self.graphicsView.scene().addItem(line_item)
677

    
678
        except Exception as ex:
679
            message = 'error occurred({}) in {}:{}'.format(repr(ex), sys.exc_info()[-1].tb_frame.f_code.co_filename,
680
                                                           sys.exc_info()[-1].tb_lineno)
681
            self.addMessage.emit(MessageType.Error, message)
682

    
683
    def display_number_of_items(self):
684
        """display count of symbol, line, text"""
685

    
686
        items = [item for item in self.graphicsView.scene().items() if type(item) is QEngineeringUnknownItem]
687
        if len(items) > 0:
688
            self.labelStatus.setText(
689
                "<font color='red'>" + self.tr('Unrecognition') + " : {}</font>".format(len(items)))
690
        else:
691
            self.labelStatus.setText(
692
                "<font color='black'>" + self.tr('Unrecognition') + " : {}</font>".format(len(items)))
693

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

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

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

    
704
        self.itemTreeWidget.sceneChanged(self.graphicsView.scene().items())
705

    
706
    def dbUpdate(self):
707
        '''
708
            @brief      db update when save or recognition
709
            @author     euisung
710
            @date       2018.11.12
711
            @history    2018.11.02      euisung     remove scene dependency
712
        '''
713
        try:
714
            appDocData = AppDocData.instance()
715
            items = appDocData.allItems
716

    
717
            '''
718
            titleBlockProps = appDocData.getTitleBlockProperties()
719
            titleBlockItems = []
720
            for item in items:
721
                # if type(item) is QEngineeringLineNoTextItem:
722
                #    item.saveLineData()
723
                if type(item) is QEngineeringTextItem:
724
                    for titleBlockProp in titleBlockProps:
725
                        if item.area == titleBlockProp[0]:
726
                            titleBlockItems.append(item)
727
            '''
728

    
729
            # unknown item is not saved now for performance
730
            db_items = [item for item in items if issubclass(type(item), QEngineeringAbstractItem) and
731
                        type(item) is not QGraphicsBoundingBoxItem and
732
                        type(item) is not QEngineeringErrorItem and
733
                        type(item) is not QEngineeringLineNoTextItem and
734
                        type(item) is not QEngineeringUnknownItem]
735
            db_items.extend([item for item in items if type(item) is QEngineeringLineNoTextItem])
736
            db_items.extend([line for line in appDocData.tracerLineNos if type(line) is QEngineeringTrimLineNoTextItem])
737
            # db_items.extend(titleBlockItems)
738
            configs = appDocData.getConfigs('Data Load', 'Xml First')
739
            if configs and int(configs[0].value) is 1:
740
                db_items.extend([item for item in items if type(item) is QEngineeringUnknownItem])
741

    
742
            '''
743
            dbItems = [item for item in items if
744
                       type(item) is QEngineeringInstrumentItem or type(item) is QEngineeringEquipmentItem or type(
745
                           item) is QEngineeringReducerItem or \
746
                       type(item) is QEngineeringNoteItem or type(item) is SymbolSvgItem or type(
747
                           item) is QEngineeringLineNoTextItem or type(
748
                           item) is QEngineeringVendorItem] + titleBlockItems
749
            '''
750
            appDocData.saveToDatabase(db_items)
751
        except Exception as ex:
752
            message = 'error occurred({}) in {}:{}'.format(ex, sys.exc_info()[-1].tb_frame.f_code.co_filename,
753
                                                           sys.exc_info()[-1].tb_lineno)
754
            self.addMessage.emit(MessageType.Error, message)
755

    
756
    def save_drawing_if_necessary(self):
757
        """ask to user to save drawing or not when drawing is modified"""
758

    
759
        app_doc_data = AppDocData.instance()
760
        if app_doc_data.activeDrawing and app_doc_data.activeDrawing.modified:
761
            if QMessageBox.Yes == QMessageBox.question(self, self.tr("Question"),
762
                                                       self.tr("Do you want to save drawing?"),
763
                                                       QMessageBox.Yes | QMessageBox.No):
764
                # self.actionSaveCliked()
765
                return True
766

    
767
    '''
768
        @brief      action save click event
769
        @author     kyouho
770
        @date       2018.08.09
771
        @history    2018.11.02      euisung     add line data list db update
772
                    humkyung save saved time to database
773
                    2018.11.05      euisung     add note data list db update
774
                    2018.11.05      euisung     add db delete process before save
775
                    2018.11.12      euisung     db part move new method to dbUpdate
776
    '''
777

    
778
    def actionSaveCliked(self):
779
        from EngineeringAbstractItem import QEngineeringAbstractItem
780
        from SaveWorkCommand import SaveWorkCommand
781

    
782
        try:
783
            if not self.actionSave.isEnabled():
784
                return
785
            self.actionSave.setEnabled(False)
786
            app_doc_data = AppDocData.instance()
787
            if app_doc_data.imgName is None:
788
                self.showImageSelectionMessageBox()
789
                return
790

    
791
            app_doc_data.clearItemList(False)
792

    
793
            items = self.graphicsView.scene().items()
794

    
795
            # for check line disappear bug
796
            disappear_lines = [line for line in app_doc_data.lines if line not in items]
797

    
798
            for item in items:
799
                if issubclass(type(item), QEngineeringAbstractItem):
800
                    app_doc_data.allItems.append(item)
801
                    if issubclass(type(item), QEngineeringTextItem):
802
                        app_doc_data.texts.append(item)
803

    
804
            # for check line disappear bug
805
            if disappear_lines:
806
                app_doc_data.allItems.extend(disappear_lines)
807
                for dis_line in disappear_lines:
808
                    self.addMessage.emit(MessageType.Check, f"disapper line from scene : {str(dis_line)}")
809

    
810
            itemTypes = []
811
            for item in items:
812
                typeExist = False
813
                for itemType in itemTypes:
814
                    if type(item) is itemType:
815
                        typeExist = True
816
                        break
817
                if not typeExist:
818
                    itemTypes.append(type(item))
819

    
820
            self._save_work_cmd = SaveWorkCommand()
821
            self._save_work_cmd.show_progress.connect(self.progress_bar.setValue)
822
            self._save_work_cmd.display_message.connect(self.onAddMessage)
823
            self._save_work_cmd.finished.connect(self.save_finished)
824

    
825
            self._save_work_cmd.start()
826
        except Exception as ex:
827
            message = 'error occurred({}) in {}:{}'.format(repr(ex), sys.exc_info()[-1].tb_frame.f_code.co_filename,
828
                                                           sys.exc_info()[-1].tb_lineno)
829
            self.addMessage.emit(MessageType.Error, message)
830

    
831
    def save_finished(self):
832
        """reload drawing list"""
833

    
834
        self._save_work_cmd.show_progress.emit(100)
835
        QMessageBox.about(self.graphicsView, self.tr('Information'), self._save_work_cmd.resultStr)
836
        self.load_drawing_list()
837

    
838
        app_doc_data = AppDocData.instance()
839
        app_doc_data.activeDrawing.modified = False
840
        title = self.windowTitle()
841
        self.setWindowTitle(title[:-1] if title[-1] == '*' else title)
842

    
843
        self.actionSave.setEnabled(True)
844

    
845
    '''
846
        @brief      refresh resultPropertyTableWidget
847
        @author     kyouho
848
        @date       2018.07.19
849
    '''
850

    
851
    def refreshResultPropertyTableWidget(self):
852
        items = self.graphicsView.scene().selectedItems()
853
        if len(items) == 1:
854
            self.resultPropertyTableWidget.show_item_property(items[0])
855

    
856
    '''
857
        @brief  add message listwidget
858
        @author humkyung
859
        @date   2018.07.31
860
    '''
861

    
862
    def onAddMessage(self, messageType, message):
863
        from AppDocData import MessageType
864

    
865
        try:
866
            current = QDateTime.currentDateTime()
867

    
868
            item = QListWidgetItem('{}: {}'.format(current.toString('hh:mm:ss'), message))
869
            item.setFlags(item.flags() | Qt.ItemIsEditable)
870
            if messageType == MessageType.Error:
871
                item.setBackground(Qt.red)
872
            elif messageType == 'check':
873
                item.setBackground(Qt.yellow)
874

    
875
            self.listWidgetLog.insertItem(0, item)
876
        except Exception as ex:
877
            print('error occurred({}) in {}:{}'.format(ex, sys.exc_info()[-1].tb_frame.f_code.co_filename,
878
                                                       sys.exc_info()[-1].tb_lineno))
879

    
880
    '''
881
        @brief      clear log
882
        @author     humkyung
883
        @date       2018.08.01
884
    '''
885

    
886
    def onClearLog(self):
887
        self.listWidgetLog.clear()
888

    
889
    '''
890
        @brief      rotate selected symbol
891
        @author     humkyung
892
        @date       2018.08.15
893
    '''
894

    
895
    def onRotate(self, action):
896
        selected = [item for item in self.graphicsView.scene().selectedItems() if issubclass(type(item), SymbolSvgItem)]
897
        if len(selected) == 1:
898
            selected[0].rotateSymbol()
899

    
900
    '''
901
        @brief      Area Zoom
902
        @author     Jeongwoo
903
        @date       2018.06.27
904
        @history    connect command's rejected signal
905
    '''
906

    
907
    def onAreaZoom(self, action):
908
        if self.actionZoom.isChecked():
909
            cmd = AreaZoomCommand.AreaZoomCommand(self.graphicsView)
910
            cmd.onRejected.connect(self.onCommandRejected)
911
            self.graphicsView.command = cmd
912

    
913
    def onVendor(self, action):
914
        """make vendor package area"""
915

    
916
        if not self.graphicsView.hasImage():
917
            self.actionVendor.setChecked(False)
918
            self.showImageSelectionMessageBox()
919
            return
920

    
921
        self.actionVendor.setChecked(True)
922
        if not hasattr(self.actionVendor, 'tag'):
923
            self.actionVendor.tag = PlacePolygonCommand.PlacePolygonCommand(self.graphicsView)
924
            self.actionVendor.tag.onSuccess.connect(self.onVendorCreated)
925
            self.actionVendor.tag.onRejected.connect(self.onCommandRejected)
926

    
927
        self.graphicsView.command = self.actionVendor.tag
928

    
929
    def onVendorCreated(self):
930
        """add created vendor polygon area to scene"""
931

    
932
        try:
933
            count = len(self.actionVendor.tag._polyline._vertices)
934
            if count > 2:
935
                points = []
936
                for point in self.actionVendor.tag._polyline._vertices:
937
                    points.append(QPoint(round(point[0]), round(point[1])))
938
                polygon = QPolygonF(points)
939
                item = QEngineeringVendorItem(polygon, pack_type=self.packageComboBox.currentText())
940
                item.area = 'Drawing'
941
                item.transfer.onRemoved.connect(self.itemRemoved)
942
                self.graphicsView.scene().addItem(item)
943
        finally:
944
            self.graphicsView.scene().removeItem(self.actionVendor.tag._polyline)
945
            self.actionVendor.tag.reset()
946

    
947
    '''
948
        @brief      Fit Window
949
        @author     Jeongwoo
950
        @date       2018.06.27
951
        @history    2018.06.27  Jeongwoo    Chnage method to initialize command [Set None → DefaultCommand]
952
    '''
953

    
954
    def fitWindow(self, action):
955
        self.graphicsView.useDefaultCommand()
956
        self.graphicsView.zoomImageInit()
957

    
958
    def scene_changed(self):
959
        """update modified flag"""
960

    
961
        self.display_number_of_items()
962

    
963
        app_doc_data = AppDocData.instance()
964
        app_doc_data.activeDrawing.modified = True
965
        title = self.windowTitle()
966
        self.setWindowTitle(title if title[-1] == '*' else title + '*')
967

    
968
    def onConvertPDFToImage(self):
969
        """convert to selected pdf to image"""
970
        import os
971

    
972
        try:
973
            file_path = os.path.join(os.path.dirname(os.path.realpath(__file__)), 'bin64', 'PDF_TO_IMAGE.exe')
974
            os.startfile(file_path)
975
        except Exception as ex:
976
            message = 'error occurred({}) in {}:{}'.format(ex, sys.exc_info()[-1].tb_frame.f_code.co_filename,
977
                                                           sys.exc_info()[-1].tb_lineno)
978
            self.addMessage.emit(MessageType.Error, message)
979

    
980
    def onImportTextFromCAD(self):
981
        """ import text from cad """
982
        try:
983
            self.onCommandRejected()
984
            dialog = QImportTextFromCADDialog(self)
985
            dialog.show()
986
            dialog.exec_()
987
        except Exception as ex:
988
            message = 'error occurred({}) in {}:{}'.format(ex, sys.exc_info()[-1].tb_frame.f_code.co_filename,
989
                                                           sys.exc_info()[-1].tb_lineno)
990
            self.addMessage.emit(MessageType.Error, message)
991

    
992
    def onSymbolThickness(self):
993
        """ symbol thickness reinforcement by using configuration filter drawing dilate size """
994
        try:
995
            self.onCommandRejected()
996
            dialog = QSymbolThicknessDialog(self)
997
            dialog.exec_()
998
        except Exception as ex:
999
            message = 'error occurred({}) in {}:{}'.format(ex, sys.exc_info()[-1].tb_frame.f_code.co_filename,
1000
                                                           sys.exc_info()[-1].tb_lineno)
1001
            self.addMessage.emit(MessageType.Error, message)
1002

    
1003
    def on_help(self):
1004
        """ open help file """
1005
        import os
1006

    
1007
        try:
1008
            help_file_path = os.path.join(os.path.dirname(os.path.realpath(__file__)), 'ID2 User Manual.pdf')
1009
            os.system('"{}"'.format(help_file_path))
1010
        except Exception as ex:
1011
            message = 'error occurred({}) in {}:{}'.format(ex, sys.exc_info()[-1].tb_frame.f_code.co_filename,
1012
                                                           sys.exc_info()[-1].tb_lineno)
1013
            self.addMessage.emit(MessageType.Error, message)
1014

    
1015
    def onSelectionChanged(self):
1016
        """selection changed"""
1017
        items = [item for item in self.graphicsView.scene().selectedItems() if issubclass(type(item), SymbolSvgItem) or
1018
                 type(item) is QEngineeringLineItem or issubclass(type(item), QEngineeringTextItem) or
1019
                 type(item) is QEngineeringUnknownItem or type(item) is QEngineeringVendorItem]
1020
        if items:
1021
            lineNos = [item for item in items if type(item) is QEngineeringLineNoTextItem]
1022
            item = items[-1] if not lineNos else lineNos[0]
1023
            self.itemTreeWidget.findItem(item)
1024
            self.resultPropertyTableWidget.show_item_property(item)
1025
            if type(item) is QEngineeringErrorItem:
1026
                for index in range(self.tableWidgetInconsistency.rowCount()):
1027
                    if self.tableWidgetInconsistency.item(index, 1).tag is item:
1028
                        self.tableWidgetInconsistency.selectRow(index)
1029
                        break
1030
            if issubclass(type(item), SymbolSvgItem):
1031
                self.symbolTreeWidget.select_symbol(item)
1032
        else:
1033
            self.resultPropertyTableWidget.show_item_property(None)
1034

    
1035
    '''
1036
        @brief      Initialize scene and itemTreeWidget
1037
        @author     Jeongwoo
1038
        @date       2018.06.14
1039
        @history    humkyung 2018.08.16 ask to delete recognized items before remove
1040
    '''
1041

    
1042
    def onInitializeScene(self, action):
1043
        if not self.graphicsView.hasImage():
1044
            # self.actionEquipment.setChecked(False)
1045
            self.showImageSelectionMessageBox()
1046

    
1047
            return
1048

    
1049
        try:
1050
            msg = QMessageBox()
1051
            msg.setIcon(QMessageBox.Critical)
1052
            msg.setText(self.tr('Do you want to remove all items?\nThis work cannot be recovered.'))
1053
            msg.setWindowTitle(self.tr("Initialize"))
1054
            msg.setStandardButtons(QMessageBox.Ok | QMessageBox.Cancel)
1055
            if QMessageBox.Ok == msg.exec_():
1056

    
1057
                appDocData = AppDocData.instance()
1058
                appDocData.clearItemList(True)
1059

    
1060
                items = self.graphicsView.scene().items()
1061
                for item in items:
1062
                    if type(item) is not QGraphicsPixmapItem and item.scene() is not None:
1063
                        # if hasattr(item, 'tranfer'):
1064
                        #    item.tranfer.onRemoved.emit(item)
1065
                        # else:
1066
                        #    self.graphicsView.scene().removeItem(item)
1067
                        self.graphicsView.scene().removeItem(item)
1068

    
1069
                        '''
1070
                        if type(item) is QEngineeringLineNoTextItem:
1071
                            self.removedItems['LINE'].append(str(item.uid))
1072
                        elif type(item) is QEngineeringInstrumentItem:
1073
                            self.removedItems['INST'].append(str(item.uid))
1074
                        elif type(item) is QEngineeringEquipmentItem:
1075
                            self.removedItems['EQUIP'].append(str(item.uid))
1076
                        elif type(item) is QEngineeringNoteItem:
1077
                            self.removedItems['NOTE'].append(str(item.uid))
1078
                        '''
1079

    
1080
                if self.path is not None:
1081
                    baseName = os.path.basename(self.path)
1082
                    self.itemTreeWidget.setCurrentPID(baseName)
1083

    
1084
        except Exception as ex:
1085
            message = 'error occurred({}) in {}:{}'.format(ex, sys.exc_info()[-1].tb_frame.f_code.co_filename,
1086
                                                           sys.exc_info()[-1].tb_lineno)
1087
            self.addMessage.emit(MessageType.Error, message)
1088

    
1089
    '''
1090
        @brief      Manage Checkable Action statement
1091
        @author     Jeongwoo
1092
        @date       2018.05.10
1093
        @history    2018.06.27  Jeongwoo    Chnage method to initialize command [Set None → DefaultCommand]
1094
    '''
1095

    
1096
    def actionGroupTriggered(self, action):
1097
        if hasattr(self.actionLine, 'tag'):
1098
            self.actionLine.tag.onRejected.emit(None)
1099

    
1100
        if hasattr(self.actionVendor, 'tag'):
1101
            self.actionVendor.tag.onRejected.emit(None)
1102

    
1103
        if self.graphicsView.command is not None:
1104
            self.graphicsView.useDefaultCommand()
1105

    
1106
        for _action in self.actionGroup.actions():
1107
            _action.setChecked(False)
1108

    
1109
        action.setChecked(True)
1110

    
1111
    '''
1112
        @brief      Create Equipment
1113
        @author     Jeongwoo
1114
        @date       18.05.03
1115
        @history    2018.05.04  Jeongwoo    Add Parameter on CreateSymbolCommand
1116
    '''
1117

    
1118
    def createEquipment(self):
1119
        if not self.graphicsView.hasImage():
1120
            self.actionEquipment.setChecked(False)
1121
            self.showImageSelectionMessageBox()
1122
            return
1123
        if self.actionEquipment.isChecked():
1124
            self.graphicsView.command = CreateSymbolCommand.CreateSymbolCommand(self.graphicsView, self.itemTreeWidget,
1125
                                                                                self.symbolTreeWidget)
1126
        else:
1127
            self.graphicsView.useDefaultCommand()
1128

    
1129
    '''
1130
        @brief      Create Nozzle
1131
        @author     Jeongwoo
1132
        @date       2018.05.03
1133
        @history    2018.05.04  Jeongwoo    Add Parameter on CreateSymbolCommand
1134
    '''
1135

    
1136
    def createNozzle(self):
1137
        if not self.graphicsView.hasImage():
1138
            self.actionNozzle.setChecked(False)
1139
            self.showImageSelectionMessageBox()
1140
            return
1141
        if self.actionNozzle.isChecked():
1142
            self.graphicsView.command = CreateSymbolCommand.CreateSymbolCommand(self.graphicsView, self.itemTreeWidget,
1143
                                                                                self.symbolTreeWidget)
1144
        else:
1145
            self.graphicsView.useDefaultCommand()
1146

    
1147
    '''
1148
        @brief      Area OCR
1149
        @author     Jeongwoo
1150
        @date       18.04.18
1151
        @history    2018.05.02  Jeongwoo    Change graphicsView.command by actionOCR checked state
1152
                                            Show MessageBox when imageviewer doesn't have image
1153
    '''
1154

    
1155
    def onAreaOcr(self):
1156
        if not self.graphicsView.hasImage():
1157
            self.actionOCR.setChecked(False)
1158
            self.showImageSelectionMessageBox()
1159
            return
1160

    
1161
        if self.actionOCR.isChecked():
1162
            cmd = AreaOcrCommand.AreaOcrCommand(self.graphicsView)
1163
            cmd.onSuccess.connect(self.onRecognizeText)
1164
            cmd.onRejected.connect(self.onCommandRejected)
1165
            self.graphicsView.command = cmd
1166
        else:
1167
            self.graphicsView.useDefaultCommand()
1168

    
1169
    '''
1170
        @brief      show text recognition dialog
1171
        @author     humkyung
1172
        @date       2018.08.08
1173
    '''
1174

    
1175
    def onRecognizeText(self, x, y, width, height):
1176
        from OcrResultDialog import QOcrResultDialog
1177
        from Area import Area
1178

    
1179
        try:
1180
            app_doc_data = AppDocData.instance()
1181

    
1182
            modifiers = QApplication.keyboardModifiers()
1183
            image = self.graphicsView.image().copy(x, y, width, height)
1184
            dialog = QOcrResultDialog(self, image, QRectF(x, y, width, height),
1185
                                      format=QOcrResultDialog.Format.Table if modifiers == Qt.AltModifier else QOcrResultDialog.Format.Normal)
1186
            if modifiers == Qt.ControlModifier:
1187
                return
1188
            (res, textInfoList) = dialog.showDialog()
1189
            if QDialog.Accepted == res and textInfoList:
1190
                for textInfo in textInfoList:
1191
                    item = QEngineeringTextItem.create_text_with(self.graphicsView.scene(), textInfo)
1192
                    if item:
1193
                        item.setDefaultTextColor(Qt.blue)
1194
                        item.transfer.onRemoved.connect(self.itemRemoved)
1195

    
1196
                        area_list = app_doc_data.getAreaList()
1197
                        title_area_list = app_doc_data.getTitleBlockProperties()
1198
                        title_list = []
1199
                        for title_area in title_area_list:
1200
                            area = Area(title_area[0])
1201
                            area.parse(title_area[2])
1202
                            title_list.append(area)
1203
                        for area in area_list + title_list:
1204
                            pt = [item.sceneBoundingRect().center().x(), item.sceneBoundingRect().center().y()]
1205
                            if area.contains(pt):
1206
                                item.area = area.name
1207
                                break
1208
                    else:
1209
                        message = 'error occurred({}) in {}:{}'.format(self.tr('Fail to create text.'),
1210
                                                                       sys.exc_info()[-1].tb_frame.f_code.co_filename, sys.exc_info()[-1].tb_lineno)
1211
                        self.addMessage.emit(MessageType.Normal, message)
1212
            elif QDialog.Accepted == res and not textInfoList:
1213
                QMessageBox.about(self.graphicsView, self.tr("Notice"), self.tr("Fail to recognize text"))
1214
        except Exception as ex:
1215
            message = 'error occurred({}) in {}:{}'.format(ex, sys.exc_info()[-1].tb_frame.f_code.co_filename,
1216
                                                           sys.exc_info()[-1].tb_lineno)
1217
            self.addMessage.emit(MessageType.Error, message)
1218

    
1219
    '''
1220
        @brief  area configuration
1221
    '''
1222

    
1223
    def areaConfiguration(self):
1224
        from ConfigurationAreaDialog import QConfigurationAreaDialog
1225
        if not self.graphicsView.hasImage():
1226
            self.showImageSelectionMessageBox()
1227
            return
1228
        self.onCommandRejected()
1229
        self.dlgConfigurationArea = QConfigurationAreaDialog(self)
1230
        self.dlgConfigurationArea.show()
1231
        self.dlgConfigurationArea.exec_()
1232

    
1233
    '''
1234
        @brief  configuration
1235
    '''
1236

    
1237
    def configuration(self):
1238
        from ConfigurationDialog import QConfigurationDialog
1239

    
1240
        self.dlgConfiguration = QConfigurationDialog(self)
1241
        # self.dlgConfiguration.show()
1242
        if QDialog.Accepted == self.dlgConfiguration.exec_():
1243
            QEngineeringLineItem.LINE_TYPE_COLORS.clear()
1244
            QEngineeringInstrumentItem.INST_COLOR = None
1245

    
1246
    '''
1247
        @brief  show special item types dialog 
1248
        @author humkyung
1249
        @date   2019.08.10
1250
    '''
1251

    
1252
    def on_show_special_item_types(self):
1253
        from SpecialItemTypesDialog import QSpecialItemTypesDialog
1254

    
1255
        dlg = QSpecialItemTypesDialog(self)
1256
        dlg.exec_()
1257

    
1258
    def on_show_data_transfer(self):
1259
        """ show data transfer dialog """
1260
        from DataTransferDialog import QDataTransferDialog
1261

    
1262
        dlg = QDataTransferDialog(self)
1263
        dlg.exec_()
1264

    
1265
    def on_show_data_export(self):
1266
        """ show data export dialog """
1267
        from DataExportDialog import QDataExportDialog
1268

    
1269
        dlg = QDataExportDialog(self)
1270
        dlg.exec_()
1271

    
1272
    def on_show_eqp_datasheet_export(self):
1273
        """ show eqp datasheet export dialog """
1274
        from EqpDatasheetExportDialog import QEqpDatasheetExportDialog
1275

    
1276
        dlg = QEqpDatasheetExportDialog(self)
1277
        dlg.exec_()
1278

    
1279
    def on_show_opc_relation(self):
1280
        """ show opc relation dialog """
1281
        from OPCRelationDialog import QOPCRelationDialog
1282

    
1283
        dlg = QOPCRelationDialog(self)
1284
        dlg.exec_()
1285

    
1286
    '''
1287
        @brief  show nominal diameter dialog 
1288
        @author humkyung
1289
        @date   2018.06.28
1290
    '''
1291

    
1292
    def onShowCodeTable(self):
1293
        from CodeTableDialog import QCodeTableDialog
1294

    
1295
        dlg = QCodeTableDialog(self)
1296
        dlg.show()
1297
        dlg.exec_()
1298
        if dlg.code_area:
1299
            if dlg.code_area.scene():
1300
                self.graphicsView.scene().removeItem(dlg.code_area)
1301
        if dlg.desc_area:
1302
            if dlg.desc_area.scene():
1303
                self.graphicsView.scene().removeItem(dlg.desc_area)
1304
        self.graphicsView.useDefaultCommand()
1305

    
1306
    def onShowCustomCodeTable(self):
1307
        from CustomCodeTablesDialog import CustomCodeTablesDialog
1308

    
1309
        dlg = CustomCodeTablesDialog(self)
1310
        dlg.show()
1311
        dlg.exec_()
1312
        self.graphicsView.useDefaultCommand()
1313

    
1314
    '''
1315
        @brief  show HMB data
1316
        @author humkyung
1317
        @date   2018.07.11
1318
    '''
1319

    
1320
    def onHMBData(self):
1321
        from HMBDialog import QHMBDialog
1322

    
1323
        dlg = QHMBDialog(self)
1324
        dlg.show()
1325
        dlg.exec_()
1326

    
1327
    '''
1328
        @brief  show line data list 
1329
        @author humkyung
1330
        @date   2018.05.03
1331
    '''
1332

    
1333
    def showItemDataList(self):
1334
        from ItemDataExportDialog import QItemDataExportDialog
1335

    
1336
        self.dlgLineDataList = QItemDataExportDialog(self)
1337
        self.dlgLineDataList.exec_()
1338

    
1339
    def showTextDataList(self):
1340
        '''
1341
            @brief      show all text item in scene
1342
            @author     euisung
1343
            @date       2019.04.18
1344
        '''
1345
        try:
1346
            if not self.graphicsView.hasImage():
1347
                self.showImageSelectionMessageBox()
1348
                return
1349

    
1350
            self.onCommandRejected()
1351
            dialog = QTextDataListDialog(self)
1352
            dialog.show()
1353
        except Exception as ex:
1354
            message = 'error occurred({}) in {}:{}'.format(ex, sys.exc_info()[-1].tb_frame.f_code.co_filename,
1355
                                                           sys.exc_info()[-1].tb_lineno)
1356
            self.addMessage.emit(MessageType.Error, message)
1357

    
1358
    '''
1359
        @brief  Show Image Selection Guide MessageBox
1360
        @author Jeongwoo
1361
        @date   2018.05.02
1362
    '''
1363

    
1364
    def showImageSelectionMessageBox(self):
1365
        QMessageBox.about(self.graphicsView, self.tr("Notice"), self.tr("First select image drawing"))
1366

    
1367
    '''
1368
        @brief  change selected lines' type by selected line type
1369
        @author humkyung
1370
        @date   2018.06.27
1371
    '''
1372

    
1373
    def onLineTypeChanged(self, param):
1374
        lineType = self.lineComboBox.itemText(param)
1375
        selected = [item for item in self.graphicsView.scene().selectedItems() if type(item) is QEngineeringLineItem]
1376
        if selected:
1377
            for item in selected:
1378
                item.lineType = lineType
1379

    
1380
    def display_colors(self, value):
1381
        """ display colors """
1382
        from DisplayColors import DisplayColors
1383
        from DisplayColors import DisplayOptions
1384

    
1385
        DisplayColors.instance().option = DisplayOptions.DisplayByLineNo if value is True else DisplayOptions.DisplayByLineType
1386
        if hasattr(self, 'graphicsView'):
1387
            self.graphicsView.scene().update(self.graphicsView.sceneRect())
1388
            DisplayColors.instance().save_data()
1389

    
1390
    def open_image_drawing(self, drawing):
1391
        """open and display image drawing file"""
1392
        from Drawing import Drawing
1393

    
1394
        try:
1395
            if not self.actionSave.isEnabled():
1396
                return
1397

    
1398
            if self.save_drawing_if_necessary():
1399
                return
1400

    
1401
            if hasattr(self, '_save_work_cmd'):
1402
                self._save_work_cmd.wait()
1403

    
1404
            app_doc_data = AppDocData.instance()
1405
            project = app_doc_data.getCurrentProject()
1406

    
1407
            #self.graphicsView.setScene(None)
1408
            self.path = self.graphicsView.loadImageFromFile(drawing)
1409
            if os.path.isfile(self.path):
1410
                self.onCommandRejected()
1411
                app_doc_data.clear()
1412

    
1413
                app_doc_data.setImgFilePath(self.path)
1414
                app_doc_data.activeDrawing = drawing
1415
                if not app_doc_data.set_occupying_drawing(app_doc_data.activeDrawing.UID):
1416
                    QMessageBox.about(self.graphicsView, self.tr("Notice"),
1417
                                      self.tr("The drawing is locked for editing by another user"))
1418
                    return
1419
                app_doc_data.activeDrawing.set_pid_source(Image.open(self.path))
1420
                self.itemTreeWidget.setCurrentPID(app_doc_data.activeDrawing.name)
1421

    
1422
                drawingList = self.treeWidgetDrawingList.topLevelItem(0)
1423
                for childIdex in range(drawingList.childCount()):
1424
                    drawingList.child(childIdex).setCheckState(0, Qt.Unchecked)
1425
                for childIdex in range(drawingList.childCount()):
1426
                    child = drawingList.child(childIdex)
1427
                    if child.text(0).replace('.png', '') == app_doc_data.activeDrawing.name:
1428
                        child.setCheckState(0, Qt.Checked)
1429
                        break
1430

    
1431
                try:
1432
                    self.show_Progress_bar()
1433

    
1434
                    # disconnect scene changed if signal is connected
1435
                    if self.graphicsView.scene().receivers(self.graphicsView.scene().contents_changed) > 0:
1436
                        self.graphicsView.scene().contents_changed.disconnect()
1437

    
1438
                    SymbolSvgItem.DOCUMENTS.clear()
1439

    
1440
                    # Load data
1441
                    path = os.path.join(app_doc_data.getCurrentProject().getTempPath(), app_doc_data.imgName + '.xml')
1442
                    configs = app_doc_data.getConfigs('Data Load', 'Xml First')
1443
                    if configs and int(configs[0].value) is 1 and os.path.isfile(path):
1444
                        self.loadRecognitionResultFromXml(path)
1445
                    else:
1446
                        self.load_drawing(app_doc_data.activeDrawing)
1447

    
1448
                    self.display_number_of_items()
1449
                    # connect scene changed signal
1450
                    self.graphicsView.scene().contents_changed.connect(self.scene_changed)
1451
                    #self.graphicsView.setScene(self.graphicsView.scene())
1452
                finally:
1453
                    if hasattr(self, 'progress'):
1454
                        self.progress.setValue(self.progress.maximum())
1455
                        # self.progress.hide()
1456

    
1457
                self.changeViewCheckedState(True)
1458
                self.setWindowTitle(self.title)
1459
        except Exception as ex:
1460
            message = 'error occurred({}) in {}:{}'.format(ex, sys.exc_info()[-1].tb_frame.f_code.co_filename,
1461
                                                           sys.exc_info()[-1].tb_lineno)
1462
            self.addMessage.emit(MessageType.Error, message)
1463

    
1464
        return self.path
1465

    
1466
    def export_as_svg(self):
1467
        """export scene to svg file"""
1468
        from ExportCommand import ExportCommand
1469

    
1470
        options = QFileDialog.Options()
1471
        options |= QFileDialog.DontUseNativeDialog
1472
        file_path, _ = QFileDialog.getSaveFileName(self, "Export as svg", os.getcwd(), "svg file(*.svg)",
1473
                                                   options=options)
1474
        if file_path:
1475
            cmd = ExportCommand(self.graphicsView.scene(), 'svg')
1476
            cmd.display_message.connect(self.onAddMessage)
1477
            if cmd.execute(file_path):
1478
                QMessageBox.information(self, self.tr('Information'), self.tr('Successfully export to svg file'))
1479
            else:
1480
                QMessageBox.information(self, self.tr('Error'), self.tr('Fail to export to svg file'))
1481

    
1482
    def export_as_xml(self):
1483
        pass
1484

    
1485
    def export_as_image(self):
1486
        """export scene to image file"""
1487
        from ExportCommand import ExportCommand
1488

    
1489
        options = QFileDialog.Options()
1490
        options |= QFileDialog.DontUseNativeDialog
1491
        file_path, _ = QFileDialog.getSaveFileName(self, "Export as png", os.getcwd(), "png file(*.png)",
1492
                                                   options=options)
1493
        if file_path:
1494
            try:
1495
                # hide image drawing
1496
                self.onViewImageDrawing(False)
1497

    
1498
                cmd = ExportCommand(self.graphicsView.scene(), 'image')
1499
                cmd.display_message.connect(self.onAddMessage)
1500

    
1501
                if cmd.execute(file_path):
1502
                    QMessageBox.information(self, self.tr('Information'), self.tr('Successfully export to image file'))
1503
                else:
1504
                    QMessageBox.information(self, self.tr('Error'), self.tr('Fail to export to image file'))
1505
            finally:
1506
                if self.actionImage_Drawing.isChecked():
1507
                    self.onViewImageDrawing(True)
1508
                    self.actionImage_Drawing.setChecked(True)
1509

    
1510
    def show_Progress_bar(self):
1511
        """ show progress bar """
1512
        self.progress = QProgressDialog(self.tr("Please wait for a while"), self.tr("Cancel"), 0, 100,
1513
                                        self) if not hasattr(self, 'progress') else self.progress
1514
        self.progress.setWindowModality(Qt.WindowModal)
1515
        self.progress.setAutoReset(True)
1516
        self.progress.setAutoClose(True)
1517
        self.progress.setMinimum(0)
1518
        self.progress.setMaximum(100)
1519
        self.progress.resize(600, 100)
1520
        self.progress.setWindowTitle(self.tr("Reading file..."))
1521
        self.progress.show()
1522

    
1523
    def changeViewCheckedState(self, checked, clear=True):
1524
        '''
1525
            @brief      change view checked state
1526
            @author     euisung
1527
            @date       2019.03.06
1528
        '''
1529
        # self.actionImage_Drawing.setChecked(checked)
1530
        self.actionViewText.setChecked(checked)
1531
        self.actionViewSymbol.setChecked(checked)
1532
        self.actionViewLine.setChecked(checked)
1533
        self.actionViewUnknown.setChecked(checked)
1534
        self.actionViewInconsistency.setChecked(checked)
1535
        self.actionViewVendor_Area.setChecked(not checked)
1536
        self.actionDrawing_Only.setChecked(not checked)
1537
        if clear:
1538
            self.tableWidgetInconsistency.clearContents()
1539
            self.tableWidgetInconsistency.setRowCount(0)
1540

    
1541
    def onViewDrawingOnly(self, isChecked):
1542
        '''
1543
            @brief  visible/invisible except image drawing
1544
            @author euisung
1545
            @date   2019.04.22
1546
        '''
1547
        self.changeViewCheckedState(not isChecked, False)
1548
        for item in self.graphicsView.scene().items():
1549
            if type(item) is not QGraphicsPixmapItem:
1550
                item.setVisible(not isChecked)
1551

    
1552
    '''
1553
        @brief  visible/invisible image drawing
1554
        @author humkyung
1555
        @date   2018.06.25
1556
    '''
1557

    
1558
    def onViewImageDrawing(self, isChecked):
1559
        for item in self.graphicsView.scene().items():
1560
            if type(item) is QGraphicsPixmapItem:
1561
                item.setVisible(isChecked)
1562
                break
1563

    
1564
    def onViewText(self, checked):
1565
        """visible/invisible text"""
1566
        selected = [item for item in self.graphicsView.scene().items() if issubclass(type(item), QEngineeringTextItem)
1567
                    and type(item) is not QEngineeringLineNoTextItem]
1568
        for item in selected:
1569
            item.setVisible(checked)
1570

    
1571
    def onViewSymbol(self, checked):
1572
        """visible/invisible symbol"""
1573
        selected = [item for item in self.graphicsView.scene().items() if
1574
                    (issubclass(type(item), SymbolSvgItem) and type(item) is not QEngineeringErrorItem)]
1575
        for item in selected:
1576
            item.setVisible(checked)
1577

    
1578
    def onViewLine(self, checked):
1579
        """visible/invisible line"""
1580
        selected = [item for item in self.graphicsView.scene().items() if type(item) is QEngineeringLineItem]
1581
        for item in selected:
1582
            item.setVisible(checked)
1583

    
1584
    def onViewInconsistency(self, isChecked):
1585
        '''
1586
            @brief  visible/invisible Inconsistency
1587
            @author euisung
1588
            @date   2019.04.03
1589
        '''
1590
        selected = [item for item in self.graphicsView.scene().items() if type(item) is QEngineeringErrorItem]
1591
        for item in selected:
1592
            item.setVisible(isChecked)
1593

    
1594
    '''
1595
        @brief  visible/invisible Unknown 
1596
        @author humkyung
1597
        @date   2018.06.28
1598
    '''
1599

    
1600
    def onViewUnknown(self, isChecked):
1601
        selected = [item for item in self.graphicsView.scene().items() if type(item) is QEngineeringUnknownItem]
1602
        for item in selected:
1603
            item.setVisible(isChecked)
1604

    
1605
    def onViewVendorArea(self, isChecked):
1606
        '''
1607
            @brief  visible/invisible Vendor Area
1608
            @author euisung
1609
            @date   2019.04.29
1610
        '''
1611
        selected = [item for item in self.graphicsView.scene().items() if type(item) is QEngineeringVendorItem]
1612
        for item in selected:
1613
            item.setVisible(isChecked)
1614

    
1615
    '''
1616
        @brief  create a symbol
1617
        @history    2018.05.02  Jeongwoo    Change return value of QSymbolEditorDialog (Single variable → Tuple)
1618
                                            Add SymbolSvgItem
1619
                    2018.05.03  Jeongwoo    Change method to draw Svg Item on Scene (svg.addSvgItemToScene)
1620
                                            Change method to make svg and image path
1621
                    2018.06.08  Jeongwoo    Add Paramter on SymbolSvgItem.buildItem()
1622
    '''
1623

    
1624
    def onCreateSymbolClicked(self):
1625
        cmd = FenceCommand.FenceCommand(self.graphicsView)
1626
        cmd.onSuccess.connect(self.onAreaSelected)
1627
        self.graphicsView.command = cmd
1628
        QApplication.setOverrideCursor(Qt.CrossCursor)
1629

    
1630
    '''
1631
        @brief      show SymbolEditorDialog with image selected by user
1632
        @author     humkyung
1633
        @date       2018.07.20
1634
    '''
1635

    
1636
    def onAreaSelected(self, x, y, width, height):
1637
        try:
1638
            image = self.graphicsView.image()
1639
            if image is not None:
1640
                symbolEditorDialog = SymbolEditorDialog.QSymbolEditorDialog(self, image.copy(x, y, width, height),
1641
                                                                            AppDocData.instance().getCurrentProject())
1642
                (isAccepted, isImmediateInsert, offsetX, offsetY, newSym) = symbolEditorDialog.showDialog()
1643
                self.symbolTreeWidget.initDirTreeWidget()
1644
                if isAccepted:
1645
                    if isImmediateInsert:
1646
                        svgPath = newSym.getSvgFileFullPath()
1647
                        img = cv2.imread(newSym.getImageFileFullPath(), 1)
1648
                        w, h = (0, 0)
1649
                        if len(img.shape[::-1]) == 2:
1650
                            w, h = img.shape[::-1]
1651
                        else:
1652
                            _chan, w, h = img.shape[::-1]
1653
                        svg = SymbolSvgItem(svgPath)
1654
                        svg.buildItem(newSym.getName(), newSym.getType(), 0, [offsetX, offsetY], [w, h],
1655
                                      [float(x) for x in newSym.getOriginalPoint().split(',')],
1656
                                      [(float(x.split(',')[0]), float(x.split(',')[1])) for x in
1657
                                       newSym.getConnectionPoint().split('/')], newSym.getBaseSymbol(),
1658
                                      newSym.getAdditionalSymbol(), newSym.getHasInstrumentLabel)
1659

    
1660
                        svg.transfer.onRemoved.connect(self.itemTreeWidget.itemRemoved)
1661
                        svg.addSvgItemToScene(self.graphicsView.scene())
1662
                        for connector in svg.connectors:
1663
                            self.graphicsView.scene().addItem(connector)
1664
        finally:
1665
            self.onCommandRejected()
1666
            QApplication.restoreOverrideCursor()
1667

    
1668
    '''
1669
        @brief      create a line
1670
        @author     humkyung
1671
        @history    Jeongwoo 2018.05.10 Change method for Checkable action
1672
    '''
1673

    
1674
    def onPlaceLine(self):
1675
        if not self.graphicsView.hasImage():
1676
            self.actionLine.setChecked(False)
1677
            self.showImageSelectionMessageBox()
1678
            return
1679

    
1680
        self.actionLine.setChecked(True)
1681
        if not hasattr(self.actionLine, 'tag'):
1682
            self.actionLine.tag = PlaceLineCommand.PlaceLineCommand(self.graphicsView)
1683
            self.actionLine.tag.onSuccess.connect(self.onLineCreated)
1684
            self.actionLine.tag.onRejected.connect(self.onCommandRejected)
1685

    
1686
        self.graphicsView.command = self.actionLine.tag
1687

    
1688
    '''
1689
        @brief      add created lines to scene
1690
        @author     humkyung
1691
        @date       2018.07.23
1692
    '''
1693

    
1694
    def onLineCreated(self):
1695
        from EngineeringConnectorItem import QEngineeringConnectorItem
1696
        from LineDetector import LineDetector
1697

    
1698
        try:
1699
            app_doc_data = AppDocData.instance()
1700

    
1701
            count = len(self.actionLine.tag._polyline._vertices)
1702
            if count > 1:
1703
                items = []
1704

    
1705
                detector = LineDetector(None)
1706

    
1707
                lineType = self.lineComboBox.currentText()
1708
                for index in range(count - 1):
1709
                    start = self.actionLine.tag._polyline._vertices[index]
1710
                    end = self.actionLine.tag._polyline._vertices[index + 1]
1711

    
1712
                    lineItem = QEngineeringLineItem(vertices=[start, end])
1713
                    lineItem.transfer.onRemoved.connect(self.itemRemoved)
1714
                    lineItem.lineType = lineType
1715
                    if items:
1716
                        lineItem.connect_if_possible(items[-1], 5)
1717
                    else:
1718
                        pt = lineItem.start_point()
1719
                        selected = [item for item in self.graphicsView.scene().items(QPointF(pt[0], pt[1])) if
1720
                                    type(item) is QEngineeringConnectorItem or type(item) is QEngineeringLineItem]
1721
                        if selected and selected[0] is not lineItem:
1722
                            if type(selected[0]) is QEngineeringConnectorItem:
1723
                                lineItem.connect_if_possible(selected[0].parent, 5)
1724
                            else:
1725
                                detector.connectLineToLine(selected[0], lineItem, 5)
1726

    
1727
                    items.append(lineItem)
1728
                    self.graphicsView.scene().addItem(lineItem)
1729
                    app_doc_data.lines.append(lineItem)
1730

    
1731
                pt = items[-1].end_point()
1732
                selected = [item for item in self.graphicsView.scene().items(QPointF(pt[0], pt[1])) if
1733
                            (type(item) is QEngineeringConnectorItem and item.parentItem() is not items[-1]) or
1734
                            (type(item) is QEngineeringLineItem and item is not items[-1])]
1735
                if selected and selected[0] is not items[-1]:
1736
                    if type(selected[0]) is QEngineeringConnectorItem:
1737
                        items[-1].connect_if_possible(selected[0].parent, 5)
1738
                    else:
1739
                        detector.connectLineToLine(selected[0], items[-1], 5)
1740

    
1741
        finally:
1742
            self.graphicsView.scene().removeItem(self.actionLine.tag._polyline)
1743
            self.actionLine.tag.reset()
1744

    
1745
    '''
1746
        @brief      refresh scene
1747
        @author     humkyung
1748
        @date       2018.07.23
1749
    '''
1750

    
1751
    def onCommandRejected(self, cmd=None):
1752
        try:
1753
            if type(cmd) is PlaceLineCommand.PlaceLineCommand:
1754
                if self.actionLine.tag._polyline:
1755
                    self.graphicsView.scene().removeItem(self.actionLine.tag._polyline)
1756
                self.graphicsView.scene().update()
1757
                self.actionLine.tag.reset()
1758

    
1759
                self.actionLine.setChecked(False)
1760
            elif type(cmd) is AreaZoomCommand.AreaZoomCommand:
1761
                self.actionZoom.setChecked(False)
1762
            elif type(cmd) is AreaOcrCommand.AreaOcrCommand:
1763
                self.actionOCR.setChecked(False)
1764
            elif type(cmd) is PlacePolygonCommand.PlacePolygonCommand:
1765
                self.actionVendor.setChecked(False)
1766
            else:
1767
                if hasattr(self.actionLine, 'tag') and self.actionLine.tag._polyline:
1768
                    self.graphicsView.scene().removeItem(self.actionLine.tag._polyline)
1769
                    self.graphicsView.scene().update()
1770
                    self.actionLine.tag.reset()
1771
                if hasattr(self.actionVendor, 'tag') and self.actionVendor.tag._polyline:
1772
                    self.graphicsView.scene().removeItem(self.actionVendor.tag._polyline)
1773
                    self.graphicsView.scene().update()
1774
                    self.actionVendor.tag.reset()
1775
                self.actionLine.setChecked(False)
1776
                self.actionZoom.setChecked(False)
1777
                self.actionOCR.setChecked(False)
1778
                self.actionVendor.setChecked(False)
1779
        finally:
1780
            self.graphicsView.useDefaultCommand()
1781

    
1782
    '''
1783
        @brief      restore to default command when user press Escape key
1784
        @author     humkyung 
1785
        @date       2018.08.09
1786
        
1787
    '''
1788

    
1789
    def keyPressEvent(self, event):
1790
        try:
1791
            if event.key() == Qt.Key_Escape:
1792
                checked = self.actionGroup.checkedAction()
1793
                if checked:
1794
                    checked.setChecked(False)
1795
                    self.graphicsView.useDefaultCommand()
1796
            elif event.key() == Qt.Key_1:
1797
                if self.actionImage_Drawing.isChecked():
1798
                    self.onViewImageDrawing(False)
1799
                    self.actionImage_Drawing.setChecked(False)
1800
                else:
1801
                    self.onViewImageDrawing(True)
1802
                    self.actionImage_Drawing.setChecked(True)
1803
            elif event.key() == Qt.Key_2:
1804
                if self.actionViewText.isChecked():
1805
                    self.onViewText(False)
1806
                    self.actionViewText.setChecked(False)
1807
                else:
1808
                    self.onViewText(True)
1809
                    self.actionViewText.setChecked(True)
1810
            elif event.key() == Qt.Key_3:
1811
                if self.actionViewSymbol.isChecked():
1812
                    self.onViewSymbol(False)
1813
                    self.actionViewSymbol.setChecked(False)
1814
                else:
1815
                    self.onViewSymbol(True)
1816
                    self.actionViewSymbol.setChecked(True)
1817
            elif event.key() == Qt.Key_4:
1818
                if self.actionViewLine.isChecked():
1819
                    self.onViewLine(False)
1820
                    self.actionViewLine.setChecked(False)
1821
                else:
1822
                    self.onViewLine(True)
1823
                    self.actionViewLine.setChecked(True)
1824
            elif event.key() == Qt.Key_5:
1825
                if self.actionViewUnknown.isChecked():
1826
                    self.onViewUnknown(False)
1827
                    self.actionViewUnknown.setChecked(False)
1828
                else:
1829
                    self.onViewUnknown(True)
1830
                    self.actionViewUnknown.setChecked(True)
1831
            elif event.key() == Qt.Key_6:
1832
                if self.actionViewInconsistency.isChecked():
1833
                    self.onViewInconsistency(False)
1834
                    self.actionViewInconsistency.setChecked(False)
1835
                else:
1836
                    self.onViewInconsistency(True)
1837
                    self.actionViewInconsistency.setChecked(True)
1838
            elif event.key() == Qt.Key_7:
1839
                if self.actionViewVendor_Area.isChecked():
1840
                    self.onViewVendorArea(False)
1841
                    self.actionViewVendor_Area.setChecked(False)
1842
                else:
1843
                    self.onViewVendorArea(True)
1844
                    self.actionViewVendor_Area.setChecked(True)
1845
            elif event.key() == 96:  # '`' key
1846
                if self.actionDrawing_Only.isChecked():
1847
                    self.onViewDrawingOnly(False)
1848
                    self.actionDrawing_Only.setChecked(False)
1849
                else:
1850
                    self.onViewDrawingOnly(True)
1851
                    self.actionDrawing_Only.setChecked(True)
1852
            elif event.key() == Qt.Key_M:  # merge text as vertical
1853
                from TextInfo import TextInfo
1854

    
1855
                textItems = [text for text in self.graphicsView.scene().selectedItems() if
1856
                             type(text) is QEngineeringTextItem]
1857
                if not textItems or len(textItems) is 1:
1858
                    return
1859

    
1860
                angle = None
1861
                for item in textItems:
1862
                    if angle is None:
1863
                        angle = item.angle
1864
                    else:
1865
                        if angle != item.angle:
1866
                            return
1867

    
1868
                modifiers = QApplication.keyboardModifiers()
1869
                enter_or_space = ' ' if modifiers == Qt.ControlModifier else '\n'
1870
                x_or_y = 0 if modifiers == Qt.ControlModifier else 1
1871

    
1872
                textItems = sorted(textItems, key=lambda text: text.loc[x_or_y]) if textItems[0].angle == 0 else ( \
1873
                    sorted(textItems, key=lambda text: text.loc[x_or_y]) if textItems[0].angle == 1.57 else ( \
1874
                        sorted(textItems, key=lambda text: text.loc[x_or_y], reverse=True) if textItems[0].angle == 4.71 else \
1875
                            sorted(textItems, key=lambda text: text.loc[x_or_y], reverse=True)))
1876

    
1877
                if textItems[0].angle == 1.57 and modifiers == Qt.ControlModifier:
1878
                    textItems.reverse()
1879

    
1880
                minX = sys.maxsize
1881
                minY = sys.maxsize
1882
                maxX = 0
1883
                maxY = 0
1884
                newText = ''
1885

    
1886
                for text in textItems:
1887
                    if text.loc[0] < minX: minX = text.loc[0]
1888
                    if text.loc[1] < minY: minY = text.loc[1]
1889
                    if text.loc[0] + text.size[0] > maxX: maxX = text.loc[0] + text.size[0]
1890
                    if text.loc[1] + text.size[1] > maxY: maxY = text.loc[1] + text.size[1]
1891
                    newText = newText + text.text() + enter_or_space
1892
                    text.transfer.onRemoved.emit(text)
1893
                newText = newText[:-1]
1894

    
1895
                textInfo = TextInfo(newText, minX, minY, maxX - minX, maxY - minY, textItems[0].angle)
1896
                x = textInfo.getX()
1897
                y = textInfo.getY()
1898
                angle = textInfo.getAngle()
1899
                text = textInfo.getText()
1900
                width = textInfo.getW()
1901
                height = textInfo.getH()
1902
                item = TextItemFactory.instance().createTextItem(textInfo)
1903
                if item is not None:
1904
                    item.loc = [x, y]
1905
                    item.size = (width, height)
1906
                    item.angle = angle
1907
                    item.setDefaultTextColor(Qt.blue)
1908
                    item.addTextItemToScene(self.graphicsView.scene())
1909
                    item.transfer.onRemoved.connect(self.itemRemoved)
1910
            elif event.key() == Qt.Key_D:
1911
                # pop up development toolkit dialog
1912
                from DevelopmentToolkitDialog import QDevelopmentToolkitDialog
1913

    
1914
                modifiers = QApplication.keyboardModifiers()
1915
                if modifiers == Qt.ControlModifier:
1916
                    dlg = QDevelopmentToolkitDialog(self, self.graphicsView)
1917
                    dlg.show()
1918
            elif event.key() == Qt.Key_I:
1919
                # insert symbol item that is selected symbol in tree to main window if symbol already selected on main window, replace
1920
                items = self.symbolTreeWidget.selectedItems()
1921
                if items and hasattr(items[0], 'svgFilePath'):
1922
                    symData = items[0].data(0, self.symbolTreeWidget.TREE_DATA_ROLE)
1923
                    symName = symData.getName()
1924
                else:
1925
                    return
1926

    
1927
                symbolItems = [symbol for symbol in self.graphicsView.scene().selectedItems() if
1928
                               issubclass(type(symbol), SymbolSvgItem)]
1929
                old_symbol = None
1930
                if symbolItems and len(symbolItems) is 1:
1931
                    old_symbol = symbolItems[0]
1932
                    scenePos = QPoint(old_symbol.origin[0], old_symbol.origin[1])
1933
                    old_symbol.transfer.onRemoved.emit(old_symbol)
1934
                else:
1935
                    scenePos = self.current_pos
1936

    
1937
                svg = self.graphicsView.createSymbolObject(symName)
1938
                self.graphicsView.matchSymbolToLine(svg, scenePos)
1939

    
1940
                if old_symbol:
1941
                    return
1942
            elif event.key() == Qt.Key_X:
1943
                app_doc_data = AppDocData.instance()
1944
                configs = app_doc_data.getAppConfigs('app', 'mode')
1945
                if configs and 1 == len(configs) and 'advanced' == configs[0].value:
1946
                    advanced = True
1947
                    items = self.graphicsView.scene().selectedItems()
1948
                    if items:
1949
                        item = self.symbolTreeWidget.currentItem()
1950
                        if item:
1951
                            self.symbolTreeWidget.showSymbolEditorDialog(item, 0)
1952

    
1953
            QMainWindow.keyPressEvent(self, event)
1954
        except Exception as ex:
1955
            message = 'error occurred({}) in {}:{}'.format(ex, sys.exc_info()[-1].tb_frame.f_code.co_filename,
1956
                                                           sys.exc_info()[-1].tb_lineno)
1957
            self.addMessage.emit(MessageType.Error, message)
1958

    
1959
    def recognizeBatch(self, MainWindow):
1960
        '''
1961
            @brief      batch recognize symbol, text and line
1962
            @author     euisung
1963
            @date       2018.11.23
1964
        
1965
        '''
1966
        from datetime import datetime
1967
        from RecognitionDialog import QRecognitionDialog
1968

    
1969
        app_doc_data = AppDocData.instance()
1970
        project = app_doc_data.getCurrentProject()
1971
        app_doc_data.needReOpening = None
1972
        current_drawing, currentPid = None, None
1973

    
1974
        if self.graphicsView.hasImage():
1975
            current_drawing = app_doc_data.activeDrawing
1976
            currentPid = app_doc_data.activeDrawing.name
1977

    
1978
        # TODO: 무슨 의미인지 주석 필요
1979
        drawingTop = self.treeWidgetDrawingList.topLevelItem(0)
1980
        drawingCount = drawingTop.childCount()
1981
        checkedTreeItems = []
1982
        checkedDrawingPath = []
1983
        for drawing in range(drawingCount):
1984
            drawingChild = drawingTop.child(drawing)
1985
            if drawingChild.checkState(0) == 2:
1986
                checkedTreeItems.append(drawingChild)
1987
                checkedDrawingPath.append(os.path.join(project.getDrawingFilePath(), drawingChild.data(0, 0)))
1988
                if currentPid is not None and drawingChild.data(0, 0).find(currentPid) is 0:
1989
                    app_doc_data.needReOpening = False  # later check need reopening at drawUnknownItems()
1990
                    currentPid = drawingChild.data(0, 0)
1991
        # up to here
1992

    
1993
        if len(checkedDrawingPath) == 0:
1994
            self.showImageSelectionMessageBox()
1995
            return
1996

    
1997
        try:
1998
            self.onClearLog()
1999
            self.dlg = QRecognitionDialog(self, checkedDrawingPath, True)
2000
            self.dlg.exec_()
2001
            if self.dlg.isAccepted == True:
2002
                pass
2003

    
2004
            if app_doc_data.needReOpening == True:
2005
                self.open_image_drawing(current_drawing)
2006

    
2007
            # save working date-time
2008
            drawings = app_doc_data.getDrawings()
2009
            checkedDrawings = []
2010
            for checkedTreeItem in checkedTreeItems:
2011
                for drawing in drawings:
2012
                    if checkedTreeItem.data(0, 0) == drawing.name:
2013
                        if drawing:
2014
                            drawing.datetime = datetime.now().strftime('%Y-%m-%d %H:%M:%S')
2015
                            checkedDrawings.append(drawing)
2016
                            checkedTreeItem.setText(1, datetime.now().strftime('%Y-%m-%d %H:%M:%S'))
2017
            app_doc_data.saveDrawings(checkedDrawings)
2018
            self.changeViewCheckedState(True)
2019
            # up to here
2020
        except Exception as ex:
2021
            message = 'error occurred({}) in {}:{}'.format(repr(ex), sys.exc_info()[-1].tb_frame.f_code.co_filename,
2022
                                                           sys.exc_info()[-1].tb_lineno)
2023
            self.addMessage.emit(MessageType.Error, message)
2024

    
2025
    '''
2026
        @brief      recognize symbol and text
2027
        @author     humkyung
2028
        @date       2018.04.??
2029
        @history    2018.04.16  humkyung    execute line no tracing
2030
                    2018.05.02  Jeongwoo    Show MessageBox when imageviewer doesn't have image
2031
                    2018.05.25  Jeongwoo    Add parameter on QRecognitionDialog.__init__() and Move thread to QRecognitionDialog
2032
                                            Remove codes below if self.dlg.isAccepted == True
2033
                    2018.05.29  Jeongwoo    Remove connects and comments
2034
                    humkyung 2018.11.05 save working date-time
2035
    '''
2036

    
2037
    def recognize(self, MainWindow):
2038
        from datetime import datetime
2039
        from RecognitionDialog import QRecognitionDialog
2040

    
2041
        if not self.graphicsView.hasImage():
2042
            self.showImageSelectionMessageBox()
2043
            return
2044

    
2045
        try:
2046
            appDocData = AppDocData.instance()
2047

    
2048
            self.onClearLog()
2049
            appDocData.needReOpening = False
2050
            drawingList = []
2051
            drawingList.append(self.path)
2052
            self.dlg = QRecognitionDialog(self, drawingList, False)
2053
            self.dlg.exec_()
2054

    
2055
            if appDocData.needReOpening:
2056
                self.itemTreeWidget.setCurrentPID(appDocData.activeDrawing.name)
2057
                self.drawDetectedItemsToScene()
2058

    
2059
                # save working date-time
2060
                drawings = appDocData.getDrawings()
2061
                drawing = [drawing for drawing in drawings if appDocData.imgName == os.path.splitext(drawing.name)[0]]
2062
                if drawing[0]:
2063
                    drawing[0].datetime = datetime.now().strftime('%Y-%m-%d %H:%M:%S')
2064
                    appDocData.saveDrawings(drawing)
2065

    
2066
                currentPid = appDocData.activeDrawing.name
2067

    
2068
                drawingTop = self.treeWidgetDrawingList.topLevelItem(0)
2069
                drawingCount = drawingTop.childCount()
2070

    
2071
                for drawing in range(drawingCount):
2072
                    drawingChild = drawingTop.child(drawing)
2073
                    if drawingChild.data(0, 0).find(currentPid) is 0:
2074
                        drawingChild.setText(1, datetime.now().strftime('%Y-%m-%d %H:%M:%S'))
2075
                self.changeViewCheckedState(True)
2076
                # up to here
2077
        except Exception as ex:
2078
            message = 'error occurred({}) in {}:{}'.format(ex, sys.exc_info()[-1].tb_frame.f_code.co_filename,
2079
                                                           sys.exc_info()[-1].tb_lineno)
2080
            self.addMessage.emit(MessageType.Error, message)
2081

    
2082
    '''
2083
        @brief      remove item from tree widget and then remove from scene
2084
        @date       2018.05.25
2085
        @author     Jeongwoo
2086
    '''
2087

    
2088
    def itemRemoved(self, item):
2089
        try:
2090
            if type(item) is QEngineeringErrorItem:
2091
                # remove error item from inconsistency list
2092
                for row in range(self.tableWidgetInconsistency.rowCount()):
2093
                    if item is self.tableWidgetInconsistency.item(row, 0).tag:
2094
                        self.tableWidgetInconsistency.removeRow(row)
2095
                        break
2096

    
2097
                if item.scene() is not None: item.scene().removeItem(item)
2098
                del item
2099
            else:
2100
                self.itemTreeWidget.itemRemoved(item)
2101

    
2102
                matches = [_item for _item in self.graphicsView.scene().items() if
2103
                           hasattr(_item, 'connectors') and [connector for connector in _item.connectors if
2104
                                                             connector.connectedItem is item]]
2105
                for match in matches:
2106
                    for connector in match.connectors:
2107
                        if connector.connectedItem is item:
2108
                            connector.connectedItem = None
2109
                            connector.highlight(False)
2110

    
2111
                # matches = [_item for _item in self.graphicsView.scene().items() if hasattr(_item, 'remove_assoc_item')]
2112
                # for _item in matches:
2113
                #    _item.remove_assoc_item(item)
2114

    
2115
                app_doc_data = AppDocData.instance()
2116
                if type(item) is QEngineeringLineNoTextItem and item in app_doc_data.tracerLineNos:
2117
                    app_doc_data.tracerLineNos.pop(app_doc_data.tracerLineNos.index(item))
2118

    
2119
                if type(item) is QEngineeringLineItem and item in app_doc_data.lines:
2120
                    app_doc_data.lines.remove(item)
2121

    
2122
                matches = [_item for _item in self.graphicsView.scene().items() if
2123
                           type(_item) is QEngineeringLineNoTextItem]
2124
                matches.extend([lineNo for lineNo in app_doc_data.tracerLineNos if
2125
                                type(lineNo) is QEngineeringTrimLineNoTextItem])
2126
                for match in matches:
2127
                    if item is match.prop('From'):
2128
                        match.set_property('From', None)
2129
                    if item is match.prop('To'):
2130
                        match.set_property('To', None)
2131

    
2132
                    for run_index in reversed(range(len(match.runs))):
2133
                        run = match.runs[run_index]
2134
                        if item in run.items:
2135
                            index = run.items.index(item)
2136
                            run.items.pop(index)
2137
                            if not run.items:
2138
                                run.explode()
2139
                                if type(match) is QEngineeringTrimLineNoTextItem and not match.runs:
2140
                                    app_doc_data.tracerLineNos.pop(app_doc_data.tracerLineNos.index(match))
2141
                            # break
2142

    
2143
                matches = [_item for _item in self.graphicsView.scene().items() if hasattr(_item, 'owner')]
2144
                for match in matches:
2145
                    if match.owner is item:
2146
                        match.owner = None
2147

    
2148
                matches = [_item for _item in self.graphicsView.scene().items() if hasattr(_item, 'attrs')]
2149
                # done = False
2150
                for match in matches:
2151
                    assocs = match.associations()
2152
                    for assoc in assocs:
2153
                        if item is assoc:
2154
                            for attr in match.attrs.keys():
2155
                                if attr.AssocItem and str(item.uid) == str(attr.AssocItem.uid):
2156
                                    attr.AssocItem = None
2157
                                    match.attrs[attr] = ''
2158
                                    # done = True
2159
                            match.remove_assoc_item(item)
2160
                            break
2161
                    # if done: break
2162

    
2163
                if item.scene() is not None: item.scene().removeItem(item)
2164
        except Exception as ex:
2165
            message = 'error occurred({}) in {}:{}'.format(ex, sys.exc_info()[-1].tb_frame.f_code.co_filename,
2166
                                                           sys.exc_info()[-1].tb_lineno)
2167
            self.addMessage.emit(MessageType.Error, message)
2168

    
2169
    '''
2170
        @brief      recognize line
2171
        @author     humkyung
2172
        @date       2018.04.19
2173
        @history    Jeongwoo 2018.04.26 Variable name changed (texts → lineNos)
2174
                                        TextItem type changed (QEngineeringTextItem → QEngineeringLineNoTextItem)
2175
                    humkyung 2018.04.26 remove small objects before recognizing line
2176
                    Jeongwoo 2018.05.02 Show MessageBox when imageviewer doesn't have image
2177
                    Jeongwoo 2018.05.25 Move codes about LineDetector
2178
                    humkyung 2018.06.17 show progress dialog
2179
    '''
2180

    
2181
    def connect_attributes(self, MainWindow):
2182
        from LineNoTracer import LineNoTracer
2183
        from ConnectAttrDialog import QConnectAttrDialog
2184

    
2185
        if not self.graphicsView.hasImage():
2186
            self.showImageSelectionMessageBox()
2187
            return
2188

    
2189
        try:
2190
            dlg = QConnectAttrDialog(self, self.graphicsView.scene())
2191
            dlg.setWindowFlags(self.windowFlags() & ~Qt.WindowCloseButtonHint & ~Qt.WindowContextHelpButtonHint)
2192
            dlg.exec_()
2193
            if dlg.isRunned:
2194
                self.itemTreeWidget.InitLineNoItems()
2195

    
2196
                # construct line no item
2197
                line_nos = AppDocData.instance().tracerLineNos
2198
                for line_no in line_nos:
2199
                    item = self.itemTreeWidget.addTreeItem(self.itemTreeWidget.root, line_no)
2200
                    connectedItems = line_no.getConnectedItems()
2201
                    for connectedItem in connectedItems:
2202
                        if issubclass(type(connectedItem), SymbolSvgItem):
2203
                            self.itemTreeWidget.addTreeItem(item, connectedItem)
2204
                # up to here
2205

    
2206
                if dlg.validation_checked:
2207
                    self.onValidation()
2208

    
2209
                self.graphicsView.invalidateScene()
2210
        except Exception as ex:
2211
            message = 'error occurred({}) in {}:{}'.format(ex, sys.exc_info()[-1].tb_frame.f_code.co_filename,
2212
                                                           sys.exc_info()[-1].tb_lineno)
2213
            self.addMessage.emit(MessageType.Error, message)
2214

    
2215
    '''
2216
        @history    2018.05.25  Jeongwoo    Moved from MainWindow
2217
                                            SvgItem and TextItem Connect with method in this class
2218
                                            Change method to add GraphicsItem
2219
                    2018.05.28  Jeongwoo    Make QGraphicsItem by symbol, text object. Not xml
2220
                    2018.05.29  Jeongwoo    Change method name and Moved from QRecognitionDialog
2221
                    2018.05.30  Jeongwoo    Add parameters on SymbolSvgItem.__init__() (parentSymbol, childSymbol)
2222
                                            Change Method name and seperate each item
2223
                    humkyung 2018.06.11     display difference between original and recognized image
2224
                    Jeongwoo 2018.06.18     Update Scene after all item added
2225
                    2018.11.05  euisung     add save note item because of dependency
2226
                    2018.11.05  euisung     add db delete process before save
2227
                    2018.11.12  euisung     add title block properties
2228
                    2018.11.12  euisung     db part move new method to dbUpdate
2229
                    2018.11.26  euisung     isolate scene adding part -> drawDetectedItemsToScene()
2230
                    2018.11.29  euisung     change name drawDetectedItems() -> createDetectedItems
2231
    '''
2232

    
2233
    def createDetectedItems(self, symbolList, textInfoList, otherTextInfoList, titleBlockTextInfoList):
2234
        try:
2235
            QApplication.processEvents()
2236
            self.createDetectedSymbolItem(symbolList)
2237
            QApplication.processEvents()
2238
            self.createDetectedTextItem(textInfoList)
2239
            QApplication.processEvents()
2240
            self.createDetectedOtherTextItem(otherTextInfoList)
2241
            QApplication.processEvents()
2242
            self.createDetectedTitleBlockTextItem(titleBlockTextInfoList)
2243

    
2244
            # update scene
2245
            # self.graphicsView.scene().update(self.graphicsView.sceneRect())
2246
        except Exception as ex:
2247
            message = 'error occurred({}) in {}:{}'.format(ex, sys.exc_info()[-1].tb_frame.f_code.co_filename,
2248
                                                           sys.exc_info()[-1].tb_lineno)
2249
            self.addMessage.emit(MessageType.Error, message)
2250

    
2251
    def drawDetectedItemsToScene(self):
2252
        '''
2253
            @brief  add detected items to scene
2254
            @author euisung
2255
            @date   2018.11.26
2256
        '''
2257
        appDocData = AppDocData.instance()
2258

    
2259
        try:
2260
            for symbol in appDocData.symbols:
2261
                if issubclass(type(symbol), SymbolSvgItem):
2262
                    self.addSvgItemToScene(symbol)
2263
                else:
2264
                    self.graphicsView.scene().addItem(symbol)
2265

    
2266
            for text in appDocData.texts:
2267
                self.addTextItemToScene(text)
2268

    
2269
            for lineNo in appDocData.tracerLineNos:
2270
                self.addTextItemToScene(lineNo)
2271

    
2272
            for line in appDocData.lines:
2273
                self.graphicsView.scene().addItem(line)
2274
                line.transfer.onRemoved.connect(self.itemRemoved)
2275
                for conn in line.connectors:
2276
                    conn.transfer.onPosChanged.connect(line.onConnectorPosChaned)
2277

    
2278
            for unknown in appDocData.unknowns + appDocData.lineIndicators:
2279
                self.graphicsView.scene().addItem(unknown)
2280
        finally:
2281
            # update scene
2282
            self.graphicsView.scene().update(self.graphicsView.sceneRect())
2283

    
2284
    def postDetectLineProcess(self):
2285
        '''
2286
            @brief  check allowables among undetected items
2287
            @author euisung
2288
            @date   2018.11.15
2289
            @history    2018.11.15  euisung    no more used, moved to TextItemFactoy isLineNo()
2290
        '''
2291
        from TextItemFactory import TextItemFactory
2292

    
2293
        appDocData = AppDocData.instance()
2294

    
2295
        tableNames = ["Fluid Code", "Insulation Purpose", "PnID Number", "Piping Materials Class", "Unit Number"]
2296
        tableDatas = []
2297
        for tableName in tableNames:
2298
            tableNameFormat = tableName.replace(' ', '').replace('&&', 'n')
2299
            tableDatas.append(appDocData.getCodeTable(tableNameFormat))
2300

    
2301
        items = self.graphicsView.scene().items()
2302
        for item in items:
2303
            if type(item) is not QEngineeringTextItem:
2304
                continue
2305
            text = item.text()
2306
            for tableData in tableDatas:
2307
                for data in tableData:
2308
                    if data[3] == '':
2309
                        continue
2310
                    else:
2311
                        allows = data[3].split(',')
2312
                        for allow in allows:
2313
                            text = text.replace(allow, data[1])
2314

    
2315
            lineItem = TextItemFactory.instance().createTextItem(text)
2316
            if type(lineItem) is QEngineeringLineNoTextItem:
2317
                lineItem.loc = item.loc
2318
                lineItem.size = item.size
2319
                lineItem.angle = item.angle
2320
                lineItem.area = item.area
2321
                # lineItem.addTextItemToScene(self.graphicsView.scene())
2322
                lineItem.transfer.onRemoved.connect(self.itemRemoved)
2323
                item.transfer.onRemoved.emit(item)
2324
                appDocData.lineNos.append(lineItem)
2325

    
2326
    def createDetectedTitleBlockTextItem(self, textInfoList):
2327
        '''
2328
            @brief  draw title block
2329
            @author euisung
2330
            @date   2018.11.12
2331
            @history    2018.11.26  euisung     remove scene dependency
2332
                        2018.11.29  euisung     change name drawDetectedTitleBlockTextItem() -> createDetectedTitleBlockTextItem
2333
        '''
2334
        from TextItemFactory import TextItemFactory
2335
        import math
2336

    
2337
        try:
2338
            appDocData = AppDocData.instance()
2339

    
2340
            # parse texts
2341
            for textInfos in textInfoList:
2342
                if len(textInfos[1]) is 0:
2343
                    continue
2344

    
2345
                for textInfo in textInfos[1]:
2346
                    x = textInfo.getX()
2347
                    y = textInfo.getY()
2348
                    width = textInfo.getW()
2349
                    height = textInfo.getH()
2350
                    angle = round(math.radians(textInfo.getAngle()), 2)
2351
                    text = textInfo.getText()
2352
                    if not text: continue
2353
                    item = TextItemFactory.instance().createTextItem(textInfo)
2354

    
2355
                    if item is not None:
2356
                        item.loc = [x, y]
2357
                        item.size = (width, height)
2358
                        item.angle = angle
2359
                        item.area = textInfos[0]
2360
                        # self.addTextItemToScene(item)
2361
                        # appDocData.texts.append(item)
2362
                        appDocData.allItems.append(item)
2363
        except Exception as ex:
2364
            message = 'error occurred({}) in {}:{}'.format(ex, sys.exc_info()[-1].tb_frame.f_code.co_filename,
2365
                                                           sys.exc_info()[-1].tb_lineno)
2366
            self.addMessage.emit(MessageType.Error, message)
2367

    
2368
    '''
2369
        @brief      
2370
        @author     humkyung
2371
        @date       2018.08.23
2372
        @history    2018.11.26  euisung     remove scene dependency
2373
                    2018.11.26  euisung     isolate scene adding part -> drawDetectedItemsToScene()
2374
                    2018.11.    euisung     no more used
2375
                    2018.11.29  euisung     change name drawDetectedLines() -> createDetectedLines
2376
    '''
2377

    
2378
    def createDetectedLines(self, lineList, worker):
2379
        appDocData = AppDocData.instance()
2380
        area = appDocData.getArea('Drawing')
2381

    
2382
        for pts in lineList:
2383
            processLine = QEngineeringLineItem(vertices=[(area.x + param[0], area.y + param[1]) for param in pts])
2384
            processLine.area = 'Drawing'
2385
            # self.graphicsView.scene().addItem(processLine)
2386
            appDocData.lines.append(processLine)
2387
            appDocData.allItems.append(processLine)
2388

    
2389
            # if processLine.length() > 100: # TODO: check critical length
2390
            #    processLine.addFlowArrow()
2391

    
2392
        # re-order process line's start,end according to flow mark
2393
        # worker.arrangeLinePosition(lines, symbols, listWidget)
2394
        # up to here
2395

    
2396
    '''
2397
        history     2018.06.09  humkyung    check length of original and connection point is 2 while parsing
2398
                    2018.11.26  euisung     remove scene dependency
2399
                    2018.11.29  euisung     change name drawDetectedSymbolItem() -> createDetectedSymbolItem
2400
    '''
2401

    
2402
    def createDetectedSymbolItem(self, symbolList):
2403
        from GraphicsBoundingBoxItem import QGraphicsBoundingBoxItem
2404
        from SymbolSvgItem import SymbolSvgItem
2405
        import math
2406

    
2407
        try:
2408
            appDocData = AppDocData.instance()
2409
            project = appDocData.getCurrentProject()
2410

    
2411
            searchedMap = []
2412
            for symbol in symbolList:
2413
                pt = [float(x) for x in symbol.getSp()]
2414
                size = [symbol.getWidth(), symbol.getHeight()]
2415
                name = symbol.getName()
2416
                angle = round(math.radians(symbol.getRotatedAngle()), 2)
2417
                _type = symbol.getType()
2418
                flip = symbol.getDetectFlip()
2419
                origin = [0, 0]
2420
                if 2 == len(symbol.getOriginalPoint().split(',')):
2421
                    tokens = symbol.getOriginalPoint().split(',')
2422
                    origin = [pt[0] + float(tokens[0]), pt[1] + float(tokens[1])]
2423
                connPts = []
2424
                if symbol.getConnectionPoint() is not None and symbol.getConnectionPoint() != '':
2425
                    for param in symbol.getConnectionPoint().split('/'):
2426
                        tokens = param.split(',')
2427
                        connPts.append(
2428
                            ('AUTO', pt[0] + float(tokens[0]), pt[1] + float(tokens[1]), '0') if len(tokens) == 2 else \
2429
                                (tokens[0], pt[0] + float(tokens[1]), pt[1] + float(tokens[2]), '0') if len(
2430
                                    tokens) == 3 else \
2431
                                    (tokens[0], pt[0] + float(tokens[1]), pt[1] + float(tokens[2]), tokens[3]) if len(
2432
                                        tokens) == 4 else None)
2433

    
2434
                parentSymbol = symbol.getBaseSymbol()
2435
                childSymbol = symbol.getAdditionalSymbol()
2436
                hasInstrumentLabel = symbol.getHasInstrumentLabel()
2437

    
2438
                svgFilePath = os.path.join(project.getSvgFilePath(), _type, name + '.svg')
2439
                if os.path.isfile(svgFilePath):
2440
                    svg = SymbolSvgItem.createItem(_type, None, svgFilePath, owner=None, flip=flip)
2441
                    svg.hit_ratio = symbol.hitRate
2442
                    svg.buildItem(name, _type, angle, pt, size, origin, connPts, parentSymbol, childSymbol,
2443
                                  hasInstrumentLabel)
2444
                    svg.reCalculationRotatedItem()
2445
                    svg.area = 'Drawing'
2446

    
2447
                    # set owner - 2018.07.20 added by humkyung                   
2448
                    matches = [searched for searched in searchedMap if searched[0] == symbol.owner]
2449
                    if len(matches) == 1:
2450
                        svg.owner = matches[0][1]
2451
                    searchedMap.append((symbol, svg))
2452
                    # up to here
2453

    
2454
                    svg.transfer.onRemoved.connect(self.itemRemoved)
2455
                    # self.addSvgItemToScene(svg)
2456
                    appDocData.symbols.append(svg)
2457
                    appDocData.allItems.append(svg)
2458
                else:
2459
                    item = QGraphicsBoundingBoxItem(pt[0], pt[1], size[0], size[1])
2460
                    item.isSymbol = True
2461
                    item.angle = angle
2462
                    item.setPen(QPen(Qt.red, 5, Qt.SolidLine))
2463
                    # self.graphicsView.scene().addItem(item)
2464
                    # appDocData.symbols.append(item)
2465
                    appDocData.allItems.append(item)
2466
            # up to here
2467
        except Exception as ex:
2468
            message = 'error occurred({}) in {}:{}'.format(ex, sys.exc_info()[-1].tb_frame.f_code.co_filename,
2469
                                                           sys.exc_info()[-1].tb_lineno)
2470
            self.addMessage.emit(MessageType.Error, message)
2471

    
2472
    '''
2473
        @history    2018.06.08  Jeongwoo    Add parameter on round method
2474
        @history    2018.11.02  euisung     Add save note text item
2475
        @history    2018.11.05  euisung     delete save note text item and move to drawDetectedItems()
2476
                    2018.11.26  euisung     remove scene dependency
2477
                    2018.11.29  euisung     change name drawDetectedTextItem() -> createDetectedTextItem
2478
    '''
2479

    
2480
    def createDetectedTextItem(self, textInfoList):
2481
        from TextItemFactory import TextItemFactory
2482
        import math
2483

    
2484
        try:
2485
            appDocData = AppDocData.instance()
2486

    
2487
            # parse texts
2488
            for textInfo in textInfoList:
2489
                x = textInfo.getX()
2490
                y = textInfo.getY()
2491
                width = textInfo.getW()
2492
                height = textInfo.getH()
2493
                angle = round(math.radians(textInfo.getAngle()), 2)
2494
                text = textInfo.getText()
2495
                if not text: continue
2496

    
2497
                item = TextItemFactory.instance().createTextItem(textInfo)
2498
                if item is not None:
2499
                    item.loc = [x, y]
2500
                    item.size = (width, height)
2501
                    item.angle = angle
2502
                    item.area = 'Drawing'
2503
                    item.transfer.onRemoved.connect(self.itemRemoved)
2504
                    # self.addTextItemToScene(item)
2505
                    # appDocData.texts.append(item)
2506
                    appDocData.allItems.append(item)
2507
        except Exception as ex:
2508
            message = 'error occurred({}) in {}:{}'.format(ex, sys.exc_info()[-1].tb_frame.f_code.co_filename,
2509
                                                           sys.exc_info()[-1].tb_lineno)
2510
            self.addMessage.emit(MessageType.Error, message)
2511

    
2512
    '''
2513
        @brief      draw detected texts except which in drawing area
2514
        @history    2018.11.29  euisung     change name drawDetectedOtherTextItem() -> createDetectedOtherTextItem
2515
    '''
2516

    
2517
    def createDetectedOtherTextItem(self, otherTextInfoList):
2518
        from TextItemFactory import TextItemFactory
2519
        import math
2520

    
2521
        try:
2522
            appDocData = AppDocData.instance()
2523

    
2524
            # parse notes
2525
            for textInfoMap in otherTextInfoList:
2526
                if textInfoMap[0] == 'Note' or textInfoMap[1] is None:
2527
                    pass
2528

    
2529
                for textInfo in textInfoMap[1]:
2530
                    x = textInfo.getX()
2531
                    y = textInfo.getY()
2532
                    width = textInfo.getW()
2533
                    height = textInfo.getH()
2534
                    angle = round(math.radians(textInfo.getAngle()))
2535
                    text = textInfo.getText()
2536

    
2537
                    item = TextItemFactory.instance().createTextItem(textInfo)
2538

    
2539
                    item.loc = [x, y]
2540
                    item.size = (width, height)
2541
                    item.angle = angle
2542
                    item.area = textInfoMap[0]
2543
                    item.transfer.onRemoved.connect(self.itemRemoved)
2544
                    # appDocData.texts.append(item)
2545
                    appDocData.allItems.append(item)
2546
        except Exception as ex:
2547
            message = 'error occurred({}) in {}:{}'.format(ex, sys.exc_info()[-1].tb_frame.f_code.co_filename,
2548
                                                           sys.exc_info()[-1].tb_lineno)
2549
            self.addMessage.emit(MessageType.Error, message)
2550

    
2551
    '''
2552
        @brief  draw unknown items 
2553
        @author humkyung
2554
        @date   2018.06.12
2555
        @history    2018.06.14  Jeongwoo    Change method to add unknown item
2556
                    2018.06.18  Jeongwoo    Add connect on unknown item
2557
                                            Add [transfer] for using pyqtSignal
2558
                    2018.11.26  euisung     remove scene dependency
2559
                    2018.11.26  euisung     isolate scene adding part -> drawDetectedItemsToScene()
2560
                    2018.11.27  euisung     add save to xml
2561
                    2018.11.29  euisung     change name drawUnknownItems() -> createUnknownItems
2562
    '''
2563

    
2564
    def createUnknownItems(self, path):
2565
        from QEngineeringFlowArrowItem import QEngineeringFlowArrowItem
2566
        from EngineeringLineItem import QEngineeringLineItem
2567
        from EngineeringUnknownItem import QEngineeringUnknownItem
2568
        from SaveWorkCommand import SaveWorkCommand
2569

    
2570
        try:
2571
            docData = AppDocData.instance()
2572
            project = docData.getCurrentProject()
2573
            windowSize = docData.getSlidingWindowSize()
2574

    
2575
            thickness = int(windowSize[1])
2576

    
2577
            if docData.needReOpening is not None:
2578
                docData.needReOpening = True
2579

    
2580
            diffFilePath = os.path.join(project.getTempPath(), "DIFF_" + os.path.basename(path))
2581
            if os.path.isfile(diffFilePath):
2582
                imgDiff = cv2.threshold(cv2.cvtColor(cv2.imread(diffFilePath, 1), cv2.COLOR_BGR2GRAY), 0, 255,
2583
                                        cv2.THRESH_BINARY + cv2.THRESH_OTSU)[1]
2584

    
2585
                # remove line from image
2586
                lines = docData.lines
2587
                for line in lines:
2588
                    line.drawToImage(imgDiff, 255, thickness) if line.thickness is None else \
2589
                        line.drawToImage(imgDiff, 255, line.thickness)
2590
                cv2.imwrite(diffFilePath, imgDiff)
2591
                # up to here
2592

    
2593
                imgNot = np.ones(imgDiff.shape, np.uint8)
2594
                cv2.bitwise_not(imgDiff, imgNot)
2595
                configs = docData.getConfigs('Filter', 'ErodeSize')
2596
                kernel = int(configs[0].value) if 1 == len(configs) else 3
2597
                imgNot = cv2.erode(imgNot, np.ones((kernel, kernel), np.uint8))
2598
                imgNot = cv2.dilate(imgNot, np.ones((8 + kernel, 8 + kernel), np.uint8))
2599

    
2600
                contours, hierarchy = cv2.findContours(imgNot, cv2.RETR_EXTERNAL, cv2.CHAIN_APPROX_SIMPLE)
2601

    
2602
                ##
2603
                idx = 0
2604
                ##
2605
                smallContours = []
2606
                minimumSize = docData.getConfigs('Filter', 'MinimumSize')
2607
                for contour in contours:
2608
                    [x, y, w, h] = cv2.boundingRect(contour)
2609

    
2610
                    # remove too small one
2611
                    if len(minimumSize) is 1:
2612
                        if (w * h < int(minimumSize[0].value) * int(minimumSize[0].value)):
2613
                            smallContours.append(contour)
2614
                            idx += 1
2615
                            continue
2616

    
2617
                    '''
2618
                    rect = QRectF(x, y, w, h)
2619
                    items = [item for item in diffItems if item.boundingRect().contains(rect)]
2620
                    if len(items) > 0: continue
2621
                    
2622
                    items = [item for item in diffItems if rect.contains(item.boundingRect())]
2623
                    for item in items:
2624
                        diffItems.remove(item)
2625
                    '''
2626

    
2627
                    # create unknown item
2628
                    epsilon = cv2.arcLength(contour, True) * 0.001
2629
                    approx = cv2.approxPolyDP(contour, epsilon, True)
2630
                    approx = [pt[0] for pt in approx]
2631
                    resultStr, resultList = self.determineRemainObject(idx, contours, imgNot)
2632
                    if resultStr == 'LineIndicator':
2633
                        item = QEngineeringUnknownItem(approx, 'True', resultList[0], resultList[1])
2634
                        docData.lineIndicators.append(item)
2635
                    elif resultStr == 'MissingLine':
2636
                        pass
2637
                    elif resultStr == 'Unknown':
2638
                        item = QEngineeringUnknownItem(approx, 'False')
2639
                        docData.unknowns.append(item)
2640
                    item.area = 'Drawing'
2641
                    docData.allItems.append(item)
2642
                    item.transfer.onRemoved.connect(self.itemRemoved)
2643
                    idx += 1
2644
                    # up to here                    
2645

    
2646
                imgNotRemoveSmall = cv2.drawContours(imgNot, smallContours, -1, 0, -1)
2647
                notFilePath = os.path.join(project.getTempPath(), "NOT_" + os.path.basename(path))
2648
                cv2.imwrite(notFilePath, imgNotRemoveSmall)
2649
            else:
2650
                message = 'can\'t found {}'.format(diffFilePath)
2651
                self.addMessage.emit(MessageType.Normal, message)
2652

    
2653
            self.dbUpdate()
2654
            SaveWorkCommand.save_to_xml()
2655
        except Exception as ex:
2656
            message = 'error occurred({}) in {}:{}'.format(ex, sys.exc_info()[-1].tb_frame.f_code.co_filename,
2657
                                                           sys.exc_info()[-1].tb_lineno)
2658
            self.addMessage.emit(MessageType.Error, message)
2659

    
2660
    def determineRemainObject(self, idx, contours, imgNot):
2661
        '''
2662
            @brief      determine remain objects -> line no indicator or unknown
2663
            @author     euisung
2664
            @date       2018.12.26
2665
            @history    2019.03.25  euisung    Change name isLineNoIndicator -> determineRemainObject
2666
        '''
2667
        import math
2668
        [x, y, w, h] = cv2.boundingRect(contours[idx])
2669

    
2670
        if (w < 250 and h < 250):
2671
            return ('Unknown', [])
2672

    
2673
        fLines = []
2674
        maxDifAngle = 3
2675
        mask = np.zeros_like(imgNot)
2676
        cv2.drawContours(mask, contours, idx, 123, -1)  # Draw filled contour in mask
2677
        out = np.zeros_like(imgNot)  # Extract out the object and place into output image
2678
        out[mask == 123] = imgNot[mask == 123]
2679

    
2680
        # Now crop
2681
        ##print(out)
2682
        (x, y) = np.where(mask == 123)
2683
        (topx, topy) = (np.min(x), np.min(y))
2684
        (bottomx, bottomy) = (np.max(x), np.max(y))
2685
        out = out[topx:bottomx + 1, topy:bottomy + 1]
2686
        h, w = out.shape[0], out.shape[1]
2687
        maxDifH, maxDifW = math.ceil(math.tan(4 * math.pi / 180) / 2 * w), math.ceil(
2688
            math.tan(4 * math.pi / 180) / 2 * h)
2689

    
2690
        # detection lines
2691
        edged2 = cv2.Canny(out, 100, 200)
2692
        lines = cv2.HoughLinesP(image=edged2, rho=1, theta=np.pi / 180, threshold=25, minLineLength=30, maxLineGap=25)
2693
        # lines = cv2.HoughLines(edged2, 1, np.pi/180, 60)
2694
        if lines is None:
2695
            return ('Unknown', [])
2696
        for line in lines:
2697
            # r, theta = line[0]
2698
            # a, b = np.cos(theta), np.sin(theta)
2699
            # x0, y0 = a * r, b * r
2700
            # x1, y1 = int(x0 + 1000 * (-b)), int(y0 + 1000 * a)
2701
            # x2, y2 = int(x0 - 1000 * (-b)), int(y0 - 1000 * a)
2702
            # cv2.line(out, (x1, y1), (x2, y2), (0, 255, 0), 3)
2703
            x1, y1, x2, y2 = line[0]
2704
            degree = math.atan2(y2 - y1, x2 - x1) * 180 / math.pi
2705
            fLine = [x1, y1, x2, y2, degree]
2706
            # print(fLine)
2707
            fLines.append(fLine)
2708

    
2709
        horLines = []
2710
        verLines = []
2711
        otherLines = []
2712
        isVH = None
2713
        for fLine in fLines:
2714
            degree = math.fabs(fLine[4])
2715
            if degree >= 90 - maxDifAngle:
2716
                verLines.append(fLine)
2717
            elif degree <= maxDifAngle:
2718
                horLines.append(fLine)
2719
            else:
2720
                otherLines.append(fLine)
2721

    
2722
        baseLines = []
2723
        baseDifV = 0
2724
        if len(horLines):
2725
            x, y = w / 2, 0
2726
            baseDifV = maxDifH
2727
            for horLine in horLines:
2728
                x1, y1, x2, y2 = horLine[0], horLine[1], horLine[2], horLine[3]
2729
                y = ((y2 - y1) / (x2 - x1)) * x + y1 - ((y2 - y1) / (x2 - x1)) * x1
2730
                horLine.append(y)
2731
            baseLines = horLines
2732
            isVH = 'H'
2733
        if len(verLines):
2734
            x, y = 0, h / 2
2735
            baseDifV = maxDifW
2736
            for verLine in verLines:
2737
                x1, y1, x2, y2 = verLine[0], verLine[1], verLine[2], verLine[3]
2738
                x = ((x2 - x1) / (y2 - y1)) * y + x1 - ((x2 - x1) / (y2 - y1)) * y1
2739
                verLine.append(x)
2740
            baseLines = verLines
2741
            isVH = 'V'
2742

    
2743
        for otherLine in otherLines:
2744
            x, y = w / 2, 0
2745
            x1, y1, x2, y2 = otherLine[0], otherLine[1], otherLine[2], otherLine[3]
2746
            y = ((y2 - y1) / (x2 - x1)) * x + y1 - ((y2 - y1) / (x2 - x1)) * x1
2747
            otherLine.append(y)
2748

    
2749
        # determine line no indicator 
2750
        if not ((len(horLines) > 0 and len(verLines) > 0) or len(otherLines) is 0 or (
2751
                len(horLines) == 0 and len(verLines) == 0)):
2752
            result, mergedOtherLine = self.isLineNoIndicator(w, h, maxDifAngle, baseDifV, baseLines, otherLines)
2753
            if result:
2754
                # print(fLines)
2755
                return ('LineIndicator', [isVH, mergedOtherLine])
2756

    
2757
        return ('Unknown', [])
2758

    
2759
    def isLineNoIndicator(self, w, h, maxDifAngle, baseDifV, baseLines, otherLines):
2760
        '''
2761
            @brief      determine line no indicator
2762
            @author     euisung
2763
            @date       2019.03.25
2764
        '''
2765
        import math
2766

    
2767
        if (w < 250 and h < 250):
2768
            return (False, None)
2769

    
2770
        isSameLine = True
2771
        i = 0
2772
        for baseLine in baseLines:
2773
            if not isSameLine: break
2774
            j = 0
2775
            for baseLinee in baseLines:
2776
                if i == j:
2777
                    j += 1
2778
                    continue
2779
                difV = math.fabs(baseLine[5] - baseLinee[5])
2780
                if difV > baseDifV:
2781
                    isSameLine = False
2782
                    break
2783
                j += 1
2784
            i += 1
2785
        if not isSameLine:
2786
            return (False, None)
2787

    
2788
        isSameLine = True
2789
        i = 0
2790
        maxY = 0
2791
        for otherLine in otherLines:
2792
            y = otherLine[5]
2793
            if math.fabs(y) > maxY:
2794
                maxY = math.fabs(y)
2795
            if not isSameLine: break
2796
            j = 0
2797
            for otherLinee in otherLines:
2798
                if i == j:
2799
                    j += 1
2800
                    continue
2801
                difV = math.fabs(otherLine[4] - otherLinee[4])
2802
                if difV > maxDifAngle:
2803
                    isSameLine = False
2804
                    break
2805
                j += 1
2806
            i += 1
2807
        if not isSameLine:
2808
            return (False, None)
2809

    
2810
        isSameLine = True
2811
        mergedOtherLine = [0, 0, 0, 0]
2812
        i = 0
2813
        maxDif = math.ceil(math.tan(4 * math.pi / 180) * maxY)
2814
        for otherLine in otherLines:
2815
            if not isSameLine: break
2816
            j = 0
2817
            for otherLinee in otherLines:
2818
                if i == j:
2819
                    j += 1
2820
                    continue
2821
                angle = math.fabs(otherLine[4] + otherLinee[4]) / 2
2822
                difV = math.fabs(otherLine[5] - otherLinee[5])
2823
                dist = math.sin((90 - angle) * math.pi / 180) * difV
2824
                if dist > maxDif:
2825
                    isSameLine = False
2826
                    break
2827
                j += 1
2828
            i += 1
2829
            mergedOtherLine[0] += otherLine[0]
2830
            mergedOtherLine[1] += otherLine[1]
2831
            mergedOtherLine[2] += otherLine[2]
2832
            mergedOtherLine[3] += otherLine[3]
2833
        if not isSameLine:
2834
            (False, None)
2835

    
2836
        # Show the output image
2837
        # print('line no indicator')
2838
        mergedOtherLine[0] = round(mergedOtherLine[0] / len(otherLines))
2839
        mergedOtherLine[1] = round(mergedOtherLine[1] / len(otherLines))
2840
        mergedOtherLine[2] = round(mergedOtherLine[2] / len(otherLines))
2841
        mergedOtherLine[3] = round(mergedOtherLine[3] / len(otherLines))
2842
        # cv2.line(out, (mergedOtherLine[0], mergedOtherLine[1]), (mergedOtherLine[2], mergedOtherLine[3]), (255, 255, 255), 3)
2843
        # cv2.imshow('Output', out)
2844
        # cv2.waitKey(0)
2845
        # cv2.destroyAllWindows()
2846
        return (True, mergedOtherLine)
2847

    
2848
    def init_add_tree_item(self, line_no_tree_item, run_item):
2849
        """ insert symbol item and find line no as owner """
2850
        # insert
2851
        self.itemTreeWidget.addTreeItem(line_no_tree_item, run_item)
2852
        # find
2853
        self.itemTreeWidget.addTreeItem(line_no_tree_item, run_item)
2854

    
2855
    def load_drawing(self, drawing):
2856
        """ load drawing """
2857
        from EngineeringRunItem import QEngineeringRunItem
2858
        from QEngineeringTrimLineNoTextItem import QEngineeringTrimLineNoTextItem
2859

    
2860
        app_doc_data = AppDocData.instance()
2861
        try:
2862
            symbols = []
2863
            lines = []
2864

    
2865
            components = app_doc_data.get_components(drawing.UID)
2866
            maxValue = len(components) * 2
2867
            self.progress.setMaximum(maxValue) if maxValue > 0 else None
2868

    
2869
            """ parsing all symbols """
2870
            for symbol in [component for component in components if int(component['SymbolType_UID']) != -1]:
2871
                item = SymbolSvgItem.from_database(symbol)
2872
                if item is not None:
2873
                    item.transfer.onRemoved.connect(self.itemRemoved)
2874
                    symbols.append(item)
2875
                    app_doc_data.symbols.append(item)
2876
                    self.addSvgItemToScene(item)
2877
                else:
2878
                    pt = [float(symbol['X']), float(symbol['Y'])]
2879
                    size = [float(symbol['Width']), float(symbol['Height'])]
2880
                    angle = float(symbol['Rotation'])
2881
                    item = QGraphicsBoundingBoxItem(pt[0], pt[1], size[0], size[1])
2882
                    item.isSymbol = True
2883
                    item.angle = angle
2884
                    item.setPen(QPen(Qt.red, 5, Qt.SolidLine))
2885
                    self.graphicsView.scene().addItem(item)
2886
                    item.transfer.onRemoved.connect(self.itemRemoved)
2887

    
2888
                self.progress.setValue(self.progress.value() + 1)
2889

    
2890
            QApplication.processEvents()
2891

    
2892
            # parse texts
2893
            for text in [component for component in components if
2894
                         component['Name'] == 'Text' and component['SymbolType_UID'] == -1]:
2895
                item = QEngineeringTextItem.from_database(text)
2896
                if item is not None:
2897
                    item.uid = text['UID']
2898
                    item.attribute = text['Value']
2899
                    name = text['Name']
2900
                    item.transfer.onRemoved.connect(self.itemRemoved)
2901
                    self.addTextItemToScene(item)
2902

    
2903
                self.progress.setValue(self.progress.value() + 1)
2904

    
2905
            QApplication.processEvents()
2906

    
2907
            # note
2908
            for note in [component for component in components if
2909
                         component['Name'] == 'Note' and component['SymbolType_UID'] == -1]:
2910
                item = QEngineeringTextItem.from_database(note)
2911
                if item is not None:
2912
                    item.uid = note['UID']
2913
                    attributeValue = note['Value']
2914
                    name = note['Name']
2915
                    item.transfer.onRemoved.connect(self.itemRemoved)
2916
                    self.addTextItemToScene(item)
2917

    
2918
                self.progress.setValue(self.progress.value() + 1)
2919

    
2920
            QApplication.processEvents()
2921

    
2922
            for line in [component for component in components if
2923
                         component['Name'] == 'Line' and component['SymbolType_UID'] == -1]:
2924
                item = QEngineeringLineItem.from_database(line)
2925
                if item:
2926
                    item.transfer.onRemoved.connect(self.itemRemoved)
2927
                    self.graphicsView.scene().addItem(item)
2928
                    lines.append(item)
2929

    
2930
                self.progress.setValue(self.progress.value() + 1)
2931

    
2932
            QApplication.processEvents()
2933

    
2934
            for unknown in [component for component in components if
2935
                            component['Name'] == 'Unknown' and component['SymbolType_UID'] == -1]:
2936
                item = QEngineeringUnknownItem.from_database(unknown)
2937
                item.transfer.onRemoved.connect(self.itemRemoved)
2938
                if item is not None:
2939
                    item.transfer.onRemoved.connect(self.itemRemoved)
2940
                    self.graphicsView.scene().addItem(item)
2941

    
2942
                self.progress.setValue(self.progress.value() + 1)
2943

    
2944
            QApplication.processEvents()
2945

    
2946
            for component in [component for component in components if
2947
                              component['Name'] == 'Line NO' and component['SymbolType_UID'] == -1]:
2948
                line_no = QEngineeringLineNoTextItem.from_database(component)
2949
                if type(line_no) is QEngineeringLineNoTextItem:
2950
                    line_no.transfer.onRemoved.connect(self.itemRemoved)
2951
                    self.addTextItemToScene(line_no)
2952
                    line_no_tree_item = self.itemTreeWidget.addTreeItem(self.itemTreeWidget.root, line_no)
2953

    
2954
                    runs = app_doc_data.get_pipe_runs(str(line_no.uid))
2955
                    if not runs: continue
2956
                    for run in runs:
2957
                        line_run = QEngineeringRunItem()
2958
                        run_items = app_doc_data.get_pipe_run_items(run['UID'])
2959
                        for record in run_items:
2960
                            uid = record['Components_UID']
2961
                            run_item = self.graphicsView.findItemByUid(uid)
2962
                            if run_item is not None:
2963
                                run_item._owner = line_no
2964
                                line_run.items.append(run_item)
2965
                        line_run.owner = line_no
2966
                        line_no.runs.append(line_run)
2967

    
2968
                        for run_item in line_run.items:
2969
                            if issubclass(type(run_item), SymbolSvgItem):
2970
                                self.init_add_tree_item(line_no_tree_item, run_item)
2971

    
2972
                self.progress.setValue(self.progress.value() + 1)
2973
            QApplication.processEvents()
2974

    
2975
            for component in [component for component in components if
2976
                              component['Name'] == 'Trim Line NO' and component['SymbolType_UID'] == -1]:
2977
                line_no = QEngineeringTrimLineNoTextItem()
2978
                line_no.uid = uuid.UUID(component['UID'])
2979

    
2980
                runs = app_doc_data.get_pipe_runs(str(line_no.uid))
2981
                if not runs: continue
2982

    
2983
                line_no_tree_item = self.itemTreeWidget.addTreeItem(self.itemTreeWidget.root, line_no)
2984

    
2985
                for run in runs:
2986
                    line_run = QEngineeringRunItem()
2987
                    run_items = app_doc_data.get_pipe_run_items(run['UID'])
2988
                    for record in run_items:
2989
                        uid = record['Components_UID']
2990
                        run_item = self.graphicsView.findItemByUid(uid)
2991
                        if run_item is not None:
2992
                            run_item.owner = line_no
2993
                            line_run.items.append(run_item)
2994
                    line_run.owner = line_no
2995
                    line_no.runs.append(line_run)
2996

    
2997
                    for run_item in line_run.items:
2998
                        if issubclass(type(run_item), SymbolSvgItem):
2999
                            self.init_add_tree_item(line_no_tree_item, run_item)
3000

    
3001
                app_doc_data.tracerLineNos.append(line_no)
3002

    
3003
                self.progress.setValue(self.progress.value() + 1)
3004

    
3005
            for component in [component for component in components if
3006
                              component['Name'] == 'VendorPackage' and component['SymbolType_UID'] == -1]:
3007
                item = QEngineeringVendorItem.from_database(component)
3008
                if item is not None:
3009
                    item.transfer.onRemoved.connect(self.itemRemoved)
3010
                    self.graphicsView.scene().addItem(item)
3011

    
3012
            # connect flow item to line
3013
            for line in lines:
3014
                line.update_arrow()
3015
                app_doc_data.lines.append(line)
3016
            # for flowMark in [item for item in symbols if type(item) is QEngineeringFlowMarkItem]:
3017
            #    for line in lines:
3018
            #        if flowMark.owner is line:
3019
            #            line._flowMark.append(flowMark)
3020
            #            flowMark.setParentItem(line)
3021
            # up to here
3022

    
3023
            """ update scene """
3024
            self.graphicsView.scene().update(self.graphicsView.sceneRect())
3025
            for item in self.graphicsView.scene().items():
3026
                up_progress = False
3027
                # binding items
3028
                if hasattr(item, 'owner'):
3029
                    item.owner
3030
                    up_progress = True
3031
                if hasattr(item, 'connectors'):
3032
                    for connector in item.connectors:
3033
                        connector.connectedItem
3034
                    up_progress = True
3035

    
3036
                if up_progress:
3037
                    self.progress.setValue(self.progress.value() + 1)
3038
            
3039
            for item in self.graphicsView.scene().items():
3040
                item.setVisible(True)
3041

    
3042
        except Exception as ex:
3043
            message = 'error occurred({}) in {}:{}'.format(ex, sys.exc_info()[-1].tb_frame.f_code.co_filename,
3044
                                                           sys.exc_info()[-1].tb_lineno)
3045
            self.addMessage.emit(MessageType.Error, message)
3046
        finally:
3047
            app_doc_data.clearTempDBData()
3048
            self.itemTreeWidget.update_item_count()
3049
            self.itemTreeWidget.expandAll()
3050
            # self.graphicsView.scene().blockSignals(False)
3051

    
3052
    '''
3053
        @brief      load recognition result
3054
        @author     humkyung
3055
        @date       2018.04.??
3056
        @history    humkyung 2018.01.12 parse originalpoint and connectionpoint
3057
                    Jeongwoo 2018.04.17 add QGraphicItem with Rotated text
3058
                    Jeongwoo 2018.04.23 Change to Draw texts on QEngineeringTextItem
3059
                    humkyung 2018.04.23 connect item remove slot to result tree
3060
                    Jeongwoo 2018.04.25 Add if state with QEngineeringNoteItem
3061
                    Jeongwoo 2018.04.26 Change method to create TextItem object with TextItemFactory
3062
                    Jeongwoo 2018.05.03 Change method to draw Svg Item on Scene (svg.addSvgItemToScene)
3063
                    Jeongwoo 2018.05.29 Change method name / Change method to add item / Add Line item
3064
                    Jeongwoo 2018.05.30 Add parameters on SymbolSvgItem.__init__() (parentSymbol, childSymbol) / Change method name / Change XML NODE NAMES
3065
                    Jeongwoo 2018.06.12 Add LineNoTextItem from LINE_NO
3066
                    Jeongwoo 2018.06.14 Add UnknownItem from UNKNOWN
3067
                    Jeongwoo 2018.06.18 Update Scene after all item added
3068
                                        Add connect on unknown item
3069
                                        Add [transfer] for using pyqtSignal
3070
                    kyouho  2018.07.12  Add line property logic
3071
                    humkyung 2018.08.22 show progress while loading xml file
3072
                    2018.11.22      euisung     fix note road
3073
    '''
3074

    
3075
    def loadRecognitionResultFromXml(self, xmlPath):
3076
        # Yield successive n-sized
3077
        # chunks from l.
3078
        def divide_chunks(l, n):
3079
            # looping till length l
3080
            for i in range(0, len(l), n):
3081
                yield l[i:i + n]
3082

    
3083
        def update_items(items):
3084
            for item in items:
3085
                # binding items
3086
                item.owner
3087
                for connector in item.connectors:
3088
                    connector.connectedItem
3089

    
3090
            return items
3091

    
3092
        import concurrent.futures as futures
3093
        from xml.etree.ElementTree import Element, SubElement, dump, ElementTree, parse
3094
        from App import App
3095
        from EngineeringRunItem import QEngineeringRunItem
3096
        from QEngineeringTrimLineNoTextItem import QEngineeringTrimLineNoTextItem
3097
        from EngineeringGraphicsLineItem import QEngineeringGraphicsLineItem
3098

    
3099
        docData = AppDocData.instance()
3100

    
3101
        try:
3102
            self.graphicsView.scene().blockSignals(True)
3103

    
3104
            symbols = []
3105
            lines = []
3106

    
3107
            xml = parse(xmlPath)
3108
            root = xml.getroot()
3109

    
3110
            maxValue = 0
3111
            maxValue = maxValue + len(list(root.iter('SYMBOL'))) - len(
3112
                list(root.iterfind('LINENOS/LINE_NO/RUN/SYMBOL'))) - len(
3113
                list(root.iterfind('TRIMLINENOS/TRIM_LINE_NO/RUN/SYMBOL')))
3114
            maxValue = maxValue + len(list(root.iterfind('TEXTINFOS/ATTRIBUTE')))
3115
            maxValue = maxValue + len(list(root.iterfind('NOTES/ATTRIBUTE')))
3116
            maxValue = maxValue + len(list(root.iter('LINE_NO')))
3117
            maxValue = maxValue + len(list(root.iter('LINE'))) - len(
3118
                list(root.iterfind('LINENOS/LINE_NO/RUN/LINE'))) - len(
3119
                list(root.iterfind('TRIMLINENOS/TRIM_LINE_NO/RUN/LINE')))
3120
            maxValue = maxValue + len(list(root.iter('GRAPHICS_LINE')))
3121
            maxValue = maxValue + len(list(root.iter('UNKNOWN')))
3122
            # maxValue = maxValue + len(list(root.iter('SIZETEXT')))
3123
            maxValue = maxValue + len(list(root.iter('TRIM_LINE_NO')))
3124
            maxValue *= 2
3125
            self.progress.setMaximum(maxValue) if maxValue > 0 else None
3126

    
3127
            """ parsing all symbols """
3128
            """
3129
            with futures.ThreadPoolExecutor(max_workers=App.THREAD_MAX_WORKER) as pool:
3130
                future_symbol = {pool.submit(SymbolSvgItem.fromXml, symbol): symbol for symbol in root.find('SYMBOLS').iter('SYMBOL')}
3131

3132
                for future in futures.as_completed(future_symbol):
3133
                    try:
3134
                        item = future.result()
3135
                        if item:
3136
                            if item is not None:
3137
                                item.transfer.onRemoved.connect(self.itemRemoved)
3138
                                symbols.append(item)
3139
                                docData.symbols.append(item)
3140
                                self.addSvgItemToScene(item)
3141
                            else:
3142
                                pt = [float(x) for x in symbol.find('LOCATION').text.split(',')]
3143
                                size = [float(x) for x in symbol.find('SIZE').text.split(',')]
3144
                                angle = float(symbol.find('ANGLE').text)
3145
                                item = QGraphicsBoundingBoxItem(pt[0], pt[1], size[0], size[1])
3146
                                item.isSymbol = True
3147
                                item.angle = angle
3148
                                item.setPen(QPen(Qt.red, 5, Qt.SolidLine))
3149
                                self.graphicsView.scene().addItem(item)
3150
                                item.transfer.onRemoved.connect(self.itemRemoved)
3151
                    except Exception as ex:
3152
                        message = 'error occurred({}) in {}:{}'.format(repr(ex), sys.exc_info()[-1].tb_frame.f_code.co_filename,
3153
                                                                       sys.exc_info()[-1].tb_lineno)
3154

3155
            """
3156
            for symbol in root.find('SYMBOLS').iter('SYMBOL'):
3157
                item = SymbolSvgItem.fromXml(symbol)
3158
                if item is not None:
3159
                    item.transfer.onRemoved.connect(self.itemRemoved)
3160
                    symbols.append(item)
3161
                    docData.symbols.append(item)
3162
                    item.addSvgItemToScene(self.graphicsView.scene())
3163
                else:
3164
                    pt = [float(x) for x in symbol.find('LOCATION').text.split(',')]
3165
                    size = [float(x) for x in symbol.find('SIZE').text.split(',')]
3166
                    angle = float(symbol.find('ANGLE').text)
3167
                    item = QGraphicsBoundingBoxItem(pt[0], pt[1], size[0], size[1])
3168
                    item.isSymbol = True
3169
                    item.angle = angle
3170
                    item.setPen(QPen(Qt.red, 5, Qt.SolidLine))
3171
                    self.graphicsView.scene().addItem(item)
3172
                    item.transfer.onRemoved.connect(self.itemRemoved)
3173

    
3174
                self.progress.setValue(self.progress.value() + 1)
3175

    
3176
            QApplication.processEvents()
3177

    
3178
            # parse texts
3179
            for text in root.find('TEXTINFOS').iter('ATTRIBUTE'):
3180
                item = QEngineeringTextItem.fromXml(text)
3181
                if item is not None:
3182
                    uid = text.find('UID')
3183
                    attributeValue = text.find('ATTRIBUTEVALUE')
3184
                    name = text.find('NAME').text
3185
                    item.transfer.onRemoved.connect(self.itemRemoved)
3186
                    self.addTextItemToScene(item)
3187
                    # docData.texts.append(item)
3188

    
3189
                    if name == 'TEXT':
3190
                        if uid is not None and attributeValue is not None:
3191
                            item.uid = uid.text
3192
                            item.attribute = attributeValue.text
3193

    
3194
                self.progress.setValue(self.progress.value() + 1)
3195

    
3196
            QApplication.processEvents()
3197

    
3198
            # note
3199
            for text in root.find('NOTES').iter('ATTRIBUTE'):
3200
                item = QEngineeringTextItem.fromXml(text)
3201
                if item is not None:
3202
                    uid = text.find('UID')
3203
                    attributeValue = text.find('ATTRIBUTEVALUE')
3204
                    name = text.find('NAME').text
3205
                    item.transfer.onRemoved.connect(self.itemRemoved)
3206
                    self.addTextItemToScene(item)
3207

    
3208
                    if name == 'NOTE':
3209
                        if uid is not None:
3210
                            item.uid = uid.text
3211

    
3212
                self.progress.setValue(self.progress.value() + 1)
3213

    
3214
            QApplication.processEvents()
3215

    
3216
            for line in root.find('LINEINFOS').iter('LINE'):
3217
                item = QEngineeringLineItem.fromXml(line)
3218
                if item:
3219
                    item.transfer.onRemoved.connect(self.itemRemoved)
3220
                    self.graphicsView.scene().addItem(item)
3221
                    lines.append(item)
3222

    
3223
                self.progress.setValue(self.progress.value() + 1)
3224

    
3225
            for line in root.find('LINEINFOS').iter('GRAPHICS_LINE'):
3226
                item = QEngineeringGraphicsLineItem.fromXml(line)
3227
                if item:
3228
                    item.transfer.onRemoved.connect(self.itemRemoved)
3229
                    self.graphicsView.scene().addItem(item)
3230

    
3231
                self.progress.setValue(self.progress.value() + 1)
3232

    
3233
            QApplication.processEvents()
3234

    
3235
            for unknown in root.iter('UNKNOWN'):
3236
                item = QEngineeringUnknownItem.fromXml(unknown)
3237
                if item is not None:
3238
                    item.transfer.onRemoved.connect(self.itemRemoved)
3239
                    self.graphicsView.scene().addItem(item)
3240

    
3241
                self.progress.setValue(self.progress.value() + 1)
3242

    
3243
            QApplication.processEvents()
3244

    
3245
            # """ add tree widget """
3246
            # for item in symbols:
3247
            #    docData.symbols.append(item)
3248
            #    self.addSvgItemToScene(item)
3249
            #    self.itemTreeWidget.addTreeItem(self.itemTreeWidget.root, item)
3250

    
3251
            for line_no_node in root.find('LINENOS').iter('LINE_NO'):
3252
                line_no = QEngineeringLineNoTextItem.fromXml(line_no_node)
3253
                if line_no is None: continue
3254
                line_no.transfer.onRemoved.connect(self.itemRemoved)
3255
                self.addTextItemToScene(line_no)
3256
                line_no_tree_item = self.itemTreeWidget.addTreeItem(self.itemTreeWidget.root, line_no)
3257
                if type(line_no) is not QEngineeringLineNoTextItem: continue
3258

    
3259
                runs_node = line_no_node.findall('RUN')
3260
                if runs_node is None: continue
3261

    
3262
                for run_node in runs_node:
3263
                    line_run = QEngineeringRunItem()
3264
                    for child_node in run_node:
3265
                        uidElement = child_node.find('UID')
3266
                        if uidElement is not None:
3267
                            uid = uidElement.text
3268
                            run_item = self.graphicsView.findItemByUid(uid)
3269
                            if run_item is not None:
3270
                                run_item._owner = line_no
3271
                                line_run.items.append(run_item)
3272
                    line_run.owner = line_no
3273
                    line_no.runs.append(line_run)
3274

    
3275
                    for run_item in line_run.items:
3276
                        if issubclass(type(run_item), SymbolSvgItem):
3277
                            self.init_add_tree_item(line_no_tree_item, run_item)
3278

    
3279
                # docData.tracerLineNos.append(line_no)
3280

    
3281
                self.progress.setValue(self.progress.value() + 1)
3282
            QApplication.processEvents()
3283

    
3284
            for trimLineNo in root.iter('TRIM_LINE_NO'):
3285
                line_no = QEngineeringTrimLineNoTextItem()
3286
                line_no.uid = uuid.UUID(trimLineNo.find('UID').text)
3287

    
3288
                runs_node = trimLineNo.findall('RUN')
3289
                if runs_node is None: continue
3290
                line_no_tree_item = self.itemTreeWidget.addTreeItem(self.itemTreeWidget.root, line_no)
3291

    
3292
                for run in runs_node:
3293
                    line_run = QEngineeringRunItem()
3294
                    for child in run:
3295
                        uidElement = child.find('UID')
3296
                        if uidElement is not None:
3297
                            uid = uidElement.text
3298
                            run_item = self.graphicsView.findItemByUid(uid)
3299
                            if run_item is not None:
3300
                                run_item.owner = line_no
3301
                                line_run.items.append(run_item)
3302
                    line_run.owner = line_no
3303
                    line_no.runs.append(line_run)
3304

    
3305
                    for run_item in line_run.items:
3306
                        if issubclass(type(run_item), SymbolSvgItem):
3307
                            self.init_add_tree_item(line_no_tree_item, run_item)
3308

    
3309
                docData.tracerLineNos.append(line_no)
3310

    
3311
                self.progress.setValue(self.progress.value() + 1)
3312
            QApplication.processEvents()
3313

    
3314
            if root.find('VENDORS') is not None:
3315
                for vendor in root.find('VENDORS').iter('VENDOR'):
3316
                    item = QEngineeringVendorItem.fromXml(vendor)
3317
                    item.transfer.onRemoved.connect(self.itemRemoved)
3318
                    self.graphicsView.scene().addItem(item)
3319

    
3320
            # connect flow item to line
3321
            for line in lines:
3322
                line.update_arrow()
3323
                docData.lines.append(line)
3324
            # for flowMark in [item for item in symbols if type(item) is QEngineeringFlowMarkItem]:
3325
            #    for line in lines:
3326
            #        if flowMark.owner is line:
3327
            #            line._flowMark.append(flowMark)
3328
            #            flowMark.setParentItem(line)
3329
            # up to here
3330

    
3331
            """
3332
            group_box = QGroupBox("Contact Details")
3333
            number_label = QLabel("Telephone number");
3334
            number_edit = QTextEdit('hello\nthis is ....')
3335
            layout = QFormLayout()
3336
            layout.addRow(number_label, number_edit)
3337
            group_box.setLayout(layout)
3338

3339
            proxy = QGraphicsProxyWidget()
3340
            proxy.setWidget(group_box)
3341
            self.graphicsView.scene().addItem(proxy)  # (group_box, QGraphicsItem.ItemIgnoresTransformations)
3342
            """
3343

    
3344
            """ update scene """
3345
            _items = [_item for _item in self.graphicsView.scene().items() if hasattr(_item, 'owner') or hasattr(_item, 'connectors')]
3346
            if _items:
3347
                items = divide_chunks(_items, App.THREAD_MAX_WORKER if len(_items) > App.THREAD_MAX_WORKER else len(_items))
3348
                with futures.ThreadPoolExecutor(max_workers=App.THREAD_MAX_WORKER) as pool:
3349
                    future_items = {pool.submit(update_items, _items): _items for _items in items}
3350
                    for future in futures.as_completed(future_items):
3351
                        _items = future.result()
3352
                        self.progress.setValue(self.progress.value() + len(_items))
3353

    
3354
            """
3355
            for item in [_item for _item in self.graphicsView.scene().items() if hasattr(_item, 'owner') or hasattr(_item, 'connectors')]:
3356
                up_progress = False
3357
                # binding items
3358
                item.owner
3359
                for connector in item.connectors:
3360
                    connector.connectedItem
3361

3362
                self.progress.setValue(self.progress.value() + 1)
3363
            """
3364

    
3365
            for item in self.graphicsView.scene().items():
3366
                item.setVisible(True)
3367

    
3368
            self.graphicsView.scene().update(self.graphicsView.sceneRect())
3369
        except Exception as ex:
3370
            message = 'error occurred({}) in {}:{}'.format(ex, sys.exc_info()[-1].tb_frame.f_code.co_filename,
3371
                                                           sys.exc_info()[-1].tb_lineno)
3372
            self.addMessage.emit(MessageType.Error, message)
3373
        finally:
3374
            self.itemTreeWidget.update_item_count()
3375
            self.itemTreeWidget.expandAll()
3376
            self.graphicsView.scene().blockSignals(False)
3377

    
3378
    '''
3379
        @brief      Remove added item on same place and Add GraphicsItem
3380
        @author     Jeongwoo
3381
        @date       2018.05.25
3382
        @history    2018.05.29  Jeongwoo    Moved from QRecognitionDialog
3383
                    2018.06.18  Jeongwoo    Set Z-index
3384
    '''
3385

    
3386
    def addSvgItemToScene(self, svgItem):
3387
        svgItem.addSvgItemToScene(self.graphicsView.scene())
3388

    
3389
    '''
3390
        @brief      Remove added item on same place and Add GraphicsItem
3391
        @author     Jeongwoo
3392
        @date       2018.05.25
3393
        @history    2018.05.29  Jeongwoo    Moved from QRecognitionDialog
3394
                    2018.06.05  Jeongwoo    Remove Size condition
3395
                    2018.06.18  Jeongwoo    Set Z-index
3396
    '''
3397

    
3398
    def addTextItemToScene(self, textItem):
3399
        textItem.addTextItemToScene(self.graphicsView.scene())
3400

    
3401
    '''
3402
        @brief      Remove added item on same place and Add GraphicsItem
3403
        @author     Jeongwoo
3404
        @date       2018.05.29
3405
        @history    2018.06.18  Jeongwoo    Set Z-index
3406
    '''
3407

    
3408
    def addLineItemToScene(self, lineItem):
3409
        self.graphicsView.scene().addItem(lineItem)
3410

    
3411
    '''
3412
        @brief      generate output xml file
3413
        @author     humkyung
3414
        @date       2018.04.23
3415
        @history    2018.05.02  Jeongwoo    Show MessageBox when imageviewer doesn't have image
3416
    '''
3417

    
3418
    def generateOutput(self):
3419
        import XmlGenerator as xg
3420

    
3421
        if not self.graphicsView.hasImage():
3422
            self.showImageSelectionMessageBox()
3423
            return
3424

    
3425
        try:
3426
            appDocData = AppDocData.instance()
3427

    
3428
            # collect items
3429
            appDocData.lines.clear()
3430
            appDocData.lines = [item for item in self.graphicsView.scene().items() if
3431
                                type(item) is QEngineeringLineItem and item.owner is None]
3432

    
3433
            appDocData.symbols.clear()
3434
            appDocData.symbols = [item for item in self.graphicsView.scene().items() if
3435
                                  issubclass(type(item), SymbolSvgItem) and item.owner is None]
3436

    
3437
            appDocData.equipments.clear()
3438
            for item in self.graphicsView.scene().items():
3439
                if type(item) is QEngineeringEquipmentItem:
3440
                    appDocData.equipments.append(item)
3441

    
3442
            appDocData.texts.clear()
3443
            appDocData.texts = [item for item in self.graphicsView.scene().items() if
3444
                                issubclass(type(item), QEngineeringTextItem) and type(
3445
                                    item) is not QEngineeringLineNoTextItem]
3446
            # up to here
3447

    
3448
            appDocData.imgOutput = np.ones((appDocData.activeDrawing.height, appDocData.activeDrawing.width),
3449
                                           np.uint8) * 255
3450
            xg.writeOutputXml(appDocData.imgName, appDocData.activeDrawing.width,
3451
                              appDocData.activeDrawing.height)  # TODO: check
3452
            project = appDocData.getCurrentProject()
3453
            cv2.imwrite(os.path.join(project.getTempPath(), 'OUTPUT.png'), appDocData.imgOutput)
3454
        except Exception as ex:
3455
            message = 'error occurred({}) in {}:{}'.format(ex, sys.exc_info()[-1].tb_frame.f_code.co_filename,
3456
                                                           sys.exc_info()[-1].tb_lineno)
3457
            self.addMessage.emit(MessageType.Error, message)
3458

    
3459
    '''
3460
        @brief      resetting attribute at secne
3461
        @author     kyoyho
3462
        @date       2018.08.21
3463
    '''
3464
    """
3465
    def checkAttribute(self):
3466
        try:
3467

3468
            docData = AppDocData.instance()
3469
            if not self.graphicsView.hasImage():
3470
                return
3471

3472
            # symbol 경우
3473
            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]
3474
            for item in items:
3475
                attrs = item.attrs
3476
                
3477
                removeAttrList = []
3478
                for attr in attrs:
3479
                    if type(attr) is tuple:
3480
                        continue
3481

3482
                    if attr is None:
3483
                        removeAttrList.append(attr)
3484
                        continue
3485

3486
                    attrInfo = docData.getSymbolAttributeByUID(attr.UID)
3487
                    if attrInfo is None:
3488
                        removeAttrList.append(attr)
3489
                    # 해당 attribute가 맞는지 확인
3490
                    else:
3491
                        attrType = attrInfo.AttributeType
3492
                        _type = type(attr)
3493
                        if attrType == 'Symbol Item':
3494
                            if not issubclass(_type, SymbolSvgItem):
3495
                                removeAttrList.append(attr)
3496
                        elif attrType == 'Text Item':
3497
                            if _type is not QEngineeringTextItem:
3498
                                removeAttrList.append(attr)
3499
                        elif attrType == 'Int':
3500
                            if _type is not UserInputAttribute and self.isNumber(attr.text):
3501
                                removeAttrList.append(attr)
3502
                        elif attrType == 'String':
3503
                            if _type is not UserInputAttribute:
3504
                                removeAttrList.append(attr)
3505

3506
                for attr in removeAttrList:
3507
                    del attrs[attr]
3508

3509
            # Line No Text Item의 경우
3510
            items = [item for item in self.graphicsView.scene().items() if issubclass(type(item), QEngineeringLineNoTextItem)]
3511
            for item in items:
3512
                attrs = item.attrs
3513
                
3514
                removeAttrList = []
3515
                for attr in attrs:
3516
                    if type(attr) is UserInputAttribute:
3517
                        attrInfo = docData.getLinePropertiesByUID(attr.attribute)
3518
                        if attrInfo is None:
3519
                            removeAttrList.append(attr)
3520

3521
                for attr in removeAttrList:
3522
                    del attrs[attr]
3523

3524
        except Exception as ex:
3525
                message = 'error occurred({}) in {}:{}'.format(ex, sys.exc_info()[-1].tb_frame.f_code.co_filename, sys.exc_info()[-1].tb_lineno)
3526
                self.addMessage.emit(MessageType.Error, message)
3527
    """
3528
    '''
3529
        @brief      Check Number
3530
        @author     kyouho
3531
        @date       2018.08.20
3532
    '''
3533

    
3534
    def isNumber(self, num):
3535
        p = re.compile('(^[0-9]+$)')
3536
        result = p.match(num)
3537

    
3538
        if result:
3539
            return True
3540
        else:
3541
            return False
3542

    
3543
    '''
3544
        @brief      find overlap Connector
3545
        @author     kyouho
3546
        @date       2018.08.28
3547
    '''
3548

    
3549
    def findOverlapConnector(self, connectorItem):
3550
        from shapely.geometry import Point
3551
        from EngineeringConnectorItem import QEngineeringConnectorItem
3552
        itemList = []
3553

    
3554
        x = connectorItem.center()[0]
3555
        y = connectorItem.center()[1]
3556

    
3557
        connectors = [item for item in self.graphicsView.scene().items() if
3558
                      type(item) is QEngineeringConnectorItem and item != connectorItem]
3559
        for connector in connectors:
3560
            if Point(x, y).distance(Point(connector.center()[0], connector.center()[1])) < 5:
3561
                itemList.append(connector.parent)
3562

    
3563
        return itemList
3564

    
3565

    
3566
if __name__ == '__main__':
3567
    import locale
3568
    from PyQt5.QtCore import QTranslator
3569
    from License import QLicenseDialog
3570
    from ProjectDialog import Ui_Dialog
3571
    from App import App
3572

    
3573
    app = App(sys.argv)
3574
    try:
3575
        if True == QLicenseDialog.check_license_key():
3576
            dlg = Ui_Dialog()
3577
            selectedProject = dlg.showDialog()
3578
            if selectedProject is not None:
3579
                AppDocData.instance().setCurrentProject(selectedProject)
3580
                app._mainWnd = MainWindow.instance()
3581
                app._mainWnd.show()
3582
                sys.exit(app.exec_())
3583
    except Exception as ex:
3584
        print('error occurred({}) in {}:{}'.format(ex, sys.exc_info()[-1].tb_frame.f_code.co_filename,
3585
                                                   sys.exc_info()[-1].tb_lineno))
3586
    finally:
3587
        pass
클립보드 이미지 추가 (최대 크기: 500 MB)