프로젝트

일반

사용자정보

통계
| 개정판:

hytos / DTI_PID / DTI_PID / MainWindow.py @ 695442ff

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

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

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

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

    
21
import cv2
22
import numpy as np
23

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

    
29
from PIL import Image
30

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

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

    
71

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

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

    
79

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

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

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

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

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

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

    
133
        # save timer
134
        self.save_timer = None
135

    
136
        self.lineComboBox = QComboBox(self.toolBar)
137
        for condition in LineTypeConditions.items():
138
            self.lineComboBox.addItem(condition.name)
139

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

    
149
        self.toolBar.insertWidget(self.actionOCR, self.lineComboBox)
150
        self.toolBar.insertSeparator(self.actionOCR)
151

    
152
        self.packageComboBox = QComboBox(self.toolBar)
153
        self.packageComboBox.addItems(['Equipment Package', 'Vendor Package'])
154
        self.toolBar.insertWidget(self.actionValidate, self.packageComboBox)
155

    
156
        self._scene = QtImageViewerScene(self)
157

    
158
        self.graphicsView = QtImageViewer(self)
159
        self.graphicsView.setParent(self.centralwidget)
160
        self.graphicsView.useDefaultCommand()  # USE DEFAULT COMMAND
161
        self.graphicsView.setMouseTracking(True)
162
        self.graphicsView.viewport().installEventFilter(self)
163
        self.graphicsView.setScene(self._scene)
164

    
165
        self._display_widget = QDisplayWidget()
166
        self._display_widget.radioButtonByGroup.toggled.connect(self.display_colors)
167
        self._display_widget.radioButtonByGroup.toggled.connect(self.display_colors)
168
        self.EditToolbar.addWidget(self._display_widget)
169
        self._display_widget.radioButtonByGroup.setChecked(True) \
170
            if DisplayColors.instance().option == DisplayOptions.DisplayByLineNo else \
171
            self._display_widget.radioButtonByType.setChecked(True)
172

    
173
        self.verticalLayout.addWidget(self.graphicsView)
174

    
175
        # Add Custom TreeWidget
176
        self.symbolTreeWidget = SymbolTreeWidget.QSymbolTreeWidget()
177
        self.symbolTreeWidget.header().hide()
178
        self.verticalLayoutSymbolTree.addWidget(self.symbolTreeWidget)
179

    
180
        from LibraryItem import LibraryItemWidget
181
        self.libraryWidget = LibraryItemWidget(symbol_tree_widget=self.symbolTreeWidget)
182
        self.verticalLayoutLibrary.addWidget(self.libraryWidget)
183
        # Add Custom Property TableWidget
184
        self.propertyTableWidget = SymbolPropertyTableWidget.QSymbolPropertyTableWidget()
185
        self.verticalLayoutSymbolProperty.addWidget(self.propertyTableWidget)
186
        self.symbolTreeWidget.singleClicked.connect(self.propertyTableWidget.getClickedSymbol)
187

    
188
        self.splitterSymbol.setSizes([500, 300])
189

    
190
        # Add Custom Result Tree Widget (Symbol Explorer)
191
        self.itemTreeWidget = ItemTreeWidget.QItemTreeWidget(self.graphicsView)
192
        self.itemTreeWidget.header().hide()
193
        self.symbolExplorerVerticalLayout.addWidget(self.itemTreeWidget)
194

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

    
209
        # Initialize Action group
210
        self.actionGroup = QActionGroup(self)
211
        self.actionGroup.addAction(self.actionRecognition)
212
        self.actionGroup.addAction(self.actionLineRecognition)
213
        self.actionGroup.addAction(self.actionLine)
214
        self.actionGroup.addAction(self.actionGenerateOutput)
215
        self.actionGroup.addAction(self.actionOCR)
216
        self.actionGroup.addAction(self.actionZoom)
217
        self.actionGroup.addAction(self.actionFitWindow)
218
        self.actionGroup.addAction(self.actionSave)
219
        self.actionGroup.addAction(self.actionValidate)
220
        self.actionGroup.addAction(self.actionVendor)
221
        self.actionGroup.triggered.connect(self.actionGroupTriggered)
222

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

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

    
290
        self.delimiter = '"'
291

    
292
        self.resizeDocks({self.dockWidget}, {self.dockWidgetObjectExplorer.sizeHint().width()}, Qt.Horizontal)
293

    
294
        self.treeWidgetDrawingList.setHeaderHidden(False)
295
        self.treeWidgetDrawingList.header().setStretchLastSection(False)
296
        self.treeWidgetDrawingList.setHeaderLabels([self.tr('Name'), self.tr('DateTime')])
297
        self.treeWidgetDrawingList.header().setSectionResizeMode(0, QHeaderView.ResizeToContents)
298
        self.treeWidgetDrawingList.header().setSectionResizeMode(1, QHeaderView.ResizeToContents)
299
        self.treeWidgetDrawingList.itemDoubleClicked.connect(self.open_selected_drawing)
300
        self.load_drawing_list()
301

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

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

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

    
334
        self.read_settings()
335

    
336
    @property
337
    def title(self) -> str:
338
        """return window title"""
339

    
340
        from App import App
341

    
342
        app_doc_data = AppDocData.instance()
343
        project = app_doc_data.getCurrentProject()
344
        version = QCoreApplication.applicationVersion()
345
        title = f"{App.NAME}({version}) - {project.name}:" \
346
                f"{app_doc_data.activeDrawing.name if app_doc_data.activeDrawing else ''}"
347

    
348
        return title
349

    
350
    @property
351
    def scene(self):
352
        """getter scene"""
353
        return self._scene
354

    
355
    def eventFilter(self, source, event):
356
        """display mouse position of graphics view"""
357
        try:
358
            if event.type() == QEvent.MouseMove:
359
                self.current_pos = self.graphicsView.mapToScene(event.pos())
360
                self._label_mouse.setText(
361
                    'mouse pos : ({},{})'.format(round(self.current_pos.x()), round(self.current_pos.y())))
362
        except Exception as ex:
363
            message = 'error occurred({}) in {}:{}'.format(ex, sys.exc_info()[-1].tb_frame.f_code.co_filename,
364
                                                           sys.exc_info()[-1].tb_lineno)
365
            self.addMessage.emit(MessageType.Error, message)
366

    
367
        return QWidget.eventFilter(self, source, event)
368

    
369
    def closeEvent(self, event):
370
        """save geometry and state and ask user to save drawing which is modified"""
371

    
372
        self.settings.setValue('geometry', self.saveGeometry())
373
        self.settings.setValue('windowState', self.saveState())
374
        # TODO: need to modify
375
        # self.save_drawing_if_necessary()
376
        AppDocData.instance().clear()
377
        event.accept()
378

    
379
    def inconsistencyTableKeyPressEvent(self, event):
380
        try:
381
            row = self.tableWidgetInconsistency.selectedIndexes()[0].row()
382
            col = self.tableWidgetInconsistency.selectedIndexes()[0].column()
383
            from HighlightCommand import HighlightCommand
384
            if event.key() == Qt.Key_Up:
385
                if row is not 0:
386
                    errorItem = self.tableWidgetInconsistency.item(row - 1, 1).tag
387
                    HighlightCommand(self.graphicsView).execute(errorItem)
388
            elif event.key() == Qt.Key_Down:
389
                if row is not self.tableWidgetInconsistency.rowCount() - 1:
390
                    errorItem = self.tableWidgetInconsistency.item(row + 1, 1).tag
391
                    HighlightCommand(self.graphicsView).execute(errorItem)
392
            elif event.key() == Qt.Key_Delete:
393
                item = self.tableWidgetInconsistency.item(row, 0).tag
394
                if item and item.scene(): item.scene().removeItem(item)
395
                self.tableWidgetInconsistency.removeRow(row)
396

    
397
                self.tabWidget_2.setTabText(self.tabWidget_2.indexOf(self.tabInconsistency),
398
                                            self.tr('Inconsistency') + f"({self.tableWidgetInconsistency.rowCount()})")
399
        except Exception as ex:
400
            message = 'error occurred({}) in {}:{}'.format(ex, sys.exc_info()[-1].tb_frame.f_code.co_filename,
401
                                                           sys.exc_info()[-1].tb_lineno)
402
            self.addMessage.emit(MessageType.Error, message)
403
        # finally:
404
        #    return QTableView.keyPressEvent(self.tableWidgetInconsistency, event)
405

    
406
    def onValidation(self):
407
        """validation check"""
408
        from ValidationDialog import QValidationDialog
409
        from ValidateCommand import ValidateCommand
410

    
411
        if not self.graphicsView.hasImage():
412
            self.showImageSelectionMessageBox()
413
            return
414

    
415
        try:
416
            dlg = QValidationDialog(self)
417
            if QDialog.Accepted == dlg.exec_():
418
                # remove error items
419
                for item in self.graphicsView.scene().items():
420
                    if type(item) is QEngineeringErrorItem:
421
                        item.transfer.onRemoved.emit(item)
422
                # up to here
423

    
424
                self.progress_bar.setMaximum(len(self.graphicsView.scene().items()))
425
                self.progress_bar.setValue(0)
426

    
427
                cmd = ValidateCommand(self.graphicsView)
428
                cmd.show_progress.connect(self.progress_bar.setValue)
429
                errors = cmd.execute(self.graphicsView.scene().items())
430
                for error in errors:
431
                    error.transfer.onRemoved.connect(self.itemRemoved)
432
                    #self.graphicsView.scene().addItem(error)
433
                    error.addSvgItemToScene(self.graphicsView.scene())
434

    
435
                self.tableWidgetInconsistency.clearContents()
436
                self.tableWidgetInconsistency.setRowCount(len(errors))
437
                for index, error in enumerate(errors):
438
                    self.makeInconsistencyTableRow(index, error)
439

    
440
                self.tabWidget_2.setTabText(self.tabWidget_2.indexOf(self.tabInconsistency),
441
                                            self.tr('Inconsistency') + f"({len(errors)})")
442
                if errors:
443
                    self.tabWidget_2.tabBar().setTabTextColor(self.tabWidget_2.indexOf(self.tabInconsistency), Qt.red)
444
                else:
445
                    self.tabWidget_2.tabBar().setTabTextColor(self.tabWidget_2.indexOf(self.tabInconsistency), Qt.black)
446
        except Exception as ex:
447
            message = 'error occurred({}) in {}:{}'.format(ex, sys.exc_info()[-1].tb_frame.f_code.co_filename,
448
                                                           sys.exc_info()[-1].tb_lineno)
449
            self.addMessage.emit(MessageType.Error, message)
450
        finally:
451
            self.progress_bar.setValue(self.progress_bar.maximum())
452

    
453
    def makeInconsistencyTableRow(self, row, errorItem):
454
        '''
455
            @brief  make row data for inconsistency widget
456
            @author euisung
457
            @date   2019.04.16
458
        '''
459

    
460
        item = QTableWidgetItem(str(errorItem.parent))
461
        item.tag = errorItem
462
        self.tableWidgetInconsistency.setItem(row, 0, item)
463

    
464
        item = QTableWidgetItem(str(type(errorItem.parent)))
465
        item.tag = errorItem
466
        self.tableWidgetInconsistency.setItem(row, 1, item)
467

    
468
        item = QTableWidgetItem(errorItem.msg)
469
        item.tag = errorItem
470
        self.tableWidgetInconsistency.setItem(row, 2, item)
471

    
472
    def inconsistencyItemClickEvent(self, item):
473
        """
474
        @brief  inconsistency table item clicked
475
        @author euisung
476
        @date   2019.04.02
477
        """
478
        from HighlightCommand import HighlightCommand
479

    
480
        HighlightCommand(self.graphicsView).execute(item.tag)
481

    
482
    def read_settings(self):
483
        """read geometry and state"""
484
        from App import App
485

    
486
        try:
487
            self.settings = QSettings(App.COMPANY, App.NAME)
488
            self.restoreGeometry(self.settings.value("geometry", ""))
489
            self.restoreState(self.settings.value("windowState", ""))
490
        except Exception as ex:
491
            message = 'error occurred({}) in {}:{}'.format(ex, sys.exc_info()[-1].tb_frame.f_code.co_filename,
492
                                                           sys.exc_info()[-1].tb_lineno)
493
            print(message)
494

    
495
    def load_stylesheet(self, file):
496
        """load stylesheets"""
497

    
498
        QtWidgets.qApp.loadStyleSheet(os.path.join(os.path.dirname(os.path.realpath(__file__)), file))
499

    
500
        app_doc_data = AppDocData.instance()
501
        configs = [Config('app', 'stylesheet', file)]
502
        app_doc_data.saveAppConfigs(configs)
503

    
504
        for action in self.menuTheme.actions():
505
            if action.text() == file: continue
506
            action.setChecked(False)
507

    
508
    def load_language(self, file):
509
        """load language file and then apply selected language"""
510
        try:
511
            qm_file = os.path.join(os.path.dirname(os.path.realpath(__file__)), 'translate', '{0}.qm'.format(file))
512
            QtWidgets.qApp.load_language(qm_file)
513

    
514
            app_doc_data = AppDocData.instance()
515
            configs = [Config('app', 'language', file)]
516
            app_doc_data.saveAppConfigs(configs)
517

    
518
            for action in self.menuLanguage.actions():
519
                if action.text().lower() == file.lower(): continue
520
                action.setChecked(False)
521
        finally:
522
            self.retranslateUi(self)
523
            self.propertyTableWidget.retranslateUi()
524

    
525
    def load_drawing_list(self):
526
        """load p&id drawing list"""
527
        from Drawing import Drawing
528

    
529
        try:
530
            app_doc_data = AppDocData.instance()
531
            drawings = app_doc_data.getDrawings()
532

    
533
            self.treeWidgetDrawingList.clear()
534
            self.treeWidgetDrawingList.root = QTreeWidgetItem(self.treeWidgetDrawingList,
535
                                                              [self.tr('P&ID Drawings'), ''])
536
            self.treeWidgetDrawingList.root.setFlags(
537
                self.treeWidgetDrawingList.root.flags() | Qt.ItemIsTristate | Qt.ItemIsUserCheckable)
538
            self.treeWidgetDrawingList.root.setCheckState(0, Qt.Unchecked)
539
            files = app_doc_data.getDrawingFileList()
540

    
541
            # self.progress_bar.setMaximum(len(files))
542
            count = 0
543
            # self.progress_bar.setValue(count)
544
            for file in files:
545
                x = [drawing for drawing in drawings if drawing.name == file]
546
                if not x or not x[0].UID:
547
                    drawing = Drawing(None, file, None)
548
                    drawings.append(drawing)
549
                else:
550
                    drawing = x[0]
551

    
552
                item = QTreeWidgetItem(self.treeWidgetDrawingList.root, [file, drawing.datetime])
553
                item.setIcon(0, QIcon(':newPrefix/image.png'))
554
                item.setFlags(item.flags() | Qt.ItemIsUserCheckable)
555
                item.setCheckState(0, Qt.Unchecked)
556
                item.setData(Qt.UserRole, 0, drawing)
557

    
558
                count += 1
559
                # self.progress_bar.setValue(count)
560
                # QApplication.processEvents()
561

    
562
            self.treeWidgetDrawingList.root.setText(0, self.tr('P&ID Drawings') +
563
                                                    f"({self.treeWidgetDrawingList.root.childCount()})")
564
            self.treeWidgetDrawingList.expandItem(self.treeWidgetDrawingList.root)
565
            self.treeWidgetDrawingList.root.sortChildren(0, Qt.AscendingOrder)
566
            self.treeWidgetDrawingList.resizeColumnToContents(0)
567

    
568
            app_doc_data.saveDrawings(drawings)
569
        except Exception as ex:
570
            message = 'error occurred({}) in {}:{}'.format(repr(ex), sys.exc_info()[-1].tb_frame.f_code.co_filename,
571
                                                           sys.exc_info()[-1].tb_lineno)
572
            self.addMessage.emit(MessageType.Error, message)
573
        finally:
574
            self.progress_bar.setValue(self.progress_bar.maximum())
575

    
576
    def open_selected_drawing(self, item, column):
577
        """open selected p&id drawing"""
578

    
579
        app_doc_data = AppDocData.instance()
580
        drawing = item.data(Qt.UserRole, 0)
581
        if drawing:
582
            # uncheck all drawing tree item
583
            drawing_top = self.treeWidgetDrawingList.topLevelItem(0)
584
            count = drawing_top.childCount()
585
            for idx in range(count):
586
                child = drawing_top.child(idx)
587
                child.setCheckState(column, Qt.Unchecked)
588
            # up to here
589

    
590
            drawing.image = None
591
            self.open_image_drawing(drawing)
592
            item.setCheckState(column, Qt.Checked)
593

    
594
    def show_detect_symbol_dialog(self):
595
        from DetectSymbolDialog import QDetectSymbolDialog
596

    
597
        dlg = QDetectSymbolDialog(self)
598
        dlg.exec_()
599

    
600
    '''
601
        @brief      OCR Editor
602
        @author     euisung
603
        @date       2018.10.05
604
        @history    2018.10.16 euisung      no more used, Integrated with oCRTrainingClicked
605
    '''
606

    
607
    def oCRTrainingEdidorClicked(self):
608
        from TrainingEditorDialog import QTrainingEditorDialog
609

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

    
618
        return
619

    
620
    '''
621
        @brief      OCR Training
622
        @author     euisung
623
        @date       2018.09.27
624
        @history    euisung 2018.10.16 TrainingListDialog -> TrainingImageListDialog
625
    '''
626

    
627
    def oCRTrainingClicked(self):
628
        try:
629
            dialog = QTrainingImageListDialog(self)
630
            dialog.exec_()
631
        except Exception as ex:
632
            message = 'error occurred({}) in {}:{}'.format(ex, sys.exc_info()[-1].tb_frame.f_code.co_filename,
633
                                                           sys.exc_info()[-1].tb_lineno)
634
            self.addMessage.emit(MessageType.Error, message)
635

    
636
    def symbolTrainingClicked(self):
637
        try:
638
            dialog = QTrainingSymbolImageListDialog(self)
639
            dialog.exec_()
640
        except Exception as ex:
641
            message = 'error occurred({}) in {}:{}'.format(ex, sys.exc_info()[-1].tb_frame.f_code.co_filename,
642
                                                           sys.exc_info()[-1].tb_lineno)
643
            self.addMessage.emit(MessageType.Error, message)
644

    
645
    def findReplaceTextClicked(self):
646
        """pop up find and replace dialog"""
647
        if not self.graphicsView.hasImage():
648
            self.showImageSelectionMessageBox()
649
            return
650

    
651
        from TextItemEditDialog import QTextItemEditDialog
652

    
653
        self.dlgTextItemEdit = QTextItemEditDialog(self)
654
        self.dlgTextItemEdit.show()
655
        self.dlgTextItemEdit.exec_()
656

    
657
    def ReplaceInsertSymbolClicked(self):
658
        """pop up replace and insert dialog"""
659
        if not self.graphicsView.hasImage():
660
            self.showImageSelectionMessageBox()
661
            return
662

    
663
        from ReplaceSymbolDialog import QReplaceSymbolDialog
664

    
665
        self.dlgReplace = QReplaceSymbolDialog(self)
666
        self.dlgReplace.show()
667
        self.dlgReplace.exec_()
668

    
669
    def on_recognize_line(self):
670
        """recognize lines in selected area"""
671
        from RecognizeLineCommand import RecognizeLineCommand
672

    
673
        if not self.graphicsView.hasImage():
674
            self.actionOCR.setChecked(False)
675
            self.showImageSelectionMessageBox()
676
            return
677

    
678
        cmd = RecognizeLineCommand(self.graphicsView)
679
        cmd.onSuccess.connect(self.on_success_to_recognize_line)
680
        cmd.onRejected.connect(self.onCommandRejected)
681
        self.graphicsView.command = cmd
682

    
683
    '''
684
            @brief      show text recognition dialog
685
            @author     humkyung
686
            @date       2018.08.08
687
        '''
688

    
689
    def on_success_to_recognize_line(self, x, y, width, height):
690
        import io
691
        from LineDetector import LineDetector
692
        from EngineeringGraphicsLineItem import QEngineeringGraphicsLineItem
693

    
694
        try:
695
            image = self.graphicsView.image().copy(x, y, width, height)
696
            buffer = QBuffer()
697
            buffer.open(QBuffer.ReadWrite)
698
            image.save(buffer, "PNG")
699
            pyImage = Image.open(io.BytesIO(buffer.data()))
700
            img = np.array(pyImage)
701
            img = cv2.cvtColor(img, cv2.COLOR_BGR2GRAY)
702

    
703
            detector = LineDetector(img)
704
            lines = detector.detect_line_without_symbol()
705
            for line in lines:
706
                vertices = [[line[0][0] + x, line[0][1] + y], [line[1][0] + x, line[1][1] + y]]
707
                line_item = QEngineeringGraphicsLineItem(vertices)
708
                self.graphicsView.scene().addItem(line_item)
709

    
710
        except Exception as ex:
711
            message = 'error occurred({}) in {}:{}'.format(repr(ex), sys.exc_info()[-1].tb_frame.f_code.co_filename,
712
                                                           sys.exc_info()[-1].tb_lineno)
713
            self.addMessage.emit(MessageType.Error, message)
714

    
715
    def display_number_of_items(self):
716
        """display count of symbol, line, text"""
717

    
718
        items = [item for item in self.graphicsView.scene().items() if type(item) is QEngineeringUnknownItem]
719
        if len(items) > 0:
720
            self.labelStatus.setText(
721
                "<font color='red'>" + self.tr('Unrecognition') + " : {}</font>".format(len(items)))
722
        else:
723
            self.labelStatus.setText(
724
                "<font color='black'>" + self.tr('Unrecognition') + " : {}</font>".format(len(items)))
725

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

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

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

    
736
        self.itemTreeWidget.sceneChanged(self.graphicsView.scene().items())
737

    
738
    def dbUpdate(self):
739
        """ no more used """
740
        """db update when save or recognition"""
741

    
742
        try:
743
            appDocData = AppDocData.instance()
744
            items = appDocData.allItems
745

    
746
            '''
747
            titleBlockProps = appDocData.getTitleBlockProperties()
748
            titleBlockItems = []
749
            for item in items:
750
                # if type(item) is QEngineeringLineNoTextItem:
751
                #    item.saveLineData()
752
                if type(item) is QEngineeringTextItem:
753
                    for titleBlockProp in titleBlockProps:
754
                        if item.area == titleBlockProp[0]:
755
                            titleBlockItems.append(item)
756
            '''
757

    
758
            # unknown item is not saved now for performance
759
            db_items = [item for item in items if issubclass(type(item), QEngineeringAbstractItem) and
760
                        type(item) is not QGraphicsBoundingBoxItem and
761
                        type(item) is not QEngineeringErrorItem and
762
                        type(item) is not QEngineeringLineNoTextItem and
763
                        type(item) is not QEngineeringUnknownItem]
764
            db_items.extend([item for item in items if type(item) is QEngineeringLineNoTextItem])
765
            db_items.extend([line for line in appDocData.tracerLineNos if type(line) is QEngineeringTrimLineNoTextItem])
766
            # db_items.extend(titleBlockItems)
767
            configs = appDocData.getConfigs('Data Save', 'Unknown Xml Only')
768
            if configs and int(configs[0].value) is -1:
769
                db_items.extend([item for item in items if type(item) is QEngineeringUnknownItem])
770

    
771
            '''
772
            dbItems = [item for item in items if
773
                       type(item) is QEngineeringInstrumentItem or type(item) is QEngineeringEquipmentItem or type(
774
                           item) is QEngineeringReducerItem or \
775
                       type(item) is QEngineeringNoteItem or type(item) is SymbolSvgItem or type(
776
                           item) is QEngineeringLineNoTextItem or type(
777
                           item) is QEngineeringVendorItem] + titleBlockItems
778
            '''
779
            appDocData.saveToDatabase(db_items)
780
        except Exception as ex:
781
            message = 'error occurred({}) in {}:{}'.format(ex, sys.exc_info()[-1].tb_frame.f_code.co_filename,
782
                                                           sys.exc_info()[-1].tb_lineno)
783
            self.addMessage.emit(MessageType.Error, message)
784

    
785
    def save_drawing_if_necessary(self):
786
        """ask to user to save drawing or not when drawing is modified"""
787

    
788
        app_doc_data = AppDocData.instance()
789
        if app_doc_data.activeDrawing and app_doc_data.activeDrawing.modified:
790
            #if QMessageBox.Yes == QMessageBox.question(self, self.tr("Question"),
791
            #                                           self.tr("Do you want to save drawing?"),
792
            #                                           QMessageBox.Yes | QMessageBox.No):
793
            #    self.actionSaveCliked()
794
            #    return True
795
            if QMessageBox.Ignore == QMessageBox.question(self, self.tr('Continue?'),
796
                                                       self.tr('Changes may not have been saved.'),
797
                                                       QMessageBox.Ignore | QMessageBox.Cancel):
798
                return False
799
            return True
800

    
801
    '''
802
        @brief      action save click event
803
        @author     kyouho
804
        @date       2018.08.09
805
        @history    2018.11.02      euisung     add line data list db update
806
                    humkyung save saved time to database
807
                    2018.11.05      euisung     add note data list db update
808
                    2018.11.05      euisung     add db delete process before save
809
                    2018.11.12      euisung     db part move new method to dbUpdate
810
    '''
811

    
812
    def actionSaveCliked(self):
813
        from EngineeringAbstractItem import QEngineeringAbstractItem
814
        from SaveWorkCommand import SaveWorkCommand
815

    
816
        try:
817
            if not self.actionSave.isEnabled():
818
                return
819
            self.actionSave.setEnabled(False)
820

    
821
            # save alarm
822
            self.save_alarm_enable(False)
823

    
824
            app_doc_data = AppDocData.instance()
825
            if app_doc_data.imgName is None:
826
                self.showImageSelectionMessageBox()
827
                return
828

    
829
            app_doc_data.clearItemList(False)
830

    
831
            items = self.graphicsView.scene().items()
832

    
833
            '''
834
            # for check line disappear bug
835
            disappear_lines = [line for line in app_doc_data.lines if line not in items]
836
            '''
837

    
838
            '''
839
            for item in items:
840
                if issubclass(type(item), QEngineeringAbstractItem):
841
                    app_doc_data.allItems.append(item)
842
                    if issubclass(type(item), QEngineeringTextItem):
843
                        app_doc_data.texts.append(item)
844
            '''
845

    
846
            '''
847
            # for check line disappear bug
848
            if disappear_lines:
849
                app_doc_data.allItems.extend(disappear_lines)
850
                for dis_line in disappear_lines:
851
                    self.addMessage.emit(MessageType.Check, f"disapper line from scene : {str(dis_line)}")
852
            '''
853

    
854
            '''
855
            itemTypes = []
856
            for item in items:
857
                typeExist = False
858
                for itemType in itemTypes:
859
                    if type(item) is itemType:
860
                        typeExist = True
861
                        break
862
                if not typeExist:
863
                    itemTypes.append(type(item))
864
            '''
865

    
866
            self._save_work_cmd = SaveWorkCommand(self.graphicsView.scene())
867
            self._save_work_cmd.show_progress.connect(self.progress_bar.setValue)
868
            self._save_work_cmd.display_message.connect(self.onAddMessage)
869
            self._save_work_cmd.finished.connect(self.save_finished)
870

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

    
877
    def save_finished(self):
878
        """reload drawing list"""
879

    
880
        self._save_work_cmd.show_progress.emit(100)
881
        QMessageBox.about(self.graphicsView, self.tr('Information'), self._save_work_cmd.resultStr)
882
        self.load_drawing_list()
883

    
884
        app_doc_data = AppDocData.instance()
885
        app_doc_data.activeDrawing.modified = False
886
        title = self.windowTitle()
887
        self.setWindowTitle(title[:-1] if title[-1] == '*' else title)
888

    
889
        self.actionSave.setEnabled(True)
890
        
891
        # save alarm
892
        self.save_alarm_enable(True)
893

    
894
    '''
895
        @brief      refresh resultPropertyTableWidget
896
        @author     kyouho
897
        @date       2018.07.19
898
    '''
899

    
900
    def refreshResultPropertyTableWidget(self):
901
        items = self.graphicsView.scene().selectedItems()
902
        if len(items) == 1:
903
            self.resultPropertyTableWidget.show_item_property(items[0])
904

    
905
    '''
906
        @brief  add message listwidget
907
        @author humkyung
908
        @date   2018.07.31
909
    '''
910

    
911
    def onAddMessage(self, messageType, message):
912
        from AppDocData import MessageType
913

    
914
        try:
915
            current = QDateTime.currentDateTime()
916

    
917
            item = QListWidgetItem('{}: {}'.format(current.toString('hh:mm:ss'), message))
918
            item.setFlags(item.flags() | Qt.ItemIsEditable)
919
            if messageType == MessageType.Error:
920
                item.setBackground(Qt.red)
921
            elif messageType == 'check':
922
                item.setBackground(Qt.yellow)
923

    
924
            self.listWidgetLog.insertItem(0, item)
925
        except Exception as ex:
926
            print('error occurred({}) in {}:{}'.format(ex, sys.exc_info()[-1].tb_frame.f_code.co_filename,
927
                                                       sys.exc_info()[-1].tb_lineno))
928

    
929
    '''
930
        @brief      clear log
931
        @author     humkyung
932
        @date       2018.08.01
933
    '''
934

    
935
    def onClearLog(self):
936
        self.listWidgetLog.clear()
937

    
938
    '''
939
        @brief      rotate selected symbol
940
        @author     humkyung
941
        @date       2018.08.15
942
    '''
943

    
944
    def onRotate(self, action):
945
        selected = [item for item in self.graphicsView.scene().selectedItems() if issubclass(type(item), SymbolSvgItem)]
946
        if len(selected) == 1:
947
            from RotateCommand import RotateCommand
948
            self.graphicsView.scene()._undo_stack.push(RotateCommand(self.graphicsView.scene(), selected))
949

    
950
    '''
951
        @brief      Area Zoom
952
        @author     Jeongwoo
953
        @date       2018.06.27
954
        @history    connect command's rejected signal
955
    '''
956

    
957
    def onAreaZoom(self, action):
958
        if self.actionZoom.isChecked():
959
            cmd = AreaZoomCommand.AreaZoomCommand(self.graphicsView)
960
            cmd.onRejected.connect(self.onCommandRejected)
961
            self.graphicsView.command = cmd
962

    
963
    def onVendor(self, action):
964
        """make vendor package area"""
965

    
966
        if not self.graphicsView.hasImage():
967
            self.actionVendor.setChecked(False)
968
            self.showImageSelectionMessageBox()
969
            return
970

    
971
        self.actionVendor.setChecked(True)
972
        if not hasattr(self.actionVendor, 'tag'):
973
            self.actionVendor.tag = PlacePolygonCommand.PlacePolygonCommand(self.graphicsView)
974
            self.actionVendor.tag.onSuccess.connect(self.onVendorCreated)
975
            self.actionVendor.tag.onRejected.connect(self.onCommandRejected)
976

    
977
        self.graphicsView.command = self.actionVendor.tag
978

    
979
    def onVendorCreated(self):
980
        """add created vendor polygon area to scene"""
981

    
982
        try:
983
            count = len(self.actionVendor.tag._polyline._vertices)
984
            if count > 2:
985
                points = []
986
                for point in self.actionVendor.tag._polyline._vertices:
987
                    points.append(QPoint(round(point[0]), round(point[1])))
988
                polygon = QPolygonF(points)
989
                item = QEngineeringVendorItem(polygon, pack_type=self.packageComboBox.currentText())
990
                item.area = 'Drawing'
991
                item.transfer.onRemoved.connect(self.itemRemoved)
992
                self.graphicsView.scene().addItem(item)
993
        finally:
994
            self.graphicsView.scene().removeItem(self.actionVendor.tag._polyline)
995
            self.actionVendor.tag.reset()
996

    
997
    '''
998
        @brief      Fit Window
999
        @author     Jeongwoo
1000
        @date       2018.06.27
1001
        @history    2018.06.27  Jeongwoo    Chnage method to initialize command [Set None → DefaultCommand]
1002
    '''
1003

    
1004
    def fitWindow(self, action):
1005
        self.graphicsView.useDefaultCommand()
1006
        self.graphicsView.zoomImageInit()
1007

    
1008
    def scene_changed(self):
1009
        """update modified flag"""
1010

    
1011
        self.display_number_of_items()
1012

    
1013
        app_doc_data = AppDocData.instance()
1014
        app_doc_data.activeDrawing.modified = True
1015
        title = self.windowTitle()
1016
        self.setWindowTitle(title if title[-1] == '*' else title + '*')
1017

    
1018
    def onConvertPDFToImage(self):
1019
        """convert to selected pdf to image"""
1020
        import os
1021

    
1022
        try:
1023
            file_path = os.path.join(os.path.dirname(os.path.realpath(__file__)), 'bin64', 'PDF_TO_IMAGE.exe')
1024
            os.startfile(file_path)
1025
        except Exception as ex:
1026
            message = 'error occurred({}) in {}:{}'.format(ex, sys.exc_info()[-1].tb_frame.f_code.co_filename,
1027
                                                           sys.exc_info()[-1].tb_lineno)
1028
            self.addMessage.emit(MessageType.Error, message)
1029

    
1030
    def onImportTextFromCAD(self):
1031
        """ import text from cad """
1032
        try:
1033
            self.onCommandRejected()
1034
            dialog = QImportTextFromCADDialog(self)
1035
            dialog.show()
1036
            dialog.exec_()
1037
        except Exception as ex:
1038
            message = 'error occurred({}) in {}:{}'.format(ex, sys.exc_info()[-1].tb_frame.f_code.co_filename,
1039
                                                           sys.exc_info()[-1].tb_lineno)
1040
            self.addMessage.emit(MessageType.Error, message)
1041

    
1042
    def onSymbolThickness(self):
1043
        """ symbol thickness reinforcement by using configuration filter drawing dilate size """
1044
        try:
1045
            self.onCommandRejected()
1046
            dialog = QSymbolThicknessDialog(self)
1047
            dialog.exec_()
1048
        except Exception as ex:
1049
            message = 'error occurred({}) in {}:{}'.format(ex, sys.exc_info()[-1].tb_frame.f_code.co_filename,
1050
                                                           sys.exc_info()[-1].tb_lineno)
1051
            self.addMessage.emit(MessageType.Error, message)
1052

    
1053
    def on_help(self):
1054
        """ open help file """
1055
        import os
1056

    
1057
        try:
1058
            help_file_path = os.path.join(os.path.dirname(os.path.realpath(__file__)), 'ID2 User Manual.pdf')
1059
            os.system('"{}"'.format(help_file_path))
1060
        except Exception as ex:
1061
            message = 'error occurred({}) in {}:{}'.format(ex, sys.exc_info()[-1].tb_frame.f_code.co_filename,
1062
                                                           sys.exc_info()[-1].tb_lineno)
1063
            self.addMessage.emit(MessageType.Error, message)
1064

    
1065
    def onSelectionChanged(self):
1066
        """selection changed"""
1067
        items = [item for item in self.graphicsView.scene().selectedItems() if issubclass(type(item), SymbolSvgItem) or
1068
                 type(item) is QEngineeringLineItem or issubclass(type(item), QEngineeringTextItem) or
1069
                 type(item) is QEngineeringUnknownItem or type(item) is QEngineeringVendorItem]
1070
        if items:
1071
            lineNos = [item for item in items if type(item) is QEngineeringLineNoTextItem]
1072
            item = items[-1] if not lineNos else lineNos[0]
1073
            self.itemTreeWidget.findItem(item)
1074
            self.resultPropertyTableWidget.show_item_property(item)
1075
            if type(item) is QEngineeringErrorItem:
1076
                for index in range(self.tableWidgetInconsistency.rowCount()):
1077
                    if self.tableWidgetInconsistency.item(index, 1).tag is item:
1078
                        self.tableWidgetInconsistency.selectRow(index)
1079
                        break
1080
            if issubclass(type(item), SymbolSvgItem):
1081
                pass
1082
                #self.symbolTreeWidget.select_symbol(item)
1083
        else:
1084
            self.resultPropertyTableWidget.show_item_property(None)
1085

    
1086
    '''
1087
        @brief      Initialize scene and itemTreeWidget
1088
        @author     Jeongwoo
1089
        @date       2018.06.14
1090
        @history    humkyung 2018.08.16 ask to delete recognized items before remove
1091
    '''
1092

    
1093
    def on_initialize_scene(self, action):
1094
        if not self.graphicsView.hasImage():
1095
            self.showImageSelectionMessageBox()
1096

    
1097
            return
1098

    
1099
        try:
1100
            msg = QMessageBox()
1101
            msg.setIcon(QMessageBox.Critical)
1102
            msg.setText(self.tr('Do you want to remove all items?\nThis work cannot be recovered.'))
1103
            msg.setWindowTitle(self.tr("Initialize"))
1104
            msg.setStandardButtons(QMessageBox.Ok | QMessageBox.Cancel)
1105
            if QMessageBox.Ok == msg.exec_():
1106
                app_doc_data = AppDocData.instance()
1107
                app_doc_data.clearItemList(True)
1108

    
1109
                scene = self.graphicsView.scene()
1110
                pixmap = self.graphicsView.getPixmapHandle()
1111
                scene.removeItem(pixmap)    # disconnect pixmap from scene
1112
                scene.clear()               # remove all items from scene and then delete them
1113
                scene.addItem(pixmap)       # add pixmap
1114

    
1115
                if self.path is not None:
1116
                    baseName = os.path.basename(self.path)
1117
                    self.itemTreeWidget.setCurrentPID(baseName)
1118

    
1119
        except Exception as ex:
1120
            message = 'error occurred({}) in {}:{}'.format(ex, sys.exc_info()[-1].tb_frame.f_code.co_filename,
1121
                                                           sys.exc_info()[-1].tb_lineno)
1122
            self.addMessage.emit(MessageType.Error, message)
1123

    
1124
    '''
1125
        @brief      Manage Checkable Action statement
1126
        @author     Jeongwoo
1127
        @date       2018.05.10
1128
        @history    2018.06.27  Jeongwoo    Chnage method to initialize command [Set None → DefaultCommand]
1129
    '''
1130

    
1131
    def actionGroupTriggered(self, action):
1132
        if hasattr(self.actionLine, 'tag'):
1133
            self.actionLine.tag.onRejected.emit(None)
1134

    
1135
        if hasattr(self.actionVendor, 'tag'):
1136
            self.actionVendor.tag.onRejected.emit(None)
1137

    
1138
        if self.graphicsView.command is not None:
1139
            self.graphicsView.useDefaultCommand()
1140

    
1141
        for _action in self.actionGroup.actions():
1142
            _action.setChecked(False)
1143

    
1144
        action.setChecked(True)
1145

    
1146
    '''
1147
        @brief      Create Equipment
1148
        @author     Jeongwoo
1149
        @date       18.05.03
1150
        @history    2018.05.04  Jeongwoo    Add Parameter on CreateSymbolCommand
1151
    '''
1152

    
1153
    def createEquipment(self):
1154
        if not self.graphicsView.hasImage():
1155
            self.actionEquipment.setChecked(False)
1156
            self.showImageSelectionMessageBox()
1157
            return
1158
        if self.actionEquipment.isChecked():
1159
            self.graphicsView.command = CreateSymbolCommand.CreateSymbolCommand(self.graphicsView, self.itemTreeWidget,
1160
                                                                                self.symbolTreeWidget)
1161
        else:
1162
            self.graphicsView.useDefaultCommand()
1163

    
1164
    '''
1165
        @brief      Create Nozzle
1166
        @author     Jeongwoo
1167
        @date       2018.05.03
1168
        @history    2018.05.04  Jeongwoo    Add Parameter on CreateSymbolCommand
1169
    '''
1170

    
1171
    def createNozzle(self):
1172
        if not self.graphicsView.hasImage():
1173
            self.actionNozzle.setChecked(False)
1174
            self.showImageSelectionMessageBox()
1175
            return
1176
        if self.actionNozzle.isChecked():
1177
            self.graphicsView.command = CreateSymbolCommand.CreateSymbolCommand(self.graphicsView, self.itemTreeWidget,
1178
                                                                                self.symbolTreeWidget)
1179
        else:
1180
            self.graphicsView.useDefaultCommand()
1181

    
1182
    '''
1183
        @brief      Area OCR
1184
        @author     Jeongwoo
1185
        @date       18.04.18
1186
        @history    2018.05.02  Jeongwoo    Change graphicsView.command by actionOCR checked state
1187
                                            Show MessageBox when imageviewer doesn't have image
1188
    '''
1189

    
1190
    def onAreaOcr(self):
1191
        if not self.graphicsView.hasImage():
1192
            self.actionOCR.setChecked(False)
1193
            self.showImageSelectionMessageBox()
1194
            return
1195

    
1196
        if self.actionOCR.isChecked():
1197
            cmd = AreaOcrCommand.AreaOcrCommand(self.graphicsView)
1198
            cmd.onSuccess.connect(self.onRecognizeText)
1199
            cmd.onRejected.connect(self.onCommandRejected)
1200
            self.graphicsView.command = cmd
1201
        else:
1202
            self.graphicsView.useDefaultCommand()
1203

    
1204
    '''
1205
        @brief      show text recognition dialog
1206
        @author     humkyung
1207
        @date       2018.08.08
1208
    '''
1209

    
1210
    def onRecognizeText(self, x, y, width, height):
1211
        from OcrResultDialog import QOcrResultDialog
1212
        from Area import Area
1213

    
1214
        try:
1215
            app_doc_data = AppDocData.instance()
1216

    
1217
            modifiers = QApplication.keyboardModifiers()
1218
            image = self.graphicsView.image().copy(x, y, width, height)
1219
            dialog = QOcrResultDialog(self, image, QRectF(x, y, width, height),
1220
                                      format=QOcrResultDialog.Format.Table if modifiers == Qt.AltModifier else QOcrResultDialog.Format.Normal)
1221
            if modifiers == Qt.ControlModifier:
1222
                return
1223
            (res, textInfoList) = dialog.showDialog()
1224
            if QDialog.Accepted == res and textInfoList:
1225
                for textInfo in textInfoList:
1226
                    item = QEngineeringTextItem.create_text_with(self.graphicsView.scene(), textInfo)
1227
                    if item:
1228
                        item.setDefaultTextColor(Qt.blue)
1229
                        item.transfer.onRemoved.connect(self.itemRemoved)
1230

    
1231
                        area_list = app_doc_data.getAreaList()
1232
                        title_area_list = app_doc_data.getTitleBlockProperties()
1233
                        title_list = []
1234
                        if title_area_list:
1235
                            for title_area in title_area_list:
1236
                                area = Area(title_area[0])
1237
                                area.parse(title_area[2])
1238
                                title_list.append(area)
1239
                        for area in area_list + title_list:
1240
                            pt = [item.sceneBoundingRect().center().x(), item.sceneBoundingRect().center().y()]
1241
                            if area.contains(pt):
1242
                                item.area = area.name
1243
                                break
1244
                    else:
1245
                        self.addMessage.emit(MessageType.Normal, self.tr('Fail to create text.'))
1246
            elif QDialog.Accepted == res and not textInfoList:
1247
                QMessageBox.about(self.graphicsView, self.tr("Notice"), self.tr("Fail to recognize text"))
1248
        except Exception as ex:
1249
            message = 'error occurred({}) in {}:{}'.format(ex, sys.exc_info()[-1].tb_frame.f_code.co_filename,
1250
                                                           sys.exc_info()[-1].tb_lineno)
1251
            self.addMessage.emit(MessageType.Error, message)
1252

    
1253
    '''
1254
        @brief  area configuration
1255
    '''
1256

    
1257
    def areaConfiguration(self):
1258
        from ConfigurationAreaDialog import QConfigurationAreaDialog
1259
        if not self.graphicsView.hasImage():
1260
            self.showImageSelectionMessageBox()
1261
            return
1262
        self.onCommandRejected()
1263
        self.dlgConfigurationArea = QConfigurationAreaDialog(self)
1264
        self.dlgConfigurationArea.show()
1265
        self.dlgConfigurationArea.exec_()
1266

    
1267
    '''
1268
        @brief  configuration
1269
    '''
1270

    
1271
    def configuration(self):
1272
        from ConfigurationDialog import QConfigurationDialog
1273

    
1274
        self.dlgConfiguration = QConfigurationDialog(self)
1275
        # self.dlgConfiguration.show()
1276
        if QDialog.Accepted == self.dlgConfiguration.exec_():
1277
            QEngineeringLineItem.LINE_TYPE_COLORS.clear()
1278
            QEngineeringInstrumentItem.INST_COLOR = None
1279

    
1280
    '''
1281
        @brief  show special item types dialog 
1282
        @author humkyung
1283
        @date   2019.08.10
1284
    '''
1285

    
1286
    def on_show_special_item_types(self):
1287
        from SpecialItemTypesDialog import QSpecialItemTypesDialog
1288

    
1289
        dlg = QSpecialItemTypesDialog(self)
1290
        dlg.exec_()
1291

    
1292
    def on_show_data_transfer(self):
1293
        """ show data transfer dialog """
1294
        from DataTransferDialog import QDataTransferDialog
1295

    
1296
        dlg = QDataTransferDialog(self)
1297
        dlg.exec_()
1298

    
1299
    def on_show_data_export(self):
1300
        """ show data export dialog """
1301
        from DataExportDialog import QDataExportDialog
1302

    
1303
        dlg = QDataExportDialog(self)
1304
        dlg.exec_()
1305

    
1306
    def on_show_eqp_datasheet_export(self):
1307
        """ show eqp datasheet export dialog """
1308
        from EqpDatasheetExportDialog import QEqpDatasheetExportDialog
1309

    
1310
        dlg = QEqpDatasheetExportDialog(self)
1311
        dlg.exec_()
1312

    
1313
    def on_show_opc_relation(self):
1314
        """ show opc relation dialog """
1315
        from OPCRelationDialog import QOPCRelationDialog
1316

    
1317
        dlg = QOPCRelationDialog(self)
1318
        dlg.exec_()
1319

    
1320
    '''
1321
        @brief  show nominal diameter dialog 
1322
        @author humkyung
1323
        @date   2018.06.28
1324
    '''
1325

    
1326
    def onShowCodeTable(self):
1327
        from CodeTableDialog import QCodeTableDialog
1328

    
1329
        dlg = QCodeTableDialog(self)
1330
        dlg.show()
1331
        dlg.exec_()
1332
        if dlg.code_area:
1333
            if dlg.code_area.scene():
1334
                self.graphicsView.scene().removeItem(dlg.code_area)
1335
        if dlg.desc_area:
1336
            if dlg.desc_area.scene():
1337
                self.graphicsView.scene().removeItem(dlg.desc_area)
1338
        self.graphicsView.useDefaultCommand()
1339

    
1340
    def onShowCustomCodeTable(self):
1341
        from CustomCodeTablesDialog import CustomCodeTablesDialog
1342

    
1343
        dlg = CustomCodeTablesDialog(self)
1344
        dlg.show()
1345
        dlg.exec_()
1346
        self.graphicsView.useDefaultCommand()
1347

    
1348
    '''
1349
        @brief  show HMB data
1350
        @author humkyung
1351
        @date   2018.07.11
1352
    '''
1353

    
1354
    def onHMBData(self):
1355
        from HMBDialog import QHMBDialog
1356

    
1357
        dlg = QHMBDialog(self)
1358
        dlg.show()
1359
        dlg.exec_()
1360

    
1361
    '''
1362
        @brief  show line data list 
1363
        @author humkyung
1364
        @date   2018.05.03
1365
    '''
1366

    
1367
    def showItemDataList(self):
1368
        from ItemDataExportDialog import QItemDataExportDialog
1369

    
1370
        dlg = QItemDataExportDialog(self)
1371
        dlg.exec_()
1372

    
1373
    def showTextDataList(self):
1374
        '''
1375
            @brief      show all text item in scene
1376
            @author     euisung
1377
            @date       2019.04.18
1378
        '''
1379
        try:
1380
            if not self.graphicsView.hasImage():
1381
                self.showImageSelectionMessageBox()
1382
                return
1383

    
1384
            self.onCommandRejected()
1385
            dialog = QTextDataListDialog(self)
1386
            dialog.show()
1387
        except Exception as ex:
1388
            message = 'error occurred({}) in {}:{}'.format(ex, sys.exc_info()[-1].tb_frame.f_code.co_filename,
1389
                                                           sys.exc_info()[-1].tb_lineno)
1390
            self.addMessage.emit(MessageType.Error, message)
1391

    
1392
    '''
1393
        @brief  Show Image Selection Guide MessageBox
1394
        @author Jeongwoo
1395
        @date   2018.05.02
1396
    '''
1397

    
1398
    def showImageSelectionMessageBox(self):
1399
        QMessageBox.about(self.graphicsView, self.tr("Notice"), self.tr("First select image drawing"))
1400

    
1401
    '''
1402
        @brief  change selected lines' type by selected line type
1403
        @author humkyung
1404
        @date   2018.06.27
1405
    '''
1406

    
1407
    def onLineTypeChanged(self, param):
1408
        lineType = self.lineComboBox.itemText(param)
1409
        selected = [item for item in self.graphicsView.scene().selectedItems() if type(item) is QEngineeringLineItem]
1410
        if selected:
1411
            for item in selected:
1412
                item.lineType = lineType
1413

    
1414
    def display_colors(self, value):
1415
        """ display colors """
1416
        from DisplayColors import DisplayColors
1417
        from DisplayColors import DisplayOptions
1418

    
1419
        DisplayColors.instance().option = DisplayOptions.DisplayByLineNo if value is True else DisplayOptions.DisplayByLineType
1420
        if hasattr(self, 'graphicsView'):
1421
            self.graphicsView.scene().update(self.graphicsView.sceneRect())
1422
            DisplayColors.instance().save_data()
1423

    
1424
    def open_image_drawing(self, drawing, force=False):
1425
        """open and display image drawing file"""
1426
        from Drawing import Drawing
1427
        from App import App
1428
        from LoadCommand import LoadCommand
1429
        import concurrent.futures as futures
1430

    
1431
        # Yield successive n-sized
1432
        # chunks from l.
1433
        def divide_chunks(l, n):
1434
            # looping till length l
1435
            for i in range(0, len(l), n):
1436
                yield l[i:i + n]
1437

    
1438
        def update_items(items):
1439
            for item in items:
1440
                # binding items
1441
                item.owner
1442
                for connector in item.connectors:
1443
                    connector.connectedItem
1444

    
1445
            return items
1446

    
1447
        try:
1448
            app_doc_data = AppDocData.instance()
1449

    
1450
            if not self.actionSave.isEnabled():
1451
                return
1452

    
1453
            if not force and self.save_drawing_if_necessary():
1454
                return
1455

    
1456
            occupied = app_doc_data.set_occupying_drawing(drawing.UID)
1457
            if occupied:
1458
                QMessageBox.about(self.graphicsView, self.tr("Notice"),
1459
                                  self.tr(f"The drawing is locked for editing by another user({occupied})"))
1460
                return
1461

    
1462
            # save alarm
1463
            self.save_alarm_enable(False)
1464

    
1465
            if hasattr(self, '_save_work_cmd'):
1466
                self._save_work_cmd.wait()
1467

    
1468
            project = app_doc_data.getCurrentProject()
1469

    
1470
            self.path = self.graphicsView.loadImageFromFile(drawing)
1471
            if os.path.isfile(self.path):
1472
                self.onCommandRejected()
1473
                app_doc_data.clear()
1474

    
1475
                app_doc_data.setImgFilePath(self.path)
1476
                app_doc_data.activeDrawing = drawing
1477
                
1478
                #app_doc_data.activeDrawing.set_pid_source(Image.open(self.path))
1479
                self.itemTreeWidget.setCurrentPID(app_doc_data.activeDrawing.name)
1480

    
1481
                drawingList = self.treeWidgetDrawingList.topLevelItem(0)
1482
                for idx in range(drawingList.childCount()):
1483
                    child = drawingList.child(idx)
1484
                    if child.data(Qt.UserRole, 0) is drawing:
1485
                        child.setCheckState(0, Qt.Checked)
1486
                    else:
1487
                        child.setCheckState(0, Qt.Unchecked)
1488

    
1489
                try:
1490
                    self.show_Progress_bar()
1491

    
1492
                    # disconnect scene changed if signal is connected
1493
                    if self.graphicsView.scene().receivers(self.graphicsView.scene().contents_changed) > 0:
1494
                        self.graphicsView.scene().contents_changed.disconnect()
1495

    
1496
                    SymbolSvgItem.DOCUMENTS.clear()
1497

    
1498
                    # load data
1499
                    cmd = LoadCommand()
1500
                    cmd.display_message.connect(self.onAddMessage)
1501
                    cmd.set_maximum.connect(self.progress.setMaximum)
1502
                    cmd.show_progress.connect(self.progress.setValue)
1503
                    cmd.execute((drawing, self.graphicsView.scene()),
1504
                                symbol=True, text=True, line=True, unknown=True, package=True, update=True)
1505
                    # up to here
1506

    
1507
                    """"update item tree widget"""
1508
                    line_no_items = [item for item in self.graphicsView.scene().items()
1509
                                     if type(item) is QEngineeringLineNoTextItem]
1510
                    for line_no in line_no_items:
1511
                        line_no_tree_item = self.itemTreeWidget.addTreeItem(self.itemTreeWidget.root, line_no)
1512
                        for run in line_no.runs:
1513
                            for run_item in run.items:
1514
                                if issubclass(type(run_item), SymbolSvgItem):
1515
                                    self.init_add_tree_item(line_no_tree_item, run_item)
1516

    
1517
                    line_no_items = [item for item in self.graphicsView.scene().items()
1518
                                     if type(item) is QEngineeringTrimLineNoTextItem]
1519
                    for line_no in line_no_items:
1520
                        line_no_tree_item = self.itemTreeWidget.addTreeItem(self.itemTreeWidget.root, line_no)
1521
                        for run in line_no.runs:
1522
                            for run_item in run.items:
1523
                                if issubclass(type(run_item), SymbolSvgItem):
1524
                                    self.init_add_tree_item(line_no_tree_item, run_item)
1525

    
1526
                    for trim_line_no in app_doc_data.tracerLineNos:
1527
                        line_no_tree_item = self.itemTreeWidget.addTreeItem(self.itemTreeWidget.root, trim_line_no)
1528
                        for run in trim_line_no.runs:
1529
                            for run_item in run.items:
1530
                                if issubclass(type(run_item), SymbolSvgItem):
1531
                                    self.init_add_tree_item(line_no_tree_item, run_item)
1532

    
1533
                    self.itemTreeWidget.update_item_count()
1534
                    self.itemTreeWidget.expandAll()
1535
                    """up to here"""
1536

    
1537
                    """update scene"""
1538
                    for item in self._scene.items():
1539
                        item.setVisible(True)
1540

    
1541
                    self._scene.update(self._scene.sceneRect())
1542

    
1543
                    """
1544
                    # old open drawing
1545
                    path = os.path.join(app_doc_data.getCurrentProject().getTempPath(), app_doc_data.imgName + '.xml')
1546
                    configs = app_doc_data.getConfigs('Data Load', 'Xml First')
1547
                    if configs and int(configs[0].value) >= 1 and os.path.isfile(path):
1548
                        self.load_recognition_result_from_xml(drawing)
1549
                    elif configs and int(configs[0].value) <= 1:
1550
                        self.load_drawing(app_doc_data.activeDrawing)
1551
                    """
1552

    
1553
                    self.display_number_of_items()
1554
                    # connect scene changed signal
1555
                    self.graphicsView.scene().contents_changed.connect(self.scene_changed)
1556
                finally:
1557
                    if hasattr(self, 'progress'):
1558
                        self.progress.setValue(self.progress.maximum())
1559

    
1560
                self.changeViewCheckedState(True)
1561
                self.setWindowTitle(self.title)
1562

    
1563
                # save alarm
1564
                self.save_alarm_enable(True, True)
1565
        except Exception as ex:
1566
            message = 'error occurred({}) in {}:{}'.format(ex, sys.exc_info()[-1].tb_frame.f_code.co_filename,
1567
                                                           sys.exc_info()[-1].tb_lineno)
1568
            self.addMessage.emit(MessageType.Error, message)
1569

    
1570
        return self.path
1571

    
1572
    def save_alarm_enable(self, enable, init=False):
1573
        from datetime import datetime
1574

    
1575
        app_doc_data = AppDocData.instance()
1576
        configs = app_doc_data.getConfigs('Data Save', 'Time')
1577
        time_min = int(configs[0].value) if 1 == len(configs) else 0
1578

    
1579
        if enable and time_min > 0:
1580
            if not self.save_timer:
1581
                self.save_timer = QTimer()
1582
                self.save_timer.timeout.connect(self.save_alarm)
1583
                self.save_timer.setInterval(60000)
1584

    
1585
            if init:
1586
                self.save_timer._init_time = datetime.now()
1587
                self.save_timer._stop_time = None
1588
                self.save_timer._interval_time = datetime.now() - datetime.now()
1589

    
1590
            if self.save_timer._stop_time:
1591
                self.save_timer._interval_time = datetime.now() - self.save_timer._stop_time
1592
            
1593
            #if 60000 * time_min != self.save_timer.interval():
1594
            #    self.save_timer.setInterval(60000)
1595

    
1596
            self.save_timer.start()
1597
        else:
1598
            if self.save_timer:
1599
                self.save_timer.stop()
1600
                self.save_timer._stop_time = datetime.now()
1601

    
1602
    def save_alarm(self):
1603
        from datetime import datetime
1604

    
1605
        app_doc_data = AppDocData.instance()
1606
        configs = app_doc_data.getConfigs('Data Save', 'Time')
1607
        time_min = int(configs[0].value) if 1 == len(configs) else 0
1608

    
1609
        self.save_timer.stop()
1610
        if self.graphicsView.hasFocus() and (datetime.now() - self.save_timer._init_time - self.save_timer._interval_time).seconds > time_min * 60:
1611
            QMessageBox.information(self, self.tr('Information'), self.tr('Please save Drawing'))
1612
            self.save_timer._init_time = datetime.now()
1613
            self.save_timer._interval_time = datetime.now() - datetime.now()
1614
        self.save_timer.start()
1615

    
1616
    def export_as_svg(self):
1617
        """export scene to svg file"""
1618
        from ExportCommand import ExportCommand
1619

    
1620
        options = QFileDialog.Options()
1621
        options |= QFileDialog.DontUseNativeDialog
1622
        file_path, _ = QFileDialog.getSaveFileName(self, "Export as svg", os.getcwd(), "svg file(*.svg)",
1623
                                                   options=options)
1624
        if file_path:
1625
            cmd = ExportCommand(self.graphicsView.scene(), 'svg')
1626
            cmd.display_message.connect(self.onAddMessage)
1627
            if cmd.execute(file_path):
1628
                QMessageBox.information(self, self.tr('Information'), self.tr('Successfully export to svg file'))
1629
            else:
1630
                QMessageBox.information(self, self.tr('Error'), self.tr('Fail to export to svg file'))
1631

    
1632
    def export_as_xml(self):
1633
        pass
1634

    
1635
    def export_as_image(self):
1636
        """export scene to image file"""
1637
        from ExportCommand import ExportCommand
1638

    
1639
        options = QFileDialog.Options()
1640
        options |= QFileDialog.DontUseNativeDialog
1641
        file_path, _ = QFileDialog.getSaveFileName(self, "Export as png", os.getcwd(), "png file(*.png)",
1642
                                                   options=options)
1643
        if file_path:
1644
            try:
1645
                # hide image drawing
1646
                self.onViewImageDrawing(False)
1647

    
1648
                cmd = ExportCommand(self.graphicsView.scene(), 'image')
1649
                cmd.display_message.connect(self.onAddMessage)
1650

    
1651
                if cmd.execute(file_path):
1652
                    QMessageBox.information(self, self.tr('Information'), self.tr('Successfully export to image file'))
1653
                else:
1654
                    QMessageBox.information(self, self.tr('Error'), self.tr('Fail to export to image file'))
1655
            finally:
1656
                if self.actionImage_Drawing.isChecked():
1657
                    self.onViewImageDrawing(True)
1658
                    self.actionImage_Drawing.setChecked(True)
1659

    
1660
    def show_Progress_bar(self):
1661
        """ show progress bar """
1662
        self.progress = QProgressDialog(self.tr("Please wait for a while"), self.tr("Cancel"), 0, 100,
1663
                                        self) if not hasattr(self, 'progress') else self.progress
1664
        self.progress.setWindowModality(Qt.WindowModal)
1665
        self.progress.setAutoReset(True)
1666
        self.progress.setAutoClose(True)
1667
        self.progress.setMinimum(0)
1668
        self.progress.setMaximum(100)
1669
        self.progress.resize(600, 100)
1670
        self.progress.setWindowTitle(self.tr("Reading file..."))
1671
        self.progress.show()
1672

    
1673
    def changeViewCheckedState(self, checked, clear=True):
1674
        '''
1675
            @brief      change view checked state
1676
            @author     euisung
1677
            @date       2019.03.06
1678
        '''
1679
        # self.actionImage_Drawing.setChecked(checked)
1680
        self.actionViewText.setChecked(checked)
1681
        self.actionViewSymbol.setChecked(checked)
1682
        self.actionViewLine.setChecked(checked)
1683
        self.actionViewUnknown.setChecked(checked)
1684
        self.actionViewInconsistency.setChecked(checked)
1685
        self.actionViewVendor_Area.setChecked(not checked)
1686
        self.actionDrawing_Only.setChecked(not checked)
1687
        if clear:
1688
            self.tableWidgetInconsistency.clearContents()
1689
            self.tableWidgetInconsistency.setRowCount(0)
1690

    
1691
    def onViewDrawingOnly(self, isChecked):
1692
        '''
1693
            @brief  visible/invisible except image drawing
1694
            @author euisung
1695
            @date   2019.04.22
1696
        '''
1697
        self.changeViewCheckedState(not isChecked, False)
1698
        for item in self.graphicsView.scene().items():
1699
            if type(item) is not QGraphicsPixmapItem:
1700
                item.setVisible(not isChecked)
1701

    
1702
    '''
1703
        @brief  visible/invisible image drawing
1704
        @author humkyung
1705
        @date   2018.06.25
1706
    '''
1707

    
1708
    def onViewImageDrawing(self, isChecked):
1709
        for item in self.graphicsView.scene().items():
1710
            if type(item) is QGraphicsPixmapItem:
1711
                item.setVisible(isChecked)
1712
                break
1713

    
1714
    def onViewText(self, checked):
1715
        """visible/invisible text"""
1716
        selected = [item for item in self.graphicsView.scene().items() if issubclass(type(item), QEngineeringTextItem)
1717
                    and type(item) is not QEngineeringLineNoTextItem]
1718
        for item in selected:
1719
            item.setVisible(checked)
1720

    
1721
    def onViewSymbol(self, checked):
1722
        """visible/invisible symbol"""
1723
        selected = [item for item in self.graphicsView.scene().items() if
1724
                    (issubclass(type(item), SymbolSvgItem) and type(item) is not QEngineeringErrorItem)]
1725
        for item in selected:
1726
            item.setVisible(checked)
1727

    
1728
    def onViewLine(self, checked):
1729
        """visible/invisible line"""
1730
        selected = [item for item in self.graphicsView.scene().items() if type(item) is QEngineeringLineItem]
1731
        for item in selected:
1732
            item.setVisible(checked)
1733

    
1734
    def onViewInconsistency(self, isChecked):
1735
        '''
1736
            @brief  visible/invisible Inconsistency
1737
            @author euisung
1738
            @date   2019.04.03
1739
        '''
1740
        selected = [item for item in self.graphicsView.scene().items() if type(item) is QEngineeringErrorItem]
1741
        for item in selected:
1742
            item.setVisible(isChecked)
1743

    
1744
    '''
1745
        @brief  visible/invisible Unknown 
1746
        @author humkyung
1747
        @date   2018.06.28
1748
    '''
1749

    
1750
    def onViewUnknown(self, isChecked):
1751
        selected = [item for item in self.graphicsView.scene().items() if type(item) is QEngineeringUnknownItem]
1752
        for item in selected:
1753
            item.setVisible(isChecked)
1754

    
1755
    def onViewVendorArea(self, isChecked):
1756
        '''
1757
            @brief  visible/invisible Vendor Area
1758
            @author euisung
1759
            @date   2019.04.29
1760
        '''
1761
        selected = [item for item in self.graphicsView.scene().items() if type(item) is QEngineeringVendorItem]
1762
        for item in selected:
1763
            item.setVisible(isChecked)
1764

    
1765
    '''
1766
        @brief  create a symbol
1767
        @history    2018.05.02  Jeongwoo    Change return value of QSymbolEditorDialog (Single variable → Tuple)
1768
                                            Add SymbolSvgItem
1769
                    2018.05.03  Jeongwoo    Change method to draw Svg Item on Scene (svg.addSvgItemToScene)
1770
                                            Change method to make svg and image path
1771
                    2018.06.08  Jeongwoo    Add Paramter on SymbolSvgItem.buildItem()
1772
    '''
1773

    
1774
    def onCreateSymbolClicked(self):
1775
        cmd = FenceCommand.FenceCommand(self.graphicsView)
1776
        cmd.onSuccess.connect(self.onAreaSelected)
1777
        self.graphicsView.command = cmd
1778
        QApplication.setOverrideCursor(Qt.CrossCursor)
1779

    
1780
    '''
1781
        @brief      show SymbolEditorDialog with image selected by user
1782
        @author     humkyung
1783
        @date       2018.07.20
1784
    '''
1785

    
1786
    def onAreaSelected(self, x, y, width, height):
1787
        try:
1788
            image = self.graphicsView.image()
1789
            if image is not None:
1790
                symbolEditorDialog = SymbolEditorDialog.QSymbolEditorDialog(self, image.copy(x, y, width, height),
1791
                                                                            AppDocData.instance().getCurrentProject())
1792
                (isAccepted, isImmediateInsert, offsetX, offsetY, newSym) = symbolEditorDialog.showDialog()
1793
                self.symbolTreeWidget.initDirTreeWidget()
1794
                if isAccepted:
1795
                    if isImmediateInsert:
1796
                        svgPath = newSym.getSvgFileFullPath()
1797
                        img = cv2.imread(newSym.getImageFileFullPath(), 1)
1798
                        w, h = (0, 0)
1799
                        if len(img.shape[::-1]) == 2:
1800
                            w, h = img.shape[::-1]
1801
                        else:
1802
                            _chan, w, h = img.shape[::-1]
1803
                        svg = SymbolSvgItem(svgPath)
1804
                        svg.buildItem(newSym.getName(), newSym.getType(), 0, [offsetX, offsetY], [w, h],
1805
                                      [float(x) for x in newSym.getOriginalPoint().split(',')],
1806
                                      [(float(x.split(',')[0]), float(x.split(',')[1])) for x in
1807
                                       newSym.getConnectionPoint().split('/')], newSym.getBaseSymbol(),
1808
                                      newSym.getAdditionalSymbol(), newSym.getHasInstrumentLabel)
1809

    
1810
                        svg.transfer.onRemoved.connect(self.itemTreeWidget.itemRemoved)
1811
                        svg.addSvgItemToScene(self.graphicsView.scene())
1812
                        for connector in svg.connectors:
1813
                            self.graphicsView.scene().addItem(connector)
1814
        finally:
1815
            self.onCommandRejected()
1816
            QApplication.restoreOverrideCursor()
1817

    
1818
    '''
1819
        @brief      create a line
1820
        @author     humkyung
1821
        @history    Jeongwoo 2018.05.10 Change method for Checkable action
1822
    '''
1823

    
1824
    def onPlaceLine(self):
1825
        if not self.graphicsView.hasImage():
1826
            self.actionLine.setChecked(False)
1827
            self.showImageSelectionMessageBox()
1828
            return
1829

    
1830
        self.actionLine.setChecked(True)
1831
        if not hasattr(self.actionLine, 'tag'):
1832
            self.actionLine.tag = PlaceLineCommand.PlaceLineCommand(self.graphicsView)
1833
            self.actionLine.tag.onSuccess.connect(self.onLineCreated)
1834
            self.actionLine.tag.onRejected.connect(self.onCommandRejected)
1835

    
1836
        self.graphicsView.command = self.actionLine.tag
1837

    
1838
    '''
1839
        @brief      add created lines to scene
1840
        @author     humkyung
1841
        @date       2018.07.23
1842
    '''
1843

    
1844
    def onLineCreated(self):
1845
        from EngineeringConnectorItem import QEngineeringConnectorItem
1846
        from LineDetector import LineDetector
1847

    
1848
        try:
1849
            app_doc_data = AppDocData.instance()
1850

    
1851
            count = len(self.actionLine.tag._polyline._vertices)
1852
            if count > 1:
1853
                items = []
1854

    
1855
                detector = LineDetector(None)
1856

    
1857
                if not self.actionLine.tag.line_type:
1858
                    line_type = self.lineComboBox.currentText()
1859
                else:
1860
                    if not (QEngineeringLineItem.check_piping(self.actionLine.tag.line_type) ^ QEngineeringLineItem.check_piping(self.lineComboBox.currentText())):
1861
                        line_type = self.lineComboBox.currentText()
1862
                    else:
1863
                        line_type = self.actionLine.tag.line_type
1864
                for index in range(count - 1):
1865
                    start = self.actionLine.tag._polyline._vertices[index]
1866
                    end = self.actionLine.tag._polyline._vertices[index + 1]
1867

    
1868
                    lineItem = QEngineeringLineItem(vertices=[start, end])
1869
                    lineItem.transfer.onRemoved.connect(self.itemRemoved)
1870
                    lineItem.lineType = line_type
1871
                    if items:
1872
                        lineItem.connect_if_possible(items[-1], 5)
1873
                    else:
1874
                        pt = lineItem.start_point()
1875
                        selected = [item for item in self.graphicsView.scene().items(QPointF(pt[0], pt[1])) if
1876
                                    type(item) is QEngineeringConnectorItem or type(item) is QEngineeringLineItem]
1877
                        if selected and selected[0] is not lineItem:
1878
                            if type(selected[0]) is QEngineeringConnectorItem:
1879
                                lineItem.connect_if_possible(selected[0].parent, 5)
1880
                            else:
1881
                                detector.connectLineToLine(selected[0], lineItem, 5)
1882

    
1883
                    items.append(lineItem)
1884
                    self.graphicsView.scene().addItem(lineItem)
1885
                    #app_doc_data.lines.append(lineItem)
1886

    
1887
                pt = items[-1].end_point()
1888
                selected = [item for item in self.graphicsView.scene().items(QPointF(pt[0], pt[1])) if
1889
                            (type(item) is QEngineeringConnectorItem and item.parentItem() is not items[-1]) or
1890
                            (type(item) is QEngineeringLineItem and item is not items[-1])]
1891
                if selected and selected[0] is not items[-1]:
1892
                    if type(selected[0]) is QEngineeringConnectorItem:
1893
                        items[-1].connect_if_possible(selected[0].parent, 5)
1894
                    else:
1895
                        detector.connectLineToLine(selected[0], items[-1], 5)
1896

    
1897
                self._scene.undo_stack.push(CreateCommand(self._scene, items))
1898
        finally:
1899
            self.graphicsView.scene().removeItem(self.actionLine.tag._polyline)
1900
            self.actionLine.tag.reset()
1901

    
1902
    '''
1903
        @brief      refresh scene
1904
        @author     humkyung
1905
        @date       2018.07.23
1906
    '''
1907

    
1908
    def onCommandRejected(self, cmd=None):
1909
        try:
1910
            if type(cmd) is PlaceLineCommand.PlaceLineCommand:
1911
                if self.actionLine.tag._polyline:
1912
                    self.graphicsView.scene().removeItem(self.actionLine.tag._polyline)
1913
                self.graphicsView.scene().update()
1914
                self.actionLine.tag.reset()
1915

    
1916
                self.actionLine.setChecked(False)
1917
            elif type(cmd) is AreaZoomCommand.AreaZoomCommand:
1918
                self.actionZoom.setChecked(False)
1919
            elif type(cmd) is AreaOcrCommand.AreaOcrCommand:
1920
                self.actionOCR.setChecked(False)
1921
            elif type(cmd) is PlacePolygonCommand.PlacePolygonCommand:
1922
                self.actionVendor.setChecked(False)
1923
            else:
1924
                if hasattr(self.actionLine, 'tag') and self.actionLine.tag._polyline:
1925
                    self.graphicsView.scene().removeItem(self.actionLine.tag._polyline)
1926
                    self.graphicsView.scene().update()
1927
                    self.actionLine.tag.reset()
1928
                if hasattr(self.actionVendor, 'tag') and self.actionVendor.tag._polyline:
1929
                    self.graphicsView.scene().removeItem(self.actionVendor.tag._polyline)
1930
                    self.graphicsView.scene().update()
1931
                    self.actionVendor.tag.reset()
1932
                self.actionLine.setChecked(False)
1933
                self.actionZoom.setChecked(False)
1934
                self.actionOCR.setChecked(False)
1935
                self.actionVendor.setChecked(False)
1936
        finally:
1937
            self.graphicsView.useDefaultCommand()
1938

    
1939
    '''
1940
        @brief      restore to default command when user press Escape key
1941
        @author     humkyung 
1942
        @date       2018.08.09
1943
        
1944
    '''
1945

    
1946
    def keyPressEvent(self, event):
1947
        try:
1948
            if event.key() == Qt.Key_Escape:
1949
                checked = self.actionGroup.checkedAction()
1950
                if checked:
1951
                    checked.setChecked(False)
1952
                    self.graphicsView.useDefaultCommand()
1953
            elif event.key() == Qt.Key_1:
1954
                if self.actionImage_Drawing.isChecked():
1955
                    self.onViewImageDrawing(False)
1956
                    self.actionImage_Drawing.setChecked(False)
1957
                else:
1958
                    self.onViewImageDrawing(True)
1959
                    self.actionImage_Drawing.setChecked(True)
1960
            elif event.key() == Qt.Key_2:
1961
                if self.actionViewText.isChecked():
1962
                    self.onViewText(False)
1963
                    self.actionViewText.setChecked(False)
1964
                else:
1965
                    self.onViewText(True)
1966
                    self.actionViewText.setChecked(True)
1967
            elif event.key() == Qt.Key_3:
1968
                if self.actionViewSymbol.isChecked():
1969
                    self.onViewSymbol(False)
1970
                    self.actionViewSymbol.setChecked(False)
1971
                else:
1972
                    self.onViewSymbol(True)
1973
                    self.actionViewSymbol.setChecked(True)
1974
            elif event.key() == Qt.Key_4:
1975
                if self.actionViewLine.isChecked():
1976
                    self.onViewLine(False)
1977
                    self.actionViewLine.setChecked(False)
1978
                else:
1979
                    self.onViewLine(True)
1980
                    self.actionViewLine.setChecked(True)
1981
            elif event.key() == Qt.Key_5:
1982
                if self.actionViewUnknown.isChecked():
1983
                    self.onViewUnknown(False)
1984
                    self.actionViewUnknown.setChecked(False)
1985
                else:
1986
                    self.onViewUnknown(True)
1987
                    self.actionViewUnknown.setChecked(True)
1988
            elif event.key() == Qt.Key_6:
1989
                if self.actionViewInconsistency.isChecked():
1990
                    self.onViewInconsistency(False)
1991
                    self.actionViewInconsistency.setChecked(False)
1992
                else:
1993
                    self.onViewInconsistency(True)
1994
                    self.actionViewInconsistency.setChecked(True)
1995
            elif event.key() == Qt.Key_7:
1996
                if self.actionViewVendor_Area.isChecked():
1997
                    self.onViewVendorArea(False)
1998
                    self.actionViewVendor_Area.setChecked(False)
1999
                else:
2000
                    self.onViewVendorArea(True)
2001
                    self.actionViewVendor_Area.setChecked(True)
2002
            elif event.key() == 96:  # '`' key
2003
                if self.actionDrawing_Only.isChecked():
2004
                    self.onViewDrawingOnly(False)
2005
                    self.actionDrawing_Only.setChecked(False)
2006
                else:
2007
                    self.onViewDrawingOnly(True)
2008
                    self.actionDrawing_Only.setChecked(True)
2009
            elif event.key() == Qt.Key_M:  # merge text as vertical
2010
                from TextInfo import TextInfo
2011

    
2012
                textItems = [text for text in self.graphicsView.scene().selectedItems() if
2013
                             issubclass(type(text), QEngineeringTextItem)]
2014
                if not textItems or len(textItems) is 1:
2015
                    return
2016

    
2017
                angle = None
2018
                for item in textItems:
2019
                    if angle is None:
2020
                        angle = item.angle
2021
                    else:
2022
                        if angle != item.angle:
2023
                            return
2024

    
2025
                modifiers = QApplication.keyboardModifiers()
2026
                enter_or_space = ' ' if modifiers == Qt.ControlModifier else '\n'
2027
                x_or_y = 0 if modifiers == Qt.ControlModifier else 1
2028

    
2029
                textItems = sorted(textItems, key=lambda text: text.loc[x_or_y]) if textItems[0].angle == 0 else ( \
2030
                    sorted(textItems, key=lambda text: text.loc[x_or_y]) if textItems[0].angle == 1.57 else ( \
2031
                        sorted(textItems, key=lambda text: text.loc[x_or_y], reverse=True) if textItems[0].angle == 4.71 else \
2032
                            sorted(textItems, key=lambda text: text.loc[x_or_y], reverse=True)))
2033

    
2034
                if textItems[0].angle == 1.57 and modifiers == Qt.ControlModifier:
2035
                    textItems.reverse()
2036

    
2037
                minX = sys.maxsize
2038
                minY = sys.maxsize
2039
                maxX = 0
2040
                maxY = 0
2041
                newText = ''
2042

    
2043
                for text in textItems:
2044
                    if text.loc[0] < minX: minX = text.loc[0]
2045
                    if text.loc[1] < minY: minY = text.loc[1]
2046
                    if text.loc[0] + text.size[0] > maxX: maxX = text.loc[0] + text.size[0]
2047
                    if text.loc[1] + text.size[1] > maxY: maxY = text.loc[1] + text.size[1]
2048
                    newText = newText + text.text() + enter_or_space
2049
                    text.transfer.onRemoved.emit(text)
2050
                newText = newText[:-1]
2051

    
2052
                textInfo = TextInfo(newText, minX, minY, maxX - minX, maxY - minY, textItems[0].angle)
2053
                x = textInfo.getX()
2054
                y = textInfo.getY()
2055
                angle = textInfo.getAngle()
2056
                text = textInfo.getText()
2057
                width = textInfo.getW()
2058
                height = textInfo.getH()
2059
                item = TextItemFactory.instance().createTextItem(textInfo)
2060
                if item is not None:
2061
                    item.loc = [x, y]
2062
                    item.size = (width, height)
2063
                    item.angle = angle
2064
                    item.setDefaultTextColor(Qt.blue)
2065
                    item.addTextItemToScene(self.graphicsView.scene())
2066
                    item.transfer.onRemoved.connect(self.itemRemoved)
2067
            elif event.key() == Qt.Key_D:
2068
                # pop up development toolkit dialog
2069
                from DevelopmentToolkitDialog import QDevelopmentToolkitDialog
2070

    
2071
                modifiers = QApplication.keyboardModifiers()
2072
                if modifiers == Qt.ControlModifier:
2073
                    dlg = QDevelopmentToolkitDialog(self, self.graphicsView)
2074
                    dlg.show()
2075
            elif event.key() == Qt.Key_I:
2076
                # insert symbol item that is selected symbol in tree to main window if symbol already selected on main window, replace
2077
                items = self.symbolTreeWidget.selectedItems()
2078
                if items and hasattr(items[0], 'svgFilePath'):
2079
                    symData = items[0].data(0, self.symbolTreeWidget.TREE_DATA_ROLE)
2080
                    symName = symData.getName()
2081
                else:
2082
                    return
2083

    
2084
                symbolItems = [symbol for symbol in self.graphicsView.scene().selectedItems() if
2085
                               issubclass(type(symbol), SymbolSvgItem)]
2086
                old_symbol = None
2087
                if symbolItems and len(symbolItems) is 1:
2088
                    old_symbol = symbolItems[0]
2089
                    #scenePos = QPoint(old_symbol.origin[0], old_symbol.origin[1])
2090
                    scenePos = old_symbol.mapToScene(old_symbol.transformOriginPoint())
2091
                    old_symbol.transfer.onRemoved.emit(old_symbol)
2092
                else:
2093
                    scenePos = self.current_pos
2094

    
2095
                svg = QtImageViewer.createSymbolObject(symName)
2096
                QtImageViewer.matchSymbolToLine(self.graphicsView.scene(), svg, scenePos)
2097

    
2098
                if old_symbol and svg:
2099
                    from ReplaceCommand import ReplaceCommand
2100

    
2101
                    cmd = ReplaceCommand(self.graphicsView.scene(), old_symbol, svg)
2102
                    self._scene.undo_stack.push(cmd)
2103
                    return
2104
            elif event.key() == Qt.Key_J:
2105
                # insert and connect symbol item that is selected symbol in tree to selected symbol
2106
                items = self.symbolTreeWidget.selectedItems()
2107
                if items and hasattr(items[0], 'svgFilePath'):
2108
                    symData = items[0].data(0, self.symbolTreeWidget.TREE_DATA_ROLE)
2109
                    symName = symData.getName()
2110
                else:
2111
                    return
2112

    
2113
                symbolItems = [symbol for symbol in self.graphicsView.scene().selectedItems() if
2114
                               issubclass(type(symbol), SymbolSvgItem)]
2115
                if symbolItems and len(symbolItems) is not 1:
2116
                    return
2117
                    
2118
                target_symbol = symbolItems[0]
2119
                index =  [index for index in range(len(target_symbol.conn_type)) \
2120
                            if target_symbol.conn_type[index] == 'Primary' or target_symbol.conn_type[index] == 'Secondary']
2121
                for connector in target_symbol.connectors:
2122
                    svg = QtImageViewer.createSymbolObject(symName)
2123
                    if len(svg.connectors) > 1: 
2124
                        if ((target_symbol.conn_type and target_symbol.connectors.index(connector) in index) or not target_symbol.conn_type) and \
2125
                                    (not connector.connectedItem or (connector.connectedItem and type(connector.connectedItem) is QEngineeringLineItem)):
2126
                            QtImageViewer.matchSymbolToLine(self.graphicsView.scene(), svg, connector.sceneBoundingRect().center())
2127
                    elif len(svg.connectors) == 1:
2128
                        if ((target_symbol.conn_type and target_symbol.connectors.index(connector) in index) or not target_symbol.conn_type) and \
2129
                                    not connector.connectedItem:
2130
                            QtImageViewer.matchSymbolToLine(self.graphicsView.scene(), svg, connector.sceneBoundingRect().center())
2131

    
2132
                if target_symbol:
2133
                    return
2134
            elif event.key() == Qt.Key_X:
2135
                app_doc_data = AppDocData.instance()
2136
                configs = app_doc_data.getAppConfigs('app', 'mode')
2137
                if configs and 1 == len(configs) and 'advanced' == configs[0].value:
2138
                    advanced = True
2139
                    items = self.graphicsView.scene().selectedItems()
2140
                    if items:
2141
                        item = self.symbolTreeWidget.currentItem()
2142
                        if item:
2143
                            self.symbolTreeWidget.showSymbolEditorDialog(item, 0)
2144

    
2145
            QMainWindow.keyPressEvent(self, event)
2146
        except Exception as ex:
2147
            message = 'error occurred({}) in {}:{}'.format(ex, sys.exc_info()[-1].tb_frame.f_code.co_filename,
2148
                                                           sys.exc_info()[-1].tb_lineno)
2149
            self.addMessage.emit(MessageType.Error, message)
2150

    
2151
    def recognize(self):
2152
        """recognize symbol, text and line for selected drawings"""
2153
        from datetime import datetime
2154
        from RecognitionDialog import QRecognitionDialog
2155

    
2156
        # save alarm
2157
        self.save_alarm_enable(False)
2158

    
2159
        app_doc_data = AppDocData.instance()
2160
        current_drawing, currentPid = None, None
2161

    
2162
        if self.graphicsView.hasImage():
2163
            current_drawing = app_doc_data.activeDrawing
2164
            currentPid = app_doc_data.activeDrawing.name
2165

    
2166
        # get checked drawings
2167
        drawing_top = self.treeWidgetDrawingList.topLevelItem(0)
2168
        count = drawing_top.childCount()
2169
        checked_drawings = {}
2170
        for idx in range(count):
2171
            child = drawing_top.child(idx)
2172
            if child.checkState(0) == Qt.Checked and child.data(Qt.UserRole, 0):
2173
                checked_drawings[child.data(Qt.UserRole, 0)] = child
2174
        # up to here
2175

    
2176
        # if there is no checked drawing
2177
        if current_drawing and currentPid and not checked_drawings:
2178
            for idx in range(count):
2179
                child = drawing_top.child(idx)
2180
                if child.data(Qt.UserRole, 0) is current_drawing:
2181
                    checked_drawings[child.data(Qt.UserRole, 0)] = child
2182

    
2183
        if not checked_drawings:
2184
            self.showImageSelectionMessageBox()
2185
            return
2186

    
2187
        try:
2188
            self.onClearLog()
2189
            dlg = QRecognitionDialog(self, [drawing for drawing in checked_drawings.keys()])
2190
            dlg.exec_()
2191

    
2192
            if current_drawing and current_drawing in checked_drawings.keys() and dlg.isTreated:
2193
                self.open_image_drawing(current_drawing, force=True)
2194

    
2195
            # save working date-time
2196
            _now = datetime.now().strftime('%Y-%m-%d %H:%M:%S')
2197
            for drawing, tree_item in checked_drawings.items():
2198
                drawing.datetime = _now
2199
                tree_item.setText(1, _now)
2200
            #app_doc_data.saveDrawings(checked_drawings.keys())
2201
            self.changeViewCheckedState(True)
2202
            # up to here
2203
        except Exception as ex:
2204
            message = 'error occurred({}) in {}:{}'.format(repr(ex), sys.exc_info()[-1].tb_frame.f_code.co_filename,
2205
                                                           sys.exc_info()[-1].tb_lineno)
2206
            self.addMessage.emit(MessageType.Error, message)
2207

    
2208
        # save alarm
2209
            self.save_alarm_enable(True)
2210

    
2211
    '''
2212
        @brief      remove item from tree widget and then remove from scene
2213
        @date       2018.05.25
2214
        @author     Jeongwoo
2215
    '''
2216

    
2217
    def itemRemoved(self, item):
2218
        try:
2219
            if type(item) is QEngineeringErrorItem:
2220
                # remove error item from inconsistency list
2221
                for row in range(self.tableWidgetInconsistency.rowCount()):
2222
                    if item is self.tableWidgetInconsistency.item(row, 0).tag:
2223
                        self.tableWidgetInconsistency.removeRow(row)
2224
                        break
2225

    
2226
                if item.scene() is not None: item.scene().removeItem(item)
2227
                del item
2228
            else:
2229
                self.itemTreeWidget.itemRemoved(item)
2230

    
2231
                matches = [_item for _item in self.graphicsView.scene().items() if
2232
                           hasattr(_item, 'connectors') and [connector for connector in _item.connectors if
2233
                                                             connector.connectedItem is item]]
2234
                for match in matches:
2235
                    for connector in match.connectors:
2236
                        if connector.connectedItem is item:
2237
                            connector.connectedItem = None
2238
                            connector.highlight(False)
2239

    
2240
                # matches = [_item for _item in self.graphicsView.scene().items() if hasattr(_item, 'remove_assoc_item')]
2241
                # for _item in matches:
2242
                #    _item.remove_assoc_item(item)
2243

    
2244
                app_doc_data = AppDocData.instance()
2245
                if type(item) is QEngineeringLineNoTextItem and item in app_doc_data.tracerLineNos:
2246
                    app_doc_data.tracerLineNos.pop(app_doc_data.tracerLineNos.index(item))
2247

    
2248
                if type(item) is QEngineeringLineItem and item in app_doc_data.lines:
2249
                    app_doc_data.lines.remove(item)
2250

    
2251
                matches = [_item for _item in self.graphicsView.scene().items() if
2252
                           type(_item) is QEngineeringLineNoTextItem]
2253
                matches.extend([lineNo for lineNo in app_doc_data.tracerLineNos if
2254
                                type(lineNo) is QEngineeringTrimLineNoTextItem])
2255
                for match in matches:
2256
                    if item is match.prop('From'):
2257
                        match.set_property('From', None)
2258
                    if item is match.prop('To'):
2259
                        match.set_property('To', None)
2260

    
2261
                    for run_index in reversed(range(len(match.runs))):
2262
                        run = match.runs[run_index]
2263
                        if item in run.items:
2264
                            index = run.items.index(item)
2265
                            run.items.pop(index)
2266
                            if not run.items:
2267
                                run.explode()
2268
                                if type(match) is QEngineeringTrimLineNoTextItem and not match.runs:
2269
                                    app_doc_data.tracerLineNos.pop(app_doc_data.tracerLineNos.index(match))
2270
                            # break
2271

    
2272
                matches = [_item for _item in self.graphicsView.scene().items() if hasattr(_item, 'owner')]
2273
                for match in matches:
2274
                    if match.owner is item:
2275
                        match.owner = None
2276

    
2277
                matches = [_item for _item in self.graphicsView.scene().items() if hasattr(_item, 'attrs')]
2278
                # done = False
2279
                for match in matches:
2280
                    assocs = match.associations()
2281
                    for assoc in assocs:
2282
                        if item is assoc:
2283
                            for attr in match.attrs.keys():
2284
                                if attr.AssocItem and str(item.uid) == str(attr.AssocItem.uid):
2285
                                    attr.AssocItem = None
2286
                                    match.attrs[attr] = ''
2287
                                    # done = True
2288
                            match.remove_assoc_item(item)
2289
                            break
2290
                    # if done: break
2291

    
2292
                if item.scene() is not None: item.scene().removeItem(item)
2293
        except Exception as ex:
2294
            message = 'error occurred({}) in {}:{}'.format(ex, sys.exc_info()[-1].tb_frame.f_code.co_filename,
2295
                                                           sys.exc_info()[-1].tb_lineno)
2296
            self.addMessage.emit(MessageType.Error, message)
2297

    
2298
    def connect_attributes(self, MainWindow):
2299
        """connect attributes to symbol"""
2300
        from LineNoTracer import LineNoTracer
2301
        from ConnectAttrDialog import QConnectAttrDialog
2302

    
2303
        if not self.graphicsView.hasImage():
2304
            self.showImageSelectionMessageBox()
2305
            return
2306

    
2307
        # save alarm
2308
        self.save_alarm_enable(False)
2309

    
2310
        try:
2311
            dlg = QConnectAttrDialog(self, self.graphicsView.scene())
2312
            dlg.setWindowFlags(self.windowFlags() & ~Qt.WindowCloseButtonHint & ~Qt.WindowContextHelpButtonHint)
2313
            dlg.exec_()
2314
            if dlg.isRunned:
2315
                self.itemTreeWidget.InitLineNoItems()
2316

    
2317
                # construct line no item
2318
                line_nos = AppDocData.instance().tracerLineNos
2319
                for line_no in line_nos:
2320
                    item = self.itemTreeWidget.addTreeItem(self.itemTreeWidget.root, line_no)
2321
                    connectedItems = line_no.getConnectedItems()
2322
                    for connectedItem in connectedItems:
2323
                        if issubclass(type(connectedItem), SymbolSvgItem):
2324
                            self.itemTreeWidget.addTreeItem(item, connectedItem)
2325
                # up to here
2326

    
2327
                if dlg.validation_checked:
2328
                    self.onValidation()
2329

    
2330
                self.graphicsView.invalidateScene()
2331
        except Exception as ex:
2332
            message = 'error occurred({}) in {}:{}'.format(ex, sys.exc_info()[-1].tb_frame.f_code.co_filename,
2333
                                                           sys.exc_info()[-1].tb_lineno)
2334
            self.addMessage.emit(MessageType.Error, message)
2335
        finally:
2336
            # save alarm
2337
            self.save_alarm_enable(True)
2338

    
2339
    def postDetectLineProcess(self):
2340
        '''
2341
            @brief  check allowables among undetected items
2342
            @author euisung
2343
            @date   2018.11.15
2344
            @history    2018.11.15  euisung    no more used, moved to TextItemFactoy isLineNo()
2345
        '''
2346
        from TextItemFactory import TextItemFactory
2347

    
2348
        appDocData = AppDocData.instance()
2349

    
2350
        tableNames = ["Fluid Code", "Insulation Purpose", "PnID Number", "Piping Materials Class", "Unit Number"]
2351
        tableDatas = []
2352
        for tableName in tableNames:
2353
            tableNameFormat = tableName.replace(' ', '').replace('&&', 'n')
2354
            tableDatas.append(appDocData.getCodeTable(tableNameFormat))
2355

    
2356
        items = self.graphicsView.scene().items()
2357
        for item in items:
2358
            if type(item) is not QEngineeringTextItem:
2359
                continue
2360
            text = item.text()
2361
            for tableData in tableDatas:
2362
                for data in tableData:
2363
                    if data[3] == '':
2364
                        continue
2365
                    else:
2366
                        allows = data[3].split(',')
2367
                        for allow in allows:
2368
                            text = text.replace(allow, data[1])
2369

    
2370
            lineItem = TextItemFactory.instance().createTextItem(text)
2371
            if type(lineItem) is QEngineeringLineNoTextItem:
2372
                lineItem.loc = item.loc
2373
                lineItem.size = item.size
2374
                lineItem.angle = item.angle
2375
                lineItem.area = item.area
2376
                # lineItem.addTextItemToScene(self.graphicsView.scene())
2377
                lineItem.transfer.onRemoved.connect(self.itemRemoved)
2378
                item.transfer.onRemoved.emit(item)
2379
                appDocData.lineNos.append(lineItem)
2380

    
2381
    def init_add_tree_item(self, line_no_tree_item, run_item):
2382
        """ insert symbol item and find line no as owner """
2383
        # insert
2384
        self.itemTreeWidget.addTreeItem(line_no_tree_item, run_item)
2385
        # find
2386
        self.itemTreeWidget.addTreeItem(line_no_tree_item, run_item)
2387

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

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

    
2398
            components = app_doc_data.get_components(drawing.UID)
2399
            maxValue = len(components) * 2
2400
            self.progress.setMaximum(maxValue) if maxValue > 0 else None
2401

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

    
2421
                self.progress.setValue(self.progress.value() + 1)
2422

    
2423
            QApplication.processEvents()
2424

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

    
2436
                self.progress.setValue(self.progress.value() + 1)
2437

    
2438
            QApplication.processEvents()
2439

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

    
2451
                self.progress.setValue(self.progress.value() + 1)
2452

    
2453
            QApplication.processEvents()
2454

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

    
2463
                self.progress.setValue(self.progress.value() + 1)
2464

    
2465
            QApplication.processEvents()
2466

    
2467
            for unknown in [component for component in components if
2468
                            component['Name'] == 'Unknown' and component['SymbolType_UID'] == -1]:
2469
                item = QEngineeringUnknownItem.from_database(unknown)
2470
                item.transfer.onRemoved.connect(self.itemRemoved)
2471
                if item is not None:
2472
                    item.transfer.onRemoved.connect(self.itemRemoved)
2473
                    self.graphicsView.scene().addItem(item)
2474

    
2475
                self.progress.setValue(self.progress.value() + 1)
2476

    
2477
            QApplication.processEvents()
2478

    
2479
            for component in [component for component in components if
2480
                              component['Name'] == 'Line NO' and component['SymbolType_UID'] == -1]:
2481
                line_no = QEngineeringLineNoTextItem.from_database(component)
2482
                if type(line_no) is QEngineeringLineNoTextItem:
2483
                    line_no.transfer.onRemoved.connect(self.itemRemoved)
2484
                    self.addTextItemToScene(line_no)
2485
                    line_no_tree_item = self.itemTreeWidget.addTreeItem(self.itemTreeWidget.root, line_no)
2486

    
2487
                    runs = app_doc_data.get_pipe_runs(str(line_no.uid))
2488
                    if not runs: continue
2489
                    for run in runs:
2490
                        line_run = QEngineeringRunItem()
2491
                        run_items = app_doc_data.get_pipe_run_items(run['UID'])
2492
                        for record in run_items:
2493
                            uid = record['Components_UID']
2494
                            run_item = self.graphicsView.findItemByUid(uid)
2495
                            if run_item is not None:
2496
                                run_item._owner = line_no
2497
                                line_run.items.append(run_item)
2498
                        line_run.owner = line_no
2499
                        line_no.runs.append(line_run)
2500

    
2501
                        for run_item in line_run.items:
2502
                            if issubclass(type(run_item), SymbolSvgItem):
2503
                                self.init_add_tree_item(line_no_tree_item, run_item)
2504

    
2505
                self.progress.setValue(self.progress.value() + 1)
2506
            QApplication.processEvents()
2507

    
2508
            for component in [component for component in components if
2509
                              component['Name'] == 'Trim Line NO' and component['SymbolType_UID'] == -1]:
2510
                line_no = QEngineeringTrimLineNoTextItem()
2511
                line_no.uid = uuid.UUID(component['UID'])
2512

    
2513
                runs = app_doc_data.get_pipe_runs(str(line_no.uid))
2514
                if not runs: continue
2515

    
2516
                line_no_tree_item = self.itemTreeWidget.addTreeItem(self.itemTreeWidget.root, line_no)
2517

    
2518
                for run in runs:
2519
                    line_run = QEngineeringRunItem()
2520
                    run_items = app_doc_data.get_pipe_run_items(run['UID'])
2521
                    for record in run_items:
2522
                        uid = record['Components_UID']
2523
                        run_item = self.graphicsView.findItemByUid(uid)
2524
                        if run_item is not None:
2525
                            run_item.owner = line_no
2526
                            line_run.items.append(run_item)
2527
                    line_run.owner = line_no
2528
                    line_no.runs.append(line_run)
2529

    
2530
                    for run_item in line_run.items:
2531
                        if issubclass(type(run_item), SymbolSvgItem):
2532
                            self.init_add_tree_item(line_no_tree_item, run_item)
2533

    
2534
                app_doc_data.tracerLineNos.append(line_no)
2535

    
2536
                self.progress.setValue(self.progress.value() + 1)
2537

    
2538
            for component in [component for component in components if
2539
                              component['Name'] == 'VendorPackage' and component['SymbolType_UID'] == -1]:
2540
                item = QEngineeringVendorItem.from_database(component)
2541
                if item is not None:
2542
                    item.transfer.onRemoved.connect(self.itemRemoved)
2543
                    self.graphicsView.scene().addItem(item)
2544

    
2545
            # connect flow item to line
2546
            for line in lines:
2547
                line.update_arrow()
2548
                app_doc_data.lines.append(line)
2549
            # for flowMark in [item for item in symbols if type(item) is QEngineeringFlowMarkItem]:
2550
            #    for line in lines:
2551
            #        if flowMark.owner is line:
2552
            #            line._flowMark.append(flowMark)
2553
            #            flowMark.setParentItem(line)
2554
            # up to here
2555

    
2556
            """ update scene """
2557
            self.graphicsView.scene().update(self.graphicsView.sceneRect())
2558
            for item in self.graphicsView.scene().items():
2559
                up_progress = False
2560
                # binding items
2561
                if hasattr(item, 'owner'):
2562
                    item.owner
2563
                    up_progress = True
2564
                if hasattr(item, 'connectors'):
2565
                    for connector in item.connectors:
2566
                        connector.connectedItem
2567
                    up_progress = True
2568

    
2569
                if up_progress:
2570
                    self.progress.setValue(self.progress.value() + 1)
2571
            
2572
            for item in self.graphicsView.scene().items():
2573
                item.setVisible(True)
2574

    
2575
        except Exception as ex:
2576
            message = 'error occurred({}) in {}:{}'.format(ex, sys.exc_info()[-1].tb_frame.f_code.co_filename,
2577
                                                           sys.exc_info()[-1].tb_lineno)
2578
            self.addMessage.emit(MessageType.Error, message)
2579
        finally:
2580
            app_doc_data.clearTempDBData()
2581
            self.itemTreeWidget.update_item_count()
2582
            self.itemTreeWidget.expandAll()
2583
            # self.graphicsView.scene().blockSignals(False)
2584

    
2585
    '''
2586
        @brief      load recognition result
2587
        @author     humkyung
2588
        @date       2018.04.??
2589
        @history    humkyung 2018.01.12 parse originalpoint and connectionpoint
2590
                    Jeongwoo 2018.04.17 add QGraphicItem with Rotated text
2591
                    Jeongwoo 2018.04.23 Change to Draw texts on QEngineeringTextItem
2592
                    humkyung 2018.04.23 connect item remove slot to result tree
2593
                    Jeongwoo 2018.04.25 Add if state with QEngineeringNoteItem
2594
                    Jeongwoo 2018.04.26 Change method to create TextItem object with TextItemFactory
2595
                    Jeongwoo 2018.05.03 Change method to draw Svg Item on Scene (svg.addSvgItemToScene)
2596
                    Jeongwoo 2018.05.29 Change method name / Change method to add item / Add Line item
2597
                    Jeongwoo 2018.05.30 Add parameters on SymbolSvgItem.__init__() (parentSymbol, childSymbol) / Change method name / Change XML NODE NAMES
2598
                    Jeongwoo 2018.06.12 Add LineNoTextItem from LINE_NO
2599
                    Jeongwoo 2018.06.14 Add UnknownItem from UNKNOWN
2600
                    Jeongwoo 2018.06.18 Update Scene after all item added
2601
                                        Add connect on unknown item
2602
                                        Add [transfer] for using pyqtSignal
2603
                    kyouho  2018.07.12  Add line property logic
2604
                    humkyung 2018.08.22 show progress while loading xml file
2605
                    2018.11.22      euisung     fix note road
2606
    '''
2607

    
2608
    def load_recognition_result_from_xml(self, drawing):
2609
        # Yield successive n-sized
2610
        # chunks from l.
2611
        def divide_chunks(l, n):
2612
            # looping till length l
2613
            for i in range(0, len(l), n):
2614
                yield l[i:i + n]
2615

    
2616
        def update_items(items):
2617
            for item in items:
2618
                # binding items
2619
                item.owner
2620
                for connector in item.connectors:
2621
                    connector.connectedItem
2622

    
2623
            return items
2624

    
2625
        import concurrent.futures as futures
2626
        from xml.etree.ElementTree import Element, SubElement, dump, ElementTree, parse
2627
        from App import App
2628
        from EngineeringRunItem import QEngineeringRunItem
2629
        from QEngineeringTrimLineNoTextItem import QEngineeringTrimLineNoTextItem
2630
        from EngineeringGraphicsLineItem import QEngineeringGraphicsLineItem
2631

    
2632
        app_doc_data = AppDocData.instance()
2633

    
2634
        try:
2635
            file_name = os.path.splitext(os.path.basename(drawing.file_path))[0]
2636
            path = os.path.join(app_doc_data.getCurrentProject().getTempPath(), file_name + '.xml')
2637
            self.graphicsView.scene().blockSignals(True)
2638

    
2639
            symbols = []
2640
            lines = []
2641

    
2642
            xml = parse(path)
2643
            root = xml.getroot()
2644

    
2645
            maxValue = 0
2646
            maxValue = maxValue + len(list(root.iter('SYMBOL'))) - \
2647
                       len(list(root.iterfind('LINENOS/LINE_NO/RUN/SYMBOL'))) - \
2648
                       len(list(root.iterfind('TRIMLINENOS/TRIM_LINE_NO/RUN/SYMBOL')))
2649
            maxValue = maxValue + len(list(root.iterfind('TEXTINFOS/ATTRIBUTE')))
2650
            maxValue = maxValue + len(list(root.iterfind('NOTES/ATTRIBUTE')))
2651
            maxValue = maxValue + len(list(root.iter('LINE_NO')))
2652
            maxValue = maxValue + len(list(root.iter('LINE'))) - \
2653
                       len(list(root.iterfind('LINENOS/LINE_NO/RUN/LINE'))) - \
2654
                       len(list(root.iterfind('TRIMLINENOS/TRIM_LINE_NO/RUN/LINE')))
2655
            maxValue = maxValue + len(list(root.iter('GRAPHICS_LINE')))
2656
            maxValue = maxValue + len(list(root.iter('UNKNOWN')))
2657
            # maxValue = maxValue + len(list(root.iter('SIZETEXT')))
2658
            maxValue = maxValue + len(list(root.iter('TRIM_LINE_NO')))
2659
            maxValue *= 2
2660
            self.progress.setMaximum(maxValue) if maxValue > 0 else None
2661

    
2662
            """ parsing all symbols """
2663
            """
2664
            with futures.ThreadPoolExecutor(max_workers=App.THREAD_MAX_WORKER) as pool:
2665
                future_symbol = {pool.submit(SymbolSvgItem.fromXml, symbol): symbol for symbol in root.find('SYMBOLS').iter('SYMBOL')}
2666

2667
                for future in futures.as_completed(future_symbol):
2668
                    try:
2669
                        item = future.result()
2670
                        if item:
2671
                            if item is not None:
2672
                                item.transfer.onRemoved.connect(self.itemRemoved)
2673
                                symbols.append(item)
2674
                                docData.symbols.append(item)
2675
                                self.addSvgItemToScene(item)
2676
                            else:
2677
                                pt = [float(x) for x in symbol.find('LOCATION').text.split(',')]
2678
                                size = [float(x) for x in symbol.find('SIZE').text.split(',')]
2679
                                angle = float(symbol.find('ANGLE').text)
2680
                                item = QGraphicsBoundingBoxItem(pt[0], pt[1], size[0], size[1])
2681
                                item.isSymbol = True
2682
                                item.angle = angle
2683
                                item.setPen(QPen(Qt.red, 5, Qt.SolidLine))
2684
                                self.graphicsView.scene().addItem(item)
2685
                                item.transfer.onRemoved.connect(self.itemRemoved)
2686
                    except Exception as ex:
2687
                        message = 'error occurred({}) in {}:{}'.format(repr(ex), sys.exc_info()[-1].tb_frame.f_code.co_filename,
2688
                                                                       sys.exc_info()[-1].tb_lineno)
2689

2690
            """
2691
            for symbol in root.find('SYMBOLS').iter('SYMBOL'):
2692
                item = SymbolSvgItem.fromXml(symbol)
2693
                if item is not None:
2694
                    item.transfer.onRemoved.connect(self.itemRemoved)
2695
                    symbols.append(item)
2696
                    #app_doc_data.symbols.append(item)
2697
                    item.addSvgItemToScene(self.graphicsView.scene())
2698
                else:
2699
                    pt = [float(x) for x in symbol.find('LOCATION').text.split(',')]
2700
                    size = [float(x) for x in symbol.find('SIZE').text.split(',')]
2701
                    angle = float(symbol.find('ANGLE').text)
2702
                    item = QGraphicsBoundingBoxItem(pt[0], pt[1], size[0], size[1])
2703
                    item.isSymbol = True
2704
                    item.angle = angle
2705
                    item.setPen(QPen(Qt.red, 5, Qt.SolidLine))
2706
                    self.graphicsView.scene().addItem(item)
2707
                    item.transfer.onRemoved.connect(self.itemRemoved)
2708

    
2709
                self.progress.setValue(self.progress.value() + 1)
2710

    
2711
            QApplication.processEvents()
2712

    
2713
            # parse texts
2714
            for text in root.find('TEXTINFOS').iter('ATTRIBUTE'):
2715
                item = QEngineeringTextItem.fromXml(text)
2716
                if item is not None:
2717
                    uid = text.find('UID')
2718
                    attributeValue = text.find('ATTRIBUTEVALUE')
2719
                    name = text.find('NAME').text
2720
                    item.transfer.onRemoved.connect(self.itemRemoved)
2721
                    item.addTextItemToScene(self.graphicsView.scene())
2722
                    # docData.texts.append(item)
2723

    
2724
                    if name == 'TEXT':
2725
                        if uid is not None and attributeValue is not None:
2726
                            item.uid = uid.text
2727
                            item.attribute = attributeValue.text
2728

    
2729
                self.progress.setValue(self.progress.value() + 1)
2730

    
2731
            QApplication.processEvents()
2732

    
2733
            # note
2734
            for text in root.find('NOTES').iter('ATTRIBUTE'):
2735
                item = QEngineeringTextItem.fromXml(text)
2736
                if item is not None:
2737
                    uid = text.find('UID')
2738
                    attributeValue = text.find('ATTRIBUTEVALUE')
2739
                    name = text.find('NAME').text
2740
                    item.transfer.onRemoved.connect(self.itemRemoved)
2741
                    item.addTextItemToScene(self.graphicsView.scene())
2742

    
2743
                    if name == 'NOTE':
2744
                        if uid is not None:
2745
                            item.uid = uid.text
2746

    
2747
                self.progress.setValue(self.progress.value() + 1)
2748

    
2749
            QApplication.processEvents()
2750

    
2751
            for line in root.find('LINEINFOS').iter('LINE'):
2752
                item = QEngineeringLineItem.fromXml(line)
2753
                if item:
2754
                    item.transfer.onRemoved.connect(self.itemRemoved)
2755
                    self.graphicsView.scene().addItem(item)
2756
                    lines.append(item)
2757

    
2758
                self.progress.setValue(self.progress.value() + 1)
2759

    
2760
            for line in root.find('LINEINFOS').iter('GRAPHICS_LINE'):
2761
                item = QEngineeringGraphicsLineItem.fromXml(line)
2762
                if item:
2763
                    item.transfer.onRemoved.connect(self.itemRemoved)
2764
                    self.graphicsView.scene().addItem(item)
2765

    
2766
                self.progress.setValue(self.progress.value() + 1)
2767

    
2768
            QApplication.processEvents()
2769

    
2770
            for unknown in root.iter('UNKNOWN'):
2771
                item = QEngineeringUnknownItem.fromXml(unknown)
2772
                if item is not None:
2773
                    item.transfer.onRemoved.connect(self.itemRemoved)
2774
                    self.graphicsView.scene().addItem(item)
2775

    
2776
                self.progress.setValue(self.progress.value() + 1)
2777

    
2778
            QApplication.processEvents()
2779

    
2780
            # """ add tree widget """
2781
            # for item in symbols:
2782
            #    docData.symbols.append(item)
2783
            #    self.addSvgItemToScene(item)
2784
            #    self.itemTreeWidget.addTreeItem(self.itemTreeWidget.root, item)
2785

    
2786
            for line_no_node in root.find('LINENOS').iter('LINE_NO'):
2787
                line_no = QEngineeringLineNoTextItem.fromXml(line_no_node)
2788
                if line_no is None: continue
2789
                line_no.transfer.onRemoved.connect(self.itemRemoved)
2790
                line_no.addTextItemToScene(self.graphicsView.scene())
2791
                line_no_tree_item = self.itemTreeWidget.addTreeItem(self.itemTreeWidget.root, line_no)
2792
                if type(line_no) is not QEngineeringLineNoTextItem: continue
2793

    
2794
                runs_node = line_no_node.findall('RUN')
2795
                if runs_node is None: continue
2796

    
2797
                for run_node in runs_node:
2798
                    line_run = QEngineeringRunItem()
2799
                    for child_node in run_node:
2800
                        uidElement = child_node.find('UID')
2801
                        if uidElement is not None:
2802
                            uid = uidElement.text
2803
                            run_item = self.graphicsView.findItemByUid(uid)
2804
                            if run_item is not None:
2805
                                run_item._owner = line_no
2806
                                line_run.items.append(run_item)
2807
                    line_run.owner = line_no
2808
                    line_no.runs.append(line_run)
2809

    
2810
                    for run_item in line_run.items:
2811
                        if issubclass(type(run_item), SymbolSvgItem):
2812
                            self.init_add_tree_item(line_no_tree_item, run_item)
2813

    
2814
                # docData.tracerLineNos.append(line_no)
2815

    
2816
                self.progress.setValue(self.progress.value() + 1)
2817
            QApplication.processEvents()
2818

    
2819
            for trimLineNo in root.iter('TRIM_LINE_NO'):
2820
                line_no = QEngineeringTrimLineNoTextItem()
2821
                line_no.uid = uuid.UUID(trimLineNo.find('UID').text)
2822

    
2823
                runs_node = trimLineNo.findall('RUN')
2824
                if runs_node is None: continue
2825
                line_no_tree_item = self.itemTreeWidget.addTreeItem(self.itemTreeWidget.root, line_no)
2826

    
2827
                for run in runs_node:
2828
                    line_run = QEngineeringRunItem()
2829
                    for child in run:
2830
                        uidElement = child.find('UID')
2831
                        if uidElement is not None:
2832
                            uid = uidElement.text
2833
                            run_item = self.graphicsView.findItemByUid(uid)
2834
                            if run_item is not None:
2835
                                run_item.owner = line_no
2836
                                line_run.items.append(run_item)
2837
                    line_run.owner = line_no
2838
                    line_no.runs.append(line_run)
2839

    
2840
                    for run_item in line_run.items:
2841
                        if issubclass(type(run_item), SymbolSvgItem):
2842
                            self.init_add_tree_item(line_no_tree_item, run_item)
2843

    
2844
                app_doc_data.tracerLineNos.append(line_no)
2845

    
2846
                self.progress.setValue(self.progress.value() + 1)
2847
            QApplication.processEvents()
2848

    
2849
            if root.find('VENDORS') is not None:
2850
                for vendor in root.find('VENDORS').iter('VENDOR'):
2851
                    item = QEngineeringVendorItem.fromXml(vendor)
2852
                    item.transfer.onRemoved.connect(self.itemRemoved)
2853
                    self.graphicsView.scene().addItem(item)
2854

    
2855
            # connect flow item to line
2856
            for line in lines:
2857
                line.update_arrow()
2858
                app_doc_data.lines.append(line)
2859
            # for flowMark in [item for item in symbols if type(item) is QEngineeringFlowMarkItem]:
2860
            #    for line in lines:
2861
            #        if flowMark.owner is line:
2862
            #            line._flowMark.append(flowMark)
2863
            #            flowMark.setParentItem(line)
2864
            # up to here
2865

    
2866
            """
2867
            group_box = QGroupBox("Contact Details")
2868
            number_label = QLabel("Telephone number");
2869
            number_edit = QTextEdit('hello\nthis is ....')
2870
            layout = QFormLayout()
2871
            layout.addRow(number_label, number_edit)
2872
            group_box.setLayout(layout)
2873

2874
            proxy = QGraphicsProxyWidget()
2875
            proxy.setWidget(group_box)
2876
            self.graphicsView.scene().addItem(proxy)  # (group_box, QGraphicsItem.ItemIgnoresTransformations)
2877
            """
2878

    
2879
            """ update scene """
2880
            _items = [_item for _item in self.graphicsView.scene().items() if hasattr(_item, 'owner') or hasattr(_item, 'connectors')]
2881
            if _items:
2882
                items = divide_chunks(_items, App.THREAD_MAX_WORKER if len(_items) > App.THREAD_MAX_WORKER else len(_items))
2883
                with futures.ThreadPoolExecutor(max_workers=App.THREAD_MAX_WORKER) as pool:
2884
                    future_items = {pool.submit(update_items, _items): _items for _items in items}
2885
                    for future in futures.as_completed(future_items):
2886
                        _items = future.result()
2887
                        self.progress.setValue(self.progress.value() + len(_items))
2888

    
2889
            """
2890
            for item in [_item for _item in self.graphicsView.scene().items() if hasattr(_item, 'owner') or hasattr(_item, 'connectors')]:
2891
                up_progress = False
2892
                # binding items
2893
                item.owner
2894
                for connector in item.connectors:
2895
                    connector.connectedItem
2896

2897
                self.progress.setValue(self.progress.value() + 1)
2898
            """
2899

    
2900
            for item in self.graphicsView.scene().items():
2901
                item.setVisible(True)
2902

    
2903
            self.graphicsView.scene().update(self.graphicsView.sceneRect())
2904
        except Exception as ex:
2905
            message = 'error occurred({}) in {}:{}'.format(ex, sys.exc_info()[-1].tb_frame.f_code.co_filename,
2906
                                                           sys.exc_info()[-1].tb_lineno)
2907
            self.addMessage.emit(MessageType.Error, message)
2908
        finally:
2909
            self.itemTreeWidget.update_item_count()
2910
            self.itemTreeWidget.expandAll()
2911
            self.graphicsView.scene().blockSignals(False)
2912

    
2913
    '''
2914
        @brief      Remove added item on same place and Add GraphicsItem
2915
        @author     Jeongwoo
2916
        @date       2018.05.29
2917
        @history    2018.06.18  Jeongwoo    Set Z-index
2918
    '''
2919

    
2920
    def addLineItemToScene(self, lineItem):
2921
        self.graphicsView.scene().addItem(lineItem)
2922

    
2923
    '''
2924
        @brief      generate output xml file
2925
        @author     humkyung
2926
        @date       2018.04.23
2927
        @history    2018.05.02  Jeongwoo    Show MessageBox when imageviewer doesn't have image
2928
    '''
2929

    
2930
    def generateOutput(self):
2931
        import XmlGenerator as xg
2932

    
2933
        if not self.graphicsView.hasImage():
2934
            self.showImageSelectionMessageBox()
2935
            return
2936

    
2937
        try:
2938
            appDocData = AppDocData.instance()
2939

    
2940
            # collect items
2941
            appDocData.lines.clear()
2942
            appDocData.lines = [item for item in self.graphicsView.scene().items() if
2943
                                type(item) is QEngineeringLineItem and item.owner is None]
2944

    
2945
            appDocData.symbols.clear()
2946
            appDocData.symbols = [item for item in self.graphicsView.scene().items() if
2947
                                  issubclass(type(item), SymbolSvgItem) and item.owner is None]
2948

    
2949
            appDocData.equipments.clear()
2950
            for item in self.graphicsView.scene().items():
2951
                if type(item) is QEngineeringEquipmentItem:
2952
                    appDocData.equipments.append(item)
2953

    
2954
            appDocData.texts.clear()
2955
            appDocData.texts = [item for item in self.graphicsView.scene().items() if
2956
                                issubclass(type(item), QEngineeringTextItem) and type(
2957
                                    item) is not QEngineeringLineNoTextItem]
2958
            # up to here
2959

    
2960
            appDocData.imgOutput = np.ones((appDocData.activeDrawing.height, appDocData.activeDrawing.width),
2961
                                           np.uint8) * 255
2962
            xg.writeOutputXml(appDocData.imgName, appDocData.activeDrawing.width,
2963
                              appDocData.activeDrawing.height)  # TODO: check
2964
            project = appDocData.getCurrentProject()
2965
            cv2.imwrite(os.path.join(project.getTempPath(), 'OUTPUT.png'), appDocData.imgOutput)
2966
        except Exception as ex:
2967
            message = 'error occurred({}) in {}:{}'.format(ex, sys.exc_info()[-1].tb_frame.f_code.co_filename,
2968
                                                           sys.exc_info()[-1].tb_lineno)
2969
            self.addMessage.emit(MessageType.Error, message)
2970

    
2971
    '''
2972
        @brief      resetting attribute at secne
2973
        @author     kyoyho
2974
        @date       2018.08.21
2975
    '''
2976
    """
2977
    def checkAttribute(self):
2978
        try:
2979

2980
            docData = AppDocData.instance()
2981
            if not self.graphicsView.hasImage():
2982
                return
2983

2984
            # symbol 경우
2985
            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]
2986
            for item in items:
2987
                attrs = item.attrs
2988
                
2989
                removeAttrList = []
2990
                for attr in attrs:
2991
                    if type(attr) is tuple:
2992
                        continue
2993

2994
                    if attr is None:
2995
                        removeAttrList.append(attr)
2996
                        continue
2997

2998
                    attrInfo = docData.getSymbolAttributeByUID(attr.UID)
2999
                    if attrInfo is None:
3000
                        removeAttrList.append(attr)
3001
                    # 해당 attribute가 맞는지 확인
3002
                    else:
3003
                        attrType = attrInfo.AttributeType
3004
                        _type = type(attr)
3005
                        if attrType == 'Symbol Item':
3006
                            if not issubclass(_type, SymbolSvgItem):
3007
                                removeAttrList.append(attr)
3008
                        elif attrType == 'Text Item':
3009
                            if _type is not QEngineeringTextItem:
3010
                                removeAttrList.append(attr)
3011
                        elif attrType == 'Int':
3012
                            if _type is not UserInputAttribute and self.isNumber(attr.text):
3013
                                removeAttrList.append(attr)
3014
                        elif attrType == 'String':
3015
                            if _type is not UserInputAttribute:
3016
                                removeAttrList.append(attr)
3017

3018
                for attr in removeAttrList:
3019
                    del attrs[attr]
3020

3021
            # Line No Text Item의 경우
3022
            items = [item for item in self.graphicsView.scene().items() if issubclass(type(item), QEngineeringLineNoTextItem)]
3023
            for item in items:
3024
                attrs = item.attrs
3025
                
3026
                removeAttrList = []
3027
                for attr in attrs:
3028
                    if type(attr) is UserInputAttribute:
3029
                        attrInfo = docData.getLinePropertiesByUID(attr.attribute)
3030
                        if attrInfo is None:
3031
                            removeAttrList.append(attr)
3032

3033
                for attr in removeAttrList:
3034
                    del attrs[attr]
3035

3036
        except Exception as ex:
3037
                message = 'error occurred({}) in {}:{}'.format(ex, sys.exc_info()[-1].tb_frame.f_code.co_filename, sys.exc_info()[-1].tb_lineno)
3038
                self.addMessage.emit(MessageType.Error, message)
3039
    """
3040
    '''
3041
        @brief      Check Number
3042
        @author     kyouho
3043
        @date       2018.08.20
3044
    '''
3045

    
3046
    def isNumber(self, num):
3047
        p = re.compile('(^[0-9]+$)')
3048
        result = p.match(num)
3049

    
3050
        if result:
3051
            return True
3052
        else:
3053
            return False
3054

    
3055
    '''
3056
        @brief      find overlap Connector
3057
        @author     kyouho
3058
        @date       2018.08.28
3059
    '''
3060

    
3061
    def findOverlapConnector(self, connectorItem):
3062
        from shapely.geometry import Point
3063
        from EngineeringConnectorItem import QEngineeringConnectorItem
3064
        itemList = []
3065

    
3066
        x = connectorItem.center()[0]
3067
        y = connectorItem.center()[1]
3068

    
3069
        connectors = [item for item in self.graphicsView.scene().items() if
3070
                      type(item) is QEngineeringConnectorItem and item != connectorItem]
3071
        for connector in connectors:
3072
            if Point(x, y).distance(Point(connector.center()[0], connector.center()[1])) < 5:
3073
                itemList.append(connector.parent)
3074

    
3075
        return itemList
3076

    
3077
    def make_diff_image(self):
3078
        """ make diff image """
3079
        # test
3080

    
3081
        from RecognitionDialog import Worker
3082
        from symbol import Symbol
3083
        import math
3084
        from PIL import Image
3085

    
3086
        app_doc_data = AppDocData.instance()
3087
        img = app_doc_data.imgSrc.copy()
3088

    
3089
        # check break
3090
        symbols = [item for item in self.graphicsView.scene().items() if issubclass(type(item), SymbolSvgItem)]
3091

    
3092
        for symbol in symbols:
3093
            rect = symbol.sceneBoundingRect()
3094
            sName = symbol.name
3095
            sType = symbol.type
3096
            sp = (rect.x(), rect.y())
3097
            w, h = rect.width(), rect.height()
3098
            rotatedAngle = round(math.degrees(symbol.angle))
3099
            detectFlip = symbol.flip
3100

    
3101
            dummySym = Symbol(sName, sType, sp, w, h, 0, 0, 0, rotatedAngle,
3102
                                   1, 0, 1, 0,
3103
                                   ','.join(str(x) for x in [0, 0]),
3104
                                   '/'.join('{},{},{},{}'.format(param[0], param[1], param[2], param[3]) for param in
3105
                                            []),
3106
                                   'dummy', 'dummy', 0, detectFlip=detectFlip,
3107
                                   hasInstrumentLabel=0, text_area='')
3108

    
3109
            Worker.remove_detected_symbol_image(dummySym, img, lock=False)
3110

    
3111
        Image.fromarray(img).show()
3112

    
3113
if __name__ == '__main__':
3114
    import locale
3115
    from PyQt5.QtCore import QTranslator
3116
    from License import QLicenseDialog
3117
    from ProjectDialog import Ui_Dialog
3118
    from App import App
3119

    
3120
    app = App(sys.argv)
3121
    try:
3122
        if True == QLicenseDialog.check_license_key():
3123
            dlg = Ui_Dialog()
3124
            selectedProject = dlg.showDialog()
3125
            if selectedProject is not None:
3126
                AppDocData.instance().setCurrentProject(selectedProject)
3127
                app._mainWnd = MainWindow.instance()
3128
                app._mainWnd.show()
3129
                sys.exit(app.exec_())
3130
    except Exception as ex:
3131
        print('error occurred({}) in {}:{}'.format(ex, sys.exc_info()[-1].tb_frame.f_code.co_filename,
3132
                                                   sys.exc_info()[-1].tb_lineno))
3133
    finally:
3134
        pass
클립보드 이미지 추가 (최대 크기: 500 MB)