프로젝트

일반

사용자정보

통계
| 개정판:

hytos / DTI_PID / DTI_PID / MainWindow.py @ 5ac97832

이력 | 보기 | 이력해설 | 다운로드 (158 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
from PyQt5.QtPrintSupport import QPrintDialog, QPrinter
29

    
30
from PIL import Image
31

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

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

    
75

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

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

    
83

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

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

    
95
        super(self.__class__, self).__init__()
96
        self.setupUi(self)
97

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

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

    
117
        #self.refresh_rate = 0
118

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

    
127
        # save timer
128
        self.save_timer = None
129

    
130
        self._scene = QtImageViewerScene(self)
131

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

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

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

    
154
        self.splitterSymbol.setSizes([500, 300])
155

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

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

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

    
239
        self.delimiter = '"'
240

    
241
        self.resizeDocks({self.dockWidget}, {self.dockWidgetObjectExplorer.sizeHint().width()}, Qt.Horizontal)
242

    
243
        # drawing list
244
        self.treeWidgetDrawingList.setHeaderHidden(False)
245
        self.treeWidgetDrawingList.header().setStretchLastSection(False)
246
        self.treeWidgetDrawingList.setHeaderLabels([self.tr('Name'), self.tr('DateTime')])
247
        self.treeWidgetDrawingList.header().setSectionResizeMode(0, QHeaderView.ResizeToContents)
248
        self.treeWidgetDrawingList.header().setSectionResizeMode(1, QHeaderView.ResizeToContents)
249
        self.treeWidgetDrawingList.header().setSectionsClickable(True)
250
        self.treeWidgetDrawingList.header().sectionClicked.connect(self.sort_drawing_list)
251
        self.treeWidgetDrawingList.itemDoubleClicked.connect(self.open_selected_drawing)
252
        self.load_drawing_list()
253

    
254
        self.ribbon = AppRibbon()
255
        self.setMenuWidget(self.ribbon)
256

    
257
        if not self.ribbon.advanced_mode:
258
            self.pushButtonCreateSymbol.setVisible(False)
259
            self.pushButtonDetectSymbol.setVisible(False)
260

    
261
        configs = app_doc_data.getConfigs('Line List', 'Use Stream No')
262
        if configs and int(configs[0].value) == 1:
263
            pass
264
        else:
265
            self.ribbon.get_pane('Home Visualization').ui.radioButtonByStreamNo.setHidden(True)
266

    
267
        '''
268
        view_pane = self.ribbon.get_pane('View')
269
        shortcut = QShortcut(QKeySequence(Qt.Key_1), view_pane.ui.toolButtonViewImageDrawing)
270
        shortcut.activated.connect(partial(self.on_view_toggle, Qt.Key_1))
271
        shortcut = QShortcut(QKeySequence(Qt.Key_2), view_pane.ui.toolButtonViewText)
272
        shortcut.activated.connect(partial(self.on_view_toggle, Qt.Key_2))
273
        shortcut = QShortcut(QKeySequence(Qt.Key_3), view_pane.ui.toolButtonViewSymbol)
274
        shortcut.activated.connect(partial(self.on_view_toggle, Qt.Key_3))
275
        shortcut = QShortcut(QKeySequence(Qt.Key_4), view_pane.ui.toolButtonViewLine)
276
        shortcut.activated.connect(partial(self.on_view_toggle, Qt.Key_4))
277
        shortcut = QShortcut(QKeySequence(Qt.Key_5), view_pane.ui.toolButtonViewUnknown)
278
        shortcut.activated.connect(partial(self.on_view_toggle, Qt.Key_5))
279
        shortcut = QShortcut(QKeySequence(Qt.Key_6), view_pane.ui.toolButtonViewInconsistency)
280
        shortcut.activated.connect(partial(self.on_view_toggle, Qt.Key_6))
281
        shortcut = QShortcut(QKeySequence(Qt.Key_7), view_pane.ui.toolButtonViewVendorArea)
282
        shortcut.activated.connect(partial(self.on_view_toggle, Qt.Key_7))
283
        shortcut = QShortcut(QKeySequence(96), view_pane.ui.toolButtonViewDrawingOnly)
284
        shortcut.activated.connect(partial(self.on_view_toggle, 96))
285
        '''
286

    
287
        # inconsistency table
288
        self.tableWidgetInconsistency.setColumnCount(3)
289
        self.tableWidgetInconsistency.setHorizontalHeaderLabels(['Owner', 'Type', 'Message'])
290
        self.tableWidgetInconsistency.setEditTriggers(QAbstractItemView.NoEditTriggers)
291
        self.tableWidgetInconsistency.itemClicked.connect(self.inconsistencyItemClickEvent)
292
        self.tableWidgetInconsistency.keyPressEvent = self.inconsistencyTableKeyPressEvent
293
        self.tableWidgetInconsistency.setSortingEnabled(True)
294

    
295
        # memo tab
296
        self.on_memo_refresh_clicked()
297

    
298
        self.read_settings()
299

    
300
    @property
301
    def title(self) -> str:
302
        """return window title"""
303

    
304
        from App import App
305

    
306
        app_doc_data = AppDocData.instance()
307
        project = app_doc_data.getCurrentProject()
308
        version = QCoreApplication.applicationVersion()
309
        title = f"{App.NAME}({version}) - {project.name}: " \
310
                f"{app_doc_data.activeDrawing.name if app_doc_data.activeDrawing else ''}"
311
        #title = f"{App.NAME} : ID2 " \
312
        #        f"{app_doc_data.activeDrawing.name if app_doc_data.activeDrawing else ''}"
313

    
314
        return title
315

    
316
    @property
317
    def scene(self):
318
        """getter scene"""
319
        return self._scene
320

    
321
    def eventFilter(self, source, event):
322
        """display mouse position of graphics view"""
323
        try:
324
            if event.type() == QEvent.MouseMove:
325
                self.current_pos = self.graphicsView.mapToScene(event.pos())
326
                self._label_mouse.setText(
327
                    'mouse pos : ({},{})'.format(round(self.current_pos.x()), round(self.current_pos.y())))
328
        except Exception as ex:
329
            message = 'error occurred({}) in {}:{}'.format(ex, sys.exc_info()[-1].tb_frame.f_code.co_filename,
330
                                                           sys.exc_info()[-1].tb_lineno)
331
            self.addMessage.emit(MessageType.Error, message)
332

    
333
        return QWidget.eventFilter(self, source, event)
334

    
335
    def closeEvent(self, event):
336
        """save geometry and state and ask user to save drawing which is modified"""
337

    
338
        self.settings.setValue('geometry', self.saveGeometry())
339
        self.settings.setValue('windowState', self.saveState())
340
        # TODO: need to modify
341

    
342
        """save current view region"""
343
        app_doc_data = AppDocData.instance()
344
        if app_doc_data.activeDrawing:
345
            rect = self.graphicsView.viewport().rect()
346
            app_doc_data.activeDrawing.view_rect = self.graphicsView.mapToScene(rect).boundingRect()
347
            app_doc_data.update_view_region(app_doc_data.activeDrawing)
348
        """up to here"""
349

    
350
        # self.save_drawing_if_necessary()
351
        AppDocData.instance().clear()
352
        event.accept()
353

    
354
    def on_memo_refresh_clicked(self):
355
        """refresh memo"""
356
        try:
357
            app_doc_data = AppDocData.instance()
358
            configs = app_doc_data.getConfigs('Memo', 'Global')
359
            if 1 == len(configs):
360
                self.textEditMemo.setText(configs[0].value)
361
            else:
362
                self.textEditMemo.setText("")
363

    
364
            self.pushButtonMemoEdit.setText('Edit')
365
            self.textEditMemo.setEnabled(False)
366
            self.pushButtonMemoEdit.setEnabled(True)
367
            self.pushButtonMemoSave.setEnabled(False)
368
        except Exception as ex:
369
            message = 'error occurred({}) in {}:{}'.format(ex, sys.exc_info()[-1].tb_frame.f_code.co_filename,
370
                                                           sys.exc_info()[-1].tb_lineno)
371
            self.addMessage.emit(MessageType.Error, message)
372

    
373
    def on_memo_edit_clicked(self):
374
        """edit memo"""
375
        try:
376
            if not self.textEditMemo.isEnabled():
377
                self.pushButtonMemoEdit.setText('Cancel')
378
                self.textEditMemo.setEnabled(True)
379
                self.pushButtonMemoSave.setEnabled(True)
380
            else:
381
                self.pushButtonMemoEdit.setText('Edit')
382
                self.on_memo_refresh_clicked()
383
        except Exception as ex:
384
            message = 'error occurred({}) in {}:{}'.format(ex, sys.exc_info()[-1].tb_frame.f_code.co_filename,
385
                                                           sys.exc_info()[-1].tb_lineno)
386
            self.addMessage.emit(MessageType.Error, message)
387

    
388
    def on_memo_save_clicked(self):
389
        """save memo"""
390
        try:
391
            app_doc_data = AppDocData.instance()
392
            app_doc_data.saveConfigs([Config('Memo', 'Global', self.textEditMemo.toPlainText())])
393
            self.on_memo_refresh_clicked()
394
        except Exception as ex:
395
            message = 'error occurred({}) in {}:{}'.format(ex, sys.exc_info()[-1].tb_frame.f_code.co_filename,
396
                                                           sys.exc_info()[-1].tb_lineno)
397
            self.addMessage.emit(MessageType.Error, message)
398

    
399
    def inconsistencyTableKeyPressEvent(self, event):
400
        try:
401
            row = self.tableWidgetInconsistency.selectedIndexes()[0].row()
402
            col = self.tableWidgetInconsistency.selectedIndexes()[0].column()
403
            from HighlightCommand import HighlightCommand
404
            if event.key() == Qt.Key_Up:
405
                if row is not 0:
406
                    errorItem = self.tableWidgetInconsistency.item(row - 1, 1).tag
407
                    HighlightCommand(self.graphicsView).execute(errorItem)
408
            elif event.key() == Qt.Key_Down:
409
                if row is not self.tableWidgetInconsistency.rowCount() - 1:
410
                    errorItem = self.tableWidgetInconsistency.item(row + 1, 1).tag
411
                    HighlightCommand(self.graphicsView).execute(errorItem)
412
            elif event.key() == Qt.Key_Delete:
413
                item = self.tableWidgetInconsistency.item(row, 0).tag
414
                if item and item.scene(): item.scene().removeItem(item)
415
                self.tableWidgetInconsistency.removeRow(row)
416

    
417
                self.tabWidget_2.setTabText(self.tabWidget_2.indexOf(self.tabInconsistency),
418
                                            self.tr('Inconsistency') + f"({self.tableWidgetInconsistency.rowCount()})")
419
        except Exception as ex:
420
            message = 'error occurred({}) in {}:{}'.format(ex, sys.exc_info()[-1].tb_frame.f_code.co_filename,
421
                                                           sys.exc_info()[-1].tb_lineno)
422
            self.addMessage.emit(MessageType.Error, message)
423
        # finally:
424
        #    return QTableView.keyPressEvent(self.tableWidgetInconsistency, event)
425

    
426
    def onValidation(self):
427
        """validation check"""
428
        from ValidationDialog import QValidationDialog
429
        from ValidateCommand import ValidateCommand
430

    
431
        if not self.graphicsView.hasImage():
432
            self.showImageSelectionMessageBox()
433
            return
434

    
435
        try:
436
            dlg = QValidationDialog(self)
437
            if QDialog.Accepted == dlg.exec_():
438
                # remove error items
439
                for item in self.graphicsView.scene().items():
440
                    if type(item) is QEngineeringErrorItem:
441
                        item.transfer.onRemoved.emit(item)
442
                # up to here
443

    
444
                self.progress_bar.setMaximum(len(self.graphicsView.scene().items()))
445
                self.progress_bar.setValue(0)
446

    
447
                cmd = ValidateCommand(self.graphicsView)
448
                cmd.show_progress.connect(self.progress_bar.setValue)
449
                errors = cmd.execute(self.graphicsView.scene().items())
450
                for error in errors:
451
                    error.transfer.onRemoved.connect(self.itemRemoved)
452
                    #self.graphicsView.scene().addItem(error)
453
                    error.addSvgItemToScene(self.graphicsView.scene())
454

    
455
                self.tableWidgetInconsistency.clearContents()
456
                self.tableWidgetInconsistency.setRowCount(len(errors))
457
                for index, error in enumerate(errors):
458
                    self.makeInconsistencyTableRow(index, error)
459

    
460
                self.tabWidget_2.setTabText(self.tabWidget_2.indexOf(self.tabInconsistency),
461
                                            self.tr('Inconsistency') + f"({len(errors)})")
462
                if errors:
463
                    self.tabWidget_2.tabBar().setTabTextColor(self.tabWidget_2.indexOf(self.tabInconsistency), Qt.red)
464
                else:
465
                    self.tabWidget_2.tabBar().setTabTextColor(self.tabWidget_2.indexOf(self.tabInconsistency), Qt.black)
466
        except Exception as ex:
467
            message = 'error occurred({}) in {}:{}'.format(ex, sys.exc_info()[-1].tb_frame.f_code.co_filename,
468
                                                           sys.exc_info()[-1].tb_lineno)
469
            self.addMessage.emit(MessageType.Error, message)
470
        finally:
471
            self.progress_bar.setValue(self.progress_bar.maximum())
472

    
473
    def makeInconsistencyTableRow(self, row, errorItem):
474
        '''
475
            @brief  make row data for inconsistency widget
476
            @author euisung
477
            @date   2019.04.16
478
        '''
479

    
480
        item = QTableWidgetItem(str(errorItem.parent))
481
        item.tag = errorItem
482
        self.tableWidgetInconsistency.setItem(row, 0, item)
483

    
484
        item = QTableWidgetItem(str(type(errorItem.parent)))
485
        item.tag = errorItem
486
        self.tableWidgetInconsistency.setItem(row, 1, item)
487

    
488
        item = QTableWidgetItem(errorItem.msg)
489
        item.tag = errorItem
490
        self.tableWidgetInconsistency.setItem(row, 2, item)
491

    
492
    def inconsistencyItemClickEvent(self, item):
493
        """
494
        @brief  inconsistency table item clicked
495
        @author euisung
496
        @date   2019.04.02
497
        """
498
        from HighlightCommand import HighlightCommand
499

    
500
        HighlightCommand(self.graphicsView).execute(item.tag)
501

    
502
    def read_settings(self):
503
        """read geometry and state"""
504
        from App import App
505

    
506
        try:
507
            self.settings = QSettings(App.COMPANY, App.NAME)
508
            self.restoreGeometry(self.settings.value("geometry", ""))
509
            self.restoreState(self.settings.value("windowState", ""))
510
        except Exception as ex:
511
            message = f"error occurred({repr(ex)}) in {sys.exc_info()[-1].tb_frame.f_code.co_filename}:" \
512
                      f"{sys.exc_info()[-1].tb_lineno}"
513

    
514
    def load_stylesheet(self, file):
515
        """load stylesheets"""
516

    
517
        QtWidgets.qApp.loadStyleSheet(os.path.join(os.path.dirname(os.path.realpath(__file__)), file))
518

    
519
        app_doc_data = AppDocData.instance()
520
        configs = [Config('app', 'stylesheet', file)]
521
        app_doc_data.saveAppConfigs(configs)
522

    
523
    def load_language(self, file):
524
        """load language file and then apply selected language"""
525
        try:
526
            qm_file = os.path.join(os.path.dirname(os.path.realpath(__file__)), 'translate', '{0}.qm'.format(file))
527
            QtWidgets.qApp.load_language(qm_file)
528

    
529
            app_doc_data = AppDocData.instance()
530
            configs = [Config('app', 'language', file)]
531
            app_doc_data.saveAppConfigs(configs)
532
        finally:
533
            self.retranslateUi(self)
534

    
535
    def refresh_item_list(self):
536
        """refresh item tree"""
537

    
538
        app_doc_data = AppDocData.instance()
539
        
540
        '''
541
        self.itemTreeWidget.setCurrentPID(app_doc_data.activeDrawing.name)
542

543
        """update item tree widget"""
544
        line_no_items = [item for item in self.graphicsView.scene().items()
545
                            if type(item) is QEngineeringLineNoTextItem]
546
        for line_no in line_no_items:
547
            if (hasattr(line_no, 'treeItem')):
548
                line_no.treeItem = None
549

550
            line_no_tree_item = self.itemTreeWidget.addTreeItem(self.itemTreeWidget.root, line_no)
551
            for run in line_no.runs:
552
                for run_item in run.items:
553
                    if issubclass(type(run_item), SymbolSvgItem):
554
                        self.init_add_tree_item(line_no_tree_item, run_item)
555

556
        line_no_items = [item for item in self.graphicsView.scene().items()
557
                            if type(item) is QEngineeringTrimLineNoTextItem]
558
        for line_no in line_no_items:
559
            line_no_tree_item = self.itemTreeWidget.addTreeItem(self.itemTreeWidget.root, line_no)
560
            for run in line_no.runs:
561
                for run_item in run.items:
562
                    if issubclass(type(run_item), SymbolSvgItem):
563
                        self.init_add_tree_item(line_no_tree_item, run_item)
564

565
        for trim_line_no in app_doc_data.tracerLineNos:
566
            line_no_tree_item = self.itemTreeWidget.addTreeItem(self.itemTreeWidget.root, trim_line_no)
567
            for run in trim_line_no.runs:
568
                for run_item in run.items:
569
                    if issubclass(type(run_item), SymbolSvgItem):
570
                        self.init_add_tree_item(line_no_tree_item, run_item)
571

572
        self.itemTreeWidget.update_item_count()
573
        self.itemTreeWidget.expandAll()
574
        """up to here"""
575
        '''
576

    
577
        self.itemTreeWidget.InitLineNoItems()
578

    
579
        #'''
580
        line_nos = app_doc_data.tracerLineNos
581
        for line_no in line_nos:
582
            item = self.itemTreeWidget.addTreeItem(self.itemTreeWidget.root, line_no)
583
            connectedItems = line_no.getConnectedItems()
584
            for connectedItem in connectedItems:
585
                if issubclass(type(connectedItem), SymbolSvgItem):
586
                    self.itemTreeWidget.addTreeItem(item, connectedItem)
587
        #'''
588
        
589
    def sort_drawing_list(self, index):
590
        """ sort drawing list """
591
        if index == 0:
592
            if self.drawing_reverse:
593
                self.load_drawing_list(reverse=False)
594
            else:
595
                self.load_drawing_list(reverse=True)
596

    
597

    
598
    def load_drawing_list(self, reverse=False):
599
        """load p&id drawing list"""
600
        from Drawing import Drawing
601

    
602
        try:
603
            app_doc_data = AppDocData.instance()
604
            drawings = app_doc_data.getDrawings()
605
            new_drawings = []
606

    
607
            self.treeWidgetDrawingList.clear()
608
            self.treeWidgetDrawingList.root = QTreeWidgetItem(self.treeWidgetDrawingList,
609
                                                              [self.tr('P&ID Drawings'), ''])
610
            self.treeWidgetDrawingList.root.setFlags(
611
                self.treeWidgetDrawingList.root.flags() | Qt.ItemIsTristate | Qt.ItemIsUserCheckable)
612
            self.treeWidgetDrawingList.root.setCheckState(0, Qt.Unchecked)
613
            files = app_doc_data.getDrawingFileList()
614

    
615
            # self.progress_bar.setMaximum(len(files))
616
            count = 0
617
            # self.progress_bar.setValue(count)
618
            self.drawing_reverse = reverse
619
            for file in files if not self.drawing_reverse else reversed(files):
620
                x = [drawing for drawing in drawings if drawing.name == file]
621
                if not x or not x[0].UID:
622
                    drawing = Drawing(None, file, None)
623
                    new_drawings.append(drawing)
624
                else:
625
                    drawing = x[0]
626

    
627
                item = QTreeWidgetItem(self.treeWidgetDrawingList.root, [file, drawing.datetime])
628
                item.setIcon(0, QIcon(':newPrefix/image.png'))
629
                item.setFlags(item.flags() | Qt.ItemIsUserCheckable)
630
                item.setCheckState(0, Qt.Unchecked)
631
                item.setData(Qt.UserRole, 0, drawing)
632

    
633
                count += 1
634
                # self.progress_bar.setValue(count)
635
                # QApplication.processEvents()
636

    
637
            self.treeWidgetDrawingList.root.setText(0, self.tr('P&ID Drawings') +
638
                                                    f"({self.treeWidgetDrawingList.root.childCount()})")
639
            self.treeWidgetDrawingList.expandItem(self.treeWidgetDrawingList.root)
640
            #self.treeWidgetDrawingList.root.sortChildren(0, Qt.AscendingOrder)
641
            self.treeWidgetDrawingList.resizeColumnToContents(0)
642

    
643
            app_doc_data.saveDrawings(new_drawings)
644
        except Exception as ex:
645
            message = 'error occurred({}) in {}:{}'.format(repr(ex), sys.exc_info()[-1].tb_frame.f_code.co_filename,
646
                                                           sys.exc_info()[-1].tb_lineno)
647
            self.addMessage.emit(MessageType.Error, message)
648
        finally:
649
            self.progress_bar.setValue(self.progress_bar.maximum())
650

    
651
    def open_selected_drawing(self, item, column):
652
        """open selected p&id drawing"""
653

    
654
        app_doc_data = AppDocData.instance()
655
        drawing = item.data(Qt.UserRole, 0)
656
        if drawing:
657
            # uncheck all drawing tree item
658
            drawing_top = self.treeWidgetDrawingList.topLevelItem(0)
659
            count = drawing_top.childCount()
660
            for idx in range(count):
661
                child = drawing_top.child(idx)
662
                child.setCheckState(column, Qt.Unchecked)
663
            # up to here
664

    
665
            drawing.image = None
666
            self.open_image_drawing(drawing)
667
            item.setCheckState(column, Qt.Checked)
668

    
669
    def show_detect_symbol_dialog(self):
670
        from DetectSymbolDialog import QDetectSymbolDialog
671

    
672
        dlg = QDetectSymbolDialog(self)
673
        dlg.exec_()
674
        
675
        self.symbolTreeWidget.initSymbolTreeView()
676

    
677
    '''
678
        @brief      OCR Editor
679
        @author     euisung
680
        @date       2018.10.05
681
        @history    2018.10.16 euisung      no more used, Integrated with oCRTrainingClicked
682
    '''
683
    def oCRTrainingEdidorClicked(self):
684
        from TrainingEditorDialog import QTrainingEditorDialog
685

    
686
        try:
687
            dialog = QTrainingEditorDialog(self)
688
            dialog.exec_()
689
        except Exception as ex:
690
            message = 'error occurred({}) in {}:{}'.format(ex, sys.exc_info()[-1].tb_frame.f_code.co_filename,
691
                                                           sys.exc_info()[-1].tb_lineno)
692
            self.addMessage.emit(MessageType.Error, message)
693

    
694
        return
695

    
696
    '''
697
        @brief      OCR Training
698
        @author     euisung
699
        @date       2018.09.27
700
        @history    euisung 2018.10.16 TrainingListDialog -> TrainingImageListDialog
701
    '''
702
    def oCRTrainingClicked(self):
703
        try:
704
            dialog = QTrainingImageListDialog(self)
705
            dialog.exec_()
706
        except Exception as ex:
707
            message = 'error occurred({}) in {}:{}'.format(ex, sys.exc_info()[-1].tb_frame.f_code.co_filename,
708
                                                           sys.exc_info()[-1].tb_lineno)
709
            self.addMessage.emit(MessageType.Error, message)
710

    
711
    def symbolTrainingClicked(self):
712
        try:
713
            dialog = QTrainingSymbolImageListDialog(self)
714
            dialog.show()
715
            dialog.exec_()
716
        except Exception as ex:
717
            message = 'error occurred({}) in {}:{}'.format(ex, sys.exc_info()[-1].tb_frame.f_code.co_filename,
718
                                                           sys.exc_info()[-1].tb_lineno)
719
            self.addMessage.emit(MessageType.Error, message)
720

    
721
    def findReplaceTextClicked(self):
722
        """pop up find and replace dialog"""
723
        if not self.graphicsView.hasImage():
724
            self.showImageSelectionMessageBox()
725
            return
726

    
727
        from TextItemEditDialog import QTextItemEditDialog
728

    
729
        dlgTextItemEdit = QTextItemEditDialog(self)
730
        dlgTextItemEdit.show()
731
        dlgTextItemEdit.exec_()
732

    
733
    def on_validation_global_clicked(self):
734
        """ global validation dialog """
735
        from ValidationGlobalDialog import QValidationGlobalDialog
736

    
737
        dlg = QValidationGlobalDialog(self)
738
        dlg.show()
739
        dlg.exec_()
740

    
741
    def replaceInsertSymbolClicked(self):
742
        """pop up replace and insert dialog"""
743
        if not self.graphicsView.hasImage():
744
            self.showImageSelectionMessageBox()
745
            return
746

    
747
        from ReplaceSymbolDialog import QReplaceSymbolDialog
748

    
749
        dlg = QReplaceSymbolDialog(self)
750
        dlg.show()
751
        dlg.exec_()
752

    
753
    def on_ocr_unknown_items(self):
754
        """ try to ocr for unknown items """
755
        from OcrResultDialog import QOcrResultDialog
756

    
757
        if not self.graphicsView.hasImage():
758
            self.showImageSelectionMessageBox()
759
            return
760

    
761
        app_doc_data = AppDocData.instance()
762
        configs = app_doc_data.getConfigs('Text Size', 'Max Text Size')
763
        maxSize = int(configs[0].value) if 1 == len(configs) else 100
764
        configs = app_doc_data.getConfigs('Text Size', 'Min Text Size')
765
        minSize = int(configs[0].value) if 1 == len(configs) else 15
766

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

    
769
        for unknown in unknowns:
770
            rect = unknown.sceneBoundingRect()
771
            if rect.width() < minSize or rect.height() < minSize or rect.width() > maxSize or rect.height() > maxSize:
772
                continue
773
            if self.onRecognizeText(round(rect.left()), round(rect.top()), round(rect.width()), round(rect.height()), show=False):
774
                unknown.transfer.onRemoved.emit(unknown)
775

    
776
    def on_connect_line_to_symbol(self):
777
        """connect line to symbol"""
778
        from LineDetector import LineDetector
779
        from RecognitionDialog import Worker
780

    
781
        if not self.graphicsView.hasImage():
782
            self.showImageSelectionMessageBox()
783
            return
784

    
785
        app_doc_data = AppDocData.instance()
786
        #configs = app_doc_data.getConfigs('Project', 'Operation')
787
        configs = app_doc_data.getConfigs('Line Detector', 'Length to connect line')
788
        toler = int(configs[0].value) if configs else 20
789
        detector = LineDetector(app_doc_data.imgSrc)
790

    
791
        lines = [item for item in self.graphicsView.scene().items() if type(item) is QEngineeringLineItem if item.length() > 50]
792
        lines_short = [item for item in self.graphicsView.scene().items() if type(item) is QEngineeringLineItem if item.length() <= 50]
793
        unknowns = [item for item in self.graphicsView.scene().items() if type(item) is QEngineeringUnknownItem]
794
        symbols = [item for item in self.graphicsView.scene().items() if issubclass(type(item), SymbolSvgItem)]
795

    
796
        for item in lines_short + unknowns:
797
            item.transfer.onRemoved.emit(item)
798
        
799
        if lines:
800
            new_lines = []
801
            try:
802
                conns = []
803
                for sym in symbols:
804
                    if sym.conn_type:
805
                        for index in range(len(sym.conn_type)):
806
                            if sym.conn_type[index] == 'Secondary' or sym.conn_type[index] == 'Primary':
807
                                item = sym.connectors[index].connectedItem
808
                                if item is None:
809
                                    conns.append(sym.connectors[index])
810
                
811
                new_lines.extend(Worker.make_short_lines_sts(conns, None))
812

    
813
                conns = []
814
                for sym in symbols:
815
                    if sym.conn_type:
816
                        for index in range(len(sym.conn_type)):
817
                            if sym.conn_type[index] == 'Secondary' or sym.conn_type[index] == 'Primary':
818
                                item = sym.connectors[index].connectedItem
819
                                if item is None and sym.connectors[index]:
820
                                    conns.append(sym.connectors[index])
821
                
822
                new_lines.extend(Worker.make_short_lines_stl(lines, conns, None))
823

    
824
                for line in new_lines:
825
                    self.graphicsView.scene().addItem(line)
826
                    for conn in line.connectors:
827
                        conn.transfer.onPosChanged.connect(line.onConnectorPosChaned)
828
            except Exception as ex:
829
                message = f"error occurred({repr(ex)}) in {sys.exc_info()[-1].tb_frame.f_code.co_filename}:" \
830
                          f"{sys.exc_info()[-1].tb_lineno}"
831
                self.addMessage.emit(MessageType.Error, message)
832
                
833
            # connect line to symbol
834
            try:
835
                for line in lines:
836
                    matches = [_symbol for _symbol in symbols if _symbol.is_connectable(line, toler=toler)]
837
                    for _symbol in matches:
838
                        detector.connectLineToSymbol(line, _symbol, toler=toler)
839
            except Exception as ex:
840
                message = f"error occurred({repr(ex)}) in {sys.exc_info()[-1].tb_frame.f_code.co_filename}:" \
841
                          f"{sys.exc_info()[-1].tb_lineno}"
842
                self.addMessage.emit(MessageType.Error, message)
843
            # up to here
844

    
845
            # connect line to line
846
            try:
847
                for line in lines:
848
                    matches = [it for it in lines if (it is not line) and (not line.isParallel(it))]
849

    
850
                    for match in matches:
851
                        detector.connectLineToLine(match, line, toler)
852
            except Exception as ex:
853
                message = f"error occurred({repr(ex)}) in {sys.exc_info()[-1].tb_frame.f_code.co_filename}:" \
854
                          f"{sys.exc_info()[-1].tb_lineno}"
855
                self.addMessage.emit(MessageType.Error, message)
856
            # up to here
857

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

    
860
    def on_recognize_line(self):
861
        """recognize lines in selected area"""
862
        from RecognizeLineCommand import RecognizeLineCommand
863

    
864
        if not self.graphicsView.hasImage():
865
            self.actionOCR.setChecked(False)
866
            self.showImageSelectionMessageBox()
867
            return
868

    
869
        cmd = RecognizeLineCommand(self.graphicsView)
870
        cmd.onSuccess.connect(self.on_success_to_recognize_line)
871
        cmd.onRejected.connect(self.onCommandRejected)
872
        self.graphicsView.command = cmd
873

    
874
    '''
875
            @brief      show text recognition dialog
876
            @author     humkyung
877
            @date       2018.08.08
878
    '''
879
    def on_success_to_recognize_line(self, x, y, width, height):
880
        import io
881
        from LineDetector import LineDetector
882
        from EngineeringGraphicsLineItem import QEngineeringGraphicsLineItem
883

    
884
        try:
885
            image = self.graphicsView.image().copy(x, y, width, height)
886
            buffer = QBuffer()
887
            buffer.open(QBuffer.ReadWrite)
888
            image.save(buffer, "PNG")
889
            pyImage = Image.open(io.BytesIO(buffer.data()))
890
            img = np.array(pyImage)
891
            img = cv2.cvtColor(img, cv2.COLOR_BGR2GRAY)
892

    
893
            detector = LineDetector(img)
894
            lines = detector.detect_line_without_symbol()
895
            for line in lines:
896
                vertices = [[line[0][0] + x, line[0][1] + y], [line[1][0] + x, line[1][1] + y]]
897
                line_item = QEngineeringGraphicsLineItem(vertices)
898
                self.graphicsView.scene().addItem(line_item)
899

    
900
        except Exception as ex:
901
            message = 'error occurred({}) in {}:{}'.format(repr(ex), sys.exc_info()[-1].tb_frame.f_code.co_filename,
902
                                                           sys.exc_info()[-1].tb_lineno)
903
            self.addMessage.emit(MessageType.Error, message)
904

    
905
    def display_number_of_items(self):
906
        """display count of symbol, line, text"""
907

    
908
        items = [item for item in self.graphicsView.scene().items() if type(item) is QEngineeringUnknownItem]
909
        if len(items) > 0:
910
            self.labelStatus.setText(
911
                "<font color='red'>" + self.tr('Unrecognition') + " : {}</font>".format(len(items)))
912
        else:
913
            self.labelStatus.setText(
914
                "<font color='black'>" + self.tr('Unrecognition') + " : {}</font>".format(len(items)))
915

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

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

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

    
926
        self.itemTreeWidget.sceneChanged(self.graphicsView.scene().items())
927

    
928
    def dbUpdate(self):
929
        """ no more used """
930
        """db update when save or recognition"""
931

    
932
        try:
933
            appDocData = AppDocData.instance()
934
            items = appDocData.allItems
935

    
936
            '''
937
            titleBlockProps = appDocData.getTitleBlockProperties()
938
            titleBlockItems = []
939
            for item in items:
940
                # if type(item) is QEngineeringLineNoTextItem:
941
                #    item.saveLineData()
942
                if type(item) is QEngineeringTextItem:
943
                    for titleBlockProp in titleBlockProps:
944
                        if item.area == titleBlockProp[0]:
945
                            titleBlockItems.append(item)
946
            '''
947

    
948
            # unknown item is not saved now for performance
949
            db_items = [item for item in items if issubclass(type(item), QEngineeringAbstractItem) and
950
                        type(item) is not QGraphicsBoundingBoxItem and
951
                        type(item) is not QEngineeringErrorItem and
952
                        type(item) is not QEngineeringLineNoTextItem and
953
                        type(item) is not QEngineeringUnknownItem]
954
            db_items.extend([item for item in items if type(item) is QEngineeringLineNoTextItem])
955
            db_items.extend([line for line in appDocData.tracerLineNos if type(line) is QEngineeringTrimLineNoTextItem])
956
            # db_items.extend(titleBlockItems)
957
            configs = appDocData.getConfigs('Data Save', 'Unknown Xml Only')
958
            if configs and int(configs[0].value) is -1:
959
                db_items.extend([item for item in items if type(item) is QEngineeringUnknownItem])
960

    
961
            '''
962
            dbItems = [item for item in items if
963
                       type(item) is QEngineeringInstrumentItem or type(item) is QEngineeringEquipmentItem or type(
964
                           item) is QEngineeringReducerItem or \
965
                       type(item) is QEngineeringNoteItem or type(item) is SymbolSvgItem or type(
966
                           item) is QEngineeringLineNoTextItem or type(
967
                           item) is QEngineeringVendorItem] + titleBlockItems
968
            '''
969
            appDocData.saveToDatabase(db_items)
970
        except Exception as ex:
971
            message = 'error occurred({}) in {}:{}'.format(ex, sys.exc_info()[-1].tb_frame.f_code.co_filename,
972
                                                           sys.exc_info()[-1].tb_lineno)
973
            self.addMessage.emit(MessageType.Error, message)
974

    
975
    def save_drawing_if_necessary(self):
976
        """ask to user to save drawing or not when drawing is modified"""
977

    
978
        app_doc_data = AppDocData.instance()
979
        if app_doc_data.activeDrawing and app_doc_data.activeDrawing.modified:
980
            #if QMessageBox.Yes == QMessageBox.question(self, self.tr("Question"),
981
            #                                           self.tr("Do you want to save drawing?"),
982
            #                                           QMessageBox.Yes | QMessageBox.No):
983
            #    self.actionSaveCliked()
984
            #    return True
985
            if QMessageBox.Ignore == QMessageBox.question(self, self.tr('Continue?'),
986
                                                       self.tr('Changes may not have been saved.'),
987
                                                       QMessageBox.Ignore | QMessageBox.Cancel):
988
                return False
989
            return True
990

    
991
    def actionSaveCliked(self):
992
        """
993
        save current drawing
994
        @return:
995
        """
996
        from EngineeringAbstractItem import QEngineeringAbstractItem
997
        from SaveWorkCommand import SaveWorkCommand
998

    
999
        try:
1000
            home_pane = self.ribbon.get_pane('Home File')
1001
            if not home_pane.ui.toolButtonFileSave.isEnabled():
1002
                return
1003

    
1004
            home_pane.ui.toolButtonFileSave.setEnabled(False)
1005

    
1006
            # save alarm
1007
            self.save_alarm_enable(False)
1008

    
1009
            app_doc_data = AppDocData.instance()
1010
            if app_doc_data.imgName is None:
1011
                self.showImageSelectionMessageBox()
1012
                return
1013

    
1014
            app_doc_data.clearItemList(False)
1015

    
1016
            items = self.graphicsView.scene().items()
1017

    
1018
            self._save_work_cmd = SaveWorkCommand(self.graphicsView.scene())
1019
            self._save_work_cmd.show_progress.connect(self.progress_bar.setValue)
1020
            self._save_work_cmd.display_message.connect(self.onAddMessage)
1021
            self._save_work_cmd.finished.connect(self.save_finished)
1022

    
1023
            self._save_work_cmd.start()
1024
        except Exception as ex:
1025
            message = f"error occurred({repr(ex)}) in {sys.exc_info()[-1].tb_frame.f_code.co_filename}:" \
1026
                      f"{sys.exc_info()[-1].tb_lineno}"
1027
            self.addMessage.emit(MessageType.Error, message)
1028

    
1029
    def save_finished(self):
1030
        """
1031
        reload drawing list when save is finished
1032
        @return: None
1033
        """
1034

    
1035
        try:
1036
            self._save_work_cmd.show_progress.emit(100)
1037
            QMessageBox.about(self.graphicsView, self.tr('Information'), self._save_work_cmd.resultStr)
1038
            self.load_drawing_list()
1039

    
1040
            app_doc_data = AppDocData.instance()
1041
            app_doc_data.activeDrawing.modified = False
1042
            title = self.windowTitle()
1043
            self.setWindowTitle(title[:-1] if title[-1] == '*' else title)
1044

    
1045
            # save alarm
1046
            self.save_alarm_enable(True)
1047
        finally:
1048
            home_pane = self.ribbon.get_pane('Home File')
1049
            home_pane.ui.toolButtonFileSave.setEnabled(True)
1050

    
1051
    '''
1052
        @brief      refresh resultPropertyTableWidget
1053
        @author     kyouho
1054
        @date       2018.07.19
1055
    '''
1056
    def refreshResultPropertyTableWidget(self):
1057
        items = self.graphicsView.scene().selectedItems()
1058
        if len(items) == 1:
1059
            self.resultPropertyTableWidget.show_item_property(items[0])
1060

    
1061
    '''
1062
        @brief  add message listwidget
1063
        @author humkyung
1064
        @date   2018.07.31
1065
    '''
1066
    def onAddMessage(self, messageType, message):
1067
        from AppDocData import MessageType
1068

    
1069
        try:
1070
            current = QDateTime.currentDateTime()
1071

    
1072
            item = QListWidgetItem('{}: {}'.format(current.toString('hh:mm:ss'), message))
1073
            item.setFlags(item.flags() | Qt.ItemIsEditable)
1074
            if messageType == MessageType.Error:
1075
                item.setBackground(Qt.red)
1076
            elif messageType == 'check':
1077
                item.setBackground(Qt.yellow)
1078

    
1079
            self.listWidgetLog.insertItem(0, item)
1080
        except Exception as ex:
1081
            print('error occurred({}) in {}:{}'.format(ex, sys.exc_info()[-1].tb_frame.f_code.co_filename,
1082
                                                       sys.exc_info()[-1].tb_lineno))
1083

    
1084
    def on_clear_log(self):
1085
        """clear log"""
1086
        self.listWidgetLog.clear()
1087

    
1088
    def onRotate(self, action):
1089
        """rotate a selected symbol"""
1090
        selected = [item for item in self.graphicsView.scene().selectedItems() if issubclass(type(item), SymbolSvgItem)]
1091
        if len(selected) == 1:
1092
            from RotateCommand import RotateCommand
1093
            self.graphicsView.scene()._undo_stack.push(RotateCommand(self.graphicsView.scene(), selected))
1094

    
1095
    def onAreaZoom(self):
1096
        """Area Zoom"""
1097
        visualization_pane = self.ribbon.get_pane('Home Visualization')
1098

    
1099
        self.update_action_group(visualization_pane.ui.toolButtonZoom)
1100
        if visualization_pane.ui.toolButtonZoom.isChecked():
1101
            cmd = AreaZoomCommand.AreaZoomCommand(self.graphicsView)
1102
            cmd.onRejected.connect(self.onCommandRejected)
1103
            self.graphicsView.command = cmd
1104

    
1105
    def onVendor(self, action):
1106
        """make vendor/equipment package area"""
1107

    
1108
        pane = self.ribbon.get_pane('Home')
1109
        if not self.graphicsView.hasImage():
1110
            pane.ui.toolButtonVendor.setChecked(False)
1111
            self.showImageSelectionMessageBox()
1112
            return
1113

    
1114
        pane = self.ribbon.get_pane('Home')
1115
        self.update_action_group(pane.ui.toolButtonVendor)
1116
        checked = pane.ui.toolButtonVendor.isChecked()
1117
        if not hasattr(pane.ui.toolButtonVendor, 'tag'):
1118
            pane.ui.toolButtonVendor.tag = PlacePolygonCommand.PlacePolygonCommand(self.graphicsView)
1119
            pane.ui.toolButtonVendor.tag.onSuccess.connect(self.onVendorCreated)
1120
            pane.ui.toolButtonVendor.tag.onRejected.connect(self.onCommandRejected)
1121

    
1122
        self.graphicsView.command = pane.ui.toolButtonVendor.tag
1123

    
1124
    def onVendorCreated(self):
1125
        """add created vendor polygon area to scene"""
1126

    
1127
        try:
1128
            vendor_tool = self.ribbon.get_pane('Home').ui.toolButtonVendor
1129
            package_combo = self.ribbon.get_pane('Home').ui.comboBoxPackage
1130
            count = len(vendor_tool.tag._polyline._vertices)
1131
            if count > 2:
1132
                points = []
1133
                for point in vendor_tool.tag._polyline._vertices:
1134
                    points.append(QPoint(round(point[0]), round(point[1])))
1135
                polygon = QPolygonF(points)
1136
                item = QEngineeringVendorItem(polygon, pack_type=package_combo.currentText())
1137
                item.area = 'Drawing'
1138
                item.transfer.onRemoved.connect(self.itemRemoved)
1139
                self.graphicsView.scene().addItem(item)
1140
        finally:
1141
            self.graphicsView.scene().removeItem(vendor_tool.tag._polyline)
1142
            vendor_tool.tag.reset()
1143

    
1144
    def fitWindow(self, view_rect: QRectF = QRectF()):
1145
        """Fit Window"""
1146
        self.graphicsView.useDefaultCommand()
1147
        self.graphicsView.zoomImageInit()
1148

    
1149
        visualization_pane = self.ribbon.get_pane('Home Visualization')
1150
        self.update_action_group(visualization_pane.ui.toolButtonFitWindow)
1151
        if view_rect:
1152
            self.graphicsView.zoom_rect(view_rect)
1153

    
1154
    def on_toggle_lock_axis(self):
1155
        """toggle lock axis"""
1156
        from EngineeringPolylineItem import QEngineeringPolylineItem
1157

    
1158
        visualization_pane = self.ribbon.get_pane('Home Visualization')
1159
        if self.sender() is not visualization_pane.ui.toolButtonLockAxis:
1160
            checked = visualization_pane.ui.toolButtonLockAxis.isChecked()
1161
            visualization_pane.ui.toolButtonLockAxis.setChecked(not checked)
1162

    
1163
        checked = visualization_pane.ui.toolButtonLockAxis.isChecked()
1164
        QEngineeringPolylineItem.DRAWING_MODE = QEngineeringPolylineItem.AXIS_MODE if checked else \
1165
            QEngineeringPolylineItem.FREE_MODE
1166

    
1167
    def scene_changed(self):
1168
        """update modified flag"""
1169

    
1170
        self.display_number_of_items()
1171

    
1172
        app_doc_data = AppDocData.instance()
1173
        app_doc_data.activeDrawing.modified = True
1174
        title = self.windowTitle()
1175
        self.setWindowTitle(title if title[-1] == '*' else title + '*')
1176

    
1177
    def onConvertPDFToImage(self):
1178
        """convert to selected pdf to image"""
1179
        import os
1180

    
1181
        try:
1182
            file_path = os.path.join(os.path.dirname(os.path.realpath(__file__)), 'bin64', 'PDF_TO_IMAGE.exe')
1183
            os.startfile(file_path)
1184
        except Exception as ex:
1185
            message = 'error occurred({}) in {}:{}'.format(ex, sys.exc_info()[-1].tb_frame.f_code.co_filename,
1186
                                                           sys.exc_info()[-1].tb_lineno)
1187
            self.addMessage.emit(MessageType.Error, message)
1188

    
1189
    def on_import_text_from_cad_for_instrument(self):
1190
        """ import text from cad for instrument """
1191
        try:
1192
            self.onCommandRejected()
1193
            dialog = QImportTextFromPDFDialog(self)
1194
            dialog.show()
1195
            dialog.exec_()
1196
        except Exception as ex:
1197
            message = f"error occurred({repr(ex)}) in {sys.exc_info()[-1].tb_frame.f_code.co_filename}:" \
1198
                      f"{sys.exc_info()[-1].tb_lineno}"
1199
            self.addMessage.emit(MessageType.Error, message)
1200

    
1201
    def on_import_text_from_cad(self):
1202
        """ import text from cad """
1203
        try:
1204
            self.onCommandRejected()
1205
            dialog = QImportTextFromCADDialog(self)
1206
            dialog.show()
1207
            dialog.exec_()
1208
        except Exception as ex:
1209
            message = f"error occurred({repr(ex)}) in {sys.exc_info()[-1].tb_frame.f_code.co_filename}:" \
1210
                      f"{sys.exc_info()[-1].tb_lineno}"
1211
            self.addMessage.emit(MessageType.Error, message)
1212

    
1213
    def on_export_PDF(self):
1214
        if not self.graphicsView.hasImage():
1215
            self.showImageSelectionMessageBox()
1216
            return
1217

    
1218
        try:
1219
            printer = QPrinter(QPrinter.HighResolution)
1220
            #printer.setPageSize(QPrinter.A4)
1221
            printer.setOrientation(QPrinter.Orientation.Landscape)
1222
            dialog = QPrintDialog(printer)
1223
            if (dialog.exec() == QDialog.Accepted):
1224
                painter = QPainter(printer)
1225
                isfull_print = False
1226

    
1227
                scene = self.graphicsView.scene()
1228

    
1229
                #for item in scene.items():
1230
                #    if not hasattr(item, 'connectors'): continue
1231
                #    for connector in item.connectors: connector.setVisible(False)
1232

    
1233
                canvasRect = scene.sceneRect() # or canvasRect = scene.border.boundingRect()
1234
                source = canvasRect
1235
                page = printer.pageRect(QPrinter.Unit.DevicePixel)
1236
                target = QRectF(QPointF(0, 0), QSizeF(page.width(), page.height()))
1237
                scene.render(painter, target, source)
1238
                painter.end()
1239

    
1240
                #for item in scene.items():
1241
                #    if not hasattr(item, 'connectors'): continue
1242
                #    for connector in item.connectors: connector.setVisible(True)
1243

    
1244
        except Exception as ex:
1245
            message = 'error occurred({}) in {}:{}'.format(ex, sys.exc_info()[-1].tb_frame.f_code.co_filename,
1246
                                                           sys.exc_info()[-1].tb_lineno)
1247
            self.addMessage.emit(MessageType.Error, message)
1248

    
1249
    def onSymbolThickness(self):
1250
        """ symbol thickness reinforcement by using configuration filter drawing dilate size """
1251
        try:
1252
            self.onCommandRejected()
1253
            dialog = QSymbolThicknessDialog(self)
1254
            dialog.exec_()
1255
        except Exception as ex:
1256
            message = 'error occurred({}) in {}:{}'.format(ex, sys.exc_info()[-1].tb_frame.f_code.co_filename,
1257
                                                           sys.exc_info()[-1].tb_lineno)
1258
            self.addMessage.emit(MessageType.Error, message)
1259

    
1260
    def on_help(self):
1261
        """ open help file """
1262
        import os
1263

    
1264
        try:
1265
            help_file_path = os.path.join(os.path.dirname(os.path.realpath(__file__)), 'ID2 User Manual.pdf')
1266
            if os.path.exists(help_file_path):
1267
                os.startfile(f"\"{help_file_path}\"")
1268
            else:
1269
                QMessageBox.warning(self, self.tr('Warning'), self.tr('There is no help file'))
1270
        except Exception as ex:
1271
            message = f"error occurred({repr(ex)}) in {sys.exc_info()[-1].tb_frame.f_code.co_filename}:" \
1272
                      f"{sys.exc_info()[-1].tb_lineno}"
1273
            self.addMessage.emit(MessageType.Error, message)
1274

    
1275
    def on_readme(self):
1276
        """open readme.html"""
1277

    
1278
        file_path = os.path.join(os.path.dirname(os.path.realpath(__file__)), 'readme.html')
1279
        if os.path.exists(file_path):
1280
            os.startfile(f"\"{file_path}\"")
1281
        else:
1282
            QMessageBox.warning(self, self.tr('Warning'), self.tr('There is no readme file'))
1283

    
1284
    def onSelectionChanged(self):
1285
        """selection changed"""
1286
        items = [item for item in self.graphicsView.scene().selectedItems() if issubclass(type(item), SymbolSvgItem) or
1287
                 type(item) is QEngineeringLineItem or issubclass(type(item), QEngineeringTextItem) or
1288
                 type(item) is QEngineeringUnknownItem or type(item) is QEngineeringVendorItem]
1289
        if items:
1290
            lineNos = [item for item in items if type(item) is QEngineeringLineNoTextItem]
1291
            item = items[-1] if not lineNos else lineNos[0]
1292
            self.itemTreeWidget.findItem(item)
1293
            self.resultPropertyTableWidget.show_item_property(item)
1294
            if type(item) is QEngineeringErrorItem:
1295
                for index in range(self.tableWidgetInconsistency.rowCount()):
1296
                    if self.tableWidgetInconsistency.item(index, 1).tag is item:
1297
                        self.tableWidgetInconsistency.selectRow(index)
1298
                        break
1299
            if issubclass(type(item), SymbolSvgItem):
1300
                pass
1301
                #self.symbolTreeWidget.select_symbol(item)
1302
        else:
1303
            self.resultPropertyTableWidget.show_item_property(None)
1304

    
1305
    '''
1306
        @brief      Initialize scene and itemTreeWidget
1307
        @author     Jeongwoo
1308
        @date       2018.06.14
1309
        @history    humkyung 2018.08.16 ask to delete recognized items before remove
1310
    '''
1311
    def on_initialize_scene(self, action):
1312
        if not self.graphicsView.hasImage():
1313
            self.showImageSelectionMessageBox()
1314

    
1315
            return
1316

    
1317
        try:
1318
            msg = QMessageBox()
1319
            msg.setIcon(QMessageBox.Critical)
1320
            msg.setText(self.tr('Do you want to remove all items?\nThis work cannot be recovered.'))
1321
            msg.setWindowTitle(self.tr("Initialize"))
1322
            msg.setStandardButtons(QMessageBox.Ok | QMessageBox.Cancel)
1323
            if QMessageBox.Ok == msg.exec_():
1324
                app_doc_data = AppDocData.instance()
1325
                app_doc_data.clearItemList(True)
1326

    
1327
                scene = self.graphicsView.scene()
1328
                pixmap = self.graphicsView.getPixmapHandle()
1329
                scene.removeItem(pixmap)    # disconnect pixmap from scene
1330
                scene.clear()               # remove all items from scene and then delete them
1331
                scene.addItem(pixmap)       # add pixmap
1332

    
1333
                if self.path is not None:
1334
                    baseName = os.path.basename(self.path)
1335
                    self.itemTreeWidget.setCurrentPID(baseName)
1336

    
1337
        except Exception as ex:
1338
            message = 'error occurred({}) in {}:{}'.format(ex, sys.exc_info()[-1].tb_frame.f_code.co_filename,
1339
                                                           sys.exc_info()[-1].tb_lineno)
1340
            self.addMessage.emit(MessageType.Error, message)
1341

    
1342
    def checked_action(self):
1343
        """return checked action"""
1344
        home_file_pane = self.ribbon.get_pane('Home File')
1345
        home_pane = self.ribbon.get_pane('Home')
1346
        visualization_pane = self.ribbon.get_pane('Home Visualization')
1347
        actions = [home_pane.ui.toolButtonRecognition, home_pane.ui.toolButtonLinkAttribute,
1348
                   home_pane.ui.toolButtonLine, home_pane.ui.toolButtonOCR, visualization_pane.ui.toolButtonZoom,
1349
                   visualization_pane.ui.toolButtonFitWindow, home_pane.ui.toolButtonVendor]
1350

    
1351
        checked = [ui_ for ui_ in actions if ui_.isChecked()]
1352
        return checked[0] if checked else None
1353

    
1354
    def update_action_group(self, ui):
1355
        """Manage Checkable Action statement"""
1356
        home_file_pane = self.ribbon.get_pane('Home File')
1357
        home_pane = self.ribbon.get_pane('Home')
1358
        visualization_pane = self.ribbon.get_pane('Home Visualization')
1359
        actions = [home_pane.ui.toolButtonRecognition, home_pane.ui.toolButtonLinkAttribute, home_pane.ui.toolButtonLine,
1360
                   home_pane.ui.toolButtonOCR, visualization_pane.ui.toolButtonZoom,
1361
                   visualization_pane.ui.toolButtonFitWindow, home_file_pane.ui.toolButtonFileSave,
1362
                   home_pane.ui.toolButtonValidate, home_pane.ui.toolButtonVendor]
1363

    
1364
        if hasattr(ui, 'tag'):
1365
            ui.tag.onRejected.emit(None)
1366

    
1367
        if self.graphicsView.command is not None:
1368
            self.graphicsView.useDefaultCommand()
1369

    
1370
        for ui_ in actions:
1371
            ui_.setChecked(False)
1372

    
1373
        ui.setChecked(True)
1374

    
1375
    '''
1376
        @brief      Create Equipment
1377
        @author     Jeongwoo
1378
        @date       18.05.03
1379
        @history    2018.05.04  Jeongwoo    Add Parameter on CreateSymbolCommand
1380
    '''
1381
    def createEquipment(self):
1382
        if not self.graphicsView.hasImage():
1383
            self.actionEquipment.setChecked(False)
1384
            self.showImageSelectionMessageBox()
1385
            return
1386
        if self.actionEquipment.isChecked():
1387
            self.graphicsView.command = CreateSymbolCommand.CreateSymbolCommand(self.graphicsView, self.itemTreeWidget,
1388
                                                                                self.symbolTreeWidget)
1389
        else:
1390
            self.graphicsView.useDefaultCommand()
1391

    
1392
    '''
1393
        @brief      Create Nozzle
1394
        @author     Jeongwoo
1395
        @date       2018.05.03
1396
        @history    2018.05.04  Jeongwoo    Add Parameter on CreateSymbolCommand
1397
    '''
1398
    def createNozzle(self):
1399
        if not self.graphicsView.hasImage():
1400
            self.actionNozzle.setChecked(False)
1401
            self.showImageSelectionMessageBox()
1402
            return
1403
        if self.actionNozzle.isChecked():
1404
            self.graphicsView.command = CreateSymbolCommand.CreateSymbolCommand(self.graphicsView, self.itemTreeWidget,
1405
                                                                                self.symbolTreeWidget)
1406
        else:
1407
            self.graphicsView.useDefaultCommand()
1408

    
1409
    def onAreaOcr(self):
1410
        """Area OCR"""
1411
        if not self.graphicsView.hasImage():
1412
            self.actionOCR.setChecked(False)
1413
            self.showImageSelectionMessageBox()
1414
            return
1415

    
1416
        pane = self.ribbon.get_pane('Home')
1417
        ui = pane.ui.toolButtonOCR
1418
        self.update_action_group(ui=ui)
1419
        checked = ui.isChecked()
1420
        if checked:
1421
            cmd = AreaOcrCommand.AreaOcrCommand(self.graphicsView)
1422
            cmd.onSuccess.connect(self.onRecognizeText)
1423
            cmd.onRejected.connect(self.onCommandRejected)
1424
            self.graphicsView.command = cmd
1425
        else:
1426
            self.graphicsView.useDefaultCommand()
1427

    
1428
    def onRecognizeText(self, x, y, width, height, show=True):
1429
        """show text recognition dialog"""
1430
        from OcrResultDialog import QOcrResultDialog
1431
        from Area import Area
1432

    
1433
        try:
1434
            app_doc_data = AppDocData.instance()
1435

    
1436
            modifiers = QApplication.keyboardModifiers()
1437
            image = self.graphicsView.image().copy(x, y, width, height)
1438
            dialog = QOcrResultDialog(self, image, QRectF(x, y, width, height),
1439
                                      format=QOcrResultDialog.Format.Table if modifiers == Qt.AltModifier else QOcrResultDialog.Format.Normal)
1440
            if modifiers == Qt.ControlModifier:
1441
                return
1442
            
1443
            if show:
1444
                (res, textInfoList) = dialog.showDialog()
1445
            else:
1446
                dialog.accept(show=False)
1447
                (res, textInfoList) = QDialog.Accepted, dialog.textInfoList
1448

    
1449
            if QDialog.Accepted == res and textInfoList:
1450
                for textInfo in textInfoList:
1451
                    item = QEngineeringTextItem.create_text_with(self.graphicsView.scene(), textInfo)
1452
                    if item:
1453
                        item.setDefaultTextColor(Qt.blue)
1454
                        item.transfer.onRemoved.connect(self.itemRemoved)
1455

    
1456
                        area_list = app_doc_data.getAreaList()
1457
                        title_area_list = app_doc_data.getTitleBlockProperties()
1458
                        title_list = []
1459
                        if title_area_list:
1460
                            for title_area in title_area_list:
1461
                                area = Area(title_area[0])
1462
                                area.parse(title_area[2])
1463
                                title_list.append(area)
1464
                        for area in area_list + title_list:
1465
                            pt = [item.sceneBoundingRect().center().x(), item.sceneBoundingRect().center().y()]
1466
                            if area.contains(pt):
1467
                                item.area = area.name
1468
                                break
1469
                    else:
1470
                        self.addMessage.emit(MessageType.Normal, self.tr('Fail to create text.'))
1471

    
1472
                return True
1473
            elif QDialog.Accepted == res and not textInfoList and show:
1474
                QMessageBox.about(self.graphicsView, self.tr("Notice"), self.tr("Fail to recognize text"))
1475
        except Exception as ex:
1476
            message = 'error occurred({}) in {}:{}'.format(ex, sys.exc_info()[-1].tb_frame.f_code.co_filename,
1477
                                                           sys.exc_info()[-1].tb_lineno)
1478
            self.addMessage.emit(MessageType.Error, message)
1479
        
1480
        return False
1481

    
1482
    '''
1483
        @brief  area configuration
1484
    '''
1485
    def areaConfiguration(self):
1486
        from ConfigurationAreaDialog import QConfigurationAreaDialog
1487
        if not self.graphicsView.hasImage():
1488
            self.showImageSelectionMessageBox()
1489
            return
1490
        self.onCommandRejected()
1491
        dlgConfigurationArea = QConfigurationAreaDialog(self)
1492
        dlgConfigurationArea.show()
1493
        dlgConfigurationArea.exec_()
1494

    
1495
    '''
1496
        @brief  configuration
1497
    '''
1498
    def configuration(self):
1499
        from ConfigurationDialog import QConfigurationDialog
1500

    
1501
        dlgConfiguration = QConfigurationDialog(self)
1502
        if QDialog.Accepted == dlgConfiguration.exec_():
1503
            QEngineeringLineItem.LINE_TYPE_COLORS.clear()
1504
            QEngineeringInstrumentItem.INST_COLOR = None
1505

    
1506
    '''
1507
        @brief  show special item types dialog 
1508
        @author humkyung
1509
        @date   2019.08.10
1510
    '''
1511
    def on_show_special_item_types(self):
1512
        from SpecialItemTypesDialog import QSpecialItemTypesDialog
1513

    
1514
        dlg = QSpecialItemTypesDialog(self)
1515
        dlg.exec_()
1516

    
1517
    def on_show_data_transfer(self):
1518
        """ show data transfer dialog """
1519
        from DataTransferDialog import QDataTransferDialog
1520

    
1521
        dlg = QDataTransferDialog(self)
1522
        dlg.exec_()
1523

    
1524
    def on_show_data_export(self):
1525
        """ show data export dialog """
1526
        from DataExportDialog import QDataExportDialog
1527

    
1528
        dlg = QDataExportDialog(self)
1529
        dlg.exec_()
1530

    
1531
    def on_show_eqp_datasheet_export(self):
1532
        """ show eqp datasheet export dialog """
1533
        from EqpDatasheetExportDialog import QEqpDatasheetExportDialog
1534

    
1535
        dlg = QEqpDatasheetExportDialog(self)
1536
        dlg.exec_()
1537

    
1538
    def on_show_opc_relation(self):
1539
        """ show opc relation dialog """
1540
        from OPCRelationDialog import QOPCRelationDialog
1541

    
1542
        dlg = QOPCRelationDialog(self)
1543
        dlg.exec_()
1544

    
1545
    '''
1546
        @brief  show nominal diameter dialog 
1547
        @author humkyung
1548
        @date   2018.06.28
1549
    '''
1550
    def onShowCodeTable(self):
1551
        from CodeTableDialog import QCodeTableDialog
1552

    
1553
        dlg = QCodeTableDialog(self)
1554
        dlg.show()
1555
        dlg.exec_()
1556
        if dlg.code_area:
1557
            if dlg.code_area.scene():
1558
                self.graphicsView.scene().removeItem(dlg.code_area)
1559
        if dlg.desc_area:
1560
            if dlg.desc_area.scene():
1561
                self.graphicsView.scene().removeItem(dlg.desc_area)
1562
        self.graphicsView.useDefaultCommand()
1563

    
1564
    def on_ext_app_connection(self):
1565
        from TcpServer import TcpServer
1566

    
1567
        tool_pane = self.ribbon.get_pane('Tool')
1568
        if tool_pane.ui.toolButtonConnection.isChecked():
1569
            if not hasattr(self, '_tcpserver'):
1570
                self._tcpserver = TcpServer()
1571
                self._tcpserver.sessionOpened()
1572
        else:
1573
            self._tcpserver.sessionClosed()
1574
            del self._tcpserver
1575

    
1576
    def on_execute_ext_app(self):
1577
        """execute external application"""
1578
        from ExtAppsDialog import QExtAppsDialog
1579

    
1580
        dlg = QExtAppsDialog(self)
1581
        dlg.exec_()
1582

    
1583
    def onShowCustomCodeTable(self):
1584
        from CustomCodeTablesDialog import CustomCodeTablesDialog
1585

    
1586
        dlg = CustomCodeTablesDialog(self)
1587
        dlg.show()
1588
        dlg.exec_()
1589
        self.graphicsView.useDefaultCommand()
1590

    
1591
    def onShowReplaceCodeTable(self):
1592
        from CustomCodeTablesDialog import CustomCodeTablesDialog
1593

    
1594
        dlg = CustomCodeTablesDialog(self, replace=True)
1595
        dlg.show()
1596
        dlg.exec_()
1597
        self.graphicsView.useDefaultCommand()
1598

    
1599
    def on_streamline(self):
1600
        """pop up stream line dialog"""
1601
        from StreamlineDialog import QStreamlineDialog
1602

    
1603
        if not self.graphicsView.hasImage():
1604
            self.showImageSelectionMessageBox()
1605
            return
1606

    
1607
        hmbs = AppDocData.instance().get_hmb_data(None)
1608
        if not hmbs:
1609
            return
1610

    
1611
        dlg = QStreamlineDialog(self)
1612
        dlg.show()
1613

    
1614
    def onHMBData(self):
1615
        """show HMB data"""
1616
        from HMBDialog import QHMBDialog
1617

    
1618
        dlg = QHMBDialog(self)
1619
        dlg.show()
1620
        dlg.exec_()
1621

    
1622
    '''
1623
        @brief  show line data list 
1624
        @author humkyung
1625
        @date   2018.05.03
1626
    '''
1627
    def showItemDataList(self):
1628
        from ItemDataExportDialog import QItemDataExportDialog
1629

    
1630
        dlg = QItemDataExportDialog(self)
1631
        dlg.exec_()
1632

    
1633
    def showTextDataList(self):
1634
        '''
1635
            @brief      show all text item in scene
1636
            @author     euisung
1637
            @date       2019.04.18
1638
        '''
1639
        try:
1640
            if not self.graphicsView.hasImage():
1641
                self.showImageSelectionMessageBox()
1642
                return
1643

    
1644
            self.onCommandRejected()
1645
            dialog = QTextDataListDialog(self)
1646
            dialog.show()
1647
        except Exception as ex:
1648
            message = 'error occurred({}) in {}:{}'.format(ex, sys.exc_info()[-1].tb_frame.f_code.co_filename,
1649
                                                           sys.exc_info()[-1].tb_lineno)
1650
            self.addMessage.emit(MessageType.Error, message)
1651

    
1652
    '''
1653
        @brief  Show Image Selection Guide MessageBox
1654
        @author Jeongwoo
1655
        @date   2018.05.02
1656
    '''
1657
    def showImageSelectionMessageBox(self):
1658
        QMessageBox.about(self.graphicsView, self.tr("Notice"), self.tr("First select image drawing"))
1659

    
1660
    def on_search_text_changed(self):
1661
        """filter symbol tree view"""
1662
        regexp = QRegExp(self.lineEditFilter.text(), Qt.CaseInsensitive, QRegExp.FixedString)
1663

    
1664
        proxy_model = self.symbolTreeWidget.model()
1665
        proxy_model.text = self.lineEditFilter.text().lower()
1666
        proxy_model.setFilterRegExp(regexp)
1667

    
1668
        self.symbolTreeWidget.expandAll()
1669

    
1670
    def change_display_colors(self):
1671
        """ change display color mode """
1672
        visualization_pane = self.ribbon.get_pane('Home Visualization')
1673
        if visualization_pane.ui.radioButtonByGroup.isChecked():
1674
            visualization_pane.ui.radioButtonByType.setChecked(True)
1675
        else:
1676
            visualization_pane.ui.radioButtonByGroup.setChecked(True)
1677

    
1678
    def display_colors(self, value):
1679
        """ display colors """
1680
        from DisplayColors import DisplayColors
1681
        from DisplayColors import DisplayOptions
1682

    
1683
        if hasattr(self, 'ribbon'):
1684
            visualization_pane = self.ribbon.get_pane('Home Visualization')
1685
            if self.sender() is visualization_pane.ui.radioButtonByGroup and value is True:
1686
                DisplayColors.instance().option = DisplayOptions.DisplayByLineNo
1687
            elif self.sender() is visualization_pane.ui.radioButtonByType and value is True:
1688
                DisplayColors.instance().option = DisplayOptions.DisplayByLineType
1689
            elif self.sender() is visualization_pane.ui.radioButtonByStreamNo and value is True:
1690
                DisplayColors.instance().option = DisplayOptions.DisplayByStreamNo
1691

    
1692
            if hasattr(self, 'graphicsView') and value is True:
1693
                self.graphicsView.scene().update(self.graphicsView.sceneRect())
1694
                for item in self.graphicsView.scene().items():
1695
                    if issubclass(type(item), SymbolSvgItem):
1696
                        item.update()
1697
                DisplayColors.instance().save_data()
1698

    
1699
    def open_image_drawing(self, drawing, force=False, ocrUnknown=False):
1700
        """open and display image drawing file"""
1701
        from Drawing import Drawing
1702
        from App import App
1703
        from LoadCommand import LoadCommand
1704
        import concurrent.futures as futures
1705

    
1706
        # Yield successive n-sized
1707
        # chunks from l.
1708
        def divide_chunks(l, n):
1709
            # looping till length l
1710
            for i in range(0, len(l), n):
1711
                yield l[i:i + n]
1712

    
1713
        def update_items(items):
1714
            for item in items:
1715
                # binding items
1716
                item.owner
1717
                for connector in item.connectors:
1718
                    connector.connectedItem
1719

    
1720
            return items
1721

    
1722
        try:
1723
            app_doc_data = AppDocData.instance()
1724

    
1725
            if not self.actionSave.isEnabled():
1726
                return
1727

    
1728
            if not force and self.save_drawing_if_necessary():
1729
                return
1730

    
1731
            occupied = app_doc_data.set_occupying_drawing(drawing.UID)
1732
            if occupied:
1733
                QMessageBox.about(self.graphicsView, self.tr("Notice"),
1734
                                  self.tr(f"The drawing is locked for editing by another user({occupied})"))
1735
                return
1736

    
1737
            # save alarm
1738
            self.save_alarm_enable(False)
1739

    
1740
            if hasattr(self, '_save_work_cmd'):
1741
                self._save_work_cmd.wait()
1742

    
1743
            project = app_doc_data.getCurrentProject()
1744

    
1745
            self.path = self.graphicsView.loadImageFromFile(drawing)
1746
            if os.path.isfile(self.path):
1747
                self.onCommandRejected()
1748
                app_doc_data.clear(past=drawing.UID)
1749

    
1750
                # load color for stream no coloring
1751
                configs = app_doc_data.getConfigs('Line List', 'Use Stream No')
1752
                if configs and int(configs[0].value) == 1:
1753
                    hmbs = app_doc_data.get_hmb_data(None)
1754
                    colors = {}
1755
                    if hmbs:
1756
                        for hmb in hmbs:
1757
                            rgb = app_doc_data.colors
1758
                            colors[hmb.stream_no] = QColor(rgb.red, rgb.green, rgb.blue).name()
1759
                        app_doc_data._hmbColors = colors
1760
                # up to here
1761

    
1762
                app_doc_data.setImgFilePath(self.path)
1763
                app_doc_data.activeDrawing = drawing
1764
                
1765
                #app_doc_data.activeDrawing.set_pid_source(Image.open(self.path))
1766
                self.itemTreeWidget.setCurrentPID(app_doc_data.activeDrawing.name)
1767

    
1768
                drawingList = self.treeWidgetDrawingList.topLevelItem(0)
1769
                for idx in range(drawingList.childCount()):
1770
                    child = drawingList.child(idx)
1771
                    if child.data(Qt.UserRole, 0) is drawing:
1772
                        child.setCheckState(0, Qt.Checked)
1773
                    else:
1774
                        child.setCheckState(0, Qt.Unchecked)
1775

    
1776
                try:
1777
                    self.show_Progress_bar()
1778

    
1779
                    # disconnect scene changed if signal is connected
1780
                    if self.graphicsView.scene().receivers(self.graphicsView.scene().contents_changed) > 0:
1781
                        self.graphicsView.scene().contents_changed.disconnect()
1782

    
1783
                    SymbolSvgItem.DOCUMENTS.clear()
1784

    
1785
                    # load data
1786
                    cmd = LoadCommand()
1787
                    cmd.display_message.connect(self.onAddMessage)
1788
                    cmd.set_maximum.connect(self.progress.setMaximum)
1789
                    cmd.show_progress.connect(self.progress.setValue)
1790
                    cmd.execute((drawing, self.graphicsView.scene()),
1791
                                symbol=True, text=True, line=True, unknown=True, package=True, update=True)
1792

    
1793
                    configs = app_doc_data.getConfigs('Line List', 'Use Stream No')
1794
                    if configs and int(configs[0].value) == 1:
1795
                        app_doc_data._streamLineListModelDatas = app_doc_data.get_stream_line_list_data()
1796
                    # up to here
1797

    
1798
                    """update item tree widget"""
1799
                    line_no_items = [item for item in self.graphicsView.scene().items()
1800
                                     if type(item) is QEngineeringLineNoTextItem]
1801
                    for line_no in line_no_items:
1802
                        line_no_tree_item = self.itemTreeWidget.addTreeItem(self.itemTreeWidget.root, line_no)
1803
                        for run in line_no.runs:
1804
                            for run_item in run.items:
1805
                                if issubclass(type(run_item), SymbolSvgItem):
1806
                                    self.init_add_tree_item(line_no_tree_item, run_item)
1807

    
1808
                    line_no_items = [item for item in self.graphicsView.scene().items()
1809
                                     if type(item) is QEngineeringTrimLineNoTextItem]
1810
                    for line_no in line_no_items:
1811
                        line_no_tree_item = self.itemTreeWidget.addTreeItem(self.itemTreeWidget.root, line_no)
1812
                        for run in line_no.runs:
1813
                            for run_item in run.items:
1814
                                if issubclass(type(run_item), SymbolSvgItem):
1815
                                    self.init_add_tree_item(line_no_tree_item, run_item)
1816

    
1817
                    for trim_line_no in app_doc_data.tracerLineNos:
1818
                        line_no_tree_item = self.itemTreeWidget.addTreeItem(self.itemTreeWidget.root, trim_line_no)
1819
                        for run in trim_line_no.runs:
1820
                            for run_item in run.items:
1821
                                if issubclass(type(run_item), SymbolSvgItem):
1822
                                    self.init_add_tree_item(line_no_tree_item, run_item)
1823

    
1824
                    self.itemTreeWidget.update_item_count()
1825
                    self.itemTreeWidget.expandAll()
1826
                    """up to here"""
1827

    
1828
                    """update scene"""
1829
                    for item in self._scene.items():
1830
                        item.setVisible(True)
1831

    
1832
                    self._scene.update(self._scene.sceneRect())
1833

    
1834
                    """
1835
                    # old open drawing
1836
                    path = os.path.join(app_doc_data.getCurrentProject().getTempPath(), app_doc_data.imgName + '.xml')
1837
                    configs = app_doc_data.getConfigs('Data Load', 'Xml First')
1838
                    if configs and int(configs[0].value) >= 1 and os.path.isfile(path):
1839
                        self.load_recognition_result_from_xml(drawing)
1840
                    elif configs and int(configs[0].value) <= 1:
1841
                        self.load_drawing(app_doc_data.activeDrawing)
1842
                    """
1843

    
1844
                    self.display_number_of_items()
1845
                    # connect scene changed signal
1846
                    self.graphicsView.scene().contents_changed.connect(self.scene_changed)
1847
                finally:
1848
                    if hasattr(self, 'progress'):
1849
                        self.progress.setValue(self.progress.maximum())
1850

    
1851
                self.changeViewCheckedState(True)
1852
                self.setWindowTitle(self.title)
1853
                self.fitWindow(drawing.view_rect)
1854

    
1855
                if ocrUnknown:
1856
                    self.on_ocr_unknown_items()
1857

    
1858
                # save alarm
1859
                self.save_alarm_enable(True, True)
1860
        except Exception as ex:
1861
            message = f"error occurred({repr(ex)}) in {sys.exc_info()[-1].tb_frame.f_code.co_filename}:" \
1862
                      f"{sys.exc_info()[-1].tb_lineno}"
1863
            self.addMessage.emit(MessageType.Error, message)
1864

    
1865
        return self.path
1866

    
1867
    def save_alarm_enable(self, enable, init=False):
1868
        from datetime import datetime
1869

    
1870
        try:
1871
            app_doc_data = AppDocData.instance()
1872
            configs = app_doc_data.getConfigs('Data Save', 'Time')
1873
            time_min = int(configs[0].value) if 1 == len(configs) else 0
1874

    
1875
            if enable and time_min > 0:
1876
                if not self.save_timer:
1877
                    self.save_timer = QTimer()
1878
                    self.save_timer.timeout.connect(self.save_alarm)
1879
                    self.save_timer.setInterval(60000)
1880

    
1881
                if init:
1882
                    self.save_timer._init_time = datetime.now()
1883
                    self.save_timer._stop_time = None
1884
                    self.save_timer._interval_time = datetime.now() - datetime.now()
1885

    
1886
                if self.save_timer._stop_time:
1887
                    self.save_timer._interval_time = datetime.now() - self.save_timer._stop_time
1888
                
1889
                #if 60000 * time_min != self.save_timer.interval():
1890
                #    self.save_timer.setInterval(60000)
1891

    
1892
                self.save_timer.start()
1893
            else:
1894
                if self.save_timer:
1895
                    self.save_timer.stop()
1896
                    self.save_timer._stop_time = datetime.now()
1897
        
1898
        except Exception as ex:
1899
            message = f"error occurred({repr(ex)}) in {sys.exc_info()[-1].tb_frame.f_code.co_filename}:" \
1900
                      f"{sys.exc_info()[-1].tb_lineno}"
1901
            self.addMessage.emit(MessageType.Error, message)
1902

    
1903
    def save_alarm(self):
1904
        from datetime import datetime
1905

    
1906
        app_doc_data = AppDocData.instance()
1907
        configs = app_doc_data.getConfigs('Data Save', 'Time')
1908
        time_min = int(configs[0].value) if 1 == len(configs) else 0
1909

    
1910
        self.save_timer.stop()
1911
        if self.graphicsView.hasFocus() and (datetime.now() - self.save_timer._init_time - self.save_timer._interval_time).seconds > time_min * 60:
1912
            QMessageBox.information(self, self.tr('Information'), self.tr('Please save Drawing'))
1913
            self.save_timer._init_time = datetime.now()
1914
            self.save_timer._interval_time = datetime.now() - datetime.now()
1915
        self.save_timer.start()
1916

    
1917
    def export_as_svg(self):
1918
        """export scene to svg file"""
1919
        from ExportCommand import ExportCommand
1920

    
1921
        options = QFileDialog.Options()
1922
        options |= QFileDialog.DontUseNativeDialog
1923
        file_path, _ = QFileDialog.getSaveFileName(self, "Export as svg", os.getcwd(), "svg file(*.svg)",
1924
                                                   options=options)
1925
        if file_path:
1926
            cmd = ExportCommand(self.graphicsView.scene(), 'svg')
1927
            cmd.display_message.connect(self.onAddMessage)
1928
            if cmd.execute(file_path):
1929
                QMessageBox.information(self, self.tr('Information'), self.tr('Successfully export to svg file'))
1930
            else:
1931
                QMessageBox.information(self, self.tr('Error'), self.tr('Fail to export to svg file'))
1932

    
1933
    def export_as_xml(self):
1934
        pass
1935

    
1936
    def export_as_image(self):
1937
        """export scene to image file"""
1938
        from ExportCommand import ExportCommand
1939

    
1940
        options = QFileDialog.Options()
1941
        options |= QFileDialog.DontUseNativeDialog
1942
        file_path, _ = QFileDialog.getSaveFileName(self, "Export as png", os.getcwd(), "png file(*.png)",
1943
                                                   options=options)
1944
        if file_path:
1945
            try:
1946
                # hide image drawing
1947
                self.onViewImageDrawing(False)
1948

    
1949
                cmd = ExportCommand(self.graphicsView.scene(), 'image')
1950
                cmd.display_message.connect(self.onAddMessage)
1951

    
1952
                if cmd.execute(file_path):
1953
                    QMessageBox.information(self, self.tr('Information'), self.tr('Successfully export to image file'))
1954
                else:
1955
                    QMessageBox.information(self, self.tr('Error'), self.tr('Fail to export to image file'))
1956
            finally:
1957
                if self.actionImage_Drawing.isChecked():
1958
                    self.onViewImageDrawing(True)
1959
                    self.actionImage_Drawing.setChecked(True)
1960

    
1961
    def show_Progress_bar(self):
1962
        """ show progress bar """
1963
        self.progress = QProgressDialog(self.tr("Please wait for a while"), self.tr("Cancel"), 0, 100,
1964
                                        self) if not hasattr(self, 'progress') else self.progress
1965
        self.progress.setWindowModality(Qt.WindowModal)
1966
        self.progress.setAutoReset(True)
1967
        self.progress.setAutoClose(True)
1968
        self.progress.setMinimum(0)
1969
        self.progress.setMaximum(100)
1970
        self.progress.resize(600, 100)
1971
        self.progress.setWindowTitle(self.tr("Reading file..."))
1972
        self.progress.show()
1973

    
1974
    def changeViewCheckedState(self, checked, clear=True):
1975
        """change view checked state"""
1976
        # self.actionImage_Drawing.setChecked(checked)
1977
        self.actionViewText.setChecked(checked)
1978
        self.actionViewSymbol.setChecked(checked)
1979
        self.actionViewLine.setChecked(checked)
1980
        self.actionViewUnknown.setChecked(checked)
1981
        self.actionViewInconsistency.setChecked(checked)
1982
        self.actionViewVendor_Area.setChecked(not checked)
1983
        self.actionDrawing_Only.setChecked(not checked)
1984
        if clear:
1985
            self.tableWidgetInconsistency.clearContents()
1986
            self.tableWidgetInconsistency.setRowCount(0)
1987

    
1988
    def onViewDrawingOnly(self, isChecked):
1989
        '''
1990
            @brief  visible/invisible except image drawing
1991
            @author euisung
1992
            @date   2019.04.22
1993
        '''
1994
        self.changeViewCheckedState(not isChecked, False)
1995
        for item in self.graphicsView.scene().items():
1996
            if type(item) is not QGraphicsPixmapItem:
1997
                item.setVisible(not isChecked)
1998

    
1999
    '''
2000
        @brief  visible/invisible image drawing
2001
        @author humkyung
2002
        @date   2018.06.25
2003
    '''
2004
    def onViewImageDrawing(self, isChecked):
2005
        for item in self.graphicsView.scene().items():
2006
            if type(item) is QGraphicsPixmapItem:
2007
                item.setVisible(isChecked)
2008
                break
2009

    
2010
    def onViewText(self, checked):
2011
        """visible/invisible text"""
2012
        selected = [item for item in self.graphicsView.scene().items() if issubclass(type(item), QEngineeringTextItem)
2013
                    and type(item) is not QEngineeringLineNoTextItem]
2014
        for item in selected:
2015
            item.setVisible(checked)
2016

    
2017
    def onViewSymbol(self, checked):
2018
        """visible/invisible symbol"""
2019
        selected = [item for item in self.graphicsView.scene().items() if
2020
                    (issubclass(type(item), SymbolSvgItem) and type(item) is not QEngineeringErrorItem)]
2021
        for item in selected:
2022
            item.setVisible(checked)
2023

    
2024
    def onViewLine(self, checked):
2025
        """visible/invisible line"""
2026
        selected = [item for item in self.graphicsView.scene().items() if type(item) is QEngineeringLineItem]
2027
        for item in selected:
2028
            item.setVisible(checked)
2029

    
2030
    def onViewInconsistency(self, isChecked):
2031
        '''
2032
            @brief  visible/invisible Inconsistency
2033
            @author euisung
2034
            @date   2019.04.03
2035
        '''
2036
        selected = [item for item in self.graphicsView.scene().items() if type(item) is QEngineeringErrorItem]
2037
        for item in selected:
2038
            item.setVisible(isChecked)
2039

    
2040
    '''
2041
        @brief  visible/invisible Unknown 
2042
        @author humkyung
2043
        @date   2018.06.28
2044
    '''
2045
    def onViewUnknown(self, isChecked):
2046
        selected = [item for item in self.graphicsView.scene().items() if type(item) is QEngineeringUnknownItem]
2047
        for item in selected:
2048
            item.setVisible(isChecked)
2049

    
2050
    def onViewVendorArea(self, isChecked):
2051
        '''
2052
            @brief  visible/invisible Vendor Area
2053
            @author euisung
2054
            @date   2019.04.29
2055
        '''
2056
        selected = [item for item in self.graphicsView.scene().items() if issubclass(type(item), QEngineeringVendorItem)]
2057
        for item in selected:
2058
            item.setVisible(isChecked)
2059

    
2060
    '''
2061
        @brief  create a symbol
2062
        @history    2018.05.02  Jeongwoo    Change return value of QSymbolEditorDialog (Single variable → Tuple)
2063
                                            Add SymbolSvgItem
2064
                    2018.05.03  Jeongwoo    Change method to draw Svg Item on Scene (svg.addSvgItemToScene)
2065
                                            Change method to make svg and image path
2066
                    2018.06.08  Jeongwoo    Add Paramter on SymbolSvgItem.buildItem()
2067
    '''
2068
    def onCreateSymbolClicked(self):
2069
        selected = [item for item in self.graphicsView.scene().selectedItems() if issubclass(type(item), QEngineeringVendorItem)]
2070
        if len(selected) == 1:
2071
            symbol_image = AppDocData.instance().activeDrawing.image_origin
2072
            rect = selected[0].sceneBoundingRect()
2073

    
2074
            points = []
2075
            for conn in selected[0].connectors:
2076
                points.append([round(conn.center()[0] - rect.x()), round(conn.center()[1] - rect.y())])
2077
            poly = np.array(points, np.int32)
2078

    
2079
            #mask = np.zeros((int(rect.height()), int(rect.width())))
2080
            #cv2.fillPoly(mask, [poly], (255))
2081
            #poly_copied = np.multiply(mask, symbol_image[round(rect.y()):round(rect.y() + rect.height()),
2082
            #                   round(rect.x()):round(rect.x() + rect.width())])
2083
            #cv2.fillPoly(mask,[poly],0)
2084
            #src2 = np.multiply(mask,src2)
2085

    
2086
            mask = np.ones((int(rect.height()), int(rect.width())), dtype=np.uint8) * 255
2087
            cv2.fillPoly(mask, [poly], (0))
2088
            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())])
2089
            sym_img = cv2.merge((sym_img, sym_img, sym_img))
2090

    
2091
            h, w, c = sym_img.shape
2092
            qImg = QImage(sym_img.data, w, h, w * c, QImage.Format_RGB888)
2093
            #pixmap = QPixmap.fromImage(qImg)
2094

    
2095
            self.onAreaSelected(None, None, None, None, package=qImg, position=rect.topLeft(), package_item=selected[0])
2096
        else:
2097
            cmd = FenceCommand.FenceCommand(self.graphicsView)
2098
            cmd.onSuccess.connect(self.onAreaSelected)
2099
            self.graphicsView.command = cmd
2100
            QApplication.setOverrideCursor(Qt.CrossCursor)
2101

    
2102
    '''
2103
        @brief      show SymbolEditorDialog with image selected by user
2104
        @author     humkyung
2105
        @date       2018.07.20
2106
    '''
2107
    def onAreaSelected(self, x, y, width, height, package=False, position=None, package_item=None):
2108
        try:
2109
            image = self.graphicsView.image()
2110
            if image is not None:
2111
                if not package:
2112
                    symbolEditorDialog = SymbolEditorDialog.QSymbolEditorDialog(self, image.copy(x, y, width, height),
2113
                                                                                AppDocData.instance().getCurrentProject())
2114
                else:
2115
                    symbolEditorDialog = SymbolEditorDialog.QSymbolEditorDialog(self, package,
2116
                                                                                AppDocData.instance().getCurrentProject(), package=True)
2117
                (isAccepted, isImmediateInsert, offsetX, offsetY, newSym) = symbolEditorDialog.showDialog()
2118
                # TODO: not initialize symbol tree view when user reject to create a new symbol
2119
                self.symbolTreeWidget.initSymbolTreeView()
2120
                if isAccepted:
2121
                    if isImmediateInsert:
2122
                        svg = QtImageViewer.createSymbolObject(newSym.getName())
2123
                        offsetX, offsetY = [int(point) for point in newSym.getOriginalPoint().split(',')]
2124
                        QtImageViewer.matchSymbolToLine(self.graphicsView.scene(), svg, QPoint(position.x() + offsetX, position.y() + offsetY))
2125

    
2126
                        package_item.transfer.onRemoved.emit(package_item)
2127
        finally:
2128
            self.onCommandRejected()
2129
            QApplication.restoreOverrideCursor()
2130
            QApplication.restoreOverrideCursor()
2131

    
2132
    def on_line_list(self):
2133
        """ line list export dialog """
2134
        from LineListDialog import LineListDialog
2135

    
2136
        if not self.graphicsView.hasImage():
2137
            self.showImageSelectionMessageBox()
2138
            return
2139

    
2140
        dialog = LineListDialog(self)
2141
        dialog.showDialog()
2142

    
2143
    def on_make_label_data(self):
2144
        """ make label data from symbol info """
2145
        from xml.etree.ElementTree import Element, SubElement, dump, ElementTree, parse
2146

    
2147
        if not self.graphicsView.hasImage():
2148
            self.showImageSelectionMessageBox()
2149
            return
2150

    
2151
        app_doc_data = AppDocData.instance()
2152
        project = app_doc_data.getCurrentProject()
2153

    
2154
        smalls = []
2155
        bigs = []
2156

    
2157
        symbol_list = app_doc_data.getTargetSymbolList(all=True)
2158
        #symbol_list = app_doc_data.getTargetSymbolList(all=False)
2159
        for symbol in symbol_list:
2160
            if symbol.iType == 38 or symbol.iType == 33 or symbol.iType == 0 or symbol.iType == 40:
2161
                continue
2162
            elif symbol.width and symbol.height:
2163
                if symbol.width > 300 or symbol.height > 300:
2164
                    bigs.append(symbol.getName())
2165
                elif (symbol.width * symbol.height < 1500) or (symbol.width > 450 or symbol.height > 450):
2166
                    continue
2167
                else:
2168
                    smalls.append(symbol.getName())
2169

    
2170
        symbols = [item for item in self.graphicsView.scene().items() if issubclass(type(item), SymbolSvgItem)]
2171
        names = [smalls, bigs]
2172

    
2173
        img = app_doc_data.activeDrawing.image_origin
2174

    
2175
        small_size = 500
2176
        big_size = 850
2177

    
2178
        save_path = project.getTrainingSymbolFilePath()
2179

    
2180
        index = 0
2181
        for size in [small_size, big_size]:
2182
            offsets = [0, int(size / 2)]
2183

    
2184
            width, height = img.shape[1], img.shape[0]
2185
            width_count, height_count = width // size + 2, height // size + 2
2186
            b_width, b_height = width_count * size, height_count * size
2187
            b_img = np.zeros((b_height, b_width), np.uint8) + 255
2188
            b_img[:height, :width] = img[:, :]
2189

    
2190
            for offset in offsets:
2191
                for row in range(height_count):
2192
                    for col in range(width_count):
2193
                        x, y = col * size + offset, row * size + offset
2194
                        tile_rect = QRectF(x, y, size, size)
2195
                        tile_symbols = []
2196
                        for symbol in [symbol for symbol in symbols if symbol.name in names[index]]:
2197
                            if tile_rect.contains(symbol.sceneBoundingRect()):
2198
                                tile_symbols.append(symbol)
2199
                                symbols.remove(symbol)
2200

    
2201
                        if tile_symbols:
2202
                            training_uid = str(uuid.uuid4())
2203
                            training_image_path = os.path.join(save_path, training_uid + '.png')
2204
                            training_xml_path = os.path.join(save_path, training_uid + '.xml')
2205

    
2206
                            # save image
2207
                            #_img = b_img[round(tile_rect.top()):round(tile_rect.bottom()),
2208
                            #       round(tile_rect.left()):round(tile_rect.right())]
2209
                            #cv2.imwrite(training_image_path, _img)
2210
                            _img = self.graphicsView.image().copy(round(tile_rect.left()), round(tile_rect.top()), round(tile_rect.width()), round(tile_rect.height()))
2211
                            _img.save(training_image_path)
2212

    
2213
                            # save label
2214
                            xml = Element('annotation')
2215
                            SubElement(xml, 'folder').text = 'None'
2216
                            SubElement(xml, 'filename').text = os.path.basename(save_path)
2217

    
2218
                            pathNode = Element('path')
2219
                            pathNode.text = save_path.replace('/', '\\')
2220
                            xml.append(pathNode)
2221

    
2222
                            sourceNode = Element('source')
2223
                            databaseNode = Element('database')
2224
                            databaseNode.text = 'Unknown'
2225
                            sourceNode.append(databaseNode)
2226
                            xml.append(sourceNode)
2227

    
2228
                            sizeNode = Element('size')
2229
                            widthNode = Element('width')
2230
                            widthNode.text = str(int(tile_rect.width()))
2231
                            sizeNode.append(widthNode)
2232
                            heightNode = Element('height')
2233
                            heightNode.text = str(int(tile_rect.height()))
2234
                            sizeNode.append(heightNode)
2235
                            depthNode = Element('depth')
2236
                            depthNode.text = '3'
2237
                            sizeNode.append(depthNode)
2238
                            xml.append(sizeNode)
2239

    
2240
                            segmentedNode = Element('segmented')
2241
                            segmentedNode.text = '0'
2242
                            xml.append(segmentedNode)
2243

    
2244
                            labelContent = []
2245
                            counts = {}
2246
                            for item in tile_symbols:
2247
                                rect = item.sceneBoundingRect()
2248
                                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)
2249
                                #label = 'small' if index == 0 else 'big' # for single class test
2250
                                xMin = xMin if xMin > 0 else 0
2251
                                yMin = yMin if yMin > 0 else 0
2252
                                xMax = xMax if xMax < size else size
2253
                                yMax = yMax if yMax < size else size
2254

    
2255
                                if label == 'None' or label == '':
2256
                                    continue
2257
                                if label not in labelContent:
2258
                                    labelContent.append(label)
2259
                                    counts[label] = 1
2260
                                else:
2261
                                    counts[label] = counts[label] + 1
2262

    
2263
                                objectNode = Element('object')
2264
                                nameNode = Element('name')
2265
                                nameNode.text = label
2266
                                objectNode.append(nameNode)
2267
                                poseNode = Element('pose')
2268
                                poseNode.text = 'Unspecified'
2269
                                objectNode.append(poseNode)
2270
                                truncatedNode = Element('truncated')
2271
                                truncatedNode.text = '0'
2272
                                objectNode.append(truncatedNode)
2273
                                difficultNode = Element('difficult')
2274
                                difficultNode.text = '0'
2275
                                objectNode.append(difficultNode)
2276

    
2277
                                bndboxNode = Element('bndbox')
2278
                                xminNode = Element('xmin')
2279
                                xminNode.text = str(xMin)
2280
                                bndboxNode.append(xminNode)
2281
                                yminNode = Element('ymin')
2282
                                yminNode.text = str(yMin)
2283
                                bndboxNode.append(yminNode)
2284
                                xmaxNode = Element('xmax')
2285
                                xmaxNode.text = str(xMax)
2286
                                bndboxNode.append(xmaxNode)
2287
                                ymaxNode = Element('ymax')
2288
                                ymaxNode.text = str(yMax)
2289
                                bndboxNode.append(ymaxNode)
2290
                                objectNode.append(bndboxNode)
2291

    
2292
                                xml.append(objectNode)
2293

    
2294
                            ElementTree(xml).write(training_xml_path)
2295

    
2296
            index += 1
2297

    
2298
        QMessageBox.about(self, self.tr("Notice"), self.tr('Successfully applied. '))
2299

    
2300
    def onPlaceLine(self):
2301
        """create a line"""
2302
        home_pane = self.ribbon.get_pane('Home')
2303

    
2304
        if not self.graphicsView.hasImage():
2305
            home_pane.ui.toolButtonLine.setChecked(False)
2306
            self.showImageSelectionMessageBox()
2307
            return
2308

    
2309
        self.update_action_group(home_pane.ui.toolButtonLine)
2310
        if not hasattr(home_pane.ui.toolButtonLine, 'tag'):
2311
            home_pane.ui.toolButtonLine.tag = PlaceLineCommand.PlaceLineCommand(self.graphicsView)
2312
            home_pane.ui.toolButtonLine.tag.onSuccess.connect(self.onLineCreated)
2313
            home_pane.ui.toolButtonLine.tag.onRejected.connect(self.onCommandRejected)
2314

    
2315
        self.graphicsView.command = home_pane.ui.toolButtonLine.tag
2316

    
2317
    def onLineCreated(self):
2318
        """add created lines to scene"""
2319
        from EngineeringConnectorItem import QEngineeringConnectorItem
2320
        from LineDetector import LineDetector
2321

    
2322
        try:
2323
            app_doc_data = AppDocData.instance()
2324
            home_pane = self.ribbon.get_pane('Home')
2325

    
2326
            count = len(home_pane.ui.toolButtonLine.tag._polyline._vertices)
2327
            if count > 1:
2328
                items = []
2329

    
2330
                detector = LineDetector(None)
2331

    
2332
                if not home_pane.ui.toolButtonLine.tag.line_type:
2333
                    line_type = home_pane.ui.comboBoxLineType.currentText()
2334
                else:
2335
                    pane = self.ribbon.get_pane('Home')
2336
                    selected_line_type = pane.ui.comboBoxLineType.currentText()
2337
                    if selected_line_type == 'Connect To Process':
2338
                        line_type = selected_line_type
2339
                    elif not (QEngineeringLineItem.check_piping(home_pane.ui.toolButtonLine.tag.line_type) ^
2340
                              QEngineeringLineItem.check_piping(selected_line_type)):
2341
                        line_type = selected_line_type
2342
                    else:
2343
                        line_type = home_pane.ui.toolButtonLine.tag.line_type
2344
                for index in range(count - 1):
2345
                    start = home_pane.ui.toolButtonLine.tag._polyline._vertices[index]
2346
                    end = home_pane.ui.toolButtonLine.tag._polyline._vertices[index + 1]
2347

    
2348
                    lineItem = QEngineeringLineItem(vertices=[start, end])
2349
                    lineItem.transfer.onRemoved.connect(self.itemRemoved)
2350
                    lineItem.lineType = line_type
2351
                    if items:
2352
                        lineItem.connect_if_possible(items[-1], 5)
2353
                    else:
2354
                        pt = lineItem.start_point()
2355
                        selected = [item for item in self.graphicsView.scene().items(QPointF(pt[0], pt[1])) if
2356
                                    type(item) is QEngineeringConnectorItem or type(item) is QEngineeringLineItem]
2357
                        if selected and selected[0] is not lineItem:
2358
                            if type(selected[0]) is QEngineeringConnectorItem:
2359
                                lineItem.connect_if_possible(selected[0].parent, 5)
2360
                            else:
2361
                                detector.connectLineToLine(selected[0], lineItem, 5)
2362

    
2363
                    items.append(lineItem)
2364
                    self.graphicsView.scene().addItem(lineItem)
2365

    
2366
                pt = items[-1].end_point()
2367
                selected = [item for item in self.graphicsView.scene().items(QPointF(pt[0], pt[1])) if
2368
                            (type(item) is QEngineeringConnectorItem and item.parentItem() is not items[-1]) or
2369
                            (type(item) is QEngineeringLineItem and item is not items[-1])]
2370
                if selected and selected[0] is not items[-1]:
2371
                    if type(selected[0]) is QEngineeringConnectorItem:
2372
                        items[-1].connect_if_possible(selected[0].parent, 5)
2373
                    else:
2374
                        detector.connectLineToLine(selected[0], items[-1], 5)
2375

    
2376
                self._scene.undo_stack.push(CreateCommand(self._scene, items))
2377
        finally:
2378
            self.graphicsView.scene().removeItem(home_pane.ui.toolButtonLine.tag._polyline)
2379
            home_pane.ui.toolButtonLine.tag.reset()
2380

    
2381
    def onCommandRejected(self, cmd=None):
2382
        """command is rejected"""
2383
        try:
2384
            home_pane = self.ribbon.get_pane('Home')
2385
            visualization_pane = self.ribbon.get_pane('Home Visualization')
2386
            if type(cmd) is PlaceLineCommand.PlaceLineCommand:
2387
                if home_pane.ui.toolButtonLine.tag._polyline:
2388
                    self.graphicsView.scene().removeItem(home_pane.ui.toolButtonLine.tag._polyline)
2389
                self.graphicsView.scene().update()
2390
                home_pane.ui.toolButtonLine.tag.reset()
2391

    
2392
                home_pane.ui.toolButtonLine.setChecked(False)
2393
            elif type(cmd) is AreaZoomCommand.AreaZoomCommand:
2394
                visualization_pane.ui.toolButtonZoom.setChecked(False)
2395
            elif type(cmd) is AreaOcrCommand.AreaOcrCommand:
2396
                home_pane.ui.toolButtonOCR.setChecked(False)
2397
            elif type(cmd) is PlacePolygonCommand.PlacePolygonCommand:
2398
                home_pane.ui.toolButtonVendor.setChecked(False)
2399
            else:
2400
                if hasattr(home_pane.ui.toolButtonVendor, 'tag') and home_pane.ui.toolButtonVendor.tag._polyline:
2401
                    self.graphicsView.scene().removeItem(home_pane.ui.toolButtonVendor.tag._polyline)
2402
                    self.graphicsView.scene().update()
2403
                    home_pane.ui.toolButtonVendor.tag.reset()
2404
                home_pane.ui.toolButtonLine.setChecked(False)
2405
                visualization_pane.ui.toolButtonZoom.setChecked(False)
2406
                home_pane.ui.toolButtonOCR.setChecked(False)
2407
                home_pane.ui.toolButtonVendor.setChecked(False)
2408
        finally:
2409
            self.graphicsView.useDefaultCommand()
2410

    
2411
    def on_view_toggle(self, key: int) -> None:
2412
        """view toggled"""
2413

    
2414
        view_pane = self.ribbon.get_pane('View')
2415
        if key == Qt.Key_1:
2416
            checked = view_pane.ui.toolButtonViewImageDrawing.isChecked()
2417
            self.onViewImageDrawing(not checked)
2418
            view_pane.ui.toolButtonViewImageDrawing.setChecked(not checked)
2419
        elif key == Qt.Key_2:
2420
            checked = view_pane.ui.toolButtonViewText.isChecked()
2421
            self.onViewText(not checked)
2422
            view_pane.ui.toolButtonViewText.setChecked(not checked)
2423
        elif key == Qt.Key_3:
2424
            checked = view_pane.ui.toolButtonViewSymbol.isChecked()
2425
            self.onViewSymbol(not checked)
2426
            view_pane.ui.toolButtonViewSymbol.setChecked(not checked)
2427
        elif key == Qt.Key_4:
2428
            checked = view_pane.ui.toolButtonViewLine.isChecked()
2429
            self.onViewLine(not checked)
2430
            view_pane.ui.toolButtonViewLine.setChecked(not checked)
2431
        elif key == Qt.Key_5:
2432
            checked = view_pane.ui.toolButtonViewUnknown.isChecked()
2433
            self.onViewUnknown(not checked)
2434
            view_pane.ui.toolButtonViewUnknown.setChecked(not checked)
2435
        elif key == Qt.Key_6:
2436
            checked = view_pane.ui.toolButtonViewInconsistency.isChecked()
2437
            self.onViewInconsistency(not checked)
2438
            view_pane.ui.toolButtonViewInconsistency.setChecked(not checked)
2439
        elif key == Qt.Key_7:
2440
            checked = view_pane.ui.toolButtonViewVendorArea.isChecked()
2441
            self.onViewVendorArea(not checked)
2442
            view_pane.ui.toolButtonViewVendorArea.setChecked(not checked)
2443
        elif key == 96:  # '~' key
2444
            checked = view_pane.ui.toolButtonViewDrawingOnly.isChecked()
2445
            self.onViewDrawingOnly(not checked)
2446
            view_pane.ui.toolButtonViewDrawingOnly.setChecked(not checked)
2447

    
2448
    def keyPressEvent(self, event):
2449
        """restore to default command when user press Escape key"""
2450
        try:
2451
            if event.key() == Qt.Key_Escape:
2452
                checked = self.checked_action()
2453
                if checked:
2454
                    checked.setChecked(False)
2455
                    self.graphicsView.useDefaultCommand()
2456
            elif event.key() == Qt.Key_M:  # merge text as vertical
2457
                from TextInfo import TextInfo
2458

    
2459
                textItems = [text for text in self.graphicsView.scene().selectedItems() if
2460
                             issubclass(type(text), QEngineeringTextItem)]
2461
                if not textItems or len(textItems) is 1:
2462
                    return
2463

    
2464
                angle = None
2465
                for item in textItems:
2466
                    if angle is None:
2467
                        angle = item.angle
2468
                    else:
2469
                        if angle != item.angle:
2470
                            return
2471

    
2472
                modifiers = QApplication.keyboardModifiers()
2473
                enter_or_space = ' ' if modifiers == Qt.ControlModifier else '\n'
2474
                x_or_y = 0 if (modifiers == Qt.ControlModifier and angle == 0) or (modifiers != Qt.ControlModifier and angle == 1.57) else 1
2475

    
2476
                textItems = sorted(textItems, key=lambda text: text.loc[x_or_y]) if textItems[0].angle == 0 else ( \
2477
                    sorted(textItems, key=lambda text: text.loc[x_or_y]) if textItems[0].angle == 1.57 else ( \
2478
                        sorted(textItems, key=lambda text: text.loc[x_or_y], reverse=True) if textItems[0].angle == 4.71 else \
2479
                            sorted(textItems, key=lambda text: text.loc[x_or_y], reverse=True)))
2480

    
2481
                if textItems[0].angle == 1.57 and modifiers == Qt.ControlModifier:
2482
                    textItems.reverse()
2483

    
2484
                minX = sys.maxsize
2485
                minY = sys.maxsize
2486
                maxX = 0
2487
                maxY = 0
2488
                newText = ''
2489

    
2490
                for text in textItems:
2491
                    if text.loc[0] < minX: minX = text.loc[0]
2492
                    if text.loc[1] < minY: minY = text.loc[1]
2493
                    if text.loc[0] + text.size[0] > maxX: maxX = text.loc[0] + text.size[0]
2494
                    if text.loc[1] + text.size[1] > maxY: maxY = text.loc[1] + text.size[1]
2495
                    newText = newText + text.text() + enter_or_space
2496
                    text.transfer.onRemoved.emit(text)
2497
                newText = newText[:-1]
2498

    
2499
                textInfo = TextInfo(newText, minX, minY, maxX - minX, maxY - minY, textItems[0].angle)
2500
                x = textInfo.getX()
2501
                y = textInfo.getY()
2502
                angle = textInfo.getAngle()
2503
                text = textInfo.getText()
2504
                width = textInfo.getW()
2505
                height = textInfo.getH()
2506
                item = TextItemFactory.instance().createTextItem(textInfo)
2507
                if item is not None:
2508
                    item.loc = [x, y]
2509
                    item.size = (width, height)
2510
                    item.angle = angle
2511
                    item.area = textItems[0].area
2512
                    item.setDefaultTextColor(Qt.blue)
2513
                    item.addTextItemToScene(self.graphicsView.scene())
2514
                    item.transfer.onRemoved.connect(self.itemRemoved)
2515
            elif event.key() == Qt.Key_D:
2516
                # pop up development toolkit dialog
2517
                from DevelopmentToolkitDialog import QDevelopmentToolkitDialog
2518

    
2519
                modifiers = QApplication.keyboardModifiers()
2520
                if modifiers == Qt.ControlModifier:
2521
                    dlg = QDevelopmentToolkitDialog(self, self.graphicsView)
2522
                    dlg.show()
2523
            elif event.key() == Qt.Key_I:
2524
                # insert symbol item that is selected symbol in tree to main window if symbol already selected on main window, replace
2525
                index = self.symbolTreeWidget.currentIndex()
2526
                proxy_model = self.symbolTreeWidget.model()
2527
                items = [proxy_model.sourceModel().itemFromIndex(proxy_model.mapToSource(index))]
2528
                if items and hasattr(items[0], 'svgFilePath'):
2529
                    symData = items[0].data(self.symbolTreeWidget.TREE_DATA_ROLE)
2530
                    symName = symData.getName()
2531
                else:
2532
                    return
2533

    
2534
                symbolItems = [symbol for symbol in self.graphicsView.scene().selectedItems() if
2535
                               issubclass(type(symbol), SymbolSvgItem)]
2536
                old_symbol = None
2537
                if symbolItems and len(symbolItems) is 1:
2538
                    old_symbol = symbolItems[0]
2539
                    #scenePos = QPoint(old_symbol.origin[0], old_symbol.origin[1])
2540
                    scenePos = old_symbol.mapToScene(old_symbol.transformOriginPoint())
2541
                    old_symbol.transfer.onRemoved.emit(old_symbol)
2542
                else:
2543
                    scenePos = self.current_pos
2544

    
2545
                svg = QtImageViewer.createSymbolObject(symName)
2546
                QtImageViewer.matchSymbolToLine(self.graphicsView.scene(), svg, scenePos, angle=old_symbol.angle if old_symbol else 0.0)
2547

    
2548
                if old_symbol and svg:
2549
                    from ReplaceCommand import ReplaceCommand
2550

    
2551
                    cmd = ReplaceCommand(self.graphicsView.scene(), old_symbol, svg)
2552
                    self._scene.undo_stack.push(cmd)
2553
                    return
2554
            elif event.key() == Qt.Key_J:
2555
                # insert and connect symbol item that is selected symbol in tree to selected symbol
2556
                index = self.symbolTreeWidget.currentIndex()
2557
                proxy_model = self.symbolTreeWidget.model()
2558
                items = [proxy_model.sourceModel().itemFromIndex(proxy_model.mapToSource(index))]
2559
                if items and hasattr(items[0], 'svgFilePath'):
2560
                    symData = items[0].data(self.symbolTreeWidget.TREE_DATA_ROLE)
2561
                    symName = symData.getName()
2562
                else:
2563
                    return
2564

    
2565
                symbolItems = [symbol for symbol in self.graphicsView.scene().selectedItems() if
2566
                               issubclass(type(symbol), SymbolSvgItem)]
2567
                if symbolItems and len(symbolItems) is not 1:
2568
                    return
2569
                    
2570
                target_symbol = symbolItems[0]
2571
                index =  [index for index in range(len(target_symbol.conn_type)) \
2572
                            if target_symbol.conn_type[index] == 'Primary' or target_symbol.conn_type[index] == 'Secondary']
2573
                for connector in target_symbol.connectors:
2574
                    svg = QtImageViewer.createSymbolObject(symName)
2575
                    if len(svg.connectors) > 1: 
2576
                        if ((target_symbol.conn_type and target_symbol.connectors.index(connector) in index) or not target_symbol.conn_type) and \
2577
                                    (not connector.connectedItem or (connector.connectedItem and type(connector.connectedItem) is QEngineeringLineItem)):
2578
                            QtImageViewer.matchSymbolToLine(self.graphicsView.scene(), svg, connector.sceneBoundingRect().center())
2579
                    elif len(svg.connectors) == 1:
2580
                        if ((target_symbol.conn_type and target_symbol.connectors.index(connector) in index) or not target_symbol.conn_type) and \
2581
                                    not connector.connectedItem:
2582
                            QtImageViewer.matchSymbolToLine(self.graphicsView.scene(), svg, connector.sceneBoundingRect().center())
2583

    
2584
                if target_symbol:
2585
                    return
2586
            elif event.key() == Qt.Key_X:
2587
                pass
2588
                '''
2589
                app_doc_data = AppDocData.instance()
2590
                configs = app_doc_data.getAppConfigs('app', 'mode')
2591
                if configs and 1 == len(configs) and 'advanced' == configs[0].value:
2592
                    advanced = True
2593
                    items = self.graphicsView.scene().selectedItems()
2594
                    if items:
2595
                        item = self.symbolTreeWidget.currentItem()
2596
                        if item:
2597
                            self.symbolTreeWidget.showSymbolEditorDialog(item, 0)
2598
                '''
2599
            elif event.key() == Qt.Key_F6:
2600
                from DEXPI import scene_to_dexpi
2601

    
2602
                app_doc_data = AppDocData.instance()
2603
                scene_to_dexpi('D:\\Temp\\DEXPI.xml', app_doc_data.activeDrawing.name, self.graphicsView.scene())
2604

    
2605
            QMainWindow.keyPressEvent(self, event)
2606
        except Exception as ex:
2607
            message = f"error occurred({repr(ex)}) in {sys.exc_info()[-1].tb_frame.f_code.co_filename}:" \
2608
                      f"{sys.exc_info()[-1].tb_lineno}"
2609
            self.addMessage.emit(MessageType.Error, message)
2610

    
2611
    def recognize(self):
2612
        """recognize symbol, text and line for selected drawings"""
2613
        from datetime import datetime
2614
        from License import QLicenseDialog
2615

    
2616
        # save alarm
2617
        self.save_alarm_enable(False)
2618

    
2619
        app_doc_data = AppDocData.instance()
2620
        current_drawing, currentPid = None, None
2621

    
2622
        if self.graphicsView.hasImage():
2623
            current_drawing = app_doc_data.activeDrawing
2624
            currentPid = app_doc_data.activeDrawing.name
2625

    
2626
        # get checked drawings
2627
        drawing_top = self.treeWidgetDrawingList.topLevelItem(0)
2628
        count = drawing_top.childCount()
2629
        checked_drawings = {}
2630
        for idx in range(count):
2631
            child = drawing_top.child(idx)
2632
            if child.checkState(0) == Qt.Checked and child.data(Qt.UserRole, 0):
2633
                checked_drawings[child.data(Qt.UserRole, 0)] = child
2634
        # up to here
2635

    
2636
        # if there is no checked drawing
2637
        if current_drawing and currentPid and not checked_drawings:
2638
            for idx in range(count):
2639
                child = drawing_top.child(idx)
2640
                if child.data(Qt.UserRole, 0) is current_drawing:
2641
                    checked_drawings[child.data(Qt.UserRole, 0)] = child
2642

    
2643
        if not checked_drawings:
2644
            self.showImageSelectionMessageBox()
2645
            return
2646

    
2647
        try:
2648
            self.on_clear_log()
2649
            dlg = QRecognitionDialog(self, [drawing for drawing in checked_drawings.keys()])
2650
            dlg.exec_()
2651

    
2652
            if current_drawing and current_drawing in checked_drawings.keys() and dlg.isTreated:
2653
                self.open_image_drawing(current_drawing, force=True, ocrUnknown=dlg.ui.checkBoxOCRUnknown.isChecked())
2654

    
2655
            # save working date-time
2656
            _now = datetime.now().strftime('%Y-%m-%d %H:%M:%S')
2657
            for drawing, tree_item in checked_drawings.items():
2658
                drawing.datetime = _now
2659
                tree_item.setText(1, _now)
2660
            #app_doc_data.saveDrawings(checked_drawings.keys())
2661
            self.changeViewCheckedState(True)
2662
            # count up for recognition
2663
            QLicenseDialog.count_up()
2664
            # up to here
2665
        except Exception as ex:
2666
            message = f"error occurred({repr(ex)}) in {sys.exc_info()[-1].tb_frame.f_code.co_filename}:" \
2667
                      f"{sys.exc_info()[-1].tb_lineno}"
2668
            self.addMessage.emit(MessageType.Error, message)
2669

    
2670
        # save alarm
2671
        self.save_alarm_enable(True, True)
2672

    
2673
    '''
2674
        @brief      remove item from tree widget and then remove from scene
2675
        @date       2018.05.25
2676
        @author     Jeongwoo
2677
    '''
2678
    def itemRemoved(self, item):
2679
        try:
2680
            if type(item) is QEngineeringErrorItem:
2681
                # remove error item from inconsistency list
2682
                for row in range(self.tableWidgetInconsistency.rowCount()):
2683
                    if item is self.tableWidgetInconsistency.item(row, 0).tag:
2684
                        self.tableWidgetInconsistency.removeRow(row)
2685
                        break
2686

    
2687
                if item.scene() is not None:
2688
                    item.scene().removeItem(item)
2689
                del item
2690
            else:
2691
                remove_scene = item.scene()
2692
                self.itemTreeWidget.itemRemoved(item)
2693

    
2694
                if remove_scene:
2695
                    matches = [_item for _item in remove_scene.items() if
2696
                            hasattr(_item, 'connectors') and [connector for connector in _item.connectors if
2697
                                                                connector.connectedItem is item]]
2698
                    for match in matches:
2699
                        for connector in match.connectors:
2700
                            if connector.connectedItem is item:
2701
                                connector.connectedItem = None
2702
                                connector.highlight(False)
2703

    
2704
                # matches = [_item for _item in self.graphicsView.scene().items() if hasattr(_item, 'remove_assoc_item')]
2705
                # for _item in matches:
2706
                #    _item.remove_assoc_item(item)
2707

    
2708
                app_doc_data = AppDocData.instance()
2709
                if type(item) is QEngineeringLineNoTextItem and item in app_doc_data.tracerLineNos:
2710
                    app_doc_data.tracerLineNos.pop(app_doc_data.tracerLineNos.index(item))
2711

    
2712
                if type(item) is QEngineeringLineItem and item in app_doc_data.lines:
2713
                    app_doc_data.lines.remove(item)
2714

    
2715
                if remove_scene:
2716
                    matches = [_item for _item in remove_scene.items() if
2717
                            type(_item) is QEngineeringLineNoTextItem]
2718
                    matches.extend([lineNo for lineNo in app_doc_data.tracerLineNos if
2719
                                    type(lineNo) is QEngineeringTrimLineNoTextItem])
2720
                    for match in matches:
2721
                        if item is match.prop('From'):
2722
                            match.set_property('From', None)
2723
                        if item is match.prop('To'):
2724
                            match.set_property('To', None)
2725

    
2726
                        for run_index in reversed(range(len(match.runs))):
2727
                            run = match.runs[run_index]
2728
                            if item in run.items:
2729
                                index = run.items.index(item)
2730
                                run.items.pop(index)
2731
                                if not run.items:
2732
                                    run.explode()
2733
                                    if type(match) is QEngineeringTrimLineNoTextItem and not match.runs:
2734
                                        app_doc_data.tracerLineNos.pop(app_doc_data.tracerLineNos.index(match))
2735
                                # break
2736

    
2737
                if remove_scene:
2738
                    matches = [_item for _item in remove_scene.items() if hasattr(_item, 'owner')]
2739
                    for match in matches:
2740
                        if match.owner is item:
2741
                            match.owner = None
2742

    
2743
                    matches = [_item for _item in remove_scene.items() if hasattr(_item, 'attrs')]
2744
                    # done = False
2745
                    for match in matches:
2746
                        assocs = match.associations()
2747
                        for assoc in assocs:
2748
                            if item is assoc:
2749
                                keys = match.attrs.keys()
2750
                                for attr in keys:
2751
                                    if attr.AssocItem and str(item.uid) == str(attr.AssocItem.uid):
2752
                                        attr.AssocItem = None
2753
                                        match.attrs[attr] = ''
2754
                                        # done = True
2755
                                match.remove_assoc_item(item)
2756
                                break
2757
                        # if done: break
2758

    
2759
                if item.scene() is not None:
2760
                    #if type(item) is QEngineeringLineNoTextItem and item._labels:
2761
                    #    for _label in item._labels:
2762
                    #        item.scene().removeItem(_label)
2763
                    #    item._labels = []
2764

    
2765
                    item.scene().removeItem(item)
2766
        except Exception as ex:
2767
            message = 'error occurred({}) in {}:{}'.format(ex, sys.exc_info()[-1].tb_frame.f_code.co_filename,
2768
                                                           sys.exc_info()[-1].tb_lineno)
2769
            self.addMessage.emit(MessageType.Error, message)
2770
        '''
2771
        finally:
2772
            if hasattr(item, '_cond'):
2773
                item._cond.wakeAll()
2774
        '''
2775

    
2776

    
2777
    def connect_attributes(self, MainWindow):
2778
        """connect attributes to symbol"""
2779
        from LineNoTracer import LineNoTracer
2780
        from ConnectAttrDialog import QConnectAttrDialog
2781

    
2782
        if not self.graphicsView.hasImage():
2783
            self.showImageSelectionMessageBox()
2784
            return
2785

    
2786
        # save alarm
2787
        self.save_alarm_enable(False)
2788

    
2789
        try:
2790
            dlg = QConnectAttrDialog(self, self.graphicsView.scene())
2791
            dlg.setWindowFlags(self.windowFlags() & ~Qt.WindowCloseButtonHint & ~Qt.WindowContextHelpButtonHint)
2792
            dlg.exec_()
2793
            if dlg.isRunned:
2794
                self.refresh_item_list()
2795

    
2796
                if dlg.validation_checked:
2797
                    self.onValidation()
2798

    
2799
                self.graphicsView.invalidateScene()
2800
        except Exception as ex:
2801
            message = 'error occurred({}) in {}:{}'.format(ex, sys.exc_info()[-1].tb_frame.f_code.co_filename,
2802
                                                           sys.exc_info()[-1].tb_lineno)
2803
            self.addMessage.emit(MessageType.Error, message)
2804
        finally:
2805
            # save alarm
2806
            self.save_alarm_enable(True)
2807

    
2808
    def postDetectLineProcess(self):
2809
        '''
2810
            @brief  check allowables among undetected items
2811
            @author euisung
2812
            @date   2018.11.15
2813
            @history    2018.11.15  euisung    no more used, moved to TextItemFactoy isLineNo()
2814
        '''
2815
        from TextItemFactory import TextItemFactory
2816

    
2817
        appDocData = AppDocData.instance()
2818

    
2819
        tableNames = ["Fluid Code", "Insulation Purpose", "PnID Number", "Piping Materials Class", "Unit Number"]
2820
        tableDatas = []
2821
        for tableName in tableNames:
2822
            tableNameFormat = tableName.replace(' ', '').replace('&&', 'n')
2823
            tableDatas.append(appDocData.getCodeTable(tableNameFormat))
2824

    
2825
        items = self.graphicsView.scene().items()
2826
        for item in items:
2827
            if type(item) is not QEngineeringTextItem:
2828
                continue
2829
            text = item.text()
2830
            for tableData in tableDatas:
2831
                for data in tableData:
2832
                    if data[3] == '':
2833
                        continue
2834
                    else:
2835
                        allows = data[3].split(',')
2836
                        for allow in allows:
2837
                            text = text.replace(allow, data[1])
2838

    
2839
            lineItem = TextItemFactory.instance().createTextItem(text)
2840
            if type(lineItem) is QEngineeringLineNoTextItem:
2841
                lineItem.loc = item.loc
2842
                lineItem.size = item.size
2843
                lineItem.angle = item.angle
2844
                lineItem.area = item.area
2845
                # lineItem.addTextItemToScene(self.graphicsView.scene())
2846
                lineItem.transfer.onRemoved.connect(self.itemRemoved)
2847
                item.transfer.onRemoved.emit(item)
2848
                appDocData.lineNos.append(lineItem)
2849

    
2850
    def init_add_tree_item(self, line_no_tree_item, run_item):
2851
        """ insert symbol item and find line no as owner """
2852
        # insert
2853
        self.itemTreeWidget.addTreeItem(line_no_tree_item, run_item)
2854
        # find
2855
        self.itemTreeWidget.addTreeItem(line_no_tree_item, run_item)
2856

    
2857
    def load_drawing(self, drawing):
2858
        """ load drawing """
2859
        """ no more used """
2860
        from EngineeringRunItem import QEngineeringRunItem
2861
        from QEngineeringTrimLineNoTextItem import QEngineeringTrimLineNoTextItem
2862

    
2863
        app_doc_data = AppDocData.instance()
2864
        try:
2865
            symbols = []
2866
            lines = []
2867

    
2868
            components = app_doc_data.get_components(drawing.UID)
2869
            maxValue = len(components) * 2
2870
            self.progress.setMaximum(maxValue) if maxValue > 0 else None
2871

    
2872
            """ parsing all symbols """
2873
            for symbol in [component for component in components if int(component['SymbolType_UID']) != -1]:
2874
                item = SymbolSvgItem.from_database(symbol)
2875
                if item is not None:
2876
                    item.transfer.onRemoved.connect(self.itemRemoved)
2877
                    symbols.append(item)
2878
                    app_doc_data.symbols.append(item)
2879
                    item.addSvgItemToScene(self.graphicsView.scene())
2880
                else:
2881
                    pt = [float(symbol['X']), float(symbol['Y'])]
2882
                    size = [float(symbol['Width']), float(symbol['Height'])]
2883
                    angle = float(symbol['Rotation'])
2884
                    item = QGraphicsBoundingBoxItem(pt[0], pt[1], size[0], size[1])
2885
                    item.isSymbol = True
2886
                    item.angle = angle
2887
                    item.setPen(QPen(Qt.red, 5, Qt.SolidLine))
2888
                    self.graphicsView.scene().addItem(item)
2889
                    item.transfer.onRemoved.connect(self.itemRemoved)
2890

    
2891
                self.progress.setValue(self.progress.value() + 1)
2892

    
2893
            QApplication.processEvents()
2894

    
2895
            # parse texts
2896
            for text in [component for component in components if
2897
                         component['Name'] == 'Text' and component['SymbolType_UID'] == -1]:
2898
                item = QEngineeringTextItem.from_database(text)
2899
                if item is not None:
2900
                    item.uid = text['UID']
2901
                    item.attribute = text['Value']
2902
                    name = text['Name']
2903
                    item.transfer.onRemoved.connect(self.itemRemoved)
2904
                    item.addTextItemToScene(self.graphicsView.scene())
2905

    
2906
                self.progress.setValue(self.progress.value() + 1)
2907

    
2908
            QApplication.processEvents()
2909

    
2910
            # note
2911
            for note in [component for component in components if
2912
                         component['Name'] == 'Note' and component['SymbolType_UID'] == -1]:
2913
                item = QEngineeringTextItem.from_database(note)
2914
                if item is not None:
2915
                    item.uid = note['UID']
2916
                    attributeValue = note['Value']
2917
                    name = note['Name']
2918
                    item.transfer.onRemoved.connect(self.itemRemoved)
2919
                    item.addTextItemToScene(self.graphicsView.scene())
2920

    
2921
                self.progress.setValue(self.progress.value() + 1)
2922

    
2923
            QApplication.processEvents()
2924

    
2925
            for line in [component for component in components if
2926
                         component['Name'] == 'Line' and component['SymbolType_UID'] == -1]:
2927
                item = QEngineeringLineItem.from_database(line)
2928
                if item:
2929
                    item.transfer.onRemoved.connect(self.itemRemoved)
2930
                    self.graphicsView.scene().addItem(item)
2931
                    lines.append(item)
2932

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

    
2935
            QApplication.processEvents()
2936

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

    
2945
                self.progress.setValue(self.progress.value() + 1)
2946

    
2947
            QApplication.processEvents()
2948

    
2949
            for component in [component for component in components if
2950
                              component['Name'] == 'Line NO' and component['SymbolType_UID'] == -1]:
2951
                line_no = QEngineeringLineNoTextItem.from_database(component)
2952
                if type(line_no) is QEngineeringLineNoTextItem:
2953
                    line_no.transfer.onRemoved.connect(self.itemRemoved)
2954
                    self.addTextItemToScene(line_no)
2955
                    line_no_tree_item = self.itemTreeWidget.addTreeItem(self.itemTreeWidget.root, line_no)
2956

    
2957
                    runs = app_doc_data.get_pipe_runs(str(line_no.uid))
2958
                    if not runs: continue
2959
                    for run in runs:
2960
                        line_run = QEngineeringRunItem()
2961
                        run_items = app_doc_data.get_pipe_run_items(run['UID'])
2962
                        for record in run_items:
2963
                            uid = record['Components_UID']
2964
                            run_item = self.graphicsView.findItemByUid(uid)
2965
                            if run_item is not None:
2966
                                run_item._owner = line_no
2967
                                line_run.items.append(run_item)
2968
                        line_run.owner = line_no
2969
                        line_no.runs.append(line_run)
2970

    
2971
                        for run_item in line_run.items:
2972
                            if issubclass(type(run_item), SymbolSvgItem):
2973
                                self.init_add_tree_item(line_no_tree_item, run_item)
2974

    
2975
                self.progress.setValue(self.progress.value() + 1)
2976
            QApplication.processEvents()
2977

    
2978
            for component in [component for component in components if
2979
                              component['Name'] == 'Trim Line NO' and component['SymbolType_UID'] == -1]:
2980
                line_no = QEngineeringTrimLineNoTextItem()
2981
                line_no.uid = uuid.UUID(component['UID'])
2982

    
2983
                runs = app_doc_data.get_pipe_runs(str(line_no.uid))
2984
                if not runs: continue
2985

    
2986
                line_no_tree_item = self.itemTreeWidget.addTreeItem(self.itemTreeWidget.root, line_no)
2987

    
2988
                for run in runs:
2989
                    line_run = QEngineeringRunItem()
2990
                    run_items = app_doc_data.get_pipe_run_items(run['UID'])
2991
                    for record in run_items:
2992
                        uid = record['Components_UID']
2993
                        run_item = self.graphicsView.findItemByUid(uid)
2994
                        if run_item is not None:
2995
                            run_item.owner = line_no
2996
                            line_run.items.append(run_item)
2997
                    line_run.owner = line_no
2998
                    line_no.runs.append(line_run)
2999

    
3000
                    for run_item in line_run.items:
3001
                        if issubclass(type(run_item), SymbolSvgItem):
3002
                            self.init_add_tree_item(line_no_tree_item, run_item)
3003

    
3004
                app_doc_data.tracerLineNos.append(line_no)
3005

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

    
3008
            for component in [component for component in components if
3009
                              component['Name'] == 'VendorPackage' and component['SymbolType_UID'] == -1]:
3010
                item = QEngineeringVendorItem.from_database(component)
3011
                if item is not None:
3012
                    item.transfer.onRemoved.connect(self.itemRemoved)
3013
                    self.graphicsView.scene().addItem(item)
3014

    
3015
            # connect flow item to line
3016
            for line in lines:
3017
                line.update_arrow()
3018
                app_doc_data.lines.append(line)
3019
            # for flowMark in [item for item in symbols if type(item) is QEngineeringFlowMarkItem]:
3020
            #    for line in lines:
3021
            #        if flowMark.owner is line:
3022
            #            line._flowMark.append(flowMark)
3023
            #            flowMark.setParentItem(line)
3024
            # up to here
3025

    
3026
            """ update scene """
3027
            self.graphicsView.scene().update(self.graphicsView.sceneRect())
3028
            for item in self.graphicsView.scene().items():
3029
                up_progress = False
3030
                # binding items
3031
                if hasattr(item, 'owner'):
3032
                    item.owner
3033
                    up_progress = True
3034
                if hasattr(item, 'connectors'):
3035
                    for connector in item.connectors:
3036
                        connector.connectedItem
3037
                    up_progress = True
3038

    
3039
                if up_progress:
3040
                    self.progress.setValue(self.progress.value() + 1)
3041
            
3042
            for item in self.graphicsView.scene().items():
3043
                item.setVisible(True)
3044

    
3045
        except Exception as ex:
3046
            message = 'error occurred({}) in {}:{}'.format(ex, sys.exc_info()[-1].tb_frame.f_code.co_filename,
3047
                                                           sys.exc_info()[-1].tb_lineno)
3048
            self.addMessage.emit(MessageType.Error, message)
3049
        finally:
3050
            app_doc_data.clearTempDBData()
3051
            self.itemTreeWidget.update_item_count()
3052
            self.itemTreeWidget.expandAll()
3053
            # self.graphicsView.scene().blockSignals(False)
3054

    
3055
    '''
3056
        @brief      load recognition result
3057
        @author     humkyung
3058
        @date       2018.04.??
3059
        @history    humkyung 2018.01.12 parse originalpoint and connectionpoint
3060
                    Jeongwoo 2018.04.17 add QGraphicItem with Rotated text
3061
                    Jeongwoo 2018.04.23 Change to Draw texts on QEngineeringTextItem
3062
                    humkyung 2018.04.23 connect item remove slot to result tree
3063
                    Jeongwoo 2018.04.25 Add if state with QEngineeringNoteItem
3064
                    Jeongwoo 2018.04.26 Change method to create TextItem object with TextItemFactory
3065
                    Jeongwoo 2018.05.03 Change method to draw Svg Item on Scene (svg.addSvgItemToScene)
3066
                    Jeongwoo 2018.05.29 Change method name / Change method to add item / Add Line item
3067
                    Jeongwoo 2018.05.30 Add parameters on SymbolSvgItem.__init__() (parentSymbol, childSymbol) / Change method name / Change XML NODE NAMES
3068
                    Jeongwoo 2018.06.12 Add LineNoTextItem from LINE_NO
3069
                    Jeongwoo 2018.06.14 Add UnknownItem from UNKNOWN
3070
                    Jeongwoo 2018.06.18 Update Scene after all item added
3071
                                        Add connect on unknown item
3072
                                        Add [transfer] for using pyqtSignal
3073
                    kyouho  2018.07.12  Add line property logic
3074
                    humkyung 2018.08.22 show progress while loading xml file
3075
                    2018.11.22      euisung     fix note road
3076
    '''
3077
    def load_recognition_result_from_xml(self, drawing):
3078
        # Yield successive n-sized
3079
        # chunks from l.
3080
        def divide_chunks(l, n):
3081
            # looping till length l
3082
            for i in range(0, len(l), n):
3083
                yield l[i:i + n]
3084

    
3085
        def update_items(items):
3086
            for item in items:
3087
                # binding items
3088
                item.owner
3089
                for connector in item.connectors:
3090
                    connector.connectedItem
3091

    
3092
            return items
3093

    
3094
        import concurrent.futures as futures
3095
        from xml.etree.ElementTree import Element, SubElement, dump, ElementTree, parse
3096
        from App import App
3097
        from EngineeringRunItem import QEngineeringRunItem
3098
        from QEngineeringTrimLineNoTextItem import QEngineeringTrimLineNoTextItem
3099
        from EngineeringGraphicsLineItem import QEngineeringGraphicsLineItem
3100

    
3101
        app_doc_data = AppDocData.instance()
3102

    
3103
        try:
3104
            file_name = os.path.splitext(os.path.basename(drawing.file_path))[0]
3105
            path = os.path.join(app_doc_data.getCurrentProject().getTempPath(), file_name + '.xml')
3106
            self.graphicsView.scene().blockSignals(True)
3107

    
3108
            symbols = []
3109
            lines = []
3110

    
3111
            xml = parse(path)
3112
            root = xml.getroot()
3113

    
3114
            maxValue = 0
3115
            maxValue = maxValue + len(list(root.iter('SYMBOL'))) - \
3116
                       len(list(root.iterfind('LINENOS/LINE_NO/RUN/SYMBOL'))) - \
3117
                       len(list(root.iterfind('TRIMLINENOS/TRIM_LINE_NO/RUN/SYMBOL')))
3118
            maxValue = maxValue + len(list(root.iterfind('TEXTINFOS/ATTRIBUTE')))
3119
            maxValue = maxValue + len(list(root.iterfind('NOTES/ATTRIBUTE')))
3120
            maxValue = maxValue + len(list(root.iter('LINE_NO')))
3121
            maxValue = maxValue + len(list(root.iter('LINE'))) - \
3122
                       len(list(root.iterfind('LINENOS/LINE_NO/RUN/LINE'))) - \
3123
                       len(list(root.iterfind('TRIMLINENOS/TRIM_LINE_NO/RUN/LINE')))
3124
            maxValue = maxValue + len(list(root.iter('GRAPHICS_LINE')))
3125
            maxValue = maxValue + len(list(root.iter('UNKNOWN')))
3126
            # maxValue = maxValue + len(list(root.iter('SIZETEXT')))
3127
            maxValue = maxValue + len(list(root.iter('TRIM_LINE_NO')))
3128
            maxValue *= 2
3129
            self.progress.setMaximum(maxValue) if maxValue > 0 else None
3130

    
3131
            """ parsing all symbols """
3132
            """
3133
            with futures.ThreadPoolExecutor(max_workers=App.THREAD_MAX_WORKER) as pool:
3134
                future_symbol = {pool.submit(SymbolSvgItem.fromXml, symbol): symbol for symbol in root.find('SYMBOLS').iter('SYMBOL')}
3135

3136
                for future in futures.as_completed(future_symbol):
3137
                    try:
3138
                        item = future.result()
3139
                        if item:
3140
                            if item is not None:
3141
                                item.transfer.onRemoved.connect(self.itemRemoved)
3142
                                symbols.append(item)
3143
                                docData.symbols.append(item)
3144
                                self.addSvgItemToScene(item)
3145
                            else:
3146
                                pt = [float(x) for x in symbol.find('LOCATION').text.split(',')]
3147
                                size = [float(x) for x in symbol.find('SIZE').text.split(',')]
3148
                                angle = float(symbol.find('ANGLE').text)
3149
                                item = QGraphicsBoundingBoxItem(pt[0], pt[1], size[0], size[1])
3150
                                item.isSymbol = True
3151
                                item.angle = angle
3152
                                item.setPen(QPen(Qt.red, 5, Qt.SolidLine))
3153
                                self.graphicsView.scene().addItem(item)
3154
                                item.transfer.onRemoved.connect(self.itemRemoved)
3155
                    except Exception as ex:
3156
                        message = 'error occurred({}) in {}:{}'.format(repr(ex), sys.exc_info()[-1].tb_frame.f_code.co_filename,
3157
                                                                       sys.exc_info()[-1].tb_lineno)
3158

3159
            """
3160
            for symbol in root.find('SYMBOLS').iter('SYMBOL'):
3161
                item = SymbolSvgItem.fromXml(symbol)
3162
                if item is not None:
3163
                    item.transfer.onRemoved.connect(self.itemRemoved)
3164
                    symbols.append(item)
3165
                    #app_doc_data.symbols.append(item)
3166
                    item.addSvgItemToScene(self.graphicsView.scene())
3167
                else:
3168
                    pt = [float(x) for x in symbol.find('LOCATION').text.split(',')]
3169
                    size = [float(x) for x in symbol.find('SIZE').text.split(',')]
3170
                    angle = float(symbol.find('ANGLE').text)
3171
                    item = QGraphicsBoundingBoxItem(pt[0], pt[1], size[0], size[1])
3172
                    item.isSymbol = True
3173
                    item.angle = angle
3174
                    item.setPen(QPen(Qt.red, 5, Qt.SolidLine))
3175
                    self.graphicsView.scene().addItem(item)
3176
                    item.transfer.onRemoved.connect(self.itemRemoved)
3177

    
3178
                self.progress.setValue(self.progress.value() + 1)
3179

    
3180
            QApplication.processEvents()
3181

    
3182
            # parse texts
3183
            for text in root.find('TEXTINFOS').iter('ATTRIBUTE'):
3184
                item = QEngineeringTextItem.fromXml(text)
3185
                if item is not None:
3186
                    uid = text.find('UID')
3187
                    attributeValue = text.find('ATTRIBUTEVALUE')
3188
                    name = text.find('NAME').text
3189
                    item.transfer.onRemoved.connect(self.itemRemoved)
3190
                    item.addTextItemToScene(self.graphicsView.scene())
3191
                    # docData.texts.append(item)
3192

    
3193
                    if name == 'TEXT':
3194
                        if uid is not None and attributeValue is not None:
3195
                            item.uid = uid.text
3196
                            item.attribute = attributeValue.text
3197

    
3198
                self.progress.setValue(self.progress.value() + 1)
3199

    
3200
            QApplication.processEvents()
3201

    
3202
            # note
3203
            for text in root.find('NOTES').iter('ATTRIBUTE'):
3204
                item = QEngineeringTextItem.fromXml(text)
3205
                if item is not None:
3206
                    uid = text.find('UID')
3207
                    attributeValue = text.find('ATTRIBUTEVALUE')
3208
                    name = text.find('NAME').text
3209
                    item.transfer.onRemoved.connect(self.itemRemoved)
3210
                    item.addTextItemToScene(self.graphicsView.scene())
3211

    
3212
                    if name == 'NOTE':
3213
                        if uid is not None:
3214
                            item.uid = uid.text
3215

    
3216
                self.progress.setValue(self.progress.value() + 1)
3217

    
3218
            QApplication.processEvents()
3219

    
3220
            for line in root.find('LINEINFOS').iter('LINE'):
3221
                item = QEngineeringLineItem.fromXml(line)
3222
                if item:
3223
                    item.transfer.onRemoved.connect(self.itemRemoved)
3224
                    self.graphicsView.scene().addItem(item)
3225
                    lines.append(item)
3226

    
3227
                self.progress.setValue(self.progress.value() + 1)
3228

    
3229
            for line in root.find('LINEINFOS').iter('GRAPHICS_LINE'):
3230
                item = QEngineeringGraphicsLineItem.fromXml(line)
3231
                if item:
3232
                    item.transfer.onRemoved.connect(self.itemRemoved)
3233
                    self.graphicsView.scene().addItem(item)
3234

    
3235
                self.progress.setValue(self.progress.value() + 1)
3236

    
3237
            QApplication.processEvents()
3238

    
3239
            for unknown in root.iter('UNKNOWN'):
3240
                item = QEngineeringUnknownItem.fromXml(unknown)
3241
                if item is not None:
3242
                    item.transfer.onRemoved.connect(self.itemRemoved)
3243
                    self.graphicsView.scene().addItem(item)
3244

    
3245
                self.progress.setValue(self.progress.value() + 1)
3246

    
3247
            QApplication.processEvents()
3248

    
3249
            # """ add tree widget """
3250
            # for item in symbols:
3251
            #    docData.symbols.append(item)
3252
            #    self.addSvgItemToScene(item)
3253
            #    self.itemTreeWidget.addTreeItem(self.itemTreeWidget.root, item)
3254

    
3255
            for line_no_node in root.find('LINENOS').iter('LINE_NO'):
3256
                line_no = QEngineeringLineNoTextItem.fromXml(line_no_node)
3257
                if line_no is None: continue
3258
                line_no.transfer.onRemoved.connect(self.itemRemoved)
3259
                line_no.addTextItemToScene(self.graphicsView.scene())
3260
                line_no_tree_item = self.itemTreeWidget.addTreeItem(self.itemTreeWidget.root, line_no)
3261
                if type(line_no) is not QEngineeringLineNoTextItem: continue
3262

    
3263
                runs_node = line_no_node.findall('RUN')
3264
                if runs_node is None: continue
3265

    
3266
                for run_node in runs_node:
3267
                    line_run = QEngineeringRunItem()
3268
                    for child_node in run_node:
3269
                        uidElement = child_node.find('UID')
3270
                        if uidElement is not None:
3271
                            uid = uidElement.text
3272
                            run_item = self.graphicsView.findItemByUid(uid)
3273
                            if run_item is not None:
3274
                                run_item._owner = line_no
3275
                                line_run.items.append(run_item)
3276
                    line_run.owner = line_no
3277
                    line_no.runs.append(line_run)
3278

    
3279
                    for run_item in line_run.items:
3280
                        if issubclass(type(run_item), SymbolSvgItem):
3281
                            self.init_add_tree_item(line_no_tree_item, run_item)
3282

    
3283
                # docData.tracerLineNos.append(line_no)
3284

    
3285
                self.progress.setValue(self.progress.value() + 1)
3286
            QApplication.processEvents()
3287

    
3288
            for trimLineNo in root.iter('TRIM_LINE_NO'):
3289
                line_no = QEngineeringTrimLineNoTextItem()
3290
                line_no.uid = uuid.UUID(trimLineNo.find('UID').text)
3291

    
3292
                runs_node = trimLineNo.findall('RUN')
3293
                if runs_node is None: continue
3294
                line_no_tree_item = self.itemTreeWidget.addTreeItem(self.itemTreeWidget.root, line_no)
3295

    
3296
                for run in runs_node:
3297
                    line_run = QEngineeringRunItem()
3298
                    for child in run:
3299
                        uidElement = child.find('UID')
3300
                        if uidElement is not None:
3301
                            uid = uidElement.text
3302
                            run_item = self.graphicsView.findItemByUid(uid)
3303
                            if run_item is not None:
3304
                                run_item.owner = line_no
3305
                                line_run.items.append(run_item)
3306
                    line_run.owner = line_no
3307
                    line_no.runs.append(line_run)
3308

    
3309
                    for run_item in line_run.items:
3310
                        if issubclass(type(run_item), SymbolSvgItem):
3311
                            self.init_add_tree_item(line_no_tree_item, run_item)
3312

    
3313
                app_doc_data.tracerLineNos.append(line_no)
3314

    
3315
                self.progress.setValue(self.progress.value() + 1)
3316
            QApplication.processEvents()
3317

    
3318
            if root.find('VENDORS') is not None:
3319
                for vendor in root.find('VENDORS').iter('VENDOR'):
3320
                    item = QEngineeringVendorItem.fromXml(vendor)
3321
                    item.transfer.onRemoved.connect(self.itemRemoved)
3322
                    self.graphicsView.scene().addItem(item)
3323

    
3324
            # connect flow item to line
3325
            for line in lines:
3326
                line.update_arrow()
3327
                app_doc_data.lines.append(line)
3328
            # for flowMark in [item for item in symbols if type(item) is QEngineeringFlowMarkItem]:
3329
            #    for line in lines:
3330
            #        if flowMark.owner is line:
3331
            #            line._flowMark.append(flowMark)
3332
            #            flowMark.setParentItem(line)
3333
            # up to here
3334

    
3335
            """
3336
            group_box = QGroupBox("Contact Details")
3337
            number_label = QLabel("Telephone number");
3338
            number_edit = QTextEdit('hello\nthis is ....')
3339
            layout = QFormLayout()
3340
            layout.addRow(number_label, number_edit)
3341
            group_box.setLayout(layout)
3342

3343
            proxy =  ㅐ()
3344
            proxy.setWidget(group_box)
3345
            self.graphicsView.scene().addItem(proxy)  # (group_box, QGraphicsItem.ItemIgnoresTransformations)
3346
            """
3347

    
3348
            """ update scene """
3349
            _items = [_item for _item in self.graphicsView.scene().items() if hasattr(_item, 'owner') or hasattr(_item, 'connectors')]
3350
            if _items:
3351
                items = divide_chunks(_items, App.THREAD_MAX_WORKER if len(_items) > App.THREAD_MAX_WORKER else len(_items))
3352
                with futures.ThreadPoolExecutor(max_workers=App.THREAD_MAX_WORKER) as pool:
3353
                    future_items = {pool.submit(update_items, _items): _items for _items in items}
3354
                    for future in futures.as_completed(future_items):
3355
                        _items = future.result()
3356
                        self.progress.setValue(self.progress.value() + len(_items))
3357

    
3358
            """
3359
            for item in [_item for _item in self.graphicsView.scene().items() if hasattr(_item, 'owner') or hasattr(_item, 'connectors')]:
3360
                up_progress = False
3361
                # binding items
3362
                item.owner
3363
                for connector in item.connectors:
3364
                    connector.connectedItem
3365

3366
                self.progress.setValue(self.progress.value() + 1)
3367
            """
3368

    
3369
            for item in self.graphicsView.scene().items():
3370
                item.setVisible(True)
3371

    
3372
            self.graphicsView.scene().update(self.graphicsView.sceneRect())
3373
        except Exception as ex:
3374
            message = 'error occurred({}) in {}:{}'.format(ex, sys.exc_info()[-1].tb_frame.f_code.co_filename,
3375
                                                           sys.exc_info()[-1].tb_lineno)
3376
            self.addMessage.emit(MessageType.Error, message)
3377
        finally:
3378
            self.itemTreeWidget.update_item_count()
3379
            self.itemTreeWidget.expandAll()
3380
            self.graphicsView.scene().blockSignals(False)
3381

    
3382
    '''
3383
        @brief      Remove added item on same place and Add GraphicsItem
3384
        @author     Jeongwoo
3385
        @date       2018.05.29
3386
        @history    2018.06.18  Jeongwoo    Set Z-index
3387
    '''
3388
    def addLineItemToScene(self, lineItem):
3389
        self.graphicsView.scene().addItem(lineItem)
3390

    
3391
    '''
3392
        @brief      generate output xml file
3393
        @author     humkyung
3394
        @date       2018.04.23
3395
        @history    2018.05.02  Jeongwoo    Show MessageBox when imageviewer doesn't have image
3396
    '''
3397
    def generateOutput(self):
3398
        import XmlGenerator as xg
3399

    
3400
        if not self.graphicsView.hasImage():
3401
            self.showImageSelectionMessageBox()
3402
            return
3403

    
3404
        try:
3405
            appDocData = AppDocData.instance()
3406

    
3407
            # collect items
3408
            appDocData.lines.clear()
3409
            appDocData.lines = [item for item in self.graphicsView.scene().items() if
3410
                                type(item) is QEngineeringLineItem and item.owner is None]
3411

    
3412
            appDocData.symbols.clear()
3413
            appDocData.symbols = [item for item in self.graphicsView.scene().items() if
3414
                                  issubclass(type(item), SymbolSvgItem) and item.owner is None]
3415

    
3416
            appDocData.equipments.clear()
3417
            for item in self.graphicsView.scene().items():
3418
                if type(item) is QEngineeringEquipmentItem:
3419
                    appDocData.equipments.append(item)
3420

    
3421
            appDocData.texts.clear()
3422
            appDocData.texts = [item for item in self.graphicsView.scene().items() if
3423
                                issubclass(type(item), QEngineeringTextItem) and type(
3424
                                    item) is not QEngineeringLineNoTextItem]
3425
            # up to here
3426

    
3427
            appDocData.imgOutput = np.ones((appDocData.activeDrawing.height, appDocData.activeDrawing.width),
3428
                                           np.uint8) * 255
3429
            xg.writeOutputXml(appDocData.imgName, appDocData.activeDrawing.width,
3430
                              appDocData.activeDrawing.height)  # TODO: check
3431
            project = appDocData.getCurrentProject()
3432
            cv2.imwrite(os.path.join(project.getTempPath(), 'OUTPUT.png'), appDocData.imgOutput)
3433
        except Exception as ex:
3434
            message = 'error occurred({}) in {}:{}'.format(ex, sys.exc_info()[-1].tb_frame.f_code.co_filename,
3435
                                                           sys.exc_info()[-1].tb_lineno)
3436
            self.addMessage.emit(MessageType.Error, message)
3437

    
3438
    '''
3439
        @brief      Check Number
3440
        @author     kyouho
3441
        @date       2018.08.20
3442
    '''
3443
    def isNumber(self, num):
3444
        p = re.compile('(^[0-9]+$)')
3445
        result = p.match(num)
3446

    
3447
        if result:
3448
            return True
3449
        else:
3450
            return False
3451

    
3452
    '''
3453
        @brief      find overlap Connector
3454
        @author     kyouho
3455
        @date       2018.08.28
3456
    '''
3457
    def findOverlapConnector(self, connectorItem):
3458
        from shapely.geometry import Point
3459
        from EngineeringConnectorItem import QEngineeringConnectorItem
3460
        itemList = []
3461

    
3462
        x = connectorItem.center()[0]
3463
        y = connectorItem.center()[1]
3464

    
3465
        connectors = [item for item in self.graphicsView.scene().items() if
3466
                      type(item) is QEngineeringConnectorItem and item != connectorItem]
3467
        for connector in connectors:
3468
            if Point(x, y).distance(Point(connector.center()[0], connector.center()[1])) < 5:
3469
                itemList.append(connector.parent)
3470

    
3471
        return itemList
3472

    
3473
    def make_diff_image(self):
3474
        """ make diff image """
3475
        # test
3476

    
3477
        from RecognitionDialog import Worker
3478
        from symbol import Symbol
3479
        import math
3480
        from PIL import Image
3481

    
3482
        app_doc_data = AppDocData.instance()
3483
        img = app_doc_data.imgSrc.copy()
3484

    
3485
        # check break
3486
        symbols = [item for item in self.graphicsView.scene().items() if issubclass(type(item), SymbolSvgItem)]
3487

    
3488
        for symbol in symbols:
3489
            rect = symbol.sceneBoundingRect()
3490
            sName = symbol.name
3491
            sType = symbol.type
3492
            sp = (rect.x(), rect.y())
3493
            w, h = rect.width(), rect.height()
3494
            rotatedAngle = round(math.degrees(symbol.angle))
3495
            detectFlip = symbol.flip
3496

    
3497
            dummySym = Symbol(sName, sType, sp, w, h, 0, 0, 0, rotatedAngle,
3498
                                   1, 0, 1, 0,
3499
                                   ','.join(str(x) for x in [0, 0]),
3500
                                   '/'.join('{},{},{},{}'.format(param[0], param[1], param[2], param[3]) for param in
3501
                                            []),
3502
                                   'dummy', 'dummy', 0, detectFlip=detectFlip,
3503
                                   hasInstrumentLabel=0, text_area='')
3504

    
3505
            Worker.remove_detected_symbol_image(dummySym, img, lock=False)
3506

    
3507
        Image.fromarray(img).show()
3508

    
3509
    #def paintEvent(self, event):
3510
    #    self.refresh_rate += 1
3511
    #    if self.refresh_rate == 3:
3512
    #        super(self.__class__, self).paintEvent(event)
3513
    #        self.refresh_rate = 0
3514

    
3515
if __name__ == '__main__':
3516
    import locale
3517
    from PyQt5.QtCore import QTranslator
3518
    from License import QLicenseDialog
3519
    from ProjectDialog import Ui_Dialog
3520
    from App import App
3521

    
3522
    app = App(sys.argv)
3523
    try:
3524
        if True == QLicenseDialog.check_license_key():
3525
            dlg = Ui_Dialog()
3526
            selectedProject = dlg.showDialog()
3527
            if selectedProject is not None:
3528
                AppDocData.instance().setCurrentProject(selectedProject)
3529
                app._mainWnd = MainWindow.instance()
3530
                app._mainWnd.show()
3531
                sys.exit(app.exec_())
3532
    except Exception as ex:
3533
        print('error occurred({}) in {}:{}'.format(ex, sys.exc_info()[-1].tb_frame.f_code.co_filename,
3534
                                                   sys.exc_info()[-1].tb_lineno))
3535
    finally:
3536
        pass
클립보드 이미지 추가 (최대 크기: 500 MB)