프로젝트

일반

사용자정보

통계
| 개정판:

hytos / DTI_PID / DTI_PID / MainWindow.py @ e8f8936a

이력 | 보기 | 이력해설 | 다운로드 (149 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 ImportTextFromPDFDialog import QImportTextFromPDFDialog
67
from SymbolThicknessDialog import QSymbolThicknessDialog
68
from DisplayColors import DisplayColors
69
from DisplayColors import DisplayOptions
70
from RecognitionDialog import QRecognitionDialog
71
import uuid
72

    
73

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

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

    
81

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

    
86
    def __init__(self):
87
        """initialize"""
88
        from App import App
89
        from LineTypeConditions import LineTypeConditions
90

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

    
105
        self.statusbar.addWidget(self._label_mouse)
106
        self.statusbar.addPermanentWidget(self.progress_bar, 1)
107
        self.statusbar.addPermanentWidget(self.labelSymbolStatus)
108
        self.statusbar.addPermanentWidget(self.labelLineStatus)
109
        self.statusbar.addPermanentWidget(self.labelTextStatus)
110
        self.statusbar.addPermanentWidget(self.labelStatus)
111

    
112
        #self.refresh_rate = 0
113

    
114
        app_doc_data = AppDocData.instance()
115
        app_doc_data.clear()
116
        project = app_doc_data.getCurrentProject()
117
        _translate = QCoreApplication.translate
118
        version = QCoreApplication.applicationVersion()
119
        # set title
120
        self.setWindowTitle(self.title)
121

    
122
        # save timer
123
        self.save_timer = None
124

    
125
        self.lineComboBox = QComboBox(self.toolBar)
126
        for condition in LineTypeConditions.items():
127
            self.lineComboBox.addItem(condition.name)
128

    
129
        configs = app_doc_data.getConfigs('Line', 'Default Type')
130
        value = configs[0].value if 1 == len(configs) else ''
131
        if value:
132
            at = self.lineComboBox.findText(value)
133
            self.lineComboBox.setCurrentIndex(at)
134
        else:
135
            at = self.lineComboBox.findText('Secondary')
136
            self.lineComboBox.setCurrentIndex(at)
137

    
138
        self.toolBar.insertWidget(self.actionOCR, self.lineComboBox)
139
        self.toolBar.insertSeparator(self.actionOCR)
140

    
141
        self.packageComboBox = QComboBox(self.toolBar)
142
        self.packageComboBox.addItems(['Equipment Package', 'Vendor Package'])
143
        self.toolBar.insertWidget(self.actionValidate, self.packageComboBox)
144

    
145
        self._scene = QtImageViewerScene(self)
146

    
147
        self.graphicsView = QtImageViewer(self)
148
        self.graphicsView.setParent(self.centralwidget)
149
        self.graphicsView.useDefaultCommand()  # USE DEFAULT COMMAND
150
        self.graphicsView.setMouseTracking(True)
151
        self.graphicsView.viewport().installEventFilter(self)
152
        self.graphicsView.setScene(self._scene)
153

    
154
        self._display_widget = QDisplayWidget()
155
        self._display_widget.radioButtonByGroup.toggled.connect(self.display_colors)
156
        self._display_widget.radioButtonByGroup.toggled.connect(self.display_colors)
157
        self.EditToolbar.addWidget(self._display_widget)
158
        self._display_widget.radioButtonByGroup.setChecked(True) \
159
            if DisplayColors.instance().option == DisplayOptions.DisplayByLineNo else \
160
            self._display_widget.radioButtonByType.setChecked(True)
161

    
162
        self.verticalLayout.addWidget(self.graphicsView)
163

    
164
        # Add Custom TreeWidget
165
        self.symbolTreeWidget = SymbolTreeWidget.QSymbolTreeWidget()
166
        self.symbolTreeWidget.header().hide()
167
        self.verticalLayoutSymbolTree.addWidget(self.symbolTreeWidget)
168
        self.lineEditFilter.textChanged.connect(self.on_search_text_changed)
169

    
170
        from LibraryItem import LibraryItemWidget
171
        self.libraryWidget = LibraryItemWidget(symbol_tree_widget=self.symbolTreeWidget)
172
        self.verticalLayoutLibrary.addWidget(self.libraryWidget)
173
        # Add Custom Property TableWidget
174
        self.propertyTableWidget = SymbolPropertyTableWidget.QSymbolPropertyTableWidget()
175
        self.verticalLayoutSymbolProperty.addWidget(self.propertyTableWidget)
176
        self.symbolTreeWidget.singleClicked.connect(self.propertyTableWidget.getClickedSymbol)
177

    
178
        self.splitterSymbol.setSizes([500, 300])
179

    
180
        # Add Custom Result Tree Widget (Symbol Explorer)
181
        self.itemTreeWidget = ItemTreeWidget.QItemTreeWidget(self.graphicsView)
182
        self.itemTreeWidget.header().hide()
183
        self.symbolExplorerVerticalLayout.addWidget(self.itemTreeWidget)
184

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

    
199
        # Initialize Action group
200
        self.actionGroup = QActionGroup(self)
201
        self.actionGroup.addAction(self.actionRecognition)
202
        self.actionGroup.addAction(self.actionLineRecognition)
203
        self.actionGroup.addAction(self.actionLine)
204
        self.actionGroup.addAction(self.actionGenerateOutput)
205
        self.actionGroup.addAction(self.actionOCR)
206
        self.actionGroup.addAction(self.actionZoom)
207
        self.actionGroup.addAction(self.actionFitWindow)
208
        self.actionGroup.addAction(self.actionSave)
209
        self.actionGroup.addAction(self.actionValidate)
210
        self.actionGroup.addAction(self.actionVendor)
211
        self.actionGroup.triggered.connect(self.actionGroupTriggered)
212

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

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

    
287
        self.delimiter = '"'
288

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

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

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

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

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

    
333
        self.read_settings()
334

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

    
339
        from App import App
340

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

    
349
        return title
350

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

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

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

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

    
373
        self.settings.setValue('geometry', self.saveGeometry())
374
        self.settings.setValue('windowState', self.saveState())
375
        # TODO: need to modify
376

    
377
        """save current view region"""
378
        app_doc_data = AppDocData.instance()
379
        if app_doc_data.activeDrawing:
380
            rect = self.graphicsView.viewport().rect()
381
            app_doc_data.activeDrawing.view_rect = self.graphicsView.mapToScene(rect).boundingRect()
382
            app_doc_data.update_view_region(app_doc_data.activeDrawing)
383
        """up to here"""
384

    
385
        # self.save_drawing_if_necessary()
386
        AppDocData.instance().clear()
387
        event.accept()
388

    
389
    def inconsistencyTableKeyPressEvent(self, event):
390
        try:
391
            row = self.tableWidgetInconsistency.selectedIndexes()[0].row()
392
            col = self.tableWidgetInconsistency.selectedIndexes()[0].column()
393
            from HighlightCommand import HighlightCommand
394
            if event.key() == Qt.Key_Up:
395
                if row is not 0:
396
                    errorItem = self.tableWidgetInconsistency.item(row - 1, 1).tag
397
                    HighlightCommand(self.graphicsView).execute(errorItem)
398
            elif event.key() == Qt.Key_Down:
399
                if row is not self.tableWidgetInconsistency.rowCount() - 1:
400
                    errorItem = self.tableWidgetInconsistency.item(row + 1, 1).tag
401
                    HighlightCommand(self.graphicsView).execute(errorItem)
402
            elif event.key() == Qt.Key_Delete:
403
                item = self.tableWidgetInconsistency.item(row, 0).tag
404
                if item and item.scene(): item.scene().removeItem(item)
405
                self.tableWidgetInconsistency.removeRow(row)
406

    
407
                self.tabWidget_2.setTabText(self.tabWidget_2.indexOf(self.tabInconsistency),
408
                                            self.tr('Inconsistency') + f"({self.tableWidgetInconsistency.rowCount()})")
409
        except Exception as ex:
410
            message = 'error occurred({}) in {}:{}'.format(ex, sys.exc_info()[-1].tb_frame.f_code.co_filename,
411
                                                           sys.exc_info()[-1].tb_lineno)
412
            self.addMessage.emit(MessageType.Error, message)
413
        # finally:
414
        #    return QTableView.keyPressEvent(self.tableWidgetInconsistency, event)
415

    
416
    def onValidation(self):
417
        """validation check"""
418
        from ValidationDialog import QValidationDialog
419
        from ValidateCommand import ValidateCommand
420

    
421
        if not self.graphicsView.hasImage():
422
            self.showImageSelectionMessageBox()
423
            return
424

    
425
        try:
426
            dlg = QValidationDialog(self)
427
            if QDialog.Accepted == dlg.exec_():
428
                # remove error items
429
                for item in self.graphicsView.scene().items():
430
                    if type(item) is QEngineeringErrorItem:
431
                        item.transfer.onRemoved.emit(item)
432
                # up to here
433

    
434
                self.progress_bar.setMaximum(len(self.graphicsView.scene().items()))
435
                self.progress_bar.setValue(0)
436

    
437
                cmd = ValidateCommand(self.graphicsView)
438
                cmd.show_progress.connect(self.progress_bar.setValue)
439
                errors = cmd.execute(self.graphicsView.scene().items())
440
                for error in errors:
441
                    error.transfer.onRemoved.connect(self.itemRemoved)
442
                    #self.graphicsView.scene().addItem(error)
443
                    error.addSvgItemToScene(self.graphicsView.scene())
444

    
445
                self.tableWidgetInconsistency.clearContents()
446
                self.tableWidgetInconsistency.setRowCount(len(errors))
447
                for index, error in enumerate(errors):
448
                    self.makeInconsistencyTableRow(index, error)
449

    
450
                self.tabWidget_2.setTabText(self.tabWidget_2.indexOf(self.tabInconsistency),
451
                                            self.tr('Inconsistency') + f"({len(errors)})")
452
                if errors:
453
                    self.tabWidget_2.tabBar().setTabTextColor(self.tabWidget_2.indexOf(self.tabInconsistency), Qt.red)
454
                else:
455
                    self.tabWidget_2.tabBar().setTabTextColor(self.tabWidget_2.indexOf(self.tabInconsistency), Qt.black)
456
        except Exception as ex:
457
            message = 'error occurred({}) in {}:{}'.format(ex, sys.exc_info()[-1].tb_frame.f_code.co_filename,
458
                                                           sys.exc_info()[-1].tb_lineno)
459
            self.addMessage.emit(MessageType.Error, message)
460
        finally:
461
            self.progress_bar.setValue(self.progress_bar.maximum())
462

    
463
    def makeInconsistencyTableRow(self, row, errorItem):
464
        '''
465
            @brief  make row data for inconsistency widget
466
            @author euisung
467
            @date   2019.04.16
468
        '''
469

    
470
        item = QTableWidgetItem(str(errorItem.parent))
471
        item.tag = errorItem
472
        self.tableWidgetInconsistency.setItem(row, 0, item)
473

    
474
        item = QTableWidgetItem(str(type(errorItem.parent)))
475
        item.tag = errorItem
476
        self.tableWidgetInconsistency.setItem(row, 1, item)
477

    
478
        item = QTableWidgetItem(errorItem.msg)
479
        item.tag = errorItem
480
        self.tableWidgetInconsistency.setItem(row, 2, item)
481

    
482
    def inconsistencyItemClickEvent(self, item):
483
        """
484
        @brief  inconsistency table item clicked
485
        @author euisung
486
        @date   2019.04.02
487
        """
488
        from HighlightCommand import HighlightCommand
489

    
490
        HighlightCommand(self.graphicsView).execute(item.tag)
491

    
492
    def read_settings(self):
493
        """read geometry and state"""
494
        from App import App
495

    
496
        try:
497
            self.settings = QSettings(App.COMPANY, App.NAME)
498
            self.restoreGeometry(self.settings.value("geometry", ""))
499
            self.restoreState(self.settings.value("windowState", ""))
500
        except Exception as ex:
501
            message = 'error occurred({}) in {}:{}'.format(ex, sys.exc_info()[-1].tb_frame.f_code.co_filename,
502
                                                           sys.exc_info()[-1].tb_lineno)
503
            print(message)
504

    
505
    def load_stylesheet(self, file):
506
        """load stylesheets"""
507

    
508
        QtWidgets.qApp.loadStyleSheet(os.path.join(os.path.dirname(os.path.realpath(__file__)), file))
509

    
510
        app_doc_data = AppDocData.instance()
511
        configs = [Config('app', 'stylesheet', file)]
512
        app_doc_data.saveAppConfigs(configs)
513

    
514
        for action in self.menuTheme.actions():
515
            if action.text() == file: continue
516
            action.setChecked(False)
517

    
518
    def load_language(self, file):
519
        """load language file and then apply selected language"""
520
        try:
521
            qm_file = os.path.join(os.path.dirname(os.path.realpath(__file__)), 'translate', '{0}.qm'.format(file))
522
            QtWidgets.qApp.load_language(qm_file)
523

    
524
            app_doc_data = AppDocData.instance()
525
            configs = [Config('app', 'language', file)]
526
            app_doc_data.saveAppConfigs(configs)
527

    
528
            for action in self.menuLanguage.actions():
529
                if action.text().lower() == file.lower(): continue
530
                action.setChecked(False)
531
        finally:
532
            self.retranslateUi(self)
533
            self.propertyTableWidget.retranslateUi()
534

    
535
    def refresh_item_list(self):
536
        """refresh item tree"""
537
        self.itemTreeWidget.InitLineNoItems()
538

    
539
        line_nos = AppDocData.instance().tracerLineNos
540
        for line_no in line_nos:
541
            item = self.itemTreeWidget.addTreeItem(self.itemTreeWidget.root, line_no)
542
            connectedItems = line_no.getConnectedItems()
543
            for connectedItem in connectedItems:
544
                if issubclass(type(connectedItem), SymbolSvgItem):
545
                    self.itemTreeWidget.addTreeItem(item, connectedItem)
546
        
547
    def sort_drawing_list(self, index):
548
        """ sort drawing list """
549
        if index == 0:
550
            if self.drawing_reverse:
551
                self.load_drawing_list(reverse=False)
552
            else:
553
                self.load_drawing_list(reverse=True)
554

    
555

    
556
    def load_drawing_list(self, reverse=False):
557
        """load p&id drawing list"""
558
        from Drawing import Drawing
559

    
560
        try:
561
            app_doc_data = AppDocData.instance()
562
            drawings = app_doc_data.getDrawings()
563

    
564
            self.treeWidgetDrawingList.clear()
565
            self.treeWidgetDrawingList.root = QTreeWidgetItem(self.treeWidgetDrawingList,
566
                                                              [self.tr('P&ID Drawings'), ''])
567
            self.treeWidgetDrawingList.root.setFlags(
568
                self.treeWidgetDrawingList.root.flags() | Qt.ItemIsTristate | Qt.ItemIsUserCheckable)
569
            self.treeWidgetDrawingList.root.setCheckState(0, Qt.Unchecked)
570
            files = app_doc_data.getDrawingFileList()
571

    
572
            # self.progress_bar.setMaximum(len(files))
573
            count = 0
574
            # self.progress_bar.setValue(count)
575
            self.drawing_reverse = reverse
576
            for file in files if not self.drawing_reverse else reversed(files):
577
                x = [drawing for drawing in drawings if drawing.name == file]
578
                if not x or not x[0].UID:
579
                    drawing = Drawing(None, file, None)
580
                    drawings.append(drawing)
581
                else:
582
                    drawing = x[0]
583

    
584
                item = QTreeWidgetItem(self.treeWidgetDrawingList.root, [file, drawing.datetime])
585
                item.setIcon(0, QIcon(':newPrefix/image.png'))
586
                item.setFlags(item.flags() | Qt.ItemIsUserCheckable)
587
                item.setCheckState(0, Qt.Unchecked)
588
                item.setData(Qt.UserRole, 0, drawing)
589

    
590
                count += 1
591
                # self.progress_bar.setValue(count)
592
                # QApplication.processEvents()
593

    
594
            self.treeWidgetDrawingList.root.setText(0, self.tr('P&ID Drawings') +
595
                                                    f"({self.treeWidgetDrawingList.root.childCount()})")
596
            self.treeWidgetDrawingList.expandItem(self.treeWidgetDrawingList.root)
597
            #self.treeWidgetDrawingList.root.sortChildren(0, Qt.AscendingOrder)
598
            self.treeWidgetDrawingList.resizeColumnToContents(0)
599

    
600
            app_doc_data.saveDrawings(drawings)
601
        except Exception as ex:
602
            message = 'error occurred({}) in {}:{}'.format(repr(ex), sys.exc_info()[-1].tb_frame.f_code.co_filename,
603
                                                           sys.exc_info()[-1].tb_lineno)
604
            self.addMessage.emit(MessageType.Error, message)
605
        finally:
606
            self.progress_bar.setValue(self.progress_bar.maximum())
607

    
608
    def open_selected_drawing(self, item, column):
609
        """open selected p&id drawing"""
610

    
611
        app_doc_data = AppDocData.instance()
612
        drawing = item.data(Qt.UserRole, 0)
613
        if drawing:
614
            # uncheck all drawing tree item
615
            drawing_top = self.treeWidgetDrawingList.topLevelItem(0)
616
            count = drawing_top.childCount()
617
            for idx in range(count):
618
                child = drawing_top.child(idx)
619
                child.setCheckState(column, Qt.Unchecked)
620
            # up to here
621

    
622
            drawing.image = None
623
            self.open_image_drawing(drawing)
624
            item.setCheckState(column, Qt.Checked)
625

    
626
    def show_detect_symbol_dialog(self):
627
        from DetectSymbolDialog import QDetectSymbolDialog
628

    
629
        dlg = QDetectSymbolDialog(self)
630
        dlg.exec_()
631

    
632
    '''
633
        @brief      OCR Editor
634
        @author     euisung
635
        @date       2018.10.05
636
        @history    2018.10.16 euisung      no more used, Integrated with oCRTrainingClicked
637
    '''
638

    
639
    def oCRTrainingEdidorClicked(self):
640
        from TrainingEditorDialog import QTrainingEditorDialog
641

    
642
        try:
643
            dialog = QTrainingEditorDialog(self)
644
            dialog.exec_()
645
        except Exception as ex:
646
            message = 'error occurred({}) in {}:{}'.format(ex, sys.exc_info()[-1].tb_frame.f_code.co_filename,
647
                                                           sys.exc_info()[-1].tb_lineno)
648
            self.addMessage.emit(MessageType.Error, message)
649

    
650
        return
651

    
652
    '''
653
        @brief      OCR Training
654
        @author     euisung
655
        @date       2018.09.27
656
        @history    euisung 2018.10.16 TrainingListDialog -> TrainingImageListDialog
657
    '''
658

    
659
    def oCRTrainingClicked(self):
660
        try:
661
            dialog = QTrainingImageListDialog(self)
662
            dialog.exec_()
663
        except Exception as ex:
664
            message = 'error occurred({}) in {}:{}'.format(ex, sys.exc_info()[-1].tb_frame.f_code.co_filename,
665
                                                           sys.exc_info()[-1].tb_lineno)
666
            self.addMessage.emit(MessageType.Error, message)
667

    
668
    def symbolTrainingClicked(self):
669
        try:
670
            dialog = QTrainingSymbolImageListDialog(self)
671
            dialog.show()
672
            dialog.exec_()
673
        except Exception as ex:
674
            message = 'error occurred({}) in {}:{}'.format(ex, sys.exc_info()[-1].tb_frame.f_code.co_filename,
675
                                                           sys.exc_info()[-1].tb_lineno)
676
            self.addMessage.emit(MessageType.Error, message)
677

    
678
    def findReplaceTextClicked(self):
679
        """pop up find and replace dialog"""
680
        if not self.graphicsView.hasImage():
681
            self.showImageSelectionMessageBox()
682
            return
683

    
684
        from TextItemEditDialog import QTextItemEditDialog
685

    
686
        dlgTextItemEdit = QTextItemEditDialog(self)
687
        dlgTextItemEdit.show()
688
        dlgTextItemEdit.exec_()
689

    
690
    def on_validation_global_clicked(self):
691
        """ global validation dialog """
692
        from ValidationGlobalDialog import QValidationGlobalDialog
693

    
694
        dlg = QValidationGlobalDialog(self)
695
        dlg.show()
696
        dlg.exec_()
697

    
698
    def replaceInsertSymbolClicked(self):
699
        """pop up replace and insert dialog"""
700
        if not self.graphicsView.hasImage():
701
            self.showImageSelectionMessageBox()
702
            return
703

    
704
        from ReplaceSymbolDialog import QReplaceSymbolDialog
705

    
706
        dlg = QReplaceSymbolDialog(self)
707
        dlg.show()
708
        dlg.exec_()
709

    
710
    def on_connect_line_to_symbol(self):
711
        """connect line to symbol"""
712
        from LineDetector import LineDetector
713

    
714
        if not self.graphicsView.hasImage():
715
            self.showImageSelectionMessageBox()
716
            return
717

    
718
        app_doc_data = AppDocData.instance()
719
        configs = app_doc_data.getConfigs('Project', 'Operation')
720
        configs = app_doc_data.getConfigs('Line Detector', 'Length to connect line')
721
        toler = int(configs[0].value) if configs else 20
722
        detector = LineDetector(app_doc_data.imgSrc)
723

    
724
        lines = [item for item in self.graphicsView.scene().items() if type(item) is QEngineeringLineItem]
725
        symbols = [item for item in self.graphicsView.scene().items() if issubclass(type(item), SymbolSvgItem)]
726
        if lines:
727
            # connect line to symbol
728
            try:
729
                for line in lines:
730
                    matches = [_symbol for _symbol in symbols if _symbol.is_connectable(line, toler=toler)]
731
                    for _symbol in matches:
732
                        detector.connectLineToSymbol(line, _symbol, toler=toler)
733
            except Exception as ex:
734
                message = f"error occurred({repr(ex)}) in {sys.exc_info()[-1].tb_frame.f_code.co_filename}:" \
735
                          f"{sys.exc_info()[-1].tb_lineno}"
736
                self.addMessage.emit(MessageType.Error, message)
737
            # up to here
738

    
739
            # connect line to line
740
            try:
741
                for line in lines:
742
                    matches = [it for it in lines if (it is not line) and (not line.isParallel(it))]
743

    
744
                    for match in matches:
745
                        detector.connectLineToLine(match, line, toler)
746
            except Exception as ex:
747
                message = f"error occurred({repr(ex)}) in {sys.exc_info()[-1].tb_frame.f_code.co_filename}:" \
748
                          f"{sys.exc_info()[-1].tb_lineno}"
749
                self.addMessage.emit(MessageType.Error, message)
750
            # up to here
751

    
752
        QMessageBox.information(self, self.tr('Information'), self.tr('Connecting between symbols and lines is complete'))
753

    
754
    def on_recognize_line(self):
755
        """recognize lines in selected area"""
756
        from RecognizeLineCommand import RecognizeLineCommand
757

    
758
        if not self.graphicsView.hasImage():
759
            self.actionOCR.setChecked(False)
760
            self.showImageSelectionMessageBox()
761
            return
762

    
763
        cmd = RecognizeLineCommand(self.graphicsView)
764
        cmd.onSuccess.connect(self.on_success_to_recognize_line)
765
        cmd.onRejected.connect(self.onCommandRejected)
766
        self.graphicsView.command = cmd
767

    
768
    '''
769
            @brief      show text recognition dialog
770
            @author     humkyung
771
            @date       2018.08.08
772
    '''
773

    
774
    def on_success_to_recognize_line(self, x, y, width, height):
775
        import io
776
        from LineDetector import LineDetector
777
        from EngineeringGraphicsLineItem import QEngineeringGraphicsLineItem
778

    
779
        try:
780
            image = self.graphicsView.image().copy(x, y, width, height)
781
            buffer = QBuffer()
782
            buffer.open(QBuffer.ReadWrite)
783
            image.save(buffer, "PNG")
784
            pyImage = Image.open(io.BytesIO(buffer.data()))
785
            img = np.array(pyImage)
786
            img = cv2.cvtColor(img, cv2.COLOR_BGR2GRAY)
787

    
788
            detector = LineDetector(img)
789
            lines = detector.detect_line_without_symbol()
790
            for line in lines:
791
                vertices = [[line[0][0] + x, line[0][1] + y], [line[1][0] + x, line[1][1] + y]]
792
                line_item = QEngineeringGraphicsLineItem(vertices)
793
                self.graphicsView.scene().addItem(line_item)
794

    
795
        except Exception as ex:
796
            message = 'error occurred({}) in {}:{}'.format(repr(ex), sys.exc_info()[-1].tb_frame.f_code.co_filename,
797
                                                           sys.exc_info()[-1].tb_lineno)
798
            self.addMessage.emit(MessageType.Error, message)
799

    
800
    def display_number_of_items(self):
801
        """display count of symbol, line, text"""
802

    
803
        items = [item for item in self.graphicsView.scene().items() if type(item) is QEngineeringUnknownItem]
804
        if len(items) > 0:
805
            self.labelStatus.setText(
806
                "<font color='red'>" + self.tr('Unrecognition') + " : {}</font>".format(len(items)))
807
        else:
808
            self.labelStatus.setText(
809
                "<font color='black'>" + self.tr('Unrecognition') + " : {}</font>".format(len(items)))
810

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

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

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

    
821
        self.itemTreeWidget.sceneChanged(self.graphicsView.scene().items())
822

    
823
    def dbUpdate(self):
824
        """ no more used """
825
        """db update when save or recognition"""
826

    
827
        try:
828
            appDocData = AppDocData.instance()
829
            items = appDocData.allItems
830

    
831
            '''
832
            titleBlockProps = appDocData.getTitleBlockProperties()
833
            titleBlockItems = []
834
            for item in items:
835
                # if type(item) is QEngineeringLineNoTextItem:
836
                #    item.saveLineData()
837
                if type(item) is QEngineeringTextItem:
838
                    for titleBlockProp in titleBlockProps:
839
                        if item.area == titleBlockProp[0]:
840
                            titleBlockItems.append(item)
841
            '''
842

    
843
            # unknown item is not saved now for performance
844
            db_items = [item for item in items if issubclass(type(item), QEngineeringAbstractItem) and
845
                        type(item) is not QGraphicsBoundingBoxItem and
846
                        type(item) is not QEngineeringErrorItem and
847
                        type(item) is not QEngineeringLineNoTextItem and
848
                        type(item) is not QEngineeringUnknownItem]
849
            db_items.extend([item for item in items if type(item) is QEngineeringLineNoTextItem])
850
            db_items.extend([line for line in appDocData.tracerLineNos if type(line) is QEngineeringTrimLineNoTextItem])
851
            # db_items.extend(titleBlockItems)
852
            configs = appDocData.getConfigs('Data Save', 'Unknown Xml Only')
853
            if configs and int(configs[0].value) is -1:
854
                db_items.extend([item for item in items if type(item) is QEngineeringUnknownItem])
855

    
856
            '''
857
            dbItems = [item for item in items if
858
                       type(item) is QEngineeringInstrumentItem or type(item) is QEngineeringEquipmentItem or type(
859
                           item) is QEngineeringReducerItem or \
860
                       type(item) is QEngineeringNoteItem or type(item) is SymbolSvgItem or type(
861
                           item) is QEngineeringLineNoTextItem or type(
862
                           item) is QEngineeringVendorItem] + titleBlockItems
863
            '''
864
            appDocData.saveToDatabase(db_items)
865
        except Exception as ex:
866
            message = 'error occurred({}) in {}:{}'.format(ex, sys.exc_info()[-1].tb_frame.f_code.co_filename,
867
                                                           sys.exc_info()[-1].tb_lineno)
868
            self.addMessage.emit(MessageType.Error, message)
869

    
870
    def save_drawing_if_necessary(self):
871
        """ask to user to save drawing or not when drawing is modified"""
872

    
873
        app_doc_data = AppDocData.instance()
874
        if app_doc_data.activeDrawing and app_doc_data.activeDrawing.modified:
875
            #if QMessageBox.Yes == QMessageBox.question(self, self.tr("Question"),
876
            #                                           self.tr("Do you want to save drawing?"),
877
            #                                           QMessageBox.Yes | QMessageBox.No):
878
            #    self.actionSaveCliked()
879
            #    return True
880
            if QMessageBox.Ignore == QMessageBox.question(self, self.tr('Continue?'),
881
                                                       self.tr('Changes may not have been saved.'),
882
                                                       QMessageBox.Ignore | QMessageBox.Cancel):
883
                return False
884
            return True
885

    
886
    def actionSaveCliked(self):
887
        """save current drawing"""
888
        from EngineeringAbstractItem import QEngineeringAbstractItem
889
        from SaveWorkCommand import SaveWorkCommand
890

    
891
        try:
892
            if not self.actionSave.isEnabled():
893
                return
894
            self.actionSave.setEnabled(False)
895

    
896
            # save alarm
897
            self.save_alarm_enable(False)
898

    
899
            app_doc_data = AppDocData.instance()
900
            if app_doc_data.imgName is None:
901
                self.showImageSelectionMessageBox()
902
                return
903

    
904
            app_doc_data.clearItemList(False)
905

    
906
            items = self.graphicsView.scene().items()
907

    
908
            self._save_work_cmd = SaveWorkCommand(self.graphicsView.scene())
909
            self._save_work_cmd.show_progress.connect(self.progress_bar.setValue)
910
            self._save_work_cmd.display_message.connect(self.onAddMessage)
911
            self._save_work_cmd.finished.connect(self.save_finished)
912

    
913
            self._save_work_cmd.start()
914
        except Exception as ex:
915
            message = f"error occurred({repr(ex)}) in {sys.exc_info()[-1].tb_frame.f_code.co_filename}:" \
916
                      f"{sys.exc_info()[-1].tb_lineno}"
917
            self.addMessage.emit(MessageType.Error, message)
918

    
919
    def save_finished(self):
920
        """reload drawing list"""
921

    
922
        self._save_work_cmd.show_progress.emit(100)
923
        QMessageBox.about(self.graphicsView, self.tr('Information'), self._save_work_cmd.resultStr)
924
        self.load_drawing_list()
925

    
926
        app_doc_data = AppDocData.instance()
927
        app_doc_data.activeDrawing.modified = False
928
        title = self.windowTitle()
929
        self.setWindowTitle(title[:-1] if title[-1] == '*' else title)
930

    
931
        self.actionSave.setEnabled(True)
932
        
933
        # save alarm
934
        self.save_alarm_enable(True)
935

    
936
    '''
937
        @brief      refresh resultPropertyTableWidget
938
        @author     kyouho
939
        @date       2018.07.19
940
    '''
941

    
942
    def refreshResultPropertyTableWidget(self):
943
        items = self.graphicsView.scene().selectedItems()
944
        if len(items) == 1:
945
            self.resultPropertyTableWidget.show_item_property(items[0])
946

    
947
    '''
948
        @brief  add message listwidget
949
        @author humkyung
950
        @date   2018.07.31
951
    '''
952

    
953
    def onAddMessage(self, messageType, message):
954
        from AppDocData import MessageType
955

    
956
        try:
957
            current = QDateTime.currentDateTime()
958

    
959
            item = QListWidgetItem('{}: {}'.format(current.toString('hh:mm:ss'), message))
960
            item.setFlags(item.flags() | Qt.ItemIsEditable)
961
            if messageType == MessageType.Error:
962
                item.setBackground(Qt.red)
963
            elif messageType == 'check':
964
                item.setBackground(Qt.yellow)
965

    
966
            self.listWidgetLog.insertItem(0, item)
967
        except Exception as ex:
968
            print('error occurred({}) in {}:{}'.format(ex, sys.exc_info()[-1].tb_frame.f_code.co_filename,
969
                                                       sys.exc_info()[-1].tb_lineno))
970

    
971
    def on_clear_log(self):
972
        """clear log"""
973
        self.listWidgetLog.clear()
974

    
975
    '''
976
        @brief      rotate selected symbol
977
        @author     humkyung
978
        @date       2018.08.15
979
    '''
980

    
981
    def onRotate(self, action):
982
        selected = [item for item in self.graphicsView.scene().selectedItems() if issubclass(type(item), SymbolSvgItem)]
983
        if len(selected) == 1:
984
            from RotateCommand import RotateCommand
985
            self.graphicsView.scene()._undo_stack.push(RotateCommand(self.graphicsView.scene(), selected))
986

    
987
    '''
988
        @brief      Area Zoom
989
        @author     Jeongwoo
990
        @date       2018.06.27
991
        @history    connect command's rejected signal
992
    '''
993

    
994
    def onAreaZoom(self, action):
995
        if self.actionZoom.isChecked():
996
            cmd = AreaZoomCommand.AreaZoomCommand(self.graphicsView)
997
            cmd.onRejected.connect(self.onCommandRejected)
998
            self.graphicsView.command = cmd
999

    
1000
    def onVendor(self, action):
1001
        """make vendor package area"""
1002

    
1003
        if not self.graphicsView.hasImage():
1004
            self.actionVendor.setChecked(False)
1005
            self.showImageSelectionMessageBox()
1006
            return
1007

    
1008
        self.actionVendor.setChecked(True)
1009
        if not hasattr(self.actionVendor, 'tag'):
1010
            self.actionVendor.tag = PlacePolygonCommand.PlacePolygonCommand(self.graphicsView)
1011
            self.actionVendor.tag.onSuccess.connect(self.onVendorCreated)
1012
            self.actionVendor.tag.onRejected.connect(self.onCommandRejected)
1013

    
1014
        self.graphicsView.command = self.actionVendor.tag
1015

    
1016
    def onVendorCreated(self):
1017
        """add created vendor polygon area to scene"""
1018

    
1019
        try:
1020
            count = len(self.actionVendor.tag._polyline._vertices)
1021
            if count > 2:
1022
                points = []
1023
                for point in self.actionVendor.tag._polyline._vertices:
1024
                    points.append(QPoint(round(point[0]), round(point[1])))
1025
                polygon = QPolygonF(points)
1026
                item = QEngineeringVendorItem(polygon, pack_type=self.packageComboBox.currentText())
1027
                item.area = 'Drawing'
1028
                item.transfer.onRemoved.connect(self.itemRemoved)
1029
                self.graphicsView.scene().addItem(item)
1030
        finally:
1031
            self.graphicsView.scene().removeItem(self.actionVendor.tag._polyline)
1032
            self.actionVendor.tag.reset()
1033

    
1034
    def fitWindow(self, view_rect: QRectF = QRectF()):
1035
        """Fit Window"""
1036
        self.graphicsView.useDefaultCommand()
1037
        self.graphicsView.zoomImageInit()
1038

    
1039
        if view_rect:
1040
            self.graphicsView.zoom_rect(view_rect)
1041

    
1042
    def scene_changed(self):
1043
        """update modified flag"""
1044

    
1045
        self.display_number_of_items()
1046

    
1047
        app_doc_data = AppDocData.instance()
1048
        app_doc_data.activeDrawing.modified = True
1049
        title = self.windowTitle()
1050
        self.setWindowTitle(title if title[-1] == '*' else title + '*')
1051

    
1052
    def onConvertPDFToImage(self):
1053
        """convert to selected pdf to image"""
1054
        import os
1055

    
1056
        try:
1057
            file_path = os.path.join(os.path.dirname(os.path.realpath(__file__)), 'bin64', 'PDF_TO_IMAGE.exe')
1058
            os.startfile(file_path)
1059
        except Exception as ex:
1060
            message = 'error occurred({}) in {}:{}'.format(ex, sys.exc_info()[-1].tb_frame.f_code.co_filename,
1061
                                                           sys.exc_info()[-1].tb_lineno)
1062
            self.addMessage.emit(MessageType.Error, message)
1063

    
1064
    def on_import_text_from_cad_for_instrument(self):
1065
        """ import text from cad for instrument """
1066
        try:
1067
            self.onCommandRejected()
1068
            dialog = QImportTextFromPDFDialog(self)
1069
            dialog.show()
1070
            dialog.exec_()
1071
        except Exception as ex:
1072
            message = f"error occurred({repr(ex)}) in {sys.exc_info()[-1].tb_frame.f_code.co_filename}:" \
1073
                      f"{sys.exc_info()[-1].tb_lineno}"
1074
            self.addMessage.emit(MessageType.Error, message)
1075

    
1076
    def on_import_text_from_cad(self):
1077
        """ import text from cad """
1078
        try:
1079
            self.onCommandRejected()
1080
            dialog = QImportTextFromCADDialog(self)
1081
            dialog.show()
1082
            dialog.exec_()
1083
        except Exception as ex:
1084
            message = f"error occurred({repr(ex)}) in {sys.exc_info()[-1].tb_frame.f_code.co_filename}:" \
1085
                      f"{sys.exc_info()[-1].tb_lineno}"
1086
            self.addMessage.emit(MessageType.Error, message)
1087

    
1088
    def onSymbolThickness(self):
1089
        """ symbol thickness reinforcement by using configuration filter drawing dilate size """
1090
        try:
1091
            self.onCommandRejected()
1092
            dialog = QSymbolThicknessDialog(self)
1093
            dialog.exec_()
1094
        except Exception as ex:
1095
            message = 'error occurred({}) in {}:{}'.format(ex, sys.exc_info()[-1].tb_frame.f_code.co_filename,
1096
                                                           sys.exc_info()[-1].tb_lineno)
1097
            self.addMessage.emit(MessageType.Error, message)
1098

    
1099
    def on_help(self):
1100
        """ open help file """
1101
        import os
1102

    
1103
        try:
1104
            help_file_path = os.path.join(os.path.dirname(os.path.realpath(__file__)), 'ID2 User Manual.pdf')
1105
            if os.path.exists(help_file_path):
1106
                os.startfile(f"\"{help_file_path}\"")
1107
            else:
1108
                QMessageBox.warning(self, self.tr('Warning'), self.tr('There is no help file'))
1109
        except Exception as ex:
1110
            message = f"error occurred({repr(ex)}) in {sys.exc_info()[-1].tb_frame.f_code.co_filename}:" \
1111
                      f"{sys.exc_info()[-1].tb_lineno}"
1112
            self.addMessage.emit(MessageType.Error, message)
1113

    
1114
    def on_readme(self):
1115
        """open readme.html"""
1116

    
1117
        file_path = os.path.join(os.path.dirname(os.path.realpath(__file__)), 'readme.html')
1118
        if os.path.exists(file_path):
1119
            os.startfile(f"\"{file_path}\"")
1120
        else:
1121
            QMessageBox.warning(self, self.tr('Warning'), self.tr('There is no readme file'))
1122

    
1123
    def onSelectionChanged(self):
1124
        """selection changed"""
1125
        items = [item for item in self.graphicsView.scene().selectedItems() if issubclass(type(item), SymbolSvgItem) or
1126
                 type(item) is QEngineeringLineItem or issubclass(type(item), QEngineeringTextItem) or
1127
                 type(item) is QEngineeringUnknownItem or type(item) is QEngineeringVendorItem]
1128
        if items:
1129
            lineNos = [item for item in items if type(item) is QEngineeringLineNoTextItem]
1130
            item = items[-1] if not lineNos else lineNos[0]
1131
            self.itemTreeWidget.findItem(item)
1132
            self.resultPropertyTableWidget.show_item_property(item)
1133
            if type(item) is QEngineeringErrorItem:
1134
                for index in range(self.tableWidgetInconsistency.rowCount()):
1135
                    if self.tableWidgetInconsistency.item(index, 1).tag is item:
1136
                        self.tableWidgetInconsistency.selectRow(index)
1137
                        break
1138
            if issubclass(type(item), SymbolSvgItem):
1139
                pass
1140
                #self.symbolTreeWidget.select_symbol(item)
1141
        else:
1142
            self.resultPropertyTableWidget.show_item_property(None)
1143

    
1144
    '''
1145
        @brief      Initialize scene and itemTreeWidget
1146
        @author     Jeongwoo
1147
        @date       2018.06.14
1148
        @history    humkyung 2018.08.16 ask to delete recognized items before remove
1149
    '''
1150

    
1151
    def on_initialize_scene(self, action):
1152
        if not self.graphicsView.hasImage():
1153
            self.showImageSelectionMessageBox()
1154

    
1155
            return
1156

    
1157
        try:
1158
            msg = QMessageBox()
1159
            msg.setIcon(QMessageBox.Critical)
1160
            msg.setText(self.tr('Do you want to remove all items?\nThis work cannot be recovered.'))
1161
            msg.setWindowTitle(self.tr("Initialize"))
1162
            msg.setStandardButtons(QMessageBox.Ok | QMessageBox.Cancel)
1163
            if QMessageBox.Ok == msg.exec_():
1164
                app_doc_data = AppDocData.instance()
1165
                app_doc_data.clearItemList(True)
1166

    
1167
                scene = self.graphicsView.scene()
1168
                pixmap = self.graphicsView.getPixmapHandle()
1169
                scene.removeItem(pixmap)    # disconnect pixmap from scene
1170
                scene.clear()               # remove all items from scene and then delete them
1171
                scene.addItem(pixmap)       # add pixmap
1172

    
1173
                if self.path is not None:
1174
                    baseName = os.path.basename(self.path)
1175
                    self.itemTreeWidget.setCurrentPID(baseName)
1176

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

    
1182
    '''
1183
        @brief      Manage Checkable Action statement
1184
        @author     Jeongwoo
1185
        @date       2018.05.10
1186
        @history    2018.06.27  Jeongwoo    Chnage method to initialize command [Set None → DefaultCommand]
1187
    '''
1188

    
1189
    def actionGroupTriggered(self, action):
1190
        if hasattr(self.actionLine, 'tag'):
1191
            self.actionLine.tag.onRejected.emit(None)
1192

    
1193
        if hasattr(self.actionVendor, 'tag'):
1194
            self.actionVendor.tag.onRejected.emit(None)
1195

    
1196
        if self.graphicsView.command is not None:
1197
            self.graphicsView.useDefaultCommand()
1198

    
1199
        for _action in self.actionGroup.actions():
1200
            _action.setChecked(False)
1201

    
1202
        action.setChecked(True)
1203

    
1204
    '''
1205
        @brief      Create Equipment
1206
        @author     Jeongwoo
1207
        @date       18.05.03
1208
        @history    2018.05.04  Jeongwoo    Add Parameter on CreateSymbolCommand
1209
    '''
1210

    
1211
    def createEquipment(self):
1212
        if not self.graphicsView.hasImage():
1213
            self.actionEquipment.setChecked(False)
1214
            self.showImageSelectionMessageBox()
1215
            return
1216
        if self.actionEquipment.isChecked():
1217
            self.graphicsView.command = CreateSymbolCommand.CreateSymbolCommand(self.graphicsView, self.itemTreeWidget,
1218
                                                                                self.symbolTreeWidget)
1219
        else:
1220
            self.graphicsView.useDefaultCommand()
1221

    
1222
    '''
1223
        @brief      Create Nozzle
1224
        @author     Jeongwoo
1225
        @date       2018.05.03
1226
        @history    2018.05.04  Jeongwoo    Add Parameter on CreateSymbolCommand
1227
    '''
1228

    
1229
    def createNozzle(self):
1230
        if not self.graphicsView.hasImage():
1231
            self.actionNozzle.setChecked(False)
1232
            self.showImageSelectionMessageBox()
1233
            return
1234
        if self.actionNozzle.isChecked():
1235
            self.graphicsView.command = CreateSymbolCommand.CreateSymbolCommand(self.graphicsView, self.itemTreeWidget,
1236
                                                                                self.symbolTreeWidget)
1237
        else:
1238
            self.graphicsView.useDefaultCommand()
1239

    
1240
    '''
1241
        @brief      Area OCR
1242
        @author     Jeongwoo
1243
        @date       18.04.18
1244
        @history    2018.05.02  Jeongwoo    Change graphicsView.command by actionOCR checked state
1245
                                            Show MessageBox when imageviewer doesn't have image
1246
    '''
1247

    
1248
    def onAreaOcr(self):
1249
        if not self.graphicsView.hasImage():
1250
            self.actionOCR.setChecked(False)
1251
            self.showImageSelectionMessageBox()
1252
            return
1253

    
1254
        if self.actionOCR.isChecked():
1255
            cmd = AreaOcrCommand.AreaOcrCommand(self.graphicsView)
1256
            cmd.onSuccess.connect(self.onRecognizeText)
1257
            cmd.onRejected.connect(self.onCommandRejected)
1258
            self.graphicsView.command = cmd
1259
        else:
1260
            self.graphicsView.useDefaultCommand()
1261

    
1262
    '''
1263
        @brief      show text recognition dialog
1264
        @author     humkyung
1265
        @date       2018.08.08
1266
    '''
1267

    
1268
    def onRecognizeText(self, x, y, width, height):
1269
        from OcrResultDialog import QOcrResultDialog
1270
        from Area import Area
1271

    
1272
        try:
1273
            app_doc_data = AppDocData.instance()
1274

    
1275
            modifiers = QApplication.keyboardModifiers()
1276
            image = self.graphicsView.image().copy(x, y, width, height)
1277
            dialog = QOcrResultDialog(self, image, QRectF(x, y, width, height),
1278
                                      format=QOcrResultDialog.Format.Table if modifiers == Qt.AltModifier else QOcrResultDialog.Format.Normal)
1279
            if modifiers == Qt.ControlModifier:
1280
                return
1281
            (res, textInfoList) = dialog.showDialog()
1282
            if QDialog.Accepted == res and textInfoList:
1283
                for textInfo in textInfoList:
1284
                    item = QEngineeringTextItem.create_text_with(self.graphicsView.scene(), textInfo)
1285
                    if item:
1286
                        item.setDefaultTextColor(Qt.blue)
1287
                        item.transfer.onRemoved.connect(self.itemRemoved)
1288

    
1289
                        area_list = app_doc_data.getAreaList()
1290
                        title_area_list = app_doc_data.getTitleBlockProperties()
1291
                        title_list = []
1292
                        if title_area_list:
1293
                            for title_area in title_area_list:
1294
                                area = Area(title_area[0])
1295
                                area.parse(title_area[2])
1296
                                title_list.append(area)
1297
                        for area in area_list + title_list:
1298
                            pt = [item.sceneBoundingRect().center().x(), item.sceneBoundingRect().center().y()]
1299
                            if area.contains(pt):
1300
                                item.area = area.name
1301
                                break
1302
                    else:
1303
                        self.addMessage.emit(MessageType.Normal, self.tr('Fail to create text.'))
1304
            elif QDialog.Accepted == res and not textInfoList:
1305
                QMessageBox.about(self.graphicsView, self.tr("Notice"), self.tr("Fail to recognize text"))
1306
        except Exception as ex:
1307
            message = 'error occurred({}) in {}:{}'.format(ex, sys.exc_info()[-1].tb_frame.f_code.co_filename,
1308
                                                           sys.exc_info()[-1].tb_lineno)
1309
            self.addMessage.emit(MessageType.Error, message)
1310

    
1311
    '''
1312
        @brief  area configuration
1313
    '''
1314

    
1315
    def areaConfiguration(self):
1316
        from ConfigurationAreaDialog import QConfigurationAreaDialog
1317
        if not self.graphicsView.hasImage():
1318
            self.showImageSelectionMessageBox()
1319
            return
1320
        self.onCommandRejected()
1321
        dlgConfigurationArea = QConfigurationAreaDialog(self)
1322
        dlgConfigurationArea.show()
1323
        dlgConfigurationArea.exec_()
1324

    
1325
    '''
1326
        @brief  configuration
1327
    '''
1328

    
1329
    def configuration(self):
1330
        from ConfigurationDialog import QConfigurationDialog
1331

    
1332
        dlgConfiguration = QConfigurationDialog(self)
1333
        if QDialog.Accepted == dlgConfiguration.exec_():
1334
            QEngineeringLineItem.LINE_TYPE_COLORS.clear()
1335
            QEngineeringInstrumentItem.INST_COLOR = None
1336

    
1337
    '''
1338
        @brief  show special item types dialog 
1339
        @author humkyung
1340
        @date   2019.08.10
1341
    '''
1342

    
1343
    def on_show_special_item_types(self):
1344
        from SpecialItemTypesDialog import QSpecialItemTypesDialog
1345

    
1346
        dlg = QSpecialItemTypesDialog(self)
1347
        dlg.exec_()
1348

    
1349
    def on_show_data_transfer(self):
1350
        """ show data transfer dialog """
1351
        from DataTransferDialog import QDataTransferDialog
1352

    
1353
        dlg = QDataTransferDialog(self)
1354
        dlg.exec_()
1355

    
1356
    def on_show_data_export(self):
1357
        """ show data export dialog """
1358
        from DataExportDialog import QDataExportDialog
1359

    
1360
        dlg = QDataExportDialog(self)
1361
        dlg.exec_()
1362

    
1363
    def on_show_eqp_datasheet_export(self):
1364
        """ show eqp datasheet export dialog """
1365
        from EqpDatasheetExportDialog import QEqpDatasheetExportDialog
1366

    
1367
        dlg = QEqpDatasheetExportDialog(self)
1368
        dlg.exec_()
1369

    
1370
    def on_show_opc_relation(self):
1371
        """ show opc relation dialog """
1372
        from OPCRelationDialog import QOPCRelationDialog
1373

    
1374
        dlg = QOPCRelationDialog(self)
1375
        dlg.exec_()
1376

    
1377
    '''
1378
        @brief  show nominal diameter dialog 
1379
        @author humkyung
1380
        @date   2018.06.28
1381
    '''
1382

    
1383
    def onShowCodeTable(self):
1384
        from CodeTableDialog import QCodeTableDialog
1385

    
1386
        dlg = QCodeTableDialog(self)
1387
        dlg.show()
1388
        dlg.exec_()
1389
        if dlg.code_area:
1390
            if dlg.code_area.scene():
1391
                self.graphicsView.scene().removeItem(dlg.code_area)
1392
        if dlg.desc_area:
1393
            if dlg.desc_area.scene():
1394
                self.graphicsView.scene().removeItem(dlg.desc_area)
1395
        self.graphicsView.useDefaultCommand()
1396

    
1397
    def onShowCustomCodeTable(self):
1398
        from CustomCodeTablesDialog import CustomCodeTablesDialog
1399

    
1400
        dlg = CustomCodeTablesDialog(self)
1401
        dlg.show()
1402
        dlg.exec_()
1403
        self.graphicsView.useDefaultCommand()
1404

    
1405
    def onShowReplaceCodeTable(self):
1406
        from CustomCodeTablesDialog import CustomCodeTablesDialog
1407

    
1408
        dlg = CustomCodeTablesDialog(self, replace=True)
1409
        dlg.show()
1410
        dlg.exec_()
1411
        self.graphicsView.useDefaultCommand()
1412

    
1413
    '''
1414
        @brief  show HMB data
1415
        @author humkyung
1416
        @date   2018.07.11
1417
    '''
1418

    
1419
    def onHMBData(self):
1420
        from HMBDialog import QHMBDialog
1421

    
1422
        dlg = QHMBDialog(self)
1423
        dlg.show()
1424
        dlg.exec_()
1425

    
1426
    '''
1427
        @brief  show line data list 
1428
        @author humkyung
1429
        @date   2018.05.03
1430
    '''
1431

    
1432
    def showItemDataList(self):
1433
        from ItemDataExportDialog import QItemDataExportDialog
1434

    
1435
        dlg = QItemDataExportDialog(self)
1436
        dlg.exec_()
1437

    
1438
    def showTextDataList(self):
1439
        '''
1440
            @brief      show all text item in scene
1441
            @author     euisung
1442
            @date       2019.04.18
1443
        '''
1444
        try:
1445
            if not self.graphicsView.hasImage():
1446
                self.showImageSelectionMessageBox()
1447
                return
1448

    
1449
            self.onCommandRejected()
1450
            dialog = QTextDataListDialog(self)
1451
            dialog.show()
1452
        except Exception as ex:
1453
            message = 'error occurred({}) in {}:{}'.format(ex, sys.exc_info()[-1].tb_frame.f_code.co_filename,
1454
                                                           sys.exc_info()[-1].tb_lineno)
1455
            self.addMessage.emit(MessageType.Error, message)
1456

    
1457
    '''
1458
        @brief  Show Image Selection Guide MessageBox
1459
        @author Jeongwoo
1460
        @date   2018.05.02
1461
    '''
1462

    
1463
    def showImageSelectionMessageBox(self):
1464
        QMessageBox.about(self.graphicsView, self.tr("Notice"), self.tr("First select image drawing"))
1465

    
1466
    def on_search_text_changed(self):
1467
        """filter symbol tree view"""
1468
        regexp = QRegExp(self.lineEditFilter.text(), Qt.CaseInsensitive, QRegExp.FixedString)
1469

    
1470
        proxy_model = self.symbolTreeWidget.model()
1471
        proxy_model.text = self.lineEditFilter.text().lower()
1472
        proxy_model.setFilterRegExp(regexp)
1473

    
1474
        self.symbolTreeWidget.expandAll()
1475

    
1476
    '''
1477
        @brief  change selected lines' type by selected line type
1478
        @author humkyung
1479
        @date   2018.06.27
1480
    '''
1481

    
1482
    def onLineTypeChanged(self, param):
1483
        lineType = self.lineComboBox.itemText(param)
1484
        selected = [item for item in self.graphicsView.scene().selectedItems() if type(item) is QEngineeringLineItem]
1485
        if selected:
1486
            for item in selected:
1487
                item.lineType = lineType
1488

    
1489
    def display_colors(self, value):
1490
        """ display colors """
1491
        from DisplayColors import DisplayColors
1492
        from DisplayColors import DisplayOptions
1493

    
1494
        DisplayColors.instance().option = DisplayOptions.DisplayByLineNo if value is True else DisplayOptions.DisplayByLineType
1495
        if hasattr(self, 'graphicsView'):
1496
            self.graphicsView.scene().update(self.graphicsView.sceneRect())
1497
            DisplayColors.instance().save_data()
1498

    
1499
    def open_image_drawing(self, drawing, force=False):
1500
        """open and display image drawing file"""
1501
        from Drawing import Drawing
1502
        from App import App
1503
        from LoadCommand import LoadCommand
1504
        import concurrent.futures as futures
1505

    
1506
        # Yield successive n-sized
1507
        # chunks from l.
1508
        def divide_chunks(l, n):
1509
            # looping till length l
1510
            for i in range(0, len(l), n):
1511
                yield l[i:i + n]
1512

    
1513
        def update_items(items):
1514
            for item in items:
1515
                # binding items
1516
                item.owner
1517
                for connector in item.connectors:
1518
                    connector.connectedItem
1519

    
1520
            return items
1521

    
1522
        try:
1523
            app_doc_data = AppDocData.instance()
1524

    
1525
            if not self.actionSave.isEnabled():
1526
                return
1527

    
1528
            if not force and self.save_drawing_if_necessary():
1529
                return
1530

    
1531
            occupied = app_doc_data.set_occupying_drawing(drawing.UID)
1532
            if occupied:
1533
                QMessageBox.about(self.graphicsView, self.tr("Notice"),
1534
                                  self.tr(f"The drawing is locked for editing by another user({occupied})"))
1535
                return
1536

    
1537
            # save alarm
1538
            self.save_alarm_enable(False)
1539

    
1540
            if hasattr(self, '_save_work_cmd'):
1541
                self._save_work_cmd.wait()
1542

    
1543
            project = app_doc_data.getCurrentProject()
1544

    
1545
            self.path = self.graphicsView.loadImageFromFile(drawing)
1546
            if os.path.isfile(self.path):
1547
                self.onCommandRejected()
1548
                app_doc_data.clear(past=drawing.UID)
1549

    
1550
                app_doc_data.setImgFilePath(self.path)
1551
                app_doc_data.activeDrawing = drawing
1552
                
1553
                #app_doc_data.activeDrawing.set_pid_source(Image.open(self.path))
1554
                self.itemTreeWidget.setCurrentPID(app_doc_data.activeDrawing.name)
1555

    
1556
                drawingList = self.treeWidgetDrawingList.topLevelItem(0)
1557
                for idx in range(drawingList.childCount()):
1558
                    child = drawingList.child(idx)
1559
                    if child.data(Qt.UserRole, 0) is drawing:
1560
                        child.setCheckState(0, Qt.Checked)
1561
                    else:
1562
                        child.setCheckState(0, Qt.Unchecked)
1563

    
1564
                try:
1565
                    self.show_Progress_bar()
1566

    
1567
                    # disconnect scene changed if signal is connected
1568
                    if self.graphicsView.scene().receivers(self.graphicsView.scene().contents_changed) > 0:
1569
                        self.graphicsView.scene().contents_changed.disconnect()
1570

    
1571
                    SymbolSvgItem.DOCUMENTS.clear()
1572

    
1573
                    # load data
1574
                    cmd = LoadCommand()
1575
                    cmd.display_message.connect(self.onAddMessage)
1576
                    cmd.set_maximum.connect(self.progress.setMaximum)
1577
                    cmd.show_progress.connect(self.progress.setValue)
1578
                    cmd.execute((drawing, self.graphicsView.scene()),
1579
                                symbol=True, text=True, line=True, unknown=True, package=True, update=True)
1580
                    # up to here
1581

    
1582
                    """"update item tree widget"""
1583
                    line_no_items = [item for item in self.graphicsView.scene().items()
1584
                                     if type(item) is QEngineeringLineNoTextItem]
1585
                    for line_no in line_no_items:
1586
                        line_no_tree_item = self.itemTreeWidget.addTreeItem(self.itemTreeWidget.root, line_no)
1587
                        for run in line_no.runs:
1588
                            for run_item in run.items:
1589
                                if issubclass(type(run_item), SymbolSvgItem):
1590
                                    self.init_add_tree_item(line_no_tree_item, run_item)
1591

    
1592
                    line_no_items = [item for item in self.graphicsView.scene().items()
1593
                                     if type(item) is QEngineeringTrimLineNoTextItem]
1594
                    for line_no in line_no_items:
1595
                        line_no_tree_item = self.itemTreeWidget.addTreeItem(self.itemTreeWidget.root, line_no)
1596
                        for run in line_no.runs:
1597
                            for run_item in run.items:
1598
                                if issubclass(type(run_item), SymbolSvgItem):
1599
                                    self.init_add_tree_item(line_no_tree_item, run_item)
1600

    
1601
                    for trim_line_no in app_doc_data.tracerLineNos:
1602
                        line_no_tree_item = self.itemTreeWidget.addTreeItem(self.itemTreeWidget.root, trim_line_no)
1603
                        for run in trim_line_no.runs:
1604
                            for run_item in run.items:
1605
                                if issubclass(type(run_item), SymbolSvgItem):
1606
                                    self.init_add_tree_item(line_no_tree_item, run_item)
1607

    
1608
                    self.itemTreeWidget.update_item_count()
1609
                    self.itemTreeWidget.expandAll()
1610
                    """up to here"""
1611

    
1612
                    """update scene"""
1613
                    for item in self._scene.items():
1614
                        item.setVisible(True)
1615

    
1616
                    self._scene.update(self._scene.sceneRect())
1617

    
1618
                    """
1619
                    # old open drawing
1620
                    path = os.path.join(app_doc_data.getCurrentProject().getTempPath(), app_doc_data.imgName + '.xml')
1621
                    configs = app_doc_data.getConfigs('Data Load', 'Xml First')
1622
                    if configs and int(configs[0].value) >= 1 and os.path.isfile(path):
1623
                        self.load_recognition_result_from_xml(drawing)
1624
                    elif configs and int(configs[0].value) <= 1:
1625
                        self.load_drawing(app_doc_data.activeDrawing)
1626
                    """
1627

    
1628
                    self.display_number_of_items()
1629
                    # connect scene changed signal
1630
                    self.graphicsView.scene().contents_changed.connect(self.scene_changed)
1631
                finally:
1632
                    if hasattr(self, 'progress'):
1633
                        self.progress.setValue(self.progress.maximum())
1634

    
1635
                self.changeViewCheckedState(True)
1636
                self.setWindowTitle(self.title)
1637
                self.fitWindow(drawing.view_rect)
1638

    
1639
                # save alarm
1640
                self.save_alarm_enable(True, True)
1641
        except Exception as ex:
1642
            message = f"error occurred({repr(ex)}) in {sys.exc_info()[-1].tb_frame.f_code.co_filename}:" \
1643
                      f"{sys.exc_info()[-1].tb_lineno}"
1644
            self.addMessage.emit(MessageType.Error, message)
1645

    
1646
        return self.path
1647

    
1648
    def save_alarm_enable(self, enable, init=False):
1649
        from datetime import datetime
1650

    
1651
        try:
1652
            app_doc_data = AppDocData.instance()
1653
            configs = app_doc_data.getConfigs('Data Save', 'Time')
1654
            time_min = int(configs[0].value) if 1 == len(configs) else 0
1655

    
1656
            if enable and time_min > 0:
1657
                if not self.save_timer:
1658
                    self.save_timer = QTimer()
1659
                    self.save_timer.timeout.connect(self.save_alarm)
1660
                    self.save_timer.setInterval(60000)
1661

    
1662
                if init:
1663
                    self.save_timer._init_time = datetime.now()
1664
                    self.save_timer._stop_time = None
1665
                    self.save_timer._interval_time = datetime.now() - datetime.now()
1666

    
1667
                if self.save_timer._stop_time:
1668
                    self.save_timer._interval_time = datetime.now() - self.save_timer._stop_time
1669
                
1670
                #if 60000 * time_min != self.save_timer.interval():
1671
                #    self.save_timer.setInterval(60000)
1672

    
1673
                self.save_timer.start()
1674
            else:
1675
                if self.save_timer:
1676
                    self.save_timer.stop()
1677
                    self.save_timer._stop_time = datetime.now()
1678
        
1679
        except Exception as ex:
1680
            message = f"error occurred({repr(ex)}) in {sys.exc_info()[-1].tb_frame.f_code.co_filename}:" \
1681
                      f"{sys.exc_info()[-1].tb_lineno}"
1682
            self.addMessage.emit(MessageType.Error, message)
1683

    
1684
    def save_alarm(self):
1685
        from datetime import datetime
1686

    
1687
        app_doc_data = AppDocData.instance()
1688
        configs = app_doc_data.getConfigs('Data Save', 'Time')
1689
        time_min = int(configs[0].value) if 1 == len(configs) else 0
1690

    
1691
        self.save_timer.stop()
1692
        if self.graphicsView.hasFocus() and (datetime.now() - self.save_timer._init_time - self.save_timer._interval_time).seconds > time_min * 60:
1693
            QMessageBox.information(self, self.tr('Information'), self.tr('Please save Drawing'))
1694
            self.save_timer._init_time = datetime.now()
1695
            self.save_timer._interval_time = datetime.now() - datetime.now()
1696
        self.save_timer.start()
1697

    
1698
    def export_as_svg(self):
1699
        """export scene to svg file"""
1700
        from ExportCommand import ExportCommand
1701

    
1702
        options = QFileDialog.Options()
1703
        options |= QFileDialog.DontUseNativeDialog
1704
        file_path, _ = QFileDialog.getSaveFileName(self, "Export as svg", os.getcwd(), "svg file(*.svg)",
1705
                                                   options=options)
1706
        if file_path:
1707
            cmd = ExportCommand(self.graphicsView.scene(), 'svg')
1708
            cmd.display_message.connect(self.onAddMessage)
1709
            if cmd.execute(file_path):
1710
                QMessageBox.information(self, self.tr('Information'), self.tr('Successfully export to svg file'))
1711
            else:
1712
                QMessageBox.information(self, self.tr('Error'), self.tr('Fail to export to svg file'))
1713

    
1714
    def export_as_xml(self):
1715
        pass
1716

    
1717
    def export_as_image(self):
1718
        """export scene to image file"""
1719
        from ExportCommand import ExportCommand
1720

    
1721
        options = QFileDialog.Options()
1722
        options |= QFileDialog.DontUseNativeDialog
1723
        file_path, _ = QFileDialog.getSaveFileName(self, "Export as png", os.getcwd(), "png file(*.png)",
1724
                                                   options=options)
1725
        if file_path:
1726
            try:
1727
                # hide image drawing
1728
                self.onViewImageDrawing(False)
1729

    
1730
                cmd = ExportCommand(self.graphicsView.scene(), 'image')
1731
                cmd.display_message.connect(self.onAddMessage)
1732

    
1733
                if cmd.execute(file_path):
1734
                    QMessageBox.information(self, self.tr('Information'), self.tr('Successfully export to image file'))
1735
                else:
1736
                    QMessageBox.information(self, self.tr('Error'), self.tr('Fail to export to image file'))
1737
            finally:
1738
                if self.actionImage_Drawing.isChecked():
1739
                    self.onViewImageDrawing(True)
1740
                    self.actionImage_Drawing.setChecked(True)
1741

    
1742
    def show_Progress_bar(self):
1743
        """ show progress bar """
1744
        self.progress = QProgressDialog(self.tr("Please wait for a while"), self.tr("Cancel"), 0, 100,
1745
                                        self) if not hasattr(self, 'progress') else self.progress
1746
        self.progress.setWindowModality(Qt.WindowModal)
1747
        self.progress.setAutoReset(True)
1748
        self.progress.setAutoClose(True)
1749
        self.progress.setMinimum(0)
1750
        self.progress.setMaximum(100)
1751
        self.progress.resize(600, 100)
1752
        self.progress.setWindowTitle(self.tr("Reading file..."))
1753
        self.progress.show()
1754

    
1755
    def changeViewCheckedState(self, checked, clear=True):
1756
        '''
1757
            @brief      change view checked state
1758
            @author     euisung
1759
            @date       2019.03.06
1760
        '''
1761
        # self.actionImage_Drawing.setChecked(checked)
1762
        self.actionViewText.setChecked(checked)
1763
        self.actionViewSymbol.setChecked(checked)
1764
        self.actionViewLine.setChecked(checked)
1765
        self.actionViewUnknown.setChecked(checked)
1766
        self.actionViewInconsistency.setChecked(checked)
1767
        self.actionViewVendor_Area.setChecked(not checked)
1768
        self.actionDrawing_Only.setChecked(not checked)
1769
        if clear:
1770
            self.tableWidgetInconsistency.clearContents()
1771
            self.tableWidgetInconsistency.setRowCount(0)
1772

    
1773
    def onViewDrawingOnly(self, isChecked):
1774
        '''
1775
            @brief  visible/invisible except image drawing
1776
            @author euisung
1777
            @date   2019.04.22
1778
        '''
1779
        self.changeViewCheckedState(not isChecked, False)
1780
        for item in self.graphicsView.scene().items():
1781
            if type(item) is not QGraphicsPixmapItem:
1782
                item.setVisible(not isChecked)
1783

    
1784
    '''
1785
        @brief  visible/invisible image drawing
1786
        @author humkyung
1787
        @date   2018.06.25
1788
    '''
1789

    
1790
    def onViewImageDrawing(self, isChecked):
1791
        for item in self.graphicsView.scene().items():
1792
            if type(item) is QGraphicsPixmapItem:
1793
                item.setVisible(isChecked)
1794
                break
1795

    
1796
    def onViewText(self, checked):
1797
        """visible/invisible text"""
1798
        selected = [item for item in self.graphicsView.scene().items() if issubclass(type(item), QEngineeringTextItem)
1799
                    and type(item) is not QEngineeringLineNoTextItem]
1800
        for item in selected:
1801
            item.setVisible(checked)
1802

    
1803
    def onViewSymbol(self, checked):
1804
        """visible/invisible symbol"""
1805
        selected = [item for item in self.graphicsView.scene().items() if
1806
                    (issubclass(type(item), SymbolSvgItem) and type(item) is not QEngineeringErrorItem)]
1807
        for item in selected:
1808
            item.setVisible(checked)
1809

    
1810
    def onViewLine(self, checked):
1811
        """visible/invisible line"""
1812
        selected = [item for item in self.graphicsView.scene().items() if type(item) is QEngineeringLineItem]
1813
        for item in selected:
1814
            item.setVisible(checked)
1815

    
1816
    def onViewInconsistency(self, isChecked):
1817
        '''
1818
            @brief  visible/invisible Inconsistency
1819
            @author euisung
1820
            @date   2019.04.03
1821
        '''
1822
        selected = [item for item in self.graphicsView.scene().items() if type(item) is QEngineeringErrorItem]
1823
        for item in selected:
1824
            item.setVisible(isChecked)
1825

    
1826
    '''
1827
        @brief  visible/invisible Unknown 
1828
        @author humkyung
1829
        @date   2018.06.28
1830
    '''
1831

    
1832
    def onViewUnknown(self, isChecked):
1833
        selected = [item for item in self.graphicsView.scene().items() if type(item) is QEngineeringUnknownItem]
1834
        for item in selected:
1835
            item.setVisible(isChecked)
1836

    
1837
    def onViewVendorArea(self, isChecked):
1838
        '''
1839
            @brief  visible/invisible Vendor Area
1840
            @author euisung
1841
            @date   2019.04.29
1842
        '''
1843
        selected = [item for item in self.graphicsView.scene().items() if issubclass(type(item), QEngineeringVendorItem)]
1844
        for item in selected:
1845
            item.setVisible(isChecked)
1846

    
1847
    '''
1848
        @brief  create a symbol
1849
        @history    2018.05.02  Jeongwoo    Change return value of QSymbolEditorDialog (Single variable → Tuple)
1850
                                            Add SymbolSvgItem
1851
                    2018.05.03  Jeongwoo    Change method to draw Svg Item on Scene (svg.addSvgItemToScene)
1852
                                            Change method to make svg and image path
1853
                    2018.06.08  Jeongwoo    Add Paramter on SymbolSvgItem.buildItem()
1854
    '''
1855
    def onCreateSymbolClicked(self):
1856
        selected = [item for item in self.graphicsView.scene().selectedItems() if issubclass(type(item), QEngineeringVendorItem)]
1857
        if len(selected) == 1:
1858
            symbol_image = AppDocData.instance().activeDrawing.image_origin
1859
            rect = selected[0].sceneBoundingRect()
1860

    
1861
            points = []
1862
            for conn in selected[0].connectors:
1863
                points.append([round(conn.center()[0] - rect.x()), round(conn.center()[1] - rect.y())])
1864
            poly = np.array(points, np.int32)
1865

    
1866
            #mask = np.zeros((int(rect.height()), int(rect.width())))
1867
            #cv2.fillPoly(mask, [poly], (255))
1868
            #poly_copied = np.multiply(mask, symbol_image[round(rect.y()):round(rect.y() + rect.height()),
1869
            #                   round(rect.x()):round(rect.x() + rect.width())])
1870
            #cv2.fillPoly(mask,[poly],0)
1871
            #src2 = np.multiply(mask,src2)
1872

    
1873
            mask = np.ones((int(rect.height()), int(rect.width())), dtype=np.uint8) * 255
1874
            cv2.fillPoly(mask, [poly], (0))
1875
            sym_img = cv2.bitwise_or(mask, symbol_image[int(rect.y()):int(rect.y()) + int(rect.height()), int(rect.x()):int(rect.x()) + int(rect.width())])
1876
            sym_img = cv2.merge((sym_img, sym_img, sym_img))
1877

    
1878
            h, w, c = sym_img.shape
1879
            qImg = QImage(sym_img.data, w, h, w * c, QImage.Format_RGB888)
1880
            #pixmap = QPixmap.fromImage(qImg)
1881

    
1882
            self.onAreaSelected(None, None, None, None, package=qImg, position=rect.topLeft(), package_item=selected[0])
1883
        else:
1884
            cmd = FenceCommand.FenceCommand(self.graphicsView)
1885
            cmd.onSuccess.connect(self.onAreaSelected)
1886
            self.graphicsView.command = cmd
1887
            QApplication.setOverrideCursor(Qt.CrossCursor)
1888

    
1889
    '''
1890
        @brief      show SymbolEditorDialog with image selected by user
1891
        @author     humkyung
1892
        @date       2018.07.20
1893
    '''
1894

    
1895
    def onAreaSelected(self, x, y, width, height, package=False, position=None, package_item=None):
1896
        try:
1897
            image = self.graphicsView.image()
1898
            if image is not None:
1899
                if not package:
1900
                    symbolEditorDialog = SymbolEditorDialog.QSymbolEditorDialog(self, image.copy(x, y, width, height),
1901
                                                                                AppDocData.instance().getCurrentProject())
1902
                else:
1903
                    symbolEditorDialog = SymbolEditorDialog.QSymbolEditorDialog(self, package,
1904
                                                                                AppDocData.instance().getCurrentProject(), package=True)
1905
                (isAccepted, isImmediateInsert, offsetX, offsetY, newSym) = symbolEditorDialog.showDialog()
1906
                # TODO: not initialize symbol tree view when user reject to create a new symbol
1907
                self.symbolTreeWidget.initSymbolTreeView()
1908
                if isAccepted:
1909
                    if isImmediateInsert:
1910
                        svg = QtImageViewer.createSymbolObject(newSym.getName())
1911
                        offsetX, offsetY = [int(point) for point in newSym.getOriginalPoint().split(',')]
1912
                        QtImageViewer.matchSymbolToLine(self.graphicsView.scene(), svg, QPoint(position.x() + offsetX, position.y() + offsetY))
1913

    
1914
                        package_item.transfer.onRemoved.emit(package_item)
1915
        finally:
1916
            self.onCommandRejected()
1917
            QApplication.restoreOverrideCursor()
1918

    
1919
    def on_make_label_data(self):
1920
        """ make label data from symbol info """
1921
        from xml.etree.ElementTree import Element, SubElement, dump, ElementTree, parse
1922

    
1923
        if not self.graphicsView.hasImage():
1924
            self.showImageSelectionMessageBox()
1925
            return
1926

    
1927
        app_doc_data = AppDocData.instance()
1928
        project = app_doc_data.getCurrentProject()
1929

    
1930
        smalls = []
1931
        bigs = []
1932

    
1933
        symbol_list = app_doc_data.getTargetSymbolList(all=True)
1934
        for symbol in symbol_list:
1935
            if symbol.width and symbol.height:
1936
                if symbol.width > 300 or symbol.height > 300:
1937
                    bigs.append(symbol.getName())
1938
                else:
1939
                    smalls.append(symbol.getName())
1940

    
1941
        symbols = [item for item in self.graphicsView.scene().items() if issubclass(type(item), SymbolSvgItem)]
1942
        names = [smalls, bigs]
1943

    
1944
        img = app_doc_data.activeDrawing.image_origin
1945

    
1946
        small_size = 500
1947
        big_size = 850
1948

    
1949
        save_path = project.getTrainingSymbolFilePath()
1950

    
1951
        index = 0
1952
        for size in [small_size, big_size]:
1953
            offsets = [0, int(size / 2)]
1954

    
1955
            width, height = img.shape[1], img.shape[0]
1956
            width_count, height_count = width // size + 2, height // size + 2
1957
            b_width, b_height = width_count * size, height_count * size
1958
            b_img = np.zeros((b_height, b_width), np.uint8) + 255
1959
            b_img[:height, :width] = img[:, :]
1960

    
1961
            for offset in offsets:
1962
                for row in range(height_count):
1963
                    for col in range(width_count):
1964
                        x, y = col * size + offset, row * size + offset
1965
                        tile_rect = QRectF(x, y, size, size)
1966
                        tile_symbols = []
1967
                        for symbol in [symbol for symbol in symbols if symbol.name in names[index]]:
1968
                            if tile_rect.contains(symbol.sceneBoundingRect()):
1969
                                tile_symbols.append(symbol)
1970
                                symbols.remove(symbol)
1971

    
1972
                        if tile_symbols:
1973
                            training_uid = str(uuid.uuid4())
1974
                            training_image_path = os.path.join(save_path, training_uid + '.png')
1975
                            training_xml_path = os.path.join(save_path, training_uid + '.xml')
1976

    
1977
                            # save image
1978
                            #_img = b_img[round(tile_rect.top()):round(tile_rect.bottom()),
1979
                            #       round(tile_rect.left()):round(tile_rect.right())]
1980
                            #cv2.imwrite(training_image_path, _img)
1981
                            _img = self.graphicsView.image().copy(round(tile_rect.left()), round(tile_rect.top()), round(tile_rect.width()), round(tile_rect.height()))
1982
                            _img.save(training_image_path)
1983

    
1984
                            # save label
1985
                            xml = Element('annotation')
1986
                            SubElement(xml, 'folder').text = 'None'
1987
                            SubElement(xml, 'filename').text = os.path.basename(save_path)
1988

    
1989
                            pathNode = Element('path')
1990
                            pathNode.text = save_path.replace('/', '\\')
1991
                            xml.append(pathNode)
1992

    
1993
                            sourceNode = Element('source')
1994
                            databaseNode = Element('database')
1995
                            databaseNode.text = 'Unknown'
1996
                            sourceNode.append(databaseNode)
1997
                            xml.append(sourceNode)
1998

    
1999
                            sizeNode = Element('size')
2000
                            widthNode = Element('width')
2001
                            widthNode.text = str(int(tile_rect.width()))
2002
                            sizeNode.append(widthNode)
2003
                            heightNode = Element('height')
2004
                            heightNode.text = str(int(tile_rect.height()))
2005
                            sizeNode.append(heightNode)
2006
                            depthNode = Element('depth')
2007
                            depthNode.text = '3'
2008
                            sizeNode.append(depthNode)
2009
                            xml.append(sizeNode)
2010

    
2011
                            segmentedNode = Element('segmented')
2012
                            segmentedNode.text = '0'
2013
                            xml.append(segmentedNode)
2014

    
2015
                            labelContent = []
2016
                            counts = {}
2017
                            for item in tile_symbols:
2018
                                rect = item.sceneBoundingRect()
2019
                                label, xMin, yMin, xMax, yMax = item.name, int(rect.x() - 5 - x), int(rect.y() - 5 - y), int(rect.x() + rect.width() + 5 - x), int(rect.y() + rect.height() + 5 - y)
2020
                                xMin = xMin if xMin > 0 else 0
2021
                                yMin = yMin if yMin > 0 else 0
2022
                                xMax = xMax if xMax < size else size
2023
                                yMax = yMax if yMax < size else size
2024

    
2025
                                if label == 'None' or label == '':
2026
                                    continue
2027
                                if label not in labelContent:
2028
                                    labelContent.append(label)
2029
                                    counts[label] = 1
2030
                                else:
2031
                                    counts[label] = counts[label] + 1
2032

    
2033
                                objectNode = Element('object')
2034
                                nameNode = Element('name')
2035
                                nameNode.text = label
2036
                                objectNode.append(nameNode)
2037
                                poseNode = Element('pose')
2038
                                poseNode.text = 'Unspecified'
2039
                                objectNode.append(poseNode)
2040
                                truncatedNode = Element('truncated')
2041
                                truncatedNode.text = '0'
2042
                                objectNode.append(truncatedNode)
2043
                                difficultNode = Element('difficult')
2044
                                difficultNode.text = '0'
2045
                                objectNode.append(difficultNode)
2046

    
2047
                                bndboxNode = Element('bndbox')
2048
                                xminNode = Element('xmin')
2049
                                xminNode.text = str(xMin)
2050
                                bndboxNode.append(xminNode)
2051
                                yminNode = Element('ymin')
2052
                                yminNode.text = str(yMin)
2053
                                bndboxNode.append(yminNode)
2054
                                xmaxNode = Element('xmax')
2055
                                xmaxNode.text = str(xMax)
2056
                                bndboxNode.append(xmaxNode)
2057
                                ymaxNode = Element('ymax')
2058
                                ymaxNode.text = str(yMax)
2059
                                bndboxNode.append(ymaxNode)
2060
                                objectNode.append(bndboxNode)
2061

    
2062
                                xml.append(objectNode)
2063

    
2064
                            ElementTree(xml).write(training_xml_path)
2065

    
2066
            index += 1
2067

    
2068
        QMessageBox.about(self, self.tr("Notice"), self.tr('Successfully applied. '))
2069

    
2070
    '''
2071
        @brief      create a line
2072
        @author     humkyung
2073
        @history    Jeongwoo 2018.05.10 Change method for Checkable action
2074
    '''
2075
    def onPlaceLine(self):
2076
        if not self.graphicsView.hasImage():
2077
            self.actionLine.setChecked(False)
2078
            self.showImageSelectionMessageBox()
2079
            return
2080

    
2081
        self.actionLine.setChecked(True)
2082
        if not hasattr(self.actionLine, 'tag'):
2083
            self.actionLine.tag = PlaceLineCommand.PlaceLineCommand(self.graphicsView)
2084
            self.actionLine.tag.onSuccess.connect(self.onLineCreated)
2085
            self.actionLine.tag.onRejected.connect(self.onCommandRejected)
2086

    
2087
        self.graphicsView.command = self.actionLine.tag
2088

    
2089
    '''
2090
        @brief      add created lines to scene
2091
        @author     humkyung
2092
        @date       2018.07.23
2093
    '''
2094

    
2095
    def onLineCreated(self):
2096
        from EngineeringConnectorItem import QEngineeringConnectorItem
2097
        from LineDetector import LineDetector
2098

    
2099
        try:
2100
            app_doc_data = AppDocData.instance()
2101

    
2102
            count = len(self.actionLine.tag._polyline._vertices)
2103
            if count > 1:
2104
                items = []
2105

    
2106
                detector = LineDetector(None)
2107

    
2108
                if not self.actionLine.tag.line_type:
2109
                    line_type = self.lineComboBox.currentText()
2110
                else:
2111
                    if not (QEngineeringLineItem.check_piping(self.actionLine.tag.line_type) ^ QEngineeringLineItem.check_piping(self.lineComboBox.currentText())):
2112
                        line_type = self.lineComboBox.currentText()
2113
                    else:
2114
                        line_type = self.actionLine.tag.line_type
2115
                for index in range(count - 1):
2116
                    start = self.actionLine.tag._polyline._vertices[index]
2117
                    end = self.actionLine.tag._polyline._vertices[index + 1]
2118

    
2119
                    lineItem = QEngineeringLineItem(vertices=[start, end])
2120
                    lineItem.transfer.onRemoved.connect(self.itemRemoved)
2121
                    lineItem.lineType = line_type
2122
                    if items:
2123
                        lineItem.connect_if_possible(items[-1], 5)
2124
                    else:
2125
                        pt = lineItem.start_point()
2126
                        selected = [item for item in self.graphicsView.scene().items(QPointF(pt[0], pt[1])) if
2127
                                    type(item) is QEngineeringConnectorItem or type(item) is QEngineeringLineItem]
2128
                        if selected and selected[0] is not lineItem:
2129
                            if type(selected[0]) is QEngineeringConnectorItem:
2130
                                lineItem.connect_if_possible(selected[0].parent, 5)
2131
                            else:
2132
                                detector.connectLineToLine(selected[0], lineItem, 5)
2133

    
2134
                    items.append(lineItem)
2135
                    self.graphicsView.scene().addItem(lineItem)
2136
                    #app_doc_data.lines.append(lineItem)
2137

    
2138
                pt = items[-1].end_point()
2139
                selected = [item for item in self.graphicsView.scene().items(QPointF(pt[0], pt[1])) if
2140
                            (type(item) is QEngineeringConnectorItem and item.parentItem() is not items[-1]) or
2141
                            (type(item) is QEngineeringLineItem and item is not items[-1])]
2142
                if selected and selected[0] is not items[-1]:
2143
                    if type(selected[0]) is QEngineeringConnectorItem:
2144
                        items[-1].connect_if_possible(selected[0].parent, 5)
2145
                    else:
2146
                        detector.connectLineToLine(selected[0], items[-1], 5)
2147

    
2148
                self._scene.undo_stack.push(CreateCommand(self._scene, items))
2149
        finally:
2150
            self.graphicsView.scene().removeItem(self.actionLine.tag._polyline)
2151
            self.actionLine.tag.reset()
2152

    
2153
    '''
2154
        @brief      refresh scene
2155
        @author     humkyung
2156
        @date       2018.07.23
2157
    '''
2158

    
2159
    def onCommandRejected(self, cmd=None):
2160
        try:
2161
            if type(cmd) is PlaceLineCommand.PlaceLineCommand:
2162
                if self.actionLine.tag._polyline:
2163
                    self.graphicsView.scene().removeItem(self.actionLine.tag._polyline)
2164
                self.graphicsView.scene().update()
2165
                self.actionLine.tag.reset()
2166

    
2167
                self.actionLine.setChecked(False)
2168
            elif type(cmd) is AreaZoomCommand.AreaZoomCommand:
2169
                self.actionZoom.setChecked(False)
2170
            elif type(cmd) is AreaOcrCommand.AreaOcrCommand:
2171
                self.actionOCR.setChecked(False)
2172
            elif type(cmd) is PlacePolygonCommand.PlacePolygonCommand:
2173
                self.actionVendor.setChecked(False)
2174
            else:
2175
                if hasattr(self.actionLine, 'tag') and self.actionLine.tag._polyline:
2176
                    self.graphicsView.scene().removeItem(self.actionLine.tag._polyline)
2177
                    self.graphicsView.scene().update()
2178
                    self.actionLine.tag.reset()
2179
                if hasattr(self.actionVendor, 'tag') and self.actionVendor.tag._polyline:
2180
                    self.graphicsView.scene().removeItem(self.actionVendor.tag._polyline)
2181
                    self.graphicsView.scene().update()
2182
                    self.actionVendor.tag.reset()
2183
                self.actionLine.setChecked(False)
2184
                self.actionZoom.setChecked(False)
2185
                self.actionOCR.setChecked(False)
2186
                self.actionVendor.setChecked(False)
2187
        finally:
2188
            self.graphicsView.useDefaultCommand()
2189

    
2190
    '''
2191
        @brief      restore to default command when user press Escape key
2192
        @author     humkyung 
2193
        @date       2018.08.09
2194
        
2195
    '''
2196

    
2197
    def keyPressEvent(self, event):
2198
        try:
2199
            if event.key() == Qt.Key_Escape:
2200
                checked = self.actionGroup.checkedAction()
2201
                if checked:
2202
                    checked.setChecked(False)
2203
                    self.graphicsView.useDefaultCommand()
2204
            elif event.key() == Qt.Key_1:
2205
                if self.actionImage_Drawing.isChecked():
2206
                    self.onViewImageDrawing(False)
2207
                    self.actionImage_Drawing.setChecked(False)
2208
                else:
2209
                    self.onViewImageDrawing(True)
2210
                    self.actionImage_Drawing.setChecked(True)
2211
            elif event.key() == Qt.Key_2:
2212
                if self.actionViewText.isChecked():
2213
                    self.onViewText(False)
2214
                    self.actionViewText.setChecked(False)
2215
                else:
2216
                    self.onViewText(True)
2217
                    self.actionViewText.setChecked(True)
2218
            elif event.key() == Qt.Key_3:
2219
                if self.actionViewSymbol.isChecked():
2220
                    self.onViewSymbol(False)
2221
                    self.actionViewSymbol.setChecked(False)
2222
                else:
2223
                    self.onViewSymbol(True)
2224
                    self.actionViewSymbol.setChecked(True)
2225
            elif event.key() == Qt.Key_4:
2226
                if self.actionViewLine.isChecked():
2227
                    self.onViewLine(False)
2228
                    self.actionViewLine.setChecked(False)
2229
                else:
2230
                    self.onViewLine(True)
2231
                    self.actionViewLine.setChecked(True)
2232
            elif event.key() == Qt.Key_5:
2233
                if self.actionViewUnknown.isChecked():
2234
                    self.onViewUnknown(False)
2235
                    self.actionViewUnknown.setChecked(False)
2236
                else:
2237
                    self.onViewUnknown(True)
2238
                    self.actionViewUnknown.setChecked(True)
2239
            elif event.key() == Qt.Key_6:
2240
                if self.actionViewInconsistency.isChecked():
2241
                    self.onViewInconsistency(False)
2242
                    self.actionViewInconsistency.setChecked(False)
2243
                else:
2244
                    self.onViewInconsistency(True)
2245
                    self.actionViewInconsistency.setChecked(True)
2246
            elif event.key() == Qt.Key_7:
2247
                if self.actionViewVendor_Area.isChecked():
2248
                    self.onViewVendorArea(False)
2249
                    self.actionViewVendor_Area.setChecked(False)
2250
                else:
2251
                    self.onViewVendorArea(True)
2252
                    self.actionViewVendor_Area.setChecked(True)
2253
            elif event.key() == 96:  # '`' key
2254
                if self.actionDrawing_Only.isChecked():
2255
                    self.onViewDrawingOnly(False)
2256
                    self.actionDrawing_Only.setChecked(False)
2257
                else:
2258
                    self.onViewDrawingOnly(True)
2259
                    self.actionDrawing_Only.setChecked(True)
2260
            elif event.key() == Qt.Key_M:  # merge text as vertical
2261
                from TextInfo import TextInfo
2262

    
2263
                textItems = [text for text in self.graphicsView.scene().selectedItems() if
2264
                             issubclass(type(text), QEngineeringTextItem)]
2265
                if not textItems or len(textItems) is 1:
2266
                    return
2267

    
2268
                angle = None
2269
                for item in textItems:
2270
                    if angle is None:
2271
                        angle = item.angle
2272
                    else:
2273
                        if angle != item.angle:
2274
                            return
2275

    
2276
                modifiers = QApplication.keyboardModifiers()
2277
                enter_or_space = ' ' if modifiers == Qt.ControlModifier else '\n'
2278
                x_or_y = 0 if (modifiers == Qt.ControlModifier and angle == 0) or (modifiers != Qt.ControlModifier and angle == 1.57) else 1
2279

    
2280
                textItems = sorted(textItems, key=lambda text: text.loc[x_or_y]) if textItems[0].angle == 0 else ( \
2281
                    sorted(textItems, key=lambda text: text.loc[x_or_y]) if textItems[0].angle == 1.57 else ( \
2282
                        sorted(textItems, key=lambda text: text.loc[x_or_y], reverse=True) if textItems[0].angle == 4.71 else \
2283
                            sorted(textItems, key=lambda text: text.loc[x_or_y], reverse=True)))
2284

    
2285
                if textItems[0].angle == 1.57 and modifiers == Qt.ControlModifier:
2286
                    textItems.reverse()
2287

    
2288
                minX = sys.maxsize
2289
                minY = sys.maxsize
2290
                maxX = 0
2291
                maxY = 0
2292
                newText = ''
2293

    
2294
                for text in textItems:
2295
                    if text.loc[0] < minX: minX = text.loc[0]
2296
                    if text.loc[1] < minY: minY = text.loc[1]
2297
                    if text.loc[0] + text.size[0] > maxX: maxX = text.loc[0] + text.size[0]
2298
                    if text.loc[1] + text.size[1] > maxY: maxY = text.loc[1] + text.size[1]
2299
                    newText = newText + text.text() + enter_or_space
2300
                    text.transfer.onRemoved.emit(text)
2301
                newText = newText[:-1]
2302

    
2303
                textInfo = TextInfo(newText, minX, minY, maxX - minX, maxY - minY, textItems[0].angle)
2304
                x = textInfo.getX()
2305
                y = textInfo.getY()
2306
                angle = textInfo.getAngle()
2307
                text = textInfo.getText()
2308
                width = textInfo.getW()
2309
                height = textInfo.getH()
2310
                item = TextItemFactory.instance().createTextItem(textInfo)
2311
                if item is not None:
2312
                    item.loc = [x, y]
2313
                    item.size = (width, height)
2314
                    item.angle = angle
2315
                    item.setDefaultTextColor(Qt.blue)
2316
                    item.addTextItemToScene(self.graphicsView.scene())
2317
                    item.transfer.onRemoved.connect(self.itemRemoved)
2318
            elif event.key() == Qt.Key_D:
2319
                # pop up development toolkit dialog
2320
                from DevelopmentToolkitDialog import QDevelopmentToolkitDialog
2321

    
2322
                modifiers = QApplication.keyboardModifiers()
2323
                if modifiers == Qt.ControlModifier:
2324
                    dlg = QDevelopmentToolkitDialog(self, self.graphicsView)
2325
                    dlg.show()
2326
            elif event.key() == Qt.Key_I:
2327
                # insert symbol item that is selected symbol in tree to main window if symbol already selected on main window, replace
2328
                index = self.symbolTreeWidget.currentIndex()
2329
                proxy_model = self.symbolTreeWidget.model()
2330
                items = [proxy_model.sourceModel().itemFromIndex(proxy_model.mapToSource(index))]
2331
                if items and hasattr(items[0], 'svgFilePath'):
2332
                    symData = items[0].data(self.symbolTreeWidget.TREE_DATA_ROLE)
2333
                    symName = symData.getName()
2334
                else:
2335
                    return
2336

    
2337
                symbolItems = [symbol for symbol in self.graphicsView.scene().selectedItems() if
2338
                               issubclass(type(symbol), SymbolSvgItem)]
2339
                old_symbol = None
2340
                if symbolItems and len(symbolItems) is 1:
2341
                    old_symbol = symbolItems[0]
2342
                    #scenePos = QPoint(old_symbol.origin[0], old_symbol.origin[1])
2343
                    scenePos = old_symbol.mapToScene(old_symbol.transformOriginPoint())
2344
                    old_symbol.transfer.onRemoved.emit(old_symbol)
2345
                else:
2346
                    scenePos = self.current_pos
2347

    
2348
                svg = QtImageViewer.createSymbolObject(symName)
2349
                QtImageViewer.matchSymbolToLine(self.graphicsView.scene(), svg, scenePos)
2350

    
2351
                if old_symbol and svg:
2352
                    from ReplaceCommand import ReplaceCommand
2353

    
2354
                    cmd = ReplaceCommand(self.graphicsView.scene(), old_symbol, svg)
2355
                    self._scene.undo_stack.push(cmd)
2356
                    return
2357
            elif event.key() == Qt.Key_J:
2358
                # insert and connect symbol item that is selected symbol in tree to selected symbol
2359
                index = self.symbolTreeWidget.currentIndex()
2360
                proxy_model = self.symbolTreeWidget.model()
2361
                items = [proxy_model.sourceModel().itemFromIndex(proxy_model.mapToSource(index))]
2362
                if items and hasattr(items[0], 'svgFilePath'):
2363
                    symData = items[0].data(self.symbolTreeWidget.TREE_DATA_ROLE)
2364
                    symName = symData.getName()
2365
                else:
2366
                    return
2367

    
2368
                symbolItems = [symbol for symbol in self.graphicsView.scene().selectedItems() if
2369
                               issubclass(type(symbol), SymbolSvgItem)]
2370
                if symbolItems and len(symbolItems) is not 1:
2371
                    return
2372
                    
2373
                target_symbol = symbolItems[0]
2374
                index =  [index for index in range(len(target_symbol.conn_type)) \
2375
                            if target_symbol.conn_type[index] == 'Primary' or target_symbol.conn_type[index] == 'Secondary']
2376
                for connector in target_symbol.connectors:
2377
                    svg = QtImageViewer.createSymbolObject(symName)
2378
                    if len(svg.connectors) > 1: 
2379
                        if ((target_symbol.conn_type and target_symbol.connectors.index(connector) in index) or not target_symbol.conn_type) and \
2380
                                    (not connector.connectedItem or (connector.connectedItem and type(connector.connectedItem) is QEngineeringLineItem)):
2381
                            QtImageViewer.matchSymbolToLine(self.graphicsView.scene(), svg, connector.sceneBoundingRect().center())
2382
                    elif len(svg.connectors) == 1:
2383
                        if ((target_symbol.conn_type and target_symbol.connectors.index(connector) in index) or not target_symbol.conn_type) and \
2384
                                    not connector.connectedItem:
2385
                            QtImageViewer.matchSymbolToLine(self.graphicsView.scene(), svg, connector.sceneBoundingRect().center())
2386

    
2387
                if target_symbol:
2388
                    return
2389
            elif event.key() == Qt.Key_X:
2390
                app_doc_data = AppDocData.instance()
2391
                configs = app_doc_data.getAppConfigs('app', 'mode')
2392
                if configs and 1 == len(configs) and 'advanced' == configs[0].value:
2393
                    advanced = True
2394
                    items = self.graphicsView.scene().selectedItems()
2395
                    if items:
2396
                        item = self.symbolTreeWidget.currentItem()
2397
                        if item:
2398
                            self.symbolTreeWidget.showSymbolEditorDialog(item, 0)
2399
            elif event.key() == Qt.Key_F6:
2400
                from DEXPI import scene_to_dexpi
2401

    
2402
                app_doc_data = AppDocData.instance()
2403
                scene_to_dexpi('D:\\Temp\\DEXPI.xml', app_doc_data.activeDrawing.name, self.graphicsView.scene())
2404

    
2405
            QMainWindow.keyPressEvent(self, event)
2406
        except Exception as ex:
2407
            message = f"error occurred({repr(ex)}) in {sys.exc_info()[-1].tb_frame.f_code.co_filename}:" \
2408
                      f"{sys.exc_info()[-1].tb_lineno}"
2409
            self.addMessage.emit(MessageType.Error, message)
2410

    
2411
    def recognize(self):
2412
        """recognize symbol, text and line for selected drawings"""
2413
        from datetime import datetime
2414
        #from RecognitionDialog import QRecognitionDialog
2415

    
2416
        # save alarm
2417
        self.save_alarm_enable(False)
2418

    
2419
        app_doc_data = AppDocData.instance()
2420
        current_drawing, currentPid = None, None
2421

    
2422
        if self.graphicsView.hasImage():
2423
            current_drawing = app_doc_data.activeDrawing
2424
            currentPid = app_doc_data.activeDrawing.name
2425

    
2426
        # get checked drawings
2427
        drawing_top = self.treeWidgetDrawingList.topLevelItem(0)
2428
        count = drawing_top.childCount()
2429
        checked_drawings = {}
2430
        for idx in range(count):
2431
            child = drawing_top.child(idx)
2432
            if child.checkState(0) == Qt.Checked and child.data(Qt.UserRole, 0):
2433
                checked_drawings[child.data(Qt.UserRole, 0)] = child
2434
        # up to here
2435

    
2436
        # if there is no checked drawing
2437
        if current_drawing and currentPid and not checked_drawings:
2438
            for idx in range(count):
2439
                child = drawing_top.child(idx)
2440
                if child.data(Qt.UserRole, 0) is current_drawing:
2441
                    checked_drawings[child.data(Qt.UserRole, 0)] = child
2442

    
2443
        if not checked_drawings:
2444
            self.showImageSelectionMessageBox()
2445
            return
2446

    
2447
        try:
2448
            self.on_clear_log()
2449
            dlg = QRecognitionDialog(self, [drawing for drawing in checked_drawings.keys()])
2450
            dlg.exec_()
2451

    
2452
            if current_drawing and current_drawing in checked_drawings.keys() and dlg.isTreated:
2453
                self.open_image_drawing(current_drawing, force=True)
2454

    
2455
            # save working date-time
2456
            _now = datetime.now().strftime('%Y-%m-%d %H:%M:%S')
2457
            for drawing, tree_item in checked_drawings.items():
2458
                drawing.datetime = _now
2459
                tree_item.setText(1, _now)
2460
            #app_doc_data.saveDrawings(checked_drawings.keys())
2461
            self.changeViewCheckedState(True)
2462
            # up to here
2463
        except Exception as ex:
2464
            message = 'error occurred({}) in {}:{}'.format(repr(ex), sys.exc_info()[-1].tb_frame.f_code.co_filename,
2465
                                                           sys.exc_info()[-1].tb_lineno)
2466
            self.addMessage.emit(MessageType.Error, message)
2467

    
2468
        # save alarm
2469
            self.save_alarm_enable(True)
2470

    
2471
    '''
2472
        @brief      remove item from tree widget and then remove from scene
2473
        @date       2018.05.25
2474
        @author     Jeongwoo
2475
    '''
2476

    
2477
    def itemRemoved(self, item):
2478
        try:
2479
            if type(item) is QEngineeringErrorItem:
2480
                # remove error item from inconsistency list
2481
                for row in range(self.tableWidgetInconsistency.rowCount()):
2482
                    if item is self.tableWidgetInconsistency.item(row, 0).tag:
2483
                        self.tableWidgetInconsistency.removeRow(row)
2484
                        break
2485

    
2486
                if item.scene() is not None:
2487
                    item.scene().removeItem(item)
2488
                del item
2489
            else:
2490
                remove_scene = item.scene()
2491
                self.itemTreeWidget.itemRemoved(item)
2492

    
2493
                matches = [_item for _item in remove_scene.items() if
2494
                           hasattr(_item, 'connectors') and [connector for connector in _item.connectors if
2495
                                                             connector.connectedItem is item]]
2496
                for match in matches:
2497
                    for connector in match.connectors:
2498
                        if connector.connectedItem is item:
2499
                            connector.connectedItem = None
2500
                            connector.highlight(False)
2501

    
2502
                # matches = [_item for _item in self.graphicsView.scene().items() if hasattr(_item, 'remove_assoc_item')]
2503
                # for _item in matches:
2504
                #    _item.remove_assoc_item(item)
2505

    
2506
                app_doc_data = AppDocData.instance()
2507
                if type(item) is QEngineeringLineNoTextItem and item in app_doc_data.tracerLineNos:
2508
                    app_doc_data.tracerLineNos.pop(app_doc_data.tracerLineNos.index(item))
2509

    
2510
                if type(item) is QEngineeringLineItem and item in app_doc_data.lines:
2511
                    app_doc_data.lines.remove(item)
2512

    
2513
                matches = [_item for _item in remove_scene.items() if
2514
                           type(_item) is QEngineeringLineNoTextItem]
2515
                matches.extend([lineNo for lineNo in app_doc_data.tracerLineNos if
2516
                                type(lineNo) is QEngineeringTrimLineNoTextItem])
2517
                for match in matches:
2518
                    if item is match.prop('From'):
2519
                        match.set_property('From', None)
2520
                    if item is match.prop('To'):
2521
                        match.set_property('To', None)
2522

    
2523
                    for run_index in reversed(range(len(match.runs))):
2524
                        run = match.runs[run_index]
2525
                        if item in run.items:
2526
                            index = run.items.index(item)
2527
                            run.items.pop(index)
2528
                            if not run.items:
2529
                                run.explode()
2530
                                if type(match) is QEngineeringTrimLineNoTextItem and not match.runs:
2531
                                    app_doc_data.tracerLineNos.pop(app_doc_data.tracerLineNos.index(match))
2532
                            # break
2533

    
2534
                matches = [_item for _item in remove_scene.items() if hasattr(_item, 'owner')]
2535
                for match in matches:
2536
                    if match.owner is item:
2537
                        match.owner = None
2538

    
2539
                matches = [_item for _item in remove_scene.items() if hasattr(_item, 'attrs')]
2540
                # done = False
2541
                for match in matches:
2542
                    assocs = match.associations()
2543
                    for assoc in assocs:
2544
                        if item is assoc:
2545
                            for attr in match.attrs.keys():
2546
                                if attr.AssocItem and str(item.uid) == str(attr.AssocItem.uid):
2547
                                    attr.AssocItem = None
2548
                                    match.attrs[attr] = ''
2549
                                    # done = True
2550
                            match.remove_assoc_item(item)
2551
                            break
2552
                    # if done: break
2553

    
2554
                if item.scene() is not None: item.scene().removeItem(item)
2555
        except Exception as ex:
2556
            message = 'error occurred({}) in {}:{}'.format(ex, sys.exc_info()[-1].tb_frame.f_code.co_filename,
2557
                                                           sys.exc_info()[-1].tb_lineno)
2558
            self.addMessage.emit(MessageType.Error, message)
2559
        '''
2560
        finally:
2561
            if hasattr(item, '_cond'):
2562
                item._cond.wakeAll()
2563
        '''
2564

    
2565

    
2566
    def connect_attributes(self, MainWindow):
2567
        """connect attributes to symbol"""
2568
        from LineNoTracer import LineNoTracer
2569
        from ConnectAttrDialog import QConnectAttrDialog
2570

    
2571
        if not self.graphicsView.hasImage():
2572
            self.showImageSelectionMessageBox()
2573
            return
2574

    
2575
        # save alarm
2576
        self.save_alarm_enable(False)
2577

    
2578
        try:
2579
            dlg = QConnectAttrDialog(self, self.graphicsView.scene())
2580
            dlg.setWindowFlags(self.windowFlags() & ~Qt.WindowCloseButtonHint & ~Qt.WindowContextHelpButtonHint)
2581
            dlg.exec_()
2582
            if dlg.isRunned:
2583
                self.refresh_item_list()
2584

    
2585
                if dlg.validation_checked:
2586
                    self.onValidation()
2587

    
2588
                self.graphicsView.invalidateScene()
2589
        except Exception as ex:
2590
            message = 'error occurred({}) in {}:{}'.format(ex, sys.exc_info()[-1].tb_frame.f_code.co_filename,
2591
                                                           sys.exc_info()[-1].tb_lineno)
2592
            self.addMessage.emit(MessageType.Error, message)
2593
        finally:
2594
            # save alarm
2595
            self.save_alarm_enable(True)
2596

    
2597
    def postDetectLineProcess(self):
2598
        '''
2599
            @brief  check allowables among undetected items
2600
            @author euisung
2601
            @date   2018.11.15
2602
            @history    2018.11.15  euisung    no more used, moved to TextItemFactoy isLineNo()
2603
        '''
2604
        from TextItemFactory import TextItemFactory
2605

    
2606
        appDocData = AppDocData.instance()
2607

    
2608
        tableNames = ["Fluid Code", "Insulation Purpose", "PnID Number", "Piping Materials Class", "Unit Number"]
2609
        tableDatas = []
2610
        for tableName in tableNames:
2611
            tableNameFormat = tableName.replace(' ', '').replace('&&', 'n')
2612
            tableDatas.append(appDocData.getCodeTable(tableNameFormat))
2613

    
2614
        items = self.graphicsView.scene().items()
2615
        for item in items:
2616
            if type(item) is not QEngineeringTextItem:
2617
                continue
2618
            text = item.text()
2619
            for tableData in tableDatas:
2620
                for data in tableData:
2621
                    if data[3] == '':
2622
                        continue
2623
                    else:
2624
                        allows = data[3].split(',')
2625
                        for allow in allows:
2626
                            text = text.replace(allow, data[1])
2627

    
2628
            lineItem = TextItemFactory.instance().createTextItem(text)
2629
            if type(lineItem) is QEngineeringLineNoTextItem:
2630
                lineItem.loc = item.loc
2631
                lineItem.size = item.size
2632
                lineItem.angle = item.angle
2633
                lineItem.area = item.area
2634
                # lineItem.addTextItemToScene(self.graphicsView.scene())
2635
                lineItem.transfer.onRemoved.connect(self.itemRemoved)
2636
                item.transfer.onRemoved.emit(item)
2637
                appDocData.lineNos.append(lineItem)
2638

    
2639
    def init_add_tree_item(self, line_no_tree_item, run_item):
2640
        """ insert symbol item and find line no as owner """
2641
        # insert
2642
        self.itemTreeWidget.addTreeItem(line_no_tree_item, run_item)
2643
        # find
2644
        self.itemTreeWidget.addTreeItem(line_no_tree_item, run_item)
2645

    
2646
    def load_drawing(self, drawing):
2647
        """ load drawing """
2648
        from EngineeringRunItem import QEngineeringRunItem
2649
        from QEngineeringTrimLineNoTextItem import QEngineeringTrimLineNoTextItem
2650

    
2651
        app_doc_data = AppDocData.instance()
2652
        try:
2653
            symbols = []
2654
            lines = []
2655

    
2656
            components = app_doc_data.get_components(drawing.UID)
2657
            maxValue = len(components) * 2
2658
            self.progress.setMaximum(maxValue) if maxValue > 0 else None
2659

    
2660
            """ parsing all symbols """
2661
            for symbol in [component for component in components if int(component['SymbolType_UID']) != -1]:
2662
                item = SymbolSvgItem.from_database(symbol)
2663
                if item is not None:
2664
                    item.transfer.onRemoved.connect(self.itemRemoved)
2665
                    symbols.append(item)
2666
                    app_doc_data.symbols.append(item)
2667
                    item.addSvgItemToScene(self.graphicsView.scene())
2668
                else:
2669
                    pt = [float(symbol['X']), float(symbol['Y'])]
2670
                    size = [float(symbol['Width']), float(symbol['Height'])]
2671
                    angle = float(symbol['Rotation'])
2672
                    item = QGraphicsBoundingBoxItem(pt[0], pt[1], size[0], size[1])
2673
                    item.isSymbol = True
2674
                    item.angle = angle
2675
                    item.setPen(QPen(Qt.red, 5, Qt.SolidLine))
2676
                    self.graphicsView.scene().addItem(item)
2677
                    item.transfer.onRemoved.connect(self.itemRemoved)
2678

    
2679
                self.progress.setValue(self.progress.value() + 1)
2680

    
2681
            QApplication.processEvents()
2682

    
2683
            # parse texts
2684
            for text in [component for component in components if
2685
                         component['Name'] == 'Text' and component['SymbolType_UID'] == -1]:
2686
                item = QEngineeringTextItem.from_database(text)
2687
                if item is not None:
2688
                    item.uid = text['UID']
2689
                    item.attribute = text['Value']
2690
                    name = text['Name']
2691
                    item.transfer.onRemoved.connect(self.itemRemoved)
2692
                    item.addTextItemToScene(self.graphicsView.scene())
2693

    
2694
                self.progress.setValue(self.progress.value() + 1)
2695

    
2696
            QApplication.processEvents()
2697

    
2698
            # note
2699
            for note in [component for component in components if
2700
                         component['Name'] == 'Note' and component['SymbolType_UID'] == -1]:
2701
                item = QEngineeringTextItem.from_database(note)
2702
                if item is not None:
2703
                    item.uid = note['UID']
2704
                    attributeValue = note['Value']
2705
                    name = note['Name']
2706
                    item.transfer.onRemoved.connect(self.itemRemoved)
2707
                    item.addTextItemToScene(self.graphicsView.scene())
2708

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

    
2711
            QApplication.processEvents()
2712

    
2713
            for line in [component for component in components if
2714
                         component['Name'] == 'Line' and component['SymbolType_UID'] == -1]:
2715
                item = QEngineeringLineItem.from_database(line)
2716
                if item:
2717
                    item.transfer.onRemoved.connect(self.itemRemoved)
2718
                    self.graphicsView.scene().addItem(item)
2719
                    lines.append(item)
2720

    
2721
                self.progress.setValue(self.progress.value() + 1)
2722

    
2723
            QApplication.processEvents()
2724

    
2725
            for unknown in [component for component in components if
2726
                            component['Name'] == 'Unknown' and component['SymbolType_UID'] == -1]:
2727
                item = QEngineeringUnknownItem.from_database(unknown)
2728
                item.transfer.onRemoved.connect(self.itemRemoved)
2729
                if item is not None:
2730
                    item.transfer.onRemoved.connect(self.itemRemoved)
2731
                    self.graphicsView.scene().addItem(item)
2732

    
2733
                self.progress.setValue(self.progress.value() + 1)
2734

    
2735
            QApplication.processEvents()
2736

    
2737
            for component in [component for component in components if
2738
                              component['Name'] == 'Line NO' and component['SymbolType_UID'] == -1]:
2739
                line_no = QEngineeringLineNoTextItem.from_database(component)
2740
                if type(line_no) is QEngineeringLineNoTextItem:
2741
                    line_no.transfer.onRemoved.connect(self.itemRemoved)
2742
                    self.addTextItemToScene(line_no)
2743
                    line_no_tree_item = self.itemTreeWidget.addTreeItem(self.itemTreeWidget.root, line_no)
2744

    
2745
                    runs = app_doc_data.get_pipe_runs(str(line_no.uid))
2746
                    if not runs: continue
2747
                    for run in runs:
2748
                        line_run = QEngineeringRunItem()
2749
                        run_items = app_doc_data.get_pipe_run_items(run['UID'])
2750
                        for record in run_items:
2751
                            uid = record['Components_UID']
2752
                            run_item = self.graphicsView.findItemByUid(uid)
2753
                            if run_item is not None:
2754
                                run_item._owner = line_no
2755
                                line_run.items.append(run_item)
2756
                        line_run.owner = line_no
2757
                        line_no.runs.append(line_run)
2758

    
2759
                        for run_item in line_run.items:
2760
                            if issubclass(type(run_item), SymbolSvgItem):
2761
                                self.init_add_tree_item(line_no_tree_item, run_item)
2762

    
2763
                self.progress.setValue(self.progress.value() + 1)
2764
            QApplication.processEvents()
2765

    
2766
            for component in [component for component in components if
2767
                              component['Name'] == 'Trim Line NO' and component['SymbolType_UID'] == -1]:
2768
                line_no = QEngineeringTrimLineNoTextItem()
2769
                line_no.uid = uuid.UUID(component['UID'])
2770

    
2771
                runs = app_doc_data.get_pipe_runs(str(line_no.uid))
2772
                if not runs: continue
2773

    
2774
                line_no_tree_item = self.itemTreeWidget.addTreeItem(self.itemTreeWidget.root, line_no)
2775

    
2776
                for run in runs:
2777
                    line_run = QEngineeringRunItem()
2778
                    run_items = app_doc_data.get_pipe_run_items(run['UID'])
2779
                    for record in run_items:
2780
                        uid = record['Components_UID']
2781
                        run_item = self.graphicsView.findItemByUid(uid)
2782
                        if run_item is not None:
2783
                            run_item.owner = line_no
2784
                            line_run.items.append(run_item)
2785
                    line_run.owner = line_no
2786
                    line_no.runs.append(line_run)
2787

    
2788
                    for run_item in line_run.items:
2789
                        if issubclass(type(run_item), SymbolSvgItem):
2790
                            self.init_add_tree_item(line_no_tree_item, run_item)
2791

    
2792
                app_doc_data.tracerLineNos.append(line_no)
2793

    
2794
                self.progress.setValue(self.progress.value() + 1)
2795

    
2796
            for component in [component for component in components if
2797
                              component['Name'] == 'VendorPackage' and component['SymbolType_UID'] == -1]:
2798
                item = QEngineeringVendorItem.from_database(component)
2799
                if item is not None:
2800
                    item.transfer.onRemoved.connect(self.itemRemoved)
2801
                    self.graphicsView.scene().addItem(item)
2802

    
2803
            # connect flow item to line
2804
            for line in lines:
2805
                line.update_arrow()
2806
                app_doc_data.lines.append(line)
2807
            # for flowMark in [item for item in symbols if type(item) is QEngineeringFlowMarkItem]:
2808
            #    for line in lines:
2809
            #        if flowMark.owner is line:
2810
            #            line._flowMark.append(flowMark)
2811
            #            flowMark.setParentItem(line)
2812
            # up to here
2813

    
2814
            """ update scene """
2815
            self.graphicsView.scene().update(self.graphicsView.sceneRect())
2816
            for item in self.graphicsView.scene().items():
2817
                up_progress = False
2818
                # binding items
2819
                if hasattr(item, 'owner'):
2820
                    item.owner
2821
                    up_progress = True
2822
                if hasattr(item, 'connectors'):
2823
                    for connector in item.connectors:
2824
                        connector.connectedItem
2825
                    up_progress = True
2826

    
2827
                if up_progress:
2828
                    self.progress.setValue(self.progress.value() + 1)
2829
            
2830
            for item in self.graphicsView.scene().items():
2831
                item.setVisible(True)
2832

    
2833
        except Exception as ex:
2834
            message = 'error occurred({}) in {}:{}'.format(ex, sys.exc_info()[-1].tb_frame.f_code.co_filename,
2835
                                                           sys.exc_info()[-1].tb_lineno)
2836
            self.addMessage.emit(MessageType.Error, message)
2837
        finally:
2838
            app_doc_data.clearTempDBData()
2839
            self.itemTreeWidget.update_item_count()
2840
            self.itemTreeWidget.expandAll()
2841
            # self.graphicsView.scene().blockSignals(False)
2842

    
2843
    '''
2844
        @brief      load recognition result
2845
        @author     humkyung
2846
        @date       2018.04.??
2847
        @history    humkyung 2018.01.12 parse originalpoint and connectionpoint
2848
                    Jeongwoo 2018.04.17 add QGraphicItem with Rotated text
2849
                    Jeongwoo 2018.04.23 Change to Draw texts on QEngineeringTextItem
2850
                    humkyung 2018.04.23 connect item remove slot to result tree
2851
                    Jeongwoo 2018.04.25 Add if state with QEngineeringNoteItem
2852
                    Jeongwoo 2018.04.26 Change method to create TextItem object with TextItemFactory
2853
                    Jeongwoo 2018.05.03 Change method to draw Svg Item on Scene (svg.addSvgItemToScene)
2854
                    Jeongwoo 2018.05.29 Change method name / Change method to add item / Add Line item
2855
                    Jeongwoo 2018.05.30 Add parameters on SymbolSvgItem.__init__() (parentSymbol, childSymbol) / Change method name / Change XML NODE NAMES
2856
                    Jeongwoo 2018.06.12 Add LineNoTextItem from LINE_NO
2857
                    Jeongwoo 2018.06.14 Add UnknownItem from UNKNOWN
2858
                    Jeongwoo 2018.06.18 Update Scene after all item added
2859
                                        Add connect on unknown item
2860
                                        Add [transfer] for using pyqtSignal
2861
                    kyouho  2018.07.12  Add line property logic
2862
                    humkyung 2018.08.22 show progress while loading xml file
2863
                    2018.11.22      euisung     fix note road
2864
    '''
2865

    
2866
    def load_recognition_result_from_xml(self, drawing):
2867
        # Yield successive n-sized
2868
        # chunks from l.
2869
        def divide_chunks(l, n):
2870
            # looping till length l
2871
            for i in range(0, len(l), n):
2872
                yield l[i:i + n]
2873

    
2874
        def update_items(items):
2875
            for item in items:
2876
                # binding items
2877
                item.owner
2878
                for connector in item.connectors:
2879
                    connector.connectedItem
2880

    
2881
            return items
2882

    
2883
        import concurrent.futures as futures
2884
        from xml.etree.ElementTree import Element, SubElement, dump, ElementTree, parse
2885
        from App import App
2886
        from EngineeringRunItem import QEngineeringRunItem
2887
        from QEngineeringTrimLineNoTextItem import QEngineeringTrimLineNoTextItem
2888
        from EngineeringGraphicsLineItem import QEngineeringGraphicsLineItem
2889

    
2890
        app_doc_data = AppDocData.instance()
2891

    
2892
        try:
2893
            file_name = os.path.splitext(os.path.basename(drawing.file_path))[0]
2894
            path = os.path.join(app_doc_data.getCurrentProject().getTempPath(), file_name + '.xml')
2895
            self.graphicsView.scene().blockSignals(True)
2896

    
2897
            symbols = []
2898
            lines = []
2899

    
2900
            xml = parse(path)
2901
            root = xml.getroot()
2902

    
2903
            maxValue = 0
2904
            maxValue = maxValue + len(list(root.iter('SYMBOL'))) - \
2905
                       len(list(root.iterfind('LINENOS/LINE_NO/RUN/SYMBOL'))) - \
2906
                       len(list(root.iterfind('TRIMLINENOS/TRIM_LINE_NO/RUN/SYMBOL')))
2907
            maxValue = maxValue + len(list(root.iterfind('TEXTINFOS/ATTRIBUTE')))
2908
            maxValue = maxValue + len(list(root.iterfind('NOTES/ATTRIBUTE')))
2909
            maxValue = maxValue + len(list(root.iter('LINE_NO')))
2910
            maxValue = maxValue + len(list(root.iter('LINE'))) - \
2911
                       len(list(root.iterfind('LINENOS/LINE_NO/RUN/LINE'))) - \
2912
                       len(list(root.iterfind('TRIMLINENOS/TRIM_LINE_NO/RUN/LINE')))
2913
            maxValue = maxValue + len(list(root.iter('GRAPHICS_LINE')))
2914
            maxValue = maxValue + len(list(root.iter('UNKNOWN')))
2915
            # maxValue = maxValue + len(list(root.iter('SIZETEXT')))
2916
            maxValue = maxValue + len(list(root.iter('TRIM_LINE_NO')))
2917
            maxValue *= 2
2918
            self.progress.setMaximum(maxValue) if maxValue > 0 else None
2919

    
2920
            """ parsing all symbols """
2921
            """
2922
            with futures.ThreadPoolExecutor(max_workers=App.THREAD_MAX_WORKER) as pool:
2923
                future_symbol = {pool.submit(SymbolSvgItem.fromXml, symbol): symbol for symbol in root.find('SYMBOLS').iter('SYMBOL')}
2924

2925
                for future in futures.as_completed(future_symbol):
2926
                    try:
2927
                        item = future.result()
2928
                        if item:
2929
                            if item is not None:
2930
                                item.transfer.onRemoved.connect(self.itemRemoved)
2931
                                symbols.append(item)
2932
                                docData.symbols.append(item)
2933
                                self.addSvgItemToScene(item)
2934
                            else:
2935
                                pt = [float(x) for x in symbol.find('LOCATION').text.split(',')]
2936
                                size = [float(x) for x in symbol.find('SIZE').text.split(',')]
2937
                                angle = float(symbol.find('ANGLE').text)
2938
                                item = QGraphicsBoundingBoxItem(pt[0], pt[1], size[0], size[1])
2939
                                item.isSymbol = True
2940
                                item.angle = angle
2941
                                item.setPen(QPen(Qt.red, 5, Qt.SolidLine))
2942
                                self.graphicsView.scene().addItem(item)
2943
                                item.transfer.onRemoved.connect(self.itemRemoved)
2944
                    except Exception as ex:
2945
                        message = 'error occurred({}) in {}:{}'.format(repr(ex), sys.exc_info()[-1].tb_frame.f_code.co_filename,
2946
                                                                       sys.exc_info()[-1].tb_lineno)
2947

2948
            """
2949
            for symbol in root.find('SYMBOLS').iter('SYMBOL'):
2950
                item = SymbolSvgItem.fromXml(symbol)
2951
                if item is not None:
2952
                    item.transfer.onRemoved.connect(self.itemRemoved)
2953
                    symbols.append(item)
2954
                    #app_doc_data.symbols.append(item)
2955
                    item.addSvgItemToScene(self.graphicsView.scene())
2956
                else:
2957
                    pt = [float(x) for x in symbol.find('LOCATION').text.split(',')]
2958
                    size = [float(x) for x in symbol.find('SIZE').text.split(',')]
2959
                    angle = float(symbol.find('ANGLE').text)
2960
                    item = QGraphicsBoundingBoxItem(pt[0], pt[1], size[0], size[1])
2961
                    item.isSymbol = True
2962
                    item.angle = angle
2963
                    item.setPen(QPen(Qt.red, 5, Qt.SolidLine))
2964
                    self.graphicsView.scene().addItem(item)
2965
                    item.transfer.onRemoved.connect(self.itemRemoved)
2966

    
2967
                self.progress.setValue(self.progress.value() + 1)
2968

    
2969
            QApplication.processEvents()
2970

    
2971
            # parse texts
2972
            for text in root.find('TEXTINFOS').iter('ATTRIBUTE'):
2973
                item = QEngineeringTextItem.fromXml(text)
2974
                if item is not None:
2975
                    uid = text.find('UID')
2976
                    attributeValue = text.find('ATTRIBUTEVALUE')
2977
                    name = text.find('NAME').text
2978
                    item.transfer.onRemoved.connect(self.itemRemoved)
2979
                    item.addTextItemToScene(self.graphicsView.scene())
2980
                    # docData.texts.append(item)
2981

    
2982
                    if name == 'TEXT':
2983
                        if uid is not None and attributeValue is not None:
2984
                            item.uid = uid.text
2985
                            item.attribute = attributeValue.text
2986

    
2987
                self.progress.setValue(self.progress.value() + 1)
2988

    
2989
            QApplication.processEvents()
2990

    
2991
            # note
2992
            for text in root.find('NOTES').iter('ATTRIBUTE'):
2993
                item = QEngineeringTextItem.fromXml(text)
2994
                if item is not None:
2995
                    uid = text.find('UID')
2996
                    attributeValue = text.find('ATTRIBUTEVALUE')
2997
                    name = text.find('NAME').text
2998
                    item.transfer.onRemoved.connect(self.itemRemoved)
2999
                    item.addTextItemToScene(self.graphicsView.scene())
3000

    
3001
                    if name == 'NOTE':
3002
                        if uid is not None:
3003
                            item.uid = uid.text
3004

    
3005
                self.progress.setValue(self.progress.value() + 1)
3006

    
3007
            QApplication.processEvents()
3008

    
3009
            for line in root.find('LINEINFOS').iter('LINE'):
3010
                item = QEngineeringLineItem.fromXml(line)
3011
                if item:
3012
                    item.transfer.onRemoved.connect(self.itemRemoved)
3013
                    self.graphicsView.scene().addItem(item)
3014
                    lines.append(item)
3015

    
3016
                self.progress.setValue(self.progress.value() + 1)
3017

    
3018
            for line in root.find('LINEINFOS').iter('GRAPHICS_LINE'):
3019
                item = QEngineeringGraphicsLineItem.fromXml(line)
3020
                if item:
3021
                    item.transfer.onRemoved.connect(self.itemRemoved)
3022
                    self.graphicsView.scene().addItem(item)
3023

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

    
3026
            QApplication.processEvents()
3027

    
3028
            for unknown in root.iter('UNKNOWN'):
3029
                item = QEngineeringUnknownItem.fromXml(unknown)
3030
                if item is not None:
3031
                    item.transfer.onRemoved.connect(self.itemRemoved)
3032
                    self.graphicsView.scene().addItem(item)
3033

    
3034
                self.progress.setValue(self.progress.value() + 1)
3035

    
3036
            QApplication.processEvents()
3037

    
3038
            # """ add tree widget """
3039
            # for item in symbols:
3040
            #    docData.symbols.append(item)
3041
            #    self.addSvgItemToScene(item)
3042
            #    self.itemTreeWidget.addTreeItem(self.itemTreeWidget.root, item)
3043

    
3044
            for line_no_node in root.find('LINENOS').iter('LINE_NO'):
3045
                line_no = QEngineeringLineNoTextItem.fromXml(line_no_node)
3046
                if line_no is None: continue
3047
                line_no.transfer.onRemoved.connect(self.itemRemoved)
3048
                line_no.addTextItemToScene(self.graphicsView.scene())
3049
                line_no_tree_item = self.itemTreeWidget.addTreeItem(self.itemTreeWidget.root, line_no)
3050
                if type(line_no) is not QEngineeringLineNoTextItem: continue
3051

    
3052
                runs_node = line_no_node.findall('RUN')
3053
                if runs_node is None: continue
3054

    
3055
                for run_node in runs_node:
3056
                    line_run = QEngineeringRunItem()
3057
                    for child_node in run_node:
3058
                        uidElement = child_node.find('UID')
3059
                        if uidElement is not None:
3060
                            uid = uidElement.text
3061
                            run_item = self.graphicsView.findItemByUid(uid)
3062
                            if run_item is not None:
3063
                                run_item._owner = line_no
3064
                                line_run.items.append(run_item)
3065
                    line_run.owner = line_no
3066
                    line_no.runs.append(line_run)
3067

    
3068
                    for run_item in line_run.items:
3069
                        if issubclass(type(run_item), SymbolSvgItem):
3070
                            self.init_add_tree_item(line_no_tree_item, run_item)
3071

    
3072
                # docData.tracerLineNos.append(line_no)
3073

    
3074
                self.progress.setValue(self.progress.value() + 1)
3075
            QApplication.processEvents()
3076

    
3077
            for trimLineNo in root.iter('TRIM_LINE_NO'):
3078
                line_no = QEngineeringTrimLineNoTextItem()
3079
                line_no.uid = uuid.UUID(trimLineNo.find('UID').text)
3080

    
3081
                runs_node = trimLineNo.findall('RUN')
3082
                if runs_node is None: continue
3083
                line_no_tree_item = self.itemTreeWidget.addTreeItem(self.itemTreeWidget.root, line_no)
3084

    
3085
                for run in runs_node:
3086
                    line_run = QEngineeringRunItem()
3087
                    for child in run:
3088
                        uidElement = child.find('UID')
3089
                        if uidElement is not None:
3090
                            uid = uidElement.text
3091
                            run_item = self.graphicsView.findItemByUid(uid)
3092
                            if run_item is not None:
3093
                                run_item.owner = line_no
3094
                                line_run.items.append(run_item)
3095
                    line_run.owner = line_no
3096
                    line_no.runs.append(line_run)
3097

    
3098
                    for run_item in line_run.items:
3099
                        if issubclass(type(run_item), SymbolSvgItem):
3100
                            self.init_add_tree_item(line_no_tree_item, run_item)
3101

    
3102
                app_doc_data.tracerLineNos.append(line_no)
3103

    
3104
                self.progress.setValue(self.progress.value() + 1)
3105
            QApplication.processEvents()
3106

    
3107
            if root.find('VENDORS') is not None:
3108
                for vendor in root.find('VENDORS').iter('VENDOR'):
3109
                    item = QEngineeringVendorItem.fromXml(vendor)
3110
                    item.transfer.onRemoved.connect(self.itemRemoved)
3111
                    self.graphicsView.scene().addItem(item)
3112

    
3113
            # connect flow item to line
3114
            for line in lines:
3115
                line.update_arrow()
3116
                app_doc_data.lines.append(line)
3117
            # for flowMark in [item for item in symbols if type(item) is QEngineeringFlowMarkItem]:
3118
            #    for line in lines:
3119
            #        if flowMark.owner is line:
3120
            #            line._flowMark.append(flowMark)
3121
            #            flowMark.setParentItem(line)
3122
            # up to here
3123

    
3124
            """
3125
            group_box = QGroupBox("Contact Details")
3126
            number_label = QLabel("Telephone number");
3127
            number_edit = QTextEdit('hello\nthis is ....')
3128
            layout = QFormLayout()
3129
            layout.addRow(number_label, number_edit)
3130
            group_box.setLayout(layout)
3131

3132
            proxy =  ㅐ()
3133
            proxy.setWidget(group_box)
3134
            self.graphicsView.scene().addItem(proxy)  # (group_box, QGraphicsItem.ItemIgnoresTransformations)
3135
            """
3136

    
3137
            """ update scene """
3138
            _items = [_item for _item in self.graphicsView.scene().items() if hasattr(_item, 'owner') or hasattr(_item, 'connectors')]
3139
            if _items:
3140
                items = divide_chunks(_items, App.THREAD_MAX_WORKER if len(_items) > App.THREAD_MAX_WORKER else len(_items))
3141
                with futures.ThreadPoolExecutor(max_workers=App.THREAD_MAX_WORKER) as pool:
3142
                    future_items = {pool.submit(update_items, _items): _items for _items in items}
3143
                    for future in futures.as_completed(future_items):
3144
                        _items = future.result()
3145
                        self.progress.setValue(self.progress.value() + len(_items))
3146

    
3147
            """
3148
            for item in [_item for _item in self.graphicsView.scene().items() if hasattr(_item, 'owner') or hasattr(_item, 'connectors')]:
3149
                up_progress = False
3150
                # binding items
3151
                item.owner
3152
                for connector in item.connectors:
3153
                    connector.connectedItem
3154

3155
                self.progress.setValue(self.progress.value() + 1)
3156
            """
3157

    
3158
            for item in self.graphicsView.scene().items():
3159
                item.setVisible(True)
3160

    
3161
            self.graphicsView.scene().update(self.graphicsView.sceneRect())
3162
        except Exception as ex:
3163
            message = 'error occurred({}) in {}:{}'.format(ex, sys.exc_info()[-1].tb_frame.f_code.co_filename,
3164
                                                           sys.exc_info()[-1].tb_lineno)
3165
            self.addMessage.emit(MessageType.Error, message)
3166
        finally:
3167
            self.itemTreeWidget.update_item_count()
3168
            self.itemTreeWidget.expandAll()
3169
            self.graphicsView.scene().blockSignals(False)
3170

    
3171
    '''
3172
        @brief      Remove added item on same place and Add GraphicsItem
3173
        @author     Jeongwoo
3174
        @date       2018.05.29
3175
        @history    2018.06.18  Jeongwoo    Set Z-index
3176
    '''
3177

    
3178
    def addLineItemToScene(self, lineItem):
3179
        self.graphicsView.scene().addItem(lineItem)
3180

    
3181
    '''
3182
        @brief      generate output xml file
3183
        @author     humkyung
3184
        @date       2018.04.23
3185
        @history    2018.05.02  Jeongwoo    Show MessageBox when imageviewer doesn't have image
3186
    '''
3187

    
3188
    def generateOutput(self):
3189
        import XmlGenerator as xg
3190

    
3191
        if not self.graphicsView.hasImage():
3192
            self.showImageSelectionMessageBox()
3193
            return
3194

    
3195
        try:
3196
            appDocData = AppDocData.instance()
3197

    
3198
            # collect items
3199
            appDocData.lines.clear()
3200
            appDocData.lines = [item for item in self.graphicsView.scene().items() if
3201
                                type(item) is QEngineeringLineItem and item.owner is None]
3202

    
3203
            appDocData.symbols.clear()
3204
            appDocData.symbols = [item for item in self.graphicsView.scene().items() if
3205
                                  issubclass(type(item), SymbolSvgItem) and item.owner is None]
3206

    
3207
            appDocData.equipments.clear()
3208
            for item in self.graphicsView.scene().items():
3209
                if type(item) is QEngineeringEquipmentItem:
3210
                    appDocData.equipments.append(item)
3211

    
3212
            appDocData.texts.clear()
3213
            appDocData.texts = [item for item in self.graphicsView.scene().items() if
3214
                                issubclass(type(item), QEngineeringTextItem) and type(
3215
                                    item) is not QEngineeringLineNoTextItem]
3216
            # up to here
3217

    
3218
            appDocData.imgOutput = np.ones((appDocData.activeDrawing.height, appDocData.activeDrawing.width),
3219
                                           np.uint8) * 255
3220
            xg.writeOutputXml(appDocData.imgName, appDocData.activeDrawing.width,
3221
                              appDocData.activeDrawing.height)  # TODO: check
3222
            project = appDocData.getCurrentProject()
3223
            cv2.imwrite(os.path.join(project.getTempPath(), 'OUTPUT.png'), appDocData.imgOutput)
3224
        except Exception as ex:
3225
            message = 'error occurred({}) in {}:{}'.format(ex, sys.exc_info()[-1].tb_frame.f_code.co_filename,
3226
                                                           sys.exc_info()[-1].tb_lineno)
3227
            self.addMessage.emit(MessageType.Error, message)
3228

    
3229
    '''
3230
        @brief      resetting attribute at secne
3231
        @author     kyoyho
3232
        @date       2018.08.21
3233
    '''
3234
    """
3235
    def checkAttribute(self):
3236
        try:
3237

3238
            docData = AppDocData.instance()
3239
            if not self.graphicsView.hasImage():
3240
                return
3241

3242
            # symbol 경우
3243
            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]
3244
            for item in items:
3245
                attrs = item.attrs
3246
                
3247
                removeAttrList = []
3248
                for attr in attrs:
3249
                    if type(attr) is tuple:
3250
                        continue
3251

3252
                    if attr is None:
3253
                        removeAttrList.append(attr)
3254
                        continue
3255

3256
                    attrInfo = docData.getSymbolAttributeByUID(attr.UID)
3257
                    if attrInfo is None:
3258
                        removeAttrList.append(attr)
3259
                    # 해당 attribute가 맞는지 확인
3260
                    else:
3261
                        attrType = attrInfo.AttributeType
3262
                        _type = type(attr)
3263
                        if attrType == 'Symbol Item':
3264
                            if not issubclass(_type, SymbolSvgItem):
3265
                                removeAttrList.append(attr)
3266
                        elif attrType == 'Text Item':
3267
                            if _type is not QEngineeringTextItem:
3268
                                removeAttrList.append(attr)
3269
                        elif attrType == 'Int':
3270
                            if _type is not UserInputAttribute and self.isNumber(attr.text):
3271
                                removeAttrList.append(attr)
3272
                        elif attrType == 'String':
3273
                            if _type is not UserInputAttribute:
3274
                                removeAttrList.append(attr)
3275

3276
                for attr in removeAttrList:
3277
                    del attrs[attr]
3278

3279
            # Line No Text Item의 경우
3280
            items = [item for item in self.graphicsView.scene().items() if issubclass(type(item), QEngineeringLineNoTextItem)]
3281
            for item in items:
3282
                attrs = item.attrs
3283
                
3284
                removeAttrList = []
3285
                for attr in attrs:
3286
                    if type(attr) is UserInputAttribute:
3287
                        attrInfo = docData.getLinePropertiesByUID(attr.attribute)
3288
                        if attrInfo is None:
3289
                            removeAttrList.append(attr)
3290

3291
                for attr in removeAttrList:
3292
                    del attrs[attr]
3293

3294
        except Exception as ex:
3295
                message = 'error occurred({}) in {}:{}'.format(ex, sys.exc_info()[-1].tb_frame.f_code.co_filename, sys.exc_info()[-1].tb_lineno)
3296
                self.addMessage.emit(MessageType.Error, message)
3297
    """
3298
    '''
3299
        @brief      Check Number
3300
        @author     kyouho
3301
        @date       2018.08.20
3302
    '''
3303

    
3304
    def isNumber(self, num):
3305
        p = re.compile('(^[0-9]+$)')
3306
        result = p.match(num)
3307

    
3308
        if result:
3309
            return True
3310
        else:
3311
            return False
3312

    
3313
    '''
3314
        @brief      find overlap Connector
3315
        @author     kyouho
3316
        @date       2018.08.28
3317
    '''
3318

    
3319
    def findOverlapConnector(self, connectorItem):
3320
        from shapely.geometry import Point
3321
        from EngineeringConnectorItem import QEngineeringConnectorItem
3322
        itemList = []
3323

    
3324
        x = connectorItem.center()[0]
3325
        y = connectorItem.center()[1]
3326

    
3327
        connectors = [item for item in self.graphicsView.scene().items() if
3328
                      type(item) is QEngineeringConnectorItem and item != connectorItem]
3329
        for connector in connectors:
3330
            if Point(x, y).distance(Point(connector.center()[0], connector.center()[1])) < 5:
3331
                itemList.append(connector.parent)
3332

    
3333
        return itemList
3334

    
3335
    def make_diff_image(self):
3336
        """ make diff image """
3337
        # test
3338

    
3339
        from RecognitionDialog import Worker
3340
        from symbol import Symbol
3341
        import math
3342
        from PIL import Image
3343

    
3344
        app_doc_data = AppDocData.instance()
3345
        img = app_doc_data.imgSrc.copy()
3346

    
3347
        # check break
3348
        symbols = [item for item in self.graphicsView.scene().items() if issubclass(type(item), SymbolSvgItem)]
3349

    
3350
        for symbol in symbols:
3351
            rect = symbol.sceneBoundingRect()
3352
            sName = symbol.name
3353
            sType = symbol.type
3354
            sp = (rect.x(), rect.y())
3355
            w, h = rect.width(), rect.height()
3356
            rotatedAngle = round(math.degrees(symbol.angle))
3357
            detectFlip = symbol.flip
3358

    
3359
            dummySym = Symbol(sName, sType, sp, w, h, 0, 0, 0, rotatedAngle,
3360
                                   1, 0, 1, 0,
3361
                                   ','.join(str(x) for x in [0, 0]),
3362
                                   '/'.join('{},{},{},{}'.format(param[0], param[1], param[2], param[3]) for param in
3363
                                            []),
3364
                                   'dummy', 'dummy', 0, detectFlip=detectFlip,
3365
                                   hasInstrumentLabel=0, text_area='')
3366

    
3367
            Worker.remove_detected_symbol_image(dummySym, img, lock=False)
3368

    
3369
        Image.fromarray(img).show()
3370

    
3371
    #def paintEvent(self, event):
3372
    #    self.refresh_rate += 1
3373
    #    if self.refresh_rate == 3:
3374
    #        super(self.__class__, self).paintEvent(event)
3375
    #        self.refresh_rate = 0
3376

    
3377
if __name__ == '__main__':
3378
    import locale
3379
    from PyQt5.QtCore import QTranslator
3380
    from License import QLicenseDialog
3381
    from ProjectDialog import Ui_Dialog
3382
    from App import App
3383

    
3384
    app = App(sys.argv)
3385
    try:
3386
        if True == QLicenseDialog.check_license_key():
3387
            dlg = Ui_Dialog()
3388
            selectedProject = dlg.showDialog()
3389
            if selectedProject is not None:
3390
                AppDocData.instance().setCurrentProject(selectedProject)
3391
                app._mainWnd = MainWindow.instance()
3392
                app._mainWnd.show()
3393
                sys.exit(app.exec_())
3394
    except Exception as ex:
3395
        print('error occurred({}) in {}:{}'.format(ex, sys.exc_info()[-1].tb_frame.f_code.co_filename,
3396
                                                   sys.exc_info()[-1].tb_lineno))
3397
    finally:
3398
        pass
클립보드 이미지 추가 (최대 크기: 500 MB)