프로젝트

일반

사용자정보

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

hytos / DTI_PID / DTI_PID / MainWindow.py @ 85ba4667

이력 | 보기 | 이력해설 | 다운로드 (158 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
import asyncio
9

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

    
21
import cv2
22
import numpy as np
23

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

    
29
from PIL import Image
30

    
31
import MainWindow_UI
32
import QtImageViewer
33
from SingletonInstance import SingletonInstance
34

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

    
71

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

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

    
79

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

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

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

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

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

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

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

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

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

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

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

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

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

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

    
175
        from LibraryItem import LibraryItemWidget
176
        self.libraryWidget = LibraryItemWidget(symbol_tree_widget=self.symbolTreeWidget)
177
        self.verticalLayoutLibrary.addWidget(self.libraryWidget)
178
        # Add Custom Property TableWidget
179
        self.propertyTableWidget = SymbolPropertyTableWidget.QSymbolPropertyTableWidget()
180
        self.verticalLayoutSymbolProperty.addWidget(self.propertyTableWidget)
181
        self.symbolTreeWidget.singleClicked.connect(self.propertyTableWidget.getClickedSymbol)
182

    
183
        self.splitterSymbol.setSizes([500, 300])
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.on_initialize_scene)
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.actionUndo.triggered.connect(app_doc_data.scene.undo_stack.undo)
270
        self.actionRedo.triggered.connect(app_doc_data.scene.undo_stack.redo)
271

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

    
286
        self.delimiter = '"'
287

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

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

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

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

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

    
330
        self.read_settings()
331

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

    
336
        from App import App
337

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

    
344
        return title
345

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

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

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

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

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

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

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

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

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

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

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

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

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

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

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

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

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

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

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

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

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

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

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

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

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

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

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

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

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

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

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

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

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

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

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

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

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

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

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

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

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

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

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

    
599
        return
600

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

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

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

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

    
632
        from TextItemEditDialog import QTextItemEditDialog
633

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

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

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

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

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

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

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

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

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

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

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

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

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

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

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

    
707
    def dbUpdate(self):
708
        """db update when save or recognition"""
709

    
710
        try:
711
            appDocData = AppDocData.instance()
712
            items = appDocData.allItems
713

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

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

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

    
753
    def save_drawing_if_necessary(self):
754
        """ask to user to save drawing or not when drawing is modified"""
755

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

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

    
775
    def actionSaveCliked(self):
776
        from EngineeringAbstractItem import QEngineeringAbstractItem
777
        from SaveWorkCommand import SaveWorkCommand
778

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

    
788
            app_doc_data.clearItemList(False)
789

    
790
            items = self.graphicsView.scene().items()
791

    
792
            # for check line disappear bug
793
            disappear_lines = [line for line in app_doc_data.lines if line not in items]
794

    
795
            for item in items:
796
                if issubclass(type(item), QEngineeringAbstractItem):
797
                    app_doc_data.allItems.append(item)
798
                    if issubclass(type(item), QEngineeringTextItem):
799
                        app_doc_data.texts.append(item)
800

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

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

    
817
            self._save_work_cmd = SaveWorkCommand()
818
            self._save_work_cmd.show_progress.connect(self.progress_bar.setValue)
819
            self._save_work_cmd.display_message.connect(self.onAddMessage)
820
            self._save_work_cmd.finished.connect(self.save_finished)
821

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

    
828
    def save_finished(self):
829
        """reload drawing list"""
830

    
831
        self._save_work_cmd.show_progress.emit(100)
832
        QMessageBox.about(self.graphicsView, self.tr('Information'), self._save_work_cmd.resultStr)
833
        self.load_drawing_list()
834

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

    
840
        self.actionSave.setEnabled(True)
841

    
842
    '''
843
        @brief      refresh resultPropertyTableWidget
844
        @author     kyouho
845
        @date       2018.07.19
846
    '''
847

    
848
    def refreshResultPropertyTableWidget(self):
849
        items = self.graphicsView.scene().selectedItems()
850
        if len(items) == 1:
851
            self.resultPropertyTableWidget.show_item_property(items[0])
852

    
853
    '''
854
        @brief  add message listwidget
855
        @author humkyung
856
        @date   2018.07.31
857
    '''
858

    
859
    def onAddMessage(self, messageType, message):
860
        from AppDocData import MessageType
861

    
862
        try:
863
            current = QDateTime.currentDateTime()
864

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

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

    
877
    '''
878
        @brief      clear log
879
        @author     humkyung
880
        @date       2018.08.01
881
    '''
882

    
883
    def onClearLog(self):
884
        self.listWidgetLog.clear()
885

    
886
    '''
887
        @brief      rotate selected symbol
888
        @author     humkyung
889
        @date       2018.08.15
890
    '''
891

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

    
897
    '''
898
        @brief      Area Zoom
899
        @author     Jeongwoo
900
        @date       2018.06.27
901
        @history    connect command's rejected signal
902
    '''
903

    
904
    def onAreaZoom(self, action):
905
        if self.actionZoom.isChecked():
906
            cmd = AreaZoomCommand.AreaZoomCommand(self.graphicsView)
907
            cmd.onRejected.connect(self.onCommandRejected)
908
            self.graphicsView.command = cmd
909

    
910
    def onVendor(self, action):
911
        """make vendor package area"""
912

    
913
        if not self.graphicsView.hasImage():
914
            self.actionVendor.setChecked(False)
915
            self.showImageSelectionMessageBox()
916
            return
917

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

    
924
        self.graphicsView.command = self.actionVendor.tag
925

    
926
    def onVendorCreated(self):
927
        """add created vendor polygon area to scene"""
928

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

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

    
951
    def fitWindow(self, action):
952
        self.graphicsView.useDefaultCommand()
953
        self.graphicsView.zoomImageInit()
954

    
955
    def scene_changed(self):
956
        """update modified flag"""
957

    
958
        self.display_number_of_items()
959

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

    
965
    def onConvertPDFToImage(self):
966
        """convert to selected pdf to image"""
967
        import os
968

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

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

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

    
1000
    def on_help(self):
1001
        """ open help file """
1002
        import os
1003

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

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

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

    
1040
    def on_initialize_scene(self, action):
1041
        if not self.graphicsView.hasImage():
1042
            self.showImageSelectionMessageBox()
1043

    
1044
            return
1045

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

    
1056
                scene = self.graphicsView.scene()
1057
                pixmap = self.graphicsView.getPixmapHandle()
1058
                scene.removeItem(pixmap)    # disconnect pixmap from scene
1059
                scene.clear()               # remove all items from scene and then delete them
1060
                scene.addItem(pixmap)       # add pixmap
1061

    
1062
                if self.path is not None:
1063
                    baseName = os.path.basename(self.path)
1064
                    self.itemTreeWidget.setCurrentPID(baseName)
1065

    
1066
        except Exception as ex:
1067
            message = 'error occurred({}) in {}:{}'.format(ex, sys.exc_info()[-1].tb_frame.f_code.co_filename,
1068
                                                           sys.exc_info()[-1].tb_lineno)
1069
            self.addMessage.emit(MessageType.Error, message)
1070

    
1071
    '''
1072
        @brief      Manage Checkable Action statement
1073
        @author     Jeongwoo
1074
        @date       2018.05.10
1075
        @history    2018.06.27  Jeongwoo    Chnage method to initialize command [Set None → DefaultCommand]
1076
    '''
1077

    
1078
    def actionGroupTriggered(self, action):
1079
        if hasattr(self.actionLine, 'tag'):
1080
            self.actionLine.tag.onRejected.emit(None)
1081

    
1082
        if hasattr(self.actionVendor, 'tag'):
1083
            self.actionVendor.tag.onRejected.emit(None)
1084

    
1085
        if self.graphicsView.command is not None:
1086
            self.graphicsView.useDefaultCommand()
1087

    
1088
        for _action in self.actionGroup.actions():
1089
            _action.setChecked(False)
1090

    
1091
        action.setChecked(True)
1092

    
1093
    '''
1094
        @brief      Create Equipment
1095
        @author     Jeongwoo
1096
        @date       18.05.03
1097
        @history    2018.05.04  Jeongwoo    Add Parameter on CreateSymbolCommand
1098
    '''
1099

    
1100
    def createEquipment(self):
1101
        if not self.graphicsView.hasImage():
1102
            self.actionEquipment.setChecked(False)
1103
            self.showImageSelectionMessageBox()
1104
            return
1105
        if self.actionEquipment.isChecked():
1106
            self.graphicsView.command = CreateSymbolCommand.CreateSymbolCommand(self.graphicsView, self.itemTreeWidget,
1107
                                                                                self.symbolTreeWidget)
1108
        else:
1109
            self.graphicsView.useDefaultCommand()
1110

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

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

    
1129
    '''
1130
        @brief      Area OCR
1131
        @author     Jeongwoo
1132
        @date       18.04.18
1133
        @history    2018.05.02  Jeongwoo    Change graphicsView.command by actionOCR checked state
1134
                                            Show MessageBox when imageviewer doesn't have image
1135
    '''
1136

    
1137
    def onAreaOcr(self):
1138
        if not self.graphicsView.hasImage():
1139
            self.actionOCR.setChecked(False)
1140
            self.showImageSelectionMessageBox()
1141
            return
1142

    
1143
        if self.actionOCR.isChecked():
1144
            cmd = AreaOcrCommand.AreaOcrCommand(self.graphicsView)
1145
            cmd.onSuccess.connect(self.onRecognizeText)
1146
            cmd.onRejected.connect(self.onCommandRejected)
1147
            self.graphicsView.command = cmd
1148
        else:
1149
            self.graphicsView.useDefaultCommand()
1150

    
1151
    '''
1152
        @brief      show text recognition dialog
1153
        @author     humkyung
1154
        @date       2018.08.08
1155
    '''
1156

    
1157
    def onRecognizeText(self, x, y, width, height):
1158
        from OcrResultDialog import QOcrResultDialog
1159
        from Area import Area
1160

    
1161
        try:
1162
            app_doc_data = AppDocData.instance()
1163

    
1164
            modifiers = QApplication.keyboardModifiers()
1165
            image = self.graphicsView.image().copy(x, y, width, height)
1166
            dialog = QOcrResultDialog(self, image, QRectF(x, y, width, height),
1167
                                      format=QOcrResultDialog.Format.Table if modifiers == Qt.AltModifier else QOcrResultDialog.Format.Normal)
1168
            if modifiers == Qt.ControlModifier:
1169
                return
1170
            (res, textInfoList) = dialog.showDialog()
1171
            if QDialog.Accepted == res and textInfoList:
1172
                for textInfo in textInfoList:
1173
                    item = QEngineeringTextItem.create_text_with(self.graphicsView.scene(), textInfo)
1174
                    if item:
1175
                        item.setDefaultTextColor(Qt.blue)
1176
                        item.transfer.onRemoved.connect(self.itemRemoved)
1177

    
1178
                        area_list = app_doc_data.getAreaList()
1179
                        title_area_list = app_doc_data.getTitleBlockProperties()
1180
                        title_list = []
1181
                        for title_area in title_area_list:
1182
                            area = Area(title_area[0])
1183
                            area.parse(title_area[2])
1184
                            title_list.append(area)
1185
                        for area in area_list + title_list:
1186
                            pt = [item.sceneBoundingRect().center().x(), item.sceneBoundingRect().center().y()]
1187
                            if area.contains(pt):
1188
                                item.area = area.name
1189
                                break
1190
                    else:
1191
                        self.addMessage.emit(MessageType.Normal, self.tr('Fail to create text.'))
1192
            elif QDialog.Accepted == res and not textInfoList:
1193
                QMessageBox.about(self.graphicsView, self.tr("Notice"), self.tr("Fail to recognize text"))
1194
        except Exception as ex:
1195
            message = 'error occurred({}) in {}:{}'.format(ex, sys.exc_info()[-1].tb_frame.f_code.co_filename,
1196
                                                           sys.exc_info()[-1].tb_lineno)
1197
            self.addMessage.emit(MessageType.Error, message)
1198

    
1199
    '''
1200
        @brief  area configuration
1201
    '''
1202

    
1203
    def areaConfiguration(self):
1204
        from ConfigurationAreaDialog import QConfigurationAreaDialog
1205
        if not self.graphicsView.hasImage():
1206
            self.showImageSelectionMessageBox()
1207
            return
1208
        self.onCommandRejected()
1209
        self.dlgConfigurationArea = QConfigurationAreaDialog(self)
1210
        self.dlgConfigurationArea.show()
1211
        self.dlgConfigurationArea.exec_()
1212

    
1213
    '''
1214
        @brief  configuration
1215
    '''
1216

    
1217
    def configuration(self):
1218
        from ConfigurationDialog import QConfigurationDialog
1219

    
1220
        self.dlgConfiguration = QConfigurationDialog(self)
1221
        # self.dlgConfiguration.show()
1222
        if QDialog.Accepted == self.dlgConfiguration.exec_():
1223
            QEngineeringLineItem.LINE_TYPE_COLORS.clear()
1224
            QEngineeringInstrumentItem.INST_COLOR = None
1225

    
1226
    '''
1227
        @brief  show special item types dialog 
1228
        @author humkyung
1229
        @date   2019.08.10
1230
    '''
1231

    
1232
    def on_show_special_item_types(self):
1233
        from SpecialItemTypesDialog import QSpecialItemTypesDialog
1234

    
1235
        dlg = QSpecialItemTypesDialog(self)
1236
        dlg.exec_()
1237

    
1238
    def on_show_data_transfer(self):
1239
        """ show data transfer dialog """
1240
        from DataTransferDialog import QDataTransferDialog
1241

    
1242
        dlg = QDataTransferDialog(self)
1243
        dlg.exec_()
1244

    
1245
    def on_show_data_export(self):
1246
        """ show data export dialog """
1247
        from DataExportDialog import QDataExportDialog
1248

    
1249
        dlg = QDataExportDialog(self)
1250
        dlg.exec_()
1251

    
1252
    def on_show_eqp_datasheet_export(self):
1253
        """ show eqp datasheet export dialog """
1254
        from EqpDatasheetExportDialog import QEqpDatasheetExportDialog
1255

    
1256
        dlg = QEqpDatasheetExportDialog(self)
1257
        dlg.exec_()
1258

    
1259
    def on_show_opc_relation(self):
1260
        """ show opc relation dialog """
1261
        from OPCRelationDialog import QOPCRelationDialog
1262

    
1263
        dlg = QOPCRelationDialog(self)
1264
        dlg.exec_()
1265

    
1266
    '''
1267
        @brief  show nominal diameter dialog 
1268
        @author humkyung
1269
        @date   2018.06.28
1270
    '''
1271

    
1272
    def onShowCodeTable(self):
1273
        from CodeTableDialog import QCodeTableDialog
1274

    
1275
        dlg = QCodeTableDialog(self)
1276
        dlg.show()
1277
        dlg.exec_()
1278
        if dlg.code_area:
1279
            if dlg.code_area.scene():
1280
                self.graphicsView.scene().removeItem(dlg.code_area)
1281
        if dlg.desc_area:
1282
            if dlg.desc_area.scene():
1283
                self.graphicsView.scene().removeItem(dlg.desc_area)
1284
        self.graphicsView.useDefaultCommand()
1285

    
1286
    def onShowCustomCodeTable(self):
1287
        from CustomCodeTablesDialog import CustomCodeTablesDialog
1288

    
1289
        dlg = CustomCodeTablesDialog(self)
1290
        dlg.show()
1291
        dlg.exec_()
1292
        self.graphicsView.useDefaultCommand()
1293

    
1294
    '''
1295
        @brief  show HMB data
1296
        @author humkyung
1297
        @date   2018.07.11
1298
    '''
1299

    
1300
    def onHMBData(self):
1301
        from HMBDialog import QHMBDialog
1302

    
1303
        dlg = QHMBDialog(self)
1304
        dlg.show()
1305
        dlg.exec_()
1306

    
1307
    '''
1308
        @brief  show line data list 
1309
        @author humkyung
1310
        @date   2018.05.03
1311
    '''
1312

    
1313
    def showItemDataList(self):
1314
        from ItemDataExportDialog import QItemDataExportDialog
1315

    
1316
        self.dlgLineDataList = QItemDataExportDialog(self)
1317
        self.dlgLineDataList.exec_()
1318

    
1319
    def showTextDataList(self):
1320
        '''
1321
            @brief      show all text item in scene
1322
            @author     euisung
1323
            @date       2019.04.18
1324
        '''
1325
        try:
1326
            if not self.graphicsView.hasImage():
1327
                self.showImageSelectionMessageBox()
1328
                return
1329

    
1330
            self.onCommandRejected()
1331
            dialog = QTextDataListDialog(self)
1332
            dialog.show()
1333
        except Exception as ex:
1334
            message = 'error occurred({}) in {}:{}'.format(ex, sys.exc_info()[-1].tb_frame.f_code.co_filename,
1335
                                                           sys.exc_info()[-1].tb_lineno)
1336
            self.addMessage.emit(MessageType.Error, message)
1337

    
1338
    '''
1339
        @brief  Show Image Selection Guide MessageBox
1340
        @author Jeongwoo
1341
        @date   2018.05.02
1342
    '''
1343

    
1344
    def showImageSelectionMessageBox(self):
1345
        QMessageBox.about(self.graphicsView, self.tr("Notice"), self.tr("First select image drawing"))
1346

    
1347
    '''
1348
        @brief  change selected lines' type by selected line type
1349
        @author humkyung
1350
        @date   2018.06.27
1351
    '''
1352

    
1353
    def onLineTypeChanged(self, param):
1354
        lineType = self.lineComboBox.itemText(param)
1355
        selected = [item for item in self.graphicsView.scene().selectedItems() if type(item) is QEngineeringLineItem]
1356
        if selected:
1357
            for item in selected:
1358
                item.lineType = lineType
1359

    
1360
    def display_colors(self, value):
1361
        """ display colors """
1362
        from DisplayColors import DisplayColors
1363
        from DisplayColors import DisplayOptions
1364

    
1365
        DisplayColors.instance().option = DisplayOptions.DisplayByLineNo if value is True else DisplayOptions.DisplayByLineType
1366
        if hasattr(self, 'graphicsView'):
1367
            self.graphicsView.scene().update(self.graphicsView.sceneRect())
1368
            DisplayColors.instance().save_data()
1369

    
1370
    def open_image_drawing(self, drawing):
1371
        """open and display image drawing file"""
1372
        from Drawing import Drawing
1373

    
1374
        try:
1375
            if not self.actionSave.isEnabled():
1376
                return
1377

    
1378
            if self.save_drawing_if_necessary():
1379
                return
1380

    
1381
            if hasattr(self, '_save_work_cmd'):
1382
                self._save_work_cmd.wait()
1383

    
1384
            app_doc_data = AppDocData.instance()
1385
            project = app_doc_data.getCurrentProject()
1386

    
1387
            self.path = self.graphicsView.loadImageFromFile(drawing)
1388
            if os.path.isfile(self.path):
1389
                self.onCommandRejected()
1390
                app_doc_data.clear()
1391

    
1392
                app_doc_data.setImgFilePath(self.path)
1393
                app_doc_data.activeDrawing = drawing
1394
                if not app_doc_data.set_occupying_drawing(app_doc_data.activeDrawing.UID):
1395
                    QMessageBox.about(self.graphicsView, self.tr("Notice"),
1396
                                      self.tr("The drawing is locked for editing by another user"))
1397
                    return
1398
                app_doc_data.activeDrawing.set_pid_source(Image.open(self.path))
1399
                self.itemTreeWidget.setCurrentPID(app_doc_data.activeDrawing.name)
1400

    
1401
                drawingList = self.treeWidgetDrawingList.topLevelItem(0)
1402
                for childIdex in range(drawingList.childCount()):
1403
                    drawingList.child(childIdex).setCheckState(0, Qt.Unchecked)
1404
                for childIdex in range(drawingList.childCount()):
1405
                    child = drawingList.child(childIdex)
1406
                    if child.text(0).replace('.png', '') == app_doc_data.activeDrawing.name:
1407
                        child.setCheckState(0, Qt.Checked)
1408
                        break
1409

    
1410
                try:
1411
                    self.show_Progress_bar()
1412

    
1413
                    # disconnect scene changed if signal is connected
1414
                    if self.graphicsView.scene().receivers(self.graphicsView.scene().contents_changed) > 0:
1415
                        self.graphicsView.scene().contents_changed.disconnect()
1416

    
1417
                    SymbolSvgItem.DOCUMENTS.clear()
1418

    
1419
                    # Load data
1420
                    path = os.path.join(app_doc_data.getCurrentProject().getTempPath(), app_doc_data.imgName + '.xml')
1421
                    configs = app_doc_data.getConfigs('Data Load', 'Xml First')
1422
                    if configs and int(configs[0].value) >= 1 and os.path.isfile(path):
1423
                        self.load_recognition_result_from_xml(path)
1424
                    elif configs and int(configs[0].value) <= 1:
1425
                        self.load_drawing(app_doc_data.activeDrawing)
1426

    
1427
                    self.display_number_of_items()
1428
                    # connect scene changed signal
1429
                    self.graphicsView.scene().contents_changed.connect(self.scene_changed)
1430
                finally:
1431
                    if hasattr(self, 'progress'):
1432
                        self.progress.setValue(self.progress.maximum())
1433

    
1434
                self.changeViewCheckedState(True)
1435
                self.setWindowTitle(self.title)
1436
        except Exception as ex:
1437
            message = 'error occurred({}) in {}:{}'.format(ex, sys.exc_info()[-1].tb_frame.f_code.co_filename,
1438
                                                           sys.exc_info()[-1].tb_lineno)
1439
            self.addMessage.emit(MessageType.Error, message)
1440

    
1441
        return self.path
1442

    
1443
    def export_as_svg(self):
1444
        """export scene to svg file"""
1445
        from ExportCommand import ExportCommand
1446

    
1447
        options = QFileDialog.Options()
1448
        options |= QFileDialog.DontUseNativeDialog
1449
        file_path, _ = QFileDialog.getSaveFileName(self, "Export as svg", os.getcwd(), "svg file(*.svg)",
1450
                                                   options=options)
1451
        if file_path:
1452
            cmd = ExportCommand(self.graphicsView.scene(), 'svg')
1453
            cmd.display_message.connect(self.onAddMessage)
1454
            if cmd.execute(file_path):
1455
                QMessageBox.information(self, self.tr('Information'), self.tr('Successfully export to svg file'))
1456
            else:
1457
                QMessageBox.information(self, self.tr('Error'), self.tr('Fail to export to svg file'))
1458

    
1459
    def export_as_xml(self):
1460
        pass
1461

    
1462
    def export_as_image(self):
1463
        """export scene to image file"""
1464
        from ExportCommand import ExportCommand
1465

    
1466
        options = QFileDialog.Options()
1467
        options |= QFileDialog.DontUseNativeDialog
1468
        file_path, _ = QFileDialog.getSaveFileName(self, "Export as png", os.getcwd(), "png file(*.png)",
1469
                                                   options=options)
1470
        if file_path:
1471
            try:
1472
                # hide image drawing
1473
                self.onViewImageDrawing(False)
1474

    
1475
                cmd = ExportCommand(self.graphicsView.scene(), 'image')
1476
                cmd.display_message.connect(self.onAddMessage)
1477

    
1478
                if cmd.execute(file_path):
1479
                    QMessageBox.information(self, self.tr('Information'), self.tr('Successfully export to image file'))
1480
                else:
1481
                    QMessageBox.information(self, self.tr('Error'), self.tr('Fail to export to image file'))
1482
            finally:
1483
                if self.actionImage_Drawing.isChecked():
1484
                    self.onViewImageDrawing(True)
1485
                    self.actionImage_Drawing.setChecked(True)
1486

    
1487
    def show_Progress_bar(self):
1488
        """ show progress bar """
1489
        self.progress = QProgressDialog(self.tr("Please wait for a while"), self.tr("Cancel"), 0, 100,
1490
                                        self) if not hasattr(self, 'progress') else self.progress
1491
        self.progress.setWindowModality(Qt.WindowModal)
1492
        self.progress.setAutoReset(True)
1493
        self.progress.setAutoClose(True)
1494
        self.progress.setMinimum(0)
1495
        self.progress.setMaximum(100)
1496
        self.progress.resize(600, 100)
1497
        self.progress.setWindowTitle(self.tr("Reading file..."))
1498
        self.progress.show()
1499

    
1500
    def changeViewCheckedState(self, checked, clear=True):
1501
        '''
1502
            @brief      change view checked state
1503
            @author     euisung
1504
            @date       2019.03.06
1505
        '''
1506
        # self.actionImage_Drawing.setChecked(checked)
1507
        self.actionViewText.setChecked(checked)
1508
        self.actionViewSymbol.setChecked(checked)
1509
        self.actionViewLine.setChecked(checked)
1510
        self.actionViewUnknown.setChecked(checked)
1511
        self.actionViewInconsistency.setChecked(checked)
1512
        self.actionViewVendor_Area.setChecked(not checked)
1513
        self.actionDrawing_Only.setChecked(not checked)
1514
        if clear:
1515
            self.tableWidgetInconsistency.clearContents()
1516
            self.tableWidgetInconsistency.setRowCount(0)
1517

    
1518
    def onViewDrawingOnly(self, isChecked):
1519
        '''
1520
            @brief  visible/invisible except image drawing
1521
            @author euisung
1522
            @date   2019.04.22
1523
        '''
1524
        self.changeViewCheckedState(not isChecked, False)
1525
        for item in self.graphicsView.scene().items():
1526
            if type(item) is not QGraphicsPixmapItem:
1527
                item.setVisible(not isChecked)
1528

    
1529
    '''
1530
        @brief  visible/invisible image drawing
1531
        @author humkyung
1532
        @date   2018.06.25
1533
    '''
1534

    
1535
    def onViewImageDrawing(self, isChecked):
1536
        for item in self.graphicsView.scene().items():
1537
            if type(item) is QGraphicsPixmapItem:
1538
                item.setVisible(isChecked)
1539
                break
1540

    
1541
    def onViewText(self, checked):
1542
        """visible/invisible text"""
1543
        selected = [item for item in self.graphicsView.scene().items() if issubclass(type(item), QEngineeringTextItem)
1544
                    and type(item) is not QEngineeringLineNoTextItem]
1545
        for item in selected:
1546
            item.setVisible(checked)
1547

    
1548
    def onViewSymbol(self, checked):
1549
        """visible/invisible symbol"""
1550
        selected = [item for item in self.graphicsView.scene().items() if
1551
                    (issubclass(type(item), SymbolSvgItem) and type(item) is not QEngineeringErrorItem)]
1552
        for item in selected:
1553
            item.setVisible(checked)
1554

    
1555
    def onViewLine(self, checked):
1556
        """visible/invisible line"""
1557
        selected = [item for item in self.graphicsView.scene().items() if type(item) is QEngineeringLineItem]
1558
        for item in selected:
1559
            item.setVisible(checked)
1560

    
1561
    def onViewInconsistency(self, isChecked):
1562
        '''
1563
            @brief  visible/invisible Inconsistency
1564
            @author euisung
1565
            @date   2019.04.03
1566
        '''
1567
        selected = [item for item in self.graphicsView.scene().items() if type(item) is QEngineeringErrorItem]
1568
        for item in selected:
1569
            item.setVisible(isChecked)
1570

    
1571
    '''
1572
        @brief  visible/invisible Unknown 
1573
        @author humkyung
1574
        @date   2018.06.28
1575
    '''
1576

    
1577
    def onViewUnknown(self, isChecked):
1578
        selected = [item for item in self.graphicsView.scene().items() if type(item) is QEngineeringUnknownItem]
1579
        for item in selected:
1580
            item.setVisible(isChecked)
1581

    
1582
    def onViewVendorArea(self, isChecked):
1583
        '''
1584
            @brief  visible/invisible Vendor Area
1585
            @author euisung
1586
            @date   2019.04.29
1587
        '''
1588
        selected = [item for item in self.graphicsView.scene().items() if type(item) is QEngineeringVendorItem]
1589
        for item in selected:
1590
            item.setVisible(isChecked)
1591

    
1592
    '''
1593
        @brief  create a symbol
1594
        @history    2018.05.02  Jeongwoo    Change return value of QSymbolEditorDialog (Single variable → Tuple)
1595
                                            Add SymbolSvgItem
1596
                    2018.05.03  Jeongwoo    Change method to draw Svg Item on Scene (svg.addSvgItemToScene)
1597
                                            Change method to make svg and image path
1598
                    2018.06.08  Jeongwoo    Add Paramter on SymbolSvgItem.buildItem()
1599
    '''
1600

    
1601
    def onCreateSymbolClicked(self):
1602
        cmd = FenceCommand.FenceCommand(self.graphicsView)
1603
        cmd.onSuccess.connect(self.onAreaSelected)
1604
        self.graphicsView.command = cmd
1605
        QApplication.setOverrideCursor(Qt.CrossCursor)
1606

    
1607
    '''
1608
        @brief      show SymbolEditorDialog with image selected by user
1609
        @author     humkyung
1610
        @date       2018.07.20
1611
    '''
1612

    
1613
    def onAreaSelected(self, x, y, width, height):
1614
        try:
1615
            image = self.graphicsView.image()
1616
            if image is not None:
1617
                symbolEditorDialog = SymbolEditorDialog.QSymbolEditorDialog(self, image.copy(x, y, width, height),
1618
                                                                            AppDocData.instance().getCurrentProject())
1619
                (isAccepted, isImmediateInsert, offsetX, offsetY, newSym) = symbolEditorDialog.showDialog()
1620
                self.symbolTreeWidget.initDirTreeWidget()
1621
                if isAccepted:
1622
                    if isImmediateInsert:
1623
                        svgPath = newSym.getSvgFileFullPath()
1624
                        img = cv2.imread(newSym.getImageFileFullPath(), 1)
1625
                        w, h = (0, 0)
1626
                        if len(img.shape[::-1]) == 2:
1627
                            w, h = img.shape[::-1]
1628
                        else:
1629
                            _chan, w, h = img.shape[::-1]
1630
                        svg = SymbolSvgItem(svgPath)
1631
                        svg.buildItem(newSym.getName(), newSym.getType(), 0, [offsetX, offsetY], [w, h],
1632
                                      [float(x) for x in newSym.getOriginalPoint().split(',')],
1633
                                      [(float(x.split(',')[0]), float(x.split(',')[1])) for x in
1634
                                       newSym.getConnectionPoint().split('/')], newSym.getBaseSymbol(),
1635
                                      newSym.getAdditionalSymbol(), newSym.getHasInstrumentLabel)
1636

    
1637
                        svg.transfer.onRemoved.connect(self.itemTreeWidget.itemRemoved)
1638
                        svg.addSvgItemToScene(self.graphicsView.scene())
1639
                        for connector in svg.connectors:
1640
                            self.graphicsView.scene().addItem(connector)
1641
        finally:
1642
            self.onCommandRejected()
1643
            QApplication.restoreOverrideCursor()
1644

    
1645
    '''
1646
        @brief      create a line
1647
        @author     humkyung
1648
        @history    Jeongwoo 2018.05.10 Change method for Checkable action
1649
    '''
1650

    
1651
    def onPlaceLine(self):
1652
        if not self.graphicsView.hasImage():
1653
            self.actionLine.setChecked(False)
1654
            self.showImageSelectionMessageBox()
1655
            return
1656

    
1657
        self.actionLine.setChecked(True)
1658
        if not hasattr(self.actionLine, 'tag'):
1659
            self.actionLine.tag = PlaceLineCommand.PlaceLineCommand(self.graphicsView)
1660
            self.actionLine.tag.onSuccess.connect(self.onLineCreated)
1661
            self.actionLine.tag.onRejected.connect(self.onCommandRejected)
1662

    
1663
        self.graphicsView.command = self.actionLine.tag
1664

    
1665
    '''
1666
        @brief      add created lines to scene
1667
        @author     humkyung
1668
        @date       2018.07.23
1669
    '''
1670

    
1671
    def onLineCreated(self):
1672
        from EngineeringConnectorItem import QEngineeringConnectorItem
1673
        from LineDetector import LineDetector
1674

    
1675
        try:
1676
            app_doc_data = AppDocData.instance()
1677

    
1678
            count = len(self.actionLine.tag._polyline._vertices)
1679
            if count > 1:
1680
                items = []
1681

    
1682
                detector = LineDetector(None)
1683

    
1684
                line_type = self.actionLine.tag.line_type if self.actionLine.tag.line_type else \
1685
                    self.lineComboBox.currentText()
1686
                for index in range(count - 1):
1687
                    start = self.actionLine.tag._polyline._vertices[index]
1688
                    end = self.actionLine.tag._polyline._vertices[index + 1]
1689

    
1690
                    lineItem = QEngineeringLineItem(vertices=[start, end])
1691
                    lineItem.transfer.onRemoved.connect(self.itemRemoved)
1692
                    lineItem.lineType = line_type
1693
                    if items:
1694
                        lineItem.connect_if_possible(items[-1], 5)
1695
                    else:
1696
                        pt = lineItem.start_point()
1697
                        selected = [item for item in self.graphicsView.scene().items(QPointF(pt[0], pt[1])) if
1698
                                    type(item) is QEngineeringConnectorItem or type(item) is QEngineeringLineItem]
1699
                        if selected and selected[0] is not lineItem:
1700
                            if type(selected[0]) is QEngineeringConnectorItem:
1701
                                lineItem.connect_if_possible(selected[0].parent, 5)
1702
                            else:
1703
                                detector.connectLineToLine(selected[0], lineItem, 5)
1704

    
1705
                    items.append(lineItem)
1706
                    self.graphicsView.scene().addItem(lineItem)
1707
                    app_doc_data.lines.append(lineItem)
1708

    
1709
                pt = items[-1].end_point()
1710
                selected = [item for item in self.graphicsView.scene().items(QPointF(pt[0], pt[1])) if
1711
                            (type(item) is QEngineeringConnectorItem and item.parentItem() is not items[-1]) or
1712
                            (type(item) is QEngineeringLineItem and item is not items[-1])]
1713
                if selected and selected[0] is not items[-1]:
1714
                    if type(selected[0]) is QEngineeringConnectorItem:
1715
                        items[-1].connect_if_possible(selected[0].parent, 5)
1716
                    else:
1717
                        detector.connectLineToLine(selected[0], items[-1], 5)
1718

    
1719
                app_doc_data.scene.undo_stack.push(CreateCommand(app_doc_data.scene, items))
1720
        finally:
1721
            self.graphicsView.scene().removeItem(self.actionLine.tag._polyline)
1722
            self.actionLine.tag.reset()
1723

    
1724
    '''
1725
        @brief      refresh scene
1726
        @author     humkyung
1727
        @date       2018.07.23
1728
    '''
1729

    
1730
    def onCommandRejected(self, cmd=None):
1731
        try:
1732
            if type(cmd) is PlaceLineCommand.PlaceLineCommand:
1733
                if self.actionLine.tag._polyline:
1734
                    self.graphicsView.scene().removeItem(self.actionLine.tag._polyline)
1735
                self.graphicsView.scene().update()
1736
                self.actionLine.tag.reset()
1737

    
1738
                self.actionLine.setChecked(False)
1739
            elif type(cmd) is AreaZoomCommand.AreaZoomCommand:
1740
                self.actionZoom.setChecked(False)
1741
            elif type(cmd) is AreaOcrCommand.AreaOcrCommand:
1742
                self.actionOCR.setChecked(False)
1743
            elif type(cmd) is PlacePolygonCommand.PlacePolygonCommand:
1744
                self.actionVendor.setChecked(False)
1745
            else:
1746
                if hasattr(self.actionLine, 'tag') and self.actionLine.tag._polyline:
1747
                    self.graphicsView.scene().removeItem(self.actionLine.tag._polyline)
1748
                    self.graphicsView.scene().update()
1749
                    self.actionLine.tag.reset()
1750
                if hasattr(self.actionVendor, 'tag') and self.actionVendor.tag._polyline:
1751
                    self.graphicsView.scene().removeItem(self.actionVendor.tag._polyline)
1752
                    self.graphicsView.scene().update()
1753
                    self.actionVendor.tag.reset()
1754
                self.actionLine.setChecked(False)
1755
                self.actionZoom.setChecked(False)
1756
                self.actionOCR.setChecked(False)
1757
                self.actionVendor.setChecked(False)
1758
        finally:
1759
            self.graphicsView.useDefaultCommand()
1760

    
1761
    '''
1762
        @brief      restore to default command when user press Escape key
1763
        @author     humkyung 
1764
        @date       2018.08.09
1765
        
1766
    '''
1767

    
1768
    def keyPressEvent(self, event):
1769
        try:
1770
            if event.key() == Qt.Key_Escape:
1771
                checked = self.actionGroup.checkedAction()
1772
                if checked:
1773
                    checked.setChecked(False)
1774
                    self.graphicsView.useDefaultCommand()
1775
            elif event.key() == Qt.Key_1:
1776
                if self.actionImage_Drawing.isChecked():
1777
                    self.onViewImageDrawing(False)
1778
                    self.actionImage_Drawing.setChecked(False)
1779
                else:
1780
                    self.onViewImageDrawing(True)
1781
                    self.actionImage_Drawing.setChecked(True)
1782
            elif event.key() == Qt.Key_2:
1783
                if self.actionViewText.isChecked():
1784
                    self.onViewText(False)
1785
                    self.actionViewText.setChecked(False)
1786
                else:
1787
                    self.onViewText(True)
1788
                    self.actionViewText.setChecked(True)
1789
            elif event.key() == Qt.Key_3:
1790
                if self.actionViewSymbol.isChecked():
1791
                    self.onViewSymbol(False)
1792
                    self.actionViewSymbol.setChecked(False)
1793
                else:
1794
                    self.onViewSymbol(True)
1795
                    self.actionViewSymbol.setChecked(True)
1796
            elif event.key() == Qt.Key_4:
1797
                if self.actionViewLine.isChecked():
1798
                    self.onViewLine(False)
1799
                    self.actionViewLine.setChecked(False)
1800
                else:
1801
                    self.onViewLine(True)
1802
                    self.actionViewLine.setChecked(True)
1803
            elif event.key() == Qt.Key_5:
1804
                if self.actionViewUnknown.isChecked():
1805
                    self.onViewUnknown(False)
1806
                    self.actionViewUnknown.setChecked(False)
1807
                else:
1808
                    self.onViewUnknown(True)
1809
                    self.actionViewUnknown.setChecked(True)
1810
            elif event.key() == Qt.Key_6:
1811
                if self.actionViewInconsistency.isChecked():
1812
                    self.onViewInconsistency(False)
1813
                    self.actionViewInconsistency.setChecked(False)
1814
                else:
1815
                    self.onViewInconsistency(True)
1816
                    self.actionViewInconsistency.setChecked(True)
1817
            elif event.key() == Qt.Key_7:
1818
                if self.actionViewVendor_Area.isChecked():
1819
                    self.onViewVendorArea(False)
1820
                    self.actionViewVendor_Area.setChecked(False)
1821
                else:
1822
                    self.onViewVendorArea(True)
1823
                    self.actionViewVendor_Area.setChecked(True)
1824
            elif event.key() == 96:  # '`' key
1825
                if self.actionDrawing_Only.isChecked():
1826
                    self.onViewDrawingOnly(False)
1827
                    self.actionDrawing_Only.setChecked(False)
1828
                else:
1829
                    self.onViewDrawingOnly(True)
1830
                    self.actionDrawing_Only.setChecked(True)
1831
            elif event.key() == Qt.Key_M:  # merge text as vertical
1832
                from TextInfo import TextInfo
1833

    
1834
                textItems = [text for text in self.graphicsView.scene().selectedItems() if
1835
                             issubclass(type(text), QEngineeringTextItem)]
1836
                if not textItems or len(textItems) is 1:
1837
                    return
1838

    
1839
                angle = None
1840
                for item in textItems:
1841
                    if angle is None:
1842
                        angle = item.angle
1843
                    else:
1844
                        if angle != item.angle:
1845
                            return
1846

    
1847
                modifiers = QApplication.keyboardModifiers()
1848
                enter_or_space = ' ' if modifiers == Qt.ControlModifier else '\n'
1849
                x_or_y = 0 if modifiers == Qt.ControlModifier else 1
1850

    
1851
                textItems = sorted(textItems, key=lambda text: text.loc[x_or_y]) if textItems[0].angle == 0 else ( \
1852
                    sorted(textItems, key=lambda text: text.loc[x_or_y]) if textItems[0].angle == 1.57 else ( \
1853
                        sorted(textItems, key=lambda text: text.loc[x_or_y], reverse=True) if textItems[0].angle == 4.71 else \
1854
                            sorted(textItems, key=lambda text: text.loc[x_or_y], reverse=True)))
1855

    
1856
                if textItems[0].angle == 1.57 and modifiers == Qt.ControlModifier:
1857
                    textItems.reverse()
1858

    
1859
                minX = sys.maxsize
1860
                minY = sys.maxsize
1861
                maxX = 0
1862
                maxY = 0
1863
                newText = ''
1864

    
1865
                for text in textItems:
1866
                    if text.loc[0] < minX: minX = text.loc[0]
1867
                    if text.loc[1] < minY: minY = text.loc[1]
1868
                    if text.loc[0] + text.size[0] > maxX: maxX = text.loc[0] + text.size[0]
1869
                    if text.loc[1] + text.size[1] > maxY: maxY = text.loc[1] + text.size[1]
1870
                    newText = newText + text.text() + enter_or_space
1871
                    text.transfer.onRemoved.emit(text)
1872
                newText = newText[:-1]
1873

    
1874
                textInfo = TextInfo(newText, minX, minY, maxX - minX, maxY - minY, textItems[0].angle)
1875
                x = textInfo.getX()
1876
                y = textInfo.getY()
1877
                angle = textInfo.getAngle()
1878
                text = textInfo.getText()
1879
                width = textInfo.getW()
1880
                height = textInfo.getH()
1881
                item = TextItemFactory.instance().createTextItem(textInfo)
1882
                if item is not None:
1883
                    item.loc = [x, y]
1884
                    item.size = (width, height)
1885
                    item.angle = angle
1886
                    item.setDefaultTextColor(Qt.blue)
1887
                    item.addTextItemToScene(self.graphicsView.scene())
1888
                    item.transfer.onRemoved.connect(self.itemRemoved)
1889
            elif event.key() == Qt.Key_D:
1890
                # pop up development toolkit dialog
1891
                from DevelopmentToolkitDialog import QDevelopmentToolkitDialog
1892

    
1893
                modifiers = QApplication.keyboardModifiers()
1894
                if modifiers == Qt.ControlModifier:
1895
                    dlg = QDevelopmentToolkitDialog(self, self.graphicsView)
1896
                    dlg.show()
1897
            elif event.key() == Qt.Key_I:
1898
                # insert symbol item that is selected symbol in tree to main window if symbol already selected on main window, replace
1899
                items = self.symbolTreeWidget.selectedItems()
1900
                if items and hasattr(items[0], 'svgFilePath'):
1901
                    symData = items[0].data(0, self.symbolTreeWidget.TREE_DATA_ROLE)
1902
                    symName = symData.getName()
1903
                else:
1904
                    return
1905

    
1906
                symbolItems = [symbol for symbol in self.graphicsView.scene().selectedItems() if
1907
                               issubclass(type(symbol), SymbolSvgItem)]
1908
                old_symbol = None
1909
                if symbolItems and len(symbolItems) is 1:
1910
                    old_symbol = symbolItems[0]
1911
                    scenePos = QPoint(old_symbol.origin[0], old_symbol.origin[1])
1912
                    old_symbol.transfer.onRemoved.emit(old_symbol)
1913
                else:
1914
                    scenePos = self.current_pos
1915

    
1916
                svg = self.graphicsView.createSymbolObject(symName)
1917
                self.graphicsView.matchSymbolToLine(svg, scenePos)
1918

    
1919
                if old_symbol and svg:
1920
                    from ReplaceCommand import ReplaceCommand
1921

    
1922
                    app_doc_data = AppDocData.instance()
1923

    
1924
                    cmd = ReplaceCommand(app_doc_data.scene, old_symbol, svg)
1925
                    app_doc_data.scene.undo_stack.push(cmd)
1926
                    return
1927
            elif event.key() == Qt.Key_J:
1928
                # insert and connect symbol item that is selected symbol in tree to selected symbol
1929
                items = self.symbolTreeWidget.selectedItems()
1930
                if items and hasattr(items[0], 'svgFilePath'):
1931
                    symData = items[0].data(0, self.symbolTreeWidget.TREE_DATA_ROLE)
1932
                    symName = symData.getName()
1933
                else:
1934
                    return
1935

    
1936
                symbolItems = [symbol for symbol in self.graphicsView.scene().selectedItems() if
1937
                               issubclass(type(symbol), SymbolSvgItem)]
1938
                if symbolItems and len(symbolItems) is not 1:
1939
                    return
1940
                    
1941
                target_symbol = symbolItems[0]
1942
                index =  [index for index in range(len(target_symbol.conn_type)) \
1943
                            if target_symbol.conn_type[index] == 'Primary' or target_symbol.conn_type[index] == 'Secondary']
1944
                for connector in target_symbol.connectors:
1945
                    svg = self.graphicsView.createSymbolObject(symName)
1946
                    if len(svg.connectors) > 1: 
1947
                        if target_symbol.connectors.index(connector) in index and \
1948
                                    (not connector.connectedItem or (connector.connectedItem and type(connector.connectedItem) is QEngineeringLineItem)):
1949
                            self.graphicsView.matchSymbolToLine(svg, connector.sceneBoundingRect().center())
1950
                    elif len(svg.connectors) == 1:
1951
                        if target_symbol.connectors.index(connector) in index and not connector.connectedItem:
1952
                            self.graphicsView.matchSymbolToLine(svg, connector.sceneBoundingRect().center())
1953

    
1954
                if target_symbol:
1955
                    return
1956
            elif event.key() == Qt.Key_X:
1957
                app_doc_data = AppDocData.instance()
1958
                configs = app_doc_data.getAppConfigs('app', 'mode')
1959
                if configs and 1 == len(configs) and 'advanced' == configs[0].value:
1960
                    advanced = True
1961
                    items = self.graphicsView.scene().selectedItems()
1962
                    if items:
1963
                        item = self.symbolTreeWidget.currentItem()
1964
                        if item:
1965
                            self.symbolTreeWidget.showSymbolEditorDialog(item, 0)
1966

    
1967
            QMainWindow.keyPressEvent(self, event)
1968
        except Exception as ex:
1969
            message = 'error occurred({}) in {}:{}'.format(ex, sys.exc_info()[-1].tb_frame.f_code.co_filename,
1970
                                                           sys.exc_info()[-1].tb_lineno)
1971
            self.addMessage.emit(MessageType.Error, message)
1972

    
1973
    def recognizeBatch(self, MainWindow):
1974
        '''
1975
            @brief      batch recognize symbol, text and line
1976
            @author     euisung
1977
            @date       2018.11.23
1978
        
1979
        '''
1980
        from datetime import datetime
1981
        from RecognitionDialog import QRecognitionDialog
1982

    
1983
        app_doc_data = AppDocData.instance()
1984
        project = app_doc_data.getCurrentProject()
1985
        app_doc_data.needReOpening = None
1986
        current_drawing, currentPid = None, None
1987

    
1988
        if self.graphicsView.hasImage():
1989
            current_drawing = app_doc_data.activeDrawing
1990
            currentPid = app_doc_data.activeDrawing.name
1991

    
1992
        # TODO: 무슨 의미인지 주석 필요
1993
        drawingTop = self.treeWidgetDrawingList.topLevelItem(0)
1994
        drawingCount = drawingTop.childCount()
1995
        checkedTreeItems = []
1996
        checkedDrawingPath = []
1997
        for drawing in range(drawingCount):
1998
            drawingChild = drawingTop.child(drawing)
1999
            if drawingChild.checkState(0) == 2:
2000
                checkedTreeItems.append(drawingChild)
2001
                checkedDrawingPath.append(os.path.join(project.getDrawingFilePath(), drawingChild.data(0, 0)))
2002
                if currentPid is not None and drawingChild.data(0, 0).find(currentPid) is 0:
2003
                    app_doc_data.needReOpening = False  # later check need reopening at drawUnknownItems()
2004
                    currentPid = drawingChild.data(0, 0)
2005
        # up to here
2006

    
2007
        if len(checkedDrawingPath) == 0:
2008
            self.showImageSelectionMessageBox()
2009
            return
2010

    
2011
        try:
2012
            self.onClearLog()
2013
            self.dlg = QRecognitionDialog(self, checkedDrawingPath, True)
2014
            self.dlg.exec_()
2015
            if self.dlg.isAccepted == True:
2016
                pass
2017

    
2018
            if app_doc_data.needReOpening == True:
2019
                self.open_image_drawing(current_drawing)
2020

    
2021
            # save working date-time
2022
            drawings = app_doc_data.getDrawings()
2023
            checkedDrawings = []
2024
            for checkedTreeItem in checkedTreeItems:
2025
                for drawing in drawings:
2026
                    if checkedTreeItem.data(0, 0) == drawing.name:
2027
                        if drawing:
2028
                            drawing.datetime = datetime.now().strftime('%Y-%m-%d %H:%M:%S')
2029
                            checkedDrawings.append(drawing)
2030
                            checkedTreeItem.setText(1, datetime.now().strftime('%Y-%m-%d %H:%M:%S'))
2031
            app_doc_data.saveDrawings(checkedDrawings)
2032
            self.changeViewCheckedState(True)
2033
            # up to here
2034
        except Exception as ex:
2035
            message = 'error occurred({}) in {}:{}'.format(repr(ex), sys.exc_info()[-1].tb_frame.f_code.co_filename,
2036
                                                           sys.exc_info()[-1].tb_lineno)
2037
            self.addMessage.emit(MessageType.Error, message)
2038

    
2039
    '''
2040
        @brief      recognize symbol and text
2041
        @author     humkyung
2042
        @date       2018.04.??
2043
        @history    2018.04.16  humkyung    execute line no tracing
2044
                    2018.05.02  Jeongwoo    Show MessageBox when imageviewer doesn't have image
2045
                    2018.05.25  Jeongwoo    Add parameter on QRecognitionDialog.__init__() and Move thread to QRecognitionDialog
2046
                                            Remove codes below if self.dlg.isAccepted == True
2047
                    2018.05.29  Jeongwoo    Remove connects and comments
2048
                    humkyung 2018.11.05 save working date-time
2049
    '''
2050

    
2051
    def recognize(self, MainWindow):
2052
        from datetime import datetime
2053
        from RecognitionDialog import QRecognitionDialog
2054

    
2055
        if not self.graphicsView.hasImage():
2056
            self.showImageSelectionMessageBox()
2057
            return
2058

    
2059
        try:
2060
            appDocData = AppDocData.instance()
2061

    
2062
            self.onClearLog()
2063
            appDocData.needReOpening = False
2064
            drawingList = []
2065
            drawingList.append(self.path)
2066
            self.dlg = QRecognitionDialog(self, drawingList, False)
2067
            self.dlg.exec_()
2068

    
2069
            if appDocData.needReOpening:
2070
                self.itemTreeWidget.setCurrentPID(appDocData.activeDrawing.name)
2071
                self.drawDetectedItemsToScene()
2072

    
2073
                # save working date-time
2074
                drawings = appDocData.getDrawings()
2075
                drawing = [drawing for drawing in drawings if appDocData.imgName == os.path.splitext(drawing.name)[0]]
2076
                if drawing[0]:
2077
                    drawing[0].datetime = datetime.now().strftime('%Y-%m-%d %H:%M:%S')
2078
                    appDocData.saveDrawings(drawing)
2079

    
2080
                currentPid = appDocData.activeDrawing.name
2081

    
2082
                drawingTop = self.treeWidgetDrawingList.topLevelItem(0)
2083
                drawingCount = drawingTop.childCount()
2084

    
2085
                for drawing in range(drawingCount):
2086
                    drawingChild = drawingTop.child(drawing)
2087
                    if drawingChild.data(0, 0).find(currentPid) is 0:
2088
                        drawingChild.setText(1, datetime.now().strftime('%Y-%m-%d %H:%M:%S'))
2089
                self.changeViewCheckedState(True)
2090
                # up to here
2091
        except Exception as ex:
2092
            message = 'error occurred({}) in {}:{}'.format(ex, sys.exc_info()[-1].tb_frame.f_code.co_filename,
2093
                                                           sys.exc_info()[-1].tb_lineno)
2094
            self.addMessage.emit(MessageType.Error, message)
2095

    
2096
    '''
2097
        @brief      remove item from tree widget and then remove from scene
2098
        @date       2018.05.25
2099
        @author     Jeongwoo
2100
    '''
2101

    
2102
    def itemRemoved(self, item):
2103
        try:
2104
            if type(item) is QEngineeringErrorItem:
2105
                # remove error item from inconsistency list
2106
                for row in range(self.tableWidgetInconsistency.rowCount()):
2107
                    if item is self.tableWidgetInconsistency.item(row, 0).tag:
2108
                        self.tableWidgetInconsistency.removeRow(row)
2109
                        break
2110

    
2111
                if item.scene() is not None: item.scene().removeItem(item)
2112
                del item
2113
            else:
2114
                self.itemTreeWidget.itemRemoved(item)
2115

    
2116
                matches = [_item for _item in self.graphicsView.scene().items() if
2117
                           hasattr(_item, 'connectors') and [connector for connector in _item.connectors if
2118
                                                             connector.connectedItem is item]]
2119
                for match in matches:
2120
                    for connector in match.connectors:
2121
                        if connector.connectedItem is item:
2122
                            connector.connectedItem = None
2123
                            connector.highlight(False)
2124

    
2125
                # matches = [_item for _item in self.graphicsView.scene().items() if hasattr(_item, 'remove_assoc_item')]
2126
                # for _item in matches:
2127
                #    _item.remove_assoc_item(item)
2128

    
2129
                app_doc_data = AppDocData.instance()
2130
                if type(item) is QEngineeringLineNoTextItem and item in app_doc_data.tracerLineNos:
2131
                    app_doc_data.tracerLineNos.pop(app_doc_data.tracerLineNos.index(item))
2132

    
2133
                if type(item) is QEngineeringLineItem and item in app_doc_data.lines:
2134
                    app_doc_data.lines.remove(item)
2135

    
2136
                matches = [_item for _item in self.graphicsView.scene().items() if
2137
                           type(_item) is QEngineeringLineNoTextItem]
2138
                matches.extend([lineNo for lineNo in app_doc_data.tracerLineNos if
2139
                                type(lineNo) is QEngineeringTrimLineNoTextItem])
2140
                for match in matches:
2141
                    if item is match.prop('From'):
2142
                        match.set_property('From', None)
2143
                    if item is match.prop('To'):
2144
                        match.set_property('To', None)
2145

    
2146
                    for run_index in reversed(range(len(match.runs))):
2147
                        run = match.runs[run_index]
2148
                        if item in run.items:
2149
                            index = run.items.index(item)
2150
                            run.items.pop(index)
2151
                            if not run.items:
2152
                                run.explode()
2153
                                if type(match) is QEngineeringTrimLineNoTextItem and not match.runs:
2154
                                    app_doc_data.tracerLineNos.pop(app_doc_data.tracerLineNos.index(match))
2155
                            # break
2156

    
2157
                matches = [_item for _item in self.graphicsView.scene().items() if hasattr(_item, 'owner')]
2158
                for match in matches:
2159
                    if match.owner is item:
2160
                        match.owner = None
2161

    
2162
                matches = [_item for _item in self.graphicsView.scene().items() if hasattr(_item, 'attrs')]
2163
                # done = False
2164
                for match in matches:
2165
                    assocs = match.associations()
2166
                    for assoc in assocs:
2167
                        if item is assoc:
2168
                            for attr in match.attrs.keys():
2169
                                if attr.AssocItem and str(item.uid) == str(attr.AssocItem.uid):
2170
                                    attr.AssocItem = None
2171
                                    match.attrs[attr] = ''
2172
                                    # done = True
2173
                            match.remove_assoc_item(item)
2174
                            break
2175
                    # if done: break
2176

    
2177
                if item.scene() is not None: item.scene().removeItem(item)
2178
        except Exception as ex:
2179
            message = 'error occurred({}) in {}:{}'.format(ex, sys.exc_info()[-1].tb_frame.f_code.co_filename,
2180
                                                           sys.exc_info()[-1].tb_lineno)
2181
            self.addMessage.emit(MessageType.Error, message)
2182

    
2183
    '''
2184
        @brief      recognize line
2185
        @author     humkyung
2186
        @date       2018.04.19
2187
        @history    Jeongwoo 2018.04.26 Variable name changed (texts → lineNos)
2188
                                        TextItem type changed (QEngineeringTextItem → QEngineeringLineNoTextItem)
2189
                    humkyung 2018.04.26 remove small objects before recognizing line
2190
                    Jeongwoo 2018.05.02 Show MessageBox when imageviewer doesn't have image
2191
                    Jeongwoo 2018.05.25 Move codes about LineDetector
2192
                    humkyung 2018.06.17 show progress dialog
2193
    '''
2194

    
2195
    def connect_attributes(self, MainWindow):
2196
        from LineNoTracer import LineNoTracer
2197
        from ConnectAttrDialog import QConnectAttrDialog
2198

    
2199
        if not self.graphicsView.hasImage():
2200
            self.showImageSelectionMessageBox()
2201
            return
2202

    
2203
        try:
2204
            dlg = QConnectAttrDialog(self, self.graphicsView.scene())
2205
            dlg.setWindowFlags(self.windowFlags() & ~Qt.WindowCloseButtonHint & ~Qt.WindowContextHelpButtonHint)
2206
            dlg.exec_()
2207
            if dlg.isRunned:
2208
                self.itemTreeWidget.InitLineNoItems()
2209

    
2210
                # construct line no item
2211
                line_nos = AppDocData.instance().tracerLineNos
2212
                for line_no in line_nos:
2213
                    item = self.itemTreeWidget.addTreeItem(self.itemTreeWidget.root, line_no)
2214
                    connectedItems = line_no.getConnectedItems()
2215
                    for connectedItem in connectedItems:
2216
                        if issubclass(type(connectedItem), SymbolSvgItem):
2217
                            self.itemTreeWidget.addTreeItem(item, connectedItem)
2218
                # up to here
2219

    
2220
                if dlg.validation_checked:
2221
                    self.onValidation()
2222

    
2223
                self.graphicsView.invalidateScene()
2224
        except Exception as ex:
2225
            message = 'error occurred({}) in {}:{}'.format(ex, sys.exc_info()[-1].tb_frame.f_code.co_filename,
2226
                                                           sys.exc_info()[-1].tb_lineno)
2227
            self.addMessage.emit(MessageType.Error, message)
2228

    
2229
    '''
2230
        @history    2018.05.25  Jeongwoo    Moved from MainWindow
2231
                                            SvgItem and TextItem Connect with method in this class
2232
                                            Change method to add GraphicsItem
2233
                    2018.05.28  Jeongwoo    Make QGraphicsItem by symbol, text object. Not xml
2234
                    2018.05.29  Jeongwoo    Change method name and Moved from QRecognitionDialog
2235
                    2018.05.30  Jeongwoo    Add parameters on SymbolSvgItem.__init__() (parentSymbol, childSymbol)
2236
                                            Change Method name and seperate each item
2237
                    humkyung 2018.06.11     display difference between original and recognized image
2238
                    Jeongwoo 2018.06.18     Update Scene after all item added
2239
                    2018.11.05  euisung     add save note item because of dependency
2240
                    2018.11.05  euisung     add db delete process before save
2241
                    2018.11.12  euisung     add title block properties
2242
                    2018.11.12  euisung     db part move new method to dbUpdate
2243
                    2018.11.26  euisung     isolate scene adding part -> drawDetectedItemsToScene()
2244
                    2018.11.29  euisung     change name drawDetectedItems() -> createDetectedItems
2245
    '''
2246

    
2247
    def createDetectedItems(self, symbolList, textInfoList, otherTextInfoList, titleBlockTextInfoList):
2248
        try:
2249
            QApplication.processEvents()
2250
            self.createDetectedSymbolItem(symbolList)
2251
            QApplication.processEvents()
2252
            self.createDetectedTextItem(textInfoList)
2253
            QApplication.processEvents()
2254
            self.createDetectedOtherTextItem(otherTextInfoList)
2255
            QApplication.processEvents()
2256
            self.createDetectedTitleBlockTextItem(titleBlockTextInfoList)
2257

    
2258
            # update scene
2259
            # self.graphicsView.scene().update(self.graphicsView.sceneRect())
2260
        except Exception as ex:
2261
            message = 'error occurred({}) in {}:{}'.format(ex, sys.exc_info()[-1].tb_frame.f_code.co_filename,
2262
                                                           sys.exc_info()[-1].tb_lineno)
2263
            self.addMessage.emit(MessageType.Error, message)
2264

    
2265
    def drawDetectedItemsToScene(self):
2266
        """add detected items to scene"""
2267
        from SaveWorkCommand import SaveWorkCommand
2268

    
2269
        app_doc_data = AppDocData.instance()
2270

    
2271
        try:
2272
            for symbol in app_doc_data.symbols:
2273
                if issubclass(type(symbol), SymbolSvgItem):
2274
                    symbol.addSvgItemToScene(self.graphicsView.scene())
2275
                else:
2276
                    self.graphicsView.scene().addItem(symbol)
2277

    
2278
            for text in app_doc_data.texts:
2279
                self.addTextItemToScene(text)
2280

    
2281
            for lineNo in app_doc_data.tracerLineNos:
2282
                self.addTextItemToScene(lineNo)
2283

    
2284
            # remove lines which is located inside symbol
2285
            for symbol in app_doc_data.symbols:
2286
                rect = symbol.sceneBoundingRect()
2287
                rect.adjust(-10, -10, 10, 10)
2288
                matches = [line for line in app_doc_data.lines if rect.contains(line.line().p1()) and
2289
                           rect.contains(line.line().p2()) and
2290
                           not line.has_connection]
2291
                app_doc_data.lines = [line for line in app_doc_data.lines if line not in matches]
2292
            # up to here
2293

    
2294
            for line in app_doc_data.lines:
2295
                self.graphicsView.scene().addItem(line)
2296
                line.transfer.onRemoved.connect(self.itemRemoved)
2297
                for conn in line.connectors:
2298
                    conn.transfer.onPosChanged.connect(line.onConnectorPosChaned)
2299

    
2300
            for unknown in app_doc_data.unknowns + app_doc_data.lineIndicators:
2301
                self.graphicsView.scene().addItem(unknown)
2302

    
2303
            # save scene
2304
            self.dbUpdate()
2305
            SaveWorkCommand.save_to_xml()
2306
        finally:
2307
            # update scene
2308
            self.graphicsView.scene().update(self.graphicsView.sceneRect())
2309

    
2310
    def postDetectLineProcess(self):
2311
        '''
2312
            @brief  check allowables among undetected items
2313
            @author euisung
2314
            @date   2018.11.15
2315
            @history    2018.11.15  euisung    no more used, moved to TextItemFactoy isLineNo()
2316
        '''
2317
        from TextItemFactory import TextItemFactory
2318

    
2319
        appDocData = AppDocData.instance()
2320

    
2321
        tableNames = ["Fluid Code", "Insulation Purpose", "PnID Number", "Piping Materials Class", "Unit Number"]
2322
        tableDatas = []
2323
        for tableName in tableNames:
2324
            tableNameFormat = tableName.replace(' ', '').replace('&&', 'n')
2325
            tableDatas.append(appDocData.getCodeTable(tableNameFormat))
2326

    
2327
        items = self.graphicsView.scene().items()
2328
        for item in items:
2329
            if type(item) is not QEngineeringTextItem:
2330
                continue
2331
            text = item.text()
2332
            for tableData in tableDatas:
2333
                for data in tableData:
2334
                    if data[3] == '':
2335
                        continue
2336
                    else:
2337
                        allows = data[3].split(',')
2338
                        for allow in allows:
2339
                            text = text.replace(allow, data[1])
2340

    
2341
            lineItem = TextItemFactory.instance().createTextItem(text)
2342
            if type(lineItem) is QEngineeringLineNoTextItem:
2343
                lineItem.loc = item.loc
2344
                lineItem.size = item.size
2345
                lineItem.angle = item.angle
2346
                lineItem.area = item.area
2347
                # lineItem.addTextItemToScene(self.graphicsView.scene())
2348
                lineItem.transfer.onRemoved.connect(self.itemRemoved)
2349
                item.transfer.onRemoved.emit(item)
2350
                appDocData.lineNos.append(lineItem)
2351

    
2352
    def createDetectedTitleBlockTextItem(self, textInfoList):
2353
        '''
2354
            @brief  draw title block
2355
            @author euisung
2356
            @date   2018.11.12
2357
            @history    2018.11.26  euisung     remove scene dependency
2358
                        2018.11.29  euisung     change name drawDetectedTitleBlockTextItem() -> createDetectedTitleBlockTextItem
2359
        '''
2360
        from TextItemFactory import TextItemFactory
2361
        import math
2362

    
2363
        try:
2364
            appDocData = AppDocData.instance()
2365

    
2366
            # parse texts
2367
            for textInfos in textInfoList:
2368
                if len(textInfos[1]) is 0:
2369
                    continue
2370

    
2371
                for textInfo in textInfos[1]:
2372
                    x = textInfo.getX()
2373
                    y = textInfo.getY()
2374
                    width = textInfo.getW()
2375
                    height = textInfo.getH()
2376
                    angle = round(math.radians(textInfo.getAngle()), 2)
2377
                    text = textInfo.getText()
2378
                    if not text: continue
2379
                    item = TextItemFactory.instance().createTextItem(textInfo)
2380

    
2381
                    if item is not None:
2382
                        item.loc = [x, y]
2383
                        item.size = (width, height)
2384
                        item.angle = angle
2385
                        item.area = textInfos[0]
2386
                        # self.addTextItemToScene(item)
2387
                        # appDocData.texts.append(item)
2388
                        appDocData.allItems.append(item)
2389
        except Exception as ex:
2390
            message = 'error occurred({}) in {}:{}'.format(ex, sys.exc_info()[-1].tb_frame.f_code.co_filename,
2391
                                                           sys.exc_info()[-1].tb_lineno)
2392
            self.addMessage.emit(MessageType.Error, message)
2393

    
2394
    '''
2395
        @brief      
2396
        @author     humkyung
2397
        @date       2018.08.23
2398
        @history    2018.11.26  euisung     remove scene dependency
2399
                    2018.11.26  euisung     isolate scene adding part -> drawDetectedItemsToScene()
2400
                    2018.11.    euisung     no more used
2401
                    2018.11.29  euisung     change name drawDetectedLines() -> createDetectedLines
2402
    '''
2403

    
2404
    def createDetectedLines(self, lineList, worker):
2405
        appDocData = AppDocData.instance()
2406
        area = appDocData.getArea('Drawing')
2407

    
2408
        for pts in lineList:
2409
            processLine = QEngineeringLineItem(vertices=[(area.x + param[0], area.y + param[1]) for param in pts])
2410
            processLine.area = 'Drawing'
2411
            # self.graphicsView.scene().addItem(processLine)
2412
            appDocData.lines.append(processLine)
2413
            appDocData.allItems.append(processLine)
2414

    
2415
            # if processLine.length() > 100: # TODO: check critical length
2416
            #    processLine.addFlowArrow()
2417

    
2418
        # re-order process line's start,end according to flow mark
2419
        # worker.arrangeLinePosition(lines, symbols, listWidget)
2420
        # up to here
2421

    
2422
    '''
2423
        history     2018.06.09  humkyung    check length of original and connection point is 2 while parsing
2424
                    2018.11.26  euisung     remove scene dependency
2425
                    2018.11.29  euisung     change name drawDetectedSymbolItem() -> createDetectedSymbolItem
2426
    '''
2427

    
2428
    def createDetectedSymbolItem(self, symbolList):
2429
        from GraphicsBoundingBoxItem import QGraphicsBoundingBoxItem
2430
        from SymbolSvgItem import SymbolSvgItem
2431
        import math
2432

    
2433
        try:
2434
            appDocData = AppDocData.instance()
2435
            project = appDocData.getCurrentProject()
2436

    
2437
            searchedMap = []
2438
            for symbol in symbolList:
2439
                pt = [float(x) for x in symbol.getSp()]
2440
                size = [symbol.getWidth(), symbol.getHeight()]
2441
                name = symbol.getName()
2442
                angle = round(math.radians(symbol.getRotatedAngle()), 2)
2443
                _type = symbol.getType()
2444
                flip = symbol.getDetectFlip()
2445
                origin = [0, 0]
2446
                if 2 == len(symbol.getOriginalPoint().split(',')):
2447
                    tokens = symbol.getOriginalPoint().split(',')
2448
                    origin = [pt[0] + float(tokens[0]), pt[1] + float(tokens[1])]
2449
                connPts = []
2450
                if symbol.getConnectionPoint() is not None and symbol.getConnectionPoint() != '':
2451
                    for param in symbol.getConnectionPoint().split('/'):
2452
                        tokens = param.split(',')
2453
                        connPts.append(
2454
                            ('AUTO', pt[0] + float(tokens[0]), pt[1] + float(tokens[1]), '0') if len(tokens) == 2 else \
2455
                                (tokens[0], pt[0] + float(tokens[1]), pt[1] + float(tokens[2]), '0') if len(
2456
                                    tokens) == 3 else \
2457
                                    (tokens[0], pt[0] + float(tokens[1]), pt[1] + float(tokens[2]), tokens[3]) if len(
2458
                                        tokens) == 4 else None)
2459

    
2460
                parentSymbol = symbol.getBaseSymbol()
2461
                childSymbol = symbol.getAdditionalSymbol()
2462
                hasInstrumentLabel = symbol.getHasInstrumentLabel()
2463

    
2464
                svgFilePath = os.path.join(project.getSvgFilePath(), _type, name + '.svg')
2465
                if os.path.isfile(svgFilePath):
2466
                    svg = SymbolSvgItem.createItem(_type, None, svgFilePath, owner=None, flip=flip)
2467
                    svg.hit_ratio = symbol.hitRate
2468
                    svg.buildItem(name, _type, angle, pt, size, origin, connPts, parentSymbol, childSymbol,
2469
                                  hasInstrumentLabel)
2470
                    # svg.reCalculationRotatedItem()
2471
                    svg.area = 'Drawing'
2472

    
2473
                    # set owner - 2018.07.20 added by humkyung                   
2474
                    matches = [searched for searched in searchedMap if searched[0] == symbol.owner]
2475
                    if len(matches) == 1:
2476
                        svg.owner = matches[0][1]
2477
                    searchedMap.append((symbol, svg))
2478
                    # up to here
2479

    
2480
                    svg.transfer.onRemoved.connect(self.itemRemoved)
2481
                    # self.addSvgItemToScene(svg)
2482
                    appDocData.symbols.append(svg)
2483
                    appDocData.allItems.append(svg)
2484
                else:
2485
                    item = QGraphicsBoundingBoxItem(pt[0], pt[1], size[0], size[1])
2486
                    item.isSymbol = True
2487
                    item.angle = angle
2488
                    item.setPen(QPen(Qt.red, 5, Qt.SolidLine))
2489
                    # self.graphicsView.scene().addItem(item)
2490
                    # appDocData.symbols.append(item)
2491
                    appDocData.allItems.append(item)
2492
            # up to here
2493
        except Exception as ex:
2494
            message = 'error occurred({}) in {}:{}'.format(ex, sys.exc_info()[-1].tb_frame.f_code.co_filename,
2495
                                                           sys.exc_info()[-1].tb_lineno)
2496
            self.addMessage.emit(MessageType.Error, message)
2497

    
2498
    '''
2499
        @history    2018.06.08  Jeongwoo    Add parameter on round method
2500
        @history    2018.11.02  euisung     Add save note text item
2501
        @history    2018.11.05  euisung     delete save note text item and move to drawDetectedItems()
2502
                    2018.11.26  euisung     remove scene dependency
2503
                    2018.11.29  euisung     change name drawDetectedTextItem() -> createDetectedTextItem
2504
    '''
2505

    
2506
    def createDetectedTextItem(self, textInfoList):
2507
        from TextItemFactory import TextItemFactory
2508
        import math
2509

    
2510
        try:
2511
            appDocData = AppDocData.instance()
2512

    
2513
            # parse texts
2514
            for textInfo in textInfoList:
2515
                x = textInfo.getX()
2516
                y = textInfo.getY()
2517
                width = textInfo.getW()
2518
                height = textInfo.getH()
2519
                angle = round(math.radians(textInfo.getAngle()), 2)
2520
                text = textInfo.getText()
2521
                if not text: continue
2522

    
2523
                item = TextItemFactory.instance().createTextItem(textInfo)
2524
                if item is not None:
2525
                    item.loc = [x, y]
2526
                    item.size = (width, height)
2527
                    item.angle = angle
2528
                    item.area = 'Drawing'
2529
                    item.transfer.onRemoved.connect(self.itemRemoved)
2530
                    # self.addTextItemToScene(item)
2531
                    # appDocData.texts.append(item)
2532
                    appDocData.allItems.append(item)
2533
        except Exception as ex:
2534
            message = 'error occurred({}) in {}:{}'.format(ex, sys.exc_info()[-1].tb_frame.f_code.co_filename,
2535
                                                           sys.exc_info()[-1].tb_lineno)
2536
            self.addMessage.emit(MessageType.Error, message)
2537

    
2538
    '''
2539
        @brief      draw detected texts except which in drawing area
2540
        @history    2018.11.29  euisung     change name drawDetectedOtherTextItem() -> createDetectedOtherTextItem
2541
    '''
2542

    
2543
    def createDetectedOtherTextItem(self, otherTextInfoList):
2544
        from TextItemFactory import TextItemFactory
2545
        import math
2546

    
2547
        try:
2548
            appDocData = AppDocData.instance()
2549

    
2550
            # parse notes
2551
            for textInfoMap in otherTextInfoList:
2552
                if textInfoMap[0] == 'Note' or textInfoMap[1] is None:
2553
                    pass
2554

    
2555
                for textInfo in textInfoMap[1]:
2556
                    x = textInfo.getX()
2557
                    y = textInfo.getY()
2558
                    width = textInfo.getW()
2559
                    height = textInfo.getH()
2560
                    angle = round(math.radians(textInfo.getAngle()))
2561
                    text = textInfo.getText()
2562

    
2563
                    item = TextItemFactory.instance().createTextItem(textInfo)
2564

    
2565
                    item.loc = [x, y]
2566
                    item.size = (width, height)
2567
                    item.angle = angle
2568
                    item.area = textInfoMap[0]
2569
                    item.transfer.onRemoved.connect(self.itemRemoved)
2570
                    # appDocData.texts.append(item)
2571
                    appDocData.allItems.append(item)
2572
        except Exception as ex:
2573
            message = 'error occurred({}) in {}:{}'.format(ex, sys.exc_info()[-1].tb_frame.f_code.co_filename,
2574
                                                           sys.exc_info()[-1].tb_lineno)
2575
            self.addMessage.emit(MessageType.Error, message)
2576

    
2577
    '''
2578
        @brief  draw unknown items 
2579
        @author humkyung
2580
        @date   2018.06.12
2581
        @history    2018.06.14  Jeongwoo    Change method to add unknown item
2582
                    2018.06.18  Jeongwoo    Add connect on unknown item
2583
                                            Add [transfer] for using pyqtSignal
2584
                    2018.11.26  euisung     remove scene dependency
2585
                    2018.11.26  euisung     isolate scene adding part -> drawDetectedItemsToScene()
2586
                    2018.11.27  euisung     add save to xml
2587
                    2018.11.29  euisung     change name drawUnknownItems() -> createUnknownItems
2588
    '''
2589

    
2590
    def createUnknownItems(self, path):
2591
        from QEngineeringFlowArrowItem import QEngineeringFlowArrowItem
2592
        from EngineeringLineItem import QEngineeringLineItem
2593
        from EngineeringUnknownItem import QEngineeringUnknownItem
2594

    
2595
        try:
2596
            docData = AppDocData.instance()
2597
            project = docData.getCurrentProject()
2598
            windowSize = docData.getSlidingWindowSize()
2599

    
2600
            thickness = int(windowSize[1] / 2)
2601

    
2602
            if docData.needReOpening is not None:
2603
                docData.needReOpening = True
2604

    
2605
            diffFilePath = os.path.join(project.getTempPath(), "DIFF_" + os.path.basename(path))
2606
            if os.path.isfile(diffFilePath):
2607
                imgDiff = cv2.threshold(cv2.cvtColor(cv2.imread(diffFilePath, 1), cv2.COLOR_BGR2GRAY), 0, 255,
2608
                                        cv2.THRESH_BINARY + cv2.THRESH_OTSU)[1]
2609

    
2610
                # remove line from image
2611
                lines = docData.lines
2612
                for line in lines:
2613
                    line.drawToImage(imgDiff, 255, thickness) if line.thickness is None else \
2614
                        line.drawToImage(imgDiff, 255, line.thickness)
2615
                cv2.imwrite(diffFilePath, imgDiff)
2616
                # up to here
2617

    
2618
                imgNot = np.ones(imgDiff.shape, np.uint8)
2619
                cv2.bitwise_not(imgDiff, imgNot)
2620
                configs = docData.getConfigs('Filter', 'ErodeSize')
2621
                kernel = int(configs[0].value) if 1 == len(configs) else 3
2622
                imgNot = cv2.erode(imgNot, np.ones((kernel, kernel), np.uint8))
2623
                imgNot = cv2.dilate(imgNot, np.ones((8 + kernel, 8 + kernel), np.uint8))
2624

    
2625
                contours, hierarchy = cv2.findContours(imgNot, cv2.RETR_EXTERNAL, cv2.CHAIN_APPROX_SIMPLE)
2626

    
2627
                ##
2628
                idx = 0
2629
                ##
2630
                smallContours = []
2631
                minimumSize = docData.getConfigs('Filter', 'MinimumSize')
2632
                for contour in contours:
2633
                    [x, y, w, h] = cv2.boundingRect(contour)
2634

    
2635
                    # remove too small one
2636
                    if len(minimumSize) is 1:
2637
                        if (w * h < int(minimumSize[0].value) * int(minimumSize[0].value)):
2638
                            smallContours.append(contour)
2639
                            idx += 1
2640
                            continue
2641

    
2642
                    '''
2643
                    rect = QRectF(x, y, w, h)
2644
                    items = [item for item in diffItems if item.boundingRect().contains(rect)]
2645
                    if len(items) > 0: continue
2646
                    
2647
                    items = [item for item in diffItems if rect.contains(item.boundingRect())]
2648
                    for item in items:
2649
                        diffItems.remove(item)
2650
                    '''
2651

    
2652
                    # create unknown item
2653
                    epsilon = cv2.arcLength(contour, True) * 0.001
2654
                    approx = cv2.approxPolyDP(contour, epsilon, True)
2655
                    approx = [pt[0] for pt in approx]
2656
                    resultStr, resultList = self.determineRemainObject(idx, contours, imgNot)
2657
                    if resultStr == 'LineIndicator':
2658
                        item = QEngineeringUnknownItem(approx, 'True', resultList[0], resultList[1])
2659
                        docData.lineIndicators.append(item)
2660
                    elif resultStr == 'MissingLine':
2661
                        pass
2662
                    elif resultStr == 'Unknown':
2663
                        item = QEngineeringUnknownItem(approx, 'False')
2664
                        docData.unknowns.append(item)
2665
                    item.area = 'Drawing'
2666
                    docData.allItems.append(item)
2667
                    item.transfer.onRemoved.connect(self.itemRemoved)
2668
                    idx += 1
2669
                    # up to here                    
2670

    
2671
                imgNotRemoveSmall = cv2.drawContours(imgNot, smallContours, -1, 0, -1)
2672
                notFilePath = os.path.join(project.getTempPath(), "NOT_" + os.path.basename(path))
2673
                cv2.imwrite(notFilePath, imgNotRemoveSmall)
2674
            else:
2675
                message = 'can\'t found {}'.format(diffFilePath)
2676
                self.addMessage.emit(MessageType.Normal, message)
2677
        except Exception as ex:
2678
            message = 'error occurred({}) in {}:{}'.format(ex, sys.exc_info()[-1].tb_frame.f_code.co_filename,
2679
                                                           sys.exc_info()[-1].tb_lineno)
2680
            self.addMessage.emit(MessageType.Error, message)
2681

    
2682
    def determineRemainObject(self, idx, contours, imgNot):
2683
        '''
2684
            @brief      determine remain objects -> line no indicator or unknown
2685
            @author     euisung
2686
            @date       2018.12.26
2687
            @history    2019.03.25  euisung    Change name isLineNoIndicator -> determineRemainObject
2688
        '''
2689
        import math
2690
        [x, y, w, h] = cv2.boundingRect(contours[idx])
2691

    
2692
        if (w < 250 and h < 250):
2693
            return ('Unknown', [])
2694

    
2695
        fLines = []
2696
        maxDifAngle = 3
2697
        mask = np.zeros_like(imgNot)
2698
        cv2.drawContours(mask, contours, idx, 123, -1)  # Draw filled contour in mask
2699
        out = np.zeros_like(imgNot)  # Extract out the object and place into output image
2700
        out[mask == 123] = imgNot[mask == 123]
2701

    
2702
        # Now crop
2703
        ##print(out)
2704
        (x, y) = np.where(mask == 123)
2705
        (topx, topy) = (np.min(x), np.min(y))
2706
        (bottomx, bottomy) = (np.max(x), np.max(y))
2707
        out = out[topx:bottomx + 1, topy:bottomy + 1]
2708
        h, w = out.shape[0], out.shape[1]
2709
        maxDifH, maxDifW = math.ceil(math.tan(4 * math.pi / 180) / 2 * w), math.ceil(
2710
            math.tan(4 * math.pi / 180) / 2 * h)
2711

    
2712
        # detection lines
2713
        edged2 = cv2.Canny(out, 100, 200)
2714
        lines = cv2.HoughLinesP(image=edged2, rho=1, theta=np.pi / 180, threshold=25, minLineLength=30, maxLineGap=25)
2715
        # lines = cv2.HoughLines(edged2, 1, np.pi/180, 60)
2716
        if lines is None:
2717
            return ('Unknown', [])
2718
        for line in lines:
2719
            # r, theta = line[0]
2720
            # a, b = np.cos(theta), np.sin(theta)
2721
            # x0, y0 = a * r, b * r
2722
            # x1, y1 = int(x0 + 1000 * (-b)), int(y0 + 1000 * a)
2723
            # x2, y2 = int(x0 - 1000 * (-b)), int(y0 - 1000 * a)
2724
            # cv2.line(out, (x1, y1), (x2, y2), (0, 255, 0), 3)
2725
            x1, y1, x2, y2 = line[0]
2726
            degree = math.atan2(y2 - y1, x2 - x1) * 180 / math.pi
2727
            fLine = [x1, y1, x2, y2, degree]
2728
            # print(fLine)
2729
            fLines.append(fLine)
2730

    
2731
        horLines = []
2732
        verLines = []
2733
        otherLines = []
2734
        isVH = None
2735
        for fLine in fLines:
2736
            degree = math.fabs(fLine[4])
2737
            if degree >= 90 - maxDifAngle:
2738
                verLines.append(fLine)
2739
            elif degree <= maxDifAngle:
2740
                horLines.append(fLine)
2741
            else:
2742
                otherLines.append(fLine)
2743

    
2744
        baseLines = []
2745
        baseDifV = 0
2746
        if len(horLines):
2747
            x, y = w / 2, 0
2748
            baseDifV = maxDifH
2749
            for horLine in horLines:
2750
                x1, y1, x2, y2 = horLine[0], horLine[1], horLine[2], horLine[3]
2751
                y = ((y2 - y1) / (x2 - x1)) * x + y1 - ((y2 - y1) / (x2 - x1)) * x1
2752
                horLine.append(y)
2753
            baseLines = horLines
2754
            isVH = 'H'
2755
        if len(verLines):
2756
            x, y = 0, h / 2
2757
            baseDifV = maxDifW
2758
            for verLine in verLines:
2759
                x1, y1, x2, y2 = verLine[0], verLine[1], verLine[2], verLine[3]
2760
                x = ((x2 - x1) / (y2 - y1)) * y + x1 - ((x2 - x1) / (y2 - y1)) * y1
2761
                verLine.append(x)
2762
            baseLines = verLines
2763
            isVH = 'V'
2764

    
2765
        for otherLine in otherLines:
2766
            x, y = w / 2, 0
2767
            x1, y1, x2, y2 = otherLine[0], otherLine[1], otherLine[2], otherLine[3]
2768
            y = ((y2 - y1) / (x2 - x1)) * x + y1 - ((y2 - y1) / (x2 - x1)) * x1
2769
            otherLine.append(y)
2770

    
2771
        # determine line no indicator 
2772
        if not ((len(horLines) > 0 and len(verLines) > 0) or len(otherLines) is 0 or (
2773
                len(horLines) == 0 and len(verLines) == 0)):
2774
            result, mergedOtherLine = self.isLineNoIndicator(w, h, maxDifAngle, baseDifV, baseLines, otherLines)
2775
            if result:
2776
                # print(fLines)
2777
                return ('LineIndicator', [isVH, mergedOtherLine])
2778

    
2779
        return ('Unknown', [])
2780

    
2781
    def isLineNoIndicator(self, w, h, maxDifAngle, baseDifV, baseLines, otherLines):
2782
        '''
2783
            @brief      determine line no indicator
2784
            @author     euisung
2785
            @date       2019.03.25
2786
        '''
2787
        import math
2788

    
2789
        if (w < 250 and h < 250):
2790
            return (False, None)
2791

    
2792
        isSameLine = True
2793
        i = 0
2794
        for baseLine in baseLines:
2795
            if not isSameLine: break
2796
            j = 0
2797
            for baseLinee in baseLines:
2798
                if i == j:
2799
                    j += 1
2800
                    continue
2801
                difV = math.fabs(baseLine[5] - baseLinee[5])
2802
                if difV > baseDifV:
2803
                    isSameLine = False
2804
                    break
2805
                j += 1
2806
            i += 1
2807
        if not isSameLine:
2808
            return (False, None)
2809

    
2810
        isSameLine = True
2811
        i = 0
2812
        maxY = 0
2813
        for otherLine in otherLines:
2814
            y = otherLine[5]
2815
            if math.fabs(y) > maxY:
2816
                maxY = math.fabs(y)
2817
            if not isSameLine: break
2818
            j = 0
2819
            for otherLinee in otherLines:
2820
                if i == j:
2821
                    j += 1
2822
                    continue
2823
                difV = math.fabs(otherLine[4] - otherLinee[4])
2824
                if difV > maxDifAngle:
2825
                    isSameLine = False
2826
                    break
2827
                j += 1
2828
            i += 1
2829
        if not isSameLine:
2830
            return (False, None)
2831

    
2832
        isSameLine = True
2833
        mergedOtherLine = [0, 0, 0, 0]
2834
        i = 0
2835
        maxDif = math.ceil(math.tan(4 * math.pi / 180) * maxY)
2836
        for otherLine in otherLines:
2837
            if not isSameLine: break
2838
            j = 0
2839
            for otherLinee in otherLines:
2840
                if i == j:
2841
                    j += 1
2842
                    continue
2843
                angle = math.fabs(otherLine[4] + otherLinee[4]) / 2
2844
                difV = math.fabs(otherLine[5] - otherLinee[5])
2845
                dist = math.sin((90 - angle) * math.pi / 180) * difV
2846
                if dist > maxDif:
2847
                    isSameLine = False
2848
                    break
2849
                j += 1
2850
            i += 1
2851
            mergedOtherLine[0] += otherLine[0]
2852
            mergedOtherLine[1] += otherLine[1]
2853
            mergedOtherLine[2] += otherLine[2]
2854
            mergedOtherLine[3] += otherLine[3]
2855
        if not isSameLine:
2856
            (False, None)
2857

    
2858
        # Show the output image
2859
        # print('line no indicator')
2860
        mergedOtherLine[0] = round(mergedOtherLine[0] / len(otherLines))
2861
        mergedOtherLine[1] = round(mergedOtherLine[1] / len(otherLines))
2862
        mergedOtherLine[2] = round(mergedOtherLine[2] / len(otherLines))
2863
        mergedOtherLine[3] = round(mergedOtherLine[3] / len(otherLines))
2864
        # cv2.line(out, (mergedOtherLine[0], mergedOtherLine[1]), (mergedOtherLine[2], mergedOtherLine[3]), (255, 255, 255), 3)
2865
        # cv2.imshow('Output', out)
2866
        # cv2.waitKey(0)
2867
        # cv2.destroyAllWindows()
2868
        return (True, mergedOtherLine)
2869

    
2870
    def init_add_tree_item(self, line_no_tree_item, run_item):
2871
        """ insert symbol item and find line no as owner """
2872
        # insert
2873
        self.itemTreeWidget.addTreeItem(line_no_tree_item, run_item)
2874
        # find
2875
        self.itemTreeWidget.addTreeItem(line_no_tree_item, run_item)
2876

    
2877
    def load_drawing(self, drawing):
2878
        """ load drawing """
2879
        from EngineeringRunItem import QEngineeringRunItem
2880
        from QEngineeringTrimLineNoTextItem import QEngineeringTrimLineNoTextItem
2881

    
2882
        app_doc_data = AppDocData.instance()
2883
        try:
2884
            symbols = []
2885
            lines = []
2886

    
2887
            components = app_doc_data.get_components(drawing.UID)
2888
            maxValue = len(components) * 2
2889
            self.progress.setMaximum(maxValue) if maxValue > 0 else None
2890

    
2891
            """ parsing all symbols """
2892
            for symbol in [component for component in components if int(component['SymbolType_UID']) != -1]:
2893
                item = SymbolSvgItem.from_database(symbol)
2894
                if item is not None:
2895
                    item.transfer.onRemoved.connect(self.itemRemoved)
2896
                    symbols.append(item)
2897
                    app_doc_data.symbols.append(item)
2898
                    item.addSvgItemToScene(self.graphicsView.scene())
2899
                else:
2900
                    pt = [float(symbol['X']), float(symbol['Y'])]
2901
                    size = [float(symbol['Width']), float(symbol['Height'])]
2902
                    angle = float(symbol['Rotation'])
2903
                    item = QGraphicsBoundingBoxItem(pt[0], pt[1], size[0], size[1])
2904
                    item.isSymbol = True
2905
                    item.angle = angle
2906
                    item.setPen(QPen(Qt.red, 5, Qt.SolidLine))
2907
                    self.graphicsView.scene().addItem(item)
2908
                    item.transfer.onRemoved.connect(self.itemRemoved)
2909

    
2910
                self.progress.setValue(self.progress.value() + 1)
2911

    
2912
            QApplication.processEvents()
2913

    
2914
            # parse texts
2915
            for text in [component for component in components if
2916
                         component['Name'] == 'Text' and component['SymbolType_UID'] == -1]:
2917
                item = QEngineeringTextItem.from_database(text)
2918
                if item is not None:
2919
                    item.uid = text['UID']
2920
                    item.attribute = text['Value']
2921
                    name = text['Name']
2922
                    item.transfer.onRemoved.connect(self.itemRemoved)
2923
                    self.addTextItemToScene(item)
2924

    
2925
                self.progress.setValue(self.progress.value() + 1)
2926

    
2927
            QApplication.processEvents()
2928

    
2929
            # note
2930
            for note in [component for component in components if
2931
                         component['Name'] == 'Note' and component['SymbolType_UID'] == -1]:
2932
                item = QEngineeringTextItem.from_database(note)
2933
                if item is not None:
2934
                    item.uid = note['UID']
2935
                    attributeValue = note['Value']
2936
                    name = note['Name']
2937
                    item.transfer.onRemoved.connect(self.itemRemoved)
2938
                    self.addTextItemToScene(item)
2939

    
2940
                self.progress.setValue(self.progress.value() + 1)
2941

    
2942
            QApplication.processEvents()
2943

    
2944
            for line in [component for component in components if
2945
                         component['Name'] == 'Line' and component['SymbolType_UID'] == -1]:
2946
                item = QEngineeringLineItem.from_database(line)
2947
                if item:
2948
                    item.transfer.onRemoved.connect(self.itemRemoved)
2949
                    self.graphicsView.scene().addItem(item)
2950
                    lines.append(item)
2951

    
2952
                self.progress.setValue(self.progress.value() + 1)
2953

    
2954
            QApplication.processEvents()
2955

    
2956
            for unknown in [component for component in components if
2957
                            component['Name'] == 'Unknown' and component['SymbolType_UID'] == -1]:
2958
                item = QEngineeringUnknownItem.from_database(unknown)
2959
                item.transfer.onRemoved.connect(self.itemRemoved)
2960
                if item is not None:
2961
                    item.transfer.onRemoved.connect(self.itemRemoved)
2962
                    self.graphicsView.scene().addItem(item)
2963

    
2964
                self.progress.setValue(self.progress.value() + 1)
2965

    
2966
            QApplication.processEvents()
2967

    
2968
            for component in [component for component in components if
2969
                              component['Name'] == 'Line NO' and component['SymbolType_UID'] == -1]:
2970
                line_no = QEngineeringLineNoTextItem.from_database(component)
2971
                if type(line_no) is QEngineeringLineNoTextItem:
2972
                    line_no.transfer.onRemoved.connect(self.itemRemoved)
2973
                    self.addTextItemToScene(line_no)
2974
                    line_no_tree_item = self.itemTreeWidget.addTreeItem(self.itemTreeWidget.root, line_no)
2975

    
2976
                    runs = app_doc_data.get_pipe_runs(str(line_no.uid))
2977
                    if not runs: continue
2978
                    for run in runs:
2979
                        line_run = QEngineeringRunItem()
2980
                        run_items = app_doc_data.get_pipe_run_items(run['UID'])
2981
                        for record in run_items:
2982
                            uid = record['Components_UID']
2983
                            run_item = self.graphicsView.findItemByUid(uid)
2984
                            if run_item is not None:
2985
                                run_item._owner = line_no
2986
                                line_run.items.append(run_item)
2987
                        line_run.owner = line_no
2988
                        line_no.runs.append(line_run)
2989

    
2990
                        for run_item in line_run.items:
2991
                            if issubclass(type(run_item), SymbolSvgItem):
2992
                                self.init_add_tree_item(line_no_tree_item, run_item)
2993

    
2994
                self.progress.setValue(self.progress.value() + 1)
2995
            QApplication.processEvents()
2996

    
2997
            for component in [component for component in components if
2998
                              component['Name'] == 'Trim Line NO' and component['SymbolType_UID'] == -1]:
2999
                line_no = QEngineeringTrimLineNoTextItem()
3000
                line_no.uid = uuid.UUID(component['UID'])
3001

    
3002
                runs = app_doc_data.get_pipe_runs(str(line_no.uid))
3003
                if not runs: continue
3004

    
3005
                line_no_tree_item = self.itemTreeWidget.addTreeItem(self.itemTreeWidget.root, line_no)
3006

    
3007
                for run in runs:
3008
                    line_run = QEngineeringRunItem()
3009
                    run_items = app_doc_data.get_pipe_run_items(run['UID'])
3010
                    for record in run_items:
3011
                        uid = record['Components_UID']
3012
                        run_item = self.graphicsView.findItemByUid(uid)
3013
                        if run_item is not None:
3014
                            run_item.owner = line_no
3015
                            line_run.items.append(run_item)
3016
                    line_run.owner = line_no
3017
                    line_no.runs.append(line_run)
3018

    
3019
                    for run_item in line_run.items:
3020
                        if issubclass(type(run_item), SymbolSvgItem):
3021
                            self.init_add_tree_item(line_no_tree_item, run_item)
3022

    
3023
                app_doc_data.tracerLineNos.append(line_no)
3024

    
3025
                self.progress.setValue(self.progress.value() + 1)
3026

    
3027
            for component in [component for component in components if
3028
                              component['Name'] == 'VendorPackage' and component['SymbolType_UID'] == -1]:
3029
                item = QEngineeringVendorItem.from_database(component)
3030
                if item is not None:
3031
                    item.transfer.onRemoved.connect(self.itemRemoved)
3032
                    self.graphicsView.scene().addItem(item)
3033

    
3034
            # connect flow item to line
3035
            for line in lines:
3036
                line.update_arrow()
3037
                app_doc_data.lines.append(line)
3038
            # for flowMark in [item for item in symbols if type(item) is QEngineeringFlowMarkItem]:
3039
            #    for line in lines:
3040
            #        if flowMark.owner is line:
3041
            #            line._flowMark.append(flowMark)
3042
            #            flowMark.setParentItem(line)
3043
            # up to here
3044

    
3045
            """ update scene """
3046
            self.graphicsView.scene().update(self.graphicsView.sceneRect())
3047
            for item in self.graphicsView.scene().items():
3048
                up_progress = False
3049
                # binding items
3050
                if hasattr(item, 'owner'):
3051
                    item.owner
3052
                    up_progress = True
3053
                if hasattr(item, 'connectors'):
3054
                    for connector in item.connectors:
3055
                        connector.connectedItem
3056
                    up_progress = True
3057

    
3058
                if up_progress:
3059
                    self.progress.setValue(self.progress.value() + 1)
3060
            
3061
            for item in self.graphicsView.scene().items():
3062
                item.setVisible(True)
3063

    
3064
        except Exception as ex:
3065
            message = 'error occurred({}) in {}:{}'.format(ex, sys.exc_info()[-1].tb_frame.f_code.co_filename,
3066
                                                           sys.exc_info()[-1].tb_lineno)
3067
            self.addMessage.emit(MessageType.Error, message)
3068
        finally:
3069
            app_doc_data.clearTempDBData()
3070
            self.itemTreeWidget.update_item_count()
3071
            self.itemTreeWidget.expandAll()
3072
            # self.graphicsView.scene().blockSignals(False)
3073

    
3074
    '''
3075
        @brief      load recognition result
3076
        @author     humkyung
3077
        @date       2018.04.??
3078
        @history    humkyung 2018.01.12 parse originalpoint and connectionpoint
3079
                    Jeongwoo 2018.04.17 add QGraphicItem with Rotated text
3080
                    Jeongwoo 2018.04.23 Change to Draw texts on QEngineeringTextItem
3081
                    humkyung 2018.04.23 connect item remove slot to result tree
3082
                    Jeongwoo 2018.04.25 Add if state with QEngineeringNoteItem
3083
                    Jeongwoo 2018.04.26 Change method to create TextItem object with TextItemFactory
3084
                    Jeongwoo 2018.05.03 Change method to draw Svg Item on Scene (svg.addSvgItemToScene)
3085
                    Jeongwoo 2018.05.29 Change method name / Change method to add item / Add Line item
3086
                    Jeongwoo 2018.05.30 Add parameters on SymbolSvgItem.__init__() (parentSymbol, childSymbol) / Change method name / Change XML NODE NAMES
3087
                    Jeongwoo 2018.06.12 Add LineNoTextItem from LINE_NO
3088
                    Jeongwoo 2018.06.14 Add UnknownItem from UNKNOWN
3089
                    Jeongwoo 2018.06.18 Update Scene after all item added
3090
                                        Add connect on unknown item
3091
                                        Add [transfer] for using pyqtSignal
3092
                    kyouho  2018.07.12  Add line property logic
3093
                    humkyung 2018.08.22 show progress while loading xml file
3094
                    2018.11.22      euisung     fix note road
3095
    '''
3096

    
3097
    def load_recognition_result_from_xml(self, xmlPath):
3098
        # Yield successive n-sized
3099
        # chunks from l.
3100
        def divide_chunks(l, n):
3101
            # looping till length l
3102
            for i in range(0, len(l), n):
3103
                yield l[i:i + n]
3104

    
3105
        def update_items(items):
3106
            for item in items:
3107
                # binding items
3108
                item.owner
3109
                for connector in item.connectors:
3110
                    connector.connectedItem
3111

    
3112
            return items
3113

    
3114
        import concurrent.futures as futures
3115
        from xml.etree.ElementTree import Element, SubElement, dump, ElementTree, parse
3116
        from App import App
3117
        from EngineeringRunItem import QEngineeringRunItem
3118
        from QEngineeringTrimLineNoTextItem import QEngineeringTrimLineNoTextItem
3119
        from EngineeringGraphicsLineItem import QEngineeringGraphicsLineItem
3120

    
3121
        docData = AppDocData.instance()
3122

    
3123
        try:
3124
            self.graphicsView.scene().blockSignals(True)
3125

    
3126
            symbols = []
3127
            lines = []
3128

    
3129
            xml = parse(xmlPath)
3130
            root = xml.getroot()
3131

    
3132
            maxValue = 0
3133
            maxValue = maxValue + len(list(root.iter('SYMBOL'))) - len(
3134
                list(root.iterfind('LINENOS/LINE_NO/RUN/SYMBOL'))) - len(
3135
                list(root.iterfind('TRIMLINENOS/TRIM_LINE_NO/RUN/SYMBOL')))
3136
            maxValue = maxValue + len(list(root.iterfind('TEXTINFOS/ATTRIBUTE')))
3137
            maxValue = maxValue + len(list(root.iterfind('NOTES/ATTRIBUTE')))
3138
            maxValue = maxValue + len(list(root.iter('LINE_NO')))
3139
            maxValue = maxValue + len(list(root.iter('LINE'))) - len(
3140
                list(root.iterfind('LINENOS/LINE_NO/RUN/LINE'))) - len(
3141
                list(root.iterfind('TRIMLINENOS/TRIM_LINE_NO/RUN/LINE')))
3142
            maxValue = maxValue + len(list(root.iter('GRAPHICS_LINE')))
3143
            maxValue = maxValue + len(list(root.iter('UNKNOWN')))
3144
            # maxValue = maxValue + len(list(root.iter('SIZETEXT')))
3145
            maxValue = maxValue + len(list(root.iter('TRIM_LINE_NO')))
3146
            maxValue *= 2
3147
            self.progress.setMaximum(maxValue) if maxValue > 0 else None
3148

    
3149
            """ parsing all symbols """
3150
            """
3151
            with futures.ThreadPoolExecutor(max_workers=App.THREAD_MAX_WORKER) as pool:
3152
                future_symbol = {pool.submit(SymbolSvgItem.fromXml, symbol): symbol for symbol in root.find('SYMBOLS').iter('SYMBOL')}
3153

3154
                for future in futures.as_completed(future_symbol):
3155
                    try:
3156
                        item = future.result()
3157
                        if item:
3158
                            if item is not None:
3159
                                item.transfer.onRemoved.connect(self.itemRemoved)
3160
                                symbols.append(item)
3161
                                docData.symbols.append(item)
3162
                                self.addSvgItemToScene(item)
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
                    except Exception as ex:
3174
                        message = 'error occurred({}) in {}:{}'.format(repr(ex), sys.exc_info()[-1].tb_frame.f_code.co_filename,
3175
                                                                       sys.exc_info()[-1].tb_lineno)
3176

3177
            """
3178
            for symbol in root.find('SYMBOLS').iter('SYMBOL'):
3179
                item = SymbolSvgItem.fromXml(symbol)
3180
                if item is not None:
3181
                    item.transfer.onRemoved.connect(self.itemRemoved)
3182
                    symbols.append(item)
3183
                    docData.symbols.append(item)
3184
                    item.addSvgItemToScene(self.graphicsView.scene())
3185
                else:
3186
                    pt = [float(x) for x in symbol.find('LOCATION').text.split(',')]
3187
                    size = [float(x) for x in symbol.find('SIZE').text.split(',')]
3188
                    angle = float(symbol.find('ANGLE').text)
3189
                    item = QGraphicsBoundingBoxItem(pt[0], pt[1], size[0], size[1])
3190
                    item.isSymbol = True
3191
                    item.angle = angle
3192
                    item.setPen(QPen(Qt.red, 5, Qt.SolidLine))
3193
                    self.graphicsView.scene().addItem(item)
3194
                    item.transfer.onRemoved.connect(self.itemRemoved)
3195

    
3196
                self.progress.setValue(self.progress.value() + 1)
3197

    
3198
            QApplication.processEvents()
3199

    
3200
            # parse texts
3201
            for text in root.find('TEXTINFOS').iter('ATTRIBUTE'):
3202
                item = QEngineeringTextItem.fromXml(text)
3203
                if item is not None:
3204
                    uid = text.find('UID')
3205
                    attributeValue = text.find('ATTRIBUTEVALUE')
3206
                    name = text.find('NAME').text
3207
                    item.transfer.onRemoved.connect(self.itemRemoved)
3208
                    self.addTextItemToScene(item)
3209
                    # docData.texts.append(item)
3210

    
3211
                    if name == 'TEXT':
3212
                        if uid is not None and attributeValue is not None:
3213
                            item.uid = uid.text
3214
                            item.attribute = attributeValue.text
3215

    
3216
                self.progress.setValue(self.progress.value() + 1)
3217

    
3218
            QApplication.processEvents()
3219

    
3220
            # note
3221
            for text in root.find('NOTES').iter('ATTRIBUTE'):
3222
                item = QEngineeringTextItem.fromXml(text)
3223
                if item is not None:
3224
                    uid = text.find('UID')
3225
                    attributeValue = text.find('ATTRIBUTEVALUE')
3226
                    name = text.find('NAME').text
3227
                    item.transfer.onRemoved.connect(self.itemRemoved)
3228
                    self.addTextItemToScene(item)
3229

    
3230
                    if name == 'NOTE':
3231
                        if uid is not None:
3232
                            item.uid = uid.text
3233

    
3234
                self.progress.setValue(self.progress.value() + 1)
3235

    
3236
            QApplication.processEvents()
3237

    
3238
            for line in root.find('LINEINFOS').iter('LINE'):
3239
                item = QEngineeringLineItem.fromXml(line)
3240
                if item:
3241
                    item.transfer.onRemoved.connect(self.itemRemoved)
3242
                    self.graphicsView.scene().addItem(item)
3243
                    lines.append(item)
3244

    
3245
                self.progress.setValue(self.progress.value() + 1)
3246

    
3247
            for line in root.find('LINEINFOS').iter('GRAPHICS_LINE'):
3248
                item = QEngineeringGraphicsLineItem.fromXml(line)
3249
                if item:
3250
                    item.transfer.onRemoved.connect(self.itemRemoved)
3251
                    self.graphicsView.scene().addItem(item)
3252

    
3253
                self.progress.setValue(self.progress.value() + 1)
3254

    
3255
            QApplication.processEvents()
3256

    
3257
            for unknown in root.iter('UNKNOWN'):
3258
                item = QEngineeringUnknownItem.fromXml(unknown)
3259
                if item is not None:
3260
                    item.transfer.onRemoved.connect(self.itemRemoved)
3261
                    self.graphicsView.scene().addItem(item)
3262

    
3263
                self.progress.setValue(self.progress.value() + 1)
3264

    
3265
            QApplication.processEvents()
3266

    
3267
            # """ add tree widget """
3268
            # for item in symbols:
3269
            #    docData.symbols.append(item)
3270
            #    self.addSvgItemToScene(item)
3271
            #    self.itemTreeWidget.addTreeItem(self.itemTreeWidget.root, item)
3272

    
3273
            for line_no_node in root.find('LINENOS').iter('LINE_NO'):
3274
                line_no = QEngineeringLineNoTextItem.fromXml(line_no_node)
3275
                if line_no is None: continue
3276
                line_no.transfer.onRemoved.connect(self.itemRemoved)
3277
                self.addTextItemToScene(line_no)
3278
                line_no_tree_item = self.itemTreeWidget.addTreeItem(self.itemTreeWidget.root, line_no)
3279
                if type(line_no) is not QEngineeringLineNoTextItem: continue
3280

    
3281
                runs_node = line_no_node.findall('RUN')
3282
                if runs_node is None: continue
3283

    
3284
                for run_node in runs_node:
3285
                    line_run = QEngineeringRunItem()
3286
                    for child_node in run_node:
3287
                        uidElement = child_node.find('UID')
3288
                        if uidElement is not None:
3289
                            uid = uidElement.text
3290
                            run_item = self.graphicsView.findItemByUid(uid)
3291
                            if run_item is not None:
3292
                                run_item._owner = line_no
3293
                                line_run.items.append(run_item)
3294
                    line_run.owner = line_no
3295
                    line_no.runs.append(line_run)
3296

    
3297
                    for run_item in line_run.items:
3298
                        if issubclass(type(run_item), SymbolSvgItem):
3299
                            self.init_add_tree_item(line_no_tree_item, run_item)
3300

    
3301
                # docData.tracerLineNos.append(line_no)
3302

    
3303
                self.progress.setValue(self.progress.value() + 1)
3304
            QApplication.processEvents()
3305

    
3306
            for trimLineNo in root.iter('TRIM_LINE_NO'):
3307
                line_no = QEngineeringTrimLineNoTextItem()
3308
                line_no.uid = uuid.UUID(trimLineNo.find('UID').text)
3309

    
3310
                runs_node = trimLineNo.findall('RUN')
3311
                if runs_node is None: continue
3312
                line_no_tree_item = self.itemTreeWidget.addTreeItem(self.itemTreeWidget.root, line_no)
3313

    
3314
                for run in runs_node:
3315
                    line_run = QEngineeringRunItem()
3316
                    for child in run:
3317
                        uidElement = child.find('UID')
3318
                        if uidElement is not None:
3319
                            uid = uidElement.text
3320
                            run_item = self.graphicsView.findItemByUid(uid)
3321
                            if run_item is not None:
3322
                                run_item.owner = line_no
3323
                                line_run.items.append(run_item)
3324
                    line_run.owner = line_no
3325
                    line_no.runs.append(line_run)
3326

    
3327
                    for run_item in line_run.items:
3328
                        if issubclass(type(run_item), SymbolSvgItem):
3329
                            self.init_add_tree_item(line_no_tree_item, run_item)
3330

    
3331
                docData.tracerLineNos.append(line_no)
3332

    
3333
                self.progress.setValue(self.progress.value() + 1)
3334
            QApplication.processEvents()
3335

    
3336
            if root.find('VENDORS') is not None:
3337
                for vendor in root.find('VENDORS').iter('VENDOR'):
3338
                    item = QEngineeringVendorItem.fromXml(vendor)
3339
                    item.transfer.onRemoved.connect(self.itemRemoved)
3340
                    self.graphicsView.scene().addItem(item)
3341

    
3342
            # connect flow item to line
3343
            for line in lines:
3344
                line.update_arrow()
3345
                docData.lines.append(line)
3346
            # for flowMark in [item for item in symbols if type(item) is QEngineeringFlowMarkItem]:
3347
            #    for line in lines:
3348
            #        if flowMark.owner is line:
3349
            #            line._flowMark.append(flowMark)
3350
            #            flowMark.setParentItem(line)
3351
            # up to here
3352

    
3353
            """
3354
            group_box = QGroupBox("Contact Details")
3355
            number_label = QLabel("Telephone number");
3356
            number_edit = QTextEdit('hello\nthis is ....')
3357
            layout = QFormLayout()
3358
            layout.addRow(number_label, number_edit)
3359
            group_box.setLayout(layout)
3360

3361
            proxy = QGraphicsProxyWidget()
3362
            proxy.setWidget(group_box)
3363
            self.graphicsView.scene().addItem(proxy)  # (group_box, QGraphicsItem.ItemIgnoresTransformations)
3364
            """
3365

    
3366
            """ update scene """
3367
            _items = [_item for _item in self.graphicsView.scene().items() if hasattr(_item, 'owner') or hasattr(_item, 'connectors')]
3368
            if _items:
3369
                items = divide_chunks(_items, App.THREAD_MAX_WORKER if len(_items) > App.THREAD_MAX_WORKER else len(_items))
3370
                with futures.ThreadPoolExecutor(max_workers=App.THREAD_MAX_WORKER) as pool:
3371
                    future_items = {pool.submit(update_items, _items): _items for _items in items}
3372
                    for future in futures.as_completed(future_items):
3373
                        _items = future.result()
3374
                        self.progress.setValue(self.progress.value() + len(_items))
3375

    
3376
            """
3377
            for item in [_item for _item in self.graphicsView.scene().items() if hasattr(_item, 'owner') or hasattr(_item, 'connectors')]:
3378
                up_progress = False
3379
                # binding items
3380
                item.owner
3381
                for connector in item.connectors:
3382
                    connector.connectedItem
3383

3384
                self.progress.setValue(self.progress.value() + 1)
3385
            """
3386

    
3387
            for item in self.graphicsView.scene().items():
3388
                item.setVisible(True)
3389

    
3390
            self.graphicsView.scene().update(self.graphicsView.sceneRect())
3391
        except Exception as ex:
3392
            message = 'error occurred({}) in {}:{}'.format(ex, sys.exc_info()[-1].tb_frame.f_code.co_filename,
3393
                                                           sys.exc_info()[-1].tb_lineno)
3394
            self.addMessage.emit(MessageType.Error, message)
3395
        finally:
3396
            self.itemTreeWidget.update_item_count()
3397
            self.itemTreeWidget.expandAll()
3398
            self.graphicsView.scene().blockSignals(False)
3399

    
3400
    '''
3401
        @brief      Remove added item on same place and Add GraphicsItem
3402
        @author     Jeongwoo
3403
        @date       2018.05.25
3404
        @history    2018.05.29  Jeongwoo    Moved from QRecognitionDialog
3405
                    2018.06.05  Jeongwoo    Remove Size condition
3406
                    2018.06.18  Jeongwoo    Set Z-index
3407
    '''
3408

    
3409
    def addTextItemToScene(self, textItem):
3410
        textItem.addTextItemToScene(self.graphicsView.scene())
3411

    
3412
    '''
3413
        @brief      Remove added item on same place and Add GraphicsItem
3414
        @author     Jeongwoo
3415
        @date       2018.05.29
3416
        @history    2018.06.18  Jeongwoo    Set Z-index
3417
    '''
3418

    
3419
    def addLineItemToScene(self, lineItem):
3420
        self.graphicsView.scene().addItem(lineItem)
3421

    
3422
    '''
3423
        @brief      generate output xml file
3424
        @author     humkyung
3425
        @date       2018.04.23
3426
        @history    2018.05.02  Jeongwoo    Show MessageBox when imageviewer doesn't have image
3427
    '''
3428

    
3429
    def generateOutput(self):
3430
        import XmlGenerator as xg
3431

    
3432
        if not self.graphicsView.hasImage():
3433
            self.showImageSelectionMessageBox()
3434
            return
3435

    
3436
        try:
3437
            appDocData = AppDocData.instance()
3438

    
3439
            # collect items
3440
            appDocData.lines.clear()
3441
            appDocData.lines = [item for item in self.graphicsView.scene().items() if
3442
                                type(item) is QEngineeringLineItem and item.owner is None]
3443

    
3444
            appDocData.symbols.clear()
3445
            appDocData.symbols = [item for item in self.graphicsView.scene().items() if
3446
                                  issubclass(type(item), SymbolSvgItem) and item.owner is None]
3447

    
3448
            appDocData.equipments.clear()
3449
            for item in self.graphicsView.scene().items():
3450
                if type(item) is QEngineeringEquipmentItem:
3451
                    appDocData.equipments.append(item)
3452

    
3453
            appDocData.texts.clear()
3454
            appDocData.texts = [item for item in self.graphicsView.scene().items() if
3455
                                issubclass(type(item), QEngineeringTextItem) and type(
3456
                                    item) is not QEngineeringLineNoTextItem]
3457
            # up to here
3458

    
3459
            appDocData.imgOutput = np.ones((appDocData.activeDrawing.height, appDocData.activeDrawing.width),
3460
                                           np.uint8) * 255
3461
            xg.writeOutputXml(appDocData.imgName, appDocData.activeDrawing.width,
3462
                              appDocData.activeDrawing.height)  # TODO: check
3463
            project = appDocData.getCurrentProject()
3464
            cv2.imwrite(os.path.join(project.getTempPath(), 'OUTPUT.png'), appDocData.imgOutput)
3465
        except Exception as ex:
3466
            message = 'error occurred({}) in {}:{}'.format(ex, sys.exc_info()[-1].tb_frame.f_code.co_filename,
3467
                                                           sys.exc_info()[-1].tb_lineno)
3468
            self.addMessage.emit(MessageType.Error, message)
3469

    
3470
    '''
3471
        @brief      resetting attribute at secne
3472
        @author     kyoyho
3473
        @date       2018.08.21
3474
    '''
3475
    """
3476
    def checkAttribute(self):
3477
        try:
3478

3479
            docData = AppDocData.instance()
3480
            if not self.graphicsView.hasImage():
3481
                return
3482

3483
            # symbol 경우
3484
            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]
3485
            for item in items:
3486
                attrs = item.attrs
3487
                
3488
                removeAttrList = []
3489
                for attr in attrs:
3490
                    if type(attr) is tuple:
3491
                        continue
3492

3493
                    if attr is None:
3494
                        removeAttrList.append(attr)
3495
                        continue
3496

3497
                    attrInfo = docData.getSymbolAttributeByUID(attr.UID)
3498
                    if attrInfo is None:
3499
                        removeAttrList.append(attr)
3500
                    # 해당 attribute가 맞는지 확인
3501
                    else:
3502
                        attrType = attrInfo.AttributeType
3503
                        _type = type(attr)
3504
                        if attrType == 'Symbol Item':
3505
                            if not issubclass(_type, SymbolSvgItem):
3506
                                removeAttrList.append(attr)
3507
                        elif attrType == 'Text Item':
3508
                            if _type is not QEngineeringTextItem:
3509
                                removeAttrList.append(attr)
3510
                        elif attrType == 'Int':
3511
                            if _type is not UserInputAttribute and self.isNumber(attr.text):
3512
                                removeAttrList.append(attr)
3513
                        elif attrType == 'String':
3514
                            if _type is not UserInputAttribute:
3515
                                removeAttrList.append(attr)
3516

3517
                for attr in removeAttrList:
3518
                    del attrs[attr]
3519

3520
            # Line No Text Item의 경우
3521
            items = [item for item in self.graphicsView.scene().items() if issubclass(type(item), QEngineeringLineNoTextItem)]
3522
            for item in items:
3523
                attrs = item.attrs
3524
                
3525
                removeAttrList = []
3526
                for attr in attrs:
3527
                    if type(attr) is UserInputAttribute:
3528
                        attrInfo = docData.getLinePropertiesByUID(attr.attribute)
3529
                        if attrInfo is None:
3530
                            removeAttrList.append(attr)
3531

3532
                for attr in removeAttrList:
3533
                    del attrs[attr]
3534

3535
        except Exception as ex:
3536
                message = 'error occurred({}) in {}:{}'.format(ex, sys.exc_info()[-1].tb_frame.f_code.co_filename, sys.exc_info()[-1].tb_lineno)
3537
                self.addMessage.emit(MessageType.Error, message)
3538
    """
3539
    '''
3540
        @brief      Check Number
3541
        @author     kyouho
3542
        @date       2018.08.20
3543
    '''
3544

    
3545
    def isNumber(self, num):
3546
        p = re.compile('(^[0-9]+$)')
3547
        result = p.match(num)
3548

    
3549
        if result:
3550
            return True
3551
        else:
3552
            return False
3553

    
3554
    '''
3555
        @brief      find overlap Connector
3556
        @author     kyouho
3557
        @date       2018.08.28
3558
    '''
3559

    
3560
    def findOverlapConnector(self, connectorItem):
3561
        from shapely.geometry import Point
3562
        from EngineeringConnectorItem import QEngineeringConnectorItem
3563
        itemList = []
3564

    
3565
        x = connectorItem.center()[0]
3566
        y = connectorItem.center()[1]
3567

    
3568
        connectors = [item for item in self.graphicsView.scene().items() if
3569
                      type(item) is QEngineeringConnectorItem and item != connectorItem]
3570
        for connector in connectors:
3571
            if Point(x, y).distance(Point(connector.center()[0], connector.center()[1])) < 5:
3572
                itemList.append(connector.parent)
3573

    
3574
        return itemList
3575

    
3576

    
3577
if __name__ == '__main__':
3578
    import locale
3579
    from PyQt5.QtCore import QTranslator
3580
    from License import QLicenseDialog
3581
    from ProjectDialog import Ui_Dialog
3582
    from App import App
3583

    
3584
    app = App(sys.argv)
3585
    try:
3586
        if True == QLicenseDialog.check_license_key():
3587
            dlg = Ui_Dialog()
3588
            selectedProject = dlg.showDialog()
3589
            if selectedProject is not None:
3590
                AppDocData.instance().setCurrentProject(selectedProject)
3591
                app._mainWnd = MainWindow.instance()
3592
                app._mainWnd.show()
3593
                sys.exit(app.exec_())
3594
    except Exception as ex:
3595
        print('error occurred({}) in {}:{}'.format(ex, sys.exc_info()[-1].tb_frame.f_code.co_filename,
3596
                                                   sys.exc_info()[-1].tb_lineno))
3597
    finally:
3598
        pass
클립보드 이미지 추가 (최대 크기: 500 MB)