프로젝트

일반

사용자정보

통계
| 개정판:

hytos / DTI_PID / DTI_PID / MainWindow.py @ eb41cac4

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

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

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

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

    
21
import cv2
22
import numpy as np
23

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

    
29
from PIL import Image
30

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

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

    
73

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

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

    
81

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

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

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

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

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

    
115
        #self.refresh_rate = 0
116

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

    
125
        # save timer
126
        self.save_timer = None
127

    
128
        self._scene = QtImageViewerScene(self)
129

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

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

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

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

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

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

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

    
234
        self.delimiter = '"'
235

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

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

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

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

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

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

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

    
287
        self.read_settings()
288

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

    
293
        from App import App
294

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

    
303
        return title
304

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

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

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

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

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

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

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

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

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

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

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

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

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

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

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

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

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

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

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

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

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

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

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

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

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

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

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

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

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

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

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

    
499

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

    
504
        try:
505
            app_doc_data = AppDocData.instance()
506
            drawings = app_doc_data.getDrawings()
507
            new_drawings = []
508

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

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

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

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

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

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

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

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

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

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

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

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

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

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

    
595
        return
596

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

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

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

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

    
629
        from TextItemEditDialog import QTextItemEditDialog
630

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

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

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

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

    
649
        from ReplaceSymbolDialog import QReplaceSymbolDialog
650

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

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

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

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

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

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

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

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

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

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

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

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

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

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

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

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

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

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

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

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

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

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

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

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

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

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

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

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

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

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

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

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

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

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

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

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

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

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

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

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

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

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

    
917
            app_doc_data.clearItemList(False)
918

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

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

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

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

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

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

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

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

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

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

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

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

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

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

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

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

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

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

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

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

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

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

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

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

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

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

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

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

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

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

    
1075
        self.display_number_of_items()
1076

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

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

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

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

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

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

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

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

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

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

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

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

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

    
1185
            return
1186

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

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

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

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

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

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

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

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

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

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

    
1243
        ui.setChecked(True)
1244

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

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

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

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

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

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

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

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

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

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

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

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

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

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

    
1368
    '''
1369
        @brief  configuration
1370
    '''
1371

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

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

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

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

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

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

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

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

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

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

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

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

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

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

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

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

    
1440
    def onShowPSN(self):
1441
        def HighLight():
1442
            try:
1443
                docData = AppDocData.instance()
1444
                itemList = docData.selectView()
1445
                text_items = [item for item in self.graphicsView.scene().items() 
1446
                                if hasattr(item, 'uid') and str(item.uid) in itemList]
1447

    
1448
                if text_items:
1449
                    from HighlightCommand import HighlightCommand
1450
                    #for item in text_items:
1451
                    #    HighlightCommand(self.graphicsView).executePSN(item)
1452
                    HighlightCommand(self.graphicsView).executeForPSN(text_items)
1453
                        
1454
            finally:
1455
                # 연결 모두 지움
1456
                print("HighLight")
1457
            
1458

    
1459
        def threadOpenDrawing():
1460
            import socket
1461
            sock = socket.socket(socket.AF_INET, socket.SOCK_STREAM)
1462

    
1463
            # 소켓을 포트에 연결
1464
            server_address = ('localhost', 2549)
1465
            sock.bind(server_address)
1466

    
1467
            # 연결을 기다림
1468
            sock.listen()
1469
             
1470
            bContinue = True
1471
            while bContinue:
1472
                #연결을 기다림
1473
                print('waiting for a connection')
1474
                connection, client_address = sock.accept()
1475
                try:
1476
                    print('connection from', client_address)
1477

    
1478
                    #작은 데이터를 받고 다시 전송
1479
                    data = connection.recv(1024)
1480
                    if data:
1481
                        sData = data.decode('utf-8')
1482
                        drawing_top = self.treeWidgetDrawingList.topLevelItem(0)
1483
                        count = drawing_top.childCount()
1484
                        for idx in range(count):
1485
                            child = drawing_top.child(idx)
1486
                            child.setCheckState(0, Qt.Unchecked)
1487
                            drawing = child.data(Qt.UserRole, 0)
1488
                            if drawing:
1489
                                name = drawing.name
1490
                                if sData == name.rsplit('.', 1)[0]:
1491
                                    self.open_image_drawing(drawing)
1492
                                    child.setCheckState(0, Qt.Checked)
1493
                                    bContinue = False
1494

    
1495
                                    HighLight()
1496

    
1497
                                    connection.sendall(bytes("End", encoding = "utf-8"))
1498
                                    break
1499

    
1500
                    else:
1501
                        print('no data from', client_address)
1502
                finally:
1503
                    # 연결 모두 지움
1504
                    print("closing current connection")
1505
                    connection.close()
1506
        
1507
        #import os
1508
        #os.system(r'C:\Program Files (x86)\DOFTECH\ID2PSN\ID2PSN.exe')
1509
        
1510
        project = AppDocData.instance().getCurrentProject()
1511
        import subprocess
1512
        args = ['C:\Program Files (x86)\DOFTECH\ID2PSN\ID2PSN.exe', project.path + '☆■☆' + self.ribbon.get_pane('Data').ui.toolButtonPSN.text().replace('\n', '')]
1513
        subprocess.Popen(args, stdout = subprocess.PIPE)
1514

    
1515
        threadOpenDrawing()
1516

    
1517
        #import threading
1518
        #t1 = threading.Thread(target=threadOpenDrawing)
1519
        #t1.daemon = True
1520
        #t1.start()
1521

    
1522

    
1523
    def onShowCustomCodeTable(self):
1524
        from CustomCodeTablesDialog import CustomCodeTablesDialog
1525

    
1526
        dlg = CustomCodeTablesDialog(self)
1527
        dlg.show()
1528
        dlg.exec_()
1529
        self.graphicsView.useDefaultCommand()
1530

    
1531
    def onShowReplaceCodeTable(self):
1532
        from CustomCodeTablesDialog import CustomCodeTablesDialog
1533

    
1534
        dlg = CustomCodeTablesDialog(self, replace=True)
1535
        dlg.show()
1536
        dlg.exec_()
1537
        self.graphicsView.useDefaultCommand()
1538

    
1539
    def on_streamline(self):
1540
        """pop up stream line dialog"""
1541
        from StreamlineDialog import QStreamlineDialog
1542

    
1543
        if not self.graphicsView.hasImage():
1544
            self.showImageSelectionMessageBox()
1545
            return
1546

    
1547
        hmbs = AppDocData.instance().get_hmb_data(None)
1548
        if not hmbs:
1549
            return
1550

    
1551
        dlg = QStreamlineDialog(self)
1552
        dlg.show()
1553

    
1554
    def onHMBData(self):
1555
        """show HMB data"""
1556
        from HMBDialog import QHMBDialog
1557

    
1558
        dlg = QHMBDialog(self)
1559
        dlg.show()
1560
        dlg.exec_()
1561

    
1562
    '''
1563
        @brief  show line data list 
1564
        @author humkyung
1565
        @date   2018.05.03
1566
    '''
1567

    
1568
    def showItemDataList(self):
1569
        from ItemDataExportDialog import QItemDataExportDialog
1570

    
1571
        dlg = QItemDataExportDialog(self)
1572
        dlg.exec_()
1573

    
1574
    def showTextDataList(self):
1575
        '''
1576
            @brief      show all text item in scene
1577
            @author     euisung
1578
            @date       2019.04.18
1579
        '''
1580
        try:
1581
            if not self.graphicsView.hasImage():
1582
                self.showImageSelectionMessageBox()
1583
                return
1584

    
1585
            self.onCommandRejected()
1586
            dialog = QTextDataListDialog(self)
1587
            dialog.show()
1588
        except Exception as ex:
1589
            message = 'error occurred({}) in {}:{}'.format(ex, sys.exc_info()[-1].tb_frame.f_code.co_filename,
1590
                                                           sys.exc_info()[-1].tb_lineno)
1591
            self.addMessage.emit(MessageType.Error, message)
1592

    
1593
    '''
1594
        @brief  Show Image Selection Guide MessageBox
1595
        @author Jeongwoo
1596
        @date   2018.05.02
1597
    '''
1598

    
1599
    def showImageSelectionMessageBox(self):
1600
        QMessageBox.about(self.graphicsView, self.tr("Notice"), self.tr("First select image drawing"))
1601

    
1602
    def on_search_text_changed(self):
1603
        """filter symbol tree view"""
1604
        regexp = QRegExp(self.lineEditFilter.text(), Qt.CaseInsensitive, QRegExp.FixedString)
1605

    
1606
        proxy_model = self.symbolTreeWidget.model()
1607
        proxy_model.text = self.lineEditFilter.text().lower()
1608
        proxy_model.setFilterRegExp(regexp)
1609

    
1610
        self.symbolTreeWidget.expandAll()
1611

    
1612
    def display_colors(self, value):
1613
        """ display colors """
1614
        from DisplayColors import DisplayColors
1615
        from DisplayColors import DisplayOptions
1616

    
1617
        if hasattr(self, 'ribbon'):
1618
            visualization_pane = self.ribbon.get_pane('Home Visualization')
1619
            if self.sender() is visualization_pane.ui.radioButtonByGroup and value is True:
1620
                DisplayColors.instance().option = DisplayOptions.DisplayByLineNo
1621
            elif self.sender() is visualization_pane.ui.radioButtonByType and value is True:
1622
                DisplayColors.instance().option = DisplayOptions.DisplayByLineType
1623
            elif self.sender() is visualization_pane.ui.radioButtonByStreamNo and value is True:
1624
                DisplayColors.instance().option = DisplayOptions.DisplayByStreamNo
1625

    
1626
            if hasattr(self, 'graphicsView') and value is True:
1627
                self.graphicsView.scene().update(self.graphicsView.sceneRect())
1628
                for item in self.graphicsView.scene().items():
1629
                    if issubclass(type(item), SymbolSvgItem):
1630
                        item.update()
1631
                DisplayColors.instance().save_data()
1632

    
1633
    def open_image_drawing(self, drawing, force=False, ocrUnknown=False):
1634
        """open and display image drawing file"""
1635
        from Drawing import Drawing
1636
        from App import App
1637
        from LoadCommand import LoadCommand
1638
        import concurrent.futures as futures
1639

    
1640
        # Yield successive n-sized
1641
        # chunks from l.
1642
        def divide_chunks(l, n):
1643
            # looping till length l
1644
            for i in range(0, len(l), n):
1645
                yield l[i:i + n]
1646

    
1647
        def update_items(items):
1648
            for item in items:
1649
                # binding items
1650
                item.owner
1651
                for connector in item.connectors:
1652
                    connector.connectedItem
1653

    
1654
            return items
1655

    
1656
        try:
1657
            app_doc_data = AppDocData.instance()
1658

    
1659
            if not self.actionSave.isEnabled():
1660
                return
1661

    
1662
            if not force and self.save_drawing_if_necessary():
1663
                return
1664

    
1665
            occupied = app_doc_data.set_occupying_drawing(drawing.UID)
1666
            if occupied:
1667
                QMessageBox.about(self.graphicsView, self.tr("Notice"),
1668
                                  self.tr(f"The drawing is locked for editing by another user({occupied})"))
1669
                return
1670

    
1671
            # save alarm
1672
            self.save_alarm_enable(False)
1673

    
1674
            if hasattr(self, '_save_work_cmd'):
1675
                self._save_work_cmd.wait()
1676

    
1677
            project = app_doc_data.getCurrentProject()
1678

    
1679
            self.path = self.graphicsView.loadImageFromFile(drawing)
1680
            if os.path.isfile(self.path):
1681
                self.onCommandRejected()
1682
                app_doc_data.clear(past=drawing.UID)
1683

    
1684
                # load color for stream no coloring
1685
                configs = app_doc_data.getConfigs('Line List', 'Use Stream No')
1686
                if configs and int(configs[0].value) == 1:
1687
                    hmbs = app_doc_data.get_hmb_data(None)
1688
                    colors = {}
1689
                    if hmbs:
1690
                        for hmb in hmbs:
1691
                            rgb = app_doc_data.colors
1692
                            colors[hmb.stream_no] = QColor(rgb.red, rgb.green, rgb.blue).name()
1693
                        app_doc_data._hmbColors = colors
1694
                # up to here
1695

    
1696
                app_doc_data.setImgFilePath(self.path)
1697
                app_doc_data.activeDrawing = drawing
1698
                
1699
                #app_doc_data.activeDrawing.set_pid_source(Image.open(self.path))
1700
                self.itemTreeWidget.setCurrentPID(app_doc_data.activeDrawing.name)
1701

    
1702
                drawingList = self.treeWidgetDrawingList.topLevelItem(0)
1703
                for idx in range(drawingList.childCount()):
1704
                    child = drawingList.child(idx)
1705
                    if child.data(Qt.UserRole, 0) is drawing:
1706
                        child.setCheckState(0, Qt.Checked)
1707
                    else:
1708
                        child.setCheckState(0, Qt.Unchecked)
1709

    
1710
                try:
1711
                    self.show_Progress_bar()
1712

    
1713
                    # disconnect scene changed if signal is connected
1714
                    if self.graphicsView.scene().receivers(self.graphicsView.scene().contents_changed) > 0:
1715
                        self.graphicsView.scene().contents_changed.disconnect()
1716

    
1717
                    SymbolSvgItem.DOCUMENTS.clear()
1718

    
1719
                    # load data
1720
                    cmd = LoadCommand()
1721
                    cmd.display_message.connect(self.onAddMessage)
1722
                    cmd.set_maximum.connect(self.progress.setMaximum)
1723
                    cmd.show_progress.connect(self.progress.setValue)
1724
                    cmd.execute((drawing, self.graphicsView.scene()),
1725
                                symbol=True, text=True, line=True, unknown=True, package=True, update=True)
1726

    
1727
                    configs = app_doc_data.getConfigs('Line List', 'Use Stream No')
1728
                    if configs and int(configs[0].value) == 1:
1729
                        app_doc_data._streamLineListModelDatas = app_doc_data.get_stream_line_list_data()
1730
                    # up to here
1731

    
1732
                    """"update item tree widget"""
1733
                    line_no_items = [item for item in self.graphicsView.scene().items()
1734
                                     if type(item) is QEngineeringLineNoTextItem]
1735
                    for line_no in line_no_items:
1736
                        line_no_tree_item = self.itemTreeWidget.addTreeItem(self.itemTreeWidget.root, line_no)
1737
                        for run in line_no.runs:
1738
                            for run_item in run.items:
1739
                                if issubclass(type(run_item), SymbolSvgItem):
1740
                                    self.init_add_tree_item(line_no_tree_item, run_item)
1741

    
1742
                    line_no_items = [item for item in self.graphicsView.scene().items()
1743
                                     if type(item) is QEngineeringTrimLineNoTextItem]
1744
                    for line_no in line_no_items:
1745
                        line_no_tree_item = self.itemTreeWidget.addTreeItem(self.itemTreeWidget.root, line_no)
1746
                        for run in line_no.runs:
1747
                            for run_item in run.items:
1748
                                if issubclass(type(run_item), SymbolSvgItem):
1749
                                    self.init_add_tree_item(line_no_tree_item, run_item)
1750

    
1751
                    for trim_line_no in app_doc_data.tracerLineNos:
1752
                        line_no_tree_item = self.itemTreeWidget.addTreeItem(self.itemTreeWidget.root, trim_line_no)
1753
                        for run in trim_line_no.runs:
1754
                            for run_item in run.items:
1755
                                if issubclass(type(run_item), SymbolSvgItem):
1756
                                    self.init_add_tree_item(line_no_tree_item, run_item)
1757

    
1758
                    self.itemTreeWidget.update_item_count()
1759
                    self.itemTreeWidget.expandAll()
1760
                    """up to here"""
1761

    
1762
                    """update scene"""
1763
                    for item in self._scene.items():
1764
                        item.setVisible(True)
1765

    
1766
                    self._scene.update(self._scene.sceneRect())
1767

    
1768
                    """
1769
                    # old open drawing
1770
                    path = os.path.join(app_doc_data.getCurrentProject().getTempPath(), app_doc_data.imgName + '.xml')
1771
                    configs = app_doc_data.getConfigs('Data Load', 'Xml First')
1772
                    if configs and int(configs[0].value) >= 1 and os.path.isfile(path):
1773
                        self.load_recognition_result_from_xml(drawing)
1774
                    elif configs and int(configs[0].value) <= 1:
1775
                        self.load_drawing(app_doc_data.activeDrawing)
1776
                    """
1777

    
1778
                    self.display_number_of_items()
1779
                    # connect scene changed signal
1780
                    self.graphicsView.scene().contents_changed.connect(self.scene_changed)
1781
                finally:
1782
                    if hasattr(self, 'progress'):
1783
                        self.progress.setValue(self.progress.maximum())
1784

    
1785
                self.changeViewCheckedState(True)
1786
                self.setWindowTitle(self.title)
1787
                self.fitWindow(drawing.view_rect)
1788

    
1789
                if ocrUnknown:
1790
                    self.on_ocr_unknown_items()
1791

    
1792
                # save alarm
1793
                self.save_alarm_enable(True, True)
1794
        except Exception as ex:
1795
            message = f"error occurred({repr(ex)}) in {sys.exc_info()[-1].tb_frame.f_code.co_filename}:" \
1796
                      f"{sys.exc_info()[-1].tb_lineno}"
1797
            self.addMessage.emit(MessageType.Error, message)
1798

    
1799
        return self.path
1800

    
1801
    def save_alarm_enable(self, enable, init=False):
1802
        from datetime import datetime
1803

    
1804
        try:
1805
            app_doc_data = AppDocData.instance()
1806
            configs = app_doc_data.getConfigs('Data Save', 'Time')
1807
            time_min = int(configs[0].value) if 1 == len(configs) else 0
1808

    
1809
            if enable and time_min > 0:
1810
                if not self.save_timer:
1811
                    self.save_timer = QTimer()
1812
                    self.save_timer.timeout.connect(self.save_alarm)
1813
                    self.save_timer.setInterval(60000)
1814

    
1815
                if init:
1816
                    self.save_timer._init_time = datetime.now()
1817
                    self.save_timer._stop_time = None
1818
                    self.save_timer._interval_time = datetime.now() - datetime.now()
1819

    
1820
                if self.save_timer._stop_time:
1821
                    self.save_timer._interval_time = datetime.now() - self.save_timer._stop_time
1822
                
1823
                #if 60000 * time_min != self.save_timer.interval():
1824
                #    self.save_timer.setInterval(60000)
1825

    
1826
                self.save_timer.start()
1827
            else:
1828
                if self.save_timer:
1829
                    self.save_timer.stop()
1830
                    self.save_timer._stop_time = datetime.now()
1831
        
1832
        except Exception as ex:
1833
            message = f"error occurred({repr(ex)}) in {sys.exc_info()[-1].tb_frame.f_code.co_filename}:" \
1834
                      f"{sys.exc_info()[-1].tb_lineno}"
1835
            self.addMessage.emit(MessageType.Error, message)
1836

    
1837
    def save_alarm(self):
1838
        from datetime import datetime
1839

    
1840
        app_doc_data = AppDocData.instance()
1841
        configs = app_doc_data.getConfigs('Data Save', 'Time')
1842
        time_min = int(configs[0].value) if 1 == len(configs) else 0
1843

    
1844
        self.save_timer.stop()
1845
        if self.graphicsView.hasFocus() and (datetime.now() - self.save_timer._init_time - self.save_timer._interval_time).seconds > time_min * 60:
1846
            QMessageBox.information(self, self.tr('Information'), self.tr('Please save Drawing'))
1847
            self.save_timer._init_time = datetime.now()
1848
            self.save_timer._interval_time = datetime.now() - datetime.now()
1849
        self.save_timer.start()
1850

    
1851
    def export_as_svg(self):
1852
        """export scene to svg file"""
1853
        from ExportCommand import ExportCommand
1854

    
1855
        options = QFileDialog.Options()
1856
        options |= QFileDialog.DontUseNativeDialog
1857
        file_path, _ = QFileDialog.getSaveFileName(self, "Export as svg", os.getcwd(), "svg file(*.svg)",
1858
                                                   options=options)
1859
        if file_path:
1860
            cmd = ExportCommand(self.graphicsView.scene(), 'svg')
1861
            cmd.display_message.connect(self.onAddMessage)
1862
            if cmd.execute(file_path):
1863
                QMessageBox.information(self, self.tr('Information'), self.tr('Successfully export to svg file'))
1864
            else:
1865
                QMessageBox.information(self, self.tr('Error'), self.tr('Fail to export to svg file'))
1866

    
1867
    def export_as_xml(self):
1868
        pass
1869

    
1870
    def export_as_image(self):
1871
        """export scene to image file"""
1872
        from ExportCommand import ExportCommand
1873

    
1874
        options = QFileDialog.Options()
1875
        options |= QFileDialog.DontUseNativeDialog
1876
        file_path, _ = QFileDialog.getSaveFileName(self, "Export as png", os.getcwd(), "png file(*.png)",
1877
                                                   options=options)
1878
        if file_path:
1879
            try:
1880
                # hide image drawing
1881
                self.onViewImageDrawing(False)
1882

    
1883
                cmd = ExportCommand(self.graphicsView.scene(), 'image')
1884
                cmd.display_message.connect(self.onAddMessage)
1885

    
1886
                if cmd.execute(file_path):
1887
                    QMessageBox.information(self, self.tr('Information'), self.tr('Successfully export to image file'))
1888
                else:
1889
                    QMessageBox.information(self, self.tr('Error'), self.tr('Fail to export to image file'))
1890
            finally:
1891
                if self.actionImage_Drawing.isChecked():
1892
                    self.onViewImageDrawing(True)
1893
                    self.actionImage_Drawing.setChecked(True)
1894

    
1895
    def show_Progress_bar(self):
1896
        """ show progress bar """
1897
        self.progress = QProgressDialog(self.tr("Please wait for a while"), self.tr("Cancel"), 0, 100,
1898
                                        self) if not hasattr(self, 'progress') else self.progress
1899
        self.progress.setWindowModality(Qt.WindowModal)
1900
        self.progress.setAutoReset(True)
1901
        self.progress.setAutoClose(True)
1902
        self.progress.setMinimum(0)
1903
        self.progress.setMaximum(100)
1904
        self.progress.resize(600, 100)
1905
        self.progress.setWindowTitle(self.tr("Reading file..."))
1906
        self.progress.show()
1907

    
1908
    def changeViewCheckedState(self, checked, clear=True):
1909
        """change view checked state"""
1910
        # self.actionImage_Drawing.setChecked(checked)
1911
        self.actionViewText.setChecked(checked)
1912
        self.actionViewSymbol.setChecked(checked)
1913
        self.actionViewLine.setChecked(checked)
1914
        self.actionViewUnknown.setChecked(checked)
1915
        self.actionViewInconsistency.setChecked(checked)
1916
        self.actionViewVendor_Area.setChecked(not checked)
1917
        self.actionDrawing_Only.setChecked(not checked)
1918
        if clear:
1919
            self.tableWidgetInconsistency.clearContents()
1920
            self.tableWidgetInconsistency.setRowCount(0)
1921

    
1922
    def onViewDrawingOnly(self, isChecked):
1923
        '''
1924
            @brief  visible/invisible except image drawing
1925
            @author euisung
1926
            @date   2019.04.22
1927
        '''
1928
        self.changeViewCheckedState(not isChecked, False)
1929
        for item in self.graphicsView.scene().items():
1930
            if type(item) is not QGraphicsPixmapItem:
1931
                item.setVisible(not isChecked)
1932

    
1933
    '''
1934
        @brief  visible/invisible image drawing
1935
        @author humkyung
1936
        @date   2018.06.25
1937
    '''
1938

    
1939
    def onViewImageDrawing(self, isChecked):
1940
        for item in self.graphicsView.scene().items():
1941
            if type(item) is QGraphicsPixmapItem:
1942
                item.setVisible(isChecked)
1943
                break
1944

    
1945
    def onViewText(self, checked):
1946
        """visible/invisible text"""
1947
        selected = [item for item in self.graphicsView.scene().items() if issubclass(type(item), QEngineeringTextItem)
1948
                    and type(item) is not QEngineeringLineNoTextItem]
1949
        for item in selected:
1950
            item.setVisible(checked)
1951

    
1952
    def onViewSymbol(self, checked):
1953
        """visible/invisible symbol"""
1954
        selected = [item for item in self.graphicsView.scene().items() if
1955
                    (issubclass(type(item), SymbolSvgItem) and type(item) is not QEngineeringErrorItem)]
1956
        for item in selected:
1957
            item.setVisible(checked)
1958

    
1959
    def onViewLine(self, checked):
1960
        """visible/invisible line"""
1961
        selected = [item for item in self.graphicsView.scene().items() if type(item) is QEngineeringLineItem]
1962
        for item in selected:
1963
            item.setVisible(checked)
1964

    
1965
    def onViewInconsistency(self, isChecked):
1966
        '''
1967
            @brief  visible/invisible Inconsistency
1968
            @author euisung
1969
            @date   2019.04.03
1970
        '''
1971
        selected = [item for item in self.graphicsView.scene().items() if type(item) is QEngineeringErrorItem]
1972
        for item in selected:
1973
            item.setVisible(isChecked)
1974

    
1975
    '''
1976
        @brief  visible/invisible Unknown 
1977
        @author humkyung
1978
        @date   2018.06.28
1979
    '''
1980

    
1981
    def onViewUnknown(self, isChecked):
1982
        selected = [item for item in self.graphicsView.scene().items() if type(item) is QEngineeringUnknownItem]
1983
        for item in selected:
1984
            item.setVisible(isChecked)
1985

    
1986
    def onViewVendorArea(self, isChecked):
1987
        '''
1988
            @brief  visible/invisible Vendor Area
1989
            @author euisung
1990
            @date   2019.04.29
1991
        '''
1992
        selected = [item for item in self.graphicsView.scene().items() if issubclass(type(item), QEngineeringVendorItem)]
1993
        for item in selected:
1994
            item.setVisible(isChecked)
1995

    
1996
    '''
1997
        @brief  create a symbol
1998
        @history    2018.05.02  Jeongwoo    Change return value of QSymbolEditorDialog (Single variable → Tuple)
1999
                                            Add SymbolSvgItem
2000
                    2018.05.03  Jeongwoo    Change method to draw Svg Item on Scene (svg.addSvgItemToScene)
2001
                                            Change method to make svg and image path
2002
                    2018.06.08  Jeongwoo    Add Paramter on SymbolSvgItem.buildItem()
2003
    '''
2004
    def onCreateSymbolClicked(self):
2005
        selected = [item for item in self.graphicsView.scene().selectedItems() if issubclass(type(item), QEngineeringVendorItem)]
2006
        if len(selected) == 1:
2007
            symbol_image = AppDocData.instance().activeDrawing.image_origin
2008
            rect = selected[0].sceneBoundingRect()
2009

    
2010
            points = []
2011
            for conn in selected[0].connectors:
2012
                points.append([round(conn.center()[0] - rect.x()), round(conn.center()[1] - rect.y())])
2013
            poly = np.array(points, np.int32)
2014

    
2015
            #mask = np.zeros((int(rect.height()), int(rect.width())))
2016
            #cv2.fillPoly(mask, [poly], (255))
2017
            #poly_copied = np.multiply(mask, symbol_image[round(rect.y()):round(rect.y() + rect.height()),
2018
            #                   round(rect.x()):round(rect.x() + rect.width())])
2019
            #cv2.fillPoly(mask,[poly],0)
2020
            #src2 = np.multiply(mask,src2)
2021

    
2022
            mask = np.ones((int(rect.height()), int(rect.width())), dtype=np.uint8) * 255
2023
            cv2.fillPoly(mask, [poly], (0))
2024
            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())])
2025
            sym_img = cv2.merge((sym_img, sym_img, sym_img))
2026

    
2027
            h, w, c = sym_img.shape
2028
            qImg = QImage(sym_img.data, w, h, w * c, QImage.Format_RGB888)
2029
            #pixmap = QPixmap.fromImage(qImg)
2030

    
2031
            self.onAreaSelected(None, None, None, None, package=qImg, position=rect.topLeft(), package_item=selected[0])
2032
        else:
2033
            cmd = FenceCommand.FenceCommand(self.graphicsView)
2034
            cmd.onSuccess.connect(self.onAreaSelected)
2035
            self.graphicsView.command = cmd
2036
            QApplication.setOverrideCursor(Qt.CrossCursor)
2037

    
2038
    '''
2039
        @brief      show SymbolEditorDialog with image selected by user
2040
        @author     humkyung
2041
        @date       2018.07.20
2042
    '''
2043

    
2044
    def onAreaSelected(self, x, y, width, height, package=False, position=None, package_item=None):
2045
        try:
2046
            image = self.graphicsView.image()
2047
            if image is not None:
2048
                if not package:
2049
                    symbolEditorDialog = SymbolEditorDialog.QSymbolEditorDialog(self, image.copy(x, y, width, height),
2050
                                                                                AppDocData.instance().getCurrentProject())
2051
                else:
2052
                    symbolEditorDialog = SymbolEditorDialog.QSymbolEditorDialog(self, package,
2053
                                                                                AppDocData.instance().getCurrentProject(), package=True)
2054
                (isAccepted, isImmediateInsert, offsetX, offsetY, newSym) = symbolEditorDialog.showDialog()
2055
                # TODO: not initialize symbol tree view when user reject to create a new symbol
2056
                self.symbolTreeWidget.initSymbolTreeView()
2057
                if isAccepted:
2058
                    if isImmediateInsert:
2059
                        svg = QtImageViewer.createSymbolObject(newSym.getName())
2060
                        offsetX, offsetY = [int(point) for point in newSym.getOriginalPoint().split(',')]
2061
                        QtImageViewer.matchSymbolToLine(self.graphicsView.scene(), svg, QPoint(position.x() + offsetX, position.y() + offsetY))
2062

    
2063
                        package_item.transfer.onRemoved.emit(package_item)
2064
        finally:
2065
            self.onCommandRejected()
2066
            QApplication.restoreOverrideCursor()
2067
            QApplication.restoreOverrideCursor()
2068

    
2069
    def on_line_list(self):
2070
        """ line list export dialog """
2071
        from LineListDialog import LineListDialog
2072

    
2073
        if not self.graphicsView.hasImage():
2074
            self.showImageSelectionMessageBox()
2075
            return
2076

    
2077
        dialog = LineListDialog(self)
2078
        dialog.showDialog()
2079

    
2080
    def on_make_label_data(self):
2081
        """ make label data from symbol info """
2082
        from xml.etree.ElementTree import Element, SubElement, dump, ElementTree, parse
2083

    
2084
        if not self.graphicsView.hasImage():
2085
            self.showImageSelectionMessageBox()
2086
            return
2087

    
2088
        app_doc_data = AppDocData.instance()
2089
        project = app_doc_data.getCurrentProject()
2090

    
2091
        smalls = []
2092
        bigs = []
2093

    
2094
        symbol_list = app_doc_data.getTargetSymbolList(all=True)
2095
        #symbol_list = app_doc_data.getTargetSymbolList(all=False)
2096
        for symbol in symbol_list:
2097
            if symbol.iType == 38 or symbol.iType == 33 or symbol.iType == 0 or symbol.iType == 40:
2098
                continue
2099
            elif symbol.width and symbol.height:
2100
                if symbol.width > 300 or symbol.height > 300:
2101
                    bigs.append(symbol.getName())
2102
                elif (symbol.width * symbol.height < 1500) or (symbol.width > 450 or symbol.height > 450):
2103
                    continue
2104
                else:
2105
                    smalls.append(symbol.getName())
2106

    
2107
        symbols = [item for item in self.graphicsView.scene().items() if issubclass(type(item), SymbolSvgItem)]
2108
        names = [smalls, bigs]
2109

    
2110
        img = app_doc_data.activeDrawing.image_origin
2111

    
2112
        small_size = 500
2113
        big_size = 850
2114

    
2115
        save_path = project.getTrainingSymbolFilePath()
2116

    
2117
        index = 0
2118
        for size in [small_size, big_size]:
2119
            offsets = [0, int(size / 2)]
2120

    
2121
            width, height = img.shape[1], img.shape[0]
2122
            width_count, height_count = width // size + 2, height // size + 2
2123
            b_width, b_height = width_count * size, height_count * size
2124
            b_img = np.zeros((b_height, b_width), np.uint8) + 255
2125
            b_img[:height, :width] = img[:, :]
2126

    
2127
            for offset in offsets:
2128
                for row in range(height_count):
2129
                    for col in range(width_count):
2130
                        x, y = col * size + offset, row * size + offset
2131
                        tile_rect = QRectF(x, y, size, size)
2132
                        tile_symbols = []
2133
                        for symbol in [symbol for symbol in symbols if symbol.name in names[index]]:
2134
                            if tile_rect.contains(symbol.sceneBoundingRect()):
2135
                                tile_symbols.append(symbol)
2136
                                symbols.remove(symbol)
2137

    
2138
                        if tile_symbols:
2139
                            training_uid = str(uuid.uuid4())
2140
                            training_image_path = os.path.join(save_path, training_uid + '.png')
2141
                            training_xml_path = os.path.join(save_path, training_uid + '.xml')
2142

    
2143
                            # save image
2144
                            #_img = b_img[round(tile_rect.top()):round(tile_rect.bottom()),
2145
                            #       round(tile_rect.left()):round(tile_rect.right())]
2146
                            #cv2.imwrite(training_image_path, _img)
2147
                            _img = self.graphicsView.image().copy(round(tile_rect.left()), round(tile_rect.top()), round(tile_rect.width()), round(tile_rect.height()))
2148
                            _img.save(training_image_path)
2149

    
2150
                            # save label
2151
                            xml = Element('annotation')
2152
                            SubElement(xml, 'folder').text = 'None'
2153
                            SubElement(xml, 'filename').text = os.path.basename(save_path)
2154

    
2155
                            pathNode = Element('path')
2156
                            pathNode.text = save_path.replace('/', '\\')
2157
                            xml.append(pathNode)
2158

    
2159
                            sourceNode = Element('source')
2160
                            databaseNode = Element('database')
2161
                            databaseNode.text = 'Unknown'
2162
                            sourceNode.append(databaseNode)
2163
                            xml.append(sourceNode)
2164

    
2165
                            sizeNode = Element('size')
2166
                            widthNode = Element('width')
2167
                            widthNode.text = str(int(tile_rect.width()))
2168
                            sizeNode.append(widthNode)
2169
                            heightNode = Element('height')
2170
                            heightNode.text = str(int(tile_rect.height()))
2171
                            sizeNode.append(heightNode)
2172
                            depthNode = Element('depth')
2173
                            depthNode.text = '3'
2174
                            sizeNode.append(depthNode)
2175
                            xml.append(sizeNode)
2176

    
2177
                            segmentedNode = Element('segmented')
2178
                            segmentedNode.text = '0'
2179
                            xml.append(segmentedNode)
2180

    
2181
                            labelContent = []
2182
                            counts = {}
2183
                            for item in tile_symbols:
2184
                                rect = item.sceneBoundingRect()
2185
                                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)
2186
                                #label = 'small' if index == 0 else 'big' # for single class test
2187
                                xMin = xMin if xMin > 0 else 0
2188
                                yMin = yMin if yMin > 0 else 0
2189
                                xMax = xMax if xMax < size else size
2190
                                yMax = yMax if yMax < size else size
2191

    
2192
                                if label == 'None' or label == '':
2193
                                    continue
2194
                                if label not in labelContent:
2195
                                    labelContent.append(label)
2196
                                    counts[label] = 1
2197
                                else:
2198
                                    counts[label] = counts[label] + 1
2199

    
2200
                                objectNode = Element('object')
2201
                                nameNode = Element('name')
2202
                                nameNode.text = label
2203
                                objectNode.append(nameNode)
2204
                                poseNode = Element('pose')
2205
                                poseNode.text = 'Unspecified'
2206
                                objectNode.append(poseNode)
2207
                                truncatedNode = Element('truncated')
2208
                                truncatedNode.text = '0'
2209
                                objectNode.append(truncatedNode)
2210
                                difficultNode = Element('difficult')
2211
                                difficultNode.text = '0'
2212
                                objectNode.append(difficultNode)
2213

    
2214
                                bndboxNode = Element('bndbox')
2215
                                xminNode = Element('xmin')
2216
                                xminNode.text = str(xMin)
2217
                                bndboxNode.append(xminNode)
2218
                                yminNode = Element('ymin')
2219
                                yminNode.text = str(yMin)
2220
                                bndboxNode.append(yminNode)
2221
                                xmaxNode = Element('xmax')
2222
                                xmaxNode.text = str(xMax)
2223
                                bndboxNode.append(xmaxNode)
2224
                                ymaxNode = Element('ymax')
2225
                                ymaxNode.text = str(yMax)
2226
                                bndboxNode.append(ymaxNode)
2227
                                objectNode.append(bndboxNode)
2228

    
2229
                                xml.append(objectNode)
2230

    
2231
                            ElementTree(xml).write(training_xml_path)
2232

    
2233
            index += 1
2234

    
2235
        QMessageBox.about(self, self.tr("Notice"), self.tr('Successfully applied. '))
2236

    
2237
    def onPlaceLine(self):
2238
        """create a line"""
2239
        home_pane = self.ribbon.get_pane('Home')
2240

    
2241
        if not self.graphicsView.hasImage():
2242
            home_pane.ui.toolButtonLine.setChecked(False)
2243
            self.showImageSelectionMessageBox()
2244
            return
2245

    
2246
        self.update_action_group(home_pane.ui.toolButtonLine)
2247
        if not hasattr(home_pane.ui.toolButtonLine, 'tag'):
2248
            home_pane.ui.toolButtonLine.tag = PlaceLineCommand.PlaceLineCommand(self.graphicsView)
2249
            home_pane.ui.toolButtonLine.tag.onSuccess.connect(self.onLineCreated)
2250
            home_pane.ui.toolButtonLine.tag.onRejected.connect(self.onCommandRejected)
2251

    
2252
        self.graphicsView.command = home_pane.ui.toolButtonLine.tag
2253

    
2254
    def onLineCreated(self):
2255
        """add created lines to scene"""
2256
        from EngineeringConnectorItem import QEngineeringConnectorItem
2257
        from LineDetector import LineDetector
2258

    
2259
        try:
2260
            app_doc_data = AppDocData.instance()
2261
            home_pane = self.ribbon.get_pane('Home')
2262

    
2263
            count = len(home_pane.ui.toolButtonLine.tag._polyline._vertices)
2264
            if count > 1:
2265
                items = []
2266

    
2267
                detector = LineDetector(None)
2268

    
2269
                if not home_pane.ui.toolButtonLine.tag.line_type:
2270
                    line_type = home_pane.ui.comboBoxLineType.currentText()
2271
                else:
2272
                    pane = self.ribbon.get_pane('Home')
2273
                    selected_line_type = pane.ui.comboBoxLineType.currentText()
2274
                    if selected_line_type == 'Connect To Process':
2275
                        line_type = selected_line_type
2276
                    elif not (QEngineeringLineItem.check_piping(home_pane.ui.toolButtonLine.tag.line_type) ^
2277
                              QEngineeringLineItem.check_piping(selected_line_type)):
2278
                        line_type = selected_line_type
2279
                    else:
2280
                        line_type = home_pane.ui.toolButtonLine.tag.line_type
2281
                for index in range(count - 1):
2282
                    start = home_pane.ui.toolButtonLine.tag._polyline._vertices[index]
2283
                    end = home_pane.ui.toolButtonLine.tag._polyline._vertices[index + 1]
2284

    
2285
                    lineItem = QEngineeringLineItem(vertices=[start, end])
2286
                    lineItem.transfer.onRemoved.connect(self.itemRemoved)
2287
                    lineItem.lineType = line_type
2288
                    if items:
2289
                        lineItem.connect_if_possible(items[-1], 5)
2290
                    else:
2291
                        pt = lineItem.start_point()
2292
                        selected = [item for item in self.graphicsView.scene().items(QPointF(pt[0], pt[1])) if
2293
                                    type(item) is QEngineeringConnectorItem or type(item) is QEngineeringLineItem]
2294
                        if selected and selected[0] is not lineItem:
2295
                            if type(selected[0]) is QEngineeringConnectorItem:
2296
                                lineItem.connect_if_possible(selected[0].parent, 5)
2297
                            else:
2298
                                detector.connectLineToLine(selected[0], lineItem, 5)
2299

    
2300
                    items.append(lineItem)
2301
                    self.graphicsView.scene().addItem(lineItem)
2302

    
2303
                pt = items[-1].end_point()
2304
                selected = [item for item in self.graphicsView.scene().items(QPointF(pt[0], pt[1])) if
2305
                            (type(item) is QEngineeringConnectorItem and item.parentItem() is not items[-1]) or
2306
                            (type(item) is QEngineeringLineItem and item is not items[-1])]
2307
                if selected and selected[0] is not items[-1]:
2308
                    if type(selected[0]) is QEngineeringConnectorItem:
2309
                        items[-1].connect_if_possible(selected[0].parent, 5)
2310
                    else:
2311
                        detector.connectLineToLine(selected[0], items[-1], 5)
2312

    
2313
                self._scene.undo_stack.push(CreateCommand(self._scene, items))
2314
        finally:
2315
            self.graphicsView.scene().removeItem(home_pane.ui.toolButtonLine.tag._polyline)
2316
            home_pane.ui.toolButtonLine.tag.reset()
2317

    
2318
    def onCommandRejected(self, cmd=None):
2319
        """command is rejected"""
2320
        try:
2321
            home_pane = self.ribbon.get_pane('Home')
2322
            visualization_pane = self.ribbon.get_pane('Home Visualization')
2323
            if type(cmd) is PlaceLineCommand.PlaceLineCommand:
2324
                if home_pane.ui.toolButtonLine.tag._polyline:
2325
                    self.graphicsView.scene().removeItem(home_pane.ui.toolButtonLine.tag._polyline)
2326
                self.graphicsView.scene().update()
2327
                home_pane.ui.toolButtonLine.tag.reset()
2328

    
2329
                home_pane.ui.toolButtonLine.setChecked(False)
2330
            elif type(cmd) is AreaZoomCommand.AreaZoomCommand:
2331
                visualization_pane.ui.toolButtonZoom.setChecked(False)
2332
            elif type(cmd) is AreaOcrCommand.AreaOcrCommand:
2333
                home_pane.ui.toolButtonOCR.setChecked(False)
2334
            elif type(cmd) is PlacePolygonCommand.PlacePolygonCommand:
2335
                home_pane.ui.toolButtonVendor.setChecked(False)
2336
            else:
2337
                if hasattr(home_pane.ui.toolButtonVendor, 'tag') and home_pane.ui.toolButtonVendor.tag._polyline:
2338
                    self.graphicsView.scene().removeItem(home_pane.ui.toolButtonVendor.tag._polyline)
2339
                    self.graphicsView.scene().update()
2340
                    home_pane.ui.toolButtonVendor.tag.reset()
2341
                home_pane.ui.toolButtonLine.setChecked(False)
2342
                visualization_pane.ui.toolButtonZoom.setChecked(False)
2343
                home_pane.ui.toolButtonOCR.setChecked(False)
2344
                home_pane.ui.toolButtonVendor.setChecked(False)
2345
        finally:
2346
            self.graphicsView.useDefaultCommand()
2347

    
2348
    def on_view_toggle(self, key: int) -> None:
2349
        """view toggled"""
2350

    
2351
        view_pane = self.ribbon.get_pane('View')
2352
        if key == Qt.Key_1:
2353
            checked = view_pane.ui.toolButtonViewImageDrawing.isChecked()
2354
            self.onViewImageDrawing(not checked)
2355
            view_pane.ui.toolButtonViewImageDrawing.setChecked(not checked)
2356
        elif key == Qt.Key_2:
2357
            checked = view_pane.ui.toolButtonViewText.isChecked()
2358
            self.onViewText(not checked)
2359
            view_pane.ui.toolButtonViewText.setChecked(not checked)
2360
        elif key == Qt.Key_3:
2361
            checked = view_pane.ui.toolButtonViewSymbol.isChecked()
2362
            self.onViewSymbol(not checked)
2363
            view_pane.ui.toolButtonViewSymbol.setChecked(not checked)
2364
        elif key == Qt.Key_4:
2365
            checked = view_pane.ui.toolButtonViewLine.isChecked()
2366
            self.onViewLine(not checked)
2367
            view_pane.ui.toolButtonViewLine.setChecked(not checked)
2368
        elif key == Qt.Key_5:
2369
            checked = view_pane.ui.toolButtonViewUnknown.isChecked()
2370
            self.onViewUnknown(not checked)
2371
            view_pane.ui.toolButtonViewUnknown.setChecked(not checked)
2372
        elif key == Qt.Key_6:
2373
            checked = view_pane.ui.toolButtonViewInconsistency.isChecked()
2374
            self.onViewInconsistency(not checked)
2375
            view_pane.ui.toolButtonViewInconsistency.setChecked(not checked)
2376
        elif key == Qt.Key_7:
2377
            checked = view_pane.ui.toolButtonViewVendorArea.isChecked()
2378
            self.onViewVendorArea(not checked)
2379
            view_pane.ui.toolButtonViewVendorArea.setChecked(not checked)
2380
        elif key == 96:  # '~' key
2381
            checked = view_pane.ui.toolButtonViewDrawingOnly.isChecked()
2382
            self.onViewDrawingOnly(not checked)
2383
            view_pane.ui.toolButtonViewDrawingOnly.setChecked(not checked)
2384

    
2385
    def keyPressEvent(self, event):
2386
        """restore to default command when user press Escape key"""
2387
        try:
2388
            if event.key() == Qt.Key_Escape:
2389
                checked = self.checked_action()
2390
                if checked:
2391
                    checked.setChecked(False)
2392
                    self.graphicsView.useDefaultCommand()
2393
            elif event.key() == Qt.Key_M:  # merge text as vertical
2394
                from TextInfo import TextInfo
2395

    
2396
                textItems = [text for text in self.graphicsView.scene().selectedItems() if
2397
                             issubclass(type(text), QEngineeringTextItem)]
2398
                if not textItems or len(textItems) is 1:
2399
                    return
2400

    
2401
                angle = None
2402
                for item in textItems:
2403
                    if angle is None:
2404
                        angle = item.angle
2405
                    else:
2406
                        if angle != item.angle:
2407
                            return
2408

    
2409
                modifiers = QApplication.keyboardModifiers()
2410
                enter_or_space = ' ' if modifiers == Qt.ControlModifier else '\n'
2411
                x_or_y = 0 if (modifiers == Qt.ControlModifier and angle == 0) or (modifiers != Qt.ControlModifier and angle == 1.57) else 1
2412

    
2413
                textItems = sorted(textItems, key=lambda text: text.loc[x_or_y]) if textItems[0].angle == 0 else ( \
2414
                    sorted(textItems, key=lambda text: text.loc[x_or_y]) if textItems[0].angle == 1.57 else ( \
2415
                        sorted(textItems, key=lambda text: text.loc[x_or_y], reverse=True) if textItems[0].angle == 4.71 else \
2416
                            sorted(textItems, key=lambda text: text.loc[x_or_y], reverse=True)))
2417

    
2418
                if textItems[0].angle == 1.57 and modifiers == Qt.ControlModifier:
2419
                    textItems.reverse()
2420

    
2421
                minX = sys.maxsize
2422
                minY = sys.maxsize
2423
                maxX = 0
2424
                maxY = 0
2425
                newText = ''
2426

    
2427
                for text in textItems:
2428
                    if text.loc[0] < minX: minX = text.loc[0]
2429
                    if text.loc[1] < minY: minY = text.loc[1]
2430
                    if text.loc[0] + text.size[0] > maxX: maxX = text.loc[0] + text.size[0]
2431
                    if text.loc[1] + text.size[1] > maxY: maxY = text.loc[1] + text.size[1]
2432
                    newText = newText + text.text() + enter_or_space
2433
                    text.transfer.onRemoved.emit(text)
2434
                newText = newText[:-1]
2435

    
2436
                textInfo = TextInfo(newText, minX, minY, maxX - minX, maxY - minY, textItems[0].angle)
2437
                x = textInfo.getX()
2438
                y = textInfo.getY()
2439
                angle = textInfo.getAngle()
2440
                text = textInfo.getText()
2441
                width = textInfo.getW()
2442
                height = textInfo.getH()
2443
                item = TextItemFactory.instance().createTextItem(textInfo)
2444
                if item is not None:
2445
                    item.loc = [x, y]
2446
                    item.size = (width, height)
2447
                    item.angle = angle
2448
                    item.area = textItems[0].area
2449
                    item.setDefaultTextColor(Qt.blue)
2450
                    item.addTextItemToScene(self.graphicsView.scene())
2451
                    item.transfer.onRemoved.connect(self.itemRemoved)
2452
            elif event.key() == Qt.Key_D:
2453
                # pop up development toolkit dialog
2454
                from DevelopmentToolkitDialog import QDevelopmentToolkitDialog
2455

    
2456
                modifiers = QApplication.keyboardModifiers()
2457
                if modifiers == Qt.ControlModifier:
2458
                    dlg = QDevelopmentToolkitDialog(self, self.graphicsView)
2459
                    dlg.show()
2460
            elif event.key() == Qt.Key_I:
2461
                # insert symbol item that is selected symbol in tree to main window if symbol already selected on main window, replace
2462
                index = self.symbolTreeWidget.currentIndex()
2463
                proxy_model = self.symbolTreeWidget.model()
2464
                items = [proxy_model.sourceModel().itemFromIndex(proxy_model.mapToSource(index))]
2465
                if items and hasattr(items[0], 'svgFilePath'):
2466
                    symData = items[0].data(self.symbolTreeWidget.TREE_DATA_ROLE)
2467
                    symName = symData.getName()
2468
                else:
2469
                    return
2470

    
2471
                symbolItems = [symbol for symbol in self.graphicsView.scene().selectedItems() if
2472
                               issubclass(type(symbol), SymbolSvgItem)]
2473
                old_symbol = None
2474
                if symbolItems and len(symbolItems) is 1:
2475
                    old_symbol = symbolItems[0]
2476
                    #scenePos = QPoint(old_symbol.origin[0], old_symbol.origin[1])
2477
                    scenePos = old_symbol.mapToScene(old_symbol.transformOriginPoint())
2478
                    old_symbol.transfer.onRemoved.emit(old_symbol)
2479
                else:
2480
                    scenePos = self.current_pos
2481

    
2482
                svg = QtImageViewer.createSymbolObject(symName)
2483
                QtImageViewer.matchSymbolToLine(self.graphicsView.scene(), svg, scenePos, angle=old_symbol.angle if old_symbol else 0.0)
2484

    
2485
                if old_symbol and svg:
2486
                    from ReplaceCommand import ReplaceCommand
2487

    
2488
                    cmd = ReplaceCommand(self.graphicsView.scene(), old_symbol, svg)
2489
                    self._scene.undo_stack.push(cmd)
2490
                    return
2491
            elif event.key() == Qt.Key_J:
2492
                # insert and connect symbol item that is selected symbol in tree to selected symbol
2493
                index = self.symbolTreeWidget.currentIndex()
2494
                proxy_model = self.symbolTreeWidget.model()
2495
                items = [proxy_model.sourceModel().itemFromIndex(proxy_model.mapToSource(index))]
2496
                if items and hasattr(items[0], 'svgFilePath'):
2497
                    symData = items[0].data(self.symbolTreeWidget.TREE_DATA_ROLE)
2498
                    symName = symData.getName()
2499
                else:
2500
                    return
2501

    
2502
                symbolItems = [symbol for symbol in self.graphicsView.scene().selectedItems() if
2503
                               issubclass(type(symbol), SymbolSvgItem)]
2504
                if symbolItems and len(symbolItems) is not 1:
2505
                    return
2506
                    
2507
                target_symbol = symbolItems[0]
2508
                index =  [index for index in range(len(target_symbol.conn_type)) \
2509
                            if target_symbol.conn_type[index] == 'Primary' or target_symbol.conn_type[index] == 'Secondary']
2510
                for connector in target_symbol.connectors:
2511
                    svg = QtImageViewer.createSymbolObject(symName)
2512
                    if len(svg.connectors) > 1: 
2513
                        if ((target_symbol.conn_type and target_symbol.connectors.index(connector) in index) or not target_symbol.conn_type) and \
2514
                                    (not connector.connectedItem or (connector.connectedItem and type(connector.connectedItem) is QEngineeringLineItem)):
2515
                            QtImageViewer.matchSymbolToLine(self.graphicsView.scene(), svg, connector.sceneBoundingRect().center())
2516
                    elif len(svg.connectors) == 1:
2517
                        if ((target_symbol.conn_type and target_symbol.connectors.index(connector) in index) or not target_symbol.conn_type) and \
2518
                                    not connector.connectedItem:
2519
                            QtImageViewer.matchSymbolToLine(self.graphicsView.scene(), svg, connector.sceneBoundingRect().center())
2520

    
2521
                if target_symbol:
2522
                    return
2523
            elif event.key() == Qt.Key_X:
2524
                app_doc_data = AppDocData.instance()
2525
                configs = app_doc_data.getAppConfigs('app', 'mode')
2526
                if configs and 1 == len(configs) and 'advanced' == configs[0].value:
2527
                    advanced = True
2528
                    items = self.graphicsView.scene().selectedItems()
2529
                    if items:
2530
                        item = self.symbolTreeWidget.currentItem()
2531
                        if item:
2532
                            self.symbolTreeWidget.showSymbolEditorDialog(item, 0)
2533
            elif event.key() == Qt.Key_F6:
2534
                from DEXPI import scene_to_dexpi
2535

    
2536
                app_doc_data = AppDocData.instance()
2537
                scene_to_dexpi('D:\\Temp\\DEXPI.xml', app_doc_data.activeDrawing.name, self.graphicsView.scene())
2538

    
2539
            QMainWindow.keyPressEvent(self, event)
2540
        except Exception as ex:
2541
            message = f"error occurred({repr(ex)}) in {sys.exc_info()[-1].tb_frame.f_code.co_filename}:" \
2542
                      f"{sys.exc_info()[-1].tb_lineno}"
2543
            self.addMessage.emit(MessageType.Error, message)
2544

    
2545
    def recognize(self):
2546
        """recognize symbol, text and line for selected drawings"""
2547
        from datetime import datetime
2548
        from License import QLicenseDialog
2549

    
2550
        # save alarm
2551
        self.save_alarm_enable(False)
2552

    
2553
        app_doc_data = AppDocData.instance()
2554
        current_drawing, currentPid = None, None
2555

    
2556
        if self.graphicsView.hasImage():
2557
            current_drawing = app_doc_data.activeDrawing
2558
            currentPid = app_doc_data.activeDrawing.name
2559

    
2560
        # get checked drawings
2561
        drawing_top = self.treeWidgetDrawingList.topLevelItem(0)
2562
        count = drawing_top.childCount()
2563
        checked_drawings = {}
2564
        for idx in range(count):
2565
            child = drawing_top.child(idx)
2566
            if child.checkState(0) == Qt.Checked and child.data(Qt.UserRole, 0):
2567
                checked_drawings[child.data(Qt.UserRole, 0)] = child
2568
        # up to here
2569

    
2570
        # if there is no checked drawing
2571
        if current_drawing and currentPid and not checked_drawings:
2572
            for idx in range(count):
2573
                child = drawing_top.child(idx)
2574
                if child.data(Qt.UserRole, 0) is current_drawing:
2575
                    checked_drawings[child.data(Qt.UserRole, 0)] = child
2576

    
2577
        if not checked_drawings:
2578
            self.showImageSelectionMessageBox()
2579
            return
2580

    
2581
        try:
2582
            self.on_clear_log()
2583
            dlg = QRecognitionDialog(self, [drawing for drawing in checked_drawings.keys()])
2584
            dlg.exec_()
2585

    
2586
            if current_drawing and current_drawing in checked_drawings.keys() and dlg.isTreated:
2587
                self.open_image_drawing(current_drawing, force=True, ocrUnknown=dlg.ui.checkBoxOCRUnknown.isChecked())
2588

    
2589
            # save working date-time
2590
            _now = datetime.now().strftime('%Y-%m-%d %H:%M:%S')
2591
            for drawing, tree_item in checked_drawings.items():
2592
                drawing.datetime = _now
2593
                tree_item.setText(1, _now)
2594
            #app_doc_data.saveDrawings(checked_drawings.keys())
2595
            self.changeViewCheckedState(True)
2596
            # count up for recognition
2597
            QLicenseDialog.count_up()
2598
            # up to here
2599
        except Exception as ex:
2600
            message = f"error occurred({repr(ex)}) in {sys.exc_info()[-1].tb_frame.f_code.co_filename}:" \
2601
                      f"{sys.exc_info()[-1].tb_lineno}"
2602
            self.addMessage.emit(MessageType.Error, message)
2603

    
2604
        # save alarm
2605
        self.save_alarm_enable(True, True)
2606

    
2607
    '''
2608
        @brief      remove item from tree widget and then remove from scene
2609
        @date       2018.05.25
2610
        @author     Jeongwoo
2611
    '''
2612

    
2613
    def itemRemoved(self, item):
2614
        try:
2615
            if type(item) is QEngineeringErrorItem:
2616
                # remove error item from inconsistency list
2617
                for row in range(self.tableWidgetInconsistency.rowCount()):
2618
                    if item is self.tableWidgetInconsistency.item(row, 0).tag:
2619
                        self.tableWidgetInconsistency.removeRow(row)
2620
                        break
2621

    
2622
                if item.scene() is not None:
2623
                    item.scene().removeItem(item)
2624
                del item
2625
            else:
2626
                remove_scene = item.scene()
2627
                self.itemTreeWidget.itemRemoved(item)
2628

    
2629
                if remove_scene:
2630
                    matches = [_item for _item in remove_scene.items() if
2631
                            hasattr(_item, 'connectors') and [connector for connector in _item.connectors if
2632
                                                                connector.connectedItem is item]]
2633
                    for match in matches:
2634
                        for connector in match.connectors:
2635
                            if connector.connectedItem is item:
2636
                                connector.connectedItem = None
2637
                                connector.highlight(False)
2638

    
2639
                # matches = [_item for _item in self.graphicsView.scene().items() if hasattr(_item, 'remove_assoc_item')]
2640
                # for _item in matches:
2641
                #    _item.remove_assoc_item(item)
2642

    
2643
                app_doc_data = AppDocData.instance()
2644
                if type(item) is QEngineeringLineNoTextItem and item in app_doc_data.tracerLineNos:
2645
                    app_doc_data.tracerLineNos.pop(app_doc_data.tracerLineNos.index(item))
2646

    
2647
                if type(item) is QEngineeringLineItem and item in app_doc_data.lines:
2648
                    app_doc_data.lines.remove(item)
2649

    
2650
                if remove_scene:
2651
                    matches = [_item for _item in remove_scene.items() if
2652
                            type(_item) is QEngineeringLineNoTextItem]
2653
                    matches.extend([lineNo for lineNo in app_doc_data.tracerLineNos if
2654
                                    type(lineNo) is QEngineeringTrimLineNoTextItem])
2655
                    for match in matches:
2656
                        if item is match.prop('From'):
2657
                            match.set_property('From', None)
2658
                        if item is match.prop('To'):
2659
                            match.set_property('To', None)
2660

    
2661
                        for run_index in reversed(range(len(match.runs))):
2662
                            run = match.runs[run_index]
2663
                            if item in run.items:
2664
                                index = run.items.index(item)
2665
                                run.items.pop(index)
2666
                                if not run.items:
2667
                                    run.explode()
2668
                                    if type(match) is QEngineeringTrimLineNoTextItem and not match.runs:
2669
                                        app_doc_data.tracerLineNos.pop(app_doc_data.tracerLineNos.index(match))
2670
                                # break
2671

    
2672
                if remove_scene:
2673
                    matches = [_item for _item in remove_scene.items() if hasattr(_item, 'owner')]
2674
                    for match in matches:
2675
                        if match.owner is item:
2676
                            match.owner = None
2677

    
2678
                    matches = [_item for _item in remove_scene.items() if hasattr(_item, 'attrs')]
2679
                    # done = False
2680
                    for match in matches:
2681
                        assocs = match.associations()
2682
                        for assoc in assocs:
2683
                            if item is assoc:
2684
                                keys = match.attrs.keys()
2685
                                for attr in keys:
2686
                                    if attr.AssocItem and str(item.uid) == str(attr.AssocItem.uid):
2687
                                        attr.AssocItem = None
2688
                                        match.attrs[attr] = ''
2689
                                        # done = True
2690
                                match.remove_assoc_item(item)
2691
                                break
2692
                        # if done: break
2693

    
2694
                if item.scene() is not None: item.scene().removeItem(item)
2695
        except Exception as ex:
2696
            message = 'error occurred({}) in {}:{}'.format(ex, sys.exc_info()[-1].tb_frame.f_code.co_filename,
2697
                                                           sys.exc_info()[-1].tb_lineno)
2698
            self.addMessage.emit(MessageType.Error, message)
2699
        '''
2700
        finally:
2701
            if hasattr(item, '_cond'):
2702
                item._cond.wakeAll()
2703
        '''
2704

    
2705

    
2706
    def connect_attributes(self, MainWindow):
2707
        """connect attributes to symbol"""
2708
        from LineNoTracer import LineNoTracer
2709
        from ConnectAttrDialog import QConnectAttrDialog
2710

    
2711
        if not self.graphicsView.hasImage():
2712
            self.showImageSelectionMessageBox()
2713
            return
2714

    
2715
        # save alarm
2716
        self.save_alarm_enable(False)
2717

    
2718
        try:
2719
            dlg = QConnectAttrDialog(self, self.graphicsView.scene())
2720
            dlg.setWindowFlags(self.windowFlags() & ~Qt.WindowCloseButtonHint & ~Qt.WindowContextHelpButtonHint)
2721
            dlg.exec_()
2722
            if dlg.isRunned:
2723
                self.refresh_item_list()
2724

    
2725
                if dlg.validation_checked:
2726
                    self.onValidation()
2727

    
2728
                self.graphicsView.invalidateScene()
2729
        except Exception as ex:
2730
            message = 'error occurred({}) in {}:{}'.format(ex, sys.exc_info()[-1].tb_frame.f_code.co_filename,
2731
                                                           sys.exc_info()[-1].tb_lineno)
2732
            self.addMessage.emit(MessageType.Error, message)
2733
        finally:
2734
            # save alarm
2735
            self.save_alarm_enable(True)
2736

    
2737
    def postDetectLineProcess(self):
2738
        '''
2739
            @brief  check allowables among undetected items
2740
            @author euisung
2741
            @date   2018.11.15
2742
            @history    2018.11.15  euisung    no more used, moved to TextItemFactoy isLineNo()
2743
        '''
2744
        from TextItemFactory import TextItemFactory
2745

    
2746
        appDocData = AppDocData.instance()
2747

    
2748
        tableNames = ["Fluid Code", "Insulation Purpose", "PnID Number", "Piping Materials Class", "Unit Number"]
2749
        tableDatas = []
2750
        for tableName in tableNames:
2751
            tableNameFormat = tableName.replace(' ', '').replace('&&', 'n')
2752
            tableDatas.append(appDocData.getCodeTable(tableNameFormat))
2753

    
2754
        items = self.graphicsView.scene().items()
2755
        for item in items:
2756
            if type(item) is not QEngineeringTextItem:
2757
                continue
2758
            text = item.text()
2759
            for tableData in tableDatas:
2760
                for data in tableData:
2761
                    if data[3] == '':
2762
                        continue
2763
                    else:
2764
                        allows = data[3].split(',')
2765
                        for allow in allows:
2766
                            text = text.replace(allow, data[1])
2767

    
2768
            lineItem = TextItemFactory.instance().createTextItem(text)
2769
            if type(lineItem) is QEngineeringLineNoTextItem:
2770
                lineItem.loc = item.loc
2771
                lineItem.size = item.size
2772
                lineItem.angle = item.angle
2773
                lineItem.area = item.area
2774
                # lineItem.addTextItemToScene(self.graphicsView.scene())
2775
                lineItem.transfer.onRemoved.connect(self.itemRemoved)
2776
                item.transfer.onRemoved.emit(item)
2777
                appDocData.lineNos.append(lineItem)
2778

    
2779
    def init_add_tree_item(self, line_no_tree_item, run_item):
2780
        """ insert symbol item and find line no as owner """
2781
        # insert
2782
        self.itemTreeWidget.addTreeItem(line_no_tree_item, run_item)
2783
        # find
2784
        self.itemTreeWidget.addTreeItem(line_no_tree_item, run_item)
2785

    
2786
    def load_drawing(self, drawing):
2787
        """ load drawing """
2788
        from EngineeringRunItem import QEngineeringRunItem
2789
        from QEngineeringTrimLineNoTextItem import QEngineeringTrimLineNoTextItem
2790

    
2791
        app_doc_data = AppDocData.instance()
2792
        try:
2793
            symbols = []
2794
            lines = []
2795

    
2796
            components = app_doc_data.get_components(drawing.UID)
2797
            maxValue = len(components) * 2
2798
            self.progress.setMaximum(maxValue) if maxValue > 0 else None
2799

    
2800
            """ parsing all symbols """
2801
            for symbol in [component for component in components if int(component['SymbolType_UID']) != -1]:
2802
                item = SymbolSvgItem.from_database(symbol)
2803
                if item is not None:
2804
                    item.transfer.onRemoved.connect(self.itemRemoved)
2805
                    symbols.append(item)
2806
                    app_doc_data.symbols.append(item)
2807
                    item.addSvgItemToScene(self.graphicsView.scene())
2808
                else:
2809
                    pt = [float(symbol['X']), float(symbol['Y'])]
2810
                    size = [float(symbol['Width']), float(symbol['Height'])]
2811
                    angle = float(symbol['Rotation'])
2812
                    item = QGraphicsBoundingBoxItem(pt[0], pt[1], size[0], size[1])
2813
                    item.isSymbol = True
2814
                    item.angle = angle
2815
                    item.setPen(QPen(Qt.red, 5, Qt.SolidLine))
2816
                    self.graphicsView.scene().addItem(item)
2817
                    item.transfer.onRemoved.connect(self.itemRemoved)
2818

    
2819
                self.progress.setValue(self.progress.value() + 1)
2820

    
2821
            QApplication.processEvents()
2822

    
2823
            # parse texts
2824
            for text in [component for component in components if
2825
                         component['Name'] == 'Text' and component['SymbolType_UID'] == -1]:
2826
                item = QEngineeringTextItem.from_database(text)
2827
                if item is not None:
2828
                    item.uid = text['UID']
2829
                    item.attribute = text['Value']
2830
                    name = text['Name']
2831
                    item.transfer.onRemoved.connect(self.itemRemoved)
2832
                    item.addTextItemToScene(self.graphicsView.scene())
2833

    
2834
                self.progress.setValue(self.progress.value() + 1)
2835

    
2836
            QApplication.processEvents()
2837

    
2838
            # note
2839
            for note in [component for component in components if
2840
                         component['Name'] == 'Note' and component['SymbolType_UID'] == -1]:
2841
                item = QEngineeringTextItem.from_database(note)
2842
                if item is not None:
2843
                    item.uid = note['UID']
2844
                    attributeValue = note['Value']
2845
                    name = note['Name']
2846
                    item.transfer.onRemoved.connect(self.itemRemoved)
2847
                    item.addTextItemToScene(self.graphicsView.scene())
2848

    
2849
                self.progress.setValue(self.progress.value() + 1)
2850

    
2851
            QApplication.processEvents()
2852

    
2853
            for line in [component for component in components if
2854
                         component['Name'] == 'Line' and component['SymbolType_UID'] == -1]:
2855
                item = QEngineeringLineItem.from_database(line)
2856
                if item:
2857
                    item.transfer.onRemoved.connect(self.itemRemoved)
2858
                    self.graphicsView.scene().addItem(item)
2859
                    lines.append(item)
2860

    
2861
                self.progress.setValue(self.progress.value() + 1)
2862

    
2863
            QApplication.processEvents()
2864

    
2865
            for unknown in [component for component in components if
2866
                            component['Name'] == 'Unknown' and component['SymbolType_UID'] == -1]:
2867
                item = QEngineeringUnknownItem.from_database(unknown)
2868
                item.transfer.onRemoved.connect(self.itemRemoved)
2869
                if item is not None:
2870
                    item.transfer.onRemoved.connect(self.itemRemoved)
2871
                    self.graphicsView.scene().addItem(item)
2872

    
2873
                self.progress.setValue(self.progress.value() + 1)
2874

    
2875
            QApplication.processEvents()
2876

    
2877
            for component in [component for component in components if
2878
                              component['Name'] == 'Line NO' and component['SymbolType_UID'] == -1]:
2879
                line_no = QEngineeringLineNoTextItem.from_database(component)
2880
                if type(line_no) is QEngineeringLineNoTextItem:
2881
                    line_no.transfer.onRemoved.connect(self.itemRemoved)
2882
                    self.addTextItemToScene(line_no)
2883
                    line_no_tree_item = self.itemTreeWidget.addTreeItem(self.itemTreeWidget.root, line_no)
2884

    
2885
                    runs = app_doc_data.get_pipe_runs(str(line_no.uid))
2886
                    if not runs: continue
2887
                    for run in runs:
2888
                        line_run = QEngineeringRunItem()
2889
                        run_items = app_doc_data.get_pipe_run_items(run['UID'])
2890
                        for record in run_items:
2891
                            uid = record['Components_UID']
2892
                            run_item = self.graphicsView.findItemByUid(uid)
2893
                            if run_item is not None:
2894
                                run_item._owner = line_no
2895
                                line_run.items.append(run_item)
2896
                        line_run.owner = line_no
2897
                        line_no.runs.append(line_run)
2898

    
2899
                        for run_item in line_run.items:
2900
                            if issubclass(type(run_item), SymbolSvgItem):
2901
                                self.init_add_tree_item(line_no_tree_item, run_item)
2902

    
2903
                self.progress.setValue(self.progress.value() + 1)
2904
            QApplication.processEvents()
2905

    
2906
            for component in [component for component in components if
2907
                              component['Name'] == 'Trim Line NO' and component['SymbolType_UID'] == -1]:
2908
                line_no = QEngineeringTrimLineNoTextItem()
2909
                line_no.uid = uuid.UUID(component['UID'])
2910

    
2911
                runs = app_doc_data.get_pipe_runs(str(line_no.uid))
2912
                if not runs: continue
2913

    
2914
                line_no_tree_item = self.itemTreeWidget.addTreeItem(self.itemTreeWidget.root, line_no)
2915

    
2916
                for run in runs:
2917
                    line_run = QEngineeringRunItem()
2918
                    run_items = app_doc_data.get_pipe_run_items(run['UID'])
2919
                    for record in run_items:
2920
                        uid = record['Components_UID']
2921
                        run_item = self.graphicsView.findItemByUid(uid)
2922
                        if run_item is not None:
2923
                            run_item.owner = line_no
2924
                            line_run.items.append(run_item)
2925
                    line_run.owner = line_no
2926
                    line_no.runs.append(line_run)
2927

    
2928
                    for run_item in line_run.items:
2929
                        if issubclass(type(run_item), SymbolSvgItem):
2930
                            self.init_add_tree_item(line_no_tree_item, run_item)
2931

    
2932
                app_doc_data.tracerLineNos.append(line_no)
2933

    
2934
                self.progress.setValue(self.progress.value() + 1)
2935

    
2936
            for component in [component for component in components if
2937
                              component['Name'] == 'VendorPackage' and component['SymbolType_UID'] == -1]:
2938
                item = QEngineeringVendorItem.from_database(component)
2939
                if item is not None:
2940
                    item.transfer.onRemoved.connect(self.itemRemoved)
2941
                    self.graphicsView.scene().addItem(item)
2942

    
2943
            # connect flow item to line
2944
            for line in lines:
2945
                line.update_arrow()
2946
                app_doc_data.lines.append(line)
2947
            # for flowMark in [item for item in symbols if type(item) is QEngineeringFlowMarkItem]:
2948
            #    for line in lines:
2949
            #        if flowMark.owner is line:
2950
            #            line._flowMark.append(flowMark)
2951
            #            flowMark.setParentItem(line)
2952
            # up to here
2953

    
2954
            """ update scene """
2955
            self.graphicsView.scene().update(self.graphicsView.sceneRect())
2956
            for item in self.graphicsView.scene().items():
2957
                up_progress = False
2958
                # binding items
2959
                if hasattr(item, 'owner'):
2960
                    item.owner
2961
                    up_progress = True
2962
                if hasattr(item, 'connectors'):
2963
                    for connector in item.connectors:
2964
                        connector.connectedItem
2965
                    up_progress = True
2966

    
2967
                if up_progress:
2968
                    self.progress.setValue(self.progress.value() + 1)
2969
            
2970
            for item in self.graphicsView.scene().items():
2971
                item.setVisible(True)
2972

    
2973
        except Exception as ex:
2974
            message = 'error occurred({}) in {}:{}'.format(ex, sys.exc_info()[-1].tb_frame.f_code.co_filename,
2975
                                                           sys.exc_info()[-1].tb_lineno)
2976
            self.addMessage.emit(MessageType.Error, message)
2977
        finally:
2978
            app_doc_data.clearTempDBData()
2979
            self.itemTreeWidget.update_item_count()
2980
            self.itemTreeWidget.expandAll()
2981
            # self.graphicsView.scene().blockSignals(False)
2982

    
2983
    '''
2984
        @brief      load recognition result
2985
        @author     humkyung
2986
        @date       2018.04.??
2987
        @history    humkyung 2018.01.12 parse originalpoint and connectionpoint
2988
                    Jeongwoo 2018.04.17 add QGraphicItem with Rotated text
2989
                    Jeongwoo 2018.04.23 Change to Draw texts on QEngineeringTextItem
2990
                    humkyung 2018.04.23 connect item remove slot to result tree
2991
                    Jeongwoo 2018.04.25 Add if state with QEngineeringNoteItem
2992
                    Jeongwoo 2018.04.26 Change method to create TextItem object with TextItemFactory
2993
                    Jeongwoo 2018.05.03 Change method to draw Svg Item on Scene (svg.addSvgItemToScene)
2994
                    Jeongwoo 2018.05.29 Change method name / Change method to add item / Add Line item
2995
                    Jeongwoo 2018.05.30 Add parameters on SymbolSvgItem.__init__() (parentSymbol, childSymbol) / Change method name / Change XML NODE NAMES
2996
                    Jeongwoo 2018.06.12 Add LineNoTextItem from LINE_NO
2997
                    Jeongwoo 2018.06.14 Add UnknownItem from UNKNOWN
2998
                    Jeongwoo 2018.06.18 Update Scene after all item added
2999
                                        Add connect on unknown item
3000
                                        Add [transfer] for using pyqtSignal
3001
                    kyouho  2018.07.12  Add line property logic
3002
                    humkyung 2018.08.22 show progress while loading xml file
3003
                    2018.11.22      euisung     fix note road
3004
    '''
3005

    
3006
    def load_recognition_result_from_xml(self, drawing):
3007
        # Yield successive n-sized
3008
        # chunks from l.
3009
        def divide_chunks(l, n):
3010
            # looping till length l
3011
            for i in range(0, len(l), n):
3012
                yield l[i:i + n]
3013

    
3014
        def update_items(items):
3015
            for item in items:
3016
                # binding items
3017
                item.owner
3018
                for connector in item.connectors:
3019
                    connector.connectedItem
3020

    
3021
            return items
3022

    
3023
        import concurrent.futures as futures
3024
        from xml.etree.ElementTree import Element, SubElement, dump, ElementTree, parse
3025
        from App import App
3026
        from EngineeringRunItem import QEngineeringRunItem
3027
        from QEngineeringTrimLineNoTextItem import QEngineeringTrimLineNoTextItem
3028
        from EngineeringGraphicsLineItem import QEngineeringGraphicsLineItem
3029

    
3030
        app_doc_data = AppDocData.instance()
3031

    
3032
        try:
3033
            file_name = os.path.splitext(os.path.basename(drawing.file_path))[0]
3034
            path = os.path.join(app_doc_data.getCurrentProject().getTempPath(), file_name + '.xml')
3035
            self.graphicsView.scene().blockSignals(True)
3036

    
3037
            symbols = []
3038
            lines = []
3039

    
3040
            xml = parse(path)
3041
            root = xml.getroot()
3042

    
3043
            maxValue = 0
3044
            maxValue = maxValue + len(list(root.iter('SYMBOL'))) - \
3045
                       len(list(root.iterfind('LINENOS/LINE_NO/RUN/SYMBOL'))) - \
3046
                       len(list(root.iterfind('TRIMLINENOS/TRIM_LINE_NO/RUN/SYMBOL')))
3047
            maxValue = maxValue + len(list(root.iterfind('TEXTINFOS/ATTRIBUTE')))
3048
            maxValue = maxValue + len(list(root.iterfind('NOTES/ATTRIBUTE')))
3049
            maxValue = maxValue + len(list(root.iter('LINE_NO')))
3050
            maxValue = maxValue + len(list(root.iter('LINE'))) - \
3051
                       len(list(root.iterfind('LINENOS/LINE_NO/RUN/LINE'))) - \
3052
                       len(list(root.iterfind('TRIMLINENOS/TRIM_LINE_NO/RUN/LINE')))
3053
            maxValue = maxValue + len(list(root.iter('GRAPHICS_LINE')))
3054
            maxValue = maxValue + len(list(root.iter('UNKNOWN')))
3055
            # maxValue = maxValue + len(list(root.iter('SIZETEXT')))
3056
            maxValue = maxValue + len(list(root.iter('TRIM_LINE_NO')))
3057
            maxValue *= 2
3058
            self.progress.setMaximum(maxValue) if maxValue > 0 else None
3059

    
3060
            """ parsing all symbols """
3061
            """
3062
            with futures.ThreadPoolExecutor(max_workers=App.THREAD_MAX_WORKER) as pool:
3063
                future_symbol = {pool.submit(SymbolSvgItem.fromXml, symbol): symbol for symbol in root.find('SYMBOLS').iter('SYMBOL')}
3064

3065
                for future in futures.as_completed(future_symbol):
3066
                    try:
3067
                        item = future.result()
3068
                        if item:
3069
                            if item is not None:
3070
                                item.transfer.onRemoved.connect(self.itemRemoved)
3071
                                symbols.append(item)
3072
                                docData.symbols.append(item)
3073
                                self.addSvgItemToScene(item)
3074
                            else:
3075
                                pt = [float(x) for x in symbol.find('LOCATION').text.split(',')]
3076
                                size = [float(x) for x in symbol.find('SIZE').text.split(',')]
3077
                                angle = float(symbol.find('ANGLE').text)
3078
                                item = QGraphicsBoundingBoxItem(pt[0], pt[1], size[0], size[1])
3079
                                item.isSymbol = True
3080
                                item.angle = angle
3081
                                item.setPen(QPen(Qt.red, 5, Qt.SolidLine))
3082
                                self.graphicsView.scene().addItem(item)
3083
                                item.transfer.onRemoved.connect(self.itemRemoved)
3084
                    except Exception as ex:
3085
                        message = 'error occurred({}) in {}:{}'.format(repr(ex), sys.exc_info()[-1].tb_frame.f_code.co_filename,
3086
                                                                       sys.exc_info()[-1].tb_lineno)
3087

3088
            """
3089
            for symbol in root.find('SYMBOLS').iter('SYMBOL'):
3090
                item = SymbolSvgItem.fromXml(symbol)
3091
                if item is not None:
3092
                    item.transfer.onRemoved.connect(self.itemRemoved)
3093
                    symbols.append(item)
3094
                    #app_doc_data.symbols.append(item)
3095
                    item.addSvgItemToScene(self.graphicsView.scene())
3096
                else:
3097
                    pt = [float(x) for x in symbol.find('LOCATION').text.split(',')]
3098
                    size = [float(x) for x in symbol.find('SIZE').text.split(',')]
3099
                    angle = float(symbol.find('ANGLE').text)
3100
                    item = QGraphicsBoundingBoxItem(pt[0], pt[1], size[0], size[1])
3101
                    item.isSymbol = True
3102
                    item.angle = angle
3103
                    item.setPen(QPen(Qt.red, 5, Qt.SolidLine))
3104
                    self.graphicsView.scene().addItem(item)
3105
                    item.transfer.onRemoved.connect(self.itemRemoved)
3106

    
3107
                self.progress.setValue(self.progress.value() + 1)
3108

    
3109
            QApplication.processEvents()
3110

    
3111
            # parse texts
3112
            for text in root.find('TEXTINFOS').iter('ATTRIBUTE'):
3113
                item = QEngineeringTextItem.fromXml(text)
3114
                if item is not None:
3115
                    uid = text.find('UID')
3116
                    attributeValue = text.find('ATTRIBUTEVALUE')
3117
                    name = text.find('NAME').text
3118
                    item.transfer.onRemoved.connect(self.itemRemoved)
3119
                    item.addTextItemToScene(self.graphicsView.scene())
3120
                    # docData.texts.append(item)
3121

    
3122
                    if name == 'TEXT':
3123
                        if uid is not None and attributeValue is not None:
3124
                            item.uid = uid.text
3125
                            item.attribute = attributeValue.text
3126

    
3127
                self.progress.setValue(self.progress.value() + 1)
3128

    
3129
            QApplication.processEvents()
3130

    
3131
            # note
3132
            for text in root.find('NOTES').iter('ATTRIBUTE'):
3133
                item = QEngineeringTextItem.fromXml(text)
3134
                if item is not None:
3135
                    uid = text.find('UID')
3136
                    attributeValue = text.find('ATTRIBUTEVALUE')
3137
                    name = text.find('NAME').text
3138
                    item.transfer.onRemoved.connect(self.itemRemoved)
3139
                    item.addTextItemToScene(self.graphicsView.scene())
3140

    
3141
                    if name == 'NOTE':
3142
                        if uid is not None:
3143
                            item.uid = uid.text
3144

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

    
3147
            QApplication.processEvents()
3148

    
3149
            for line in root.find('LINEINFOS').iter('LINE'):
3150
                item = QEngineeringLineItem.fromXml(line)
3151
                if item:
3152
                    item.transfer.onRemoved.connect(self.itemRemoved)
3153
                    self.graphicsView.scene().addItem(item)
3154
                    lines.append(item)
3155

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

    
3158
            for line in root.find('LINEINFOS').iter('GRAPHICS_LINE'):
3159
                item = QEngineeringGraphicsLineItem.fromXml(line)
3160
                if item:
3161
                    item.transfer.onRemoved.connect(self.itemRemoved)
3162
                    self.graphicsView.scene().addItem(item)
3163

    
3164
                self.progress.setValue(self.progress.value() + 1)
3165

    
3166
            QApplication.processEvents()
3167

    
3168
            for unknown in root.iter('UNKNOWN'):
3169
                item = QEngineeringUnknownItem.fromXml(unknown)
3170
                if item is not None:
3171
                    item.transfer.onRemoved.connect(self.itemRemoved)
3172
                    self.graphicsView.scene().addItem(item)
3173

    
3174
                self.progress.setValue(self.progress.value() + 1)
3175

    
3176
            QApplication.processEvents()
3177

    
3178
            # """ add tree widget """
3179
            # for item in symbols:
3180
            #    docData.symbols.append(item)
3181
            #    self.addSvgItemToScene(item)
3182
            #    self.itemTreeWidget.addTreeItem(self.itemTreeWidget.root, item)
3183

    
3184
            for line_no_node in root.find('LINENOS').iter('LINE_NO'):
3185
                line_no = QEngineeringLineNoTextItem.fromXml(line_no_node)
3186
                if line_no is None: continue
3187
                line_no.transfer.onRemoved.connect(self.itemRemoved)
3188
                line_no.addTextItemToScene(self.graphicsView.scene())
3189
                line_no_tree_item = self.itemTreeWidget.addTreeItem(self.itemTreeWidget.root, line_no)
3190
                if type(line_no) is not QEngineeringLineNoTextItem: continue
3191

    
3192
                runs_node = line_no_node.findall('RUN')
3193
                if runs_node is None: continue
3194

    
3195
                for run_node in runs_node:
3196
                    line_run = QEngineeringRunItem()
3197
                    for child_node in run_node:
3198
                        uidElement = child_node.find('UID')
3199
                        if uidElement is not None:
3200
                            uid = uidElement.text
3201
                            run_item = self.graphicsView.findItemByUid(uid)
3202
                            if run_item is not None:
3203
                                run_item._owner = line_no
3204
                                line_run.items.append(run_item)
3205
                    line_run.owner = line_no
3206
                    line_no.runs.append(line_run)
3207

    
3208
                    for run_item in line_run.items:
3209
                        if issubclass(type(run_item), SymbolSvgItem):
3210
                            self.init_add_tree_item(line_no_tree_item, run_item)
3211

    
3212
                # docData.tracerLineNos.append(line_no)
3213

    
3214
                self.progress.setValue(self.progress.value() + 1)
3215
            QApplication.processEvents()
3216

    
3217
            for trimLineNo in root.iter('TRIM_LINE_NO'):
3218
                line_no = QEngineeringTrimLineNoTextItem()
3219
                line_no.uid = uuid.UUID(trimLineNo.find('UID').text)
3220

    
3221
                runs_node = trimLineNo.findall('RUN')
3222
                if runs_node is None: continue
3223
                line_no_tree_item = self.itemTreeWidget.addTreeItem(self.itemTreeWidget.root, line_no)
3224

    
3225
                for run in runs_node:
3226
                    line_run = QEngineeringRunItem()
3227
                    for child in run:
3228
                        uidElement = child.find('UID')
3229
                        if uidElement is not None:
3230
                            uid = uidElement.text
3231
                            run_item = self.graphicsView.findItemByUid(uid)
3232
                            if run_item is not None:
3233
                                run_item.owner = line_no
3234
                                line_run.items.append(run_item)
3235
                    line_run.owner = line_no
3236
                    line_no.runs.append(line_run)
3237

    
3238
                    for run_item in line_run.items:
3239
                        if issubclass(type(run_item), SymbolSvgItem):
3240
                            self.init_add_tree_item(line_no_tree_item, run_item)
3241

    
3242
                app_doc_data.tracerLineNos.append(line_no)
3243

    
3244
                self.progress.setValue(self.progress.value() + 1)
3245
            QApplication.processEvents()
3246

    
3247
            if root.find('VENDORS') is not None:
3248
                for vendor in root.find('VENDORS').iter('VENDOR'):
3249
                    item = QEngineeringVendorItem.fromXml(vendor)
3250
                    item.transfer.onRemoved.connect(self.itemRemoved)
3251
                    self.graphicsView.scene().addItem(item)
3252

    
3253
            # connect flow item to line
3254
            for line in lines:
3255
                line.update_arrow()
3256
                app_doc_data.lines.append(line)
3257
            # for flowMark in [item for item in symbols if type(item) is QEngineeringFlowMarkItem]:
3258
            #    for line in lines:
3259
            #        if flowMark.owner is line:
3260
            #            line._flowMark.append(flowMark)
3261
            #            flowMark.setParentItem(line)
3262
            # up to here
3263

    
3264
            """
3265
            group_box = QGroupBox("Contact Details")
3266
            number_label = QLabel("Telephone number");
3267
            number_edit = QTextEdit('hello\nthis is ....')
3268
            layout = QFormLayout()
3269
            layout.addRow(number_label, number_edit)
3270
            group_box.setLayout(layout)
3271

3272
            proxy =  ㅐ()
3273
            proxy.setWidget(group_box)
3274
            self.graphicsView.scene().addItem(proxy)  # (group_box, QGraphicsItem.ItemIgnoresTransformations)
3275
            """
3276

    
3277
            """ update scene """
3278
            _items = [_item for _item in self.graphicsView.scene().items() if hasattr(_item, 'owner') or hasattr(_item, 'connectors')]
3279
            if _items:
3280
                items = divide_chunks(_items, App.THREAD_MAX_WORKER if len(_items) > App.THREAD_MAX_WORKER else len(_items))
3281
                with futures.ThreadPoolExecutor(max_workers=App.THREAD_MAX_WORKER) as pool:
3282
                    future_items = {pool.submit(update_items, _items): _items for _items in items}
3283
                    for future in futures.as_completed(future_items):
3284
                        _items = future.result()
3285
                        self.progress.setValue(self.progress.value() + len(_items))
3286

    
3287
            """
3288
            for item in [_item for _item in self.graphicsView.scene().items() if hasattr(_item, 'owner') or hasattr(_item, 'connectors')]:
3289
                up_progress = False
3290
                # binding items
3291
                item.owner
3292
                for connector in item.connectors:
3293
                    connector.connectedItem
3294

3295
                self.progress.setValue(self.progress.value() + 1)
3296
            """
3297

    
3298
            for item in self.graphicsView.scene().items():
3299
                item.setVisible(True)
3300

    
3301
            self.graphicsView.scene().update(self.graphicsView.sceneRect())
3302
        except Exception as ex:
3303
            message = 'error occurred({}) in {}:{}'.format(ex, sys.exc_info()[-1].tb_frame.f_code.co_filename,
3304
                                                           sys.exc_info()[-1].tb_lineno)
3305
            self.addMessage.emit(MessageType.Error, message)
3306
        finally:
3307
            self.itemTreeWidget.update_item_count()
3308
            self.itemTreeWidget.expandAll()
3309
            self.graphicsView.scene().blockSignals(False)
3310

    
3311
    '''
3312
        @brief      Remove added item on same place and Add GraphicsItem
3313
        @author     Jeongwoo
3314
        @date       2018.05.29
3315
        @history    2018.06.18  Jeongwoo    Set Z-index
3316
    '''
3317

    
3318
    def addLineItemToScene(self, lineItem):
3319
        self.graphicsView.scene().addItem(lineItem)
3320

    
3321
    '''
3322
        @brief      generate output xml file
3323
        @author     humkyung
3324
        @date       2018.04.23
3325
        @history    2018.05.02  Jeongwoo    Show MessageBox when imageviewer doesn't have image
3326
    '''
3327

    
3328
    def generateOutput(self):
3329
        import XmlGenerator as xg
3330

    
3331
        if not self.graphicsView.hasImage():
3332
            self.showImageSelectionMessageBox()
3333
            return
3334

    
3335
        try:
3336
            appDocData = AppDocData.instance()
3337

    
3338
            # collect items
3339
            appDocData.lines.clear()
3340
            appDocData.lines = [item for item in self.graphicsView.scene().items() if
3341
                                type(item) is QEngineeringLineItem and item.owner is None]
3342

    
3343
            appDocData.symbols.clear()
3344
            appDocData.symbols = [item for item in self.graphicsView.scene().items() if
3345
                                  issubclass(type(item), SymbolSvgItem) and item.owner is None]
3346

    
3347
            appDocData.equipments.clear()
3348
            for item in self.graphicsView.scene().items():
3349
                if type(item) is QEngineeringEquipmentItem:
3350
                    appDocData.equipments.append(item)
3351

    
3352
            appDocData.texts.clear()
3353
            appDocData.texts = [item for item in self.graphicsView.scene().items() if
3354
                                issubclass(type(item), QEngineeringTextItem) and type(
3355
                                    item) is not QEngineeringLineNoTextItem]
3356
            # up to here
3357

    
3358
            appDocData.imgOutput = np.ones((appDocData.activeDrawing.height, appDocData.activeDrawing.width),
3359
                                           np.uint8) * 255
3360
            xg.writeOutputXml(appDocData.imgName, appDocData.activeDrawing.width,
3361
                              appDocData.activeDrawing.height)  # TODO: check
3362
            project = appDocData.getCurrentProject()
3363
            cv2.imwrite(os.path.join(project.getTempPath(), 'OUTPUT.png'), appDocData.imgOutput)
3364
        except Exception as ex:
3365
            message = 'error occurred({}) in {}:{}'.format(ex, sys.exc_info()[-1].tb_frame.f_code.co_filename,
3366
                                                           sys.exc_info()[-1].tb_lineno)
3367
            self.addMessage.emit(MessageType.Error, message)
3368

    
3369
    '''
3370
        @brief      Check Number
3371
        @author     kyouho
3372
        @date       2018.08.20
3373
    '''
3374

    
3375
    def isNumber(self, num):
3376
        p = re.compile('(^[0-9]+$)')
3377
        result = p.match(num)
3378

    
3379
        if result:
3380
            return True
3381
        else:
3382
            return False
3383

    
3384
    '''
3385
        @brief      find overlap Connector
3386
        @author     kyouho
3387
        @date       2018.08.28
3388
    '''
3389

    
3390
    def findOverlapConnector(self, connectorItem):
3391
        from shapely.geometry import Point
3392
        from EngineeringConnectorItem import QEngineeringConnectorItem
3393
        itemList = []
3394

    
3395
        x = connectorItem.center()[0]
3396
        y = connectorItem.center()[1]
3397

    
3398
        connectors = [item for item in self.graphicsView.scene().items() if
3399
                      type(item) is QEngineeringConnectorItem and item != connectorItem]
3400
        for connector in connectors:
3401
            if Point(x, y).distance(Point(connector.center()[0], connector.center()[1])) < 5:
3402
                itemList.append(connector.parent)
3403

    
3404
        return itemList
3405

    
3406
    def make_diff_image(self):
3407
        """ make diff image """
3408
        # test
3409

    
3410
        from RecognitionDialog import Worker
3411
        from symbol import Symbol
3412
        import math
3413
        from PIL import Image
3414

    
3415
        app_doc_data = AppDocData.instance()
3416
        img = app_doc_data.imgSrc.copy()
3417

    
3418
        # check break
3419
        symbols = [item for item in self.graphicsView.scene().items() if issubclass(type(item), SymbolSvgItem)]
3420

    
3421
        for symbol in symbols:
3422
            rect = symbol.sceneBoundingRect()
3423
            sName = symbol.name
3424
            sType = symbol.type
3425
            sp = (rect.x(), rect.y())
3426
            w, h = rect.width(), rect.height()
3427
            rotatedAngle = round(math.degrees(symbol.angle))
3428
            detectFlip = symbol.flip
3429

    
3430
            dummySym = Symbol(sName, sType, sp, w, h, 0, 0, 0, rotatedAngle,
3431
                                   1, 0, 1, 0,
3432
                                   ','.join(str(x) for x in [0, 0]),
3433
                                   '/'.join('{},{},{},{}'.format(param[0], param[1], param[2], param[3]) for param in
3434
                                            []),
3435
                                   'dummy', 'dummy', 0, detectFlip=detectFlip,
3436
                                   hasInstrumentLabel=0, text_area='')
3437

    
3438
            Worker.remove_detected_symbol_image(dummySym, img, lock=False)
3439

    
3440
        Image.fromarray(img).show()
3441

    
3442
    #def paintEvent(self, event):
3443
    #    self.refresh_rate += 1
3444
    #    if self.refresh_rate == 3:
3445
    #        super(self.__class__, self).paintEvent(event)
3446
    #        self.refresh_rate = 0
3447

    
3448
if __name__ == '__main__':
3449
    import locale
3450
    from PyQt5.QtCore import QTranslator
3451
    from License import QLicenseDialog
3452
    from ProjectDialog import Ui_Dialog
3453
    from App import App
3454

    
3455
    app = App(sys.argv)
3456
    try:
3457
        if True == QLicenseDialog.check_license_key():
3458
            dlg = Ui_Dialog()
3459
            selectedProject = dlg.showDialog()
3460
            if selectedProject is not None:
3461
                AppDocData.instance().setCurrentProject(selectedProject)
3462
                app._mainWnd = MainWindow.instance()
3463
                app._mainWnd.show()
3464
                sys.exit(app.exec_())
3465
    except Exception as ex:
3466
        print('error occurred({}) in {}:{}'.format(ex, sys.exc_info()[-1].tb_frame.f_code.co_filename,
3467
                                                   sys.exc_info()[-1].tb_lineno))
3468
    finally:
3469
        pass