프로젝트

일반

사용자정보

통계
| 개정판:

hytos / DTI_PID / DTI_PID / MainWindow.py @ 63719626

이력 | 보기 | 이력해설 | 다운로드 (151 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
    toogle_lock_axis = pyqtSignal()
86

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

    
93
        super(self.__class__, self).__init__()
94
        self.setupUi(self)
95

    
96
        self.progress_bar = QProgressBar()
97
        self._label_mouse = QLabel(self.statusbar)
98
        self._label_mouse.setText(self.tr('mouse pos : ({},{})'.format(0, 0)))
99
        self.labelStatus = QLabel(self.statusbar)
100
        self.labelStatus.setText(self.tr('Unrecognition : '))
101
        self.labelSymbolStatus = QLabel(self.statusbar)
102
        self.labelSymbolStatus.setText(self.tr('Symbol : '))
103
        self.labelLineStatus = QLabel(self.statusbar)
104
        self.labelLineStatus.setText(self.tr('Line : '))
105
        self.labelTextStatus = QLabel(self.statusbar)
106
        self.labelTextStatus.setText(self.tr('Text : '))
107

    
108
        self.statusbar.addWidget(self._label_mouse)
109
        self.statusbar.addPermanentWidget(self.progress_bar, 1)
110
        self.statusbar.addPermanentWidget(self.labelSymbolStatus)
111
        self.statusbar.addPermanentWidget(self.labelLineStatus)
112
        self.statusbar.addPermanentWidget(self.labelTextStatus)
113
        self.statusbar.addPermanentWidget(self.labelStatus)
114

    
115
        #self.refresh_rate = 0
116

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

    
125
        # save timer
126
        self.save_timer = None
127

    
128
        self._scene = QtImageViewerScene(self)
129

    
130
        self.graphicsView = QtImageViewer(self)
131
        self.graphicsView.setParent(self.centralwidget)
132
        self.graphicsView.useDefaultCommand()  # USE DEFAULT COMMAND
133
        self.graphicsView.setMouseTracking(True)
134
        self.graphicsView.viewport().installEventFilter(self)
135
        self.graphicsView.setScene(self._scene)
136
        self.verticalLayout.addWidget(self.graphicsView)
137

    
138
        # Add Custom TreeWidget
139
        self.symbolTreeWidget = SymbolTreeWidget.QSymbolTreeWidget()
140
        self.symbolTreeWidget.header().hide()
141
        self.verticalLayoutSymbolTree.addWidget(self.symbolTreeWidget)
142
        self.lineEditFilter.textChanged.connect(self.on_search_text_changed)
143

    
144
        from LibraryItem import LibraryItemWidget
145
        self.libraryWidget = LibraryItemWidget(symbol_tree_widget=self.symbolTreeWidget)
146
        self.verticalLayoutLibrary.addWidget(self.libraryWidget)
147
        # Add Custom Property TableWidget
148
        self.propertyTableWidget = SymbolPropertyTableWidget.QSymbolPropertyTableWidget()
149
        self.verticalLayoutSymbolProperty.addWidget(self.propertyTableWidget)
150
        self.symbolTreeWidget.singleClicked.connect(self.propertyTableWidget.getClickedSymbol)
151

    
152
        self.splitterSymbol.setSizes([500, 300])
153

    
154
        # Add Custom Result Tree Widget (Symbol Explorer)
155
        self.itemTreeWidget = ItemTreeWidget.QItemTreeWidget(self.graphicsView)
156
        self.itemTreeWidget.header().hide()
157
        self.symbolExplorerVerticalLayout.addWidget(self.itemTreeWidget)
158

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

    
173
        # connect signals and slots
174
        self.actionClose.triggered.connect(self.close)
175
        self.actionOpen.triggered.connect(self.open_image_drawing)
176
        self.actionExportAsSVG.triggered.connect(self.export_as_svg)
177
        self.actionExportAsXML.triggered.connect(self.export_as_xml)
178
        self.actionExportAsImage.triggered.connect(self.export_as_image)
179
        self.actionLine.triggered.connect(self.onPlaceLine)
180
        self.actionRecognition.triggered.connect(self.recognize)
181
        self.pushButtonRefreshDrawings.clicked.connect(self.load_drawing_list)
182
        self.pushButtonRefreshTree.clicked.connect(self.refresh_item_list)
183
        self.actionLineRecognition.triggered.connect(self.connect_attributes)
184
        self.actionArea.triggered.connect(self.areaConfiguration)
185
        self.actionConfiguration.triggered.connect(self.configuration)
186
        self.actionOCR.triggered.connect(self.onAreaOcr)
187
        self.actionGenerateOutput.triggered.connect(self.generateOutput)
188
        self.pushButtonCreateSymbol.clicked.connect(self.onCreateSymbolClicked)
189
        self.toolButtonClearLog.clicked.connect(self.on_clear_log)
190
        self.actionStreamline.triggered.connect(self.on_streamline)
191
        self.actionHMB_DATA.triggered.connect(self.onHMBData)
192
        self.actionItem_Data_List.triggered.connect(self.showItemDataList)
193
        self.actionText_Data_List.triggered.connect(self.showTextDataList)
194
        self.actionSpecialItemTypes.triggered.connect(self.on_show_special_item_types)  # show special item types dialog
195
        self.actionDataTransfer.triggered.connect(self.on_show_data_transfer)  # show data transfer dialog
196
        self.actionDataExport.triggered.connect(self.on_show_data_export)
197
        self.actionExportEqpDatasheet.triggered.connect(self.on_show_eqp_datasheet_export)  # show eqp datasheet export dialog
198
        self.actionOPCRelation.triggered.connect(self.on_show_opc_relation)  # show OPC Relation dialog
199
        self.actionCodeTable.triggered.connect(self.onShowCodeTable)
200
        self.actionCustom_Code_Table.triggered.connect(self.onShowCustomCodeTable)
201
        self.actionReplace_Code_Table.triggered.connect(self.onShowReplaceCodeTable)
202
        self.actionImage_Drawing.triggered.connect(self.onViewImageDrawing)
203
        self.actionDrawing_Only.triggered.connect(self.onViewDrawingOnly)
204
        self.actionValidate.triggered.connect(self.onValidation)
205
        self.actionViewText.triggered.connect(self.onViewText)
206
        self.actionViewSymbol.triggered.connect(self.onViewSymbol)
207
        self.actionViewLine.triggered.connect(self.onViewLine)
208
        self.actionViewUnknown.triggered.connect(self.onViewUnknown)
209
        self.actionViewInconsistency.triggered.connect(self.onViewInconsistency)
210
        self.actionViewVendor_Area.triggered.connect(self.onViewVendorArea)
211
        self.actionRotate.triggered.connect(self.onRotate)
212
        self.actionZoom.triggered.connect(self.onAreaZoom)
213
        self.actionVendor.triggered.connect(self.onVendor)
214
        self.actionFitWindow.triggered.connect(self.fitWindow)
215
        self.actionpdf_to_image.triggered.connect(self.onConvertPDFToImage)
216
        self.actionImport_Text_From_CAD.triggered.connect(self.on_import_text_from_cad)
217
        self.actionImport_Text_from_CAD_for_Instrument.triggered.connect(self.on_import_text_from_cad_for_instrument)
218
        self.actionSymbol_Thickness_Reinforcement.triggered.connect(self.onSymbolThickness)
219
        self.actionHelp.triggered.connect(self.on_help)
220
        self.actionReadme.triggered.connect(self.on_readme)
221
        self.graphicsView.scene().selectionChanged.connect(self.onSelectionChanged)
222
        self.actionInitialize.triggered.connect(self.on_initialize_scene)
223
        self.actionSave.triggered.connect(self.actionSaveCliked)
224
        self.addMessage.connect(self.onAddMessage)
225
        self.toogle_lock_axis.connect(self.on_toggle_lock_axis)
226
        self.actionFindReplaceText.triggered.connect(self.findReplaceTextClicked)
227
        self.actionSymbol_Replace_Insert.triggered.connect(self.replaceInsertSymbolClicked)
228
        self.actionConnectLineToSymbol.triggered.connect(self.on_connect_line_to_symbol)
229
        self.actionGlobal_Validation.triggered.connect(self.on_validation_global_clicked)
230
        self.pushButtonDetectSymbol.clicked.connect(self.show_detect_symbol_dialog)
231
        self.actionUndo.triggered.connect(self._scene.undo_stack.undo)
232
        self.actionRedo.triggered.connect(self._scene.undo_stack.redo)
233

    
234
        self.delimiter = '"'
235

    
236
        self.resizeDocks({self.dockWidget}, {self.dockWidgetObjectExplorer.sizeHint().width()}, Qt.Horizontal)
237

    
238
        self.treeWidgetDrawingList.setHeaderHidden(False)
239
        self.treeWidgetDrawingList.header().setStretchLastSection(False)
240
        self.treeWidgetDrawingList.setHeaderLabels([self.tr('Name'), self.tr('DateTime')])
241
        self.treeWidgetDrawingList.header().setSectionResizeMode(0, QHeaderView.ResizeToContents)
242
        self.treeWidgetDrawingList.header().setSectionResizeMode(1, QHeaderView.ResizeToContents)
243
        self.treeWidgetDrawingList.header().setSectionsClickable(True)
244
        self.treeWidgetDrawingList.header().sectionClicked.connect(self.sort_drawing_list)
245
        self.treeWidgetDrawingList.itemDoubleClicked.connect(self.open_selected_drawing)
246
        self.load_drawing_list()
247

    
248
        self.ribbon = AppRibbon()
249
        self.setMenuWidget(self.ribbon)
250

    
251
        if not self.ribbon.advanced_mode:
252
            self.pushButtonCreateSymbol.setVisible(False)
253
            self.pushButtonDetectSymbol.setVisible(False)
254

    
255
        configs = app_doc_data.getConfigs('Line List', 'Use Stream No')
256
        if configs and int(configs[0].value) == 1:
257
            pass
258
        else:
259
            self.ribbon.get_pane('Home Visualization').ui.radioButtonByStreamNo.setHidden(True)
260

    
261
        view_pane = self.ribbon.get_pane('View')
262
        shortcut = QShortcut(QKeySequence(Qt.Key_1), view_pane.ui.toolButtonViewImageDrawing)
263
        shortcut.activated.connect(partial(self.on_view_toggle, Qt.Key_1))
264
        shortcut = QShortcut(QKeySequence(Qt.Key_2), view_pane.ui.toolButtonViewText)
265
        shortcut.activated.connect(partial(self.on_view_toggle, Qt.Key_2))
266
        shortcut = QShortcut(QKeySequence(Qt.Key_3), view_pane.ui.toolButtonViewSymbol)
267
        shortcut.activated.connect(partial(self.on_view_toggle, Qt.Key_3))
268
        shortcut = QShortcut(QKeySequence(Qt.Key_4), view_pane.ui.toolButtonViewLine)
269
        shortcut.activated.connect(partial(self.on_view_toggle, Qt.Key_4))
270
        shortcut = QShortcut(QKeySequence(Qt.Key_5), view_pane.ui.toolButtonViewUnknown)
271
        shortcut.activated.connect(partial(self.on_view_toggle, Qt.Key_5))
272
        shortcut = QShortcut(QKeySequence(Qt.Key_6), view_pane.ui.toolButtonViewInconsistency)
273
        shortcut.activated.connect(partial(self.on_view_toggle, Qt.Key_6))
274
        shortcut = QShortcut(QKeySequence(Qt.Key_7), view_pane.ui.toolButtonViewVendorArea)
275
        shortcut.activated.connect(partial(self.on_view_toggle, Qt.Key_7))
276
        shortcut = QShortcut(QKeySequence(96), view_pane.ui.toolButtonViewDrawingOnly)
277
        shortcut.activated.connect(partial(self.on_view_toggle, 96))
278

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

    
287
        self.read_settings()
288

    
289
    @property
290
    def title(self) -> str:
291
        """return window title"""
292

    
293
        from App import App
294

    
295
        app_doc_data = AppDocData.instance()
296
        project = app_doc_data.getCurrentProject()
297
        version = QCoreApplication.applicationVersion()
298
        title = f"{App.NAME}({version}) - {project.name}:" \
299
                f"{app_doc_data.activeDrawing.name if app_doc_data.activeDrawing else ''}"
300
        #title = f"{App.NAME} : ID2 " \
301
        #        f"{app_doc_data.activeDrawing.name if app_doc_data.activeDrawing else ''}"
302

    
303
        return title
304

    
305
    @property
306
    def scene(self):
307
        """getter scene"""
308
        return self._scene
309

    
310
    def eventFilter(self, source, event):
311
        """display mouse position of graphics view"""
312
        try:
313
            if event.type() == QEvent.MouseMove:
314
                self.current_pos = self.graphicsView.mapToScene(event.pos())
315
                self._label_mouse.setText(
316
                    'mouse pos : ({},{})'.format(round(self.current_pos.x()), round(self.current_pos.y())))
317
        except Exception as ex:
318
            message = 'error occurred({}) in {}:{}'.format(ex, sys.exc_info()[-1].tb_frame.f_code.co_filename,
319
                                                           sys.exc_info()[-1].tb_lineno)
320
            self.addMessage.emit(MessageType.Error, message)
321

    
322
        return QWidget.eventFilter(self, source, event)
323

    
324
    def closeEvent(self, event):
325
        """save geometry and state and ask user to save drawing which is modified"""
326

    
327
        self.settings.setValue('geometry', self.saveGeometry())
328
        self.settings.setValue('windowState', self.saveState())
329
        # TODO: need to modify
330

    
331
        """save current view region"""
332
        app_doc_data = AppDocData.instance()
333
        if app_doc_data.activeDrawing:
334
            rect = self.graphicsView.viewport().rect()
335
            app_doc_data.activeDrawing.view_rect = self.graphicsView.mapToScene(rect).boundingRect()
336
            app_doc_data.update_view_region(app_doc_data.activeDrawing)
337
        """up to here"""
338

    
339
        # self.save_drawing_if_necessary()
340
        AppDocData.instance().clear()
341
        event.accept()
342

    
343
    def inconsistencyTableKeyPressEvent(self, event):
344
        try:
345
            row = self.tableWidgetInconsistency.selectedIndexes()[0].row()
346
            col = self.tableWidgetInconsistency.selectedIndexes()[0].column()
347
            from HighlightCommand import HighlightCommand
348
            if event.key() == Qt.Key_Up:
349
                if row is not 0:
350
                    errorItem = self.tableWidgetInconsistency.item(row - 1, 1).tag
351
                    HighlightCommand(self.graphicsView).execute(errorItem)
352
            elif event.key() == Qt.Key_Down:
353
                if row is not self.tableWidgetInconsistency.rowCount() - 1:
354
                    errorItem = self.tableWidgetInconsistency.item(row + 1, 1).tag
355
                    HighlightCommand(self.graphicsView).execute(errorItem)
356
            elif event.key() == Qt.Key_Delete:
357
                item = self.tableWidgetInconsistency.item(row, 0).tag
358
                if item and item.scene(): item.scene().removeItem(item)
359
                self.tableWidgetInconsistency.removeRow(row)
360

    
361
                self.tabWidget_2.setTabText(self.tabWidget_2.indexOf(self.tabInconsistency),
362
                                            self.tr('Inconsistency') + f"({self.tableWidgetInconsistency.rowCount()})")
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
        # finally:
368
        #    return QTableView.keyPressEvent(self.tableWidgetInconsistency, event)
369

    
370
    def onValidation(self):
371
        """validation check"""
372
        from ValidationDialog import QValidationDialog
373
        from ValidateCommand import ValidateCommand
374

    
375
        if not self.graphicsView.hasImage():
376
            self.showImageSelectionMessageBox()
377
            return
378

    
379
        try:
380
            dlg = QValidationDialog(self)
381
            if QDialog.Accepted == dlg.exec_():
382
                # remove error items
383
                for item in self.graphicsView.scene().items():
384
                    if type(item) is QEngineeringErrorItem:
385
                        item.transfer.onRemoved.emit(item)
386
                # up to here
387

    
388
                self.progress_bar.setMaximum(len(self.graphicsView.scene().items()))
389
                self.progress_bar.setValue(0)
390

    
391
                cmd = ValidateCommand(self.graphicsView)
392
                cmd.show_progress.connect(self.progress_bar.setValue)
393
                errors = cmd.execute(self.graphicsView.scene().items())
394
                for error in errors:
395
                    error.transfer.onRemoved.connect(self.itemRemoved)
396
                    #self.graphicsView.scene().addItem(error)
397
                    error.addSvgItemToScene(self.graphicsView.scene())
398

    
399
                self.tableWidgetInconsistency.clearContents()
400
                self.tableWidgetInconsistency.setRowCount(len(errors))
401
                for index, error in enumerate(errors):
402
                    self.makeInconsistencyTableRow(index, error)
403

    
404
                self.tabWidget_2.setTabText(self.tabWidget_2.indexOf(self.tabInconsistency),
405
                                            self.tr('Inconsistency') + f"({len(errors)})")
406
                if errors:
407
                    self.tabWidget_2.tabBar().setTabTextColor(self.tabWidget_2.indexOf(self.tabInconsistency), Qt.red)
408
                else:
409
                    self.tabWidget_2.tabBar().setTabTextColor(self.tabWidget_2.indexOf(self.tabInconsistency), Qt.black)
410
        except Exception as ex:
411
            message = 'error occurred({}) in {}:{}'.format(ex, sys.exc_info()[-1].tb_frame.f_code.co_filename,
412
                                                           sys.exc_info()[-1].tb_lineno)
413
            self.addMessage.emit(MessageType.Error, message)
414
        finally:
415
            self.progress_bar.setValue(self.progress_bar.maximum())
416

    
417
    def makeInconsistencyTableRow(self, row, errorItem):
418
        '''
419
            @brief  make row data for inconsistency widget
420
            @author euisung
421
            @date   2019.04.16
422
        '''
423

    
424
        item = QTableWidgetItem(str(errorItem.parent))
425
        item.tag = errorItem
426
        self.tableWidgetInconsistency.setItem(row, 0, item)
427

    
428
        item = QTableWidgetItem(str(type(errorItem.parent)))
429
        item.tag = errorItem
430
        self.tableWidgetInconsistency.setItem(row, 1, item)
431

    
432
        item = QTableWidgetItem(errorItem.msg)
433
        item.tag = errorItem
434
        self.tableWidgetInconsistency.setItem(row, 2, item)
435

    
436
    def inconsistencyItemClickEvent(self, item):
437
        """
438
        @brief  inconsistency table item clicked
439
        @author euisung
440
        @date   2019.04.02
441
        """
442
        from HighlightCommand import HighlightCommand
443

    
444
        HighlightCommand(self.graphicsView).execute(item.tag)
445

    
446
    def read_settings(self):
447
        """read geometry and state"""
448
        from App import App
449

    
450
        try:
451
            self.settings = QSettings(App.COMPANY, App.NAME)
452
            self.restoreGeometry(self.settings.value("geometry", ""))
453
            self.restoreState(self.settings.value("windowState", ""))
454
        except Exception as ex:
455
            message = f"error occurred({repr(ex)}) in {sys.exc_info()[-1].tb_frame.f_code.co_filename}:" \
456
                      f"{sys.exc_info()[-1].tb_lineno}"
457

    
458
    def load_stylesheet(self, file):
459
        """load stylesheets"""
460

    
461
        QtWidgets.qApp.loadStyleSheet(os.path.join(os.path.dirname(os.path.realpath(__file__)), file))
462

    
463
        app_doc_data = AppDocData.instance()
464
        configs = [Config('app', 'stylesheet', file)]
465
        app_doc_data.saveAppConfigs(configs)
466

    
467
    def load_language(self, file):
468
        """load language file and then apply selected language"""
469
        try:
470
            qm_file = os.path.join(os.path.dirname(os.path.realpath(__file__)), 'translate', '{0}.qm'.format(file))
471
            QtWidgets.qApp.load_language(qm_file)
472

    
473
            app_doc_data = AppDocData.instance()
474
            configs = [Config('app', 'language', file)]
475
            app_doc_data.saveAppConfigs(configs)
476
        finally:
477
            self.retranslateUi(self)
478

    
479
    def refresh_item_list(self):
480
        """refresh item tree"""
481
        self.itemTreeWidget.InitLineNoItems()
482

    
483
        line_nos = AppDocData.instance().tracerLineNos
484
        for line_no in line_nos:
485
            item = self.itemTreeWidget.addTreeItem(self.itemTreeWidget.root, line_no)
486
            connectedItems = line_no.getConnectedItems()
487
            for connectedItem in connectedItems:
488
                if issubclass(type(connectedItem), SymbolSvgItem):
489
                    self.itemTreeWidget.addTreeItem(item, connectedItem)
490
        
491
    def sort_drawing_list(self, index):
492
        """ sort drawing list """
493
        if index == 0:
494
            if self.drawing_reverse:
495
                self.load_drawing_list(reverse=False)
496
            else:
497
                self.load_drawing_list(reverse=True)
498

    
499

    
500
    def load_drawing_list(self, reverse=False):
501
        """load p&id drawing list"""
502
        from Drawing import Drawing
503

    
504
        try:
505
            app_doc_data = AppDocData.instance()
506
            drawings = app_doc_data.getDrawings()
507

    
508
            self.treeWidgetDrawingList.clear()
509
            self.treeWidgetDrawingList.root = QTreeWidgetItem(self.treeWidgetDrawingList,
510
                                                              [self.tr('P&ID Drawings'), ''])
511
            self.treeWidgetDrawingList.root.setFlags(
512
                self.treeWidgetDrawingList.root.flags() | Qt.ItemIsTristate | Qt.ItemIsUserCheckable)
513
            self.treeWidgetDrawingList.root.setCheckState(0, Qt.Unchecked)
514
            files = app_doc_data.getDrawingFileList()
515

    
516
            # self.progress_bar.setMaximum(len(files))
517
            count = 0
518
            # self.progress_bar.setValue(count)
519
            self.drawing_reverse = reverse
520
            for file in files if not self.drawing_reverse else reversed(files):
521
                x = [drawing for drawing in drawings if drawing.name == file]
522
                if not x or not x[0].UID:
523
                    drawing = Drawing(None, file, None)
524
                    drawings.append(drawing)
525
                else:
526
                    drawing = x[0]
527

    
528
                item = QTreeWidgetItem(self.treeWidgetDrawingList.root, [file, drawing.datetime])
529
                item.setIcon(0, QIcon(':newPrefix/image.png'))
530
                item.setFlags(item.flags() | Qt.ItemIsUserCheckable)
531
                item.setCheckState(0, Qt.Unchecked)
532
                item.setData(Qt.UserRole, 0, drawing)
533

    
534
                count += 1
535
                # self.progress_bar.setValue(count)
536
                # QApplication.processEvents()
537

    
538
            self.treeWidgetDrawingList.root.setText(0, self.tr('P&ID Drawings') +
539
                                                    f"({self.treeWidgetDrawingList.root.childCount()})")
540
            self.treeWidgetDrawingList.expandItem(self.treeWidgetDrawingList.root)
541
            #self.treeWidgetDrawingList.root.sortChildren(0, Qt.AscendingOrder)
542
            self.treeWidgetDrawingList.resizeColumnToContents(0)
543

    
544
            app_doc_data.saveDrawings(drawings)
545
        except Exception as ex:
546
            message = 'error occurred({}) in {}:{}'.format(repr(ex), sys.exc_info()[-1].tb_frame.f_code.co_filename,
547
                                                           sys.exc_info()[-1].tb_lineno)
548
            self.addMessage.emit(MessageType.Error, message)
549
        finally:
550
            self.progress_bar.setValue(self.progress_bar.maximum())
551

    
552
    def open_selected_drawing(self, item, column):
553
        """open selected p&id drawing"""
554

    
555
        app_doc_data = AppDocData.instance()
556
        drawing = item.data(Qt.UserRole, 0)
557
        if drawing:
558
            # uncheck all drawing tree item
559
            drawing_top = self.treeWidgetDrawingList.topLevelItem(0)
560
            count = drawing_top.childCount()
561
            for idx in range(count):
562
                child = drawing_top.child(idx)
563
                child.setCheckState(column, Qt.Unchecked)
564
            # up to here
565

    
566
            drawing.image = None
567
            self.open_image_drawing(drawing)
568
            item.setCheckState(column, Qt.Checked)
569

    
570
    def show_detect_symbol_dialog(self):
571
        from DetectSymbolDialog import QDetectSymbolDialog
572

    
573
        dlg = QDetectSymbolDialog(self)
574
        dlg.exec_()
575

    
576
    '''
577
        @brief      OCR Editor
578
        @author     euisung
579
        @date       2018.10.05
580
        @history    2018.10.16 euisung      no more used, Integrated with oCRTrainingClicked
581
    '''
582

    
583
    def oCRTrainingEdidorClicked(self):
584
        from TrainingEditorDialog import QTrainingEditorDialog
585

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

    
594
        return
595

    
596
    '''
597
        @brief      OCR Training
598
        @author     euisung
599
        @date       2018.09.27
600
        @history    euisung 2018.10.16 TrainingListDialog -> TrainingImageListDialog
601
    '''
602

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

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

    
622
    def findReplaceTextClicked(self):
623
        """pop up find and replace dialog"""
624
        if not self.graphicsView.hasImage():
625
            self.showImageSelectionMessageBox()
626
            return
627

    
628
        from TextItemEditDialog import QTextItemEditDialog
629

    
630
        dlgTextItemEdit = QTextItemEditDialog(self)
631
        dlgTextItemEdit.show()
632
        dlgTextItemEdit.exec_()
633

    
634
    def on_validation_global_clicked(self):
635
        """ global validation dialog """
636
        from ValidationGlobalDialog import QValidationGlobalDialog
637

    
638
        dlg = QValidationGlobalDialog(self)
639
        dlg.show()
640
        dlg.exec_()
641

    
642
    def replaceInsertSymbolClicked(self):
643
        """pop up replace and insert dialog"""
644
        if not self.graphicsView.hasImage():
645
            self.showImageSelectionMessageBox()
646
            return
647

    
648
        from ReplaceSymbolDialog import QReplaceSymbolDialog
649

    
650
        dlg = QReplaceSymbolDialog(self)
651
        dlg.show()
652
        dlg.exec_()
653

    
654
    def on_ocr_unknown_items(self):
655
        """ try to ocr for unknown items """
656
        from OcrResultDialog import QOcrResultDialog
657

    
658
        if not self.graphicsView.hasImage():
659
            self.showImageSelectionMessageBox()
660
            return
661

    
662
        app_doc_data = AppDocData.instance()
663
        configs = app_doc_data.getConfigs('Text Size', 'Max Text Size')
664
        maxSize = int(configs[0].value) if 1 == len(configs) else 100
665
        configs = app_doc_data.getConfigs('Text Size', 'Min Text Size')
666
        minSize = int(configs[0].value) if 1 == len(configs) else 15
667

    
668
        unknowns = [item for item in self.graphicsView.scene().items() if type(item) is QEngineeringUnknownItem]
669

    
670
        for unknown in unknowns:
671
            rect = unknown.sceneBoundingRect()
672
            if rect.width() < minSize or rect.height() < minSize or rect.width() > maxSize or rect.height() > maxSize:
673
                continue
674
            if self.onRecognizeText(round(rect.left()), round(rect.top()), round(rect.width()), round(rect.height()), show=False):
675
                unknown.transfer.onRemoved.emit(unknown)
676

    
677
    def on_connect_line_to_symbol(self):
678
        """connect line to symbol"""
679
        from LineDetector import LineDetector
680
        from RecognitionDialog import Worker
681

    
682
        if not self.graphicsView.hasImage():
683
            self.showImageSelectionMessageBox()
684
            return
685

    
686
        app_doc_data = AppDocData.instance()
687
        #configs = app_doc_data.getConfigs('Project', 'Operation')
688
        configs = app_doc_data.getConfigs('Line Detector', 'Length to connect line')
689
        toler = int(configs[0].value) if configs else 20
690
        detector = LineDetector(app_doc_data.imgSrc)
691

    
692
        lines = [item for item in self.graphicsView.scene().items() if type(item) is QEngineeringLineItem if item.length() > 50]
693
        lines_short = [item for item in self.graphicsView.scene().items() if type(item) is QEngineeringLineItem if item.length() <= 50]
694
        unknowns = [item for item in self.graphicsView.scene().items() if type(item) is QEngineeringUnknownItem]
695
        symbols = [item for item in self.graphicsView.scene().items() if issubclass(type(item), SymbolSvgItem)]
696

    
697
        for item in lines_short + unknowns:
698
            item.transfer.onRemoved.emit(item)
699
        
700
        if lines:
701
            new_lines = []
702
            try:
703
                conns = []
704
                for sym in symbols:
705
                    if sym.conn_type:
706
                        for index in range(len(sym.conn_type)):
707
                            if sym.conn_type[index] == 'Secondary' or sym.conn_type[index] == 'Primary':
708
                                item = sym.connectors[index].connectedItem
709
                                if item is None:
710
                                    conns.append(sym.connectors[index])
711
                
712
                new_lines.extend(Worker.make_short_lines_sts(conns, None))
713

    
714
                conns = []
715
                for sym in symbols:
716
                    if sym.conn_type:
717
                        for index in range(len(sym.conn_type)):
718
                            if sym.conn_type[index] == 'Secondary' or sym.conn_type[index] == 'Primary':
719
                                item = sym.connectors[index].connectedItem
720
                                if item is None and sym.connectors[index]:
721
                                    conns.append(sym.connectors[index])
722
                
723
                new_lines.extend(Worker.make_short_lines_stl(lines, conns, None))
724

    
725
                for line in new_lines:
726
                    self.graphicsView.scene().addItem(line)
727
                    for conn in line.connectors:
728
                        conn.transfer.onPosChanged.connect(line.onConnectorPosChaned)
729
            except Exception as ex:
730
                message = f"error occurred({repr(ex)}) in {sys.exc_info()[-1].tb_frame.f_code.co_filename}:" \
731
                          f"{sys.exc_info()[-1].tb_lineno}"
732
                self.addMessage.emit(MessageType.Error, message)
733
                
734
            # connect line to symbol
735
            try:
736
                for line in lines:
737
                    matches = [_symbol for _symbol in symbols if _symbol.is_connectable(line, toler=toler)]
738
                    for _symbol in matches:
739
                        detector.connectLineToSymbol(line, _symbol, toler=toler)
740
            except Exception as ex:
741
                message = f"error occurred({repr(ex)}) in {sys.exc_info()[-1].tb_frame.f_code.co_filename}:" \
742
                          f"{sys.exc_info()[-1].tb_lineno}"
743
                self.addMessage.emit(MessageType.Error, message)
744
            # up to here
745

    
746
            # connect line to line
747
            try:
748
                for line in lines:
749
                    matches = [it for it in lines if (it is not line) and (not line.isParallel(it))]
750

    
751
                    for match in matches:
752
                        detector.connectLineToLine(match, line, toler)
753
            except Exception as ex:
754
                message = f"error occurred({repr(ex)}) in {sys.exc_info()[-1].tb_frame.f_code.co_filename}:" \
755
                          f"{sys.exc_info()[-1].tb_lineno}"
756
                self.addMessage.emit(MessageType.Error, message)
757
            # up to here
758

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

    
761
    def on_recognize_line(self):
762
        """recognize lines in selected area"""
763
        from RecognizeLineCommand import RecognizeLineCommand
764

    
765
        if not self.graphicsView.hasImage():
766
            self.actionOCR.setChecked(False)
767
            self.showImageSelectionMessageBox()
768
            return
769

    
770
        cmd = RecognizeLineCommand(self.graphicsView)
771
        cmd.onSuccess.connect(self.on_success_to_recognize_line)
772
        cmd.onRejected.connect(self.onCommandRejected)
773
        self.graphicsView.command = cmd
774

    
775
    '''
776
            @brief      show text recognition dialog
777
            @author     humkyung
778
            @date       2018.08.08
779
    '''
780

    
781
    def on_success_to_recognize_line(self, x, y, width, height):
782
        import io
783
        from LineDetector import LineDetector
784
        from EngineeringGraphicsLineItem import QEngineeringGraphicsLineItem
785

    
786
        try:
787
            image = self.graphicsView.image().copy(x, y, width, height)
788
            buffer = QBuffer()
789
            buffer.open(QBuffer.ReadWrite)
790
            image.save(buffer, "PNG")
791
            pyImage = Image.open(io.BytesIO(buffer.data()))
792
            img = np.array(pyImage)
793
            img = cv2.cvtColor(img, cv2.COLOR_BGR2GRAY)
794

    
795
            detector = LineDetector(img)
796
            lines = detector.detect_line_without_symbol()
797
            for line in lines:
798
                vertices = [[line[0][0] + x, line[0][1] + y], [line[1][0] + x, line[1][1] + y]]
799
                line_item = QEngineeringGraphicsLineItem(vertices)
800
                self.graphicsView.scene().addItem(line_item)
801

    
802
        except Exception as ex:
803
            message = 'error occurred({}) in {}:{}'.format(repr(ex), sys.exc_info()[-1].tb_frame.f_code.co_filename,
804
                                                           sys.exc_info()[-1].tb_lineno)
805
            self.addMessage.emit(MessageType.Error, message)
806

    
807
    def display_number_of_items(self):
808
        """display count of symbol, line, text"""
809

    
810
        items = [item for item in self.graphicsView.scene().items() if type(item) is QEngineeringUnknownItem]
811
        if len(items) > 0:
812
            self.labelStatus.setText(
813
                "<font color='red'>" + self.tr('Unrecognition') + " : {}</font>".format(len(items)))
814
        else:
815
            self.labelStatus.setText(
816
                "<font color='black'>" + self.tr('Unrecognition') + " : {}</font>".format(len(items)))
817

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

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

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

    
828
        self.itemTreeWidget.sceneChanged(self.graphicsView.scene().items())
829

    
830
    def dbUpdate(self):
831
        """ no more used """
832
        """db update when save or recognition"""
833

    
834
        try:
835
            appDocData = AppDocData.instance()
836
            items = appDocData.allItems
837

    
838
            '''
839
            titleBlockProps = appDocData.getTitleBlockProperties()
840
            titleBlockItems = []
841
            for item in items:
842
                # if type(item) is QEngineeringLineNoTextItem:
843
                #    item.saveLineData()
844
                if type(item) is QEngineeringTextItem:
845
                    for titleBlockProp in titleBlockProps:
846
                        if item.area == titleBlockProp[0]:
847
                            titleBlockItems.append(item)
848
            '''
849

    
850
            # unknown item is not saved now for performance
851
            db_items = [item for item in items if issubclass(type(item), QEngineeringAbstractItem) and
852
                        type(item) is not QGraphicsBoundingBoxItem and
853
                        type(item) is not QEngineeringErrorItem and
854
                        type(item) is not QEngineeringLineNoTextItem and
855
                        type(item) is not QEngineeringUnknownItem]
856
            db_items.extend([item for item in items if type(item) is QEngineeringLineNoTextItem])
857
            db_items.extend([line for line in appDocData.tracerLineNos if type(line) is QEngineeringTrimLineNoTextItem])
858
            # db_items.extend(titleBlockItems)
859
            configs = appDocData.getConfigs('Data Save', 'Unknown Xml Only')
860
            if configs and int(configs[0].value) is -1:
861
                db_items.extend([item for item in items if type(item) is QEngineeringUnknownItem])
862

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

    
877
    def save_drawing_if_necessary(self):
878
        """ask to user to save drawing or not when drawing is modified"""
879

    
880
        app_doc_data = AppDocData.instance()
881
        if app_doc_data.activeDrawing and app_doc_data.activeDrawing.modified:
882
            #if QMessageBox.Yes == QMessageBox.question(self, self.tr("Question"),
883
            #                                           self.tr("Do you want to save drawing?"),
884
            #                                           QMessageBox.Yes | QMessageBox.No):
885
            #    self.actionSaveCliked()
886
            #    return True
887
            if QMessageBox.Ignore == QMessageBox.question(self, self.tr('Continue?'),
888
                                                       self.tr('Changes may not have been saved.'),
889
                                                       QMessageBox.Ignore | QMessageBox.Cancel):
890
                return False
891
            return True
892

    
893
    def actionSaveCliked(self):
894
        """
895
        save current drawing
896
        @return:
897
        """
898
        from EngineeringAbstractItem import QEngineeringAbstractItem
899
        from SaveWorkCommand import SaveWorkCommand
900

    
901
        try:
902
            home_pane = self.ribbon.get_pane('Home File')
903
            if not home_pane.ui.toolButtonFileSave.isEnabled():
904
                return
905

    
906
            home_pane.ui.toolButtonFileSave.setEnabled(False)
907

    
908
            # save alarm
909
            self.save_alarm_enable(False)
910

    
911
            app_doc_data = AppDocData.instance()
912
            if app_doc_data.imgName is None:
913
                self.showImageSelectionMessageBox()
914
                return
915

    
916
            app_doc_data.clearItemList(False)
917

    
918
            items = self.graphicsView.scene().items()
919

    
920
            self._save_work_cmd = SaveWorkCommand(self.graphicsView.scene())
921
            self._save_work_cmd.show_progress.connect(self.progress_bar.setValue)
922
            self._save_work_cmd.display_message.connect(self.onAddMessage)
923
            self._save_work_cmd.finished.connect(self.save_finished)
924

    
925
            self._save_work_cmd.start()
926
        except Exception as ex:
927
            message = f"error occurred({repr(ex)}) in {sys.exc_info()[-1].tb_frame.f_code.co_filename}:" \
928
                      f"{sys.exc_info()[-1].tb_lineno}"
929
            self.addMessage.emit(MessageType.Error, message)
930

    
931
    def save_finished(self):
932
        """
933
        reload drawing list when save is finished
934
        @return: None
935
        """
936

    
937
        try:
938
            self._save_work_cmd.show_progress.emit(100)
939
            QMessageBox.about(self.graphicsView, self.tr('Information'), self._save_work_cmd.resultStr)
940
            self.load_drawing_list()
941

    
942
            app_doc_data = AppDocData.instance()
943
            app_doc_data.activeDrawing.modified = False
944
            title = self.windowTitle()
945
            self.setWindowTitle(title[:-1] if title[-1] == '*' else title)
946

    
947
            # save alarm
948
            self.save_alarm_enable(True)
949
        finally:
950
            home_pane = self.ribbon.get_pane('Home File')
951
            home_pane.ui.toolButtonFileSave.setEnabled(True)
952

    
953
    '''
954
        @brief      refresh resultPropertyTableWidget
955
        @author     kyouho
956
        @date       2018.07.19
957
    '''
958

    
959
    def refreshResultPropertyTableWidget(self):
960
        items = self.graphicsView.scene().selectedItems()
961
        if len(items) == 1:
962
            self.resultPropertyTableWidget.show_item_property(items[0])
963

    
964
    '''
965
        @brief  add message listwidget
966
        @author humkyung
967
        @date   2018.07.31
968
    '''
969

    
970
    def onAddMessage(self, messageType, message):
971
        from AppDocData import MessageType
972

    
973
        try:
974
            current = QDateTime.currentDateTime()
975

    
976
            item = QListWidgetItem('{}: {}'.format(current.toString('hh:mm:ss'), message))
977
            item.setFlags(item.flags() | Qt.ItemIsEditable)
978
            if messageType == MessageType.Error:
979
                item.setBackground(Qt.red)
980
            elif messageType == 'check':
981
                item.setBackground(Qt.yellow)
982

    
983
            self.listWidgetLog.insertItem(0, item)
984
        except Exception as ex:
985
            print('error occurred({}) in {}:{}'.format(ex, sys.exc_info()[-1].tb_frame.f_code.co_filename,
986
                                                       sys.exc_info()[-1].tb_lineno))
987

    
988
    def on_clear_log(self):
989
        """clear log"""
990
        self.listWidgetLog.clear()
991

    
992
    def onRotate(self, action):
993
        """rotate a selected symbol"""
994
        selected = [item for item in self.graphicsView.scene().selectedItems() if issubclass(type(item), SymbolSvgItem)]
995
        if len(selected) == 1:
996
            from RotateCommand import RotateCommand
997
            self.graphicsView.scene()._undo_stack.push(RotateCommand(self.graphicsView.scene(), selected))
998

    
999
    def onAreaZoom(self):
1000
        """Area Zoom"""
1001
        visualization_pane = self.ribbon.get_pane('Home Visualization')
1002

    
1003
        self.update_action_group(visualization_pane.ui.toolButtonZoom)
1004
        if visualization_pane.ui.toolButtonZoom.isChecked():
1005
            cmd = AreaZoomCommand.AreaZoomCommand(self.graphicsView)
1006
            cmd.onRejected.connect(self.onCommandRejected)
1007
            self.graphicsView.command = cmd
1008

    
1009
    def onVendor(self, action):
1010
        """make vendor/equipment package area"""
1011

    
1012
        pane = self.ribbon.get_pane('Home')
1013
        if not self.graphicsView.hasImage():
1014
            pane.ui.toolButtonVendor.setChecked(False)
1015
            self.showImageSelectionMessageBox()
1016
            return
1017

    
1018
        pane = self.ribbon.get_pane('Home')
1019
        self.update_action_group(pane.ui.toolButtonVendor)
1020
        checked = pane.ui.toolButtonVendor.isChecked()
1021
        if not hasattr(pane.ui.toolButtonVendor, 'tag'):
1022
            pane.ui.toolButtonVendor.tag = PlacePolygonCommand.PlacePolygonCommand(self.graphicsView)
1023
            pane.ui.toolButtonVendor.tag.onSuccess.connect(self.onVendorCreated)
1024
            pane.ui.toolButtonVendor.tag.onRejected.connect(self.onCommandRejected)
1025

    
1026
        self.graphicsView.command = pane.ui.toolButtonVendor.tag
1027

    
1028
    def onVendorCreated(self):
1029
        """add created vendor polygon area to scene"""
1030

    
1031
        try:
1032
            vendor_tool = self.ribbon.get_pane('Home').ui.toolButtonVendor
1033
            package_combo = self.ribbon.get_pane('Home').ui.comboBoxPackage
1034
            count = len(vendor_tool.tag._polyline._vertices)
1035
            if count > 2:
1036
                points = []
1037
                for point in vendor_tool.tag._polyline._vertices:
1038
                    points.append(QPoint(round(point[0]), round(point[1])))
1039
                polygon = QPolygonF(points)
1040
                item = QEngineeringVendorItem(polygon, pack_type=package_combo.currentText())
1041
                item.area = 'Drawing'
1042
                item.transfer.onRemoved.connect(self.itemRemoved)
1043
                self.graphicsView.scene().addItem(item)
1044
        finally:
1045
            self.graphicsView.scene().removeItem(vendor_tool.tag._polyline)
1046
            vendor_tool.tag.reset()
1047

    
1048
    def fitWindow(self, view_rect: QRectF = QRectF()):
1049
        """Fit Window"""
1050
        self.graphicsView.useDefaultCommand()
1051
        self.graphicsView.zoomImageInit()
1052

    
1053
        visualization_pane = self.ribbon.get_pane('Home Visualization')
1054
        self.update_action_group(visualization_pane.ui.toolButtonFitWindow)
1055
        if view_rect:
1056
            self.graphicsView.zoom_rect(view_rect)
1057

    
1058
    def on_toggle_lock_axis(self):
1059
        """toggle lock axis"""
1060
        from EngineeringPolylineItem import QEngineeringPolylineItem
1061

    
1062
        visualization_pane = self.ribbon.get_pane('Home Visualization')
1063
        if self.sender() is not visualization_pane.ui.toolButtonLockAxis:
1064
            checked = visualization_pane.ui.toolButtonLockAxis.isChecked()
1065
            visualization_pane.ui.toolButtonLockAxis.setChecked(not checked)
1066

    
1067
        checked = visualization_pane.ui.toolButtonLockAxis.isChecked()
1068
        QEngineeringPolylineItem.DRAWING_MODE = QEngineeringPolylineItem.AXIS_MODE if checked else \
1069
            QEngineeringPolylineItem.FREE_MODE
1070

    
1071
    def scene_changed(self):
1072
        """update modified flag"""
1073

    
1074
        self.display_number_of_items()
1075

    
1076
        app_doc_data = AppDocData.instance()
1077
        app_doc_data.activeDrawing.modified = True
1078
        title = self.windowTitle()
1079
        self.setWindowTitle(title if title[-1] == '*' else title + '*')
1080

    
1081
    def onConvertPDFToImage(self):
1082
        """convert to selected pdf to image"""
1083
        import os
1084

    
1085
        try:
1086
            file_path = os.path.join(os.path.dirname(os.path.realpath(__file__)), 'bin64', 'PDF_TO_IMAGE.exe')
1087
            os.startfile(file_path)
1088
        except Exception as ex:
1089
            message = 'error occurred({}) in {}:{}'.format(ex, sys.exc_info()[-1].tb_frame.f_code.co_filename,
1090
                                                           sys.exc_info()[-1].tb_lineno)
1091
            self.addMessage.emit(MessageType.Error, message)
1092

    
1093
    def on_import_text_from_cad_for_instrument(self):
1094
        """ import text from cad for instrument """
1095
        try:
1096
            self.onCommandRejected()
1097
            dialog = QImportTextFromPDFDialog(self)
1098
            dialog.show()
1099
            dialog.exec_()
1100
        except Exception as ex:
1101
            message = f"error occurred({repr(ex)}) in {sys.exc_info()[-1].tb_frame.f_code.co_filename}:" \
1102
                      f"{sys.exc_info()[-1].tb_lineno}"
1103
            self.addMessage.emit(MessageType.Error, message)
1104

    
1105
    def on_import_text_from_cad(self):
1106
        """ import text from cad """
1107
        try:
1108
            self.onCommandRejected()
1109
            dialog = QImportTextFromCADDialog(self)
1110
            dialog.show()
1111
            dialog.exec_()
1112
        except Exception as ex:
1113
            message = f"error occurred({repr(ex)}) in {sys.exc_info()[-1].tb_frame.f_code.co_filename}:" \
1114
                      f"{sys.exc_info()[-1].tb_lineno}"
1115
            self.addMessage.emit(MessageType.Error, message)
1116

    
1117
    def onSymbolThickness(self):
1118
        """ symbol thickness reinforcement by using configuration filter drawing dilate size """
1119
        try:
1120
            self.onCommandRejected()
1121
            dialog = QSymbolThicknessDialog(self)
1122
            dialog.exec_()
1123
        except Exception as ex:
1124
            message = 'error occurred({}) in {}:{}'.format(ex, sys.exc_info()[-1].tb_frame.f_code.co_filename,
1125
                                                           sys.exc_info()[-1].tb_lineno)
1126
            self.addMessage.emit(MessageType.Error, message)
1127

    
1128
    def on_help(self):
1129
        """ open help file """
1130
        import os
1131

    
1132
        try:
1133
            help_file_path = os.path.join(os.path.dirname(os.path.realpath(__file__)), 'ID2 User Manual.pdf')
1134
            if os.path.exists(help_file_path):
1135
                os.startfile(f"\"{help_file_path}\"")
1136
            else:
1137
                QMessageBox.warning(self, self.tr('Warning'), self.tr('There is no help file'))
1138
        except Exception as ex:
1139
            message = f"error occurred({repr(ex)}) in {sys.exc_info()[-1].tb_frame.f_code.co_filename}:" \
1140
                      f"{sys.exc_info()[-1].tb_lineno}"
1141
            self.addMessage.emit(MessageType.Error, message)
1142

    
1143
    def on_readme(self):
1144
        """open readme.html"""
1145

    
1146
        file_path = os.path.join(os.path.dirname(os.path.realpath(__file__)), 'readme.html')
1147
        if os.path.exists(file_path):
1148
            os.startfile(f"\"{file_path}\"")
1149
        else:
1150
            QMessageBox.warning(self, self.tr('Warning'), self.tr('There is no readme file'))
1151

    
1152
    def onSelectionChanged(self):
1153
        """selection changed"""
1154
        items = [item for item in self.graphicsView.scene().selectedItems() if issubclass(type(item), SymbolSvgItem) or
1155
                 type(item) is QEngineeringLineItem or issubclass(type(item), QEngineeringTextItem) or
1156
                 type(item) is QEngineeringUnknownItem or type(item) is QEngineeringVendorItem]
1157
        if items:
1158
            lineNos = [item for item in items if type(item) is QEngineeringLineNoTextItem]
1159
            item = items[-1] if not lineNos else lineNos[0]
1160
            self.itemTreeWidget.findItem(item)
1161
            self.resultPropertyTableWidget.show_item_property(item)
1162
            if type(item) is QEngineeringErrorItem:
1163
                for index in range(self.tableWidgetInconsistency.rowCount()):
1164
                    if self.tableWidgetInconsistency.item(index, 1).tag is item:
1165
                        self.tableWidgetInconsistency.selectRow(index)
1166
                        break
1167
            if issubclass(type(item), SymbolSvgItem):
1168
                pass
1169
                #self.symbolTreeWidget.select_symbol(item)
1170
        else:
1171
            self.resultPropertyTableWidget.show_item_property(None)
1172

    
1173
    '''
1174
        @brief      Initialize scene and itemTreeWidget
1175
        @author     Jeongwoo
1176
        @date       2018.06.14
1177
        @history    humkyung 2018.08.16 ask to delete recognized items before remove
1178
    '''
1179

    
1180
    def on_initialize_scene(self, action):
1181
        if not self.graphicsView.hasImage():
1182
            self.showImageSelectionMessageBox()
1183

    
1184
            return
1185

    
1186
        try:
1187
            msg = QMessageBox()
1188
            msg.setIcon(QMessageBox.Critical)
1189
            msg.setText(self.tr('Do you want to remove all items?\nThis work cannot be recovered.'))
1190
            msg.setWindowTitle(self.tr("Initialize"))
1191
            msg.setStandardButtons(QMessageBox.Ok | QMessageBox.Cancel)
1192
            if QMessageBox.Ok == msg.exec_():
1193
                app_doc_data = AppDocData.instance()
1194
                app_doc_data.clearItemList(True)
1195

    
1196
                scene = self.graphicsView.scene()
1197
                pixmap = self.graphicsView.getPixmapHandle()
1198
                scene.removeItem(pixmap)    # disconnect pixmap from scene
1199
                scene.clear()               # remove all items from scene and then delete them
1200
                scene.addItem(pixmap)       # add pixmap
1201

    
1202
                if self.path is not None:
1203
                    baseName = os.path.basename(self.path)
1204
                    self.itemTreeWidget.setCurrentPID(baseName)
1205

    
1206
        except Exception as ex:
1207
            message = 'error occurred({}) in {}:{}'.format(ex, sys.exc_info()[-1].tb_frame.f_code.co_filename,
1208
                                                           sys.exc_info()[-1].tb_lineno)
1209
            self.addMessage.emit(MessageType.Error, message)
1210

    
1211
    def checked_action(self):
1212
        """return checked action"""
1213
        home_file_pane = self.ribbon.get_pane('Home File')
1214
        home_pane = self.ribbon.get_pane('Home')
1215
        visualization_pane = self.ribbon.get_pane('Home Visualization')
1216
        actions = [home_pane.ui.toolButtonRecognition, home_pane.ui.toolButtonLinkAttribute,
1217
                   home_pane.ui.toolButtonLine, home_pane.ui.toolButtonOCR, visualization_pane.ui.toolButtonZoom,
1218
                   visualization_pane.ui.toolButtonFitWindow, home_pane.ui.toolButtonVendor]
1219

    
1220
        checked = [ui_ for ui_ in actions if ui_.isChecked()]
1221
        return checked[0] if checked else None
1222

    
1223
    def update_action_group(self, ui):
1224
        """Manage Checkable Action statement"""
1225
        home_file_pane = self.ribbon.get_pane('Home File')
1226
        home_pane = self.ribbon.get_pane('Home')
1227
        visualization_pane = self.ribbon.get_pane('Home Visualization')
1228
        actions = [home_pane.ui.toolButtonRecognition, home_pane.ui.toolButtonLinkAttribute, home_pane.ui.toolButtonLine,
1229
                   home_pane.ui.toolButtonOCR, visualization_pane.ui.toolButtonZoom,
1230
                   visualization_pane.ui.toolButtonFitWindow, home_file_pane.ui.toolButtonFileSave,
1231
                   home_pane.ui.toolButtonValidate, home_pane.ui.toolButtonVendor]
1232

    
1233
        if hasattr(ui, 'tag'):
1234
            ui.tag.onRejected.emit(None)
1235

    
1236
        if self.graphicsView.command is not None:
1237
            self.graphicsView.useDefaultCommand()
1238

    
1239
        for ui_ in actions:
1240
            ui_.setChecked(False)
1241

    
1242
        ui.setChecked(True)
1243

    
1244
    '''
1245
        @brief      Create Equipment
1246
        @author     Jeongwoo
1247
        @date       18.05.03
1248
        @history    2018.05.04  Jeongwoo    Add Parameter on CreateSymbolCommand
1249
    '''
1250

    
1251
    def createEquipment(self):
1252
        if not self.graphicsView.hasImage():
1253
            self.actionEquipment.setChecked(False)
1254
            self.showImageSelectionMessageBox()
1255
            return
1256
        if self.actionEquipment.isChecked():
1257
            self.graphicsView.command = CreateSymbolCommand.CreateSymbolCommand(self.graphicsView, self.itemTreeWidget,
1258
                                                                                self.symbolTreeWidget)
1259
        else:
1260
            self.graphicsView.useDefaultCommand()
1261

    
1262
    '''
1263
        @brief      Create Nozzle
1264
        @author     Jeongwoo
1265
        @date       2018.05.03
1266
        @history    2018.05.04  Jeongwoo    Add Parameter on CreateSymbolCommand
1267
    '''
1268

    
1269
    def createNozzle(self):
1270
        if not self.graphicsView.hasImage():
1271
            self.actionNozzle.setChecked(False)
1272
            self.showImageSelectionMessageBox()
1273
            return
1274
        if self.actionNozzle.isChecked():
1275
            self.graphicsView.command = CreateSymbolCommand.CreateSymbolCommand(self.graphicsView, self.itemTreeWidget,
1276
                                                                                self.symbolTreeWidget)
1277
        else:
1278
            self.graphicsView.useDefaultCommand()
1279

    
1280
    def onAreaOcr(self):
1281
        """Area OCR"""
1282
        if not self.graphicsView.hasImage():
1283
            self.actionOCR.setChecked(False)
1284
            self.showImageSelectionMessageBox()
1285
            return
1286

    
1287
        pane = self.ribbon.get_pane('Home')
1288
        ui = pane.ui.toolButtonOCR
1289
        self.update_action_group(ui=ui)
1290
        checked = ui.isChecked()
1291
        if checked:
1292
            cmd = AreaOcrCommand.AreaOcrCommand(self.graphicsView)
1293
            cmd.onSuccess.connect(self.onRecognizeText)
1294
            cmd.onRejected.connect(self.onCommandRejected)
1295
            self.graphicsView.command = cmd
1296
        else:
1297
            self.graphicsView.useDefaultCommand()
1298

    
1299
    def onRecognizeText(self, x, y, width, height, show=True):
1300
        """show text recognition dialog"""
1301
        from OcrResultDialog import QOcrResultDialog
1302
        from Area import Area
1303

    
1304
        try:
1305
            app_doc_data = AppDocData.instance()
1306

    
1307
            modifiers = QApplication.keyboardModifiers()
1308
            image = self.graphicsView.image().copy(x, y, width, height)
1309
            dialog = QOcrResultDialog(self, image, QRectF(x, y, width, height),
1310
                                      format=QOcrResultDialog.Format.Table if modifiers == Qt.AltModifier else QOcrResultDialog.Format.Normal)
1311
            if modifiers == Qt.ControlModifier:
1312
                return
1313
            
1314
            if show:
1315
                (res, textInfoList) = dialog.showDialog()
1316
            else:
1317
                dialog.accept(show=False)
1318
                (res, textInfoList) = QDialog.Accepted, dialog.textInfoList
1319

    
1320
            if QDialog.Accepted == res and textInfoList:
1321
                for textInfo in textInfoList:
1322
                    item = QEngineeringTextItem.create_text_with(self.graphicsView.scene(), textInfo)
1323
                    if item:
1324
                        item.setDefaultTextColor(Qt.blue)
1325
                        item.transfer.onRemoved.connect(self.itemRemoved)
1326

    
1327
                        area_list = app_doc_data.getAreaList()
1328
                        title_area_list = app_doc_data.getTitleBlockProperties()
1329
                        title_list = []
1330
                        if title_area_list:
1331
                            for title_area in title_area_list:
1332
                                area = Area(title_area[0])
1333
                                area.parse(title_area[2])
1334
                                title_list.append(area)
1335
                        for area in area_list + title_list:
1336
                            pt = [item.sceneBoundingRect().center().x(), item.sceneBoundingRect().center().y()]
1337
                            if area.contains(pt):
1338
                                item.area = area.name
1339
                                break
1340
                    else:
1341
                        self.addMessage.emit(MessageType.Normal, self.tr('Fail to create text.'))
1342

    
1343
                return True
1344
            elif QDialog.Accepted == res and not textInfoList and show:
1345
                QMessageBox.about(self.graphicsView, self.tr("Notice"), self.tr("Fail to recognize text"))
1346
        except Exception as ex:
1347
            message = 'error occurred({}) in {}:{}'.format(ex, sys.exc_info()[-1].tb_frame.f_code.co_filename,
1348
                                                           sys.exc_info()[-1].tb_lineno)
1349
            self.addMessage.emit(MessageType.Error, message)
1350
        
1351
        return False
1352

    
1353
    '''
1354
        @brief  area configuration
1355
    '''
1356

    
1357
    def areaConfiguration(self):
1358
        from ConfigurationAreaDialog import QConfigurationAreaDialog
1359
        if not self.graphicsView.hasImage():
1360
            self.showImageSelectionMessageBox()
1361
            return
1362
        self.onCommandRejected()
1363
        dlgConfigurationArea = QConfigurationAreaDialog(self)
1364
        dlgConfigurationArea.show()
1365
        dlgConfigurationArea.exec_()
1366

    
1367
    '''
1368
        @brief  configuration
1369
    '''
1370

    
1371
    def configuration(self):
1372
        from ConfigurationDialog import QConfigurationDialog
1373

    
1374
        dlgConfiguration = QConfigurationDialog(self)
1375
        if QDialog.Accepted == dlgConfiguration.exec_():
1376
            QEngineeringLineItem.LINE_TYPE_COLORS.clear()
1377
            QEngineeringInstrumentItem.INST_COLOR = None
1378

    
1379
    '''
1380
        @brief  show special item types dialog 
1381
        @author humkyung
1382
        @date   2019.08.10
1383
    '''
1384

    
1385
    def on_show_special_item_types(self):
1386
        from SpecialItemTypesDialog import QSpecialItemTypesDialog
1387

    
1388
        dlg = QSpecialItemTypesDialog(self)
1389
        dlg.exec_()
1390

    
1391
    def on_show_data_transfer(self):
1392
        """ show data transfer dialog """
1393
        from DataTransferDialog import QDataTransferDialog
1394

    
1395
        dlg = QDataTransferDialog(self)
1396
        dlg.exec_()
1397

    
1398
    def on_show_data_export(self):
1399
        """ show data export dialog """
1400
        from DataExportDialog import QDataExportDialog
1401

    
1402
        dlg = QDataExportDialog(self)
1403
        dlg.exec_()
1404

    
1405
    def on_show_eqp_datasheet_export(self):
1406
        """ show eqp datasheet export dialog """
1407
        from EqpDatasheetExportDialog import QEqpDatasheetExportDialog
1408

    
1409
        dlg = QEqpDatasheetExportDialog(self)
1410
        dlg.exec_()
1411

    
1412
    def on_show_opc_relation(self):
1413
        """ show opc relation dialog """
1414
        from OPCRelationDialog import QOPCRelationDialog
1415

    
1416
        dlg = QOPCRelationDialog(self)
1417
        dlg.exec_()
1418

    
1419
    '''
1420
        @brief  show nominal diameter dialog 
1421
        @author humkyung
1422
        @date   2018.06.28
1423
    '''
1424

    
1425
    def onShowCodeTable(self):
1426
        from CodeTableDialog import QCodeTableDialog
1427

    
1428
        dlg = QCodeTableDialog(self)
1429
        dlg.show()
1430
        dlg.exec_()
1431
        if dlg.code_area:
1432
            if dlg.code_area.scene():
1433
                self.graphicsView.scene().removeItem(dlg.code_area)
1434
        if dlg.desc_area:
1435
            if dlg.desc_area.scene():
1436
                self.graphicsView.scene().removeItem(dlg.desc_area)
1437
        self.graphicsView.useDefaultCommand()
1438

    
1439
    def onShowCustomCodeTable(self):
1440
        from CustomCodeTablesDialog import CustomCodeTablesDialog
1441

    
1442
        dlg = CustomCodeTablesDialog(self)
1443
        dlg.show()
1444
        dlg.exec_()
1445
        self.graphicsView.useDefaultCommand()
1446

    
1447
    def onShowReplaceCodeTable(self):
1448
        from CustomCodeTablesDialog import CustomCodeTablesDialog
1449

    
1450
        dlg = CustomCodeTablesDialog(self, replace=True)
1451
        dlg.show()
1452
        dlg.exec_()
1453
        self.graphicsView.useDefaultCommand()
1454

    
1455
    def on_streamline(self):
1456
        """pop up stream line dialog"""
1457
        from StreamlineDialog import QStreamlineDialog
1458

    
1459
        if not self.graphicsView.hasImage():
1460
            self.showImageSelectionMessageBox()
1461
            return
1462

    
1463
        hmbs = AppDocData.instance().get_hmb_data(None)
1464
        if not hmbs:
1465
            return
1466

    
1467
        dlg = QStreamlineDialog(self)
1468
        dlg.show()
1469

    
1470
    def onHMBData(self):
1471
        """show HMB data"""
1472
        from HMBDialog import QHMBDialog
1473

    
1474
        dlg = QHMBDialog(self)
1475
        dlg.show()
1476
        dlg.exec_()
1477

    
1478
    '''
1479
        @brief  show line data list 
1480
        @author humkyung
1481
        @date   2018.05.03
1482
    '''
1483

    
1484
    def showItemDataList(self):
1485
        from ItemDataExportDialog import QItemDataExportDialog
1486

    
1487
        dlg = QItemDataExportDialog(self)
1488
        dlg.exec_()
1489

    
1490
    def showTextDataList(self):
1491
        '''
1492
            @brief      show all text item in scene
1493
            @author     euisung
1494
            @date       2019.04.18
1495
        '''
1496
        try:
1497
            if not self.graphicsView.hasImage():
1498
                self.showImageSelectionMessageBox()
1499
                return
1500

    
1501
            self.onCommandRejected()
1502
            dialog = QTextDataListDialog(self)
1503
            dialog.show()
1504
        except Exception as ex:
1505
            message = 'error occurred({}) in {}:{}'.format(ex, sys.exc_info()[-1].tb_frame.f_code.co_filename,
1506
                                                           sys.exc_info()[-1].tb_lineno)
1507
            self.addMessage.emit(MessageType.Error, message)
1508

    
1509
    '''
1510
        @brief  Show Image Selection Guide MessageBox
1511
        @author Jeongwoo
1512
        @date   2018.05.02
1513
    '''
1514

    
1515
    def showImageSelectionMessageBox(self):
1516
        QMessageBox.about(self.graphicsView, self.tr("Notice"), self.tr("First select image drawing"))
1517

    
1518
    def on_search_text_changed(self):
1519
        """filter symbol tree view"""
1520
        regexp = QRegExp(self.lineEditFilter.text(), Qt.CaseInsensitive, QRegExp.FixedString)
1521

    
1522
        proxy_model = self.symbolTreeWidget.model()
1523
        proxy_model.text = self.lineEditFilter.text().lower()
1524
        proxy_model.setFilterRegExp(regexp)
1525

    
1526
        self.symbolTreeWidget.expandAll()
1527

    
1528
    def display_colors(self, value):
1529
        """ display colors """
1530
        from DisplayColors import DisplayColors
1531
        from DisplayColors import DisplayOptions
1532

    
1533
        if hasattr(self, 'ribbon'):
1534
            visualization_pane = self.ribbon.get_pane('Home Visualization')
1535
            if self.sender() is visualization_pane.ui.radioButtonByGroup and value is True:
1536
                DisplayColors.instance().option = DisplayOptions.DisplayByLineNo
1537
            elif self.sender() is visualization_pane.ui.radioButtonByType and value is True:
1538
                DisplayColors.instance().option = DisplayOptions.DisplayByLineType
1539
            elif self.sender() is visualization_pane.ui.radioButtonByStreamNo and value is True:
1540
                DisplayColors.instance().option = DisplayOptions.DisplayByStreamNo
1541

    
1542
            if hasattr(self, 'graphicsView') and value is True:
1543
                self.graphicsView.scene().update(self.graphicsView.sceneRect())
1544
                for item in self.graphicsView.scene().items():
1545
                    if issubclass(type(item), SymbolSvgItem):
1546
                        item.update()
1547
                DisplayColors.instance().save_data()
1548

    
1549
    def open_image_drawing(self, drawing, force=False, ocrUnknown=False):
1550
        """open and display image drawing file"""
1551
        from Drawing import Drawing
1552
        from App import App
1553
        from LoadCommand import LoadCommand
1554
        import concurrent.futures as futures
1555

    
1556
        # Yield successive n-sized
1557
        # chunks from l.
1558
        def divide_chunks(l, n):
1559
            # looping till length l
1560
            for i in range(0, len(l), n):
1561
                yield l[i:i + n]
1562

    
1563
        def update_items(items):
1564
            for item in items:
1565
                # binding items
1566
                item.owner
1567
                for connector in item.connectors:
1568
                    connector.connectedItem
1569

    
1570
            return items
1571

    
1572
        try:
1573
            app_doc_data = AppDocData.instance()
1574

    
1575
            if not self.actionSave.isEnabled():
1576
                return
1577

    
1578
            if not force and self.save_drawing_if_necessary():
1579
                return
1580

    
1581
            occupied = app_doc_data.set_occupying_drawing(drawing.UID)
1582
            if occupied:
1583
                QMessageBox.about(self.graphicsView, self.tr("Notice"),
1584
                                  self.tr(f"The drawing is locked for editing by another user({occupied})"))
1585
                return
1586

    
1587
            # save alarm
1588
            self.save_alarm_enable(False)
1589

    
1590
            if hasattr(self, '_save_work_cmd'):
1591
                self._save_work_cmd.wait()
1592

    
1593
            project = app_doc_data.getCurrentProject()
1594

    
1595
            self.path = self.graphicsView.loadImageFromFile(drawing)
1596
            if os.path.isfile(self.path):
1597
                self.onCommandRejected()
1598
                app_doc_data.clear(past=drawing.UID)
1599

    
1600
                # load color for stream no coloring
1601
                configs = app_doc_data.getConfigs('Line List', 'Use Stream No')
1602
                if configs and int(configs[0].value) == 1:
1603
                    hmbs = app_doc_data.get_hmb_data(None)
1604
                    colors = {}
1605
                    if hmbs:
1606
                        for hmb in hmbs:
1607
                            rgb = app_doc_data.colors
1608
                            colors[hmb.stream_no] = QColor(rgb.red, rgb.green, rgb.blue).name()
1609
                        app_doc_data._hmbColors = colors
1610
                # up to here
1611

    
1612
                app_doc_data.setImgFilePath(self.path)
1613
                app_doc_data.activeDrawing = drawing
1614
                
1615
                #app_doc_data.activeDrawing.set_pid_source(Image.open(self.path))
1616
                self.itemTreeWidget.setCurrentPID(app_doc_data.activeDrawing.name)
1617

    
1618
                drawingList = self.treeWidgetDrawingList.topLevelItem(0)
1619
                for idx in range(drawingList.childCount()):
1620
                    child = drawingList.child(idx)
1621
                    if child.data(Qt.UserRole, 0) is drawing:
1622
                        child.setCheckState(0, Qt.Checked)
1623
                    else:
1624
                        child.setCheckState(0, Qt.Unchecked)
1625

    
1626
                try:
1627
                    self.show_Progress_bar()
1628

    
1629
                    # disconnect scene changed if signal is connected
1630
                    if self.graphicsView.scene().receivers(self.graphicsView.scene().contents_changed) > 0:
1631
                        self.graphicsView.scene().contents_changed.disconnect()
1632

    
1633
                    SymbolSvgItem.DOCUMENTS.clear()
1634

    
1635
                    # load data
1636
                    cmd = LoadCommand()
1637
                    cmd.display_message.connect(self.onAddMessage)
1638
                    cmd.set_maximum.connect(self.progress.setMaximum)
1639
                    cmd.show_progress.connect(self.progress.setValue)
1640
                    cmd.execute((drawing, self.graphicsView.scene()),
1641
                                symbol=True, text=True, line=True, unknown=True, package=True, update=True)
1642

    
1643
                    app_doc_data._streamLineListModelDatas = app_doc_data.get_stream_line_list_data()
1644
                    # up to here
1645

    
1646
                    """"update item tree widget"""
1647
                    line_no_items = [item for item in self.graphicsView.scene().items()
1648
                                     if type(item) is QEngineeringLineNoTextItem]
1649
                    for line_no in line_no_items:
1650
                        line_no_tree_item = self.itemTreeWidget.addTreeItem(self.itemTreeWidget.root, line_no)
1651
                        for run in line_no.runs:
1652
                            for run_item in run.items:
1653
                                if issubclass(type(run_item), SymbolSvgItem):
1654
                                    self.init_add_tree_item(line_no_tree_item, run_item)
1655

    
1656
                    line_no_items = [item for item in self.graphicsView.scene().items()
1657
                                     if type(item) is QEngineeringTrimLineNoTextItem]
1658
                    for line_no in line_no_items:
1659
                        line_no_tree_item = self.itemTreeWidget.addTreeItem(self.itemTreeWidget.root, line_no)
1660
                        for run in line_no.runs:
1661
                            for run_item in run.items:
1662
                                if issubclass(type(run_item), SymbolSvgItem):
1663
                                    self.init_add_tree_item(line_no_tree_item, run_item)
1664

    
1665
                    for trim_line_no in app_doc_data.tracerLineNos:
1666
                        line_no_tree_item = self.itemTreeWidget.addTreeItem(self.itemTreeWidget.root, trim_line_no)
1667
                        for run in trim_line_no.runs:
1668
                            for run_item in run.items:
1669
                                if issubclass(type(run_item), SymbolSvgItem):
1670
                                    self.init_add_tree_item(line_no_tree_item, run_item)
1671

    
1672
                    self.itemTreeWidget.update_item_count()
1673
                    self.itemTreeWidget.expandAll()
1674
                    """up to here"""
1675

    
1676
                    """update scene"""
1677
                    for item in self._scene.items():
1678
                        item.setVisible(True)
1679

    
1680
                    self._scene.update(self._scene.sceneRect())
1681

    
1682
                    """
1683
                    # old open drawing
1684
                    path = os.path.join(app_doc_data.getCurrentProject().getTempPath(), app_doc_data.imgName + '.xml')
1685
                    configs = app_doc_data.getConfigs('Data Load', 'Xml First')
1686
                    if configs and int(configs[0].value) >= 1 and os.path.isfile(path):
1687
                        self.load_recognition_result_from_xml(drawing)
1688
                    elif configs and int(configs[0].value) <= 1:
1689
                        self.load_drawing(app_doc_data.activeDrawing)
1690
                    """
1691

    
1692
                    self.display_number_of_items()
1693
                    # connect scene changed signal
1694
                    self.graphicsView.scene().contents_changed.connect(self.scene_changed)
1695
                finally:
1696
                    if hasattr(self, 'progress'):
1697
                        self.progress.setValue(self.progress.maximum())
1698

    
1699
                self.changeViewCheckedState(True)
1700
                self.setWindowTitle(self.title)
1701
                self.fitWindow(drawing.view_rect)
1702

    
1703
                if ocrUnknown:
1704
                    self.on_ocr_unknown_items()
1705

    
1706
                # save alarm
1707
                self.save_alarm_enable(True, True)
1708
        except Exception as ex:
1709
            message = f"error occurred({repr(ex)}) in {sys.exc_info()[-1].tb_frame.f_code.co_filename}:" \
1710
                      f"{sys.exc_info()[-1].tb_lineno}"
1711
            self.addMessage.emit(MessageType.Error, message)
1712

    
1713
        return self.path
1714

    
1715
    def save_alarm_enable(self, enable, init=False):
1716
        from datetime import datetime
1717

    
1718
        try:
1719
            app_doc_data = AppDocData.instance()
1720
            configs = app_doc_data.getConfigs('Data Save', 'Time')
1721
            time_min = int(configs[0].value) if 1 == len(configs) else 0
1722

    
1723
            if enable and time_min > 0:
1724
                if not self.save_timer:
1725
                    self.save_timer = QTimer()
1726
                    self.save_timer.timeout.connect(self.save_alarm)
1727
                    self.save_timer.setInterval(60000)
1728

    
1729
                if init:
1730
                    self.save_timer._init_time = datetime.now()
1731
                    self.save_timer._stop_time = None
1732
                    self.save_timer._interval_time = datetime.now() - datetime.now()
1733

    
1734
                if self.save_timer._stop_time:
1735
                    self.save_timer._interval_time = datetime.now() - self.save_timer._stop_time
1736
                
1737
                #if 60000 * time_min != self.save_timer.interval():
1738
                #    self.save_timer.setInterval(60000)
1739

    
1740
                self.save_timer.start()
1741
            else:
1742
                if self.save_timer:
1743
                    self.save_timer.stop()
1744
                    self.save_timer._stop_time = datetime.now()
1745
        
1746
        except Exception as ex:
1747
            message = f"error occurred({repr(ex)}) in {sys.exc_info()[-1].tb_frame.f_code.co_filename}:" \
1748
                      f"{sys.exc_info()[-1].tb_lineno}"
1749
            self.addMessage.emit(MessageType.Error, message)
1750

    
1751
    def save_alarm(self):
1752
        from datetime import datetime
1753

    
1754
        app_doc_data = AppDocData.instance()
1755
        configs = app_doc_data.getConfigs('Data Save', 'Time')
1756
        time_min = int(configs[0].value) if 1 == len(configs) else 0
1757

    
1758
        self.save_timer.stop()
1759
        if self.graphicsView.hasFocus() and (datetime.now() - self.save_timer._init_time - self.save_timer._interval_time).seconds > time_min * 60:
1760
            QMessageBox.information(self, self.tr('Information'), self.tr('Please save Drawing'))
1761
            self.save_timer._init_time = datetime.now()
1762
            self.save_timer._interval_time = datetime.now() - datetime.now()
1763
        self.save_timer.start()
1764

    
1765
    def export_as_svg(self):
1766
        """export scene to svg file"""
1767
        from ExportCommand import ExportCommand
1768

    
1769
        options = QFileDialog.Options()
1770
        options |= QFileDialog.DontUseNativeDialog
1771
        file_path, _ = QFileDialog.getSaveFileName(self, "Export as svg", os.getcwd(), "svg file(*.svg)",
1772
                                                   options=options)
1773
        if file_path:
1774
            cmd = ExportCommand(self.graphicsView.scene(), 'svg')
1775
            cmd.display_message.connect(self.onAddMessage)
1776
            if cmd.execute(file_path):
1777
                QMessageBox.information(self, self.tr('Information'), self.tr('Successfully export to svg file'))
1778
            else:
1779
                QMessageBox.information(self, self.tr('Error'), self.tr('Fail to export to svg file'))
1780

    
1781
    def export_as_xml(self):
1782
        pass
1783

    
1784
    def export_as_image(self):
1785
        """export scene to image file"""
1786
        from ExportCommand import ExportCommand
1787

    
1788
        options = QFileDialog.Options()
1789
        options |= QFileDialog.DontUseNativeDialog
1790
        file_path, _ = QFileDialog.getSaveFileName(self, "Export as png", os.getcwd(), "png file(*.png)",
1791
                                                   options=options)
1792
        if file_path:
1793
            try:
1794
                # hide image drawing
1795
                self.onViewImageDrawing(False)
1796

    
1797
                cmd = ExportCommand(self.graphicsView.scene(), 'image')
1798
                cmd.display_message.connect(self.onAddMessage)
1799

    
1800
                if cmd.execute(file_path):
1801
                    QMessageBox.information(self, self.tr('Information'), self.tr('Successfully export to image file'))
1802
                else:
1803
                    QMessageBox.information(self, self.tr('Error'), self.tr('Fail to export to image file'))
1804
            finally:
1805
                if self.actionImage_Drawing.isChecked():
1806
                    self.onViewImageDrawing(True)
1807
                    self.actionImage_Drawing.setChecked(True)
1808

    
1809
    def show_Progress_bar(self):
1810
        """ show progress bar """
1811
        self.progress = QProgressDialog(self.tr("Please wait for a while"), self.tr("Cancel"), 0, 100,
1812
                                        self) if not hasattr(self, 'progress') else self.progress
1813
        self.progress.setWindowModality(Qt.WindowModal)
1814
        self.progress.setAutoReset(True)
1815
        self.progress.setAutoClose(True)
1816
        self.progress.setMinimum(0)
1817
        self.progress.setMaximum(100)
1818
        self.progress.resize(600, 100)
1819
        self.progress.setWindowTitle(self.tr("Reading file..."))
1820
        self.progress.show()
1821

    
1822
    def changeViewCheckedState(self, checked, clear=True):
1823
        """change view checked state"""
1824
        # self.actionImage_Drawing.setChecked(checked)
1825
        self.actionViewText.setChecked(checked)
1826
        self.actionViewSymbol.setChecked(checked)
1827
        self.actionViewLine.setChecked(checked)
1828
        self.actionViewUnknown.setChecked(checked)
1829
        self.actionViewInconsistency.setChecked(checked)
1830
        self.actionViewVendor_Area.setChecked(not checked)
1831
        self.actionDrawing_Only.setChecked(not checked)
1832
        if clear:
1833
            self.tableWidgetInconsistency.clearContents()
1834
            self.tableWidgetInconsistency.setRowCount(0)
1835

    
1836
    def onViewDrawingOnly(self, isChecked):
1837
        '''
1838
            @brief  visible/invisible except image drawing
1839
            @author euisung
1840
            @date   2019.04.22
1841
        '''
1842
        self.changeViewCheckedState(not isChecked, False)
1843
        for item in self.graphicsView.scene().items():
1844
            if type(item) is not QGraphicsPixmapItem:
1845
                item.setVisible(not isChecked)
1846

    
1847
    '''
1848
        @brief  visible/invisible image drawing
1849
        @author humkyung
1850
        @date   2018.06.25
1851
    '''
1852

    
1853
    def onViewImageDrawing(self, isChecked):
1854
        for item in self.graphicsView.scene().items():
1855
            if type(item) is QGraphicsPixmapItem:
1856
                item.setVisible(isChecked)
1857
                break
1858

    
1859
    def onViewText(self, checked):
1860
        """visible/invisible text"""
1861
        selected = [item for item in self.graphicsView.scene().items() if issubclass(type(item), QEngineeringTextItem)
1862
                    and type(item) is not QEngineeringLineNoTextItem]
1863
        for item in selected:
1864
            item.setVisible(checked)
1865

    
1866
    def onViewSymbol(self, checked):
1867
        """visible/invisible symbol"""
1868
        selected = [item for item in self.graphicsView.scene().items() if
1869
                    (issubclass(type(item), SymbolSvgItem) and type(item) is not QEngineeringErrorItem)]
1870
        for item in selected:
1871
            item.setVisible(checked)
1872

    
1873
    def onViewLine(self, checked):
1874
        """visible/invisible line"""
1875
        selected = [item for item in self.graphicsView.scene().items() if type(item) is QEngineeringLineItem]
1876
        for item in selected:
1877
            item.setVisible(checked)
1878

    
1879
    def onViewInconsistency(self, isChecked):
1880
        '''
1881
            @brief  visible/invisible Inconsistency
1882
            @author euisung
1883
            @date   2019.04.03
1884
        '''
1885
        selected = [item for item in self.graphicsView.scene().items() if type(item) is QEngineeringErrorItem]
1886
        for item in selected:
1887
            item.setVisible(isChecked)
1888

    
1889
    '''
1890
        @brief  visible/invisible Unknown 
1891
        @author humkyung
1892
        @date   2018.06.28
1893
    '''
1894

    
1895
    def onViewUnknown(self, isChecked):
1896
        selected = [item for item in self.graphicsView.scene().items() if type(item) is QEngineeringUnknownItem]
1897
        for item in selected:
1898
            item.setVisible(isChecked)
1899

    
1900
    def onViewVendorArea(self, isChecked):
1901
        '''
1902
            @brief  visible/invisible Vendor Area
1903
            @author euisung
1904
            @date   2019.04.29
1905
        '''
1906
        selected = [item for item in self.graphicsView.scene().items() if issubclass(type(item), QEngineeringVendorItem)]
1907
        for item in selected:
1908
            item.setVisible(isChecked)
1909

    
1910
    '''
1911
        @brief  create a symbol
1912
        @history    2018.05.02  Jeongwoo    Change return value of QSymbolEditorDialog (Single variable → Tuple)
1913
                                            Add SymbolSvgItem
1914
                    2018.05.03  Jeongwoo    Change method to draw Svg Item on Scene (svg.addSvgItemToScene)
1915
                                            Change method to make svg and image path
1916
                    2018.06.08  Jeongwoo    Add Paramter on SymbolSvgItem.buildItem()
1917
    '''
1918
    def onCreateSymbolClicked(self):
1919
        selected = [item for item in self.graphicsView.scene().selectedItems() if issubclass(type(item), QEngineeringVendorItem)]
1920
        if len(selected) == 1:
1921
            symbol_image = AppDocData.instance().activeDrawing.image_origin
1922
            rect = selected[0].sceneBoundingRect()
1923

    
1924
            points = []
1925
            for conn in selected[0].connectors:
1926
                points.append([round(conn.center()[0] - rect.x()), round(conn.center()[1] - rect.y())])
1927
            poly = np.array(points, np.int32)
1928

    
1929
            #mask = np.zeros((int(rect.height()), int(rect.width())))
1930
            #cv2.fillPoly(mask, [poly], (255))
1931
            #poly_copied = np.multiply(mask, symbol_image[round(rect.y()):round(rect.y() + rect.height()),
1932
            #                   round(rect.x()):round(rect.x() + rect.width())])
1933
            #cv2.fillPoly(mask,[poly],0)
1934
            #src2 = np.multiply(mask,src2)
1935

    
1936
            mask = np.ones((int(rect.height()), int(rect.width())), dtype=np.uint8) * 255
1937
            cv2.fillPoly(mask, [poly], (0))
1938
            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())])
1939
            sym_img = cv2.merge((sym_img, sym_img, sym_img))
1940

    
1941
            h, w, c = sym_img.shape
1942
            qImg = QImage(sym_img.data, w, h, w * c, QImage.Format_RGB888)
1943
            #pixmap = QPixmap.fromImage(qImg)
1944

    
1945
            self.onAreaSelected(None, None, None, None, package=qImg, position=rect.topLeft(), package_item=selected[0])
1946
        else:
1947
            cmd = FenceCommand.FenceCommand(self.graphicsView)
1948
            cmd.onSuccess.connect(self.onAreaSelected)
1949
            self.graphicsView.command = cmd
1950
            QApplication.setOverrideCursor(Qt.CrossCursor)
1951

    
1952
    '''
1953
        @brief      show SymbolEditorDialog with image selected by user
1954
        @author     humkyung
1955
        @date       2018.07.20
1956
    '''
1957

    
1958
    def onAreaSelected(self, x, y, width, height, package=False, position=None, package_item=None):
1959
        try:
1960
            image = self.graphicsView.image()
1961
            if image is not None:
1962
                if not package:
1963
                    symbolEditorDialog = SymbolEditorDialog.QSymbolEditorDialog(self, image.copy(x, y, width, height),
1964
                                                                                AppDocData.instance().getCurrentProject())
1965
                else:
1966
                    symbolEditorDialog = SymbolEditorDialog.QSymbolEditorDialog(self, package,
1967
                                                                                AppDocData.instance().getCurrentProject(), package=True)
1968
                (isAccepted, isImmediateInsert, offsetX, offsetY, newSym) = symbolEditorDialog.showDialog()
1969
                # TODO: not initialize symbol tree view when user reject to create a new symbol
1970
                self.symbolTreeWidget.initSymbolTreeView()
1971
                if isAccepted:
1972
                    if isImmediateInsert:
1973
                        svg = QtImageViewer.createSymbolObject(newSym.getName())
1974
                        offsetX, offsetY = [int(point) for point in newSym.getOriginalPoint().split(',')]
1975
                        QtImageViewer.matchSymbolToLine(self.graphicsView.scene(), svg, QPoint(position.x() + offsetX, position.y() + offsetY))
1976

    
1977
                        package_item.transfer.onRemoved.emit(package_item)
1978
        finally:
1979
            self.onCommandRejected()
1980
            QApplication.restoreOverrideCursor()
1981
            QApplication.restoreOverrideCursor()
1982

    
1983
    def on_line_list(self):
1984
        """ line list export dialog """
1985
        from LineListDialog import LineListDialog
1986

    
1987
        if not self.graphicsView.hasImage():
1988
            self.showImageSelectionMessageBox()
1989
            return
1990

    
1991
        dialog = LineListDialog(self)
1992
        dialog.showDialog()
1993

    
1994
    def on_make_label_data(self):
1995
        """ make label data from symbol info """
1996
        from xml.etree.ElementTree import Element, SubElement, dump, ElementTree, parse
1997

    
1998
        if not self.graphicsView.hasImage():
1999
            self.showImageSelectionMessageBox()
2000
            return
2001

    
2002
        app_doc_data = AppDocData.instance()
2003
        project = app_doc_data.getCurrentProject()
2004

    
2005
        smalls = []
2006
        bigs = []
2007

    
2008
        symbol_list = app_doc_data.getTargetSymbolList(all=True)
2009
        #symbol_list = app_doc_data.getTargetSymbolList(all=False)
2010
        for symbol in symbol_list:
2011
            if symbol.iType == 38 or symbol.iType == 33 or symbol.iType == 0 or symbol.iType == 40:
2012
                continue
2013
            elif symbol.width and symbol.height:
2014
                if symbol.width > 300 or symbol.height > 300:
2015
                    bigs.append(symbol.getName())
2016
                elif (symbol.width * symbol.height < 1500) or (symbol.width > 450 or symbol.height > 450):
2017
                    continue
2018
                else:
2019
                    smalls.append(symbol.getName())
2020

    
2021
        symbols = [item for item in self.graphicsView.scene().items() if issubclass(type(item), SymbolSvgItem)]
2022
        names = [smalls, bigs]
2023

    
2024
        img = app_doc_data.activeDrawing.image_origin
2025

    
2026
        small_size = 500
2027
        big_size = 850
2028

    
2029
        save_path = project.getTrainingSymbolFilePath()
2030

    
2031
        index = 0
2032
        for size in [small_size, big_size]:
2033
            offsets = [0, int(size / 2)]
2034

    
2035
            width, height = img.shape[1], img.shape[0]
2036
            width_count, height_count = width // size + 2, height // size + 2
2037
            b_width, b_height = width_count * size, height_count * size
2038
            b_img = np.zeros((b_height, b_width), np.uint8) + 255
2039
            b_img[:height, :width] = img[:, :]
2040

    
2041
            for offset in offsets:
2042
                for row in range(height_count):
2043
                    for col in range(width_count):
2044
                        x, y = col * size + offset, row * size + offset
2045
                        tile_rect = QRectF(x, y, size, size)
2046
                        tile_symbols = []
2047
                        for symbol in [symbol for symbol in symbols if symbol.name in names[index]]:
2048
                            if tile_rect.contains(symbol.sceneBoundingRect()):
2049
                                tile_symbols.append(symbol)
2050
                                symbols.remove(symbol)
2051

    
2052
                        if tile_symbols:
2053
                            training_uid = str(uuid.uuid4())
2054
                            training_image_path = os.path.join(save_path, training_uid + '.png')
2055
                            training_xml_path = os.path.join(save_path, training_uid + '.xml')
2056

    
2057
                            # save image
2058
                            #_img = b_img[round(tile_rect.top()):round(tile_rect.bottom()),
2059
                            #       round(tile_rect.left()):round(tile_rect.right())]
2060
                            #cv2.imwrite(training_image_path, _img)
2061
                            _img = self.graphicsView.image().copy(round(tile_rect.left()), round(tile_rect.top()), round(tile_rect.width()), round(tile_rect.height()))
2062
                            _img.save(training_image_path)
2063

    
2064
                            # save label
2065
                            xml = Element('annotation')
2066
                            SubElement(xml, 'folder').text = 'None'
2067
                            SubElement(xml, 'filename').text = os.path.basename(save_path)
2068

    
2069
                            pathNode = Element('path')
2070
                            pathNode.text = save_path.replace('/', '\\')
2071
                            xml.append(pathNode)
2072

    
2073
                            sourceNode = Element('source')
2074
                            databaseNode = Element('database')
2075
                            databaseNode.text = 'Unknown'
2076
                            sourceNode.append(databaseNode)
2077
                            xml.append(sourceNode)
2078

    
2079
                            sizeNode = Element('size')
2080
                            widthNode = Element('width')
2081
                            widthNode.text = str(int(tile_rect.width()))
2082
                            sizeNode.append(widthNode)
2083
                            heightNode = Element('height')
2084
                            heightNode.text = str(int(tile_rect.height()))
2085
                            sizeNode.append(heightNode)
2086
                            depthNode = Element('depth')
2087
                            depthNode.text = '3'
2088
                            sizeNode.append(depthNode)
2089
                            xml.append(sizeNode)
2090

    
2091
                            segmentedNode = Element('segmented')
2092
                            segmentedNode.text = '0'
2093
                            xml.append(segmentedNode)
2094

    
2095
                            labelContent = []
2096
                            counts = {}
2097
                            for item in tile_symbols:
2098
                                rect = item.sceneBoundingRect()
2099
                                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)
2100
                                #label = 'small' if index == 0 else 'big' # for single class test
2101
                                xMin = xMin if xMin > 0 else 0
2102
                                yMin = yMin if yMin > 0 else 0
2103
                                xMax = xMax if xMax < size else size
2104
                                yMax = yMax if yMax < size else size
2105

    
2106
                                if label == 'None' or label == '':
2107
                                    continue
2108
                                if label not in labelContent:
2109
                                    labelContent.append(label)
2110
                                    counts[label] = 1
2111
                                else:
2112
                                    counts[label] = counts[label] + 1
2113

    
2114
                                objectNode = Element('object')
2115
                                nameNode = Element('name')
2116
                                nameNode.text = label
2117
                                objectNode.append(nameNode)
2118
                                poseNode = Element('pose')
2119
                                poseNode.text = 'Unspecified'
2120
                                objectNode.append(poseNode)
2121
                                truncatedNode = Element('truncated')
2122
                                truncatedNode.text = '0'
2123
                                objectNode.append(truncatedNode)
2124
                                difficultNode = Element('difficult')
2125
                                difficultNode.text = '0'
2126
                                objectNode.append(difficultNode)
2127

    
2128
                                bndboxNode = Element('bndbox')
2129
                                xminNode = Element('xmin')
2130
                                xminNode.text = str(xMin)
2131
                                bndboxNode.append(xminNode)
2132
                                yminNode = Element('ymin')
2133
                                yminNode.text = str(yMin)
2134
                                bndboxNode.append(yminNode)
2135
                                xmaxNode = Element('xmax')
2136
                                xmaxNode.text = str(xMax)
2137
                                bndboxNode.append(xmaxNode)
2138
                                ymaxNode = Element('ymax')
2139
                                ymaxNode.text = str(yMax)
2140
                                bndboxNode.append(ymaxNode)
2141
                                objectNode.append(bndboxNode)
2142

    
2143
                                xml.append(objectNode)
2144

    
2145
                            ElementTree(xml).write(training_xml_path)
2146

    
2147
            index += 1
2148

    
2149
        QMessageBox.about(self, self.tr("Notice"), self.tr('Successfully applied. '))
2150

    
2151
    def onPlaceLine(self):
2152
        """create a line"""
2153
        home_pane = self.ribbon.get_pane('Home')
2154

    
2155
        if not self.graphicsView.hasImage():
2156
            home_pane.ui.toolButtonLine.setChecked(False)
2157
            self.showImageSelectionMessageBox()
2158
            return
2159

    
2160
        self.update_action_group(home_pane.ui.toolButtonLine)
2161
        if not hasattr(home_pane.ui.toolButtonLine, 'tag'):
2162
            home_pane.ui.toolButtonLine.tag = PlaceLineCommand.PlaceLineCommand(self.graphicsView)
2163
            home_pane.ui.toolButtonLine.tag.onSuccess.connect(self.onLineCreated)
2164
            home_pane.ui.toolButtonLine.tag.onRejected.connect(self.onCommandRejected)
2165

    
2166
        self.graphicsView.command = home_pane.ui.toolButtonLine.tag
2167

    
2168
    def onLineCreated(self):
2169
        """add created lines to scene"""
2170
        from EngineeringConnectorItem import QEngineeringConnectorItem
2171
        from LineDetector import LineDetector
2172

    
2173
        try:
2174
            app_doc_data = AppDocData.instance()
2175
            home_pane = self.ribbon.get_pane('Home')
2176

    
2177
            count = len(home_pane.ui.toolButtonLine.tag._polyline._vertices)
2178
            if count > 1:
2179
                items = []
2180

    
2181
                detector = LineDetector(None)
2182

    
2183
                if not home_pane.ui.toolButtonLine.tag.line_type:
2184
                    line_type = home_pane.ui.comboBoxLineType.currentText()
2185
                else:
2186
                    pane = self.ribbon.get_pane('Home')
2187
                    selected_line_type = pane.ui.comboBoxLineType.currentText()
2188
                    if selected_line_type == 'Connect To Process':
2189
                        line_type = selected_line_type
2190
                    elif not (QEngineeringLineItem.check_piping(home_pane.ui.toolButtonLine.tag.line_type) ^
2191
                              QEngineeringLineItem.check_piping(selected_line_type)):
2192
                        line_type = selected_line_type
2193
                    else:
2194
                        line_type = home_pane.ui.toolButtonLine.tag.line_type
2195
                for index in range(count - 1):
2196
                    start = home_pane.ui.toolButtonLine.tag._polyline._vertices[index]
2197
                    end = home_pane.ui.toolButtonLine.tag._polyline._vertices[index + 1]
2198

    
2199
                    lineItem = QEngineeringLineItem(vertices=[start, end])
2200
                    lineItem.transfer.onRemoved.connect(self.itemRemoved)
2201
                    lineItem.lineType = line_type
2202
                    if items:
2203
                        lineItem.connect_if_possible(items[-1], 5)
2204
                    else:
2205
                        pt = lineItem.start_point()
2206
                        selected = [item for item in self.graphicsView.scene().items(QPointF(pt[0], pt[1])) if
2207
                                    type(item) is QEngineeringConnectorItem or type(item) is QEngineeringLineItem]
2208
                        if selected and selected[0] is not lineItem:
2209
                            if type(selected[0]) is QEngineeringConnectorItem:
2210
                                lineItem.connect_if_possible(selected[0].parent, 5)
2211
                            else:
2212
                                detector.connectLineToLine(selected[0], lineItem, 5)
2213

    
2214
                    items.append(lineItem)
2215
                    self.graphicsView.scene().addItem(lineItem)
2216

    
2217
                pt = items[-1].end_point()
2218
                selected = [item for item in self.graphicsView.scene().items(QPointF(pt[0], pt[1])) if
2219
                            (type(item) is QEngineeringConnectorItem and item.parentItem() is not items[-1]) or
2220
                            (type(item) is QEngineeringLineItem and item is not items[-1])]
2221
                if selected and selected[0] is not items[-1]:
2222
                    if type(selected[0]) is QEngineeringConnectorItem:
2223
                        items[-1].connect_if_possible(selected[0].parent, 5)
2224
                    else:
2225
                        detector.connectLineToLine(selected[0], items[-1], 5)
2226

    
2227
                self._scene.undo_stack.push(CreateCommand(self._scene, items))
2228
        finally:
2229
            self.graphicsView.scene().removeItem(home_pane.ui.toolButtonLine.tag._polyline)
2230
            home_pane.ui.toolButtonLine.tag.reset()
2231

    
2232
    def onCommandRejected(self, cmd=None):
2233
        """command is rejected"""
2234
        try:
2235
            home_pane = self.ribbon.get_pane('Home')
2236
            visualization_pane = self.ribbon.get_pane('Home Visualization')
2237
            if type(cmd) is PlaceLineCommand.PlaceLineCommand:
2238
                if home_pane.ui.toolButtonLine.tag._polyline:
2239
                    self.graphicsView.scene().removeItem(home_pane.ui.toolButtonLine.tag._polyline)
2240
                self.graphicsView.scene().update()
2241
                home_pane.ui.toolButtonLine.tag.reset()
2242

    
2243
                home_pane.ui.toolButtonLine.setChecked(False)
2244
            elif type(cmd) is AreaZoomCommand.AreaZoomCommand:
2245
                visualization_pane.ui.toolButtonZoom.setChecked(False)
2246
            elif type(cmd) is AreaOcrCommand.AreaOcrCommand:
2247
                home_pane.ui.toolButtonOCR.setChecked(False)
2248
            elif type(cmd) is PlacePolygonCommand.PlacePolygonCommand:
2249
                home_pane.ui.toolButtonVendor.setChecked(False)
2250
            else:
2251
                if hasattr(home_pane.ui.toolButtonVendor, 'tag') and home_pane.ui.toolButtonVendor.tag._polyline:
2252
                    self.graphicsView.scene().removeItem(home_pane.ui.toolButtonVendor.tag._polyline)
2253
                    self.graphicsView.scene().update()
2254
                    home_pane.ui.toolButtonVendor.tag.reset()
2255
                home_pane.ui.toolButtonLine.setChecked(False)
2256
                visualization_pane.ui.toolButtonZoom.setChecked(False)
2257
                home_pane.ui.toolButtonOCR.setChecked(False)
2258
                home_pane.ui.toolButtonVendor.setChecked(False)
2259
        finally:
2260
            self.graphicsView.useDefaultCommand()
2261

    
2262
    def on_view_toggle(self, key: int) -> None:
2263
        """view toggled"""
2264

    
2265
        view_pane = self.ribbon.get_pane('View')
2266
        if key == Qt.Key_1:
2267
            checked = view_pane.ui.toolButtonViewImageDrawing.isChecked()
2268
            self.onViewImageDrawing(not checked)
2269
            view_pane.ui.toolButtonViewImageDrawing.setChecked(not checked)
2270
        elif key == Qt.Key_2:
2271
            checked = view_pane.ui.toolButtonViewText.isChecked()
2272
            self.onViewText(not checked)
2273
            view_pane.ui.toolButtonViewText.setChecked(not checked)
2274
        elif key == Qt.Key_3:
2275
            checked = view_pane.ui.toolButtonViewSymbol.isChecked()
2276
            self.onViewSymbol(not checked)
2277
            view_pane.ui.toolButtonViewSymbol.setChecked(not checked)
2278
        elif key == Qt.Key_4:
2279
            checked = view_pane.ui.toolButtonViewLine.isChecked()
2280
            self.onViewLine(not checked)
2281
            view_pane.ui.toolButtonViewLine.setChecked(not checked)
2282
        elif key == Qt.Key_5:
2283
            checked = view_pane.ui.toolButtonViewUnknown.isChecked()
2284
            self.onViewUnknown(not checked)
2285
            view_pane.ui.toolButtonViewUnknown.setChecked(not checked)
2286
        elif key == Qt.Key_6:
2287
            checked = view_pane.ui.toolButtonViewInconsistency.isChecked()
2288
            self.onViewInconsistency(not checked)
2289
            view_pane.ui.toolButtonViewInconsistency.setChecked(not checked)
2290
        elif key == Qt.Key_7:
2291
            checked = view_pane.ui.toolButtonViewVendorArea.isChecked()
2292
            self.onViewVendorArea(not checked)
2293
            view_pane.ui.toolButtonViewVendorArea.setChecked(not checked)
2294
        elif key == 96:  # '~' key
2295
            checked = view_pane.ui.toolButtonViewDrawingOnly.isChecked()
2296
            self.onViewDrawingOnly(not checked)
2297
            view_pane.ui.toolButtonViewDrawingOnly.setChecked(not checked)
2298

    
2299
    def keyPressEvent(self, event):
2300
        """restore to default command when user press Escape key"""
2301
        try:
2302
            if event.key() == Qt.Key_Escape:
2303
                checked = self.checked_action()
2304
                if checked:
2305
                    checked.setChecked(False)
2306
                    self.graphicsView.useDefaultCommand()
2307
            elif event.key() == Qt.Key_M:  # merge text as vertical
2308
                from TextInfo import TextInfo
2309

    
2310
                textItems = [text for text in self.graphicsView.scene().selectedItems() if
2311
                             issubclass(type(text), QEngineeringTextItem)]
2312
                if not textItems or len(textItems) is 1:
2313
                    return
2314

    
2315
                angle = None
2316
                for item in textItems:
2317
                    if angle is None:
2318
                        angle = item.angle
2319
                    else:
2320
                        if angle != item.angle:
2321
                            return
2322

    
2323
                modifiers = QApplication.keyboardModifiers()
2324
                enter_or_space = ' ' if modifiers == Qt.ControlModifier else '\n'
2325
                x_or_y = 0 if (modifiers == Qt.ControlModifier and angle == 0) or (modifiers != Qt.ControlModifier and angle == 1.57) else 1
2326

    
2327
                textItems = sorted(textItems, key=lambda text: text.loc[x_or_y]) if textItems[0].angle == 0 else ( \
2328
                    sorted(textItems, key=lambda text: text.loc[x_or_y]) if textItems[0].angle == 1.57 else ( \
2329
                        sorted(textItems, key=lambda text: text.loc[x_or_y], reverse=True) if textItems[0].angle == 4.71 else \
2330
                            sorted(textItems, key=lambda text: text.loc[x_or_y], reverse=True)))
2331

    
2332
                if textItems[0].angle == 1.57 and modifiers == Qt.ControlModifier:
2333
                    textItems.reverse()
2334

    
2335
                minX = sys.maxsize
2336
                minY = sys.maxsize
2337
                maxX = 0
2338
                maxY = 0
2339
                newText = ''
2340

    
2341
                for text in textItems:
2342
                    if text.loc[0] < minX: minX = text.loc[0]
2343
                    if text.loc[1] < minY: minY = text.loc[1]
2344
                    if text.loc[0] + text.size[0] > maxX: maxX = text.loc[0] + text.size[0]
2345
                    if text.loc[1] + text.size[1] > maxY: maxY = text.loc[1] + text.size[1]
2346
                    newText = newText + text.text() + enter_or_space
2347
                    text.transfer.onRemoved.emit(text)
2348
                newText = newText[:-1]
2349

    
2350
                textInfo = TextInfo(newText, minX, minY, maxX - minX, maxY - minY, textItems[0].angle)
2351
                x = textInfo.getX()
2352
                y = textInfo.getY()
2353
                angle = textInfo.getAngle()
2354
                text = textInfo.getText()
2355
                width = textInfo.getW()
2356
                height = textInfo.getH()
2357
                item = TextItemFactory.instance().createTextItem(textInfo)
2358
                if item is not None:
2359
                    item.loc = [x, y]
2360
                    item.size = (width, height)
2361
                    item.angle = angle
2362
                    item.area = textItems[0].area
2363
                    item.setDefaultTextColor(Qt.blue)
2364
                    item.addTextItemToScene(self.graphicsView.scene())
2365
                    item.transfer.onRemoved.connect(self.itemRemoved)
2366
            elif event.key() == Qt.Key_D:
2367
                # pop up development toolkit dialog
2368
                from DevelopmentToolkitDialog import QDevelopmentToolkitDialog
2369

    
2370
                modifiers = QApplication.keyboardModifiers()
2371
                if modifiers == Qt.ControlModifier:
2372
                    dlg = QDevelopmentToolkitDialog(self, self.graphicsView)
2373
                    dlg.show()
2374
            elif event.key() == Qt.Key_I:
2375
                # insert symbol item that is selected symbol in tree to main window if symbol already selected on main window, replace
2376
                index = self.symbolTreeWidget.currentIndex()
2377
                proxy_model = self.symbolTreeWidget.model()
2378
                items = [proxy_model.sourceModel().itemFromIndex(proxy_model.mapToSource(index))]
2379
                if items and hasattr(items[0], 'svgFilePath'):
2380
                    symData = items[0].data(self.symbolTreeWidget.TREE_DATA_ROLE)
2381
                    symName = symData.getName()
2382
                else:
2383
                    return
2384

    
2385
                symbolItems = [symbol for symbol in self.graphicsView.scene().selectedItems() if
2386
                               issubclass(type(symbol), SymbolSvgItem)]
2387
                old_symbol = None
2388
                if symbolItems and len(symbolItems) is 1:
2389
                    old_symbol = symbolItems[0]
2390
                    #scenePos = QPoint(old_symbol.origin[0], old_symbol.origin[1])
2391
                    scenePos = old_symbol.mapToScene(old_symbol.transformOriginPoint())
2392
                    old_symbol.transfer.onRemoved.emit(old_symbol)
2393
                else:
2394
                    scenePos = self.current_pos
2395

    
2396
                svg = QtImageViewer.createSymbolObject(symName)
2397
                QtImageViewer.matchSymbolToLine(self.graphicsView.scene(), svg, scenePos, angle=old_symbol.angle if old_symbol else 0.0)
2398

    
2399
                if old_symbol and svg:
2400
                    from ReplaceCommand import ReplaceCommand
2401

    
2402
                    cmd = ReplaceCommand(self.graphicsView.scene(), old_symbol, svg)
2403
                    self._scene.undo_stack.push(cmd)
2404
                    return
2405
            elif event.key() == Qt.Key_J:
2406
                # insert and connect symbol item that is selected symbol in tree to selected symbol
2407
                index = self.symbolTreeWidget.currentIndex()
2408
                proxy_model = self.symbolTreeWidget.model()
2409
                items = [proxy_model.sourceModel().itemFromIndex(proxy_model.mapToSource(index))]
2410
                if items and hasattr(items[0], 'svgFilePath'):
2411
                    symData = items[0].data(self.symbolTreeWidget.TREE_DATA_ROLE)
2412
                    symName = symData.getName()
2413
                else:
2414
                    return
2415

    
2416
                symbolItems = [symbol for symbol in self.graphicsView.scene().selectedItems() if
2417
                               issubclass(type(symbol), SymbolSvgItem)]
2418
                if symbolItems and len(symbolItems) is not 1:
2419
                    return
2420
                    
2421
                target_symbol = symbolItems[0]
2422
                index =  [index for index in range(len(target_symbol.conn_type)) \
2423
                            if target_symbol.conn_type[index] == 'Primary' or target_symbol.conn_type[index] == 'Secondary']
2424
                for connector in target_symbol.connectors:
2425
                    svg = QtImageViewer.createSymbolObject(symName)
2426
                    if len(svg.connectors) > 1: 
2427
                        if ((target_symbol.conn_type and target_symbol.connectors.index(connector) in index) or not target_symbol.conn_type) and \
2428
                                    (not connector.connectedItem or (connector.connectedItem and type(connector.connectedItem) is QEngineeringLineItem)):
2429
                            QtImageViewer.matchSymbolToLine(self.graphicsView.scene(), svg, connector.sceneBoundingRect().center())
2430
                    elif len(svg.connectors) == 1:
2431
                        if ((target_symbol.conn_type and target_symbol.connectors.index(connector) in index) or not target_symbol.conn_type) and \
2432
                                    not connector.connectedItem:
2433
                            QtImageViewer.matchSymbolToLine(self.graphicsView.scene(), svg, connector.sceneBoundingRect().center())
2434

    
2435
                if target_symbol:
2436
                    return
2437
            elif event.key() == Qt.Key_X:
2438
                app_doc_data = AppDocData.instance()
2439
                configs = app_doc_data.getAppConfigs('app', 'mode')
2440
                if configs and 1 == len(configs) and 'advanced' == configs[0].value:
2441
                    advanced = True
2442
                    items = self.graphicsView.scene().selectedItems()
2443
                    if items:
2444
                        item = self.symbolTreeWidget.currentItem()
2445
                        if item:
2446
                            self.symbolTreeWidget.showSymbolEditorDialog(item, 0)
2447
            elif event.key() == Qt.Key_F6:
2448
                from DEXPI import scene_to_dexpi
2449

    
2450
                app_doc_data = AppDocData.instance()
2451
                scene_to_dexpi('D:\\Temp\\DEXPI.xml', app_doc_data.activeDrawing.name, self.graphicsView.scene())
2452

    
2453
            QMainWindow.keyPressEvent(self, event)
2454
        except Exception as ex:
2455
            message = f"error occurred({repr(ex)}) in {sys.exc_info()[-1].tb_frame.f_code.co_filename}:" \
2456
                      f"{sys.exc_info()[-1].tb_lineno}"
2457
            self.addMessage.emit(MessageType.Error, message)
2458

    
2459
    def recognize(self):
2460
        """recognize symbol, text and line for selected drawings"""
2461
        from datetime import datetime
2462
        from License import QLicenseDialog
2463

    
2464
        # save alarm
2465
        self.save_alarm_enable(False)
2466

    
2467
        app_doc_data = AppDocData.instance()
2468
        current_drawing, currentPid = None, None
2469

    
2470
        if self.graphicsView.hasImage():
2471
            current_drawing = app_doc_data.activeDrawing
2472
            currentPid = app_doc_data.activeDrawing.name
2473

    
2474
        # get checked drawings
2475
        drawing_top = self.treeWidgetDrawingList.topLevelItem(0)
2476
        count = drawing_top.childCount()
2477
        checked_drawings = {}
2478
        for idx in range(count):
2479
            child = drawing_top.child(idx)
2480
            if child.checkState(0) == Qt.Checked and child.data(Qt.UserRole, 0):
2481
                checked_drawings[child.data(Qt.UserRole, 0)] = child
2482
        # up to here
2483

    
2484
        # if there is no checked drawing
2485
        if current_drawing and currentPid and not checked_drawings:
2486
            for idx in range(count):
2487
                child = drawing_top.child(idx)
2488
                if child.data(Qt.UserRole, 0) is current_drawing:
2489
                    checked_drawings[child.data(Qt.UserRole, 0)] = child
2490

    
2491
        if not checked_drawings:
2492
            self.showImageSelectionMessageBox()
2493
            return
2494

    
2495
        try:
2496
            self.on_clear_log()
2497
            dlg = QRecognitionDialog(self, [drawing for drawing in checked_drawings.keys()])
2498
            dlg.exec_()
2499

    
2500
            if current_drawing and current_drawing in checked_drawings.keys() and dlg.isTreated:
2501
                self.open_image_drawing(current_drawing, force=True, ocrUnknown=dlg.ui.checkBoxOCRUnknown.isChecked())
2502

    
2503
            # save working date-time
2504
            _now = datetime.now().strftime('%Y-%m-%d %H:%M:%S')
2505
            for drawing, tree_item in checked_drawings.items():
2506
                drawing.datetime = _now
2507
                tree_item.setText(1, _now)
2508
            #app_doc_data.saveDrawings(checked_drawings.keys())
2509
            self.changeViewCheckedState(True)
2510
            # count up for recognition
2511
            QLicenseDialog.count_up()
2512
            # up to here
2513
        except Exception as ex:
2514
            message = f"error occurred({repr(ex)}) in {sys.exc_info()[-1].tb_frame.f_code.co_filename}:" \
2515
                      f"{sys.exc_info()[-1].tb_lineno}"
2516
            self.addMessage.emit(MessageType.Error, message)
2517

    
2518
        # save alarm
2519
        self.save_alarm_enable(True)
2520

    
2521
    '''
2522
        @brief      remove item from tree widget and then remove from scene
2523
        @date       2018.05.25
2524
        @author     Jeongwoo
2525
    '''
2526

    
2527
    def itemRemoved(self, item):
2528
        try:
2529
            if type(item) is QEngineeringErrorItem:
2530
                # remove error item from inconsistency list
2531
                for row in range(self.tableWidgetInconsistency.rowCount()):
2532
                    if item is self.tableWidgetInconsistency.item(row, 0).tag:
2533
                        self.tableWidgetInconsistency.removeRow(row)
2534
                        break
2535

    
2536
                if item.scene() is not None:
2537
                    item.scene().removeItem(item)
2538
                del item
2539
            else:
2540
                remove_scene = item.scene()
2541
                self.itemTreeWidget.itemRemoved(item)
2542

    
2543
                matches = [_item for _item in remove_scene.items() if
2544
                           hasattr(_item, 'connectors') and [connector for connector in _item.connectors if
2545
                                                             connector.connectedItem is item]]
2546
                for match in matches:
2547
                    for connector in match.connectors:
2548
                        if connector.connectedItem is item:
2549
                            connector.connectedItem = None
2550
                            connector.highlight(False)
2551

    
2552
                # matches = [_item for _item in self.graphicsView.scene().items() if hasattr(_item, 'remove_assoc_item')]
2553
                # for _item in matches:
2554
                #    _item.remove_assoc_item(item)
2555

    
2556
                app_doc_data = AppDocData.instance()
2557
                if type(item) is QEngineeringLineNoTextItem and item in app_doc_data.tracerLineNos:
2558
                    app_doc_data.tracerLineNos.pop(app_doc_data.tracerLineNos.index(item))
2559

    
2560
                if type(item) is QEngineeringLineItem and item in app_doc_data.lines:
2561
                    app_doc_data.lines.remove(item)
2562

    
2563
                matches = [_item for _item in remove_scene.items() if
2564
                           type(_item) is QEngineeringLineNoTextItem]
2565
                matches.extend([lineNo for lineNo in app_doc_data.tracerLineNos if
2566
                                type(lineNo) is QEngineeringTrimLineNoTextItem])
2567
                for match in matches:
2568
                    if item is match.prop('From'):
2569
                        match.set_property('From', None)
2570
                    if item is match.prop('To'):
2571
                        match.set_property('To', None)
2572

    
2573
                    for run_index in reversed(range(len(match.runs))):
2574
                        run = match.runs[run_index]
2575
                        if item in run.items:
2576
                            index = run.items.index(item)
2577
                            run.items.pop(index)
2578
                            if not run.items:
2579
                                run.explode()
2580
                                if type(match) is QEngineeringTrimLineNoTextItem and not match.runs:
2581
                                    app_doc_data.tracerLineNos.pop(app_doc_data.tracerLineNos.index(match))
2582
                            # break
2583

    
2584
                matches = [_item for _item in remove_scene.items() if hasattr(_item, 'owner')]
2585
                for match in matches:
2586
                    if match.owner is item:
2587
                        match.owner = None
2588

    
2589
                matches = [_item for _item in remove_scene.items() if hasattr(_item, 'attrs')]
2590
                # done = False
2591
                for match in matches:
2592
                    assocs = match.associations()
2593
                    for assoc in assocs:
2594
                        if item is assoc:
2595
                            for attr in match.attrs.keys():
2596
                                if attr.AssocItem and str(item.uid) == str(attr.AssocItem.uid):
2597
                                    attr.AssocItem = None
2598
                                    match.attrs[attr] = ''
2599
                                    # done = True
2600
                            match.remove_assoc_item(item)
2601
                            break
2602
                    # if done: break
2603

    
2604
                if item.scene() is not None: item.scene().removeItem(item)
2605
        except Exception as ex:
2606
            message = 'error occurred({}) in {}:{}'.format(ex, sys.exc_info()[-1].tb_frame.f_code.co_filename,
2607
                                                           sys.exc_info()[-1].tb_lineno)
2608
            self.addMessage.emit(MessageType.Error, message)
2609
        '''
2610
        finally:
2611
            if hasattr(item, '_cond'):
2612
                item._cond.wakeAll()
2613
        '''
2614

    
2615

    
2616
    def connect_attributes(self, MainWindow):
2617
        """connect attributes to symbol"""
2618
        from LineNoTracer import LineNoTracer
2619
        from ConnectAttrDialog import QConnectAttrDialog
2620

    
2621
        if not self.graphicsView.hasImage():
2622
            self.showImageSelectionMessageBox()
2623
            return
2624

    
2625
        # save alarm
2626
        self.save_alarm_enable(False)
2627

    
2628
        try:
2629
            dlg = QConnectAttrDialog(self, self.graphicsView.scene())
2630
            dlg.setWindowFlags(self.windowFlags() & ~Qt.WindowCloseButtonHint & ~Qt.WindowContextHelpButtonHint)
2631
            dlg.exec_()
2632
            if dlg.isRunned:
2633
                self.refresh_item_list()
2634

    
2635
                if dlg.validation_checked:
2636
                    self.onValidation()
2637

    
2638
                self.graphicsView.invalidateScene()
2639
        except Exception as ex:
2640
            message = 'error occurred({}) in {}:{}'.format(ex, sys.exc_info()[-1].tb_frame.f_code.co_filename,
2641
                                                           sys.exc_info()[-1].tb_lineno)
2642
            self.addMessage.emit(MessageType.Error, message)
2643
        finally:
2644
            # save alarm
2645
            self.save_alarm_enable(True)
2646

    
2647
    def postDetectLineProcess(self):
2648
        '''
2649
            @brief  check allowables among undetected items
2650
            @author euisung
2651
            @date   2018.11.15
2652
            @history    2018.11.15  euisung    no more used, moved to TextItemFactoy isLineNo()
2653
        '''
2654
        from TextItemFactory import TextItemFactory
2655

    
2656
        appDocData = AppDocData.instance()
2657

    
2658
        tableNames = ["Fluid Code", "Insulation Purpose", "PnID Number", "Piping Materials Class", "Unit Number"]
2659
        tableDatas = []
2660
        for tableName in tableNames:
2661
            tableNameFormat = tableName.replace(' ', '').replace('&&', 'n')
2662
            tableDatas.append(appDocData.getCodeTable(tableNameFormat))
2663

    
2664
        items = self.graphicsView.scene().items()
2665
        for item in items:
2666
            if type(item) is not QEngineeringTextItem:
2667
                continue
2668
            text = item.text()
2669
            for tableData in tableDatas:
2670
                for data in tableData:
2671
                    if data[3] == '':
2672
                        continue
2673
                    else:
2674
                        allows = data[3].split(',')
2675
                        for allow in allows:
2676
                            text = text.replace(allow, data[1])
2677

    
2678
            lineItem = TextItemFactory.instance().createTextItem(text)
2679
            if type(lineItem) is QEngineeringLineNoTextItem:
2680
                lineItem.loc = item.loc
2681
                lineItem.size = item.size
2682
                lineItem.angle = item.angle
2683
                lineItem.area = item.area
2684
                # lineItem.addTextItemToScene(self.graphicsView.scene())
2685
                lineItem.transfer.onRemoved.connect(self.itemRemoved)
2686
                item.transfer.onRemoved.emit(item)
2687
                appDocData.lineNos.append(lineItem)
2688

    
2689
    def init_add_tree_item(self, line_no_tree_item, run_item):
2690
        """ insert symbol item and find line no as owner """
2691
        # insert
2692
        self.itemTreeWidget.addTreeItem(line_no_tree_item, run_item)
2693
        # find
2694
        self.itemTreeWidget.addTreeItem(line_no_tree_item, run_item)
2695

    
2696
    def load_drawing(self, drawing):
2697
        """ load drawing """
2698
        from EngineeringRunItem import QEngineeringRunItem
2699
        from QEngineeringTrimLineNoTextItem import QEngineeringTrimLineNoTextItem
2700

    
2701
        app_doc_data = AppDocData.instance()
2702
        try:
2703
            symbols = []
2704
            lines = []
2705

    
2706
            components = app_doc_data.get_components(drawing.UID)
2707
            maxValue = len(components) * 2
2708
            self.progress.setMaximum(maxValue) if maxValue > 0 else None
2709

    
2710
            """ parsing all symbols """
2711
            for symbol in [component for component in components if int(component['SymbolType_UID']) != -1]:
2712
                item = SymbolSvgItem.from_database(symbol)
2713
                if item is not None:
2714
                    item.transfer.onRemoved.connect(self.itemRemoved)
2715
                    symbols.append(item)
2716
                    app_doc_data.symbols.append(item)
2717
                    item.addSvgItemToScene(self.graphicsView.scene())
2718
                else:
2719
                    pt = [float(symbol['X']), float(symbol['Y'])]
2720
                    size = [float(symbol['Width']), float(symbol['Height'])]
2721
                    angle = float(symbol['Rotation'])
2722
                    item = QGraphicsBoundingBoxItem(pt[0], pt[1], size[0], size[1])
2723
                    item.isSymbol = True
2724
                    item.angle = angle
2725
                    item.setPen(QPen(Qt.red, 5, Qt.SolidLine))
2726
                    self.graphicsView.scene().addItem(item)
2727
                    item.transfer.onRemoved.connect(self.itemRemoved)
2728

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

    
2731
            QApplication.processEvents()
2732

    
2733
            # parse texts
2734
            for text in [component for component in components if
2735
                         component['Name'] == 'Text' and component['SymbolType_UID'] == -1]:
2736
                item = QEngineeringTextItem.from_database(text)
2737
                if item is not None:
2738
                    item.uid = text['UID']
2739
                    item.attribute = text['Value']
2740
                    name = text['Name']
2741
                    item.transfer.onRemoved.connect(self.itemRemoved)
2742
                    item.addTextItemToScene(self.graphicsView.scene())
2743

    
2744
                self.progress.setValue(self.progress.value() + 1)
2745

    
2746
            QApplication.processEvents()
2747

    
2748
            # note
2749
            for note in [component for component in components if
2750
                         component['Name'] == 'Note' and component['SymbolType_UID'] == -1]:
2751
                item = QEngineeringTextItem.from_database(note)
2752
                if item is not None:
2753
                    item.uid = note['UID']
2754
                    attributeValue = note['Value']
2755
                    name = note['Name']
2756
                    item.transfer.onRemoved.connect(self.itemRemoved)
2757
                    item.addTextItemToScene(self.graphicsView.scene())
2758

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

    
2761
            QApplication.processEvents()
2762

    
2763
            for line in [component for component in components if
2764
                         component['Name'] == 'Line' and component['SymbolType_UID'] == -1]:
2765
                item = QEngineeringLineItem.from_database(line)
2766
                if item:
2767
                    item.transfer.onRemoved.connect(self.itemRemoved)
2768
                    self.graphicsView.scene().addItem(item)
2769
                    lines.append(item)
2770

    
2771
                self.progress.setValue(self.progress.value() + 1)
2772

    
2773
            QApplication.processEvents()
2774

    
2775
            for unknown in [component for component in components if
2776
                            component['Name'] == 'Unknown' and component['SymbolType_UID'] == -1]:
2777
                item = QEngineeringUnknownItem.from_database(unknown)
2778
                item.transfer.onRemoved.connect(self.itemRemoved)
2779
                if item is not None:
2780
                    item.transfer.onRemoved.connect(self.itemRemoved)
2781
                    self.graphicsView.scene().addItem(item)
2782

    
2783
                self.progress.setValue(self.progress.value() + 1)
2784

    
2785
            QApplication.processEvents()
2786

    
2787
            for component in [component for component in components if
2788
                              component['Name'] == 'Line NO' and component['SymbolType_UID'] == -1]:
2789
                line_no = QEngineeringLineNoTextItem.from_database(component)
2790
                if type(line_no) is QEngineeringLineNoTextItem:
2791
                    line_no.transfer.onRemoved.connect(self.itemRemoved)
2792
                    self.addTextItemToScene(line_no)
2793
                    line_no_tree_item = self.itemTreeWidget.addTreeItem(self.itemTreeWidget.root, line_no)
2794

    
2795
                    runs = app_doc_data.get_pipe_runs(str(line_no.uid))
2796
                    if not runs: continue
2797
                    for run in runs:
2798
                        line_run = QEngineeringRunItem()
2799
                        run_items = app_doc_data.get_pipe_run_items(run['UID'])
2800
                        for record in run_items:
2801
                            uid = record['Components_UID']
2802
                            run_item = self.graphicsView.findItemByUid(uid)
2803
                            if run_item is not None:
2804
                                run_item._owner = line_no
2805
                                line_run.items.append(run_item)
2806
                        line_run.owner = line_no
2807
                        line_no.runs.append(line_run)
2808

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

    
2813
                self.progress.setValue(self.progress.value() + 1)
2814
            QApplication.processEvents()
2815

    
2816
            for component in [component for component in components if
2817
                              component['Name'] == 'Trim Line NO' and component['SymbolType_UID'] == -1]:
2818
                line_no = QEngineeringTrimLineNoTextItem()
2819
                line_no.uid = uuid.UUID(component['UID'])
2820

    
2821
                runs = app_doc_data.get_pipe_runs(str(line_no.uid))
2822
                if not runs: continue
2823

    
2824
                line_no_tree_item = self.itemTreeWidget.addTreeItem(self.itemTreeWidget.root, line_no)
2825

    
2826
                for run in runs:
2827
                    line_run = QEngineeringRunItem()
2828
                    run_items = app_doc_data.get_pipe_run_items(run['UID'])
2829
                    for record in run_items:
2830
                        uid = record['Components_UID']
2831
                        run_item = self.graphicsView.findItemByUid(uid)
2832
                        if run_item is not None:
2833
                            run_item.owner = line_no
2834
                            line_run.items.append(run_item)
2835
                    line_run.owner = line_no
2836
                    line_no.runs.append(line_run)
2837

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

    
2842
                app_doc_data.tracerLineNos.append(line_no)
2843

    
2844
                self.progress.setValue(self.progress.value() + 1)
2845

    
2846
            for component in [component for component in components if
2847
                              component['Name'] == 'VendorPackage' and component['SymbolType_UID'] == -1]:
2848
                item = QEngineeringVendorItem.from_database(component)
2849
                if item is not None:
2850
                    item.transfer.onRemoved.connect(self.itemRemoved)
2851
                    self.graphicsView.scene().addItem(item)
2852

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

    
2864
            """ update scene """
2865
            self.graphicsView.scene().update(self.graphicsView.sceneRect())
2866
            for item in self.graphicsView.scene().items():
2867
                up_progress = False
2868
                # binding items
2869
                if hasattr(item, 'owner'):
2870
                    item.owner
2871
                    up_progress = True
2872
                if hasattr(item, 'connectors'):
2873
                    for connector in item.connectors:
2874
                        connector.connectedItem
2875
                    up_progress = True
2876

    
2877
                if up_progress:
2878
                    self.progress.setValue(self.progress.value() + 1)
2879
            
2880
            for item in self.graphicsView.scene().items():
2881
                item.setVisible(True)
2882

    
2883
        except Exception as ex:
2884
            message = 'error occurred({}) in {}:{}'.format(ex, sys.exc_info()[-1].tb_frame.f_code.co_filename,
2885
                                                           sys.exc_info()[-1].tb_lineno)
2886
            self.addMessage.emit(MessageType.Error, message)
2887
        finally:
2888
            app_doc_data.clearTempDBData()
2889
            self.itemTreeWidget.update_item_count()
2890
            self.itemTreeWidget.expandAll()
2891
            # self.graphicsView.scene().blockSignals(False)
2892

    
2893
    '''
2894
        @brief      load recognition result
2895
        @author     humkyung
2896
        @date       2018.04.??
2897
        @history    humkyung 2018.01.12 parse originalpoint and connectionpoint
2898
                    Jeongwoo 2018.04.17 add QGraphicItem with Rotated text
2899
                    Jeongwoo 2018.04.23 Change to Draw texts on QEngineeringTextItem
2900
                    humkyung 2018.04.23 connect item remove slot to result tree
2901
                    Jeongwoo 2018.04.25 Add if state with QEngineeringNoteItem
2902
                    Jeongwoo 2018.04.26 Change method to create TextItem object with TextItemFactory
2903
                    Jeongwoo 2018.05.03 Change method to draw Svg Item on Scene (svg.addSvgItemToScene)
2904
                    Jeongwoo 2018.05.29 Change method name / Change method to add item / Add Line item
2905
                    Jeongwoo 2018.05.30 Add parameters on SymbolSvgItem.__init__() (parentSymbol, childSymbol) / Change method name / Change XML NODE NAMES
2906
                    Jeongwoo 2018.06.12 Add LineNoTextItem from LINE_NO
2907
                    Jeongwoo 2018.06.14 Add UnknownItem from UNKNOWN
2908
                    Jeongwoo 2018.06.18 Update Scene after all item added
2909
                                        Add connect on unknown item
2910
                                        Add [transfer] for using pyqtSignal
2911
                    kyouho  2018.07.12  Add line property logic
2912
                    humkyung 2018.08.22 show progress while loading xml file
2913
                    2018.11.22      euisung     fix note road
2914
    '''
2915

    
2916
    def load_recognition_result_from_xml(self, drawing):
2917
        # Yield successive n-sized
2918
        # chunks from l.
2919
        def divide_chunks(l, n):
2920
            # looping till length l
2921
            for i in range(0, len(l), n):
2922
                yield l[i:i + n]
2923

    
2924
        def update_items(items):
2925
            for item in items:
2926
                # binding items
2927
                item.owner
2928
                for connector in item.connectors:
2929
                    connector.connectedItem
2930

    
2931
            return items
2932

    
2933
        import concurrent.futures as futures
2934
        from xml.etree.ElementTree import Element, SubElement, dump, ElementTree, parse
2935
        from App import App
2936
        from EngineeringRunItem import QEngineeringRunItem
2937
        from QEngineeringTrimLineNoTextItem import QEngineeringTrimLineNoTextItem
2938
        from EngineeringGraphicsLineItem import QEngineeringGraphicsLineItem
2939

    
2940
        app_doc_data = AppDocData.instance()
2941

    
2942
        try:
2943
            file_name = os.path.splitext(os.path.basename(drawing.file_path))[0]
2944
            path = os.path.join(app_doc_data.getCurrentProject().getTempPath(), file_name + '.xml')
2945
            self.graphicsView.scene().blockSignals(True)
2946

    
2947
            symbols = []
2948
            lines = []
2949

    
2950
            xml = parse(path)
2951
            root = xml.getroot()
2952

    
2953
            maxValue = 0
2954
            maxValue = maxValue + len(list(root.iter('SYMBOL'))) - \
2955
                       len(list(root.iterfind('LINENOS/LINE_NO/RUN/SYMBOL'))) - \
2956
                       len(list(root.iterfind('TRIMLINENOS/TRIM_LINE_NO/RUN/SYMBOL')))
2957
            maxValue = maxValue + len(list(root.iterfind('TEXTINFOS/ATTRIBUTE')))
2958
            maxValue = maxValue + len(list(root.iterfind('NOTES/ATTRIBUTE')))
2959
            maxValue = maxValue + len(list(root.iter('LINE_NO')))
2960
            maxValue = maxValue + len(list(root.iter('LINE'))) - \
2961
                       len(list(root.iterfind('LINENOS/LINE_NO/RUN/LINE'))) - \
2962
                       len(list(root.iterfind('TRIMLINENOS/TRIM_LINE_NO/RUN/LINE')))
2963
            maxValue = maxValue + len(list(root.iter('GRAPHICS_LINE')))
2964
            maxValue = maxValue + len(list(root.iter('UNKNOWN')))
2965
            # maxValue = maxValue + len(list(root.iter('SIZETEXT')))
2966
            maxValue = maxValue + len(list(root.iter('TRIM_LINE_NO')))
2967
            maxValue *= 2
2968
            self.progress.setMaximum(maxValue) if maxValue > 0 else None
2969

    
2970
            """ parsing all symbols """
2971
            """
2972
            with futures.ThreadPoolExecutor(max_workers=App.THREAD_MAX_WORKER) as pool:
2973
                future_symbol = {pool.submit(SymbolSvgItem.fromXml, symbol): symbol for symbol in root.find('SYMBOLS').iter('SYMBOL')}
2974

2975
                for future in futures.as_completed(future_symbol):
2976
                    try:
2977
                        item = future.result()
2978
                        if item:
2979
                            if item is not None:
2980
                                item.transfer.onRemoved.connect(self.itemRemoved)
2981
                                symbols.append(item)
2982
                                docData.symbols.append(item)
2983
                                self.addSvgItemToScene(item)
2984
                            else:
2985
                                pt = [float(x) for x in symbol.find('LOCATION').text.split(',')]
2986
                                size = [float(x) for x in symbol.find('SIZE').text.split(',')]
2987
                                angle = float(symbol.find('ANGLE').text)
2988
                                item = QGraphicsBoundingBoxItem(pt[0], pt[1], size[0], size[1])
2989
                                item.isSymbol = True
2990
                                item.angle = angle
2991
                                item.setPen(QPen(Qt.red, 5, Qt.SolidLine))
2992
                                self.graphicsView.scene().addItem(item)
2993
                                item.transfer.onRemoved.connect(self.itemRemoved)
2994
                    except Exception as ex:
2995
                        message = 'error occurred({}) in {}:{}'.format(repr(ex), sys.exc_info()[-1].tb_frame.f_code.co_filename,
2996
                                                                       sys.exc_info()[-1].tb_lineno)
2997

2998
            """
2999
            for symbol in root.find('SYMBOLS').iter('SYMBOL'):
3000
                item = SymbolSvgItem.fromXml(symbol)
3001
                if item is not None:
3002
                    item.transfer.onRemoved.connect(self.itemRemoved)
3003
                    symbols.append(item)
3004
                    #app_doc_data.symbols.append(item)
3005
                    item.addSvgItemToScene(self.graphicsView.scene())
3006
                else:
3007
                    pt = [float(x) for x in symbol.find('LOCATION').text.split(',')]
3008
                    size = [float(x) for x in symbol.find('SIZE').text.split(',')]
3009
                    angle = float(symbol.find('ANGLE').text)
3010
                    item = QGraphicsBoundingBoxItem(pt[0], pt[1], size[0], size[1])
3011
                    item.isSymbol = True
3012
                    item.angle = angle
3013
                    item.setPen(QPen(Qt.red, 5, Qt.SolidLine))
3014
                    self.graphicsView.scene().addItem(item)
3015
                    item.transfer.onRemoved.connect(self.itemRemoved)
3016

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

    
3019
            QApplication.processEvents()
3020

    
3021
            # parse texts
3022
            for text in root.find('TEXTINFOS').iter('ATTRIBUTE'):
3023
                item = QEngineeringTextItem.fromXml(text)
3024
                if item is not None:
3025
                    uid = text.find('UID')
3026
                    attributeValue = text.find('ATTRIBUTEVALUE')
3027
                    name = text.find('NAME').text
3028
                    item.transfer.onRemoved.connect(self.itemRemoved)
3029
                    item.addTextItemToScene(self.graphicsView.scene())
3030
                    # docData.texts.append(item)
3031

    
3032
                    if name == 'TEXT':
3033
                        if uid is not None and attributeValue is not None:
3034
                            item.uid = uid.text
3035
                            item.attribute = attributeValue.text
3036

    
3037
                self.progress.setValue(self.progress.value() + 1)
3038

    
3039
            QApplication.processEvents()
3040

    
3041
            # note
3042
            for text in root.find('NOTES').iter('ATTRIBUTE'):
3043
                item = QEngineeringTextItem.fromXml(text)
3044
                if item is not None:
3045
                    uid = text.find('UID')
3046
                    attributeValue = text.find('ATTRIBUTEVALUE')
3047
                    name = text.find('NAME').text
3048
                    item.transfer.onRemoved.connect(self.itemRemoved)
3049
                    item.addTextItemToScene(self.graphicsView.scene())
3050

    
3051
                    if name == 'NOTE':
3052
                        if uid is not None:
3053
                            item.uid = uid.text
3054

    
3055
                self.progress.setValue(self.progress.value() + 1)
3056

    
3057
            QApplication.processEvents()
3058

    
3059
            for line in root.find('LINEINFOS').iter('LINE'):
3060
                item = QEngineeringLineItem.fromXml(line)
3061
                if item:
3062
                    item.transfer.onRemoved.connect(self.itemRemoved)
3063
                    self.graphicsView.scene().addItem(item)
3064
                    lines.append(item)
3065

    
3066
                self.progress.setValue(self.progress.value() + 1)
3067

    
3068
            for line in root.find('LINEINFOS').iter('GRAPHICS_LINE'):
3069
                item = QEngineeringGraphicsLineItem.fromXml(line)
3070
                if item:
3071
                    item.transfer.onRemoved.connect(self.itemRemoved)
3072
                    self.graphicsView.scene().addItem(item)
3073

    
3074
                self.progress.setValue(self.progress.value() + 1)
3075

    
3076
            QApplication.processEvents()
3077

    
3078
            for unknown in root.iter('UNKNOWN'):
3079
                item = QEngineeringUnknownItem.fromXml(unknown)
3080
                if item is not None:
3081
                    item.transfer.onRemoved.connect(self.itemRemoved)
3082
                    self.graphicsView.scene().addItem(item)
3083

    
3084
                self.progress.setValue(self.progress.value() + 1)
3085

    
3086
            QApplication.processEvents()
3087

    
3088
            # """ add tree widget """
3089
            # for item in symbols:
3090
            #    docData.symbols.append(item)
3091
            #    self.addSvgItemToScene(item)
3092
            #    self.itemTreeWidget.addTreeItem(self.itemTreeWidget.root, item)
3093

    
3094
            for line_no_node in root.find('LINENOS').iter('LINE_NO'):
3095
                line_no = QEngineeringLineNoTextItem.fromXml(line_no_node)
3096
                if line_no is None: continue
3097
                line_no.transfer.onRemoved.connect(self.itemRemoved)
3098
                line_no.addTextItemToScene(self.graphicsView.scene())
3099
                line_no_tree_item = self.itemTreeWidget.addTreeItem(self.itemTreeWidget.root, line_no)
3100
                if type(line_no) is not QEngineeringLineNoTextItem: continue
3101

    
3102
                runs_node = line_no_node.findall('RUN')
3103
                if runs_node is None: continue
3104

    
3105
                for run_node in runs_node:
3106
                    line_run = QEngineeringRunItem()
3107
                    for child_node in run_node:
3108
                        uidElement = child_node.find('UID')
3109
                        if uidElement is not None:
3110
                            uid = uidElement.text
3111
                            run_item = self.graphicsView.findItemByUid(uid)
3112
                            if run_item is not None:
3113
                                run_item._owner = line_no
3114
                                line_run.items.append(run_item)
3115
                    line_run.owner = line_no
3116
                    line_no.runs.append(line_run)
3117

    
3118
                    for run_item in line_run.items:
3119
                        if issubclass(type(run_item), SymbolSvgItem):
3120
                            self.init_add_tree_item(line_no_tree_item, run_item)
3121

    
3122
                # docData.tracerLineNos.append(line_no)
3123

    
3124
                self.progress.setValue(self.progress.value() + 1)
3125
            QApplication.processEvents()
3126

    
3127
            for trimLineNo in root.iter('TRIM_LINE_NO'):
3128
                line_no = QEngineeringTrimLineNoTextItem()
3129
                line_no.uid = uuid.UUID(trimLineNo.find('UID').text)
3130

    
3131
                runs_node = trimLineNo.findall('RUN')
3132
                if runs_node is None: continue
3133
                line_no_tree_item = self.itemTreeWidget.addTreeItem(self.itemTreeWidget.root, line_no)
3134

    
3135
                for run in runs_node:
3136
                    line_run = QEngineeringRunItem()
3137
                    for child in run:
3138
                        uidElement = child.find('UID')
3139
                        if uidElement is not None:
3140
                            uid = uidElement.text
3141
                            run_item = self.graphicsView.findItemByUid(uid)
3142
                            if run_item is not None:
3143
                                run_item.owner = line_no
3144
                                line_run.items.append(run_item)
3145
                    line_run.owner = line_no
3146
                    line_no.runs.append(line_run)
3147

    
3148
                    for run_item in line_run.items:
3149
                        if issubclass(type(run_item), SymbolSvgItem):
3150
                            self.init_add_tree_item(line_no_tree_item, run_item)
3151

    
3152
                app_doc_data.tracerLineNos.append(line_no)
3153

    
3154
                self.progress.setValue(self.progress.value() + 1)
3155
            QApplication.processEvents()
3156

    
3157
            if root.find('VENDORS') is not None:
3158
                for vendor in root.find('VENDORS').iter('VENDOR'):
3159
                    item = QEngineeringVendorItem.fromXml(vendor)
3160
                    item.transfer.onRemoved.connect(self.itemRemoved)
3161
                    self.graphicsView.scene().addItem(item)
3162

    
3163
            # connect flow item to line
3164
            for line in lines:
3165
                line.update_arrow()
3166
                app_doc_data.lines.append(line)
3167
            # for flowMark in [item for item in symbols if type(item) is QEngineeringFlowMarkItem]:
3168
            #    for line in lines:
3169
            #        if flowMark.owner is line:
3170
            #            line._flowMark.append(flowMark)
3171
            #            flowMark.setParentItem(line)
3172
            # up to here
3173

    
3174
            """
3175
            group_box = QGroupBox("Contact Details")
3176
            number_label = QLabel("Telephone number");
3177
            number_edit = QTextEdit('hello\nthis is ....')
3178
            layout = QFormLayout()
3179
            layout.addRow(number_label, number_edit)
3180
            group_box.setLayout(layout)
3181

3182
            proxy =  ㅐ()
3183
            proxy.setWidget(group_box)
3184
            self.graphicsView.scene().addItem(proxy)  # (group_box, QGraphicsItem.ItemIgnoresTransformations)
3185
            """
3186

    
3187
            """ update scene """
3188
            _items = [_item for _item in self.graphicsView.scene().items() if hasattr(_item, 'owner') or hasattr(_item, 'connectors')]
3189
            if _items:
3190
                items = divide_chunks(_items, App.THREAD_MAX_WORKER if len(_items) > App.THREAD_MAX_WORKER else len(_items))
3191
                with futures.ThreadPoolExecutor(max_workers=App.THREAD_MAX_WORKER) as pool:
3192
                    future_items = {pool.submit(update_items, _items): _items for _items in items}
3193
                    for future in futures.as_completed(future_items):
3194
                        _items = future.result()
3195
                        self.progress.setValue(self.progress.value() + len(_items))
3196

    
3197
            """
3198
            for item in [_item for _item in self.graphicsView.scene().items() if hasattr(_item, 'owner') or hasattr(_item, 'connectors')]:
3199
                up_progress = False
3200
                # binding items
3201
                item.owner
3202
                for connector in item.connectors:
3203
                    connector.connectedItem
3204

3205
                self.progress.setValue(self.progress.value() + 1)
3206
            """
3207

    
3208
            for item in self.graphicsView.scene().items():
3209
                item.setVisible(True)
3210

    
3211
            self.graphicsView.scene().update(self.graphicsView.sceneRect())
3212
        except Exception as ex:
3213
            message = 'error occurred({}) in {}:{}'.format(ex, sys.exc_info()[-1].tb_frame.f_code.co_filename,
3214
                                                           sys.exc_info()[-1].tb_lineno)
3215
            self.addMessage.emit(MessageType.Error, message)
3216
        finally:
3217
            self.itemTreeWidget.update_item_count()
3218
            self.itemTreeWidget.expandAll()
3219
            self.graphicsView.scene().blockSignals(False)
3220

    
3221
    '''
3222
        @brief      Remove added item on same place and Add GraphicsItem
3223
        @author     Jeongwoo
3224
        @date       2018.05.29
3225
        @history    2018.06.18  Jeongwoo    Set Z-index
3226
    '''
3227

    
3228
    def addLineItemToScene(self, lineItem):
3229
        self.graphicsView.scene().addItem(lineItem)
3230

    
3231
    '''
3232
        @brief      generate output xml file
3233
        @author     humkyung
3234
        @date       2018.04.23
3235
        @history    2018.05.02  Jeongwoo    Show MessageBox when imageviewer doesn't have image
3236
    '''
3237

    
3238
    def generateOutput(self):
3239
        import XmlGenerator as xg
3240

    
3241
        if not self.graphicsView.hasImage():
3242
            self.showImageSelectionMessageBox()
3243
            return
3244

    
3245
        try:
3246
            appDocData = AppDocData.instance()
3247

    
3248
            # collect items
3249
            appDocData.lines.clear()
3250
            appDocData.lines = [item for item in self.graphicsView.scene().items() if
3251
                                type(item) is QEngineeringLineItem and item.owner is None]
3252

    
3253
            appDocData.symbols.clear()
3254
            appDocData.symbols = [item for item in self.graphicsView.scene().items() if
3255
                                  issubclass(type(item), SymbolSvgItem) and item.owner is None]
3256

    
3257
            appDocData.equipments.clear()
3258
            for item in self.graphicsView.scene().items():
3259
                if type(item) is QEngineeringEquipmentItem:
3260
                    appDocData.equipments.append(item)
3261

    
3262
            appDocData.texts.clear()
3263
            appDocData.texts = [item for item in self.graphicsView.scene().items() if
3264
                                issubclass(type(item), QEngineeringTextItem) and type(
3265
                                    item) is not QEngineeringLineNoTextItem]
3266
            # up to here
3267

    
3268
            appDocData.imgOutput = np.ones((appDocData.activeDrawing.height, appDocData.activeDrawing.width),
3269
                                           np.uint8) * 255
3270
            xg.writeOutputXml(appDocData.imgName, appDocData.activeDrawing.width,
3271
                              appDocData.activeDrawing.height)  # TODO: check
3272
            project = appDocData.getCurrentProject()
3273
            cv2.imwrite(os.path.join(project.getTempPath(), 'OUTPUT.png'), appDocData.imgOutput)
3274
        except Exception as ex:
3275
            message = 'error occurred({}) in {}:{}'.format(ex, sys.exc_info()[-1].tb_frame.f_code.co_filename,
3276
                                                           sys.exc_info()[-1].tb_lineno)
3277
            self.addMessage.emit(MessageType.Error, message)
3278

    
3279
    '''
3280
        @brief      Check Number
3281
        @author     kyouho
3282
        @date       2018.08.20
3283
    '''
3284

    
3285
    def isNumber(self, num):
3286
        p = re.compile('(^[0-9]+$)')
3287
        result = p.match(num)
3288

    
3289
        if result:
3290
            return True
3291
        else:
3292
            return False
3293

    
3294
    '''
3295
        @brief      find overlap Connector
3296
        @author     kyouho
3297
        @date       2018.08.28
3298
    '''
3299

    
3300
    def findOverlapConnector(self, connectorItem):
3301
        from shapely.geometry import Point
3302
        from EngineeringConnectorItem import QEngineeringConnectorItem
3303
        itemList = []
3304

    
3305
        x = connectorItem.center()[0]
3306
        y = connectorItem.center()[1]
3307

    
3308
        connectors = [item for item in self.graphicsView.scene().items() if
3309
                      type(item) is QEngineeringConnectorItem and item != connectorItem]
3310
        for connector in connectors:
3311
            if Point(x, y).distance(Point(connector.center()[0], connector.center()[1])) < 5:
3312
                itemList.append(connector.parent)
3313

    
3314
        return itemList
3315

    
3316
    def make_diff_image(self):
3317
        """ make diff image """
3318
        # test
3319

    
3320
        from RecognitionDialog import Worker
3321
        from symbol import Symbol
3322
        import math
3323
        from PIL import Image
3324

    
3325
        app_doc_data = AppDocData.instance()
3326
        img = app_doc_data.imgSrc.copy()
3327

    
3328
        # check break
3329
        symbols = [item for item in self.graphicsView.scene().items() if issubclass(type(item), SymbolSvgItem)]
3330

    
3331
        for symbol in symbols:
3332
            rect = symbol.sceneBoundingRect()
3333
            sName = symbol.name
3334
            sType = symbol.type
3335
            sp = (rect.x(), rect.y())
3336
            w, h = rect.width(), rect.height()
3337
            rotatedAngle = round(math.degrees(symbol.angle))
3338
            detectFlip = symbol.flip
3339

    
3340
            dummySym = Symbol(sName, sType, sp, w, h, 0, 0, 0, rotatedAngle,
3341
                                   1, 0, 1, 0,
3342
                                   ','.join(str(x) for x in [0, 0]),
3343
                                   '/'.join('{},{},{},{}'.format(param[0], param[1], param[2], param[3]) for param in
3344
                                            []),
3345
                                   'dummy', 'dummy', 0, detectFlip=detectFlip,
3346
                                   hasInstrumentLabel=0, text_area='')
3347

    
3348
            Worker.remove_detected_symbol_image(dummySym, img, lock=False)
3349

    
3350
        Image.fromarray(img).show()
3351

    
3352
    #def paintEvent(self, event):
3353
    #    self.refresh_rate += 1
3354
    #    if self.refresh_rate == 3:
3355
    #        super(self.__class__, self).paintEvent(event)
3356
    #        self.refresh_rate = 0
3357

    
3358
if __name__ == '__main__':
3359
    import locale
3360
    from PyQt5.QtCore import QTranslator
3361
    from License import QLicenseDialog
3362
    from ProjectDialog import Ui_Dialog
3363
    from App import App
3364

    
3365
    app = App(sys.argv)
3366
    try:
3367
        if True == QLicenseDialog.check_license_key():
3368
            dlg = Ui_Dialog()
3369
            selectedProject = dlg.showDialog()
3370
            if selectedProject is not None:
3371
                AppDocData.instance().setCurrentProject(selectedProject)
3372
                app._mainWnd = MainWindow.instance()
3373
                app._mainWnd.show()
3374
                sys.exit(app.exec_())
3375
    except Exception as ex:
3376
        print('error occurred({}) in {}:{}'.format(ex, sys.exc_info()[-1].tb_frame.f_code.co_filename,
3377
                                                   sys.exc_info()[-1].tb_lineno))
3378
    finally:
3379
        pass