프로젝트

일반

사용자정보

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

hytos / DTI_PID / DTI_PID / MainWindow.py @ b00e81bf

이력 | 보기 | 이력해설 | 다운로드 (148 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
        view_pane = self.ribbon.get_pane('View')
256
        shortcut = QShortcut(QKeySequence(Qt.Key_1), view_pane.ui.toolButtonViewImageDrawing)
257
        shortcut.activated.connect(partial(self.on_view_toggle, Qt.Key_1))
258
        shortcut = QShortcut(QKeySequence(Qt.Key_2), view_pane.ui.toolButtonViewText)
259
        shortcut.activated.connect(partial(self.on_view_toggle, Qt.Key_2))
260
        shortcut = QShortcut(QKeySequence(Qt.Key_3), view_pane.ui.toolButtonViewSymbol)
261
        shortcut.activated.connect(partial(self.on_view_toggle, Qt.Key_3))
262
        shortcut = QShortcut(QKeySequence(Qt.Key_4), view_pane.ui.toolButtonViewLine)
263
        shortcut.activated.connect(partial(self.on_view_toggle, Qt.Key_4))
264
        shortcut = QShortcut(QKeySequence(Qt.Key_5), view_pane.ui.toolButtonViewUnknown)
265
        shortcut.activated.connect(partial(self.on_view_toggle, Qt.Key_5))
266
        shortcut = QShortcut(QKeySequence(Qt.Key_6), view_pane.ui.toolButtonViewInconsistency)
267
        shortcut.activated.connect(partial(self.on_view_toggle, Qt.Key_6))
268
        shortcut = QShortcut(QKeySequence(Qt.Key_7), view_pane.ui.toolButtonViewVendorArea)
269
        shortcut.activated.connect(partial(self.on_view_toggle, Qt.Key_7))
270
        shortcut = QShortcut(QKeySequence(96), view_pane.ui.toolButtonViewDrawingOnly)
271
        shortcut.activated.connect(partial(self.on_view_toggle, 96))
272

    
273
        # inconsistency table
274
        self.tableWidgetInconsistency.setColumnCount(3)
275
        self.tableWidgetInconsistency.setHorizontalHeaderLabels(['Owner', 'Type', 'Message'])
276
        self.tableWidgetInconsistency.setEditTriggers(QAbstractItemView.NoEditTriggers)
277
        self.tableWidgetInconsistency.itemClicked.connect(self.inconsistencyItemClickEvent)
278
        self.tableWidgetInconsistency.keyPressEvent = self.inconsistencyTableKeyPressEvent
279
        self.tableWidgetInconsistency.setSortingEnabled(True)
280

    
281
        self.read_settings()
282

    
283
    @property
284
    def title(self) -> str:
285
        """return window title"""
286

    
287
        from App import App
288

    
289
        app_doc_data = AppDocData.instance()
290
        project = app_doc_data.getCurrentProject()
291
        version = QCoreApplication.applicationVersion()
292
        title = f"{App.NAME}({version}) - {project.name}:" \
293
                f"{app_doc_data.activeDrawing.name if app_doc_data.activeDrawing else ''}"
294
        #title = f"{App.NAME} : ID2 " \
295
        #        f"{app_doc_data.activeDrawing.name if app_doc_data.activeDrawing else ''}"
296

    
297
        return title
298

    
299
    @property
300
    def scene(self):
301
        """getter scene"""
302
        return self._scene
303

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

    
316
        return QWidget.eventFilter(self, source, event)
317

    
318
    def closeEvent(self, event):
319
        """save geometry and state and ask user to save drawing which is modified"""
320

    
321
        self.settings.setValue('geometry', self.saveGeometry())
322
        self.settings.setValue('windowState', self.saveState())
323
        # TODO: need to modify
324

    
325
        """save current view region"""
326
        app_doc_data = AppDocData.instance()
327
        if app_doc_data.activeDrawing:
328
            rect = self.graphicsView.viewport().rect()
329
            app_doc_data.activeDrawing.view_rect = self.graphicsView.mapToScene(rect).boundingRect()
330
            app_doc_data.update_view_region(app_doc_data.activeDrawing)
331
        """up to here"""
332

    
333
        # self.save_drawing_if_necessary()
334
        AppDocData.instance().clear()
335
        event.accept()
336

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

    
355
                self.tabWidget_2.setTabText(self.tabWidget_2.indexOf(self.tabInconsistency),
356
                                            self.tr('Inconsistency') + f"({self.tableWidgetInconsistency.rowCount()})")
357
        except Exception as ex:
358
            message = 'error occurred({}) in {}:{}'.format(ex, sys.exc_info()[-1].tb_frame.f_code.co_filename,
359
                                                           sys.exc_info()[-1].tb_lineno)
360
            self.addMessage.emit(MessageType.Error, message)
361
        # finally:
362
        #    return QTableView.keyPressEvent(self.tableWidgetInconsistency, event)
363

    
364
    def onValidation(self):
365
        """validation check"""
366
        from ValidationDialog import QValidationDialog
367
        from ValidateCommand import ValidateCommand
368

    
369
        if not self.graphicsView.hasImage():
370
            self.showImageSelectionMessageBox()
371
            return
372

    
373
        try:
374
            dlg = QValidationDialog(self)
375
            if QDialog.Accepted == dlg.exec_():
376
                # remove error items
377
                for item in self.graphicsView.scene().items():
378
                    if type(item) is QEngineeringErrorItem:
379
                        item.transfer.onRemoved.emit(item)
380
                # up to here
381

    
382
                self.progress_bar.setMaximum(len(self.graphicsView.scene().items()))
383
                self.progress_bar.setValue(0)
384

    
385
                cmd = ValidateCommand(self.graphicsView)
386
                cmd.show_progress.connect(self.progress_bar.setValue)
387
                errors = cmd.execute(self.graphicsView.scene().items())
388
                for error in errors:
389
                    error.transfer.onRemoved.connect(self.itemRemoved)
390
                    #self.graphicsView.scene().addItem(error)
391
                    error.addSvgItemToScene(self.graphicsView.scene())
392

    
393
                self.tableWidgetInconsistency.clearContents()
394
                self.tableWidgetInconsistency.setRowCount(len(errors))
395
                for index, error in enumerate(errors):
396
                    self.makeInconsistencyTableRow(index, error)
397

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

    
411
    def makeInconsistencyTableRow(self, row, errorItem):
412
        '''
413
            @brief  make row data for inconsistency widget
414
            @author euisung
415
            @date   2019.04.16
416
        '''
417

    
418
        item = QTableWidgetItem(str(errorItem.parent))
419
        item.tag = errorItem
420
        self.tableWidgetInconsistency.setItem(row, 0, item)
421

    
422
        item = QTableWidgetItem(str(type(errorItem.parent)))
423
        item.tag = errorItem
424
        self.tableWidgetInconsistency.setItem(row, 1, item)
425

    
426
        item = QTableWidgetItem(errorItem.msg)
427
        item.tag = errorItem
428
        self.tableWidgetInconsistency.setItem(row, 2, item)
429

    
430
    def inconsistencyItemClickEvent(self, item):
431
        """
432
        @brief  inconsistency table item clicked
433
        @author euisung
434
        @date   2019.04.02
435
        """
436
        from HighlightCommand import HighlightCommand
437

    
438
        HighlightCommand(self.graphicsView).execute(item.tag)
439

    
440
    def read_settings(self):
441
        """read geometry and state"""
442
        from App import App
443

    
444
        try:
445
            self.settings = QSettings(App.COMPANY, App.NAME)
446
            self.restoreGeometry(self.settings.value("geometry", ""))
447
            self.restoreState(self.settings.value("windowState", ""))
448
        except Exception as ex:
449
            message = f"error occurred({repr(ex)}) in {sys.exc_info()[-1].tb_frame.f_code.co_filename}:" \
450
                      f"{sys.exc_info()[-1].tb_lineno}"
451

    
452
    def load_stylesheet(self, file):
453
        """load stylesheets"""
454

    
455
        QtWidgets.qApp.loadStyleSheet(os.path.join(os.path.dirname(os.path.realpath(__file__)), file))
456

    
457
        app_doc_data = AppDocData.instance()
458
        configs = [Config('app', 'stylesheet', file)]
459
        app_doc_data.saveAppConfigs(configs)
460

    
461
    def load_language(self, file):
462
        """load language file and then apply selected language"""
463
        try:
464
            qm_file = os.path.join(os.path.dirname(os.path.realpath(__file__)), 'translate', '{0}.qm'.format(file))
465
            QtWidgets.qApp.load_language(qm_file)
466

    
467
            app_doc_data = AppDocData.instance()
468
            configs = [Config('app', 'language', file)]
469
            app_doc_data.saveAppConfigs(configs)
470
        finally:
471
            self.retranslateUi(self)
472

    
473
    def refresh_item_list(self):
474
        """refresh item tree"""
475
        self.itemTreeWidget.InitLineNoItems()
476

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

    
493

    
494
    def load_drawing_list(self, reverse=False):
495
        """load p&id drawing list"""
496
        from Drawing import Drawing
497

    
498
        try:
499
            app_doc_data = AppDocData.instance()
500
            drawings = app_doc_data.getDrawings()
501

    
502
            self.treeWidgetDrawingList.clear()
503
            self.treeWidgetDrawingList.root = QTreeWidgetItem(self.treeWidgetDrawingList,
504
                                                              [self.tr('P&ID Drawings'), ''])
505
            self.treeWidgetDrawingList.root.setFlags(
506
                self.treeWidgetDrawingList.root.flags() | Qt.ItemIsTristate | Qt.ItemIsUserCheckable)
507
            self.treeWidgetDrawingList.root.setCheckState(0, Qt.Unchecked)
508
            files = app_doc_data.getDrawingFileList()
509

    
510
            # self.progress_bar.setMaximum(len(files))
511
            count = 0
512
            # self.progress_bar.setValue(count)
513
            self.drawing_reverse = reverse
514
            for file in files if not self.drawing_reverse else reversed(files):
515
                x = [drawing for drawing in drawings if drawing.name == file]
516
                if not x or not x[0].UID:
517
                    drawing = Drawing(None, file, None)
518
                    drawings.append(drawing)
519
                else:
520
                    drawing = x[0]
521

    
522
                item = QTreeWidgetItem(self.treeWidgetDrawingList.root, [file, drawing.datetime])
523
                item.setIcon(0, QIcon(':newPrefix/image.png'))
524
                item.setFlags(item.flags() | Qt.ItemIsUserCheckable)
525
                item.setCheckState(0, Qt.Unchecked)
526
                item.setData(Qt.UserRole, 0, drawing)
527

    
528
                count += 1
529
                # self.progress_bar.setValue(count)
530
                # QApplication.processEvents()
531

    
532
            self.treeWidgetDrawingList.root.setText(0, self.tr('P&ID Drawings') +
533
                                                    f"({self.treeWidgetDrawingList.root.childCount()})")
534
            self.treeWidgetDrawingList.expandItem(self.treeWidgetDrawingList.root)
535
            #self.treeWidgetDrawingList.root.sortChildren(0, Qt.AscendingOrder)
536
            self.treeWidgetDrawingList.resizeColumnToContents(0)
537

    
538
            app_doc_data.saveDrawings(drawings)
539
        except Exception as ex:
540
            message = 'error occurred({}) in {}:{}'.format(repr(ex), sys.exc_info()[-1].tb_frame.f_code.co_filename,
541
                                                           sys.exc_info()[-1].tb_lineno)
542
            self.addMessage.emit(MessageType.Error, message)
543
        finally:
544
            self.progress_bar.setValue(self.progress_bar.maximum())
545

    
546
    def open_selected_drawing(self, item, column):
547
        """open selected p&id drawing"""
548

    
549
        app_doc_data = AppDocData.instance()
550
        drawing = item.data(Qt.UserRole, 0)
551
        if drawing:
552
            # uncheck all drawing tree item
553
            drawing_top = self.treeWidgetDrawingList.topLevelItem(0)
554
            count = drawing_top.childCount()
555
            for idx in range(count):
556
                child = drawing_top.child(idx)
557
                child.setCheckState(column, Qt.Unchecked)
558
            # up to here
559

    
560
            drawing.image = None
561
            self.open_image_drawing(drawing)
562
            item.setCheckState(column, Qt.Checked)
563

    
564
    def show_detect_symbol_dialog(self):
565
        from DetectSymbolDialog import QDetectSymbolDialog
566

    
567
        dlg = QDetectSymbolDialog(self)
568
        dlg.exec_()
569

    
570
    '''
571
        @brief      OCR Editor
572
        @author     euisung
573
        @date       2018.10.05
574
        @history    2018.10.16 euisung      no more used, Integrated with oCRTrainingClicked
575
    '''
576

    
577
    def oCRTrainingEdidorClicked(self):
578
        from TrainingEditorDialog import QTrainingEditorDialog
579

    
580
        try:
581
            dialog = QTrainingEditorDialog(self)
582
            dialog.exec_()
583
        except Exception as ex:
584
            message = 'error occurred({}) in {}:{}'.format(ex, sys.exc_info()[-1].tb_frame.f_code.co_filename,
585
                                                           sys.exc_info()[-1].tb_lineno)
586
            self.addMessage.emit(MessageType.Error, message)
587

    
588
        return
589

    
590
    '''
591
        @brief      OCR Training
592
        @author     euisung
593
        @date       2018.09.27
594
        @history    euisung 2018.10.16 TrainingListDialog -> TrainingImageListDialog
595
    '''
596

    
597
    def oCRTrainingClicked(self):
598
        try:
599
            dialog = QTrainingImageListDialog(self)
600
            dialog.exec_()
601
        except Exception as ex:
602
            message = 'error occurred({}) in {}:{}'.format(ex, sys.exc_info()[-1].tb_frame.f_code.co_filename,
603
                                                           sys.exc_info()[-1].tb_lineno)
604
            self.addMessage.emit(MessageType.Error, message)
605

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

    
616
    def findReplaceTextClicked(self):
617
        """pop up find and replace dialog"""
618
        if not self.graphicsView.hasImage():
619
            self.showImageSelectionMessageBox()
620
            return
621

    
622
        from TextItemEditDialog import QTextItemEditDialog
623

    
624
        dlgTextItemEdit = QTextItemEditDialog(self)
625
        dlgTextItemEdit.show()
626
        dlgTextItemEdit.exec_()
627

    
628
    def on_validation_global_clicked(self):
629
        """ global validation dialog """
630
        from ValidationGlobalDialog import QValidationGlobalDialog
631

    
632
        dlg = QValidationGlobalDialog(self)
633
        dlg.show()
634
        dlg.exec_()
635

    
636
    def replaceInsertSymbolClicked(self):
637
        """pop up replace and insert dialog"""
638
        if not self.graphicsView.hasImage():
639
            self.showImageSelectionMessageBox()
640
            return
641

    
642
        from ReplaceSymbolDialog import QReplaceSymbolDialog
643

    
644
        dlg = QReplaceSymbolDialog(self)
645
        dlg.show()
646
        dlg.exec_()
647

    
648
    def on_connect_line_to_symbol(self):
649
        """connect line to symbol"""
650
        from LineDetector import LineDetector
651
        from RecognitionDialog import Worker
652

    
653
        if not self.graphicsView.hasImage():
654
            self.showImageSelectionMessageBox()
655
            return
656

    
657
        app_doc_data = AppDocData.instance()
658
        #configs = app_doc_data.getConfigs('Project', 'Operation')
659
        configs = app_doc_data.getConfigs('Line Detector', 'Length to connect line')
660
        toler = int(configs[0].value) if configs else 20
661
        detector = LineDetector(app_doc_data.imgSrc)
662

    
663
        lines = [item for item in self.graphicsView.scene().items() if type(item) is QEngineeringLineItem if item.length() > 50]
664
        lines_short = [item for item in self.graphicsView.scene().items() if type(item) is QEngineeringLineItem if item.length() <= 50]
665
        unknowns = [item for item in self.graphicsView.scene().items() if type(item) is QEngineeringUnknownItem]
666
        symbols = [item for item in self.graphicsView.scene().items() if issubclass(type(item), SymbolSvgItem)]
667

    
668
        for item in lines_short + unknowns:
669
            item.transfer.onRemoved.emit(item)
670
        
671
        if lines:
672
            new_lines = []
673
            try:
674
                conns = []
675
                for sym in symbols:
676
                    if sym.conn_type:
677
                        for index in range(len(sym.conn_type)):
678
                            if sym.conn_type[index] == 'Secondary' or sym.conn_type[index] == 'Primary':
679
                                item = sym.connectors[index].connectedItem
680
                                if item is None:
681
                                    conns.append(sym.connectors[index])
682
                
683
                new_lines.extend(Worker.make_short_lines_sts(conns, None))
684

    
685
                conns = []
686
                for sym in symbols:
687
                    if sym.conn_type:
688
                        for index in range(len(sym.conn_type)):
689
                            if sym.conn_type[index] == 'Secondary' or sym.conn_type[index] == 'Primary':
690
                                item = sym.connectors[index].connectedItem
691
                                if item is None and sym.connectors[index]:
692
                                    conns.append(sym.connectors[index])
693
                
694
                new_lines.extend(Worker.make_short_lines_stl(lines, conns, None))
695

    
696
                for line in new_lines:
697
                    self.graphicsView.scene().addItem(line)
698
                    for conn in line.connectors:
699
                        conn.transfer.onPosChanged.connect(line.onConnectorPosChaned)
700
            except Exception as ex:
701
                message = f"error occurred({repr(ex)}) in {sys.exc_info()[-1].tb_frame.f_code.co_filename}:" \
702
                          f"{sys.exc_info()[-1].tb_lineno}"
703
                self.addMessage.emit(MessageType.Error, message)
704
                
705
            # connect line to symbol
706
            try:
707
                for line in lines:
708
                    matches = [_symbol for _symbol in symbols if _symbol.is_connectable(line, toler=toler)]
709
                    for _symbol in matches:
710
                        detector.connectLineToSymbol(line, _symbol, toler=toler)
711
            except Exception as ex:
712
                message = f"error occurred({repr(ex)}) in {sys.exc_info()[-1].tb_frame.f_code.co_filename}:" \
713
                          f"{sys.exc_info()[-1].tb_lineno}"
714
                self.addMessage.emit(MessageType.Error, message)
715
            # up to here
716

    
717
            # connect line to line
718
            try:
719
                for line in lines:
720
                    matches = [it for it in lines if (it is not line) and (not line.isParallel(it))]
721

    
722
                    for match in matches:
723
                        detector.connectLineToLine(match, line, toler)
724
            except Exception as ex:
725
                message = f"error occurred({repr(ex)}) in {sys.exc_info()[-1].tb_frame.f_code.co_filename}:" \
726
                          f"{sys.exc_info()[-1].tb_lineno}"
727
                self.addMessage.emit(MessageType.Error, message)
728
            # up to here
729

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

    
732
    def on_recognize_line(self):
733
        """recognize lines in selected area"""
734
        from RecognizeLineCommand import RecognizeLineCommand
735

    
736
        if not self.graphicsView.hasImage():
737
            self.actionOCR.setChecked(False)
738
            self.showImageSelectionMessageBox()
739
            return
740

    
741
        cmd = RecognizeLineCommand(self.graphicsView)
742
        cmd.onSuccess.connect(self.on_success_to_recognize_line)
743
        cmd.onRejected.connect(self.onCommandRejected)
744
        self.graphicsView.command = cmd
745

    
746
    '''
747
            @brief      show text recognition dialog
748
            @author     humkyung
749
            @date       2018.08.08
750
    '''
751

    
752
    def on_success_to_recognize_line(self, x, y, width, height):
753
        import io
754
        from LineDetector import LineDetector
755
        from EngineeringGraphicsLineItem import QEngineeringGraphicsLineItem
756

    
757
        try:
758
            image = self.graphicsView.image().copy(x, y, width, height)
759
            buffer = QBuffer()
760
            buffer.open(QBuffer.ReadWrite)
761
            image.save(buffer, "PNG")
762
            pyImage = Image.open(io.BytesIO(buffer.data()))
763
            img = np.array(pyImage)
764
            img = cv2.cvtColor(img, cv2.COLOR_BGR2GRAY)
765

    
766
            detector = LineDetector(img)
767
            lines = detector.detect_line_without_symbol()
768
            for line in lines:
769
                vertices = [[line[0][0] + x, line[0][1] + y], [line[1][0] + x, line[1][1] + y]]
770
                line_item = QEngineeringGraphicsLineItem(vertices)
771
                self.graphicsView.scene().addItem(line_item)
772

    
773
        except Exception as ex:
774
            message = 'error occurred({}) in {}:{}'.format(repr(ex), sys.exc_info()[-1].tb_frame.f_code.co_filename,
775
                                                           sys.exc_info()[-1].tb_lineno)
776
            self.addMessage.emit(MessageType.Error, message)
777

    
778
    def display_number_of_items(self):
779
        """display count of symbol, line, text"""
780

    
781
        items = [item for item in self.graphicsView.scene().items() if type(item) is QEngineeringUnknownItem]
782
        if len(items) > 0:
783
            self.labelStatus.setText(
784
                "<font color='red'>" + self.tr('Unrecognition') + " : {}</font>".format(len(items)))
785
        else:
786
            self.labelStatus.setText(
787
                "<font color='black'>" + self.tr('Unrecognition') + " : {}</font>".format(len(items)))
788

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

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

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

    
799
        self.itemTreeWidget.sceneChanged(self.graphicsView.scene().items())
800

    
801
    def dbUpdate(self):
802
        """ no more used """
803
        """db update when save or recognition"""
804

    
805
        try:
806
            appDocData = AppDocData.instance()
807
            items = appDocData.allItems
808

    
809
            '''
810
            titleBlockProps = appDocData.getTitleBlockProperties()
811
            titleBlockItems = []
812
            for item in items:
813
                # if type(item) is QEngineeringLineNoTextItem:
814
                #    item.saveLineData()
815
                if type(item) is QEngineeringTextItem:
816
                    for titleBlockProp in titleBlockProps:
817
                        if item.area == titleBlockProp[0]:
818
                            titleBlockItems.append(item)
819
            '''
820

    
821
            # unknown item is not saved now for performance
822
            db_items = [item for item in items if issubclass(type(item), QEngineeringAbstractItem) and
823
                        type(item) is not QGraphicsBoundingBoxItem and
824
                        type(item) is not QEngineeringErrorItem and
825
                        type(item) is not QEngineeringLineNoTextItem and
826
                        type(item) is not QEngineeringUnknownItem]
827
            db_items.extend([item for item in items if type(item) is QEngineeringLineNoTextItem])
828
            db_items.extend([line for line in appDocData.tracerLineNos if type(line) is QEngineeringTrimLineNoTextItem])
829
            # db_items.extend(titleBlockItems)
830
            configs = appDocData.getConfigs('Data Save', 'Unknown Xml Only')
831
            if configs and int(configs[0].value) is -1:
832
                db_items.extend([item for item in items if type(item) is QEngineeringUnknownItem])
833

    
834
            '''
835
            dbItems = [item for item in items if
836
                       type(item) is QEngineeringInstrumentItem or type(item) is QEngineeringEquipmentItem or type(
837
                           item) is QEngineeringReducerItem or \
838
                       type(item) is QEngineeringNoteItem or type(item) is SymbolSvgItem or type(
839
                           item) is QEngineeringLineNoTextItem or type(
840
                           item) is QEngineeringVendorItem] + titleBlockItems
841
            '''
842
            appDocData.saveToDatabase(db_items)
843
        except Exception as ex:
844
            message = 'error occurred({}) in {}:{}'.format(ex, sys.exc_info()[-1].tb_frame.f_code.co_filename,
845
                                                           sys.exc_info()[-1].tb_lineno)
846
            self.addMessage.emit(MessageType.Error, message)
847

    
848
    def save_drawing_if_necessary(self):
849
        """ask to user to save drawing or not when drawing is modified"""
850

    
851
        app_doc_data = AppDocData.instance()
852
        if app_doc_data.activeDrawing and app_doc_data.activeDrawing.modified:
853
            #if QMessageBox.Yes == QMessageBox.question(self, self.tr("Question"),
854
            #                                           self.tr("Do you want to save drawing?"),
855
            #                                           QMessageBox.Yes | QMessageBox.No):
856
            #    self.actionSaveCliked()
857
            #    return True
858
            if QMessageBox.Ignore == QMessageBox.question(self, self.tr('Continue?'),
859
                                                       self.tr('Changes may not have been saved.'),
860
                                                       QMessageBox.Ignore | QMessageBox.Cancel):
861
                return False
862
            return True
863

    
864
    def actionSaveCliked(self):
865
        """save current drawing"""
866
        from EngineeringAbstractItem import QEngineeringAbstractItem
867
        from SaveWorkCommand import SaveWorkCommand
868

    
869
        try:
870
            if not self.actionSave.isEnabled():
871
                return
872
            self.actionSave.setEnabled(False)
873

    
874
            # save alarm
875
            self.save_alarm_enable(False)
876

    
877
            app_doc_data = AppDocData.instance()
878
            if app_doc_data.imgName is None:
879
                self.showImageSelectionMessageBox()
880
                return
881

    
882
            app_doc_data.clearItemList(False)
883

    
884
            items = self.graphicsView.scene().items()
885

    
886
            self._save_work_cmd = SaveWorkCommand(self.graphicsView.scene())
887
            self._save_work_cmd.show_progress.connect(self.progress_bar.setValue)
888
            self._save_work_cmd.display_message.connect(self.onAddMessage)
889
            self._save_work_cmd.finished.connect(self.save_finished)
890

    
891
            self._save_work_cmd.start()
892
        except Exception as ex:
893
            message = f"error occurred({repr(ex)}) in {sys.exc_info()[-1].tb_frame.f_code.co_filename}:" \
894
                      f"{sys.exc_info()[-1].tb_lineno}"
895
            self.addMessage.emit(MessageType.Error, message)
896

    
897
    def save_finished(self):
898
        """reload drawing list"""
899

    
900
        self._save_work_cmd.show_progress.emit(100)
901
        QMessageBox.about(self.graphicsView, self.tr('Information'), self._save_work_cmd.resultStr)
902
        self.load_drawing_list()
903

    
904
        app_doc_data = AppDocData.instance()
905
        app_doc_data.activeDrawing.modified = False
906
        title = self.windowTitle()
907
        self.setWindowTitle(title[:-1] if title[-1] == '*' else title)
908

    
909
        self.actionSave.setEnabled(True)
910
        
911
        # save alarm
912
        self.save_alarm_enable(True)
913

    
914
    '''
915
        @brief      refresh resultPropertyTableWidget
916
        @author     kyouho
917
        @date       2018.07.19
918
    '''
919

    
920
    def refreshResultPropertyTableWidget(self):
921
        items = self.graphicsView.scene().selectedItems()
922
        if len(items) == 1:
923
            self.resultPropertyTableWidget.show_item_property(items[0])
924

    
925
    '''
926
        @brief  add message listwidget
927
        @author humkyung
928
        @date   2018.07.31
929
    '''
930

    
931
    def onAddMessage(self, messageType, message):
932
        from AppDocData import MessageType
933

    
934
        try:
935
            current = QDateTime.currentDateTime()
936

    
937
            item = QListWidgetItem('{}: {}'.format(current.toString('hh:mm:ss'), message))
938
            item.setFlags(item.flags() | Qt.ItemIsEditable)
939
            if messageType == MessageType.Error:
940
                item.setBackground(Qt.red)
941
            elif messageType == 'check':
942
                item.setBackground(Qt.yellow)
943

    
944
            self.listWidgetLog.insertItem(0, item)
945
        except Exception as ex:
946
            print('error occurred({}) in {}:{}'.format(ex, sys.exc_info()[-1].tb_frame.f_code.co_filename,
947
                                                       sys.exc_info()[-1].tb_lineno))
948

    
949
    def on_clear_log(self):
950
        """clear log"""
951
        self.listWidgetLog.clear()
952

    
953
    def onRotate(self, action):
954
        """rotate a selected symbol"""
955
        selected = [item for item in self.graphicsView.scene().selectedItems() if issubclass(type(item), SymbolSvgItem)]
956
        if len(selected) == 1:
957
            from RotateCommand import RotateCommand
958
            self.graphicsView.scene()._undo_stack.push(RotateCommand(self.graphicsView.scene(), selected))
959

    
960
    def onAreaZoom(self):
961
        """Area Zoom"""
962
        visualization_pane = self.ribbon.get_pane('Home Visualization')
963

    
964
        self.update_action_group(visualization_pane.ui.toolButtonZoom)
965
        if visualization_pane.ui.toolButtonZoom.isChecked():
966
            cmd = AreaZoomCommand.AreaZoomCommand(self.graphicsView)
967
            cmd.onRejected.connect(self.onCommandRejected)
968
            self.graphicsView.command = cmd
969

    
970
    def onVendor(self, action):
971
        """make vendor/equipment package area"""
972

    
973
        pane = self.ribbon.get_pane('Home')
974
        if not self.graphicsView.hasImage():
975
            pane.ui.toolButtonVendor.setChecked(False)
976
            self.showImageSelectionMessageBox()
977
            return
978

    
979
        pane = self.ribbon.get_pane('Home')
980
        self.update_action_group(pane.ui.toolButtonVendor)
981
        checked = pane.ui.toolButtonVendor.isChecked()
982
        if not hasattr(pane.ui.toolButtonVendor, 'tag'):
983
            pane.ui.toolButtonVendor.tag = PlacePolygonCommand.PlacePolygonCommand(self.graphicsView)
984
            pane.ui.toolButtonVendor.tag.onSuccess.connect(self.onVendorCreated)
985
            pane.ui.toolButtonVendor.tag.onRejected.connect(self.onCommandRejected)
986

    
987
        self.graphicsView.command = pane.ui.toolButtonVendor.tag
988

    
989
    def onVendorCreated(self):
990
        """add created vendor polygon area to scene"""
991

    
992
        try:
993
            vendor_tool = self.ribbon.get_pane('Home').ui.toolButtonVendor
994
            package_combo = self.ribbon.get_pane('Home').ui.comboBoxPackage
995
            count = len(vendor_tool.tag._polyline._vertices)
996
            if count > 2:
997
                points = []
998
                for point in vendor_tool.tag._polyline._vertices:
999
                    points.append(QPoint(round(point[0]), round(point[1])))
1000
                polygon = QPolygonF(points)
1001
                item = QEngineeringVendorItem(polygon, pack_type=package_combo.currentText())
1002
                item.area = 'Drawing'
1003
                item.transfer.onRemoved.connect(self.itemRemoved)
1004
                self.graphicsView.scene().addItem(item)
1005
        finally:
1006
            self.graphicsView.scene().removeItem(vendor_tool.tag._polyline)
1007
            vendor_tool.tag.reset()
1008

    
1009
    def fitWindow(self, view_rect: QRectF = QRectF()):
1010
        """Fit Window"""
1011
        self.graphicsView.useDefaultCommand()
1012
        self.graphicsView.zoomImageInit()
1013

    
1014
        visualization_pane = self.ribbon.get_pane('Home Visualization')
1015
        self.update_action_group(visualization_pane.ui.toolButtonFitWindow)
1016
        if view_rect:
1017
            self.graphicsView.zoom_rect(view_rect)
1018

    
1019
    def on_toggle_lock_axis(self):
1020
        """toggle lock axis"""
1021
        from EngineeringPolylineItem import QEngineeringPolylineItem
1022

    
1023
        visualization_pane = self.ribbon.get_pane('Home Visualization')
1024
        if self.sender() is not visualization_pane.ui.toolButtonLockAxis:
1025
            checked = visualization_pane.ui.toolButtonLockAxis.isChecked()
1026
            visualization_pane.ui.toolButtonLockAxis.setChecked(not checked)
1027

    
1028
        checked = visualization_pane.ui.toolButtonLockAxis.isChecked()
1029
        QEngineeringPolylineItem.DRAWING_MODE = QEngineeringPolylineItem.AXIS_MODE if checked else \
1030
            QEngineeringPolylineItem.FREE_MODE
1031

    
1032
    def scene_changed(self):
1033
        """update modified flag"""
1034

    
1035
        self.display_number_of_items()
1036

    
1037
        app_doc_data = AppDocData.instance()
1038
        app_doc_data.activeDrawing.modified = True
1039
        title = self.windowTitle()
1040
        self.setWindowTitle(title if title[-1] == '*' else title + '*')
1041

    
1042
    def onConvertPDFToImage(self):
1043
        """convert to selected pdf to image"""
1044
        import os
1045

    
1046
        try:
1047
            file_path = os.path.join(os.path.dirname(os.path.realpath(__file__)), 'bin64', 'PDF_TO_IMAGE.exe')
1048
            os.startfile(file_path)
1049
        except Exception as ex:
1050
            message = 'error occurred({}) in {}:{}'.format(ex, sys.exc_info()[-1].tb_frame.f_code.co_filename,
1051
                                                           sys.exc_info()[-1].tb_lineno)
1052
            self.addMessage.emit(MessageType.Error, message)
1053

    
1054
    def on_import_text_from_cad_for_instrument(self):
1055
        """ import text from cad for instrument """
1056
        try:
1057
            self.onCommandRejected()
1058
            dialog = QImportTextFromPDFDialog(self)
1059
            dialog.show()
1060
            dialog.exec_()
1061
        except Exception as ex:
1062
            message = f"error occurred({repr(ex)}) in {sys.exc_info()[-1].tb_frame.f_code.co_filename}:" \
1063
                      f"{sys.exc_info()[-1].tb_lineno}"
1064
            self.addMessage.emit(MessageType.Error, message)
1065

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

    
1078
    def onSymbolThickness(self):
1079
        """ symbol thickness reinforcement by using configuration filter drawing dilate size """
1080
        try:
1081
            self.onCommandRejected()
1082
            dialog = QSymbolThicknessDialog(self)
1083
            dialog.exec_()
1084
        except Exception as ex:
1085
            message = 'error occurred({}) in {}:{}'.format(ex, sys.exc_info()[-1].tb_frame.f_code.co_filename,
1086
                                                           sys.exc_info()[-1].tb_lineno)
1087
            self.addMessage.emit(MessageType.Error, message)
1088

    
1089
    def on_help(self):
1090
        """ open help file """
1091
        import os
1092

    
1093
        try:
1094
            help_file_path = os.path.join(os.path.dirname(os.path.realpath(__file__)), 'ID2 User Manual.pdf')
1095
            if os.path.exists(help_file_path):
1096
                os.startfile(f"\"{help_file_path}\"")
1097
            else:
1098
                QMessageBox.warning(self, self.tr('Warning'), self.tr('There is no help file'))
1099
        except Exception as ex:
1100
            message = f"error occurred({repr(ex)}) in {sys.exc_info()[-1].tb_frame.f_code.co_filename}:" \
1101
                      f"{sys.exc_info()[-1].tb_lineno}"
1102
            self.addMessage.emit(MessageType.Error, message)
1103

    
1104
    def on_readme(self):
1105
        """open readme.html"""
1106

    
1107
        file_path = os.path.join(os.path.dirname(os.path.realpath(__file__)), 'readme.html')
1108
        if os.path.exists(file_path):
1109
            os.startfile(f"\"{file_path}\"")
1110
        else:
1111
            QMessageBox.warning(self, self.tr('Warning'), self.tr('There is no readme file'))
1112

    
1113
    def onSelectionChanged(self):
1114
        """selection changed"""
1115
        items = [item for item in self.graphicsView.scene().selectedItems() if issubclass(type(item), SymbolSvgItem) or
1116
                 type(item) is QEngineeringLineItem or issubclass(type(item), QEngineeringTextItem) or
1117
                 type(item) is QEngineeringUnknownItem or type(item) is QEngineeringVendorItem]
1118
        if items:
1119
            lineNos = [item for item in items if type(item) is QEngineeringLineNoTextItem]
1120
            item = items[-1] if not lineNos else lineNos[0]
1121
            self.itemTreeWidget.findItem(item)
1122
            self.resultPropertyTableWidget.show_item_property(item)
1123
            if type(item) is QEngineeringErrorItem:
1124
                for index in range(self.tableWidgetInconsistency.rowCount()):
1125
                    if self.tableWidgetInconsistency.item(index, 1).tag is item:
1126
                        self.tableWidgetInconsistency.selectRow(index)
1127
                        break
1128
            if issubclass(type(item), SymbolSvgItem):
1129
                pass
1130
                #self.symbolTreeWidget.select_symbol(item)
1131
        else:
1132
            self.resultPropertyTableWidget.show_item_property(None)
1133

    
1134
    '''
1135
        @brief      Initialize scene and itemTreeWidget
1136
        @author     Jeongwoo
1137
        @date       2018.06.14
1138
        @history    humkyung 2018.08.16 ask to delete recognized items before remove
1139
    '''
1140

    
1141
    def on_initialize_scene(self, action):
1142
        if not self.graphicsView.hasImage():
1143
            self.showImageSelectionMessageBox()
1144

    
1145
            return
1146

    
1147
        try:
1148
            msg = QMessageBox()
1149
            msg.setIcon(QMessageBox.Critical)
1150
            msg.setText(self.tr('Do you want to remove all items?\nThis work cannot be recovered.'))
1151
            msg.setWindowTitle(self.tr("Initialize"))
1152
            msg.setStandardButtons(QMessageBox.Ok | QMessageBox.Cancel)
1153
            if QMessageBox.Ok == msg.exec_():
1154
                app_doc_data = AppDocData.instance()
1155
                app_doc_data.clearItemList(True)
1156

    
1157
                scene = self.graphicsView.scene()
1158
                pixmap = self.graphicsView.getPixmapHandle()
1159
                scene.removeItem(pixmap)    # disconnect pixmap from scene
1160
                scene.clear()               # remove all items from scene and then delete them
1161
                scene.addItem(pixmap)       # add pixmap
1162

    
1163
                if self.path is not None:
1164
                    baseName = os.path.basename(self.path)
1165
                    self.itemTreeWidget.setCurrentPID(baseName)
1166

    
1167
        except Exception as ex:
1168
            message = 'error occurred({}) in {}:{}'.format(ex, sys.exc_info()[-1].tb_frame.f_code.co_filename,
1169
                                                           sys.exc_info()[-1].tb_lineno)
1170
            self.addMessage.emit(MessageType.Error, message)
1171

    
1172
    def checked_action(self):
1173
        """return checked action"""
1174
        home_file_pane = self.ribbon.get_pane('Home File')
1175
        home_pane = self.ribbon.get_pane('Home')
1176
        visualization_pane = self.ribbon.get_pane('Home Visualization')
1177
        actions = [home_pane.ui.toolButtonRecognition, home_pane.ui.toolButtonLinkAttribute,
1178
                   home_pane.ui.toolButtonLine, home_pane.ui.toolButtonOCR, visualization_pane.ui.toolButtonZoom,
1179
                   visualization_pane.ui.toolButtonFitWindow, home_pane.ui.toolButtonVendor]
1180

    
1181
        checked = [ui_ for ui_ in actions if ui_.isChecked()]
1182
        return checked[0] if checked else None
1183

    
1184
    def update_action_group(self, ui):
1185
        """Manage Checkable Action statement"""
1186
        home_file_pane = self.ribbon.get_pane('Home File')
1187
        home_pane = self.ribbon.get_pane('Home')
1188
        visualization_pane = self.ribbon.get_pane('Home Visualization')
1189
        actions = [home_pane.ui.toolButtonRecognition, home_pane.ui.toolButtonLinkAttribute, home_pane.ui.toolButtonLine,
1190
                   home_pane.ui.toolButtonOCR, visualization_pane.ui.toolButtonZoom,
1191
                   visualization_pane.ui.toolButtonFitWindow, home_file_pane.ui.toolButtonFileSave,
1192
                   home_pane.ui.toolButtonValidate, home_pane.ui.toolButtonVendor]
1193

    
1194
        if hasattr(ui, 'tag'):
1195
            ui.tag.onRejected.emit(None)
1196

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

    
1200
        for ui_ in actions:
1201
            ui_.setChecked(False)
1202

    
1203
        ui.setChecked(True)
1204

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

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

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

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

    
1241
    def onAreaOcr(self):
1242
        """Area OCR"""
1243
        if not self.graphicsView.hasImage():
1244
            self.actionOCR.setChecked(False)
1245
            self.showImageSelectionMessageBox()
1246
            return
1247

    
1248
        pane = self.ribbon.get_pane('Home')
1249
        ui = pane.ui.toolButtonOCR
1250
        self.update_action_group(ui=ui)
1251
        checked = ui.isChecked()
1252
        if checked:
1253
            cmd = AreaOcrCommand.AreaOcrCommand(self.graphicsView)
1254
            cmd.onSuccess.connect(self.onRecognizeText)
1255
            cmd.onRejected.connect(self.onCommandRejected)
1256
            self.graphicsView.command = cmd
1257
        else:
1258
            self.graphicsView.useDefaultCommand()
1259

    
1260
    def onRecognizeText(self, x, y, width, height):
1261
        """show text recognition dialog"""
1262
        from OcrResultDialog import QOcrResultDialog
1263
        from Area import Area
1264

    
1265
        try:
1266
            app_doc_data = AppDocData.instance()
1267

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

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

    
1304
    '''
1305
        @brief  area configuration
1306
    '''
1307

    
1308
    def areaConfiguration(self):
1309
        from ConfigurationAreaDialog import QConfigurationAreaDialog
1310
        if not self.graphicsView.hasImage():
1311
            self.showImageSelectionMessageBox()
1312
            return
1313
        self.onCommandRejected()
1314
        dlgConfigurationArea = QConfigurationAreaDialog(self)
1315
        dlgConfigurationArea.show()
1316
        dlgConfigurationArea.exec_()
1317

    
1318
    '''
1319
        @brief  configuration
1320
    '''
1321

    
1322
    def configuration(self):
1323
        from ConfigurationDialog import QConfigurationDialog
1324

    
1325
        dlgConfiguration = QConfigurationDialog(self)
1326
        if QDialog.Accepted == dlgConfiguration.exec_():
1327
            QEngineeringLineItem.LINE_TYPE_COLORS.clear()
1328
            QEngineeringInstrumentItem.INST_COLOR = None
1329

    
1330
    '''
1331
        @brief  show special item types dialog 
1332
        @author humkyung
1333
        @date   2019.08.10
1334
    '''
1335

    
1336
    def on_show_special_item_types(self):
1337
        from SpecialItemTypesDialog import QSpecialItemTypesDialog
1338

    
1339
        dlg = QSpecialItemTypesDialog(self)
1340
        dlg.exec_()
1341

    
1342
    def on_show_data_transfer(self):
1343
        """ show data transfer dialog """
1344
        from DataTransferDialog import QDataTransferDialog
1345

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

    
1349
    def on_show_data_export(self):
1350
        """ show data export dialog """
1351
        from DataExportDialog import QDataExportDialog
1352

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

    
1356
    def on_show_eqp_datasheet_export(self):
1357
        """ show eqp datasheet export dialog """
1358
        from EqpDatasheetExportDialog import QEqpDatasheetExportDialog
1359

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

    
1363
    def on_show_opc_relation(self):
1364
        """ show opc relation dialog """
1365
        from OPCRelationDialog import QOPCRelationDialog
1366

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

    
1370
    '''
1371
        @brief  show nominal diameter dialog 
1372
        @author humkyung
1373
        @date   2018.06.28
1374
    '''
1375

    
1376
    def onShowCodeTable(self):
1377
        from CodeTableDialog import QCodeTableDialog
1378

    
1379
        dlg = QCodeTableDialog(self)
1380
        dlg.show()
1381
        dlg.exec_()
1382
        if dlg.code_area:
1383
            if dlg.code_area.scene():
1384
                self.graphicsView.scene().removeItem(dlg.code_area)
1385
        if dlg.desc_area:
1386
            if dlg.desc_area.scene():
1387
                self.graphicsView.scene().removeItem(dlg.desc_area)
1388
        self.graphicsView.useDefaultCommand()
1389

    
1390
    def onShowCustomCodeTable(self):
1391
        from CustomCodeTablesDialog import CustomCodeTablesDialog
1392

    
1393
        dlg = CustomCodeTablesDialog(self)
1394
        dlg.show()
1395
        dlg.exec_()
1396
        self.graphicsView.useDefaultCommand()
1397

    
1398
    def onShowReplaceCodeTable(self):
1399
        from CustomCodeTablesDialog import CustomCodeTablesDialog
1400

    
1401
        dlg = CustomCodeTablesDialog(self, replace=True)
1402
        dlg.show()
1403
        dlg.exec_()
1404
        self.graphicsView.useDefaultCommand()
1405

    
1406
    def on_streamline(self):
1407
        """pop up stream line dialog"""
1408
        from StreamlineDialog import QStreamlineDialog
1409

    
1410
        if not self.graphicsView.hasImage():
1411
            self.showImageSelectionMessageBox()
1412
            return
1413

    
1414
        dlg = QStreamlineDialog(self)
1415
        dlg.show()
1416

    
1417
    def onHMBData(self):
1418
        """show HMB data"""
1419
        from HMBDialog import QHMBDialog
1420

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

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

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

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

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

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

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

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

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

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

    
1473
        self.symbolTreeWidget.expandAll()
1474

    
1475
    def display_colors(self, value):
1476
        """ display colors """
1477
        from DisplayColors import DisplayColors
1478
        from DisplayColors import DisplayOptions
1479

    
1480
        if hasattr(self, 'ribbon'):
1481
            visualization_pane = self.ribbon.get_pane('Home Visualization')
1482
            if self.sender() is visualization_pane.ui.radioButtonByGroup and value is True:
1483
                DisplayColors.instance().option = DisplayOptions.DisplayByLineNo
1484
            elif self.sender() is visualization_pane.ui.radioButtonByType and value is True:
1485
                DisplayColors.instance().option = DisplayOptions.DisplayByLineType
1486
            elif self.sender() is visualization_pane.ui.radioButtonByStreamNo:
1487
                DisplayColors.instance().option = DisplayOptions.DisplayByStreamNo
1488

    
1489
            if hasattr(self, 'graphicsView') and value is True:
1490
                self.graphicsView.scene().update(self.graphicsView.sceneRect())
1491
                DisplayColors.instance().save_data()
1492

    
1493
    def open_image_drawing(self, drawing, force=False):
1494
        """open and display image drawing file"""
1495
        from Drawing import Drawing
1496
        from App import App
1497
        from LoadCommand import LoadCommand
1498
        import concurrent.futures as futures
1499

    
1500
        # Yield successive n-sized
1501
        # chunks from l.
1502
        def divide_chunks(l, n):
1503
            # looping till length l
1504
            for i in range(0, len(l), n):
1505
                yield l[i:i + n]
1506

    
1507
        def update_items(items):
1508
            for item in items:
1509
                # binding items
1510
                item.owner
1511
                for connector in item.connectors:
1512
                    connector.connectedItem
1513

    
1514
            return items
1515

    
1516
        try:
1517
            app_doc_data = AppDocData.instance()
1518

    
1519
            if not self.actionSave.isEnabled():
1520
                return
1521

    
1522
            if not force and self.save_drawing_if_necessary():
1523
                return
1524

    
1525
            occupied = app_doc_data.set_occupying_drawing(drawing.UID)
1526
            if occupied:
1527
                QMessageBox.about(self.graphicsView, self.tr("Notice"),
1528
                                  self.tr(f"The drawing is locked for editing by another user({occupied})"))
1529
                return
1530

    
1531
            # save alarm
1532
            self.save_alarm_enable(False)
1533

    
1534
            if hasattr(self, '_save_work_cmd'):
1535
                self._save_work_cmd.wait()
1536

    
1537
            project = app_doc_data.getCurrentProject()
1538

    
1539
            self.path = self.graphicsView.loadImageFromFile(drawing)
1540
            if os.path.isfile(self.path):
1541
                self.onCommandRejected()
1542
                app_doc_data.clear(past=drawing.UID)
1543

    
1544
                # load color for stream no coloring
1545
                hmbs = app_doc_data.get_hmb_data(None)
1546
                colors = {}
1547
                if hmbs:
1548
                    for hmb in hmbs:
1549
                        rgb = app_doc_data.colors
1550
                        colors[hmb.stream_no] = QColor(rgb.red, rgb.green, rgb.blue).name()
1551
                    app_doc_data._hmbColors = colors
1552
                # up to here
1553

    
1554
                app_doc_data.setImgFilePath(self.path)
1555
                app_doc_data.activeDrawing = drawing
1556
                
1557
                #app_doc_data.activeDrawing.set_pid_source(Image.open(self.path))
1558
                self.itemTreeWidget.setCurrentPID(app_doc_data.activeDrawing.name)
1559

    
1560
                drawingList = self.treeWidgetDrawingList.topLevelItem(0)
1561
                for idx in range(drawingList.childCount()):
1562
                    child = drawingList.child(idx)
1563
                    if child.data(Qt.UserRole, 0) is drawing:
1564
                        child.setCheckState(0, Qt.Checked)
1565
                    else:
1566
                        child.setCheckState(0, Qt.Unchecked)
1567

    
1568
                try:
1569
                    self.show_Progress_bar()
1570

    
1571
                    # disconnect scene changed if signal is connected
1572
                    if self.graphicsView.scene().receivers(self.graphicsView.scene().contents_changed) > 0:
1573
                        self.graphicsView.scene().contents_changed.disconnect()
1574

    
1575
                    SymbolSvgItem.DOCUMENTS.clear()
1576

    
1577
                    # load data
1578
                    cmd = LoadCommand()
1579
                    cmd.display_message.connect(self.onAddMessage)
1580
                    cmd.set_maximum.connect(self.progress.setMaximum)
1581
                    cmd.show_progress.connect(self.progress.setValue)
1582
                    cmd.execute((drawing, self.graphicsView.scene()),
1583
                                symbol=True, text=True, line=True, unknown=True, package=True, update=True)
1584

    
1585
                    app_doc_data._streamLineListModelDatas = app_doc_data.get_stream_line_list_data()
1586
                    # up to here
1587

    
1588
                    """"update item tree widget"""
1589
                    line_no_items = [item for item in self.graphicsView.scene().items()
1590
                                     if type(item) is QEngineeringLineNoTextItem]
1591
                    for line_no in line_no_items:
1592
                        line_no_tree_item = self.itemTreeWidget.addTreeItem(self.itemTreeWidget.root, line_no)
1593
                        for run in line_no.runs:
1594
                            for run_item in run.items:
1595
                                if issubclass(type(run_item), SymbolSvgItem):
1596
                                    self.init_add_tree_item(line_no_tree_item, run_item)
1597

    
1598
                    line_no_items = [item for item in self.graphicsView.scene().items()
1599
                                     if type(item) is QEngineeringTrimLineNoTextItem]
1600
                    for line_no in line_no_items:
1601
                        line_no_tree_item = self.itemTreeWidget.addTreeItem(self.itemTreeWidget.root, line_no)
1602
                        for run in line_no.runs:
1603
                            for run_item in run.items:
1604
                                if issubclass(type(run_item), SymbolSvgItem):
1605
                                    self.init_add_tree_item(line_no_tree_item, run_item)
1606

    
1607
                    for trim_line_no in app_doc_data.tracerLineNos:
1608
                        line_no_tree_item = self.itemTreeWidget.addTreeItem(self.itemTreeWidget.root, trim_line_no)
1609
                        for run in trim_line_no.runs:
1610
                            for run_item in run.items:
1611
                                if issubclass(type(run_item), SymbolSvgItem):
1612
                                    self.init_add_tree_item(line_no_tree_item, run_item)
1613

    
1614
                    self.itemTreeWidget.update_item_count()
1615
                    self.itemTreeWidget.expandAll()
1616
                    """up to here"""
1617

    
1618
                    """update scene"""
1619
                    for item in self._scene.items():
1620
                        item.setVisible(True)
1621

    
1622
                    self._scene.update(self._scene.sceneRect())
1623

    
1624
                    """
1625
                    # old open drawing
1626
                    path = os.path.join(app_doc_data.getCurrentProject().getTempPath(), app_doc_data.imgName + '.xml')
1627
                    configs = app_doc_data.getConfigs('Data Load', 'Xml First')
1628
                    if configs and int(configs[0].value) >= 1 and os.path.isfile(path):
1629
                        self.load_recognition_result_from_xml(drawing)
1630
                    elif configs and int(configs[0].value) <= 1:
1631
                        self.load_drawing(app_doc_data.activeDrawing)
1632
                    """
1633

    
1634
                    self.display_number_of_items()
1635
                    # connect scene changed signal
1636
                    self.graphicsView.scene().contents_changed.connect(self.scene_changed)
1637
                finally:
1638
                    if hasattr(self, 'progress'):
1639
                        self.progress.setValue(self.progress.maximum())
1640

    
1641
                self.changeViewCheckedState(True)
1642
                self.setWindowTitle(self.title)
1643
                self.fitWindow(drawing.view_rect)
1644

    
1645
                # save alarm
1646
                self.save_alarm_enable(True, True)
1647
        except Exception as ex:
1648
            message = f"error occurred({repr(ex)}) in {sys.exc_info()[-1].tb_frame.f_code.co_filename}:" \
1649
                      f"{sys.exc_info()[-1].tb_lineno}"
1650
            self.addMessage.emit(MessageType.Error, message)
1651

    
1652
        return self.path
1653

    
1654
    def save_alarm_enable(self, enable, init=False):
1655
        from datetime import datetime
1656

    
1657
        try:
1658
            app_doc_data = AppDocData.instance()
1659
            configs = app_doc_data.getConfigs('Data Save', 'Time')
1660
            time_min = int(configs[0].value) if 1 == len(configs) else 0
1661

    
1662
            if enable and time_min > 0:
1663
                if not self.save_timer:
1664
                    self.save_timer = QTimer()
1665
                    self.save_timer.timeout.connect(self.save_alarm)
1666
                    self.save_timer.setInterval(60000)
1667

    
1668
                if init:
1669
                    self.save_timer._init_time = datetime.now()
1670
                    self.save_timer._stop_time = None
1671
                    self.save_timer._interval_time = datetime.now() - datetime.now()
1672

    
1673
                if self.save_timer._stop_time:
1674
                    self.save_timer._interval_time = datetime.now() - self.save_timer._stop_time
1675
                
1676
                #if 60000 * time_min != self.save_timer.interval():
1677
                #    self.save_timer.setInterval(60000)
1678

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

    
1690
    def save_alarm(self):
1691
        from datetime import datetime
1692

    
1693
        app_doc_data = AppDocData.instance()
1694
        configs = app_doc_data.getConfigs('Data Save', 'Time')
1695
        time_min = int(configs[0].value) if 1 == len(configs) else 0
1696

    
1697
        self.save_timer.stop()
1698
        if self.graphicsView.hasFocus() and (datetime.now() - self.save_timer._init_time - self.save_timer._interval_time).seconds > time_min * 60:
1699
            QMessageBox.information(self, self.tr('Information'), self.tr('Please save Drawing'))
1700
            self.save_timer._init_time = datetime.now()
1701
            self.save_timer._interval_time = datetime.now() - datetime.now()
1702
        self.save_timer.start()
1703

    
1704
    def export_as_svg(self):
1705
        """export scene to svg file"""
1706
        from ExportCommand import ExportCommand
1707

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

    
1720
    def export_as_xml(self):
1721
        pass
1722

    
1723
    def export_as_image(self):
1724
        """export scene to image file"""
1725
        from ExportCommand import ExportCommand
1726

    
1727
        options = QFileDialog.Options()
1728
        options |= QFileDialog.DontUseNativeDialog
1729
        file_path, _ = QFileDialog.getSaveFileName(self, "Export as png", os.getcwd(), "png file(*.png)",
1730
                                                   options=options)
1731
        if file_path:
1732
            try:
1733
                # hide image drawing
1734
                self.onViewImageDrawing(False)
1735

    
1736
                cmd = ExportCommand(self.graphicsView.scene(), 'image')
1737
                cmd.display_message.connect(self.onAddMessage)
1738

    
1739
                if cmd.execute(file_path):
1740
                    QMessageBox.information(self, self.tr('Information'), self.tr('Successfully export to image file'))
1741
                else:
1742
                    QMessageBox.information(self, self.tr('Error'), self.tr('Fail to export to image file'))
1743
            finally:
1744
                if self.actionImage_Drawing.isChecked():
1745
                    self.onViewImageDrawing(True)
1746
                    self.actionImage_Drawing.setChecked(True)
1747

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

    
1761
    def changeViewCheckedState(self, checked, clear=True):
1762
        """change view checked state"""
1763
        # self.actionImage_Drawing.setChecked(checked)
1764
        self.actionViewText.setChecked(checked)
1765
        self.actionViewSymbol.setChecked(checked)
1766
        self.actionViewLine.setChecked(checked)
1767
        self.actionViewUnknown.setChecked(checked)
1768
        self.actionViewInconsistency.setChecked(checked)
1769
        self.actionViewVendor_Area.setChecked(not checked)
1770
        self.actionDrawing_Only.setChecked(not checked)
1771
        if clear:
1772
            self.tableWidgetInconsistency.clearContents()
1773
            self.tableWidgetInconsistency.setRowCount(0)
1774

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

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

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

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

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

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

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

    
1828
    '''
1829
        @brief  visible/invisible Unknown 
1830
        @author humkyung
1831
        @date   2018.06.28
1832
    '''
1833

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

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

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

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

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

    
1875
            mask = np.ones((int(rect.height()), int(rect.width())), dtype=np.uint8) * 255
1876
            cv2.fillPoly(mask, [poly], (0))
1877
            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())])
1878
            sym_img = cv2.merge((sym_img, sym_img, sym_img))
1879

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

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

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

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

    
1916
                        package_item.transfer.onRemoved.emit(package_item)
1917
        finally:
1918
            self.onCommandRejected()
1919
            QApplication.restoreOverrideCursor()
1920
            QApplication.restoreOverrideCursor()
1921

    
1922
    def on_line_list(self):
1923
        """ line list export dialog """
1924
        from LineListDialog import LineListDialog
1925

    
1926
        if not self.graphicsView.hasImage():
1927
            self.showImageSelectionMessageBox()
1928
            return
1929

    
1930
        dialog = LineListDialog(self)
1931
        dialog.showDialog()
1932

    
1933
    def on_make_label_data(self):
1934
        """ make label data from symbol info """
1935
        from xml.etree.ElementTree import Element, SubElement, dump, ElementTree, parse
1936

    
1937
        if not self.graphicsView.hasImage():
1938
            self.showImageSelectionMessageBox()
1939
            return
1940

    
1941
        app_doc_data = AppDocData.instance()
1942
        project = app_doc_data.getCurrentProject()
1943

    
1944
        smalls = []
1945
        bigs = []
1946

    
1947
        symbol_list = app_doc_data.getTargetSymbolList(all=True)
1948
        #symbol_list = app_doc_data.getTargetSymbolList(all=False)
1949
        for symbol in symbol_list:
1950
            if symbol.iType == 38 or symbol.iType == 33 or symbol.iType == 0 or symbol.iType == 40:
1951
                continue
1952
            elif symbol.width and symbol.height:
1953
                if symbol.width > 300 or symbol.height > 300:
1954
                    bigs.append(symbol.getName())
1955
                elif (symbol.width * symbol.height < 1500) or (symbol.width > 450 or symbol.height > 450):
1956
                    continue
1957
                else:
1958
                    smalls.append(symbol.getName())
1959

    
1960
        symbols = [item for item in self.graphicsView.scene().items() if issubclass(type(item), SymbolSvgItem)]
1961
        names = [smalls, bigs]
1962

    
1963
        img = app_doc_data.activeDrawing.image_origin
1964

    
1965
        small_size = 500
1966
        big_size = 850
1967

    
1968
        save_path = project.getTrainingSymbolFilePath()
1969

    
1970
        index = 0
1971
        for size in [small_size, big_size]:
1972
            offsets = [0, int(size / 2)]
1973

    
1974
            width, height = img.shape[1], img.shape[0]
1975
            width_count, height_count = width // size + 2, height // size + 2
1976
            b_width, b_height = width_count * size, height_count * size
1977
            b_img = np.zeros((b_height, b_width), np.uint8) + 255
1978
            b_img[:height, :width] = img[:, :]
1979

    
1980
            for offset in offsets:
1981
                for row in range(height_count):
1982
                    for col in range(width_count):
1983
                        x, y = col * size + offset, row * size + offset
1984
                        tile_rect = QRectF(x, y, size, size)
1985
                        tile_symbols = []
1986
                        for symbol in [symbol for symbol in symbols if symbol.name in names[index]]:
1987
                            if tile_rect.contains(symbol.sceneBoundingRect()):
1988
                                tile_symbols.append(symbol)
1989
                                symbols.remove(symbol)
1990

    
1991
                        if tile_symbols:
1992
                            training_uid = str(uuid.uuid4())
1993
                            training_image_path = os.path.join(save_path, training_uid + '.png')
1994
                            training_xml_path = os.path.join(save_path, training_uid + '.xml')
1995

    
1996
                            # save image
1997
                            #_img = b_img[round(tile_rect.top()):round(tile_rect.bottom()),
1998
                            #       round(tile_rect.left()):round(tile_rect.right())]
1999
                            #cv2.imwrite(training_image_path, _img)
2000
                            _img = self.graphicsView.image().copy(round(tile_rect.left()), round(tile_rect.top()), round(tile_rect.width()), round(tile_rect.height()))
2001
                            _img.save(training_image_path)
2002

    
2003
                            # save label
2004
                            xml = Element('annotation')
2005
                            SubElement(xml, 'folder').text = 'None'
2006
                            SubElement(xml, 'filename').text = os.path.basename(save_path)
2007

    
2008
                            pathNode = Element('path')
2009
                            pathNode.text = save_path.replace('/', '\\')
2010
                            xml.append(pathNode)
2011

    
2012
                            sourceNode = Element('source')
2013
                            databaseNode = Element('database')
2014
                            databaseNode.text = 'Unknown'
2015
                            sourceNode.append(databaseNode)
2016
                            xml.append(sourceNode)
2017

    
2018
                            sizeNode = Element('size')
2019
                            widthNode = Element('width')
2020
                            widthNode.text = str(int(tile_rect.width()))
2021
                            sizeNode.append(widthNode)
2022
                            heightNode = Element('height')
2023
                            heightNode.text = str(int(tile_rect.height()))
2024
                            sizeNode.append(heightNode)
2025
                            depthNode = Element('depth')
2026
                            depthNode.text = '3'
2027
                            sizeNode.append(depthNode)
2028
                            xml.append(sizeNode)
2029

    
2030
                            segmentedNode = Element('segmented')
2031
                            segmentedNode.text = '0'
2032
                            xml.append(segmentedNode)
2033

    
2034
                            labelContent = []
2035
                            counts = {}
2036
                            for item in tile_symbols:
2037
                                rect = item.sceneBoundingRect()
2038
                                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)
2039
                                #label = 'small' if index == 0 else 'big' # for single class test
2040
                                xMin = xMin if xMin > 0 else 0
2041
                                yMin = yMin if yMin > 0 else 0
2042
                                xMax = xMax if xMax < size else size
2043
                                yMax = yMax if yMax < size else size
2044

    
2045
                                if label == 'None' or label == '':
2046
                                    continue
2047
                                if label not in labelContent:
2048
                                    labelContent.append(label)
2049
                                    counts[label] = 1
2050
                                else:
2051
                                    counts[label] = counts[label] + 1
2052

    
2053
                                objectNode = Element('object')
2054
                                nameNode = Element('name')
2055
                                nameNode.text = label
2056
                                objectNode.append(nameNode)
2057
                                poseNode = Element('pose')
2058
                                poseNode.text = 'Unspecified'
2059
                                objectNode.append(poseNode)
2060
                                truncatedNode = Element('truncated')
2061
                                truncatedNode.text = '0'
2062
                                objectNode.append(truncatedNode)
2063
                                difficultNode = Element('difficult')
2064
                                difficultNode.text = '0'
2065
                                objectNode.append(difficultNode)
2066

    
2067
                                bndboxNode = Element('bndbox')
2068
                                xminNode = Element('xmin')
2069
                                xminNode.text = str(xMin)
2070
                                bndboxNode.append(xminNode)
2071
                                yminNode = Element('ymin')
2072
                                yminNode.text = str(yMin)
2073
                                bndboxNode.append(yminNode)
2074
                                xmaxNode = Element('xmax')
2075
                                xmaxNode.text = str(xMax)
2076
                                bndboxNode.append(xmaxNode)
2077
                                ymaxNode = Element('ymax')
2078
                                ymaxNode.text = str(yMax)
2079
                                bndboxNode.append(ymaxNode)
2080
                                objectNode.append(bndboxNode)
2081

    
2082
                                xml.append(objectNode)
2083

    
2084
                            ElementTree(xml).write(training_xml_path)
2085

    
2086
            index += 1
2087

    
2088
        QMessageBox.about(self, self.tr("Notice"), self.tr('Successfully applied. '))
2089

    
2090
    def onPlaceLine(self):
2091
        """create a line"""
2092
        home_pane = self.ribbon.get_pane('Home')
2093

    
2094
        if not self.graphicsView.hasImage():
2095
            home_pane.ui.toolButtonLine.setChecked(False)
2096
            self.showImageSelectionMessageBox()
2097
            return
2098

    
2099
        self.update_action_group(home_pane.ui.toolButtonLine)
2100
        if not hasattr(home_pane.ui.toolButtonLine, 'tag'):
2101
            home_pane.ui.toolButtonLine.tag = PlaceLineCommand.PlaceLineCommand(self.graphicsView)
2102
            home_pane.ui.toolButtonLine.tag.onSuccess.connect(self.onLineCreated)
2103
            home_pane.ui.toolButtonLine.tag.onRejected.connect(self.onCommandRejected)
2104

    
2105
        self.graphicsView.command = home_pane.ui.toolButtonLine.tag
2106

    
2107
    def onLineCreated(self):
2108
        """add created lines to scene"""
2109
        from EngineeringConnectorItem import QEngineeringConnectorItem
2110
        from LineDetector import LineDetector
2111

    
2112
        try:
2113
            app_doc_data = AppDocData.instance()
2114
            home_pane = self.ribbon.get_pane('Home')
2115

    
2116
            count = len(home_pane.ui.toolButtonLine.tag._polyline._vertices)
2117
            if count > 1:
2118
                items = []
2119

    
2120
                detector = LineDetector(None)
2121

    
2122
                if not home_pane.ui.toolButtonLine.tag.line_type:
2123
                    line_type = home_pane.ui.comboBoxLineType.currentText()
2124
                else:
2125
                    pane = self.ribbon.get_pane('Home')
2126
                    selected_line_type = pane.ui.comboBoxLineType.currentText()
2127
                    if selected_line_type == 'Connect To Process':
2128
                        line_type = selected_line_type
2129
                    elif not (QEngineeringLineItem.check_piping(home_pane.ui.toolButtonLine.tag.line_type) ^
2130
                              QEngineeringLineItem.check_piping(selected_line_type)):
2131
                        line_type = selected_line_type
2132
                    else:
2133
                        line_type = home_pane.ui.toolButtonLine.tag.line_type
2134
                for index in range(count - 1):
2135
                    start = home_pane.ui.toolButtonLine.tag._polyline._vertices[index]
2136
                    end = home_pane.ui.toolButtonLine.tag._polyline._vertices[index + 1]
2137

    
2138
                    lineItem = QEngineeringLineItem(vertices=[start, end])
2139
                    lineItem.transfer.onRemoved.connect(self.itemRemoved)
2140
                    lineItem.lineType = line_type
2141
                    if items:
2142
                        lineItem.connect_if_possible(items[-1], 5)
2143
                    else:
2144
                        pt = lineItem.start_point()
2145
                        selected = [item for item in self.graphicsView.scene().items(QPointF(pt[0], pt[1])) if
2146
                                    type(item) is QEngineeringConnectorItem or type(item) is QEngineeringLineItem]
2147
                        if selected and selected[0] is not lineItem:
2148
                            if type(selected[0]) is QEngineeringConnectorItem:
2149
                                lineItem.connect_if_possible(selected[0].parent, 5)
2150
                            else:
2151
                                detector.connectLineToLine(selected[0], lineItem, 5)
2152

    
2153
                    items.append(lineItem)
2154
                    self.graphicsView.scene().addItem(lineItem)
2155

    
2156
                pt = items[-1].end_point()
2157
                selected = [item for item in self.graphicsView.scene().items(QPointF(pt[0], pt[1])) if
2158
                            (type(item) is QEngineeringConnectorItem and item.parentItem() is not items[-1]) or
2159
                            (type(item) is QEngineeringLineItem and item is not items[-1])]
2160
                if selected and selected[0] is not items[-1]:
2161
                    if type(selected[0]) is QEngineeringConnectorItem:
2162
                        items[-1].connect_if_possible(selected[0].parent, 5)
2163
                    else:
2164
                        detector.connectLineToLine(selected[0], items[-1], 5)
2165

    
2166
                self._scene.undo_stack.push(CreateCommand(self._scene, items))
2167
        finally:
2168
            self.graphicsView.scene().removeItem(home_pane.ui.toolButtonLine.tag._polyline)
2169
            home_pane.ui.toolButtonLine.tag.reset()
2170

    
2171
    def onCommandRejected(self, cmd=None):
2172
        """command is rejected"""
2173
        try:
2174
            home_pane = self.ribbon.get_pane('Home')
2175
            visualization_pane = self.ribbon.get_pane('Home Visualization')
2176
            if type(cmd) is PlaceLineCommand.PlaceLineCommand:
2177
                if home_pane.ui.toolButtonLine.tag._polyline:
2178
                    self.graphicsView.scene().removeItem(home_pane.ui.toolButtonLine.tag._polyline)
2179
                self.graphicsView.scene().update()
2180
                home_pane.ui.toolButtonLine.tag.reset()
2181

    
2182
                home_pane.ui.toolButtonLine.setChecked(False)
2183
            elif type(cmd) is AreaZoomCommand.AreaZoomCommand:
2184
                visualization_pane.ui.toolButtonZoom.setChecked(False)
2185
            elif type(cmd) is AreaOcrCommand.AreaOcrCommand:
2186
                home_pane.ui.toolButtonOCR.setChecked(False)
2187
            elif type(cmd) is PlacePolygonCommand.PlacePolygonCommand:
2188
                home_pane.ui.toolButtonVendor.setChecked(False)
2189
            else:
2190
                if hasattr(home_pane.ui.toolButtonVendor, 'tag') and home_pane.ui.toolButtonVendor.tag._polyline:
2191
                    self.graphicsView.scene().removeItem(home_pane.ui.toolButtonVendor.tag._polyline)
2192
                    self.graphicsView.scene().update()
2193
                    home_pane.ui.toolButtonVendor.tag.reset()
2194
                home_pane.ui.toolButtonLine.setChecked(False)
2195
                visualization_pane.ui.toolButtonZoom.setChecked(False)
2196
                home_pane.ui.toolButtonOCR.setChecked(False)
2197
                home_pane.ui.toolButtonVendor.setChecked(False)
2198
        finally:
2199
            self.graphicsView.useDefaultCommand()
2200

    
2201
    def on_view_toggle(self, key: int) -> None:
2202
        """view toggled"""
2203

    
2204
        view_pane = self.ribbon.get_pane('View')
2205
        if key == Qt.Key_1:
2206
            checked = view_pane.ui.toolButtonViewImageDrawing.isChecked()
2207
            self.onViewImageDrawing(not checked)
2208
            view_pane.ui.toolButtonViewImageDrawing.setChecked(not checked)
2209
        elif key == Qt.Key_2:
2210
            checked = view_pane.ui.toolButtonViewText.isChecked()
2211
            self.onViewText(not checked)
2212
            view_pane.ui.toolButtonViewText.setChecked(not checked)
2213
        elif key == Qt.Key_3:
2214
            checked = view_pane.ui.toolButtonViewSymbol.isChecked()
2215
            self.onViewSymbol(not checked)
2216
            view_pane.ui.toolButtonViewSymbol.setChecked(not checked)
2217
        elif key == Qt.Key_4:
2218
            checked = view_pane.ui.toolButtonViewLine.isChecked()
2219
            self.onViewLine(not checked)
2220
            view_pane.ui.toolButtonViewLine.setChecked(not checked)
2221
        elif key == Qt.Key_5:
2222
            checked = view_pane.ui.toolButtonViewUnknown.isChecked()
2223
            self.onViewUnknown(not checked)
2224
            view_pane.ui.toolButtonViewUnknown.setChecked(not checked)
2225
        elif key == Qt.Key_6:
2226
            checked = view_pane.ui.toolButtonViewInconsistency.isChecked()
2227
            self.onViewInconsistency(not checked)
2228
            view_pane.ui.toolButtonViewInconsistency.setChecked(not checked)
2229
        elif key == Qt.Key_7:
2230
            checked = view_pane.ui.toolButtonViewVendorArea.isChecked()
2231
            self.onViewVendorArea(not checked)
2232
            view_pane.ui.toolButtonViewVendorArea.setChecked(not checked)
2233
        elif key == 96:  # '~' key
2234
            checked = view_pane.ui.toolButtonViewDrawingOnly.isChecked()
2235
            self.onViewDrawingOnly(not checked)
2236
            view_pane.ui.toolButtonViewDrawingOnly.setChecked(not checked)
2237

    
2238
    def keyPressEvent(self, event):
2239
        """restore to default command when user press Escape key"""
2240
        try:
2241
            if event.key() == Qt.Key_Escape:
2242
                checked = self.checked_action()
2243
                if checked:
2244
                    checked.setChecked(False)
2245
                    self.graphicsView.useDefaultCommand()
2246
            elif event.key() == Qt.Key_M:  # merge text as vertical
2247
                from TextInfo import TextInfo
2248

    
2249
                textItems = [text for text in self.graphicsView.scene().selectedItems() if
2250
                             issubclass(type(text), QEngineeringTextItem)]
2251
                if not textItems or len(textItems) is 1:
2252
                    return
2253

    
2254
                angle = None
2255
                for item in textItems:
2256
                    if angle is None:
2257
                        angle = item.angle
2258
                    else:
2259
                        if angle != item.angle:
2260
                            return
2261

    
2262
                modifiers = QApplication.keyboardModifiers()
2263
                enter_or_space = ' ' if modifiers == Qt.ControlModifier else '\n'
2264
                x_or_y = 0 if (modifiers == Qt.ControlModifier and angle == 0) or (modifiers != Qt.ControlModifier and angle == 1.57) else 1
2265

    
2266
                textItems = sorted(textItems, key=lambda text: text.loc[x_or_y]) if textItems[0].angle == 0 else ( \
2267
                    sorted(textItems, key=lambda text: text.loc[x_or_y]) if textItems[0].angle == 1.57 else ( \
2268
                        sorted(textItems, key=lambda text: text.loc[x_or_y], reverse=True) if textItems[0].angle == 4.71 else \
2269
                            sorted(textItems, key=lambda text: text.loc[x_or_y], reverse=True)))
2270

    
2271
                if textItems[0].angle == 1.57 and modifiers == Qt.ControlModifier:
2272
                    textItems.reverse()
2273

    
2274
                minX = sys.maxsize
2275
                minY = sys.maxsize
2276
                maxX = 0
2277
                maxY = 0
2278
                newText = ''
2279

    
2280
                for text in textItems:
2281
                    if text.loc[0] < minX: minX = text.loc[0]
2282
                    if text.loc[1] < minY: minY = text.loc[1]
2283
                    if text.loc[0] + text.size[0] > maxX: maxX = text.loc[0] + text.size[0]
2284
                    if text.loc[1] + text.size[1] > maxY: maxY = text.loc[1] + text.size[1]
2285
                    newText = newText + text.text() + enter_or_space
2286
                    text.transfer.onRemoved.emit(text)
2287
                newText = newText[:-1]
2288

    
2289
                textInfo = TextInfo(newText, minX, minY, maxX - minX, maxY - minY, textItems[0].angle)
2290
                x = textInfo.getX()
2291
                y = textInfo.getY()
2292
                angle = textInfo.getAngle()
2293
                text = textInfo.getText()
2294
                width = textInfo.getW()
2295
                height = textInfo.getH()
2296
                item = TextItemFactory.instance().createTextItem(textInfo)
2297
                if item is not None:
2298
                    item.loc = [x, y]
2299
                    item.size = (width, height)
2300
                    item.angle = angle
2301
                    item.area = textItems[0].area
2302
                    item.setDefaultTextColor(Qt.blue)
2303
                    item.addTextItemToScene(self.graphicsView.scene())
2304
                    item.transfer.onRemoved.connect(self.itemRemoved)
2305
            elif event.key() == Qt.Key_D:
2306
                # pop up development toolkit dialog
2307
                from DevelopmentToolkitDialog import QDevelopmentToolkitDialog
2308

    
2309
                modifiers = QApplication.keyboardModifiers()
2310
                if modifiers == Qt.ControlModifier:
2311
                    dlg = QDevelopmentToolkitDialog(self, self.graphicsView)
2312
                    dlg.show()
2313
            elif event.key() == Qt.Key_I:
2314
                # insert symbol item that is selected symbol in tree to main window if symbol already selected on main window, replace
2315
                index = self.symbolTreeWidget.currentIndex()
2316
                proxy_model = self.symbolTreeWidget.model()
2317
                items = [proxy_model.sourceModel().itemFromIndex(proxy_model.mapToSource(index))]
2318
                if items and hasattr(items[0], 'svgFilePath'):
2319
                    symData = items[0].data(self.symbolTreeWidget.TREE_DATA_ROLE)
2320
                    symName = symData.getName()
2321
                else:
2322
                    return
2323

    
2324
                symbolItems = [symbol for symbol in self.graphicsView.scene().selectedItems() if
2325
                               issubclass(type(symbol), SymbolSvgItem)]
2326
                old_symbol = None
2327
                if symbolItems and len(symbolItems) is 1:
2328
                    old_symbol = symbolItems[0]
2329
                    #scenePos = QPoint(old_symbol.origin[0], old_symbol.origin[1])
2330
                    scenePos = old_symbol.mapToScene(old_symbol.transformOriginPoint())
2331
                    old_symbol.transfer.onRemoved.emit(old_symbol)
2332
                else:
2333
                    scenePos = self.current_pos
2334

    
2335
                svg = QtImageViewer.createSymbolObject(symName)
2336
                QtImageViewer.matchSymbolToLine(self.graphicsView.scene(), svg, scenePos, angle=old_symbol.angle if old_symbol else 0.0)
2337

    
2338
                if old_symbol and svg:
2339
                    from ReplaceCommand import ReplaceCommand
2340

    
2341
                    cmd = ReplaceCommand(self.graphicsView.scene(), old_symbol, svg)
2342
                    self._scene.undo_stack.push(cmd)
2343
                    return
2344
            elif event.key() == Qt.Key_J:
2345
                # insert and connect symbol item that is selected symbol in tree to selected symbol
2346
                index = self.symbolTreeWidget.currentIndex()
2347
                proxy_model = self.symbolTreeWidget.model()
2348
                items = [proxy_model.sourceModel().itemFromIndex(proxy_model.mapToSource(index))]
2349
                if items and hasattr(items[0], 'svgFilePath'):
2350
                    symData = items[0].data(self.symbolTreeWidget.TREE_DATA_ROLE)
2351
                    symName = symData.getName()
2352
                else:
2353
                    return
2354

    
2355
                symbolItems = [symbol for symbol in self.graphicsView.scene().selectedItems() if
2356
                               issubclass(type(symbol), SymbolSvgItem)]
2357
                if symbolItems and len(symbolItems) is not 1:
2358
                    return
2359
                    
2360
                target_symbol = symbolItems[0]
2361
                index =  [index for index in range(len(target_symbol.conn_type)) \
2362
                            if target_symbol.conn_type[index] == 'Primary' or target_symbol.conn_type[index] == 'Secondary']
2363
                for connector in target_symbol.connectors:
2364
                    svg = QtImageViewer.createSymbolObject(symName)
2365
                    if len(svg.connectors) > 1: 
2366
                        if ((target_symbol.conn_type and target_symbol.connectors.index(connector) in index) or not target_symbol.conn_type) and \
2367
                                    (not connector.connectedItem or (connector.connectedItem and type(connector.connectedItem) is QEngineeringLineItem)):
2368
                            QtImageViewer.matchSymbolToLine(self.graphicsView.scene(), svg, connector.sceneBoundingRect().center())
2369
                    elif len(svg.connectors) == 1:
2370
                        if ((target_symbol.conn_type and target_symbol.connectors.index(connector) in index) or not target_symbol.conn_type) and \
2371
                                    not connector.connectedItem:
2372
                            QtImageViewer.matchSymbolToLine(self.graphicsView.scene(), svg, connector.sceneBoundingRect().center())
2373

    
2374
                if target_symbol:
2375
                    return
2376
            elif event.key() == Qt.Key_X:
2377
                app_doc_data = AppDocData.instance()
2378
                configs = app_doc_data.getAppConfigs('app', 'mode')
2379
                if configs and 1 == len(configs) and 'advanced' == configs[0].value:
2380
                    advanced = True
2381
                    items = self.graphicsView.scene().selectedItems()
2382
                    if items:
2383
                        item = self.symbolTreeWidget.currentItem()
2384
                        if item:
2385
                            self.symbolTreeWidget.showSymbolEditorDialog(item, 0)
2386
            elif event.key() == Qt.Key_F6:
2387
                from DEXPI import scene_to_dexpi
2388

    
2389
                app_doc_data = AppDocData.instance()
2390
                scene_to_dexpi('D:\\Temp\\DEXPI.xml', app_doc_data.activeDrawing.name, self.graphicsView.scene())
2391

    
2392
            QMainWindow.keyPressEvent(self, event)
2393
        except Exception as ex:
2394
            message = f"error occurred({repr(ex)}) in {sys.exc_info()[-1].tb_frame.f_code.co_filename}:" \
2395
                      f"{sys.exc_info()[-1].tb_lineno}"
2396
            self.addMessage.emit(MessageType.Error, message)
2397

    
2398
    def recognize(self):
2399
        """recognize symbol, text and line for selected drawings"""
2400
        from datetime import datetime
2401
        from License import QLicenseDialog
2402

    
2403
        # save alarm
2404
        self.save_alarm_enable(False)
2405

    
2406
        app_doc_data = AppDocData.instance()
2407
        current_drawing, currentPid = None, None
2408

    
2409
        if self.graphicsView.hasImage():
2410
            current_drawing = app_doc_data.activeDrawing
2411
            currentPid = app_doc_data.activeDrawing.name
2412

    
2413
        # get checked drawings
2414
        drawing_top = self.treeWidgetDrawingList.topLevelItem(0)
2415
        count = drawing_top.childCount()
2416
        checked_drawings = {}
2417
        for idx in range(count):
2418
            child = drawing_top.child(idx)
2419
            if child.checkState(0) == Qt.Checked and child.data(Qt.UserRole, 0):
2420
                checked_drawings[child.data(Qt.UserRole, 0)] = child
2421
        # up to here
2422

    
2423
        # if there is no checked drawing
2424
        if current_drawing and currentPid and not checked_drawings:
2425
            for idx in range(count):
2426
                child = drawing_top.child(idx)
2427
                if child.data(Qt.UserRole, 0) is current_drawing:
2428
                    checked_drawings[child.data(Qt.UserRole, 0)] = child
2429

    
2430
        if not checked_drawings:
2431
            self.showImageSelectionMessageBox()
2432
            return
2433

    
2434
        try:
2435
            self.on_clear_log()
2436
            dlg = QRecognitionDialog(self, [drawing for drawing in checked_drawings.keys()])
2437
            dlg.exec_()
2438

    
2439
            if current_drawing and current_drawing in checked_drawings.keys() and dlg.isTreated:
2440
                self.open_image_drawing(current_drawing, force=True)
2441

    
2442
            # save working date-time
2443
            _now = datetime.now().strftime('%Y-%m-%d %H:%M:%S')
2444
            for drawing, tree_item in checked_drawings.items():
2445
                drawing.datetime = _now
2446
                tree_item.setText(1, _now)
2447
            #app_doc_data.saveDrawings(checked_drawings.keys())
2448
            self.changeViewCheckedState(True)
2449
            # count up for recognition
2450
            QLicenseDialog.count_up()
2451
            # up to here
2452
        except Exception as ex:
2453
            message = f"error occurred({repr(ex)}) in {sys.exc_info()[-1].tb_frame.f_code.co_filename}:" \
2454
                      f"{sys.exc_info()[-1].tb_lineno}"
2455
            self.addMessage.emit(MessageType.Error, message)
2456

    
2457
        # save alarm
2458
        self.save_alarm_enable(True)
2459

    
2460
    '''
2461
        @brief      remove item from tree widget and then remove from scene
2462
        @date       2018.05.25
2463
        @author     Jeongwoo
2464
    '''
2465

    
2466
    def itemRemoved(self, item):
2467
        try:
2468
            if type(item) is QEngineeringErrorItem:
2469
                # remove error item from inconsistency list
2470
                for row in range(self.tableWidgetInconsistency.rowCount()):
2471
                    if item is self.tableWidgetInconsistency.item(row, 0).tag:
2472
                        self.tableWidgetInconsistency.removeRow(row)
2473
                        break
2474

    
2475
                if item.scene() is not None:
2476
                    item.scene().removeItem(item)
2477
                del item
2478
            else:
2479
                remove_scene = item.scene()
2480
                self.itemTreeWidget.itemRemoved(item)
2481

    
2482
                matches = [_item for _item in remove_scene.items() if
2483
                           hasattr(_item, 'connectors') and [connector for connector in _item.connectors if
2484
                                                             connector.connectedItem is item]]
2485
                for match in matches:
2486
                    for connector in match.connectors:
2487
                        if connector.connectedItem is item:
2488
                            connector.connectedItem = None
2489
                            connector.highlight(False)
2490

    
2491
                # matches = [_item for _item in self.graphicsView.scene().items() if hasattr(_item, 'remove_assoc_item')]
2492
                # for _item in matches:
2493
                #    _item.remove_assoc_item(item)
2494

    
2495
                app_doc_data = AppDocData.instance()
2496
                if type(item) is QEngineeringLineNoTextItem and item in app_doc_data.tracerLineNos:
2497
                    app_doc_data.tracerLineNos.pop(app_doc_data.tracerLineNos.index(item))
2498

    
2499
                if type(item) is QEngineeringLineItem and item in app_doc_data.lines:
2500
                    app_doc_data.lines.remove(item)
2501

    
2502
                matches = [_item for _item in remove_scene.items() if
2503
                           type(_item) is QEngineeringLineNoTextItem]
2504
                matches.extend([lineNo for lineNo in app_doc_data.tracerLineNos if
2505
                                type(lineNo) is QEngineeringTrimLineNoTextItem])
2506
                for match in matches:
2507
                    if item is match.prop('From'):
2508
                        match.set_property('From', None)
2509
                    if item is match.prop('To'):
2510
                        match.set_property('To', None)
2511

    
2512
                    for run_index in reversed(range(len(match.runs))):
2513
                        run = match.runs[run_index]
2514
                        if item in run.items:
2515
                            index = run.items.index(item)
2516
                            run.items.pop(index)
2517
                            if not run.items:
2518
                                run.explode()
2519
                                if type(match) is QEngineeringTrimLineNoTextItem and not match.runs:
2520
                                    app_doc_data.tracerLineNos.pop(app_doc_data.tracerLineNos.index(match))
2521
                            # break
2522

    
2523
                matches = [_item for _item in remove_scene.items() if hasattr(_item, 'owner')]
2524
                for match in matches:
2525
                    if match.owner is item:
2526
                        match.owner = None
2527

    
2528
                matches = [_item for _item in remove_scene.items() if hasattr(_item, 'attrs')]
2529
                # done = False
2530
                for match in matches:
2531
                    assocs = match.associations()
2532
                    for assoc in assocs:
2533
                        if item is assoc:
2534
                            for attr in match.attrs.keys():
2535
                                if attr.AssocItem and str(item.uid) == str(attr.AssocItem.uid):
2536
                                    attr.AssocItem = None
2537
                                    match.attrs[attr] = ''
2538
                                    # done = True
2539
                            match.remove_assoc_item(item)
2540
                            break
2541
                    # if done: break
2542

    
2543
                if item.scene() is not None: item.scene().removeItem(item)
2544
        except Exception as ex:
2545
            message = 'error occurred({}) in {}:{}'.format(ex, sys.exc_info()[-1].tb_frame.f_code.co_filename,
2546
                                                           sys.exc_info()[-1].tb_lineno)
2547
            self.addMessage.emit(MessageType.Error, message)
2548
        '''
2549
        finally:
2550
            if hasattr(item, '_cond'):
2551
                item._cond.wakeAll()
2552
        '''
2553

    
2554

    
2555
    def connect_attributes(self, MainWindow):
2556
        """connect attributes to symbol"""
2557
        from LineNoTracer import LineNoTracer
2558
        from ConnectAttrDialog import QConnectAttrDialog
2559

    
2560
        if not self.graphicsView.hasImage():
2561
            self.showImageSelectionMessageBox()
2562
            return
2563

    
2564
        # save alarm
2565
        self.save_alarm_enable(False)
2566

    
2567
        try:
2568
            dlg = QConnectAttrDialog(self, self.graphicsView.scene())
2569
            dlg.setWindowFlags(self.windowFlags() & ~Qt.WindowCloseButtonHint & ~Qt.WindowContextHelpButtonHint)
2570
            dlg.exec_()
2571
            if dlg.isRunned:
2572
                self.refresh_item_list()
2573

    
2574
                if dlg.validation_checked:
2575
                    self.onValidation()
2576

    
2577
                self.graphicsView.invalidateScene()
2578
        except Exception as ex:
2579
            message = 'error occurred({}) in {}:{}'.format(ex, sys.exc_info()[-1].tb_frame.f_code.co_filename,
2580
                                                           sys.exc_info()[-1].tb_lineno)
2581
            self.addMessage.emit(MessageType.Error, message)
2582
        finally:
2583
            # save alarm
2584
            self.save_alarm_enable(True)
2585

    
2586
    def postDetectLineProcess(self):
2587
        '''
2588
            @brief  check allowables among undetected items
2589
            @author euisung
2590
            @date   2018.11.15
2591
            @history    2018.11.15  euisung    no more used, moved to TextItemFactoy isLineNo()
2592
        '''
2593
        from TextItemFactory import TextItemFactory
2594

    
2595
        appDocData = AppDocData.instance()
2596

    
2597
        tableNames = ["Fluid Code", "Insulation Purpose", "PnID Number", "Piping Materials Class", "Unit Number"]
2598
        tableDatas = []
2599
        for tableName in tableNames:
2600
            tableNameFormat = tableName.replace(' ', '').replace('&&', 'n')
2601
            tableDatas.append(appDocData.getCodeTable(tableNameFormat))
2602

    
2603
        items = self.graphicsView.scene().items()
2604
        for item in items:
2605
            if type(item) is not QEngineeringTextItem:
2606
                continue
2607
            text = item.text()
2608
            for tableData in tableDatas:
2609
                for data in tableData:
2610
                    if data[3] == '':
2611
                        continue
2612
                    else:
2613
                        allows = data[3].split(',')
2614
                        for allow in allows:
2615
                            text = text.replace(allow, data[1])
2616

    
2617
            lineItem = TextItemFactory.instance().createTextItem(text)
2618
            if type(lineItem) is QEngineeringLineNoTextItem:
2619
                lineItem.loc = item.loc
2620
                lineItem.size = item.size
2621
                lineItem.angle = item.angle
2622
                lineItem.area = item.area
2623
                # lineItem.addTextItemToScene(self.graphicsView.scene())
2624
                lineItem.transfer.onRemoved.connect(self.itemRemoved)
2625
                item.transfer.onRemoved.emit(item)
2626
                appDocData.lineNos.append(lineItem)
2627

    
2628
    def init_add_tree_item(self, line_no_tree_item, run_item):
2629
        """ insert symbol item and find line no as owner """
2630
        # insert
2631
        self.itemTreeWidget.addTreeItem(line_no_tree_item, run_item)
2632
        # find
2633
        self.itemTreeWidget.addTreeItem(line_no_tree_item, run_item)
2634

    
2635
    def load_drawing(self, drawing):
2636
        """ load drawing """
2637
        from EngineeringRunItem import QEngineeringRunItem
2638
        from QEngineeringTrimLineNoTextItem import QEngineeringTrimLineNoTextItem
2639

    
2640
        app_doc_data = AppDocData.instance()
2641
        try:
2642
            symbols = []
2643
            lines = []
2644

    
2645
            components = app_doc_data.get_components(drawing.UID)
2646
            maxValue = len(components) * 2
2647
            self.progress.setMaximum(maxValue) if maxValue > 0 else None
2648

    
2649
            """ parsing all symbols """
2650
            for symbol in [component for component in components if int(component['SymbolType_UID']) != -1]:
2651
                item = SymbolSvgItem.from_database(symbol)
2652
                if item is not None:
2653
                    item.transfer.onRemoved.connect(self.itemRemoved)
2654
                    symbols.append(item)
2655
                    app_doc_data.symbols.append(item)
2656
                    item.addSvgItemToScene(self.graphicsView.scene())
2657
                else:
2658
                    pt = [float(symbol['X']), float(symbol['Y'])]
2659
                    size = [float(symbol['Width']), float(symbol['Height'])]
2660
                    angle = float(symbol['Rotation'])
2661
                    item = QGraphicsBoundingBoxItem(pt[0], pt[1], size[0], size[1])
2662
                    item.isSymbol = True
2663
                    item.angle = angle
2664
                    item.setPen(QPen(Qt.red, 5, Qt.SolidLine))
2665
                    self.graphicsView.scene().addItem(item)
2666
                    item.transfer.onRemoved.connect(self.itemRemoved)
2667

    
2668
                self.progress.setValue(self.progress.value() + 1)
2669

    
2670
            QApplication.processEvents()
2671

    
2672
            # parse texts
2673
            for text in [component for component in components if
2674
                         component['Name'] == 'Text' and component['SymbolType_UID'] == -1]:
2675
                item = QEngineeringTextItem.from_database(text)
2676
                if item is not None:
2677
                    item.uid = text['UID']
2678
                    item.attribute = text['Value']
2679
                    name = text['Name']
2680
                    item.transfer.onRemoved.connect(self.itemRemoved)
2681
                    item.addTextItemToScene(self.graphicsView.scene())
2682

    
2683
                self.progress.setValue(self.progress.value() + 1)
2684

    
2685
            QApplication.processEvents()
2686

    
2687
            # note
2688
            for note in [component for component in components if
2689
                         component['Name'] == 'Note' and component['SymbolType_UID'] == -1]:
2690
                item = QEngineeringTextItem.from_database(note)
2691
                if item is not None:
2692
                    item.uid = note['UID']
2693
                    attributeValue = note['Value']
2694
                    name = note['Name']
2695
                    item.transfer.onRemoved.connect(self.itemRemoved)
2696
                    item.addTextItemToScene(self.graphicsView.scene())
2697

    
2698
                self.progress.setValue(self.progress.value() + 1)
2699

    
2700
            QApplication.processEvents()
2701

    
2702
            for line in [component for component in components if
2703
                         component['Name'] == 'Line' and component['SymbolType_UID'] == -1]:
2704
                item = QEngineeringLineItem.from_database(line)
2705
                if item:
2706
                    item.transfer.onRemoved.connect(self.itemRemoved)
2707
                    self.graphicsView.scene().addItem(item)
2708
                    lines.append(item)
2709

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

    
2712
            QApplication.processEvents()
2713

    
2714
            for unknown in [component for component in components if
2715
                            component['Name'] == 'Unknown' and component['SymbolType_UID'] == -1]:
2716
                item = QEngineeringUnknownItem.from_database(unknown)
2717
                item.transfer.onRemoved.connect(self.itemRemoved)
2718
                if item is not None:
2719
                    item.transfer.onRemoved.connect(self.itemRemoved)
2720
                    self.graphicsView.scene().addItem(item)
2721

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

    
2724
            QApplication.processEvents()
2725

    
2726
            for component in [component for component in components if
2727
                              component['Name'] == 'Line NO' and component['SymbolType_UID'] == -1]:
2728
                line_no = QEngineeringLineNoTextItem.from_database(component)
2729
                if type(line_no) is QEngineeringLineNoTextItem:
2730
                    line_no.transfer.onRemoved.connect(self.itemRemoved)
2731
                    self.addTextItemToScene(line_no)
2732
                    line_no_tree_item = self.itemTreeWidget.addTreeItem(self.itemTreeWidget.root, line_no)
2733

    
2734
                    runs = app_doc_data.get_pipe_runs(str(line_no.uid))
2735
                    if not runs: continue
2736
                    for run in runs:
2737
                        line_run = QEngineeringRunItem()
2738
                        run_items = app_doc_data.get_pipe_run_items(run['UID'])
2739
                        for record in run_items:
2740
                            uid = record['Components_UID']
2741
                            run_item = self.graphicsView.findItemByUid(uid)
2742
                            if run_item is not None:
2743
                                run_item._owner = line_no
2744
                                line_run.items.append(run_item)
2745
                        line_run.owner = line_no
2746
                        line_no.runs.append(line_run)
2747

    
2748
                        for run_item in line_run.items:
2749
                            if issubclass(type(run_item), SymbolSvgItem):
2750
                                self.init_add_tree_item(line_no_tree_item, run_item)
2751

    
2752
                self.progress.setValue(self.progress.value() + 1)
2753
            QApplication.processEvents()
2754

    
2755
            for component in [component for component in components if
2756
                              component['Name'] == 'Trim Line NO' and component['SymbolType_UID'] == -1]:
2757
                line_no = QEngineeringTrimLineNoTextItem()
2758
                line_no.uid = uuid.UUID(component['UID'])
2759

    
2760
                runs = app_doc_data.get_pipe_runs(str(line_no.uid))
2761
                if not runs: continue
2762

    
2763
                line_no_tree_item = self.itemTreeWidget.addTreeItem(self.itemTreeWidget.root, line_no)
2764

    
2765
                for run in runs:
2766
                    line_run = QEngineeringRunItem()
2767
                    run_items = app_doc_data.get_pipe_run_items(run['UID'])
2768
                    for record in run_items:
2769
                        uid = record['Components_UID']
2770
                        run_item = self.graphicsView.findItemByUid(uid)
2771
                        if run_item is not None:
2772
                            run_item.owner = line_no
2773
                            line_run.items.append(run_item)
2774
                    line_run.owner = line_no
2775
                    line_no.runs.append(line_run)
2776

    
2777
                    for run_item in line_run.items:
2778
                        if issubclass(type(run_item), SymbolSvgItem):
2779
                            self.init_add_tree_item(line_no_tree_item, run_item)
2780

    
2781
                app_doc_data.tracerLineNos.append(line_no)
2782

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

    
2785
            for component in [component for component in components if
2786
                              component['Name'] == 'VendorPackage' and component['SymbolType_UID'] == -1]:
2787
                item = QEngineeringVendorItem.from_database(component)
2788
                if item is not None:
2789
                    item.transfer.onRemoved.connect(self.itemRemoved)
2790
                    self.graphicsView.scene().addItem(item)
2791

    
2792
            # connect flow item to line
2793
            for line in lines:
2794
                line.update_arrow()
2795
                app_doc_data.lines.append(line)
2796
            # for flowMark in [item for item in symbols if type(item) is QEngineeringFlowMarkItem]:
2797
            #    for line in lines:
2798
            #        if flowMark.owner is line:
2799
            #            line._flowMark.append(flowMark)
2800
            #            flowMark.setParentItem(line)
2801
            # up to here
2802

    
2803
            """ update scene """
2804
            self.graphicsView.scene().update(self.graphicsView.sceneRect())
2805
            for item in self.graphicsView.scene().items():
2806
                up_progress = False
2807
                # binding items
2808
                if hasattr(item, 'owner'):
2809
                    item.owner
2810
                    up_progress = True
2811
                if hasattr(item, 'connectors'):
2812
                    for connector in item.connectors:
2813
                        connector.connectedItem
2814
                    up_progress = True
2815

    
2816
                if up_progress:
2817
                    self.progress.setValue(self.progress.value() + 1)
2818
            
2819
            for item in self.graphicsView.scene().items():
2820
                item.setVisible(True)
2821

    
2822
        except Exception as ex:
2823
            message = 'error occurred({}) in {}:{}'.format(ex, sys.exc_info()[-1].tb_frame.f_code.co_filename,
2824
                                                           sys.exc_info()[-1].tb_lineno)
2825
            self.addMessage.emit(MessageType.Error, message)
2826
        finally:
2827
            app_doc_data.clearTempDBData()
2828
            self.itemTreeWidget.update_item_count()
2829
            self.itemTreeWidget.expandAll()
2830
            # self.graphicsView.scene().blockSignals(False)
2831

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

    
2855
    def load_recognition_result_from_xml(self, drawing):
2856
        # Yield successive n-sized
2857
        # chunks from l.
2858
        def divide_chunks(l, n):
2859
            # looping till length l
2860
            for i in range(0, len(l), n):
2861
                yield l[i:i + n]
2862

    
2863
        def update_items(items):
2864
            for item in items:
2865
                # binding items
2866
                item.owner
2867
                for connector in item.connectors:
2868
                    connector.connectedItem
2869

    
2870
            return items
2871

    
2872
        import concurrent.futures as futures
2873
        from xml.etree.ElementTree import Element, SubElement, dump, ElementTree, parse
2874
        from App import App
2875
        from EngineeringRunItem import QEngineeringRunItem
2876
        from QEngineeringTrimLineNoTextItem import QEngineeringTrimLineNoTextItem
2877
        from EngineeringGraphicsLineItem import QEngineeringGraphicsLineItem
2878

    
2879
        app_doc_data = AppDocData.instance()
2880

    
2881
        try:
2882
            file_name = os.path.splitext(os.path.basename(drawing.file_path))[0]
2883
            path = os.path.join(app_doc_data.getCurrentProject().getTempPath(), file_name + '.xml')
2884
            self.graphicsView.scene().blockSignals(True)
2885

    
2886
            symbols = []
2887
            lines = []
2888

    
2889
            xml = parse(path)
2890
            root = xml.getroot()
2891

    
2892
            maxValue = 0
2893
            maxValue = maxValue + len(list(root.iter('SYMBOL'))) - \
2894
                       len(list(root.iterfind('LINENOS/LINE_NO/RUN/SYMBOL'))) - \
2895
                       len(list(root.iterfind('TRIMLINENOS/TRIM_LINE_NO/RUN/SYMBOL')))
2896
            maxValue = maxValue + len(list(root.iterfind('TEXTINFOS/ATTRIBUTE')))
2897
            maxValue = maxValue + len(list(root.iterfind('NOTES/ATTRIBUTE')))
2898
            maxValue = maxValue + len(list(root.iter('LINE_NO')))
2899
            maxValue = maxValue + len(list(root.iter('LINE'))) - \
2900
                       len(list(root.iterfind('LINENOS/LINE_NO/RUN/LINE'))) - \
2901
                       len(list(root.iterfind('TRIMLINENOS/TRIM_LINE_NO/RUN/LINE')))
2902
            maxValue = maxValue + len(list(root.iter('GRAPHICS_LINE')))
2903
            maxValue = maxValue + len(list(root.iter('UNKNOWN')))
2904
            # maxValue = maxValue + len(list(root.iter('SIZETEXT')))
2905
            maxValue = maxValue + len(list(root.iter('TRIM_LINE_NO')))
2906
            maxValue *= 2
2907
            self.progress.setMaximum(maxValue) if maxValue > 0 else None
2908

    
2909
            """ parsing all symbols """
2910
            """
2911
            with futures.ThreadPoolExecutor(max_workers=App.THREAD_MAX_WORKER) as pool:
2912
                future_symbol = {pool.submit(SymbolSvgItem.fromXml, symbol): symbol for symbol in root.find('SYMBOLS').iter('SYMBOL')}
2913

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

2937
            """
2938
            for symbol in root.find('SYMBOLS').iter('SYMBOL'):
2939
                item = SymbolSvgItem.fromXml(symbol)
2940
                if item is not None:
2941
                    item.transfer.onRemoved.connect(self.itemRemoved)
2942
                    symbols.append(item)
2943
                    #app_doc_data.symbols.append(item)
2944
                    item.addSvgItemToScene(self.graphicsView.scene())
2945
                else:
2946
                    pt = [float(x) for x in symbol.find('LOCATION').text.split(',')]
2947
                    size = [float(x) for x in symbol.find('SIZE').text.split(',')]
2948
                    angle = float(symbol.find('ANGLE').text)
2949
                    item = QGraphicsBoundingBoxItem(pt[0], pt[1], size[0], size[1])
2950
                    item.isSymbol = True
2951
                    item.angle = angle
2952
                    item.setPen(QPen(Qt.red, 5, Qt.SolidLine))
2953
                    self.graphicsView.scene().addItem(item)
2954
                    item.transfer.onRemoved.connect(self.itemRemoved)
2955

    
2956
                self.progress.setValue(self.progress.value() + 1)
2957

    
2958
            QApplication.processEvents()
2959

    
2960
            # parse texts
2961
            for text in root.find('TEXTINFOS').iter('ATTRIBUTE'):
2962
                item = QEngineeringTextItem.fromXml(text)
2963
                if item is not None:
2964
                    uid = text.find('UID')
2965
                    attributeValue = text.find('ATTRIBUTEVALUE')
2966
                    name = text.find('NAME').text
2967
                    item.transfer.onRemoved.connect(self.itemRemoved)
2968
                    item.addTextItemToScene(self.graphicsView.scene())
2969
                    # docData.texts.append(item)
2970

    
2971
                    if name == 'TEXT':
2972
                        if uid is not None and attributeValue is not None:
2973
                            item.uid = uid.text
2974
                            item.attribute = attributeValue.text
2975

    
2976
                self.progress.setValue(self.progress.value() + 1)
2977

    
2978
            QApplication.processEvents()
2979

    
2980
            # note
2981
            for text in root.find('NOTES').iter('ATTRIBUTE'):
2982
                item = QEngineeringTextItem.fromXml(text)
2983
                if item is not None:
2984
                    uid = text.find('UID')
2985
                    attributeValue = text.find('ATTRIBUTEVALUE')
2986
                    name = text.find('NAME').text
2987
                    item.transfer.onRemoved.connect(self.itemRemoved)
2988
                    item.addTextItemToScene(self.graphicsView.scene())
2989

    
2990
                    if name == 'NOTE':
2991
                        if uid is not None:
2992
                            item.uid = uid.text
2993

    
2994
                self.progress.setValue(self.progress.value() + 1)
2995

    
2996
            QApplication.processEvents()
2997

    
2998
            for line in root.find('LINEINFOS').iter('LINE'):
2999
                item = QEngineeringLineItem.fromXml(line)
3000
                if item:
3001
                    item.transfer.onRemoved.connect(self.itemRemoved)
3002
                    self.graphicsView.scene().addItem(item)
3003
                    lines.append(item)
3004

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

    
3007
            for line in root.find('LINEINFOS').iter('GRAPHICS_LINE'):
3008
                item = QEngineeringGraphicsLineItem.fromXml(line)
3009
                if item:
3010
                    item.transfer.onRemoved.connect(self.itemRemoved)
3011
                    self.graphicsView.scene().addItem(item)
3012

    
3013
                self.progress.setValue(self.progress.value() + 1)
3014

    
3015
            QApplication.processEvents()
3016

    
3017
            for unknown in root.iter('UNKNOWN'):
3018
                item = QEngineeringUnknownItem.fromXml(unknown)
3019
                if item is not None:
3020
                    item.transfer.onRemoved.connect(self.itemRemoved)
3021
                    self.graphicsView.scene().addItem(item)
3022

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

    
3025
            QApplication.processEvents()
3026

    
3027
            # """ add tree widget """
3028
            # for item in symbols:
3029
            #    docData.symbols.append(item)
3030
            #    self.addSvgItemToScene(item)
3031
            #    self.itemTreeWidget.addTreeItem(self.itemTreeWidget.root, item)
3032

    
3033
            for line_no_node in root.find('LINENOS').iter('LINE_NO'):
3034
                line_no = QEngineeringLineNoTextItem.fromXml(line_no_node)
3035
                if line_no is None: continue
3036
                line_no.transfer.onRemoved.connect(self.itemRemoved)
3037
                line_no.addTextItemToScene(self.graphicsView.scene())
3038
                line_no_tree_item = self.itemTreeWidget.addTreeItem(self.itemTreeWidget.root, line_no)
3039
                if type(line_no) is not QEngineeringLineNoTextItem: continue
3040

    
3041
                runs_node = line_no_node.findall('RUN')
3042
                if runs_node is None: continue
3043

    
3044
                for run_node in runs_node:
3045
                    line_run = QEngineeringRunItem()
3046
                    for child_node in run_node:
3047
                        uidElement = child_node.find('UID')
3048
                        if uidElement is not None:
3049
                            uid = uidElement.text
3050
                            run_item = self.graphicsView.findItemByUid(uid)
3051
                            if run_item is not None:
3052
                                run_item._owner = line_no
3053
                                line_run.items.append(run_item)
3054
                    line_run.owner = line_no
3055
                    line_no.runs.append(line_run)
3056

    
3057
                    for run_item in line_run.items:
3058
                        if issubclass(type(run_item), SymbolSvgItem):
3059
                            self.init_add_tree_item(line_no_tree_item, run_item)
3060

    
3061
                # docData.tracerLineNos.append(line_no)
3062

    
3063
                self.progress.setValue(self.progress.value() + 1)
3064
            QApplication.processEvents()
3065

    
3066
            for trimLineNo in root.iter('TRIM_LINE_NO'):
3067
                line_no = QEngineeringTrimLineNoTextItem()
3068
                line_no.uid = uuid.UUID(trimLineNo.find('UID').text)
3069

    
3070
                runs_node = trimLineNo.findall('RUN')
3071
                if runs_node is None: continue
3072
                line_no_tree_item = self.itemTreeWidget.addTreeItem(self.itemTreeWidget.root, line_no)
3073

    
3074
                for run in runs_node:
3075
                    line_run = QEngineeringRunItem()
3076
                    for child in run:
3077
                        uidElement = child.find('UID')
3078
                        if uidElement is not None:
3079
                            uid = uidElement.text
3080
                            run_item = self.graphicsView.findItemByUid(uid)
3081
                            if run_item is not None:
3082
                                run_item.owner = line_no
3083
                                line_run.items.append(run_item)
3084
                    line_run.owner = line_no
3085
                    line_no.runs.append(line_run)
3086

    
3087
                    for run_item in line_run.items:
3088
                        if issubclass(type(run_item), SymbolSvgItem):
3089
                            self.init_add_tree_item(line_no_tree_item, run_item)
3090

    
3091
                app_doc_data.tracerLineNos.append(line_no)
3092

    
3093
                self.progress.setValue(self.progress.value() + 1)
3094
            QApplication.processEvents()
3095

    
3096
            if root.find('VENDORS') is not None:
3097
                for vendor in root.find('VENDORS').iter('VENDOR'):
3098
                    item = QEngineeringVendorItem.fromXml(vendor)
3099
                    item.transfer.onRemoved.connect(self.itemRemoved)
3100
                    self.graphicsView.scene().addItem(item)
3101

    
3102
            # connect flow item to line
3103
            for line in lines:
3104
                line.update_arrow()
3105
                app_doc_data.lines.append(line)
3106
            # for flowMark in [item for item in symbols if type(item) is QEngineeringFlowMarkItem]:
3107
            #    for line in lines:
3108
            #        if flowMark.owner is line:
3109
            #            line._flowMark.append(flowMark)
3110
            #            flowMark.setParentItem(line)
3111
            # up to here
3112

    
3113
            """
3114
            group_box = QGroupBox("Contact Details")
3115
            number_label = QLabel("Telephone number");
3116
            number_edit = QTextEdit('hello\nthis is ....')
3117
            layout = QFormLayout()
3118
            layout.addRow(number_label, number_edit)
3119
            group_box.setLayout(layout)
3120

3121
            proxy =  ㅐ()
3122
            proxy.setWidget(group_box)
3123
            self.graphicsView.scene().addItem(proxy)  # (group_box, QGraphicsItem.ItemIgnoresTransformations)
3124
            """
3125

    
3126
            """ update scene """
3127
            _items = [_item for _item in self.graphicsView.scene().items() if hasattr(_item, 'owner') or hasattr(_item, 'connectors')]
3128
            if _items:
3129
                items = divide_chunks(_items, App.THREAD_MAX_WORKER if len(_items) > App.THREAD_MAX_WORKER else len(_items))
3130
                with futures.ThreadPoolExecutor(max_workers=App.THREAD_MAX_WORKER) as pool:
3131
                    future_items = {pool.submit(update_items, _items): _items for _items in items}
3132
                    for future in futures.as_completed(future_items):
3133
                        _items = future.result()
3134
                        self.progress.setValue(self.progress.value() + len(_items))
3135

    
3136
            """
3137
            for item in [_item for _item in self.graphicsView.scene().items() if hasattr(_item, 'owner') or hasattr(_item, 'connectors')]:
3138
                up_progress = False
3139
                # binding items
3140
                item.owner
3141
                for connector in item.connectors:
3142
                    connector.connectedItem
3143

3144
                self.progress.setValue(self.progress.value() + 1)
3145
            """
3146

    
3147
            for item in self.graphicsView.scene().items():
3148
                item.setVisible(True)
3149

    
3150
            self.graphicsView.scene().update(self.graphicsView.sceneRect())
3151
        except Exception as ex:
3152
            message = 'error occurred({}) in {}:{}'.format(ex, sys.exc_info()[-1].tb_frame.f_code.co_filename,
3153
                                                           sys.exc_info()[-1].tb_lineno)
3154
            self.addMessage.emit(MessageType.Error, message)
3155
        finally:
3156
            self.itemTreeWidget.update_item_count()
3157
            self.itemTreeWidget.expandAll()
3158
            self.graphicsView.scene().blockSignals(False)
3159

    
3160
    '''
3161
        @brief      Remove added item on same place and Add GraphicsItem
3162
        @author     Jeongwoo
3163
        @date       2018.05.29
3164
        @history    2018.06.18  Jeongwoo    Set Z-index
3165
    '''
3166

    
3167
    def addLineItemToScene(self, lineItem):
3168
        self.graphicsView.scene().addItem(lineItem)
3169

    
3170
    '''
3171
        @brief      generate output xml file
3172
        @author     humkyung
3173
        @date       2018.04.23
3174
        @history    2018.05.02  Jeongwoo    Show MessageBox when imageviewer doesn't have image
3175
    '''
3176

    
3177
    def generateOutput(self):
3178
        import XmlGenerator as xg
3179

    
3180
        if not self.graphicsView.hasImage():
3181
            self.showImageSelectionMessageBox()
3182
            return
3183

    
3184
        try:
3185
            appDocData = AppDocData.instance()
3186

    
3187
            # collect items
3188
            appDocData.lines.clear()
3189
            appDocData.lines = [item for item in self.graphicsView.scene().items() if
3190
                                type(item) is QEngineeringLineItem and item.owner is None]
3191

    
3192
            appDocData.symbols.clear()
3193
            appDocData.symbols = [item for item in self.graphicsView.scene().items() if
3194
                                  issubclass(type(item), SymbolSvgItem) and item.owner is None]
3195

    
3196
            appDocData.equipments.clear()
3197
            for item in self.graphicsView.scene().items():
3198
                if type(item) is QEngineeringEquipmentItem:
3199
                    appDocData.equipments.append(item)
3200

    
3201
            appDocData.texts.clear()
3202
            appDocData.texts = [item for item in self.graphicsView.scene().items() if
3203
                                issubclass(type(item), QEngineeringTextItem) and type(
3204
                                    item) is not QEngineeringLineNoTextItem]
3205
            # up to here
3206

    
3207
            appDocData.imgOutput = np.ones((appDocData.activeDrawing.height, appDocData.activeDrawing.width),
3208
                                           np.uint8) * 255
3209
            xg.writeOutputXml(appDocData.imgName, appDocData.activeDrawing.width,
3210
                              appDocData.activeDrawing.height)  # TODO: check
3211
            project = appDocData.getCurrentProject()
3212
            cv2.imwrite(os.path.join(project.getTempPath(), 'OUTPUT.png'), appDocData.imgOutput)
3213
        except Exception as ex:
3214
            message = 'error occurred({}) in {}:{}'.format(ex, sys.exc_info()[-1].tb_frame.f_code.co_filename,
3215
                                                           sys.exc_info()[-1].tb_lineno)
3216
            self.addMessage.emit(MessageType.Error, message)
3217

    
3218
    '''
3219
        @brief      Check Number
3220
        @author     kyouho
3221
        @date       2018.08.20
3222
    '''
3223

    
3224
    def isNumber(self, num):
3225
        p = re.compile('(^[0-9]+$)')
3226
        result = p.match(num)
3227

    
3228
        if result:
3229
            return True
3230
        else:
3231
            return False
3232

    
3233
    '''
3234
        @brief      find overlap Connector
3235
        @author     kyouho
3236
        @date       2018.08.28
3237
    '''
3238

    
3239
    def findOverlapConnector(self, connectorItem):
3240
        from shapely.geometry import Point
3241
        from EngineeringConnectorItem import QEngineeringConnectorItem
3242
        itemList = []
3243

    
3244
        x = connectorItem.center()[0]
3245
        y = connectorItem.center()[1]
3246

    
3247
        connectors = [item for item in self.graphicsView.scene().items() if
3248
                      type(item) is QEngineeringConnectorItem and item != connectorItem]
3249
        for connector in connectors:
3250
            if Point(x, y).distance(Point(connector.center()[0], connector.center()[1])) < 5:
3251
                itemList.append(connector.parent)
3252

    
3253
        return itemList
3254

    
3255
    def make_diff_image(self):
3256
        """ make diff image """
3257
        # test
3258

    
3259
        from RecognitionDialog import Worker
3260
        from symbol import Symbol
3261
        import math
3262
        from PIL import Image
3263

    
3264
        app_doc_data = AppDocData.instance()
3265
        img = app_doc_data.imgSrc.copy()
3266

    
3267
        # check break
3268
        symbols = [item for item in self.graphicsView.scene().items() if issubclass(type(item), SymbolSvgItem)]
3269

    
3270
        for symbol in symbols:
3271
            rect = symbol.sceneBoundingRect()
3272
            sName = symbol.name
3273
            sType = symbol.type
3274
            sp = (rect.x(), rect.y())
3275
            w, h = rect.width(), rect.height()
3276
            rotatedAngle = round(math.degrees(symbol.angle))
3277
            detectFlip = symbol.flip
3278

    
3279
            dummySym = Symbol(sName, sType, sp, w, h, 0, 0, 0, rotatedAngle,
3280
                                   1, 0, 1, 0,
3281
                                   ','.join(str(x) for x in [0, 0]),
3282
                                   '/'.join('{},{},{},{}'.format(param[0], param[1], param[2], param[3]) for param in
3283
                                            []),
3284
                                   'dummy', 'dummy', 0, detectFlip=detectFlip,
3285
                                   hasInstrumentLabel=0, text_area='')
3286

    
3287
            Worker.remove_detected_symbol_image(dummySym, img, lock=False)
3288

    
3289
        Image.fromarray(img).show()
3290

    
3291
    #def paintEvent(self, event):
3292
    #    self.refresh_rate += 1
3293
    #    if self.refresh_rate == 3:
3294
    #        super(self.__class__, self).paintEvent(event)
3295
    #        self.refresh_rate = 0
3296

    
3297
if __name__ == '__main__':
3298
    import locale
3299
    from PyQt5.QtCore import QTranslator
3300
    from License import QLicenseDialog
3301
    from ProjectDialog import Ui_Dialog
3302
    from App import App
3303

    
3304
    app = App(sys.argv)
3305
    try:
3306
        if True == QLicenseDialog.check_license_key():
3307
            dlg = Ui_Dialog()
3308
            selectedProject = dlg.showDialog()
3309
            if selectedProject is not None:
3310
                AppDocData.instance().setCurrentProject(selectedProject)
3311
                app._mainWnd = MainWindow.instance()
3312
                app._mainWnd.show()
3313
                sys.exit(app.exec_())
3314
    except Exception as ex:
3315
        print('error occurred({}) in {}:{}'.format(ex, sys.exc_info()[-1].tb_frame.f_code.co_filename,
3316
                                                   sys.exc_info()[-1].tb_lineno))
3317
    finally:
3318
        pass
클립보드 이미지 추가 (최대 크기: 500 MB)