프로젝트

일반

사용자정보

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

hytos / DTI_PID / DTI_PID / MainWindow.py @ 3a8fa29c

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

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

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

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

    
20
import cv2
21
import numpy as np
22

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

    
28
from PIL import Image
29

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

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

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

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

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

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

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

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

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

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

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

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

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

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

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

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

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

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

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

    
257
        # load stylesheet file list
258
        stylesheet_name = QtWidgets.qApp.stylesheet_name
259
        files = [os.path.splitext(file)[0] for file in os.listdir(os.path.dirname(os.path.realpath(__file__))) if os.path.splitext(file)[1] == '.qss']
260
        for file in files:
261
            action = self.menuTheme.addAction(file)
262
            action.setCheckable(True)
263
            action.setChecked(True) if stylesheet_name == file else action.setChecked(False)
264
            action.triggered.connect(partial(self.load_stylesheet, file))
265
        # up to here
266

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

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

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

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

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

    
319
    def onValidation(self):
320
        """
321
        @brief  validation check
322
        @author euisung
323
        @date   2019.04.01
324
        """
325
        from ValidateCommand import ValidateCommand
326

    
327
        if not self.graphicsView.hasImage():
328
            self.showImageSelectionMessageBox()
329
            return
330

    
331
        try:
332
            # remove error items
333
            for item in self.graphicsView.scene.items():
334
                if type(item) is QEngineeringErrorItem:
335
                    item.transfer.onRemoved.emit(item)
336
            # up to here
337

    
338
            cmd = ValidateCommand(self.graphicsView)
339
            errors = cmd.execute(self.graphicsView.scene.items())
340
            for error in errors:
341
                error.transfer.onRemoved.connect(self.itemRemoved)
342
                self.graphicsView.scene.addItem(error)
343

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

    
352
    def makeInconsistencyTableRow(self, row, errorItem):
353
        '''
354
            @brief  make row data for inconsistency widget
355
            @author euisung
356
            @date   2019.04.16
357
        '''
358

    
359
        item = QTableWidgetItem(str(errorItem.parent))
360
        item.tag = errorItem
361
        self.tableWidgetInconsistency.setItem(row, 0, item)
362

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

    
367
        item = QTableWidgetItem(errorItem.msg)
368
        item.tag = errorItem
369
        self.tableWidgetInconsistency.setItem(row, 2, item)
370

    
371
    def inconsistencyItemClickEvent(self, item):
372
        """
373
        @brief  inconsistency table item clicked
374
        @author euisung
375
        @date   2019.04.02
376
        """
377
        from HighlightCommand import HighlightCommand
378

    
379
        HighlightCommand(self.graphicsView).execute(item.tag)
380

    
381
    def load_stylesheet(self, file):
382
        """
383
        @brief  load stylesheets
384
        @author humkyung
385
        @date   2018.10.29
386
        """
387

    
388
        QtWidgets.qApp.loadStyleSheet(os.path.join(os.path.dirname(os.path.realpath(__file__)), file))
389

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

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

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

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

    
433
        try:
434
            appDocData = AppDocData.instance()
435
            drawings = appDocData.getDrawings()
436

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

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

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

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

    
472
    def onShowDetectSymbol(self):
473
        from DetectSymbolDialog import QDetectSymbolDialog
474

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

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

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

    
511
    '''
512
        @brief      show unknownitem's count
513
        @author     kyouho
514
        @date       2018.08.27
515
    '''
516
    def findReplaceTextClicked(self):
517
        if not self.graphicsView.hasImage():
518
            self.showImageSelectionMessageBox()
519
            return
520

    
521
        from TextItemEditDialog import QTextItemEditDialog
522

    
523
        self.dlgTextItemEdit = QTextItemEditDialog(self)
524
        self.dlgTextItemEdit.show()
525
        self.dlgTextItemEdit.exec_()
526

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

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

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

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

    
549
        self.itemTreeWidget.sceneChanged(self.graphicsView.scene.items())
550

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

    
560
        try:
561
            appDocData = AppDocData.instance()
562

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

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

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

    
598
        try:
599
            appDocData = AppDocData.instance()
600
            if appDocData.imgName is None:
601
                self.showImageSelectionMessageBox()
602
                return
603

    
604
            appDocData.clearItemList(False)
605

    
606
            items = self.graphicsView.scene.items()
607
            for item in items:
608
                if issubclass(type(item), QEngineeringAbstractItem):
609
                    appDocData.allItems.append(item)
610
                    if issubclass(type(item), QEngineeringTextItem):
611
                        appDocData.texts.append(item)
612
            ##
613

    
614
            itemTypes = []
615
            for item in items:
616
                typeExist = False
617
                for itemType in itemTypes:
618
                    if type(item) is itemType:
619
                        typeExist = True
620
                        break
621
                if not typeExist:
622
                    itemTypes.append(type(item))
623
            ##
624

    
625
            self._save_work_cmd = SaveWorkCommand()
626
            self._save_work_cmd.display_message.connect(self.onAddMessage)
627
            self._save_work_cmd.finished.connect(self.save_finished)
628

    
629
            """ show spinner gif animation """
630
            self.label_spinner.setWindowFlags(Qt.WindowStaysOnTopHint)
631
            if not hasattr(self, '_movie'):
632
                self._movie = QMovie(':/newPrefix/spinner.gif')
633
                self.label_spinner.setMovie(self._movie)
634
            self.label_spinner.show()
635
            self._movie.start()
636

    
637
            self._save_work_cmd.start()
638

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

    
643
    def save_finished(self):
644
        """ stop movie and hide label after finishing save """
645
        self._movie.stop()
646
        self.label_spinner.hide()
647
        QMessageBox.about(self.graphicsView, self.tr('Notice'), self._save_work_cmd.resultStr)
648
        self.load_drawing_list()
649

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

    
668
        try:
669
            current = QDateTime.currentDateTime()
670

    
671
            item = QListWidgetItem('{}: {}'.format(current.toString('hh:mm:ss'), message))
672
            if messageType == MessageType.Error:
673
                item.setBackground(Qt.red)
674

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

    
679
    '''
680
        @brief      clear log
681
        @author     humkyung
682
        @date       2018.08.01
683
    '''
684
    def onClearLog(self):
685
        self.listWidgetLog.clear()
686

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

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

    
709
    def onVendor(self, action):
710
        '''
711
            @brief      make vendor package area
712
            @author     euisung
713
            @date       2019.04.29
714
        '''
715
        if not self.graphicsView.hasImage():
716
            self.actionVendor.setChecked(False)
717
            self.showImageSelectionMessageBox()
718
            return
719

    
720
        self.actionVendor.setChecked(True)
721
        if not hasattr(self.actionVendor, 'tag'):
722
            self.actionVendor.tag = PlacePolygonCommand.PlacePolygonCommand(self.graphicsView)
723
            self.actionVendor.tag.onSuccess.connect(self.onVendorCreated)
724
            self.actionVendor.tag.onRejected.connect(self.onCommandRejected)
725

    
726
        self.graphicsView.command = self.actionVendor.tag
727

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

    
751
    '''
752
        @brief      Fit Window
753
        @author     Jeongwoo
754
        @date       2018.06.27
755
        @history    2018.06.27  Jeongwoo    Chnage method to initialize command [Set None → DefaultCommand]
756
    '''
757
    def fitWindow(self, action):
758
        self.graphicsView.useDefaultCommand()
759
        self.graphicsView.zoomImageInit()
760

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

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

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

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

    
829
            return
830

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

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

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

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

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

    
880
        if hasattr(self.actionVendor, 'tag'):
881
            self.actionVendor.tag.onRejected.emit(None)
882

    
883
        if self.graphicsView.command is not None:
884
            self.graphicsView.useDefaultCommand()
885

    
886
        for _action in self.actionGroup.actions():
887
            _action.setChecked(False)
888

    
889
        action.setChecked(True)
890

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

    
907

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

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

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

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

    
984
    '''
985
        @brief  area configuration
986
    '''
987
    def areaConfiguration(self):
988
        from ConfigurationAreaDialog import QConfigurationAreaDialog
989
        if not self.graphicsView.hasImage():
990
            self.showImageSelectionMessageBox()
991
            return
992
        self.onCommandRejected()
993
        self.dlgConfigurationArea = QConfigurationAreaDialog(self)
994
        self.dlgConfigurationArea.show()
995
        self.dlgConfigurationArea.exec_()
996

    
997
    '''
998
        @brief  configuration
999
    '''
1000
    def configuration(self):
1001
        from ConfigurationDialog import QConfigurationDialog
1002

    
1003
        self.dlgConfiguration = QConfigurationDialog(self)
1004
        #self.dlgConfiguration.show()
1005
        if QDialog.Accepted == self.dlgConfiguration.exec_():
1006
            QEngineeringLineItem.LINE_TYPE_COLORS.clear()
1007
            QEngineeringInstrumentItem.INST_COLOR = None
1008

    
1009
    '''
1010
        @brief  show special item types dialog 
1011
        @author humkyung
1012
        @date   2019.08.10
1013
    '''
1014
    def on_show_special_item_types(self):
1015
        from SpecialItemTypesDialog import QSpecialItemTypesDialog
1016

    
1017
        dlg = QSpecialItemTypesDialog(self)
1018
        dlg.exec_()
1019

    
1020
    def on_show_data_transfer(self):
1021
        """ show data transfer dialog """
1022
        from DataTransferDialog import QDataTransferDialog
1023

    
1024
        dlg = QDataTransferDialog(self)
1025
        dlg.exec_()
1026

    
1027
    def on_show_opc_relation(self):
1028
        """ show opc relation dialog """
1029
        from OPCRelationDialog import QOPCRelationDialog
1030

    
1031
        dlg = QOPCRelationDialog(self)
1032
        dlg.exec_()
1033

    
1034
    '''
1035
        @brief  show nominal diameter dialog 
1036
        @author humkyung
1037
        @date   2018.06.28
1038
    '''
1039
    def onShowCodeTable(self):
1040
        from CodeTableDialog import QCodeTableDialog
1041

    
1042
        dlg = QCodeTableDialog(self)
1043
        dlg.exec_()
1044

    
1045
    '''
1046
        @brief  show HMB data
1047
        @author humkyung
1048
        @date   2018.07.11
1049
    '''
1050
    def onHMBData(self):
1051
        from HMBDialog import QHMBDialog
1052

    
1053
        dlg = QHMBDialog(self)
1054
        dlg.show()
1055
        dlg.exec_()
1056

    
1057
    '''
1058
        @brief  show line data list 
1059
        @author humkyung
1060
        @date   2018.05.03
1061
    '''
1062
    def showItemDataList(self):
1063
        from ItemDataExportDialog import QItemDataExportDialog
1064

    
1065
        self.dlgLineDataList = QItemDataExportDialog(self)
1066
        self.dlgLineDataList.exec_()
1067

    
1068
    def showTextDataList(self):
1069
        '''
1070
            @brief      show all text item in scene
1071
            @author     euisung
1072
            @date       2019.04.18
1073
        '''
1074
        try:
1075
            if not self.graphicsView.hasImage():
1076
                self.showImageSelectionMessageBox()
1077
                return
1078

    
1079
            self.onCommandRejected()
1080
            dialog = QTextDataListDialog(self)
1081
            dialog.show()
1082
            dialog.exec_()
1083
        except Exception as ex:
1084
            message = 'error occured({}) in {}:{}'.format(ex, sys.exc_info()[-1].tb_frame.f_code.co_filename, sys.exc_info()[-1].tb_lineno)
1085
            self.addMessage.emit(MessageType.Error, message)
1086

    
1087
    '''
1088
        @brief  Show Image Selection Guide MessageBox
1089
        @author Jeongwoo
1090
        @date   2018.05.02
1091
    '''
1092
    def showImageSelectionMessageBox(self):
1093
        QMessageBox.about(self.graphicsView, self.tr("Notice"), self.tr("First select image drawing"))
1094
        
1095
    '''
1096
        @brief  change selected lines' type by selected line type
1097
        @author humkyung
1098
        @date   2018.06.27
1099
    '''
1100
    def onLineTypeChanged(self, param):
1101
        lineType = self.lineComboBox.itemText(param)
1102
        selected = [item for item in self.graphicsView.scene.selectedItems() if type(item) is QEngineeringLineItem]
1103
        if selected:
1104
            for item in selected:
1105
                item.lineType = lineType
1106

    
1107
    def display_colors(self, value):
1108
        """ display colors """
1109
        from DisplayColors import DisplayColors
1110
        from DisplayColors import DisplayOptions
1111

    
1112
        DisplayColors.instance().option = DisplayOptions.DisplayByLineNo if value == True else DisplayOptions.DisplayByLineType
1113
        if hasattr(self, 'graphicsView'):
1114
            self.graphicsView.scene.update(self.graphicsView.sceneRect())
1115
            DisplayColors.instance().save_data()
1116

    
1117
    '''
1118
        @brief      Open image drawing file and then display it
1119
        @author     humkyung
1120
        @date       2018.??.??
1121
        @history    18.04.23 Jeongwoo    Add AppDocData.instance().setCurrentPidSource
1122
                    18.04.23 Jeongwoo    Add Store Set Current Pid Image on AppDocData
1123
                    18.05.02 Jeongwoo    Add useDefaultCommand()
1124
                    humkyung 2018.05.24 load recognition result file if exists
1125
                    Jeongwoo 2018.05.29 load data on xml if xml file exist
1126
                    humkyung 2018.08.22 clear scene before loading xml file
1127
    '''
1128
    def onOpenImageDrawing(self, path=None):
1129
        from Drawing import Drawing
1130
        from xml.etree.ElementTree import Element, SubElement, dump, ElementTree, parse
1131

    
1132
        try:
1133
            appDocData = AppDocData.instance()
1134
            project = appDocData.getCurrentProject()
1135
            
1136
            self.path = self.graphicsView.loadImageFromFile(project.getDrawingFilePath(), path if type(path) is str else '')
1137
            if os.path.isfile(self.path):
1138
                appDocData.clear()
1139
                self.onCommandRejected()
1140

    
1141
                appDocData.setImgFilePath(self.path)
1142
                appDocData.activeDrawing = Drawing(None, appDocData.imgName, None)
1143
                appDocData.setCurrentPidSource(Image.open(self.path))
1144
                self.itemTreeWidget.setCurrentPID(appDocData.activeDrawing.name)
1145

    
1146
                drawingList = self.treeWidgetDrawingList.topLevelItem(0)
1147
                for childIdex in range(drawingList.childCount()):
1148
                    drawingList.child(childIdex).setCheckState(0, Qt.Unchecked)
1149
                for childIdex in range(drawingList.childCount()):
1150
                    child = drawingList.child(childIdex)
1151
                    if child.text(0).replace('.png', '') == appDocData.activeDrawing.name:
1152
                        child.setCheckState(0, Qt.Checked)
1153
                        break
1154

    
1155
                try:
1156
                    self.progress = QProgressDialog(self.tr("Please wait for a while"), self.tr("Cancel"), 0, 100, self) if not hasattr(self, 'progress') else self.progress
1157
                    self.progress.setWindowModality(Qt.WindowModal)
1158
                    self.progress.setAutoReset(True)
1159
                    self.progress.setAutoClose(True)
1160
                    self.progress.setMinimum(0)
1161
                    self.progress.setMaximum(100)
1162
                    self.progress.resize(600,100)
1163
                    self.progress.setWindowTitle(self.tr("Reading file..."))
1164
                    self.progress.show()
1165
                    ## Load data on xml
1166
                    path = os.path.join(appDocData.getCurrentProject().getTempPath(), appDocData.imgName + '.xml')
1167
                    if False:#os.path.isfile(path):
1168
                        self.loadRecognitionResultFromXml(path)
1169
                    else:
1170
                        self.load_drawing(appDocData.activeDrawing)
1171
                finally:
1172
                    self.progress.setValue(self.progress.maximum())
1173
                    self.progress.hide()
1174

    
1175
                self.changeViewCheckedState(True)
1176
        except Exception as ex:
1177
            message = 'error occured({}) in {}:{}'.format(ex, sys.exc_info()[-1].tb_frame.f_code.co_filename, sys.exc_info()[-1].tb_lineno)
1178
            self.addMessage.emit(MessageType.Error, message)
1179

    
1180
        return self.path
1181

    
1182
    def changeViewCheckedState(self, checked, clear=True):
1183
        '''
1184
            @brief      change view checked state
1185
            @author     euisung
1186
            @date       2019.03.06
1187
        '''
1188
        #self.actionImage_Drawing.setChecked(checked)
1189
        self.actionViewText.setChecked(checked)
1190
        self.actionViewSymbol.setChecked(checked)
1191
        self.actionViewLine.setChecked(checked)
1192
        self.actionViewUnknown.setChecked(checked)
1193
        self.actionViewInconsistency.setChecked(checked)
1194
        self.actionViewVendor_Area.setChecked(not checked)
1195
        self.actionDrawing_Only.setChecked(not checked)
1196
        if clear:
1197
            self.tableWidgetInconsistency.clearContents()
1198
            self.tableWidgetInconsistency.setRowCount(0)
1199

    
1200
    def onViewDrawingOnly(self, isChecked):
1201
        '''
1202
            @brief  visible/invisible except image drawing
1203
            @author euisung
1204
            @date   2019.04.22
1205
        '''
1206
        self.changeViewCheckedState(not isChecked, False)
1207
        for item in self.graphicsView.scene.items():
1208
            if type(item) is not QGraphicsPixmapItem:
1209
                item.setVisible(not isChecked)
1210

    
1211
    '''
1212
        @brief  visible/invisible image drawing
1213
        @author humkyung
1214
        @date   2018.06.25
1215
    '''
1216
    def onViewImageDrawing(self, isChecked):
1217
        for item in self.graphicsView.scene.items():
1218
            if type(item) is QGraphicsPixmapItem:
1219
                item.setVisible(isChecked)
1220
                break
1221

    
1222
    '''
1223
        @brief  visible/invisible Text 
1224
        @author humkyung
1225
        @date   2018.06.28
1226
    '''
1227
    def onViewText(self, isChecked):
1228
        selected = [item for item in self.graphicsView.scene.items() if issubclass(type(item), QEngineeringTextItem)]
1229
        for item in selected:
1230
            item.setVisible(isChecked)
1231

    
1232
    '''
1233
        @brief  visible/invisible Symbol 
1234
        @author humkyung
1235
        @date   2018.06.28
1236
    '''
1237
    def onViewSymbol(self, isChecked):
1238
        selected = [item for item in self.graphicsView.scene.items() if (issubclass(type(item), SymbolSvgItem) and type(item) is not QEngineeringErrorItem)]
1239
        for item in selected:
1240
            item.setVisible(isChecked)
1241

    
1242
    '''
1243
        @brief  visible/invisible Line
1244
        @author humkyung
1245
        @date   2018.06.28
1246
    '''
1247
    def onViewLine(self, isChecked):
1248
        selected = [item for item in self.graphicsView.scene.items() if type(item) is QEngineeringLineItem]
1249
        for item in selected:
1250
            item.setVisible(isChecked)
1251

    
1252
    def onViewInconsistency(self, isChecked):
1253
        '''
1254
            @brief  visible/invisible Inconsistency
1255
            @author euisung
1256
            @date   2019.04.03
1257
        '''
1258
        selected = [item for item in self.graphicsView.scene.items() if type(item) is QEngineeringErrorItem]
1259
        for item in selected:
1260
            item.setVisible(isChecked)
1261

    
1262
    '''
1263
        @brief  visible/invisible Unknown 
1264
        @author humkyung
1265
        @date   2018.06.28
1266
    '''
1267
    def onViewUnknown(self, isChecked):
1268
        selected = [item for item in self.graphicsView.scene.items() if type(item) is QEngineeringUnknownItem]
1269
        for item in selected:
1270
            item.setVisible(isChecked)
1271

    
1272
    def onViewVendorArea(self, isChecked):
1273
        '''
1274
            @brief  visible/invisible Vendor Area
1275
            @author euisung
1276
            @date   2019.04.29
1277
        '''
1278
        selected = [item for item in self.graphicsView.scene.items() if type(item) is QEngineeringVendorItem]
1279
        for item in selected:
1280
            item.setVisible(isChecked)
1281

    
1282
    '''
1283
        @brief  create a symbol
1284
        @history    2018.05.02  Jeongwoo    Change return value of QSymbolEditorDialog (Single variable → Tuple)
1285
                                            Add SymbolSvgItem
1286
                    2018.05.03  Jeongwoo    Change method to draw Svg Item on Scene (svg.addSvgItemToScene)
1287
                                            Change method to make svg and image path
1288
                    2018.06.08  Jeongwoo    Add Paramter on SymbolSvgItem.buildItem()
1289
    '''
1290
    def onCreateSymbolClicked(self):
1291
        cmd = FenceCommand.FenceCommand(self.graphicsView)
1292
        cmd.onSuccess.connect(self.onAreaSelected)
1293
        self.graphicsView.command = cmd
1294
        QApplication.setOverrideCursor(Qt.CrossCursor)
1295

    
1296
    '''
1297
        @brief      show SymbolEditorDialog with image selected by user
1298
        @author     humkyung
1299
        @date       2018.07.20
1300
    '''
1301
    def onAreaSelected(self, x, y, width, height):
1302
        try:
1303
            image = self.graphicsView.image()
1304
            if image is not None:
1305
                symbolEditorDialog = SymbolEditorDialog.QSymbolEditorDialog(self, image.copy(x, y, width, height), AppDocData.instance().getCurrentProject())
1306
                (isAccepted, isImmediateInsert, offsetX, offsetY, newSym) = symbolEditorDialog.showDialog()
1307
                self.dirTreeWidget.initDirTreeWidget()
1308
                if isAccepted:
1309
                    if isImmediateInsert:
1310
                        svgPath = newSym.getSvgFileFullPath()
1311
                        img = cv2.imread(newSym.getImageFileFullPath(), 1)
1312
                        w, h = (0, 0)
1313
                        if len(img.shape[::-1]) == 2:
1314
                            w, h = img.shape[::-1]
1315
                        else:
1316
                            _chan, w, h = img.shape[::-1]
1317
                        svg = SymbolSvgItem(svgPath)
1318
                        svg.buildItem(newSym.getName(), newSym.getType(), 0, [offsetX, offsetY], [w, h], [float(x) for x in newSym.getOriginalPoint().split(',')], [(float(x.split(',')[0]), float(x.split(',')[1])) for x in newSym.getConnectionPoint().split('/')], newSym.getBaseSymbol(), newSym.getAdditionalSymbol(), newSym.getHasInstrumentLabel)
1319

    
1320
                        svg.transfer.onRemoved.connect(self.itemTreeWidget.itemRemoved)
1321
                        svg.addSvgItemToScene(self.graphicsView.scene)
1322
                        for connector in svg.connectors:
1323
                            self.graphicsView.scene.addItem(connector)
1324
        finally:
1325
            self.onCommandRejected()
1326
            QApplication.restoreOverrideCursor()
1327
    
1328
    '''
1329
        @brief      create a line
1330
        @author     humkyung
1331
        @history    Jeongwoo 2018.05.10 Change method for Checkable action
1332
    '''
1333
    def onPlaceLine(self):        
1334
        if not self.graphicsView.hasImage():
1335
            self.actionLine.setChecked(False)
1336
            self.showImageSelectionMessageBox()
1337
            return
1338

    
1339
        self.actionLine.setChecked(True)
1340
        if not hasattr(self.actionLine, 'tag'):
1341
            self.actionLine.tag = PlaceLineCommand.PlaceLineCommand(self.graphicsView)
1342
            self.actionLine.tag.onSuccess.connect(self.onLineCreated)
1343
            self.actionLine.tag.onRejected.connect(self.onCommandRejected)
1344

    
1345
        self.graphicsView.command = self.actionLine.tag
1346

    
1347
    '''
1348
        @brief      add created lines to scene
1349
        @author     humkyung
1350
        @date       2018.07.23
1351
    '''
1352
    def onLineCreated(self):
1353
        from EngineeringConnectorItem import QEngineeringConnectorItem
1354

    
1355
        try:
1356
            count = len(self.actionLine.tag._polyline._vertices)
1357
            if count > 1:
1358
                items = []
1359

    
1360
                lineType = self.lineComboBox.currentText()
1361
                for index in range(count - 1):
1362
                    start = self.actionLine.tag._polyline._vertices[index]
1363
                    end  = self.actionLine.tag._polyline._vertices[index + 1]
1364
                    
1365
                    lineItem = QEngineeringLineItem(vertices=[start, end])
1366
                    lineItem.transfer.onRemoved.connect(self.itemRemoved)
1367
                    lineItem.lineType = lineType
1368
                    if items:
1369
                        lineItem.connect_if_possible(items[-1], 5)
1370
                    else:
1371
                        pt = lineItem.startPoint()
1372
                        selected = [item for item in self.graphicsView.scene.items(QPointF(pt[0], pt[1])) if type(item) is QEngineeringConnectorItem or type(item) is QEngineeringLineItem]
1373
                        if selected:
1374
                            lineItem.connect_if_possible(selected[0].parent if type(selected[0]) is QEngineeringConnectorItem else selected[0], 5)
1375
                    
1376
                    items.append(lineItem)
1377
                    self.graphicsView.scene.addItem(lineItem)
1378

    
1379
                pt = items[-1].endPoint()
1380
                selected = [item for item in self.graphicsView.scene.items(QPointF(pt[0], pt[1])) if type(item) is QEngineeringConnectorItem and item.parent is not items[-1]]
1381
                if selected:
1382
                    items[-1].connect_if_possible(selected[0].parent, 5)
1383

    
1384
        finally:
1385
            self.graphicsView.scene.removeItem(self.actionLine.tag._polyline)
1386
            self.actionLine.tag.reset()
1387

    
1388
    '''
1389
        @brief      refresh scene
1390
        @author     humkyung
1391
        @date       2018.07.23
1392
    '''
1393
    def onCommandRejected(self, cmd=None):
1394
        try:
1395
            if type(cmd) is PlaceLineCommand.PlaceLineCommand:
1396
                if self.actionLine.tag._polyline:
1397
                    self.graphicsView.scene.removeItem(self.actionLine.tag._polyline)
1398
                self.graphicsView.scene.update()
1399
                self.actionLine.tag.reset()
1400

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

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

    
1545
        appDocData = AppDocData.instance()
1546
        project = appDocData.getCurrentProject()
1547
        appDocData.needReOpening = None
1548
        currentPid = None
1549
        
1550
        if self.graphicsView.hasImage():
1551
            currentPid = appDocData.activeDrawing.name
1552

    
1553
        drawingTop = self.treeWidgetDrawingList.topLevelItem(0)
1554
        drawingCount = drawingTop.childCount()
1555
        checkedTreeItems = []
1556
        checkedDrawingPath = []
1557
        for drawing in range(drawingCount):
1558
            drawingChild = drawingTop.child(drawing)
1559
            if drawingChild.checkState(0) == 2:
1560
                checkedTreeItems.append(drawingChild)
1561
                checkedDrawingPath.append(os.path.join(project.getDrawingFilePath(), drawingChild.data(0, 0)))
1562
                if currentPid is not None and drawingChild.data(0, 0).find(currentPid) is 0:
1563
                    appDocData.needReOpening = False # later check need reopening at drawUnknownItems()
1564
                    currentPid = drawingChild.data(0, 0)
1565

    
1566
        if len(checkedDrawingPath) == 0:
1567
            self.showImageSelectionMessageBox()
1568
            return
1569

    
1570
        try:
1571
            self.onClearLog()
1572
            self.dlg = QRecognitionDialog(self, checkedDrawingPath, True)
1573
            self.dlg.exec_()
1574
            if self.dlg.isAccepted == True:
1575
                pass
1576

    
1577
            if appDocData.needReOpening == True:
1578
                drawing = os.path.join(appDocData.getCurrentProject().getDrawingFilePath(), currentPid)
1579
                self.onOpenImageDrawing(drawing)
1580

    
1581
            # save working date-time
1582
            drawings = appDocData.getDrawings()
1583
            checkedDrawings = []
1584
            for checkedTreeItem in checkedTreeItems:
1585
                for drawing in drawings:
1586
                    if checkedTreeItem.data(0, 0) == drawing[1]:
1587
                        if drawing[0]:
1588
                            drawing[2] = datetime.now().strftime('%Y-%m-%d %H:%M:%S')
1589
                            checkedDrawings.append(drawing)
1590
                            checkedTreeItem.setText(1, datetime.now().strftime('%Y-%m-%d %H:%M:%S'))
1591
            appDocData.saveDrawings(checkedDrawings)
1592
            self.changeViewCheckedState(True)
1593
            # up to here
1594
        except Exception as ex:
1595
            message = 'error occured({}) in {}:{}'.format(ex, sys.exc_info()[-1].tb_frame.f_code.co_filename, sys.exc_info()[-1].tb_lineno)
1596
            self.addMessage.emit(MessageType.Error, message)
1597

    
1598
    '''
1599
        @brief      recognize symbol and text
1600
        @author     humkyung
1601
        @date       2018.04.??
1602
        @history    2018.04.16  humkyung    execute line no tracing
1603
                    2018.05.02  Jeongwoo    Show MessageBox when imageviewer doesn't have image
1604
                    2018.05.25  Jeongwoo    Add parameter on QRecognitionDialog.__init__() and Move thread to QRecognitionDialog
1605
                                            Remove codes below if self.dlg.isAccepted == True
1606
                    2018.05.29  Jeongwoo    Remove connects and comments
1607
                    humkyung 2018.11.05 save working date-time
1608
    '''
1609
    def recognize(self, MainWindow):
1610
        from datetime import datetime
1611
        from RecognitionDialog import QRecognitionDialog
1612

    
1613
        if not self.graphicsView.hasImage():
1614
            self.showImageSelectionMessageBox()
1615
            return
1616

    
1617
        try:
1618
            appDocData = AppDocData.instance()
1619

    
1620
            self.onClearLog()
1621
            appDocData.needReOpening = False
1622
            drawingList = []
1623
            drawingList.append(self.path)
1624
            self.dlg = QRecognitionDialog(self, drawingList, False)
1625
            self.dlg.exec_()
1626

    
1627
            if appDocData.needReOpening == True:
1628
                self.itemTreeWidget.setCurrentPID(appDocData.activeDrawing.name)
1629
                self.drawDetectedItemsToScene()
1630
                
1631
                # save working date-time
1632
                drawings = appDocData.getDrawings()
1633
                drawing = [drawing for drawing in drawings if appDocData.imgName == os.path.splitext(drawing.name)[0]]
1634
                if drawing[0]:
1635
                    drawing[0].datetime = datetime.now().strftime('%Y-%m-%d %H:%M:%S')
1636
                    appDocData.saveDrawings(drawing)
1637

    
1638
                currentPid = appDocData.activeDrawing.name
1639

    
1640
                drawingTop = self.treeWidgetDrawingList.topLevelItem(0)
1641
                drawingCount = drawingTop.childCount()
1642
                
1643
                for drawing in range(drawingCount):
1644
                    drawingChild = drawingTop.child(drawing)
1645
                    if drawingChild.data(0, 0).find(currentPid) is 0:
1646
                        drawingChild.setText(1, datetime.now().strftime('%Y-%m-%d %H:%M:%S'))
1647
                self.changeViewCheckedState(True)
1648
                # up to here
1649
        except Exception as ex:
1650
            message = 'error occured({}) in {}:{}'.format(ex, sys.exc_info()[-1].tb_frame.f_code.co_filename, sys.exc_info()[-1].tb_lineno)
1651
            self.addMessage.emit(MessageType.Error, message)
1652

    
1653
    '''
1654
        @brief      remove item from tree widget and then remove from scene
1655
        @date       2018.05.25
1656
        @author     Jeongwoo
1657
    '''
1658
    def itemRemoved(self, item):
1659
        try:
1660
            self.itemTreeWidget.itemRemoved(item)
1661

    
1662
            matches = [_item for _item in self.graphicsView.scene.items() if hasattr(_item, 'connectors') and [connector for connector in _item.connectors if connector.connectedItem is item]]
1663
            for match in matches:
1664
                for connector in match.connectors:
1665
                    if connector.connectedItem is item: connector.connectedItem = None
1666

    
1667
            #matches = [_item for _item in self.graphicsView.scene.items() if hasattr(_item, 'remove_assoc_item')]
1668
            #for _item in matches:
1669
            #    _item.remove_assoc_item(item)
1670

    
1671
            matches = [_item for _item in self.graphicsView.scene.items() if type(_item) is QEngineeringLineNoTextItem]
1672
            for match in matches:
1673
                if item is match.prop('From'):
1674
                    match.set_property('From', None)
1675
                elif item is match.prop('To'):
1676
                    match.set_property('To', None)
1677

    
1678
                for run in match.runs:
1679
                    if item in run.items:
1680
                        index = run.items.index(item)
1681
                        run.items.pop(index)
1682

    
1683
            matches = [_item for _item in self.graphicsView.scene.items() if hasattr(_item, 'owner')]
1684
            for match in matches:
1685
                if match.owner is item:
1686
                    match.owner = None
1687

    
1688
            matches = [_item for _item in self.graphicsView.scene.items() if hasattr(_item, 'attrs')]
1689
            #done = False
1690
            for match in matches:
1691
                for assoc in match.associations():
1692
                    if item is assoc:
1693
                        for attr in match.attrs.keys():
1694
                            if attr.AssocItem and str(item.uid) == str(attr.AssocItem.uid):
1695
                                attr.AssocItem = None
1696
                                match.attrs[attr] = ''
1697
                                #done = True
1698
                        match.remove_assoc_item(item)
1699
                        break
1700
                #if done: break
1701

    
1702
            # remove error item from inconsistency list
1703
            if type(item) is QEngineeringErrorItem:
1704
                for row in range(self.tableWidgetInconsistency.rowCount()):
1705
                    if item is self.tableWidgetInconsistency.item(row, 0).tag:
1706
                        self.tableWidgetInconsistency.removeRow(row)
1707
                        break
1708

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

    
1714
    '''
1715
        @brief      recognize line
1716
        @author     humkyung
1717
        @date       2018.04.19
1718
        @history    Jeongwoo 2018.04.26 Variable name changed (texts → lineNos)
1719
                                        TextItem type changed (QEngineeringTextItem → QEngineeringLineNoTextItem)
1720
                    humkyung 2018.04.26 remove small objects before recognizing line
1721
                    Jeongwoo 2018.05.02 Show MessageBox when imageviewer doesn't have image
1722
                    Jeongwoo 2018.05.25 Move codes about LineDetector
1723
                    humkyung 2018.06.17 show progress dialog
1724
    '''
1725
    def connect_attributes(self, MainWindow):
1726
        from LineNoTracer import LineNoTracer
1727
        from ConnectAttrDialog import QConnectAttrDialog
1728

    
1729
        if not self.graphicsView.hasImage():
1730
            self.showImageSelectionMessageBox()
1731
            return
1732

    
1733
        try:
1734
            self.dlgConnectAttr = QConnectAttrDialog(self, self.graphicsView)
1735
            self.dlgConnectAttr.exec_()
1736
            if self.dlgConnectAttr.isRunned:
1737
                self.itemTreeWidget.InitLineNoItems()
1738

    
1739
                # construct line no item
1740
                line_nos = AppDocData.instance().tracerLineNos
1741
                for line_no in line_nos:
1742
                    item = self.itemTreeWidget.addTreeItem(self.itemTreeWidget.root, line_no)
1743
                    connectedItems = line_no.getConnectedItems()
1744
                    for connectedItem in connectedItems:
1745
                        if issubclass(type(connectedItem), SymbolSvgItem): 
1746
                            self.itemTreeWidget.addTreeItem(item, connectedItem)
1747
                # up to here
1748

    
1749
                self.tableWidgetInconsistency.clearContents()
1750
                if self.dlgConnectAttr.ui.checkBoxValidation.isChecked():
1751
                    self.onValidation()
1752

    
1753
                self.graphicsView.invalidateScene()
1754
        except Exception as ex:
1755
            message = 'error occured({}) in {}:{}'.format(ex, sys.exc_info()[-1].tb_frame.f_code.co_filename, sys.exc_info()[-1].tb_lineno)
1756
            self.addMessage.emit(MessageType.Error, message)
1757

    
1758
    '''
1759
        @history    2018.05.25  Jeongwoo    Moved from MainWindow
1760
                                            SvgItem and TextItem Connect with method in this class
1761
                                            Change method to add GraphicsItem
1762
                    2018.05.28  Jeongwoo    Make QGraphicsItem by symbol, text object. Not xml
1763
                    2018.05.29  Jeongwoo    Change method name and Moved from QRecognitionDialog
1764
                    2018.05.30  Jeongwoo    Add parameters on SymbolSvgItem.__init__() (parentSymbol, childSymbol)
1765
                                            Change Method name and seperate each item
1766
                    humkyung 2018.06.11     display difference between original and recognized image
1767
                    Jeongwoo 2018.06.18     Update Scene after all item added
1768
                    2018.11.05  euisung     add save note item because of dependency
1769
                    2018.11.05  euisung     add db delete process before save
1770
                    2018.11.12  euisung     add title block properties
1771
                    2018.11.12  euisung     db part move new method to dbUpdate
1772
                    2018.11.26  euisung     isolate scene adding part -> drawDetectedItemsToScene()
1773
                    2018.11.29  euisung     change name drawDetectedItems() -> createDetectedItems
1774
    '''
1775
    def createDetectedItems(self, symbolList, textInfoList, otherTextInfoList, titleBlockTextInfoList):
1776
        try:
1777
            appDocData = AppDocData.instance()
1778

    
1779
            QApplication.processEvents()
1780
            self.createDetectedSymbolItem(symbolList)
1781
            QApplication.processEvents()
1782
            self.createDetectedTextItem(textInfoList)
1783
            QApplication.processEvents()
1784
            self.createDetectedOtherTextItem(otherTextInfoList)
1785
            QApplication.processEvents()
1786
            self.createDetectedTitleBlockTextItem(titleBlockTextInfoList)
1787

    
1788
            self.dbUpdate()
1789

    
1790
            # update scene
1791
            #self.graphicsView.scene.update(self.graphicsView.sceneRect())
1792
        except Exception as ex:
1793
            message = 'error occured({}) in {}:{}'.format(ex, sys.exc_info()[-1].tb_frame.f_code.co_filename, sys.exc_info()[-1].tb_lineno)
1794
            self.addMessage.emit(MessageType.Error, message)
1795

    
1796
    def drawDetectedItemsToScene(self):
1797
        '''
1798
            @brief  add detected items to scene
1799
            @author euisung
1800
            @date   2018.11.26
1801
        '''
1802
        appDocData = AppDocData.instance()
1803

    
1804
        try:
1805
            for symbol in appDocData.symbols:
1806
                if issubclass(type(symbol), SymbolSvgItem):
1807
                    self.addSvgItemToScene(symbol)
1808
                else:
1809
                    self.graphicsView.scene.addItem(symbol)
1810

    
1811
            for text in appDocData.texts:
1812
                self.addTextItemToScene(text)
1813

    
1814
            for lineNo in appDocData.tracerLineNos:
1815
                self.addTextItemToScene(lineNo)
1816

    
1817
            for line in appDocData.lines:
1818
                self.graphicsView.scene.addItem(line)
1819
                line.transfer.onRemoved.connect(self.itemRemoved)
1820
                for conn in line.connectors:
1821
                    conn.transfer.onPosChanged.connect(line.onConnectorPosChaned)
1822

    
1823
            for unknown in appDocData.unknowns + appDocData.lineIndicators:
1824
                self.graphicsView.scene.addItem(unknown)
1825
        finally:
1826
            # update scene
1827
            self.graphicsView.scene.update(self.graphicsView.sceneRect())
1828

    
1829
    def postDetectLineProcess(self):
1830
        '''
1831
            @brief  check allowables among undetected items
1832
            @author euisung
1833
            @date   2018.11.15
1834
            @history    2018.11.15  euisung    no more used, moved to TextItemFactoy isLineNo()
1835
        '''
1836
        from AppDocData import AppDocData
1837
        from TextItemFactory import TextItemFactory
1838

    
1839
        appDocData = AppDocData.instance()
1840

    
1841
        tableNames = ["Fluid Code", "Insulation Purpose", "PnID Number", "Piping Materials Class", "Unit Number"]
1842
        tableDatas = []
1843
        for tableName in tableNames:
1844
            tableNameFormat = tableName.replace(' ','').replace('&&', 'n')
1845
            tableDatas.append(appDocData.getCodeTable(tableNameFormat))
1846

    
1847
        items = self.graphicsView.scene.items()
1848
        for item in items:
1849
            if type(item) is not QEngineeringTextItem:
1850
                continue
1851
            text = item.text()
1852
            for tableData in tableDatas:
1853
                for data in tableData:
1854
                    if data[3] == '':
1855
                        continue
1856
                    else:
1857
                        allows = data[3].split(',')
1858
                        for allow in allows:
1859
                            text = text.replace(allow, data[1])
1860

    
1861
            lineItem = TextItemFactory.instance().createTextItem(text)
1862
            if type(lineItem) is QEngineeringLineNoTextItem:
1863
                lineItem.loc = item.loc
1864
                lineItem.size = item.size
1865
                lineItem.angle = item.angle
1866
                lineItem.area = item.area
1867
                #lineItem.addTextItemToScene(self.graphicsView.scene)
1868
                lineItem.transfer.onRemoved.connect(self.itemRemoved)
1869
                item.transfer.onRemoved.emit(item)
1870
                appDocData.lineNos.append(lineItem)
1871
                
1872
    def createDetectedTitleBlockTextItem(self, textInfoList):
1873
        '''
1874
            @brief  draw title block
1875
            @author euisung
1876
            @date   2018.11.12
1877
            @history    2018.11.26  euisung     remove scene dependency
1878
                        2018.11.29  euisung     change name drawDetectedTitleBlockTextItem() -> createDetectedTitleBlockTextItem
1879
        '''
1880
        from TextItemFactory import TextItemFactory
1881
        import math
1882

    
1883
        try:
1884
            appDocData = AppDocData.instance()
1885

    
1886
            # parse texts
1887
            for textInfo in textInfoList:
1888
                if len(textInfo[1]) is 0:
1889
                    continue
1890
                x = textInfo[1][0].getX()
1891
                y = textInfo[1][0].getY()
1892
                width = textInfo[1][0].getW()
1893
                height = textInfo[1][0].getH()
1894
                angle = round(math.radians(textInfo[1][0].getAngle()), 2)
1895
                text = textInfo[1][0].getText()
1896
                item = TextItemFactory.instance().createTextItem(textInfo)
1897

    
1898
                if item is not None:
1899
                    item.loc = [x, y]
1900
                    item.size = (width, height)
1901
                    item.angle = angle
1902
                    item.area = textInfo[0]
1903
                    #self.addTextItemToScene(item)
1904
                    #appDocData.texts.append(item)
1905
                    appDocData.allItems.append(item)
1906
        except Exception as ex:
1907
            message = 'error occured({}) in {}:{}'.format(ex, sys.exc_info()[-1].tb_frame.f_code.co_filename, sys.exc_info()[-1].tb_lineno)
1908
            self.addMessage.emit(MessageType.Error, message)
1909

    
1910
    '''
1911
        @brief      
1912
        @author     humkyung
1913
        @date       2018.08.23
1914
        @history    2018.11.26  euisung     remove scene dependency
1915
                    2018.11.26  euisung     isolate scene adding part -> drawDetectedItemsToScene()
1916
                    2018.11.    euisung     no more used
1917
                    2018.11.29  euisung     change name drawDetectedLines() -> createDetectedLines
1918
    '''
1919
    def createDetectedLines(self, lineList, worker):
1920
        appDocData = AppDocData.instance()
1921
        area = appDocData.getArea('Drawing')
1922

    
1923
        for pts in lineList:
1924
            processLine = QEngineeringLineItem(vertices=[(area.x + param[0], area.y + param[1]) for param in pts])
1925
            processLine.area = 'Drawing'
1926
            #self.graphicsView.scene.addItem(processLine)
1927
            appDocData.lines.append(processLine)
1928
            appDocData.allItems.append(processLine)
1929

    
1930
            #if processLine.length() > 100: # TODO: check critical length
1931
            #    processLine.addFlowArrow()
1932
        
1933
        # re-order process line's start,end according to flow mark
1934
        #worker.arrangeLinePosition(lines, symbols, listWidget)
1935
        # up to here
1936

    
1937
    '''
1938
        history     2018.06.09  humkyung    check length of original and connection point is 2 while parsing
1939
                    2018.11.26  euisung     remove scene dependency
1940
                    2018.11.29  euisung     change name drawDetectedSymbolItem() -> createDetectedSymbolItem
1941
    '''
1942
    def createDetectedSymbolItem(self, symbolList):
1943
        from GraphicsBoundingBoxItem import QGraphicsBoundingBoxItem
1944
        from SymbolSvgItem import SymbolSvgItem
1945
        import math
1946

    
1947
        try:
1948
            appDocData = AppDocData.instance()
1949
            project = appDocData.getCurrentProject()
1950

    
1951
            searchedMap = []
1952
            for symbol in symbolList:
1953
                pt = [float(x) for x in symbol.getSp()]
1954
                size = [symbol.getWidth(), symbol.getHeight()]
1955
                name = symbol.getName()
1956
                angle = round(math.radians(symbol.getRotatedAngle()), 2)
1957
                _type = symbol.getType()
1958
                flip = symbol.getDetectFlip()
1959
                origin = [0,0]
1960
                if 2 == len(symbol.getOriginalPoint().split(',')):
1961
                    tokens = symbol.getOriginalPoint().split(',')
1962
                    origin = [pt[0] + float(tokens[0]), pt[1] + float(tokens[1])]
1963
                connPts = []
1964
                if symbol.getConnectionPoint() is not None and symbol.getConnectionPoint() != '':
1965
                    for param in symbol.getConnectionPoint().split('/'):
1966
                        tokens = param.split(',')
1967
                        connPts.append(('AUTO', pt[0] + float(tokens[0]), pt[1] + float(tokens[1]), '0') if len(tokens) == 2 else \
1968
                                       (tokens[0], pt[0] + float(tokens[1]), pt[1] + float(tokens[2]), '0') if len(tokens) == 3 else \
1969
                                       (tokens[0], pt[0] + float(tokens[1]), pt[1] + float(tokens[2]), tokens[3]) if len(tokens) == 4 else None)
1970

    
1971
                parentSymbol = symbol.getBaseSymbol()
1972
                childSymbol = symbol.getAdditionalSymbol()
1973
                hasInstrumentLabel = symbol.getHasInstrumentLabel()
1974

    
1975
                svgFilePath = os.path.join(project.getSvgFilePath(), _type, name + '.svg')
1976
                if os.path.isfile(svgFilePath):
1977
                    svg = SymbolSvgItem.createItem(_type, svgFilePath, owner=None, flip=flip)
1978
                    #print(pt)
1979
                    #print(origin)
1980
                    svg.buildItem(name, _type, angle, pt, size, origin, connPts, parentSymbol, childSymbol, hasInstrumentLabel)
1981
                    svg.reCalculationRotatedItem()
1982
                    svg.area = 'Drawing'
1983

    
1984
                    # set owner - 2018.07.20 added by humkyung                   
1985
                    matches = [searched for searched in searchedMap if searched[0] == symbol.owner]
1986
                    if len(matches) == 1:
1987
                        svg.owner = matches[0][1]
1988
                    searchedMap.append((symbol, svg))
1989
                    # up to here
1990

    
1991
                    svg.transfer.onRemoved.connect(self.itemRemoved)
1992
                    #self.addSvgItemToScene(svg)
1993
                    appDocData.symbols.append(svg)
1994
                    appDocData.allItems.append(svg)
1995
                else:
1996
                    item = QGraphicsBoundingBoxItem(pt[0], pt[1], size[0], size[1])
1997
                    item.isSymbol = True
1998
                    item.angle = angle
1999
                    item.setPen(QPen(Qt.red, 5, Qt.SolidLine))
2000
                    #self.graphicsView.scene.addItem(item)
2001
                    #appDocData.symbols.append(item)
2002
                    appDocData.allItems.append(item)
2003
            # up to here
2004
        except Exception as ex:
2005
            message = 'error occured({}) in {}:{}'.format(ex, sys.exc_info()[-1].tb_frame.f_code.co_filename, sys.exc_info()[-1].tb_lineno)
2006
            self.addMessage.emit(MessageType.Error, message)
2007

    
2008
    '''
2009
        @history    2018.06.08  Jeongwoo    Add parameter on round method
2010
        @history    2018.11.02  euisung     Add save note text item
2011
        @history    2018.11.05  euisung     delete save note text item and move to drawDetectedItems()
2012
                    2018.11.26  euisung     remove scene dependency
2013
                    2018.11.29  euisung     change name drawDetectedTextItem() -> createDetectedTextItem
2014
    '''
2015
    def createDetectedTextItem(self, textInfoList):
2016
        from TextItemFactory import TextItemFactory
2017
        import math
2018

    
2019
        try:
2020
            appDocData = AppDocData.instance()
2021

    
2022
            # parse texts
2023
            for textInfo in textInfoList:
2024
                x = textInfo.getX()
2025
                y = textInfo.getY()
2026
                width = textInfo.getW()
2027
                height = textInfo.getH()
2028
                angle = round(math.radians(textInfo.getAngle()), 2)
2029
                text = textInfo.getText()
2030
                if not text: continue
2031

    
2032
                item = TextItemFactory.instance().createTextItem(textInfo)
2033
                if item is not None:
2034
                    item.loc = [x, y]
2035
                    item.size = (width, height)
2036
                    item.angle = angle
2037
                    item.area = 'Drawing'
2038
                    item.transfer.onRemoved.connect(self.itemRemoved)
2039
                    #self.addTextItemToScene(item)
2040
                    #appDocData.texts.append(item)
2041
                    appDocData.allItems.append(item)
2042
        except Exception as ex:
2043
            message = 'error occured({}) in {}:{}'.format(ex, sys.exc_info()[-1].tb_frame.f_code.co_filename, sys.exc_info()[-1].tb_lineno)
2044
            self.addMessage.emit(MessageType.Error, message)
2045

    
2046
    '''
2047
        @brief      draw detected texts except which in drawing area
2048
        @history    2018.11.29  euisung     change name drawDetectedOtherTextItem() -> createDetectedOtherTextItem
2049
    '''
2050
    def createDetectedOtherTextItem(self, otherTextInfoList):
2051
        from TextItemFactory import TextItemFactory
2052
        import math
2053

    
2054
        try:
2055
            appDocData = AppDocData.instance()
2056

    
2057
            # parse notes
2058
            for textInfoMap in otherTextInfoList:
2059
                if textInfoMap[0]=='Note' or textInfoMap[1] is None:
2060
                    pass
2061

    
2062
                for textInfo in textInfoMap[1]:
2063
                    x = textInfo.getX()
2064
                    y = textInfo.getY()
2065
                    width = textInfo.getW()
2066
                    height = textInfo.getH()
2067
                    angle = round(math.radians(textInfo.getAngle()))
2068
                    text = textInfo.getText()
2069

    
2070
                    item = TextItemFactory.instance().createTextItem(textInfo)
2071

    
2072
                    item.loc = [x, y]
2073
                    item.size = (width, height)
2074
                    item.angle = angle
2075
                    item.area = textInfoMap[0]
2076
                    item.transfer.onRemoved.connect(self.itemRemoved)
2077
                    #appDocData.texts.append(item)
2078
                    appDocData.allItems.append(item)
2079
        except Exception as ex:
2080
            message = 'error occured({}) in {}:{}'.format(ex, sys.exc_info()[-1].tb_frame.f_code.co_filename, sys.exc_info()[-1].tb_lineno)
2081
            self.addMessage.emit(MessageType.Error, message)
2082

    
2083
    '''
2084
        @brief  draw unknown items 
2085
        @author humkyung
2086
        @date   2018.06.12
2087
        @history    2018.06.14  Jeongwoo    Change method to add unknown item
2088
                    2018.06.18  Jeongwoo    Add connect on unknown item
2089
                                            Add [transfer] for using pyqtSignal
2090
                    2018.11.26  euisung     remove scene dependency
2091
                    2018.11.26  euisung     isolate scene adding part -> drawDetectedItemsToScene()
2092
                    2018.11.27  euisung     add save to xml
2093
                    2018.11.29  euisung     change name drawUnknownItems() -> createUnknownItems
2094
    '''
2095
    def createUnknownItems(self, path):
2096
        from QEngineeringFlowArrowItem import QEngineeringFlowArrowItem 
2097
        from EngineeringLineItem import QEngineeringLineItem
2098
        from EngineeringUnknownItem import QEngineeringUnknownItem
2099
        from SaveWorkCommand import SaveWorkCommand
2100

    
2101
        try:
2102
            docData = AppDocData.instance()
2103
            project = docData.getCurrentProject()
2104
            windowSize = docData.getSlidingWindowSize()
2105

    
2106
            thickness = int(windowSize[1])
2107

    
2108
            if docData.needReOpening is not None:
2109
                docData.needReOpening = True
2110

    
2111
            diffFilePath = os.path.join(project.getTempPath(), "DIFF_" + os.path.basename(path))
2112
            if os.path.isfile(diffFilePath):
2113
                imgDiff = cv2.threshold(cv2.cvtColor(cv2.imread(diffFilePath, 1), cv2.COLOR_BGR2GRAY), 127, 255, cv2.THRESH_BINARY)[1]
2114

    
2115
                ## remove line
2116
                lines = docData.lines
2117
                for line in lines:
2118
                    line.drawToImage(imgDiff, 255, thickness) if line.thickness is None else line.drawToImage(imgDiff, 255, line.thickness)
2119
                cv2.imwrite(diffFilePath, imgDiff)
2120
                ## up to here
2121

    
2122
                imgNot = np.ones(imgDiff.shape, np.uint8)
2123
                cv2.bitwise_not(imgDiff, imgNot)
2124
                imgNot = cv2.dilate(imgNot, np.ones((8,8), np.uint8))
2125

    
2126
                contours, hierarchy = cv2.findContours(imgNot, cv2.RETR_EXTERNAL, cv2.CHAIN_APPROX_SIMPLE)
2127

    
2128
                ##
2129
                idx = 0
2130
                ##
2131
                smallContours = []
2132
                minimumSize = docData.getConfigs('Filter', 'MinimumSize')
2133
                for contour in contours:
2134
                    [x, y, w, h] = cv2.boundingRect(contour)
2135

    
2136
                    # remove too small one
2137
                    if len(minimumSize) is 1:
2138
                        if (w * h < int(minimumSize[0].value) * int(minimumSize[0].value)):
2139
                            smallContours.append(contour)
2140
                            idx += 1
2141
                            continue
2142

    
2143
                    '''
2144
                    rect = QRectF(x, y, w, h)
2145
                    items = [item for item in diffItems if item.boundingRect().contains(rect)]
2146
                    if len(items) > 0: continue
2147
                    
2148
                    items = [item for item in diffItems if rect.contains(item.boundingRect())]
2149
                    for item in items:
2150
                        diffItems.remove(item)
2151
                    '''
2152

    
2153
                    # create unknown item
2154
                    epsilon = cv2.arcLength(contour, True)*0.001
2155
                    approx = cv2.approxPolyDP(contour, epsilon, True)
2156
                    approx = [pt[0] for pt in approx]
2157
                    resultStr, resultList = self.determineRemainObject(idx, contours, imgNot)
2158
                    if resultStr == 'LineIndicator':
2159
                        item = QEngineeringUnknownItem(approx, 'True', resultList[0], resultList[1])
2160
                        docData.lineIndicators.append(item)
2161
                    elif resultStr == 'MissingLine':
2162
                        pass
2163
                    elif resultStr == 'Unknown':
2164
                        item = QEngineeringUnknownItem(approx, 'False')
2165
                        docData.unknowns.append(item)
2166
                    item.area = 'Drawing'
2167
                    docData.allItems.append(item)
2168
                    item.transfer.onRemoved.connect(self.itemRemoved)
2169
                    idx += 1
2170
                    # up to here                    
2171

    
2172
                imgNotRemoveSmall = cv2.drawContours(imgNot, smallContours, -1, 0, -1)
2173
                notFilePath = os.path.join(project.getTempPath(), "NOT_" + os.path.basename(path))
2174
                cv2.imwrite(notFilePath, imgNotRemoveSmall)
2175
            else:
2176
                message = 'can\'t found {}'.format(diffFilePath)
2177
                self.addMessage.emit(MessageType.Normal, message)
2178

    
2179
            SaveWorkCommand.save_to_xml()
2180
        except Exception as ex:
2181
            message = 'error occured({}) in {}:{}'.format(ex, sys.exc_info()[-1].tb_frame.f_code.co_filename, sys.exc_info()[-1].tb_lineno)
2182
            self.addMessage.emit(MessageType.Error, message)
2183

    
2184
    def determineRemainObject(self, idx, contours, imgNot):
2185
        '''
2186
            @brief      determine remain objects -> line no indicator or unknown
2187
            @author     euisung
2188
            @date       2018.12.26
2189
            @history    2019.03.25  euisung    Change name isLineNoIndicator -> determineRemainObject
2190
        '''
2191
        import math
2192
        [x, y, w, h] = cv2.boundingRect(contours[idx])
2193
        
2194
        if (w < 250 and h < 250):
2195
            return ('Unknown', [])
2196
        
2197
        fLines = []
2198
        maxDifAngle = 3
2199
        mask = np.zeros_like(imgNot)
2200
        cv2.drawContours(mask, contours, idx, 123, -1) # Draw filled contour in mask
2201
        out = np.zeros_like(imgNot) # Extract out the object and place into output image
2202
        out[mask == 123] = imgNot[mask == 123]
2203

    
2204
        # Now crop
2205
        ##print(out)
2206
        (x, y) = np.where(mask == 123)
2207
        (topx, topy) = (np.min(x), np.min(y))
2208
        (bottomx, bottomy) = (np.max(x), np.max(y))
2209
        out = out[topx:bottomx+1, topy:bottomy+1]
2210
        h, w = out.shape[0], out.shape[1]
2211
        maxDifH, maxDifW = math.ceil(math.tan(4 * math.pi / 180) / 2 * w), math.ceil(math.tan(4 * math.pi / 180) / 2 * h)
2212

    
2213
        # detection lines
2214
        edged2 = cv2.Canny(out, 100, 200)
2215
        lines = cv2.HoughLinesP(image=edged2, rho=1, theta=np.pi/180, threshold=25, minLineLength=30, maxLineGap=25)
2216
        #lines = cv2.HoughLines(edged2, 1, np.pi/180, 60)
2217
        if lines is None:
2218
            return ('Unknown', [])
2219
        for line in lines:
2220
            #r, theta = line[0]
2221
            #a, b = np.cos(theta), np.sin(theta)
2222
            #x0, y0 = a * r, b * r
2223
            #x1, y1 = int(x0 + 1000 * (-b)), int(y0 + 1000 * a)
2224
            #x2, y2 = int(x0 - 1000 * (-b)), int(y0 - 1000 * a)
2225
            #cv2.line(out, (x1, y1), (x2, y2), (0, 255, 0), 3)
2226
            x1, y1, x2, y2 = line[0]
2227
            degree = math.atan2(y2 - y1, x2 - x1) * 180 / math.pi
2228
            fLine = [x1, y1, x2, y2, degree]
2229
            #print(fLine)
2230
            fLines.append(fLine)
2231
        
2232
        horLines = []
2233
        verLines = []
2234
        otherLines = []
2235
        isVH = None
2236
        for fLine in fLines:
2237
            degree = math.fabs(fLine[4])
2238
            if degree >= 90 - maxDifAngle:
2239
                verLines.append(fLine)
2240
            elif degree <= maxDifAngle:
2241
                horLines.append(fLine)
2242
            else:
2243
                otherLines.append(fLine)
2244

    
2245
        baseLines = []
2246
        baseDifV = 0
2247
        if len(horLines):
2248
            x, y = w / 2, 0
2249
            baseDifV = maxDifH
2250
            for horLine in horLines:
2251
                x1, y1, x2, y2 = horLine[0], horLine[1], horLine[2], horLine[3]
2252
                y = ((y2-y1)/(x2-x1))*x + y1 - ((y2-y1)/(x2-x1))*x1
2253
                horLine.append(y)
2254
            baseLines = horLines
2255
            isVH = 'H'
2256
        if len(verLines):
2257
            x, y = 0, h / 2
2258
            baseDifV = maxDifW
2259
            for verLine in verLines:
2260
                x1, y1, x2, y2 = verLine[0], verLine[1], verLine[2], verLine[3]
2261
                x = ((x2-x1)/(y2-y1))*y + x1 - ((x2-x1)/(y2-y1))*y1
2262
                verLine.append(x)
2263
            baseLines = verLines
2264
            isVH = 'V'
2265

    
2266
        for otherLine in otherLines:
2267
            x, y = w / 2, 0
2268
            x1, y1, x2, y2 = otherLine[0], otherLine[1], otherLine[2], otherLine[3]
2269
            y = ((y2-y1)/(x2-x1))*x + y1 - ((y2-y1)/(x2-x1))*x1
2270
            otherLine.append(y)
2271

    
2272
        # determine line no indicator 
2273
        if not ((len(horLines) > 0 and len(verLines) > 0) or len(otherLines) is 0 or (len(horLines) == 0 and len(verLines) == 0)):    
2274
            result, mergedOtherLine = self.isLineNoIndicator(w, h, maxDifAngle, baseDifV, baseLines, otherLines)
2275
            if result:
2276
                #print(fLines)
2277
                return ('LineIndicator', [isVH, mergedOtherLine])
2278

    
2279
        return ('Unknown', [])
2280

    
2281
    def isLineNoIndicator(self, w, h, maxDifAngle, baseDifV, baseLines, otherLines):
2282
        '''
2283
            @brief      determine line no indicator
2284
            @author     euisung
2285
            @date       2019.03.25
2286
        '''
2287
        import math
2288

    
2289
        if (w < 250 and h < 250):
2290
            return (False, None)
2291

    
2292
        isSameLine = True
2293
        i = 0
2294
        for baseLine in baseLines:
2295
            if not isSameLine: break
2296
            j = 0
2297
            for baseLinee in baseLines:
2298
                if i == j:
2299
                    j += 1
2300
                    continue
2301
                difV = math.fabs(baseLine[5] - baseLinee[5])
2302
                if difV > baseDifV:
2303
                   isSameLine = False
2304
                   break
2305
                j += 1
2306
            i += 1
2307
        if not isSameLine:
2308
            return (False, None)
2309

    
2310
        isSameLine = True
2311
        i = 0
2312
        maxY = 0
2313
        for otherLine in otherLines:
2314
            y = otherLine[5]
2315
            if math.fabs(y) > maxY:
2316
                maxY = math.fabs(y)
2317
            if not isSameLine: break
2318
            j = 0
2319
            for otherLinee in otherLines:
2320
                if i == j:
2321
                    j += 1
2322
                    continue
2323
                difV = math.fabs(otherLine[4] - otherLinee[4])
2324
                if difV > maxDifAngle:
2325
                   isSameLine = False
2326
                   break
2327
                j += 1
2328
            i += 1
2329
        if not isSameLine:
2330
            return (False, None)
2331
                
2332
        isSameLine = True
2333
        mergedOtherLine = [0, 0, 0, 0]
2334
        i = 0
2335
        maxDif = math.ceil(math.tan(4 * math.pi / 180) * maxY)
2336
        for otherLine in otherLines:
2337
            if not isSameLine: break
2338
            j = 0
2339
            for otherLinee in otherLines:
2340
                if i == j:
2341
                    j += 1
2342
                    continue
2343
                angle = math.fabs(otherLine[4] + otherLinee[4]) / 2
2344
                difV = math.fabs(otherLine[5] - otherLinee[5])
2345
                dist = math.sin((90 - angle) * math.pi / 180) * difV 
2346
                if dist > maxDif:
2347
                   isSameLine = False
2348
                   break
2349
                j += 1
2350
            i += 1
2351
            mergedOtherLine[0] += otherLine[0]
2352
            mergedOtherLine[1] += otherLine[1]
2353
            mergedOtherLine[2] += otherLine[2]
2354
            mergedOtherLine[3] += otherLine[3]
2355
        if not isSameLine:
2356
            (False, None)
2357
                        
2358
        # Show the output image
2359
        #print('line no indicator')
2360
        mergedOtherLine[0] = round(mergedOtherLine[0] / len(otherLines))
2361
        mergedOtherLine[1] = round(mergedOtherLine[1] / len(otherLines))
2362
        mergedOtherLine[2] = round(mergedOtherLine[2] / len(otherLines))
2363
        mergedOtherLine[3] = round(mergedOtherLine[3] / len(otherLines))
2364
        #cv2.line(out, (mergedOtherLine[0], mergedOtherLine[1]), (mergedOtherLine[2], mergedOtherLine[3]), (255, 255, 255), 3)
2365
        #cv2.imshow('Output', out)
2366
        #cv2.waitKey(0)
2367
        #cv2.destroyAllWindows()
2368
        return (True, mergedOtherLine)
2369

    
2370
    def load_drawing(self, drawing):
2371
        """ load drawing """
2372
        from xml.etree.ElementTree import Element, SubElement, dump, ElementTree, parse
2373
        from EngineeringRunItem import QEngineeringRunItem
2374
        from QEngineeringTrimLineNoTextItem import QEngineeringTrimLineNoTextItem
2375

    
2376
        app_doc_data = AppDocData.instance()
2377
        try:
2378
            symbols = []
2379
            lines = []
2380

    
2381
            components = app_doc_data.get_components(drawing.UID)
2382
            maxValue = len(components)
2383
            self.progress.setMaximum(maxValue)
2384

    
2385
            """ parsing all symbols """
2386
            for symbol in [component for component in components if component['SymbolType_UID'] != -1]:
2387
                item = SymbolSvgItem.from_database(symbol)
2388
                if item is not None:
2389
                    item.transfer.onRemoved.connect(self.itemRemoved)
2390
                    symbols.append(item)
2391
                    app_doc_data.symbols.append(item)
2392
                    self.addSvgItemToScene(item)
2393
                else:
2394
                    pt = [float(symbol['X']), float(symbol['Y'])]
2395
                    size = [float(symbol['Width']), float(symbol['Height'])]
2396
                    angle = float(symbol['Rotation'])
2397
                    item = QGraphicsBoundingBoxItem(pt[0], pt[1], size[0], size[1])
2398
                    item.isSymbol = True
2399
                    item.angle = angle
2400
                    item.setPen(QPen(Qt.red, 5, Qt.SolidLine))
2401
                    self.graphicsView.scene.addItem(item)
2402
                    item.transfer.onRemoved.connect(self.itemRemoved)
2403

    
2404
                self.progress.setValue(self.progress.value() + 1)
2405
                
2406
            QApplication.processEvents()
2407

    
2408
            # parse texts
2409
            for text in [component for component in components if component['Name'] == 'Text' and component['SymbolType_UID'] == -1]:
2410
                item = QEngineeringTextItem.from_database(text)
2411
                if item is not None:
2412
                    item.uid = text['UID']
2413
                    item.attribute = text['Value']
2414
                    name = text['Name']
2415
                    item.transfer.onRemoved.connect(self.itemRemoved)
2416
                    self.addTextItemToScene(item)
2417

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

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

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

    
2436
            for line in [component for component in components if component['Name'] == 'Line' and component['SymbolType_UID'] == -1]:
2437
                item = QEngineeringLineItem.from_database(line)
2438
                if item:
2439
                    item.transfer.onRemoved.connect(self.itemRemoved)
2440
                    self.graphicsView.scene.addItem(item)
2441
                    lines.append(item)
2442

    
2443
                self.progress.setValue(self.progress.value() + 1)
2444
                
2445
            QApplication.processEvents()
2446

    
2447
            for unknown in [component for component in components if component['Name'] == 'Unknown' and component['SymbolType_UID'] == -1]:
2448
                item = QEngineeringUnknownItem.from_database(unknown)
2449
                item.transfer.onRemoved.connect(self.itemRemoved)
2450
                if item is not None:
2451
                    item.transfer.onRemoved.connect(self.itemRemoved)
2452
                    self.graphicsView.scene.addItem(item)
2453

    
2454
                self.progress.setValue(self.progress.value() + 1)
2455
                
2456
            QApplication.processEvents()
2457

    
2458
            for component in [component for component in components if component['Name'] == 'Line NO' and component['SymbolType_UID'] == -1]:
2459
                line_no = QEngineeringLineNoTextItem.from_database(component)
2460
                if type(line_no) is QEngineeringLineNoTextItem:
2461
                    line_no.transfer.onRemoved.connect(self.itemRemoved)
2462
                    self.addTextItemToScene(line_no)
2463
                    line_no_tree_item = self.itemTreeWidget.addTreeItem(self.itemTreeWidget.root, line_no)
2464

    
2465
                    runs = app_doc_data.get_pipe_runs(str(line_no.uid))
2466
                    if not runs: continue
2467
                    for run in runs:
2468
                        line_run = QEngineeringRunItem()
2469
                        run_items = app_doc_data.get_pipe_run_items(run['UID'])
2470
                        for record in run_items:
2471
                            uid = record['Components_UID']
2472
                            run_item = self.graphicsView.findItemByUid(uid)
2473
                            if run_item is not None:
2474
                                run_item._owner = line_no
2475
                                line_run.items.append(run_item)
2476
                        line_run.owner = line_no
2477
                        line_no.runs.append(line_run)
2478

    
2479
                        for run_item in line_run.items:
2480
                            if issubclass(type(run_item), SymbolSvgItem): self.itemTreeWidget.addTreeItem(line_no_tree_item, run_item)
2481

    
2482
                self.progress.setValue(self.progress.value() + 1)
2483
            QApplication.processEvents()
2484

    
2485
            for component in [component for component in components if component['Name'] == 'Trim Line NO' and component['SymbolType_UID'] == -1]:
2486
                line_no = QEngineeringTrimLineNoTextItem()
2487
                line_no.uid = uuid.UUID(component['UID'], version=4)
2488

    
2489
                runs = app_doc_data.get_pipe_runs(str(line_no.uid))
2490
                if not runs: continue
2491
                for run in runs:
2492
                    line_run = QEngineeringRunItem()
2493
                    run_items = app_doc_data.get_pipe_run_items(run['UID'])
2494
                    for record in run_items:
2495
                        uid = record['Components_UID']
2496
                        run_item = self.graphicsView.findItemByUid(uid)
2497
                        if run_item is not None:
2498
                            run_item.owner = line_no
2499
                            line_run.items.append(run_item)
2500
                line_no.runs.append(line_run)
2501
                line_no_tree_item = self.itemTreeWidget.addTreeItem(self.itemTreeWidget.root, line_no)
2502
                
2503
                for run_item in line_run.items:
2504
                    if issubclass(type(run_item), SymbolSvgItem): self.itemTreeWidget.addTreeItem(line_no_tree_item, run_item)
2505

    
2506
                app_doc_data.tracerLineNos.append(line_no)
2507

    
2508
                self.progress.setValue(self.progress.value() + 1)
2509

    
2510
            for component in [component for component in components if component['Name'] == 'VendorPackage' and component['SymbolType_UID'] == -1]:
2511
                item = QEngineeringVendorItem.from_database(component)
2512
                item.transfer.onRemoved.connect(self.itemRemoved)
2513
                self.graphicsView.scene.addItem(item)
2514

    
2515
            # connect flow item to line
2516
            for line in lines:
2517
                line.update_arrow()
2518
            #for flowMark in [item for item in symbols if type(item) is QEngineeringFlowMarkItem]:
2519
            #    for line in lines:
2520
            #        if flowMark.owner is line:
2521
            #            line._flowMark.append(flowMark)
2522
            #            flowMark.setParentItem(line)
2523
            # up to here
2524

    
2525
            """ update scene """
2526
            self.graphicsView.scene.update(self.graphicsView.sceneRect())
2527
            for item in self.graphicsView.scene.items():
2528
                item.setVisible(True)
2529
                
2530
                # binding items
2531
                if hasattr(item, 'owner'):
2532
                    item.owner
2533
                if hasattr(item, 'connectors'):
2534
                    for connector in item.connectors:
2535
                        connector.connectedItem
2536

    
2537
        except Exception as ex:
2538
            message = 'error occured({}) in {}:{}'.format(ex, sys.exc_info()[-1].tb_frame.f_code.co_filename, sys.exc_info()[-1].tb_lineno)
2539
            self.addMessage.emit(MessageType.Error, message)
2540
        finally:
2541
            pass
2542
            #self.graphicsView.scene.blockSignals(False)
2543

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

    
2572
        try:
2573
            #self.graphicsView.scene.blockSignals(True)
2574

    
2575
            symbols = []
2576
            lines = []
2577

    
2578
            xml = parse(xmlPath)
2579
            root = xml.getroot()
2580
            
2581
            maxValue = 0
2582
            maxValue = maxValue + len(list(root.iter('SYMBOL')))
2583
            maxValue = maxValue + len(list(root.iterfind('TEXTINFOS/ATTRIBUTE')))
2584
            maxValue = maxValue + len(list(root.iterfind('NOTES/ATTRIBUTE')))
2585
            maxValue = maxValue + len(list(root.iter('LINE_NO')))
2586
            maxValue = maxValue + len(list(root.iter('LINE')))
2587
            maxValue = maxValue + len(list(root.iter('UNKNOWN')))
2588
            maxValue = maxValue + len(list(root.iter('SIZETEXT')))
2589
            maxValue = maxValue + len(list(root.iter('TRIM_LINE_NO')))
2590
            self.progress.setMaximum(maxValue)
2591

    
2592
            """ parsing all symbols """
2593
            for symbol in root.find('SYMBOLS').iter('SYMBOL'):
2594
                item = SymbolSvgItem.fromXml(symbol)
2595
                if item is not None:
2596
                    item.transfer.onRemoved.connect(self.itemRemoved)
2597
                    symbols.append(item)
2598
                    docData.symbols.append(item)
2599
                    self.addSvgItemToScene(item)
2600
                else:
2601
                    pt = [float(x) for x in symbol.find('LOCATION').text.split(',')]
2602
                    size = [float(x) for x in symbol.find('SIZE').text.split(',')]
2603
                    angle = float(symbol.find('ANGLE').text)
2604
                    item = QGraphicsBoundingBoxItem(pt[0], pt[1], size[0], size[1])
2605
                    item.isSymbol = True
2606
                    item.angle = angle
2607
                    item.setPen(QPen(Qt.red, 5, Qt.SolidLine))
2608
                    self.graphicsView.scene.addItem(item)
2609
                    item.transfer.onRemoved.connect(self.itemRemoved)
2610

    
2611
                self.progress.setValue(self.progress.value() + 1)
2612
                
2613
            QApplication.processEvents()
2614

    
2615
            # parse texts
2616
            for text in root.find('TEXTINFOS').iter('ATTRIBUTE'):
2617
                item = QEngineeringTextItem.fromXml(text)
2618
                if item is not None:
2619
                    uid = text.find('UID')
2620
                    attributeValue = text.find('ATTRIBUTEVALUE')
2621
                    name = text.find('NAME').text
2622
                    item.transfer.onRemoved.connect(self.itemRemoved)
2623
                    self.addTextItemToScene(item)
2624
                    #docData.texts.append(item)
2625

    
2626
                    if name == 'TEXT':
2627
                        if uid is not None and attributeValue is not None:
2628
                            item.uid = uid.text
2629
                            item.attribute = attributeValue.text
2630

    
2631
                self.progress.setValue(self.progress.value() + 1)
2632
                
2633
            QApplication.processEvents()
2634

    
2635
            # note
2636
            for text in root.find('NOTES').iter('ATTRIBUTE'):
2637
                item = QEngineeringTextItem.fromXml(text)
2638
                if item is not None:
2639
                    uid = text.find('UID')
2640
                    attributeValue = text.find('ATTRIBUTEVALUE')
2641
                    name = text.find('NAME').text
2642
                    item.transfer.onRemoved.connect(self.itemRemoved)
2643
                    self.addTextItemToScene(item)
2644

    
2645
                    if name == 'NOTE':
2646
                        if uid is not None:
2647
                            item.uid = uid.text
2648

    
2649
                self.progress.setValue(self.progress.value() + 1)
2650
                
2651
            QApplication.processEvents()
2652

    
2653
            for line in root.find('LINEINFOS').iter('LINE'):
2654
                item = QEngineeringLineItem.fromXml(line)
2655
                if item:
2656
                    item.transfer.onRemoved.connect(self.itemRemoved)
2657
                    self.graphicsView.scene.addItem(item)
2658
                    lines.append(item)
2659

    
2660
                self.progress.setValue(self.progress.value() + 1)
2661
                
2662
            QApplication.processEvents()
2663

    
2664
            for unknown in root.iter('UNKNOWN'):
2665
                item = QEngineeringUnknownItem.fromXml(unknown)
2666
                item.transfer.onRemoved.connect(self.itemRemoved)
2667
                if item is not None:
2668
                    item.transfer.onRemoved.connect(self.itemRemoved)
2669
                    self.graphicsView.scene.addItem(item)
2670

    
2671
                self.progress.setValue(self.progress.value() + 1)
2672
                
2673
            QApplication.processEvents()
2674

    
2675
            #""" add tree widget """
2676
            #for item in symbols:
2677
            #    docData.symbols.append(item)
2678
            #    self.addSvgItemToScene(item)
2679
            #    self.itemTreeWidget.addTreeItem(self.itemTreeWidget.root, item)
2680

    
2681
            for line_no_node in root.find('LINENOS').iter('LINE_NO'):
2682
                line_no = QEngineeringLineNoTextItem.fromXml(line_no_node)
2683
                if line_no is None: continue
2684
                line_no.transfer.onRemoved.connect(self.itemRemoved)
2685
                self.addTextItemToScene(line_no)
2686
                line_no_tree_item = self.itemTreeWidget.addTreeItem(self.itemTreeWidget.root, line_no)
2687
                if type(line_no) is not QEngineeringLineNoTextItem: continue
2688

    
2689
                runs_node = line_no_node.findall('RUN')
2690
                if runs_node is None: continue
2691

    
2692
                for run_node in runs_node:
2693
                    line_run = QEngineeringRunItem()
2694
                    for child_node in run_node:
2695
                        uidElement = child_node.find('UID')
2696
                        if uidElement is not None:
2697
                            uid = uidElement.text
2698
                            run_item = self.graphicsView.findItemByUid(uid)
2699
                            if run_item is not None:
2700
                                run_item._owner = line_no
2701
                                line_run.items.append(run_item)
2702
                    line_run.owner = line_no
2703
                    line_no.runs.append(line_run)
2704

    
2705
                    for run_item in line_run.items:
2706
                        if issubclass(type(run_item), SymbolSvgItem): self.itemTreeWidget.addTreeItem(line_no_tree_item, run_item)
2707

    
2708
                #docData.tracerLineNos.append(line_no)
2709

    
2710
                self.progress.setValue(self.progress.value() + 1)
2711
            QApplication.processEvents()
2712

    
2713
            for trimLineNo in root.iter('TRIM_LINE_NO'):
2714
                line_no = QEngineeringTrimLineNoTextItem()
2715
                line_no.uid = uuid.UUID(trimLineNo.find('UID').text, version=4)
2716

    
2717
                run = trimLineNo.find('RUN')
2718
                if run is not None:
2719
                    line_run = QEngineeringRunItem()
2720
                    for child in run:
2721
                        uidElement = child.find('UID')
2722
                        if uidElement is not None:
2723
                            uid = uidElement.text
2724
                            run_item = self.graphicsView.findItemByUid(uid)
2725
                            if run_item is not None:
2726
                                run_item.owner = line_no
2727
                                line_run.items.append(run_item)
2728
                    line_no.runs.append(line_run)
2729
                    line_no_tree_item = self.itemTreeWidget.addTreeItem(self.itemTreeWidget.root, line_no)
2730
                    
2731
                    for run_item in line_run.items:
2732
                        if issubclass(type(run_item), SymbolSvgItem): self.itemTreeWidget.addTreeItem(line_no_tree_item, run_item)
2733

    
2734
                    docData.tracerLineNos.append(line_no)
2735

    
2736
                self.progress.setValue(self.progress.value() + 1)
2737
            QApplication.processEvents()
2738

    
2739
            if root.find('VENDORS') is not None:
2740
                for vendor in root.find('VENDORS').iter('VENDOR'):
2741
                    item = QEngineeringVendorItem.fromXml(vendor)
2742
                    item.transfer.onRemoved.connect(self.itemRemoved)
2743
                    self.graphicsView.scene.addItem(item)
2744

    
2745
            # connect flow item to line
2746
            for line in lines:
2747
                line.update_arrow()
2748
            #for flowMark in [item for item in symbols if type(item) is QEngineeringFlowMarkItem]:
2749
            #    for line in lines:
2750
            #        if flowMark.owner is line:
2751
            #            line._flowMark.append(flowMark)
2752
            #            flowMark.setParentItem(line)
2753
            # up to here
2754

    
2755
            """ update scene """
2756
            self.graphicsView.scene.update(self.graphicsView.sceneRect())
2757
            for item in self.graphicsView.scene.items():
2758
                item.setVisible(True)
2759
                
2760
                # binding items
2761
                if hasattr(item, 'owner'):
2762
                    item.owner
2763
                if hasattr(item, 'connectors'):
2764
                    for connector in item.connectors:
2765
                        connector.connectedItem
2766

    
2767
        except Exception as ex:
2768
            message = 'error occured({}) in {}:{}'.format(ex, sys.exc_info()[-1].tb_frame.f_code.co_filename, sys.exc_info()[-1].tb_lineno)
2769
            self.addMessage.emit(MessageType.Error, message)
2770
        finally:
2771
            pass
2772
            #self.graphicsView.scene.blockSignals(False)
2773

    
2774
    '''
2775
        @brief      Remove added item on same place and Add GraphicsItem
2776
        @author     Jeongwoo
2777
        @date       2018.05.25
2778
        @history    2018.05.29  Jeongwoo    Moved from QRecognitionDialog
2779
                    2018.06.18  Jeongwoo    Set Z-index
2780
    '''
2781
    def addSvgItemToScene(self, svgItem):
2782
        svgItem.addSvgItemToScene(self.graphicsView.scene)
2783
        
2784
    '''
2785
        @brief      Remove added item on same place and Add GraphicsItem
2786
        @author     Jeongwoo
2787
        @date       2018.05.25
2788
        @history    2018.05.29  Jeongwoo    Moved from QRecognitionDialog
2789
                    2018.06.05  Jeongwoo    Remove Size condition
2790
                    2018.06.18  Jeongwoo    Set Z-index
2791
    '''
2792
    def addTextItemToScene(self, textItem):
2793
        textItem.addTextItemToScene(self.graphicsView.scene)
2794
        
2795
    '''
2796
        @brief      Remove added item on same place and Add GraphicsItem
2797
        @author     Jeongwoo
2798
        @date       2018.05.29
2799
        @history    2018.06.18  Jeongwoo    Set Z-index
2800
    '''
2801
    def addLineItemToScene(self, lineItem):
2802
        self.graphicsView.scene.addItem(lineItem)
2803

    
2804
    '''
2805
        @brief      generate output xml file
2806
        @author     humkyung
2807
        @date       2018.04.23
2808
        @history    2018.05.02  Jeongwoo    Show MessageBox when imageviewer doesn't have image
2809
    '''
2810
    def generateOutput(self):
2811
        import XmlGenerator as xg
2812

    
2813
        if not self.graphicsView.hasImage():
2814
            self.showImageSelectionMessageBox()
2815
            return
2816

    
2817
        try:
2818
            appDocData = AppDocData.instance()
2819

    
2820
            ## collect items
2821
            appDocData.lines.clear()
2822
            appDocData.lines = [item for item in self.graphicsView.scene.items() if type(item) is QEngineeringLineItem and item.owner is None]
2823

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

    
2827
            appDocData.equipments.clear()
2828
            for item in self.graphicsView.scene.items():
2829
                if type(item) is QEngineeringEquipmentItem:
2830
                    appDocData.equipments.append(item)
2831

    
2832
            appDocData.texts.clear()
2833
            appDocData.texts = [item for item in self.graphicsView.scene.items() if issubclass(type(item), QEngineeringTextItem) and type(item) is not QEngineeringLineNoTextItem]
2834
            ## up to here
2835

    
2836
            appDocData.imgOutput = np.ones((appDocData.imgHeight, appDocData.imgWidth), np.uint8)*255
2837
            xg.writeOutputXml(appDocData.imgName, appDocData.imgWidth, appDocData.imgHeight) # TODO: check
2838
            project = appDocData.getCurrentProject()
2839
            cv2.imwrite(os.path.join(project.getTempPath() , 'OUTPUT.png') , appDocData.imgOutput)
2840
        except Exception as ex:
2841
            message = 'error occured({}) in {}:{}'.format(ex, sys.exc_info()[-1].tb_frame.f_code.co_filename, sys.exc_info()[-1].tb_lineno)
2842
            self.addMessage.emit(MessageType.Error, message)
2843

    
2844
    '''
2845
        @brief      resetting attribute at secne
2846
        @author     kyoyho
2847
        @date       2018.08.21
2848
    '''
2849
    """
2850
    def checkAttribute(self):
2851
        try:
2852

2853
            docData = AppDocData.instance()
2854
            if not self.graphicsView.hasImage():
2855
                return
2856

2857
            # symbol 경우
2858
            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]
2859
            for item in items:
2860
                attrs = item.attrs
2861
                
2862
                removeAttrList = []
2863
                for attr in attrs:
2864
                    if type(attr) is tuple:
2865
                        continue
2866

2867
                    if attr is None:
2868
                        removeAttrList.append(attr)
2869
                        continue
2870

2871
                    attrInfo = docData.getSymbolAttributeByUID(attr.UID)
2872
                    if attrInfo is None:
2873
                        removeAttrList.append(attr)
2874
                    # 해당 attribute가 맞는지 확인
2875
                    else:
2876
                        attrType = attrInfo.AttributeType
2877
                        _type = type(attr)
2878
                        if attrType == 'Symbol Item':
2879
                            if not issubclass(_type, SymbolSvgItem):
2880
                                removeAttrList.append(attr)
2881
                        elif attrType == 'Text Item':
2882
                            if _type is not QEngineeringTextItem:
2883
                                removeAttrList.append(attr)
2884
                        elif attrType == 'Int':
2885
                            if _type is not UserInputAttribute and self.isNumber(attr.text):
2886
                                removeAttrList.append(attr)
2887
                        elif attrType == 'String':
2888
                            if _type is not UserInputAttribute:
2889
                                removeAttrList.append(attr)
2890

2891
                for attr in removeAttrList:
2892
                    del attrs[attr]
2893

2894
            # Line No Text Item의 경우
2895
            items = [item for item in self.graphicsView.scene.items() if issubclass(type(item), QEngineeringLineNoTextItem)]
2896
            for item in items:
2897
                attrs = item.attrs
2898
                
2899
                removeAttrList = []
2900
                for attr in attrs:
2901
                    if type(attr) is UserInputAttribute:
2902
                        attrInfo = docData.getLinePropertiesByUID(attr.attribute)
2903
                        if attrInfo is None:
2904
                            removeAttrList.append(attr)
2905

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

2909
        except Exception as ex:
2910
                message = 'error occured({}) in {}:{}'.format(ex, sys.exc_info()[-1].tb_frame.f_code.co_filename, sys.exc_info()[-1].tb_lineno)
2911
                self.addMessage.emit(MessageType.Error, message)
2912
    """
2913
    '''
2914
        @brief      Check Number
2915
        @author     kyouho
2916
        @date       2018.08.20
2917
    '''
2918
    def isNumber(self, num):
2919
        p = re.compile('(^[0-9]+$)')
2920
        result = p.match(num)
2921

    
2922
        if result:
2923
            return True
2924
        else:
2925
            return False
2926

    
2927
    '''
2928
        @brief      find overlap Connector
2929
        @author     kyouho
2930
        @date       2018.08.28
2931
    '''
2932
    def findOverlapConnector(self, connectorItem):
2933
        from shapely.geometry import Point
2934
        from EngineeringConnectorItem import QEngineeringConnectorItem
2935
        itemList = []
2936
        
2937
        x = connectorItem.center()[0]
2938
        y = connectorItem.center()[1]
2939

    
2940
        connectors = [item for item in self.graphicsView.scene.items() if type(item) is QEngineeringConnectorItem and item != connectorItem]
2941
        for connector in connectors:
2942
            if Point(x, y).distance(Point(connector.center()[0], connector.center()[1])) < 5:
2943
                itemList.append(connector.parent)
2944

    
2945
        return itemList
2946

    
2947
if __name__ == '__main__':
2948
    import locale
2949
    from PyQt5.QtCore import QTranslator
2950
    from License import QLicenseDialog
2951
    from ProjectDialog import Ui_Dialog
2952
    from App import App 
2953

    
2954
    app = App(sys.argv)
2955
    try:
2956
        if True == QLicenseDialog.check_license_key():
2957
            dlg = Ui_Dialog()
2958
            selectedProject = dlg.showDialog()
2959
            if selectedProject is not None:
2960
                AppDocData.instance().setCurrentProject(selectedProject)
2961
                app._mainWnd = MainWindow.instance()
2962
                app._mainWnd.show()
2963
                sys.exit(app.exec_())
2964
    except Exception as ex:
2965
        print('error occured({}) in {}:{}'.format(ex, sys.exc_info()[-1].tb_frame.f_code.co_filename, sys.exc_info()[-1].tb_lineno))
2966
    finally:
2967
        pass
클립보드 이미지 추가 (최대 크기: 500 MB)