프로젝트

일반

사용자정보

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

hytos / DTI_PID / DTI_PID / MainWindow.py @ 958a7796

이력 | 보기 | 이력해설 | 다운로드 (159 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
                QMessageBox.about(self, self.tr("Information"), self.tr('Successfully saved.'))
1241
                #for item in scene.items():
1242
                #    if not hasattr(item, 'connectors'): continue
1243
                #    for connector in item.connectors: connector.setVisible(True)
1244

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

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

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

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

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

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

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

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

    
1316
            return
1317

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

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

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

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

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

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

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

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

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

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

    
1374
        ui.setChecked(True)
1375

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

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

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

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

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

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

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

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

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

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

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

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

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

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

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

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

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

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

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

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

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

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

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

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

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

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

    
1568
        app_doc_data = AppDocData.instance()
1569

    
1570
        tool_pane = self.ribbon.get_pane('Tool')
1571
        if tool_pane.ui.toolButtonConnection.isChecked():
1572
            if not hasattr(self, '_tcpserver'):
1573
                configs = app_doc_data.getAppConfigs('app', 'port')
1574
                port = 2549
1575
                if configs and 1 == len(configs):
1576
                    port = int(configs[0].value)
1577
                self._tcpserver = TcpServer(port)
1578
                self._tcpserver.sessionOpened()
1579
        else:
1580
            self._tcpserver.sessionClosed()
1581
            del self._tcpserver
1582

    
1583
    def on_execute_ext_app(self):
1584
        """execute external application"""
1585
        from ExtAppsDialog import QExtAppsDialog
1586

    
1587
        dlg = QExtAppsDialog(self)
1588
        dlg.exec_()
1589

    
1590
    def onShowCustomCodeTable(self):
1591
        from CustomCodeTablesDialog import CustomCodeTablesDialog
1592

    
1593
        dlg = CustomCodeTablesDialog(self)
1594
        dlg.show()
1595
        dlg.exec_()
1596
        self.graphicsView.useDefaultCommand()
1597

    
1598
    def onShowReplaceCodeTable(self):
1599
        from CustomCodeTablesDialog import CustomCodeTablesDialog
1600

    
1601
        dlg = CustomCodeTablesDialog(self, replace=True)
1602
        dlg.show()
1603
        dlg.exec_()
1604
        self.graphicsView.useDefaultCommand()
1605

    
1606
    def on_streamline(self):
1607
        """pop up stream line dialog"""
1608
        from StreamlineDialog import QStreamlineDialog
1609

    
1610
        if not self.graphicsView.hasImage():
1611
            self.showImageSelectionMessageBox()
1612
            return
1613

    
1614
        hmbs = AppDocData.instance().get_hmb_data(None)
1615
        if not hmbs:
1616
            return
1617

    
1618
        dlg = QStreamlineDialog(self)
1619
        dlg.show()
1620

    
1621
    def onHMBData(self):
1622
        """show HMB data"""
1623
        from HMBDialog import QHMBDialog
1624

    
1625
        dlg = QHMBDialog(self)
1626
        dlg.show()
1627
        dlg.exec_()
1628

    
1629
    '''
1630
        @brief  show line data list 
1631
        @author humkyung
1632
        @date   2018.05.03
1633
    '''
1634
    def showItemDataList(self):
1635
        from ItemDataExportDialog import QItemDataExportDialog
1636

    
1637
        dlg = QItemDataExportDialog(self)
1638
        dlg.exec_()
1639

    
1640
    def showTextDataList(self):
1641
        '''
1642
            @brief      show all text item in scene
1643
            @author     euisung
1644
            @date       2019.04.18
1645
        '''
1646
        try:
1647
            if not self.graphicsView.hasImage():
1648
                self.showImageSelectionMessageBox()
1649
                return
1650

    
1651
            self.onCommandRejected()
1652
            dialog = QTextDataListDialog(self)
1653
            dialog.show()
1654
        except Exception as ex:
1655
            message = 'error occurred({}) in {}:{}'.format(ex, sys.exc_info()[-1].tb_frame.f_code.co_filename,
1656
                                                           sys.exc_info()[-1].tb_lineno)
1657
            self.addMessage.emit(MessageType.Error, message)
1658

    
1659
    '''
1660
        @brief  Show Image Selection Guide MessageBox
1661
        @author Jeongwoo
1662
        @date   2018.05.02
1663
    '''
1664
    def showImageSelectionMessageBox(self):
1665
        QMessageBox.about(self.graphicsView, self.tr("Notice"), self.tr("First select image drawing"))
1666

    
1667
    def on_search_text_changed(self):
1668
        """filter symbol tree view"""
1669
        regexp = QRegExp(self.lineEditFilter.text(), Qt.CaseInsensitive, QRegExp.FixedString)
1670

    
1671
        proxy_model = self.symbolTreeWidget.model()
1672
        proxy_model.text = self.lineEditFilter.text().lower()
1673
        proxy_model.setFilterRegExp(regexp)
1674

    
1675
        self.symbolTreeWidget.expandAll()
1676

    
1677
    def change_display_colors(self):
1678
        """ change display color mode """
1679
        visualization_pane = self.ribbon.get_pane('Home Visualization')
1680
        if visualization_pane.ui.radioButtonByGroup.isChecked():
1681
            visualization_pane.ui.radioButtonByType.setChecked(True)
1682
        else:
1683
            visualization_pane.ui.radioButtonByGroup.setChecked(True)
1684

    
1685
    def display_colors(self, value):
1686
        """ display colors """
1687
        from DisplayColors import DisplayColors
1688
        from DisplayColors import DisplayOptions
1689

    
1690
        if hasattr(self, 'ribbon'):
1691
            visualization_pane = self.ribbon.get_pane('Home Visualization')
1692
            if self.sender() is visualization_pane.ui.radioButtonByGroup and value is True:
1693
                DisplayColors.instance().option = DisplayOptions.DisplayByLineNo
1694
            elif self.sender() is visualization_pane.ui.radioButtonByType and value is True:
1695
                DisplayColors.instance().option = DisplayOptions.DisplayByLineType
1696
            elif self.sender() is visualization_pane.ui.radioButtonByStreamNo and value is True:
1697
                DisplayColors.instance().option = DisplayOptions.DisplayByStreamNo
1698

    
1699
            if hasattr(self, 'graphicsView') and value is True:
1700
                self.graphicsView.scene().update(self.graphicsView.sceneRect())
1701
                for item in self.graphicsView.scene().items():
1702
                    if issubclass(type(item), SymbolSvgItem):
1703
                        item.update()
1704
                DisplayColors.instance().save_data()
1705

    
1706
    def open_image_drawing(self, drawing, force=False, ocrUnknown=False):
1707
        """open and display image drawing file"""
1708
        from Drawing import Drawing
1709
        from App import App
1710
        from LoadCommand import LoadCommand
1711
        import concurrent.futures as futures
1712

    
1713
        # Yield successive n-sized
1714
        # chunks from l.
1715
        def divide_chunks(l, n):
1716
            # looping till length l
1717
            for i in range(0, len(l), n):
1718
                yield l[i:i + n]
1719

    
1720
        def update_items(items):
1721
            for item in items:
1722
                # binding items
1723
                item.owner
1724
                for connector in item.connectors:
1725
                    connector.connectedItem
1726

    
1727
            return items
1728

    
1729
        try:
1730
            app_doc_data = AppDocData.instance()
1731

    
1732
            if not self.actionSave.isEnabled():
1733
                return
1734

    
1735
            if not force and self.save_drawing_if_necessary():
1736
                return
1737

    
1738
            occupied = app_doc_data.set_occupying_drawing(drawing.UID)
1739
            if occupied:
1740
                QMessageBox.about(self.graphicsView, self.tr("Notice"),
1741
                                  self.tr(f"The drawing is locked for editing by another user({occupied})"))
1742
                return
1743

    
1744
            # save alarm
1745
            self.save_alarm_enable(False)
1746

    
1747
            if hasattr(self, '_save_work_cmd'):
1748
                self._save_work_cmd.wait()
1749

    
1750
            project = app_doc_data.getCurrentProject()
1751

    
1752
            self.path = self.graphicsView.loadImageFromFile(drawing)
1753
            if os.path.isfile(self.path):
1754
                self.onCommandRejected()
1755
                app_doc_data.clear(past=drawing.UID)
1756

    
1757
                # load color for stream no coloring
1758
                configs = app_doc_data.getConfigs('Line List', 'Use Stream No')
1759
                if configs and int(configs[0].value) == 1:
1760
                    hmbs = app_doc_data.get_hmb_data(None)
1761
                    colors = {}
1762
                    if hmbs:
1763
                        for hmb in hmbs:
1764
                            rgb = app_doc_data.colors
1765
                            colors[hmb.stream_no] = QColor(rgb.red, rgb.green, rgb.blue).name()
1766
                        app_doc_data._hmbColors = colors
1767
                # up to here
1768

    
1769
                app_doc_data.setImgFilePath(self.path)
1770
                app_doc_data.activeDrawing = drawing
1771
                
1772
                #app_doc_data.activeDrawing.set_pid_source(Image.open(self.path))
1773
                self.itemTreeWidget.setCurrentPID(app_doc_data.activeDrawing.name)
1774

    
1775
                drawingList = self.treeWidgetDrawingList.topLevelItem(0)
1776
                for idx in range(drawingList.childCount()):
1777
                    child = drawingList.child(idx)
1778
                    if child.data(Qt.UserRole, 0) is drawing:
1779
                        child.setCheckState(0, Qt.Checked)
1780
                    else:
1781
                        child.setCheckState(0, Qt.Unchecked)
1782

    
1783
                try:
1784
                    self.show_Progress_bar()
1785

    
1786
                    # disconnect scene changed if signal is connected
1787
                    if self.graphicsView.scene().receivers(self.graphicsView.scene().contents_changed) > 0:
1788
                        self.graphicsView.scene().contents_changed.disconnect()
1789

    
1790
                    SymbolSvgItem.DOCUMENTS.clear()
1791

    
1792
                    # load data
1793
                    cmd = LoadCommand()
1794
                    cmd.display_message.connect(self.onAddMessage)
1795
                    cmd.set_maximum.connect(self.progress.setMaximum)
1796
                    cmd.show_progress.connect(self.progress.setValue)
1797
                    cmd.execute((drawing, self.graphicsView.scene()),
1798
                                symbol=True, text=True, line=True, unknown=True, package=True, update=True)
1799

    
1800
                    configs = app_doc_data.getConfigs('Line List', 'Use Stream No')
1801
                    if configs and int(configs[0].value) == 1:
1802
                        app_doc_data._streamLineListModelDatas = app_doc_data.get_stream_line_list_data()
1803
                    # up to here
1804

    
1805
                    """update item tree widget"""
1806
                    line_no_items = [item for item in self.graphicsView.scene().items()
1807
                                     if type(item) is QEngineeringLineNoTextItem]
1808
                    for line_no in line_no_items:
1809
                        line_no_tree_item = self.itemTreeWidget.addTreeItem(self.itemTreeWidget.root, line_no)
1810
                        for run in line_no.runs:
1811
                            for run_item in run.items:
1812
                                if issubclass(type(run_item), SymbolSvgItem):
1813
                                    self.init_add_tree_item(line_no_tree_item, run_item)
1814

    
1815
                    line_no_items = [item for item in self.graphicsView.scene().items()
1816
                                     if type(item) is QEngineeringTrimLineNoTextItem]
1817
                    for line_no in line_no_items:
1818
                        line_no_tree_item = self.itemTreeWidget.addTreeItem(self.itemTreeWidget.root, line_no)
1819
                        for run in 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
                    for trim_line_no in app_doc_data.tracerLineNos:
1825
                        line_no_tree_item = self.itemTreeWidget.addTreeItem(self.itemTreeWidget.root, trim_line_no)
1826
                        for run in trim_line_no.runs:
1827
                            for run_item in run.items:
1828
                                if issubclass(type(run_item), SymbolSvgItem):
1829
                                    self.init_add_tree_item(line_no_tree_item, run_item)
1830

    
1831
                    self.itemTreeWidget.update_item_count()
1832
                    self.itemTreeWidget.expandAll()
1833
                    """up to here"""
1834

    
1835
                    """update scene"""
1836
                    for item in self._scene.items():
1837
                        item.setVisible(True)
1838

    
1839
                    self._scene.update(self._scene.sceneRect())
1840

    
1841
                    """
1842
                    # old open drawing
1843
                    path = os.path.join(app_doc_data.getCurrentProject().getTempPath(), app_doc_data.imgName + '.xml')
1844
                    configs = app_doc_data.getConfigs('Data Load', 'Xml First')
1845
                    if configs and int(configs[0].value) >= 1 and os.path.isfile(path):
1846
                        self.load_recognition_result_from_xml(drawing)
1847
                    elif configs and int(configs[0].value) <= 1:
1848
                        self.load_drawing(app_doc_data.activeDrawing)
1849
                    """
1850

    
1851
                    self.display_number_of_items()
1852
                    # connect scene changed signal
1853
                    self.graphicsView.scene().contents_changed.connect(self.scene_changed)
1854
                finally:
1855
                    if hasattr(self, 'progress'):
1856
                        self.progress.setValue(self.progress.maximum())
1857

    
1858
                self.changeViewCheckedState(True)
1859
                self.setWindowTitle(self.title)
1860
                self.fitWindow(drawing.view_rect)
1861

    
1862
                if ocrUnknown:
1863
                    self.on_ocr_unknown_items()
1864

    
1865
                # save alarm
1866
                self.save_alarm_enable(True, True)
1867
        except Exception as ex:
1868
            message = f"error occurred({repr(ex)}) in {sys.exc_info()[-1].tb_frame.f_code.co_filename}:" \
1869
                      f"{sys.exc_info()[-1].tb_lineno}"
1870
            self.addMessage.emit(MessageType.Error, message)
1871

    
1872
        return self.path
1873

    
1874
    def save_alarm_enable(self, enable, init=False):
1875
        from datetime import datetime
1876

    
1877
        try:
1878
            app_doc_data = AppDocData.instance()
1879
            configs = app_doc_data.getConfigs('Data Save', 'Time')
1880
            time_min = int(configs[0].value) if 1 == len(configs) else 0
1881

    
1882
            if enable and time_min > 0:
1883
                if not self.save_timer:
1884
                    self.save_timer = QTimer()
1885
                    self.save_timer.timeout.connect(self.save_alarm)
1886
                    self.save_timer.setInterval(60000)
1887

    
1888
                if init:
1889
                    self.save_timer._init_time = datetime.now()
1890
                    self.save_timer._stop_time = None
1891
                    self.save_timer._interval_time = datetime.now() - datetime.now()
1892

    
1893
                if self.save_timer._stop_time:
1894
                    self.save_timer._interval_time = datetime.now() - self.save_timer._stop_time
1895
                
1896
                #if 60000 * time_min != self.save_timer.interval():
1897
                #    self.save_timer.setInterval(60000)
1898

    
1899
                self.save_timer.start()
1900
            else:
1901
                if self.save_timer:
1902
                    self.save_timer.stop()
1903
                    self.save_timer._stop_time = datetime.now()
1904
        
1905
        except Exception as ex:
1906
            message = f"error occurred({repr(ex)}) in {sys.exc_info()[-1].tb_frame.f_code.co_filename}:" \
1907
                      f"{sys.exc_info()[-1].tb_lineno}"
1908
            self.addMessage.emit(MessageType.Error, message)
1909

    
1910
    def save_alarm(self):
1911
        from datetime import datetime
1912

    
1913
        app_doc_data = AppDocData.instance()
1914
        configs = app_doc_data.getConfigs('Data Save', 'Time')
1915
        time_min = int(configs[0].value) if 1 == len(configs) else 0
1916

    
1917
        self.save_timer.stop()
1918
        if self.graphicsView.hasFocus() and (datetime.now() - self.save_timer._init_time - self.save_timer._interval_time).seconds > time_min * 60:
1919
            QMessageBox.information(self, self.tr('Information'), self.tr('Please save Drawing'))
1920
            self.save_timer._init_time = datetime.now()
1921
            self.save_timer._interval_time = datetime.now() - datetime.now()
1922
        self.save_timer.start()
1923

    
1924
    def export_as_svg(self):
1925
        """export scene to svg file"""
1926
        from ExportCommand import ExportCommand
1927

    
1928
        options = QFileDialog.Options()
1929
        options |= QFileDialog.DontUseNativeDialog
1930
        file_path, _ = QFileDialog.getSaveFileName(self, "Export as svg", os.getcwd(), "svg file(*.svg)",
1931
                                                   options=options)
1932
        if file_path:
1933
            cmd = ExportCommand(self.graphicsView.scene(), 'svg')
1934
            cmd.display_message.connect(self.onAddMessage)
1935
            if cmd.execute(file_path):
1936
                QMessageBox.information(self, self.tr('Information'), self.tr('Successfully export to svg file'))
1937
            else:
1938
                QMessageBox.information(self, self.tr('Error'), self.tr('Fail to export to svg file'))
1939

    
1940
    def export_as_xml(self):
1941
        pass
1942

    
1943
    def export_as_image(self):
1944
        """export scene to image file"""
1945
        from ExportCommand import ExportCommand
1946

    
1947
        options = QFileDialog.Options()
1948
        options |= QFileDialog.DontUseNativeDialog
1949
        file_path, _ = QFileDialog.getSaveFileName(self, "Export as png", os.getcwd(), "png file(*.png)",
1950
                                                   options=options)
1951
        if file_path:
1952
            try:
1953
                # hide image drawing
1954
                self.onViewImageDrawing(False)
1955

    
1956
                cmd = ExportCommand(self.graphicsView.scene(), 'image')
1957
                cmd.display_message.connect(self.onAddMessage)
1958

    
1959
                if cmd.execute(file_path):
1960
                    QMessageBox.information(self, self.tr('Information'), self.tr('Successfully export to image file'))
1961
                else:
1962
                    QMessageBox.information(self, self.tr('Error'), self.tr('Fail to export to image file'))
1963
            finally:
1964
                if self.actionImage_Drawing.isChecked():
1965
                    self.onViewImageDrawing(True)
1966
                    self.actionImage_Drawing.setChecked(True)
1967

    
1968
    def show_Progress_bar(self):
1969
        """ show progress bar """
1970
        self.progress = QProgressDialog(self.tr("Please wait for a while"), self.tr("Cancel"), 0, 100,
1971
                                        self) if not hasattr(self, 'progress') else self.progress
1972
        self.progress.setWindowModality(Qt.WindowModal)
1973
        self.progress.setAutoReset(True)
1974
        self.progress.setAutoClose(True)
1975
        self.progress.setMinimum(0)
1976
        self.progress.setMaximum(100)
1977
        self.progress.resize(600, 100)
1978
        self.progress.setWindowTitle(self.tr("Reading file..."))
1979
        self.progress.show()
1980

    
1981
    def changeViewCheckedState(self, checked, clear=True):
1982
        """change view checked state"""
1983
        # self.actionImage_Drawing.setChecked(checked)
1984
        self.actionViewText.setChecked(checked)
1985
        self.actionViewSymbol.setChecked(checked)
1986
        self.actionViewLine.setChecked(checked)
1987
        self.actionViewUnknown.setChecked(checked)
1988
        self.actionViewInconsistency.setChecked(checked)
1989
        self.actionViewVendor_Area.setChecked(not checked)
1990
        self.actionDrawing_Only.setChecked(not checked)
1991
        if clear:
1992
            self.tableWidgetInconsistency.clearContents()
1993
            self.tableWidgetInconsistency.setRowCount(0)
1994

    
1995
    def onViewDrawingOnly(self, isChecked):
1996
        '''
1997
            @brief  visible/invisible except image drawing
1998
            @author euisung
1999
            @date   2019.04.22
2000
        '''
2001
        self.changeViewCheckedState(not isChecked, False)
2002
        for item in self.graphicsView.scene().items():
2003
            if type(item) is not QGraphicsPixmapItem:
2004
                item.setVisible(not isChecked)
2005

    
2006
    '''
2007
        @brief  visible/invisible image drawing
2008
        @author humkyung
2009
        @date   2018.06.25
2010
    '''
2011
    def onViewImageDrawing(self, isChecked):
2012
        for item in self.graphicsView.scene().items():
2013
            if type(item) is QGraphicsPixmapItem:
2014
                item.setVisible(isChecked)
2015
                break
2016

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

    
2024
    def onViewSymbol(self, checked):
2025
        """visible/invisible symbol"""
2026
        selected = [item for item in self.graphicsView.scene().items() if
2027
                    (issubclass(type(item), SymbolSvgItem) and type(item) is not QEngineeringErrorItem)]
2028
        for item in selected:
2029
            item.setVisible(checked)
2030

    
2031
    def onViewLine(self, checked):
2032
        """visible/invisible line"""
2033
        selected = [item for item in self.graphicsView.scene().items() if type(item) is QEngineeringLineItem]
2034
        for item in selected:
2035
            item.setVisible(checked)
2036

    
2037
    def onViewInconsistency(self, isChecked):
2038
        '''
2039
            @brief  visible/invisible Inconsistency
2040
            @author euisung
2041
            @date   2019.04.03
2042
        '''
2043
        selected = [item for item in self.graphicsView.scene().items() if type(item) is QEngineeringErrorItem]
2044
        for item in selected:
2045
            item.setVisible(isChecked)
2046

    
2047
    '''
2048
        @brief  visible/invisible Unknown 
2049
        @author humkyung
2050
        @date   2018.06.28
2051
    '''
2052
    def onViewUnknown(self, isChecked):
2053
        selected = [item for item in self.graphicsView.scene().items() if type(item) is QEngineeringUnknownItem]
2054
        for item in selected:
2055
            item.setVisible(isChecked)
2056

    
2057
    def onViewVendorArea(self, isChecked):
2058
        '''
2059
            @brief  visible/invisible Vendor Area
2060
            @author euisung
2061
            @date   2019.04.29
2062
        '''
2063
        selected = [item for item in self.graphicsView.scene().items() if issubclass(type(item), QEngineeringVendorItem)]
2064
        for item in selected:
2065
            item.setVisible(isChecked)
2066

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

    
2081
            points = []
2082
            for conn in selected[0].connectors:
2083
                points.append([round(conn.center()[0] - rect.x()), round(conn.center()[1] - rect.y())])
2084
            poly = np.array(points, np.int32)
2085

    
2086
            #mask = np.zeros((int(rect.height()), int(rect.width())))
2087
            #cv2.fillPoly(mask, [poly], (255))
2088
            #poly_copied = np.multiply(mask, symbol_image[round(rect.y()):round(rect.y() + rect.height()),
2089
            #                   round(rect.x()):round(rect.x() + rect.width())])
2090
            #cv2.fillPoly(mask,[poly],0)
2091
            #src2 = np.multiply(mask,src2)
2092

    
2093
            mask = np.ones((int(rect.height()), int(rect.width())), dtype=np.uint8) * 255
2094
            cv2.fillPoly(mask, [poly], (0))
2095
            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())])
2096
            sym_img = cv2.merge((sym_img, sym_img, sym_img))
2097

    
2098
            h, w, c = sym_img.shape
2099
            qImg = QImage(sym_img.data, w, h, w * c, QImage.Format_RGB888)
2100
            #pixmap = QPixmap.fromImage(qImg)
2101

    
2102
            self.onAreaSelected(None, None, None, None, package=qImg, position=rect.topLeft(), package_item=selected[0])
2103
        else:
2104
            cmd = FenceCommand.FenceCommand(self.graphicsView)
2105
            cmd.onSuccess.connect(self.onAreaSelected)
2106
            self.graphicsView.command = cmd
2107
            QApplication.setOverrideCursor(Qt.CrossCursor)
2108

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

    
2133
                        package_item.transfer.onRemoved.emit(package_item)
2134
        finally:
2135
            self.onCommandRejected()
2136
            QApplication.restoreOverrideCursor()
2137
            QApplication.restoreOverrideCursor()
2138

    
2139
    def on_line_list(self):
2140
        """ line list export dialog """
2141
        from LineListDialog import LineListDialog
2142

    
2143
        if not self.graphicsView.hasImage():
2144
            self.showImageSelectionMessageBox()
2145
            return
2146

    
2147
        dialog = LineListDialog(self)
2148
        dialog.showDialog()
2149

    
2150
    def on_make_label_data(self):
2151
        """ make label data from symbol info """
2152
        from xml.etree.ElementTree import Element, SubElement, dump, ElementTree, parse
2153

    
2154
        if not self.graphicsView.hasImage():
2155
            self.showImageSelectionMessageBox()
2156
            return
2157

    
2158
        app_doc_data = AppDocData.instance()
2159
        project = app_doc_data.getCurrentProject()
2160

    
2161
        smalls = []
2162
        bigs = []
2163

    
2164
        symbol_list = app_doc_data.getTargetSymbolList(all=True)
2165
        #symbol_list = app_doc_data.getTargetSymbolList(all=False)
2166
        for symbol in symbol_list:
2167
            if symbol.iType == 38 or symbol.iType == 33 or symbol.iType == 0 or symbol.iType == 40:
2168
                continue
2169
            elif symbol.width and symbol.height:
2170
                if symbol.width > 300 or symbol.height > 300:
2171
                    bigs.append(symbol.getName())
2172
                elif (symbol.width * symbol.height < 1500) or (symbol.width > 450 or symbol.height > 450):
2173
                    continue
2174
                else:
2175
                    smalls.append(symbol.getName())
2176

    
2177
        symbols = [item for item in self.graphicsView.scene().items() if issubclass(type(item), SymbolSvgItem)]
2178
        names = [smalls, bigs]
2179

    
2180
        img = app_doc_data.activeDrawing.image_origin
2181

    
2182
        small_size = 500
2183
        big_size = 850
2184

    
2185
        save_path = project.getTrainingSymbolFilePath()
2186

    
2187
        index = 0
2188
        for size in [small_size, big_size]:
2189
            offsets = [0, int(size / 2)]
2190

    
2191
            width, height = img.shape[1], img.shape[0]
2192
            width_count, height_count = width // size + 2, height // size + 2
2193
            b_width, b_height = width_count * size, height_count * size
2194
            b_img = np.zeros((b_height, b_width), np.uint8) + 255
2195
            b_img[:height, :width] = img[:, :]
2196

    
2197
            for offset in offsets:
2198
                for row in range(height_count):
2199
                    for col in range(width_count):
2200
                        x, y = col * size + offset, row * size + offset
2201
                        tile_rect = QRectF(x, y, size, size)
2202
                        tile_symbols = []
2203
                        for symbol in [symbol for symbol in symbols if symbol.name in names[index]]:
2204
                            if tile_rect.contains(symbol.sceneBoundingRect()):
2205
                                tile_symbols.append(symbol)
2206
                                symbols.remove(symbol)
2207

    
2208
                        if tile_symbols:
2209
                            training_uid = str(uuid.uuid4())
2210
                            training_image_path = os.path.join(save_path, training_uid + '.png')
2211
                            training_xml_path = os.path.join(save_path, training_uid + '.xml')
2212

    
2213
                            # save image
2214
                            #_img = b_img[round(tile_rect.top()):round(tile_rect.bottom()),
2215
                            #       round(tile_rect.left()):round(tile_rect.right())]
2216
                            #cv2.imwrite(training_image_path, _img)
2217
                            _img = self.graphicsView.image().copy(round(tile_rect.left()), round(tile_rect.top()), round(tile_rect.width()), round(tile_rect.height()))
2218
                            _img.save(training_image_path)
2219

    
2220
                            # save label
2221
                            xml = Element('annotation')
2222
                            SubElement(xml, 'folder').text = 'None'
2223
                            SubElement(xml, 'filename').text = os.path.basename(save_path)
2224

    
2225
                            pathNode = Element('path')
2226
                            pathNode.text = save_path.replace('/', '\\')
2227
                            xml.append(pathNode)
2228

    
2229
                            sourceNode = Element('source')
2230
                            databaseNode = Element('database')
2231
                            databaseNode.text = 'Unknown'
2232
                            sourceNode.append(databaseNode)
2233
                            xml.append(sourceNode)
2234

    
2235
                            sizeNode = Element('size')
2236
                            widthNode = Element('width')
2237
                            widthNode.text = str(int(tile_rect.width()))
2238
                            sizeNode.append(widthNode)
2239
                            heightNode = Element('height')
2240
                            heightNode.text = str(int(tile_rect.height()))
2241
                            sizeNode.append(heightNode)
2242
                            depthNode = Element('depth')
2243
                            depthNode.text = '3'
2244
                            sizeNode.append(depthNode)
2245
                            xml.append(sizeNode)
2246

    
2247
                            segmentedNode = Element('segmented')
2248
                            segmentedNode.text = '0'
2249
                            xml.append(segmentedNode)
2250

    
2251
                            labelContent = []
2252
                            counts = {}
2253
                            for item in tile_symbols:
2254
                                rect = item.sceneBoundingRect()
2255
                                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)
2256
                                #label = 'small' if index == 0 else 'big' # for single class test
2257
                                xMin = xMin if xMin > 0 else 0
2258
                                yMin = yMin if yMin > 0 else 0
2259
                                xMax = xMax if xMax < size else size
2260
                                yMax = yMax if yMax < size else size
2261

    
2262
                                if label == 'None' or label == '':
2263
                                    continue
2264
                                if label not in labelContent:
2265
                                    labelContent.append(label)
2266
                                    counts[label] = 1
2267
                                else:
2268
                                    counts[label] = counts[label] + 1
2269

    
2270
                                objectNode = Element('object')
2271
                                nameNode = Element('name')
2272
                                nameNode.text = label
2273
                                objectNode.append(nameNode)
2274
                                poseNode = Element('pose')
2275
                                poseNode.text = 'Unspecified'
2276
                                objectNode.append(poseNode)
2277
                                truncatedNode = Element('truncated')
2278
                                truncatedNode.text = '0'
2279
                                objectNode.append(truncatedNode)
2280
                                difficultNode = Element('difficult')
2281
                                difficultNode.text = '0'
2282
                                objectNode.append(difficultNode)
2283

    
2284
                                bndboxNode = Element('bndbox')
2285
                                xminNode = Element('xmin')
2286
                                xminNode.text = str(xMin)
2287
                                bndboxNode.append(xminNode)
2288
                                yminNode = Element('ymin')
2289
                                yminNode.text = str(yMin)
2290
                                bndboxNode.append(yminNode)
2291
                                xmaxNode = Element('xmax')
2292
                                xmaxNode.text = str(xMax)
2293
                                bndboxNode.append(xmaxNode)
2294
                                ymaxNode = Element('ymax')
2295
                                ymaxNode.text = str(yMax)
2296
                                bndboxNode.append(ymaxNode)
2297
                                objectNode.append(bndboxNode)
2298

    
2299
                                xml.append(objectNode)
2300

    
2301
                            ElementTree(xml).write(training_xml_path)
2302

    
2303
            index += 1
2304

    
2305
        QMessageBox.about(self, self.tr("Notice"), self.tr('Successfully applied. '))
2306

    
2307
    def onPlaceLine(self):
2308
        """create a line"""
2309
        home_pane = self.ribbon.get_pane('Home')
2310

    
2311
        if not self.graphicsView.hasImage():
2312
            home_pane.ui.toolButtonLine.setChecked(False)
2313
            self.showImageSelectionMessageBox()
2314
            return
2315

    
2316
        self.update_action_group(home_pane.ui.toolButtonLine)
2317
        if not hasattr(home_pane.ui.toolButtonLine, 'tag'):
2318
            home_pane.ui.toolButtonLine.tag = PlaceLineCommand.PlaceLineCommand(self.graphicsView)
2319
            home_pane.ui.toolButtonLine.tag.onSuccess.connect(self.onLineCreated)
2320
            home_pane.ui.toolButtonLine.tag.onRejected.connect(self.onCommandRejected)
2321

    
2322
        self.graphicsView.command = home_pane.ui.toolButtonLine.tag
2323

    
2324
    def onLineCreated(self):
2325
        """add created lines to scene"""
2326
        from EngineeringConnectorItem import QEngineeringConnectorItem
2327
        from LineDetector import LineDetector
2328

    
2329
        try:
2330
            app_doc_data = AppDocData.instance()
2331
            home_pane = self.ribbon.get_pane('Home')
2332

    
2333
            count = len(home_pane.ui.toolButtonLine.tag._polyline._vertices)
2334
            if count > 1:
2335
                items = []
2336

    
2337
                detector = LineDetector(None)
2338

    
2339
                if not home_pane.ui.toolButtonLine.tag.line_type:
2340
                    line_type = home_pane.ui.comboBoxLineType.currentText()
2341
                else:
2342
                    pane = self.ribbon.get_pane('Home')
2343
                    selected_line_type = pane.ui.comboBoxLineType.currentText()
2344
                    if selected_line_type == 'Connect To Process':
2345
                        line_type = selected_line_type
2346
                    elif not (QEngineeringLineItem.check_piping(home_pane.ui.toolButtonLine.tag.line_type) ^
2347
                              QEngineeringLineItem.check_piping(selected_line_type)):
2348
                        line_type = selected_line_type
2349
                    else:
2350
                        line_type = home_pane.ui.toolButtonLine.tag.line_type
2351
                for index in range(count - 1):
2352
                    start = home_pane.ui.toolButtonLine.tag._polyline._vertices[index]
2353
                    end = home_pane.ui.toolButtonLine.tag._polyline._vertices[index + 1]
2354

    
2355
                    lineItem = QEngineeringLineItem(vertices=[start, end])
2356
                    lineItem.transfer.onRemoved.connect(self.itemRemoved)
2357
                    lineItem.lineType = line_type
2358
                    if items:
2359
                        lineItem.connect_if_possible(items[-1], 5)
2360
                    else:
2361
                        pt = lineItem.start_point()
2362
                        selected = [item for item in self.graphicsView.scene().items(QPointF(pt[0], pt[1])) if
2363
                                    type(item) is QEngineeringConnectorItem or type(item) is QEngineeringLineItem]
2364
                        if selected and selected[0] is not lineItem:
2365
                            if type(selected[0]) is QEngineeringConnectorItem:
2366
                                lineItem.connect_if_possible(selected[0].parent, 5)
2367
                            else:
2368
                                detector.connectLineToLine(selected[0], lineItem, 5)
2369

    
2370
                    items.append(lineItem)
2371
                    self.graphicsView.scene().addItem(lineItem)
2372

    
2373
                pt = items[-1].end_point()
2374
                selected = [item for item in self.graphicsView.scene().items(QPointF(pt[0], pt[1])) if
2375
                            (type(item) is QEngineeringConnectorItem and item.parentItem() is not items[-1]) or
2376
                            (type(item) is QEngineeringLineItem and item is not items[-1])]
2377
                if selected and selected[0] is not items[-1]:
2378
                    if type(selected[0]) is QEngineeringConnectorItem:
2379
                        items[-1].connect_if_possible(selected[0].parent, 5)
2380
                    else:
2381
                        detector.connectLineToLine(selected[0], items[-1], 5)
2382

    
2383
                self._scene.undo_stack.push(CreateCommand(self._scene, items))
2384
        finally:
2385
            self.graphicsView.scene().removeItem(home_pane.ui.toolButtonLine.tag._polyline)
2386
            home_pane.ui.toolButtonLine.tag.reset()
2387

    
2388
    def onCommandRejected(self, cmd=None):
2389
        """command is rejected"""
2390
        try:
2391
            home_pane = self.ribbon.get_pane('Home')
2392
            visualization_pane = self.ribbon.get_pane('Home Visualization')
2393
            if type(cmd) is PlaceLineCommand.PlaceLineCommand:
2394
                if home_pane.ui.toolButtonLine.tag._polyline:
2395
                    self.graphicsView.scene().removeItem(home_pane.ui.toolButtonLine.tag._polyline)
2396
                self.graphicsView.scene().update()
2397
                home_pane.ui.toolButtonLine.tag.reset()
2398

    
2399
                home_pane.ui.toolButtonLine.setChecked(False)
2400
            elif type(cmd) is AreaZoomCommand.AreaZoomCommand:
2401
                visualization_pane.ui.toolButtonZoom.setChecked(False)
2402
            elif type(cmd) is AreaOcrCommand.AreaOcrCommand:
2403
                home_pane.ui.toolButtonOCR.setChecked(False)
2404
            elif type(cmd) is PlacePolygonCommand.PlacePolygonCommand:
2405
                home_pane.ui.toolButtonVendor.setChecked(False)
2406
            else:
2407
                if hasattr(home_pane.ui.toolButtonVendor, 'tag') and home_pane.ui.toolButtonVendor.tag._polyline:
2408
                    self.graphicsView.scene().removeItem(home_pane.ui.toolButtonVendor.tag._polyline)
2409
                    self.graphicsView.scene().update()
2410
                    home_pane.ui.toolButtonVendor.tag.reset()
2411
                home_pane.ui.toolButtonLine.setChecked(False)
2412
                visualization_pane.ui.toolButtonZoom.setChecked(False)
2413
                home_pane.ui.toolButtonOCR.setChecked(False)
2414
                home_pane.ui.toolButtonVendor.setChecked(False)
2415
        finally:
2416
            self.graphicsView.useDefaultCommand()
2417

    
2418
    def on_view_toggle(self, key: int) -> None:
2419
        """view toggled"""
2420

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

    
2455
    def keyPressEvent(self, event):
2456
        """restore to default command when user press Escape key"""
2457
        try:
2458
            if event.key() == Qt.Key_Escape:
2459
                checked = self.checked_action()
2460
                if checked:
2461
                    checked.setChecked(False)
2462
                    self.graphicsView.useDefaultCommand()
2463
            elif event.key() == Qt.Key_M:  # merge text as vertical
2464
                from TextInfo import TextInfo
2465

    
2466
                textItems = [text for text in self.graphicsView.scene().selectedItems() if
2467
                             issubclass(type(text), QEngineeringTextItem)]
2468
                if not textItems or len(textItems) is 1:
2469
                    return
2470

    
2471
                angle = None
2472
                for item in textItems:
2473
                    if angle is None:
2474
                        angle = item.angle
2475
                    else:
2476
                        if angle != item.angle:
2477
                            return
2478

    
2479
                modifiers = QApplication.keyboardModifiers()
2480
                enter_or_space = ' ' if modifiers == Qt.ControlModifier else '\n'
2481
                x_or_y = 0 if (modifiers == Qt.ControlModifier and angle == 0) or (modifiers != Qt.ControlModifier and angle == 1.57) else 1
2482

    
2483
                textItems = sorted(textItems, key=lambda text: text.loc[x_or_y]) if textItems[0].angle == 0 else ( \
2484
                    sorted(textItems, key=lambda text: text.loc[x_or_y]) if textItems[0].angle == 1.57 else ( \
2485
                        sorted(textItems, key=lambda text: text.loc[x_or_y], reverse=True) if textItems[0].angle == 4.71 else \
2486
                            sorted(textItems, key=lambda text: text.loc[x_or_y], reverse=True)))
2487

    
2488
                if textItems[0].angle == 1.57 and modifiers == Qt.ControlModifier:
2489
                    textItems.reverse()
2490

    
2491
                minX = sys.maxsize
2492
                minY = sys.maxsize
2493
                maxX = 0
2494
                maxY = 0
2495
                newText = ''
2496

    
2497
                for text in textItems:
2498
                    if text.loc[0] < minX: minX = text.loc[0]
2499
                    if text.loc[1] < minY: minY = text.loc[1]
2500
                    if text.loc[0] + text.size[0] > maxX: maxX = text.loc[0] + text.size[0]
2501
                    if text.loc[1] + text.size[1] > maxY: maxY = text.loc[1] + text.size[1]
2502
                    newText = newText + text.text() + enter_or_space
2503
                    text.transfer.onRemoved.emit(text)
2504
                newText = newText[:-1]
2505

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

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

    
2541
                symbolItems = [symbol for symbol in self.graphicsView.scene().selectedItems() if
2542
                               issubclass(type(symbol), SymbolSvgItem)]
2543
                old_symbol = None
2544
                if symbolItems and len(symbolItems) is 1:
2545
                    old_symbol = symbolItems[0]
2546
                    #scenePos = QPoint(old_symbol.origin[0], old_symbol.origin[1])
2547
                    scenePos = old_symbol.mapToScene(old_symbol.transformOriginPoint())
2548
                    old_symbol.transfer.onRemoved.emit(old_symbol)
2549
                else:
2550
                    scenePos = self.current_pos
2551

    
2552
                svg = QtImageViewer.createSymbolObject(symName)
2553
                QtImageViewer.matchSymbolToLine(self.graphicsView.scene(), svg, scenePos, angle=old_symbol.angle if old_symbol else 0.0)
2554

    
2555
                if old_symbol and svg:
2556
                    from ReplaceCommand import ReplaceCommand
2557

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

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

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

    
2609
                app_doc_data = AppDocData.instance()
2610
                scene_to_dexpi('D:\\Temp\\DEXPI.xml', app_doc_data.activeDrawing.name, self.graphicsView.scene())
2611

    
2612
            QMainWindow.keyPressEvent(self, event)
2613
        except Exception as ex:
2614
            message = f"error occurred({repr(ex)}) in {sys.exc_info()[-1].tb_frame.f_code.co_filename}:" \
2615
                      f"{sys.exc_info()[-1].tb_lineno}"
2616
            self.addMessage.emit(MessageType.Error, message)
2617

    
2618
    def recognize(self):
2619
        """recognize symbol, text and line for selected drawings"""
2620
        from datetime import datetime
2621
        from License import QLicenseDialog
2622

    
2623
        # save alarm
2624
        self.save_alarm_enable(False)
2625

    
2626
        app_doc_data = AppDocData.instance()
2627
        current_drawing, currentPid = None, None
2628

    
2629
        if self.graphicsView.hasImage():
2630
            current_drawing = app_doc_data.activeDrawing
2631
            currentPid = app_doc_data.activeDrawing.name
2632

    
2633
        # get checked drawings
2634
        drawing_top = self.treeWidgetDrawingList.topLevelItem(0)
2635
        count = drawing_top.childCount()
2636
        checked_drawings = {}
2637
        for idx in range(count):
2638
            child = drawing_top.child(idx)
2639
            if child.checkState(0) == Qt.Checked and child.data(Qt.UserRole, 0):
2640
                checked_drawings[child.data(Qt.UserRole, 0)] = child
2641
        # up to here
2642

    
2643
        # if there is no checked drawing
2644
        if current_drawing and currentPid and not checked_drawings:
2645
            for idx in range(count):
2646
                child = drawing_top.child(idx)
2647
                if child.data(Qt.UserRole, 0) is current_drawing:
2648
                    checked_drawings[child.data(Qt.UserRole, 0)] = child
2649

    
2650
        if not checked_drawings:
2651
            self.showImageSelectionMessageBox()
2652
            return
2653

    
2654
        try:
2655
            self.on_clear_log()
2656
            dlg = QRecognitionDialog(self, [drawing for drawing in checked_drawings.keys()])
2657
            dlg.exec_()
2658

    
2659
            if current_drawing and current_drawing in checked_drawings.keys() and dlg.isTreated:
2660
                self.open_image_drawing(current_drawing, force=True, ocrUnknown=dlg.ui.checkBoxOCRUnknown.isChecked())
2661

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

    
2677
        # save alarm
2678
        self.save_alarm_enable(True, True)
2679

    
2680
    '''
2681
        @brief      remove item from tree widget and then remove from scene
2682
        @date       2018.05.25
2683
        @author     Jeongwoo
2684
    '''
2685
    def itemRemoved(self, item):
2686
        try:
2687
            if type(item) is QEngineeringErrorItem:
2688
                # remove error item from inconsistency list
2689
                for row in range(self.tableWidgetInconsistency.rowCount()):
2690
                    if item is self.tableWidgetInconsistency.item(row, 0).tag:
2691
                        self.tableWidgetInconsistency.removeRow(row)
2692
                        break
2693

    
2694
                if item.scene() is not None:
2695
                    item.scene().removeItem(item)
2696
                del item
2697
            else:
2698
                remove_scene = item.scene()
2699
                self.itemTreeWidget.itemRemoved(item)
2700

    
2701
                if remove_scene:
2702
                    matches = [_item for _item in remove_scene.items() if
2703
                            hasattr(_item, 'connectors') and [connector for connector in _item.connectors if
2704
                                                                connector.connectedItem is item]]
2705
                    for match in matches:
2706
                        for connector in match.connectors:
2707
                            if connector.connectedItem is item:
2708
                                connector.connectedItem = None
2709
                                connector.highlight(False)
2710

    
2711
                # matches = [_item for _item in self.graphicsView.scene().items() if hasattr(_item, 'remove_assoc_item')]
2712
                # for _item in matches:
2713
                #    _item.remove_assoc_item(item)
2714

    
2715
                app_doc_data = AppDocData.instance()
2716
                if type(item) is QEngineeringLineNoTextItem and item in app_doc_data.tracerLineNos:
2717
                    app_doc_data.tracerLineNos.pop(app_doc_data.tracerLineNos.index(item))
2718

    
2719
                if type(item) is QEngineeringLineItem and item in app_doc_data.lines:
2720
                    app_doc_data.lines.remove(item)
2721

    
2722
                if remove_scene:
2723
                    matches = [_item for _item in remove_scene.items() if
2724
                            type(_item) is QEngineeringLineNoTextItem]
2725
                    matches.extend([lineNo for lineNo in app_doc_data.tracerLineNos if
2726
                                    type(lineNo) is QEngineeringTrimLineNoTextItem])
2727
                    for match in matches:
2728
                        if item is match.prop('From'):
2729
                            match.set_property('From', None)
2730
                        if item is match.prop('To'):
2731
                            match.set_property('To', None)
2732

    
2733
                        for run_index in reversed(range(len(match.runs))):
2734
                            run = match.runs[run_index]
2735
                            if item in run.items:
2736
                                index = run.items.index(item)
2737
                                run.items.pop(index)
2738
                                if not run.items:
2739
                                    run.explode()
2740
                                    if type(match) is QEngineeringTrimLineNoTextItem and not match.runs:
2741
                                        app_doc_data.tracerLineNos.pop(app_doc_data.tracerLineNos.index(match))
2742
                                # break
2743

    
2744
                if remove_scene:
2745
                    matches = [_item for _item in remove_scene.items() if hasattr(_item, 'owner')]
2746
                    for match in matches:
2747
                        if match.owner is item:
2748
                            match.owner = None
2749

    
2750
                    matches = [_item for _item in remove_scene.items() if hasattr(_item, 'attrs')]
2751
                    # done = False
2752
                    for match in matches:
2753
                        assocs = match.associations()
2754
                        for assoc in assocs:
2755
                            if item is assoc:
2756
                                keys = match.attrs.keys()
2757
                                for attr in keys:
2758
                                    if attr.AssocItem and str(item.uid) == str(attr.AssocItem.uid):
2759
                                        attr.AssocItem = None
2760
                                        match.attrs[attr] = ''
2761
                                        # done = True
2762
                                match.remove_assoc_item(item)
2763
                                break
2764
                        # if done: break
2765

    
2766
                if item.scene() is not None:
2767
                    #if type(item) is QEngineeringLineNoTextItem and item._labels:
2768
                    #    for _label in item._labels:
2769
                    #        item.scene().removeItem(_label)
2770
                    #    item._labels = []
2771

    
2772
                    item.scene().removeItem(item)
2773
        except Exception as ex:
2774
            message = 'error occurred({}) in {}:{}'.format(ex, sys.exc_info()[-1].tb_frame.f_code.co_filename,
2775
                                                           sys.exc_info()[-1].tb_lineno)
2776
            self.addMessage.emit(MessageType.Error, message)
2777
        '''
2778
        finally:
2779
            if hasattr(item, '_cond'):
2780
                item._cond.wakeAll()
2781
        '''
2782

    
2783

    
2784
    def connect_attributes(self, MainWindow):
2785
        """connect attributes to symbol"""
2786
        from LineNoTracer import LineNoTracer
2787
        from ConnectAttrDialog import QConnectAttrDialog
2788

    
2789
        if not self.graphicsView.hasImage():
2790
            self.showImageSelectionMessageBox()
2791
            return
2792

    
2793
        # save alarm
2794
        self.save_alarm_enable(False)
2795

    
2796
        try:
2797
            dlg = QConnectAttrDialog(self, self.graphicsView.scene())
2798
            dlg.setWindowFlags(self.windowFlags() & ~Qt.WindowCloseButtonHint & ~Qt.WindowContextHelpButtonHint)
2799
            dlg.exec_()
2800
            if dlg.isRunned:
2801
                self.refresh_item_list()
2802

    
2803
                if dlg.validation_checked:
2804
                    self.onValidation()
2805

    
2806
                self.graphicsView.invalidateScene()
2807
        except Exception as ex:
2808
            message = 'error occurred({}) in {}:{}'.format(ex, sys.exc_info()[-1].tb_frame.f_code.co_filename,
2809
                                                           sys.exc_info()[-1].tb_lineno)
2810
            self.addMessage.emit(MessageType.Error, message)
2811
        finally:
2812
            # save alarm
2813
            self.save_alarm_enable(True)
2814

    
2815
    def postDetectLineProcess(self):
2816
        '''
2817
            @brief  check allowables among undetected items
2818
            @author euisung
2819
            @date   2018.11.15
2820
            @history    2018.11.15  euisung    no more used, moved to TextItemFactoy isLineNo()
2821
        '''
2822
        from TextItemFactory import TextItemFactory
2823

    
2824
        appDocData = AppDocData.instance()
2825

    
2826
        tableNames = ["Fluid Code", "Insulation Purpose", "PnID Number", "Piping Materials Class", "Unit Number"]
2827
        tableDatas = []
2828
        for tableName in tableNames:
2829
            tableNameFormat = tableName.replace(' ', '').replace('&&', 'n')
2830
            tableDatas.append(appDocData.getCodeTable(tableNameFormat))
2831

    
2832
        items = self.graphicsView.scene().items()
2833
        for item in items:
2834
            if type(item) is not QEngineeringTextItem:
2835
                continue
2836
            text = item.text()
2837
            for tableData in tableDatas:
2838
                for data in tableData:
2839
                    if data[3] == '':
2840
                        continue
2841
                    else:
2842
                        allows = data[3].split(',')
2843
                        for allow in allows:
2844
                            text = text.replace(allow, data[1])
2845

    
2846
            lineItem = TextItemFactory.instance().createTextItem(text)
2847
            if type(lineItem) is QEngineeringLineNoTextItem:
2848
                lineItem.loc = item.loc
2849
                lineItem.size = item.size
2850
                lineItem.angle = item.angle
2851
                lineItem.area = item.area
2852
                # lineItem.addTextItemToScene(self.graphicsView.scene())
2853
                lineItem.transfer.onRemoved.connect(self.itemRemoved)
2854
                item.transfer.onRemoved.emit(item)
2855
                appDocData.lineNos.append(lineItem)
2856

    
2857
    def init_add_tree_item(self, line_no_tree_item, run_item):
2858
        """ insert symbol item and find line no as owner """
2859
        # insert
2860
        self.itemTreeWidget.addTreeItem(line_no_tree_item, run_item)
2861
        # find
2862
        self.itemTreeWidget.addTreeItem(line_no_tree_item, run_item)
2863

    
2864
    def load_drawing(self, drawing):
2865
        """ load drawing """
2866
        """ no more used """
2867
        from EngineeringRunItem import QEngineeringRunItem
2868
        from QEngineeringTrimLineNoTextItem import QEngineeringTrimLineNoTextItem
2869

    
2870
        app_doc_data = AppDocData.instance()
2871
        try:
2872
            symbols = []
2873
            lines = []
2874

    
2875
            components = app_doc_data.get_components(drawing.UID)
2876
            maxValue = len(components) * 2
2877
            self.progress.setMaximum(maxValue) if maxValue > 0 else None
2878

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

    
2898
                self.progress.setValue(self.progress.value() + 1)
2899

    
2900
            QApplication.processEvents()
2901

    
2902
            # parse texts
2903
            for text in [component for component in components if
2904
                         component['Name'] == 'Text' and component['SymbolType_UID'] == -1]:
2905
                item = QEngineeringTextItem.from_database(text)
2906
                if item is not None:
2907
                    item.uid = text['UID']
2908
                    item.attribute = text['Value']
2909
                    name = text['Name']
2910
                    item.transfer.onRemoved.connect(self.itemRemoved)
2911
                    item.addTextItemToScene(self.graphicsView.scene())
2912

    
2913
                self.progress.setValue(self.progress.value() + 1)
2914

    
2915
            QApplication.processEvents()
2916

    
2917
            # note
2918
            for note in [component for component in components if
2919
                         component['Name'] == 'Note' and component['SymbolType_UID'] == -1]:
2920
                item = QEngineeringTextItem.from_database(note)
2921
                if item is not None:
2922
                    item.uid = note['UID']
2923
                    attributeValue = note['Value']
2924
                    name = note['Name']
2925
                    item.transfer.onRemoved.connect(self.itemRemoved)
2926
                    item.addTextItemToScene(self.graphicsView.scene())
2927

    
2928
                self.progress.setValue(self.progress.value() + 1)
2929

    
2930
            QApplication.processEvents()
2931

    
2932
            for line in [component for component in components if
2933
                         component['Name'] == 'Line' and component['SymbolType_UID'] == -1]:
2934
                item = QEngineeringLineItem.from_database(line)
2935
                if item:
2936
                    item.transfer.onRemoved.connect(self.itemRemoved)
2937
                    self.graphicsView.scene().addItem(item)
2938
                    lines.append(item)
2939

    
2940
                self.progress.setValue(self.progress.value() + 1)
2941

    
2942
            QApplication.processEvents()
2943

    
2944
            for unknown in [component for component in components if
2945
                            component['Name'] == 'Unknown' and component['SymbolType_UID'] == -1]:
2946
                item = QEngineeringUnknownItem.from_database(unknown)
2947
                item.transfer.onRemoved.connect(self.itemRemoved)
2948
                if item is not None:
2949
                    item.transfer.onRemoved.connect(self.itemRemoved)
2950
                    self.graphicsView.scene().addItem(item)
2951

    
2952
                self.progress.setValue(self.progress.value() + 1)
2953

    
2954
            QApplication.processEvents()
2955

    
2956
            for component in [component for component in components if
2957
                              component['Name'] == 'Line NO' and component['SymbolType_UID'] == -1]:
2958
                line_no = QEngineeringLineNoTextItem.from_database(component)
2959
                if type(line_no) is QEngineeringLineNoTextItem:
2960
                    line_no.transfer.onRemoved.connect(self.itemRemoved)
2961
                    self.addTextItemToScene(line_no)
2962
                    line_no_tree_item = self.itemTreeWidget.addTreeItem(self.itemTreeWidget.root, line_no)
2963

    
2964
                    runs = app_doc_data.get_pipe_runs(str(line_no.uid))
2965
                    if not runs: continue
2966
                    for run in runs:
2967
                        line_run = QEngineeringRunItem()
2968
                        run_items = app_doc_data.get_pipe_run_items(run['UID'])
2969
                        for record in run_items:
2970
                            uid = record['Components_UID']
2971
                            run_item = self.graphicsView.findItemByUid(uid)
2972
                            if run_item is not None:
2973
                                run_item._owner = line_no
2974
                                line_run.items.append(run_item)
2975
                        line_run.owner = line_no
2976
                        line_no.runs.append(line_run)
2977

    
2978
                        for run_item in line_run.items:
2979
                            if issubclass(type(run_item), SymbolSvgItem):
2980
                                self.init_add_tree_item(line_no_tree_item, run_item)
2981

    
2982
                self.progress.setValue(self.progress.value() + 1)
2983
            QApplication.processEvents()
2984

    
2985
            for component in [component for component in components if
2986
                              component['Name'] == 'Trim Line NO' and component['SymbolType_UID'] == -1]:
2987
                line_no = QEngineeringTrimLineNoTextItem()
2988
                line_no.uid = uuid.UUID(component['UID'])
2989

    
2990
                runs = app_doc_data.get_pipe_runs(str(line_no.uid))
2991
                if not runs: continue
2992

    
2993
                line_no_tree_item = self.itemTreeWidget.addTreeItem(self.itemTreeWidget.root, line_no)
2994

    
2995
                for run in runs:
2996
                    line_run = QEngineeringRunItem()
2997
                    run_items = app_doc_data.get_pipe_run_items(run['UID'])
2998
                    for record in run_items:
2999
                        uid = record['Components_UID']
3000
                        run_item = self.graphicsView.findItemByUid(uid)
3001
                        if run_item is not None:
3002
                            run_item.owner = line_no
3003
                            line_run.items.append(run_item)
3004
                    line_run.owner = line_no
3005
                    line_no.runs.append(line_run)
3006

    
3007
                    for run_item in line_run.items:
3008
                        if issubclass(type(run_item), SymbolSvgItem):
3009
                            self.init_add_tree_item(line_no_tree_item, run_item)
3010

    
3011
                app_doc_data.tracerLineNos.append(line_no)
3012

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

    
3015
            for component in [component for component in components if
3016
                              component['Name'] == 'VendorPackage' and component['SymbolType_UID'] == -1]:
3017
                item = QEngineeringVendorItem.from_database(component)
3018
                if item is not None:
3019
                    item.transfer.onRemoved.connect(self.itemRemoved)
3020
                    self.graphicsView.scene().addItem(item)
3021

    
3022
            # connect flow item to line
3023
            for line in lines:
3024
                line.update_arrow()
3025
                app_doc_data.lines.append(line)
3026
            # for flowMark in [item for item in symbols if type(item) is QEngineeringFlowMarkItem]:
3027
            #    for line in lines:
3028
            #        if flowMark.owner is line:
3029
            #            line._flowMark.append(flowMark)
3030
            #            flowMark.setParentItem(line)
3031
            # up to here
3032

    
3033
            """ update scene """
3034
            self.graphicsView.scene().update(self.graphicsView.sceneRect())
3035
            for item in self.graphicsView.scene().items():
3036
                up_progress = False
3037
                # binding items
3038
                if hasattr(item, 'owner'):
3039
                    item.owner
3040
                    up_progress = True
3041
                if hasattr(item, 'connectors'):
3042
                    for connector in item.connectors:
3043
                        connector.connectedItem
3044
                    up_progress = True
3045

    
3046
                if up_progress:
3047
                    self.progress.setValue(self.progress.value() + 1)
3048
            
3049
            for item in self.graphicsView.scene().items():
3050
                item.setVisible(True)
3051

    
3052
        except Exception as ex:
3053
            message = 'error occurred({}) in {}:{}'.format(ex, sys.exc_info()[-1].tb_frame.f_code.co_filename,
3054
                                                           sys.exc_info()[-1].tb_lineno)
3055
            self.addMessage.emit(MessageType.Error, message)
3056
        finally:
3057
            app_doc_data.clearTempDBData()
3058
            self.itemTreeWidget.update_item_count()
3059
            self.itemTreeWidget.expandAll()
3060
            # self.graphicsView.scene().blockSignals(False)
3061

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

    
3092
        def update_items(items):
3093
            for item in items:
3094
                # binding items
3095
                item.owner
3096
                for connector in item.connectors:
3097
                    connector.connectedItem
3098

    
3099
            return items
3100

    
3101
        import concurrent.futures as futures
3102
        from xml.etree.ElementTree import Element, SubElement, dump, ElementTree, parse
3103
        from App import App
3104
        from EngineeringRunItem import QEngineeringRunItem
3105
        from QEngineeringTrimLineNoTextItem import QEngineeringTrimLineNoTextItem
3106
        from EngineeringGraphicsLineItem import QEngineeringGraphicsLineItem
3107

    
3108
        app_doc_data = AppDocData.instance()
3109

    
3110
        try:
3111
            file_name = os.path.splitext(os.path.basename(drawing.file_path))[0]
3112
            path = os.path.join(app_doc_data.getCurrentProject().getTempPath(), file_name + '.xml')
3113
            self.graphicsView.scene().blockSignals(True)
3114

    
3115
            symbols = []
3116
            lines = []
3117

    
3118
            xml = parse(path)
3119
            root = xml.getroot()
3120

    
3121
            maxValue = 0
3122
            maxValue = maxValue + len(list(root.iter('SYMBOL'))) - \
3123
                       len(list(root.iterfind('LINENOS/LINE_NO/RUN/SYMBOL'))) - \
3124
                       len(list(root.iterfind('TRIMLINENOS/TRIM_LINE_NO/RUN/SYMBOL')))
3125
            maxValue = maxValue + len(list(root.iterfind('TEXTINFOS/ATTRIBUTE')))
3126
            maxValue = maxValue + len(list(root.iterfind('NOTES/ATTRIBUTE')))
3127
            maxValue = maxValue + len(list(root.iter('LINE_NO')))
3128
            maxValue = maxValue + len(list(root.iter('LINE'))) - \
3129
                       len(list(root.iterfind('LINENOS/LINE_NO/RUN/LINE'))) - \
3130
                       len(list(root.iterfind('TRIMLINENOS/TRIM_LINE_NO/RUN/LINE')))
3131
            maxValue = maxValue + len(list(root.iter('GRAPHICS_LINE')))
3132
            maxValue = maxValue + len(list(root.iter('UNKNOWN')))
3133
            # maxValue = maxValue + len(list(root.iter('SIZETEXT')))
3134
            maxValue = maxValue + len(list(root.iter('TRIM_LINE_NO')))
3135
            maxValue *= 2
3136
            self.progress.setMaximum(maxValue) if maxValue > 0 else None
3137

    
3138
            """ parsing all symbols """
3139
            """
3140
            with futures.ThreadPoolExecutor(max_workers=App.THREAD_MAX_WORKER) as pool:
3141
                future_symbol = {pool.submit(SymbolSvgItem.fromXml, symbol): symbol for symbol in root.find('SYMBOLS').iter('SYMBOL')}
3142

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

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

    
3185
                self.progress.setValue(self.progress.value() + 1)
3186

    
3187
            QApplication.processEvents()
3188

    
3189
            # parse texts
3190
            for text in root.find('TEXTINFOS').iter('ATTRIBUTE'):
3191
                item = QEngineeringTextItem.fromXml(text)
3192
                if item is not None:
3193
                    uid = text.find('UID')
3194
                    attributeValue = text.find('ATTRIBUTEVALUE')
3195
                    name = text.find('NAME').text
3196
                    item.transfer.onRemoved.connect(self.itemRemoved)
3197
                    item.addTextItemToScene(self.graphicsView.scene())
3198
                    # docData.texts.append(item)
3199

    
3200
                    if name == 'TEXT':
3201
                        if uid is not None and attributeValue is not None:
3202
                            item.uid = uid.text
3203
                            item.attribute = attributeValue.text
3204

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

    
3207
            QApplication.processEvents()
3208

    
3209
            # note
3210
            for text in root.find('NOTES').iter('ATTRIBUTE'):
3211
                item = QEngineeringTextItem.fromXml(text)
3212
                if item is not None:
3213
                    uid = text.find('UID')
3214
                    attributeValue = text.find('ATTRIBUTEVALUE')
3215
                    name = text.find('NAME').text
3216
                    item.transfer.onRemoved.connect(self.itemRemoved)
3217
                    item.addTextItemToScene(self.graphicsView.scene())
3218

    
3219
                    if name == 'NOTE':
3220
                        if uid is not None:
3221
                            item.uid = uid.text
3222

    
3223
                self.progress.setValue(self.progress.value() + 1)
3224

    
3225
            QApplication.processEvents()
3226

    
3227
            for line in root.find('LINEINFOS').iter('LINE'):
3228
                item = QEngineeringLineItem.fromXml(line)
3229
                if item:
3230
                    item.transfer.onRemoved.connect(self.itemRemoved)
3231
                    self.graphicsView.scene().addItem(item)
3232
                    lines.append(item)
3233

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

    
3236
            for line in root.find('LINEINFOS').iter('GRAPHICS_LINE'):
3237
                item = QEngineeringGraphicsLineItem.fromXml(line)
3238
                if item:
3239
                    item.transfer.onRemoved.connect(self.itemRemoved)
3240
                    self.graphicsView.scene().addItem(item)
3241

    
3242
                self.progress.setValue(self.progress.value() + 1)
3243

    
3244
            QApplication.processEvents()
3245

    
3246
            for unknown in root.iter('UNKNOWN'):
3247
                item = QEngineeringUnknownItem.fromXml(unknown)
3248
                if item is not None:
3249
                    item.transfer.onRemoved.connect(self.itemRemoved)
3250
                    self.graphicsView.scene().addItem(item)
3251

    
3252
                self.progress.setValue(self.progress.value() + 1)
3253

    
3254
            QApplication.processEvents()
3255

    
3256
            # """ add tree widget """
3257
            # for item in symbols:
3258
            #    docData.symbols.append(item)
3259
            #    self.addSvgItemToScene(item)
3260
            #    self.itemTreeWidget.addTreeItem(self.itemTreeWidget.root, item)
3261

    
3262
            for line_no_node in root.find('LINENOS').iter('LINE_NO'):
3263
                line_no = QEngineeringLineNoTextItem.fromXml(line_no_node)
3264
                if line_no is None: continue
3265
                line_no.transfer.onRemoved.connect(self.itemRemoved)
3266
                line_no.addTextItemToScene(self.graphicsView.scene())
3267
                line_no_tree_item = self.itemTreeWidget.addTreeItem(self.itemTreeWidget.root, line_no)
3268
                if type(line_no) is not QEngineeringLineNoTextItem: continue
3269

    
3270
                runs_node = line_no_node.findall('RUN')
3271
                if runs_node is None: continue
3272

    
3273
                for run_node in runs_node:
3274
                    line_run = QEngineeringRunItem()
3275
                    for child_node in run_node:
3276
                        uidElement = child_node.find('UID')
3277
                        if uidElement is not None:
3278
                            uid = uidElement.text
3279
                            run_item = self.graphicsView.findItemByUid(uid)
3280
                            if run_item is not None:
3281
                                run_item._owner = line_no
3282
                                line_run.items.append(run_item)
3283
                    line_run.owner = line_no
3284
                    line_no.runs.append(line_run)
3285

    
3286
                    for run_item in line_run.items:
3287
                        if issubclass(type(run_item), SymbolSvgItem):
3288
                            self.init_add_tree_item(line_no_tree_item, run_item)
3289

    
3290
                # docData.tracerLineNos.append(line_no)
3291

    
3292
                self.progress.setValue(self.progress.value() + 1)
3293
            QApplication.processEvents()
3294

    
3295
            for trimLineNo in root.iter('TRIM_LINE_NO'):
3296
                line_no = QEngineeringTrimLineNoTextItem()
3297
                line_no.uid = uuid.UUID(trimLineNo.find('UID').text)
3298

    
3299
                runs_node = trimLineNo.findall('RUN')
3300
                if runs_node is None: continue
3301
                line_no_tree_item = self.itemTreeWidget.addTreeItem(self.itemTreeWidget.root, line_no)
3302

    
3303
                for run in runs_node:
3304
                    line_run = QEngineeringRunItem()
3305
                    for child in run:
3306
                        uidElement = child.find('UID')
3307
                        if uidElement is not None:
3308
                            uid = uidElement.text
3309
                            run_item = self.graphicsView.findItemByUid(uid)
3310
                            if run_item is not None:
3311
                                run_item.owner = line_no
3312
                                line_run.items.append(run_item)
3313
                    line_run.owner = line_no
3314
                    line_no.runs.append(line_run)
3315

    
3316
                    for run_item in line_run.items:
3317
                        if issubclass(type(run_item), SymbolSvgItem):
3318
                            self.init_add_tree_item(line_no_tree_item, run_item)
3319

    
3320
                app_doc_data.tracerLineNos.append(line_no)
3321

    
3322
                self.progress.setValue(self.progress.value() + 1)
3323
            QApplication.processEvents()
3324

    
3325
            if root.find('VENDORS') is not None:
3326
                for vendor in root.find('VENDORS').iter('VENDOR'):
3327
                    item = QEngineeringVendorItem.fromXml(vendor)
3328
                    item.transfer.onRemoved.connect(self.itemRemoved)
3329
                    self.graphicsView.scene().addItem(item)
3330

    
3331
            # connect flow item to line
3332
            for line in lines:
3333
                line.update_arrow()
3334
                app_doc_data.lines.append(line)
3335
            # for flowMark in [item for item in symbols if type(item) is QEngineeringFlowMarkItem]:
3336
            #    for line in lines:
3337
            #        if flowMark.owner is line:
3338
            #            line._flowMark.append(flowMark)
3339
            #            flowMark.setParentItem(line)
3340
            # up to here
3341

    
3342
            """
3343
            group_box = QGroupBox("Contact Details")
3344
            number_label = QLabel("Telephone number");
3345
            number_edit = QTextEdit('hello\nthis is ....')
3346
            layout = QFormLayout()
3347
            layout.addRow(number_label, number_edit)
3348
            group_box.setLayout(layout)
3349

3350
            proxy =  ㅐ()
3351
            proxy.setWidget(group_box)
3352
            self.graphicsView.scene().addItem(proxy)  # (group_box, QGraphicsItem.ItemIgnoresTransformations)
3353
            """
3354

    
3355
            """ update scene """
3356
            _items = [_item for _item in self.graphicsView.scene().items() if hasattr(_item, 'owner') or hasattr(_item, 'connectors')]
3357
            if _items:
3358
                items = divide_chunks(_items, App.THREAD_MAX_WORKER if len(_items) > App.THREAD_MAX_WORKER else len(_items))
3359
                with futures.ThreadPoolExecutor(max_workers=App.THREAD_MAX_WORKER) as pool:
3360
                    future_items = {pool.submit(update_items, _items): _items for _items in items}
3361
                    for future in futures.as_completed(future_items):
3362
                        _items = future.result()
3363
                        self.progress.setValue(self.progress.value() + len(_items))
3364

    
3365
            """
3366
            for item in [_item for _item in self.graphicsView.scene().items() if hasattr(_item, 'owner') or hasattr(_item, 'connectors')]:
3367
                up_progress = False
3368
                # binding items
3369
                item.owner
3370
                for connector in item.connectors:
3371
                    connector.connectedItem
3372

3373
                self.progress.setValue(self.progress.value() + 1)
3374
            """
3375

    
3376
            for item in self.graphicsView.scene().items():
3377
                item.setVisible(True)
3378

    
3379
            self.graphicsView.scene().update(self.graphicsView.sceneRect())
3380
        except Exception as ex:
3381
            message = 'error occurred({}) in {}:{}'.format(ex, sys.exc_info()[-1].tb_frame.f_code.co_filename,
3382
                                                           sys.exc_info()[-1].tb_lineno)
3383
            self.addMessage.emit(MessageType.Error, message)
3384
        finally:
3385
            self.itemTreeWidget.update_item_count()
3386
            self.itemTreeWidget.expandAll()
3387
            self.graphicsView.scene().blockSignals(False)
3388

    
3389
    '''
3390
        @brief      Remove added item on same place and Add GraphicsItem
3391
        @author     Jeongwoo
3392
        @date       2018.05.29
3393
        @history    2018.06.18  Jeongwoo    Set Z-index
3394
    '''
3395
    def addLineItemToScene(self, lineItem):
3396
        self.graphicsView.scene().addItem(lineItem)
3397

    
3398
    '''
3399
        @brief      generate output xml file
3400
        @author     humkyung
3401
        @date       2018.04.23
3402
        @history    2018.05.02  Jeongwoo    Show MessageBox when imageviewer doesn't have image
3403
    '''
3404
    def generateOutput(self):
3405
        import XmlGenerator as xg
3406

    
3407
        if not self.graphicsView.hasImage():
3408
            self.showImageSelectionMessageBox()
3409
            return
3410

    
3411
        try:
3412
            appDocData = AppDocData.instance()
3413

    
3414
            # collect items
3415
            appDocData.lines.clear()
3416
            appDocData.lines = [item for item in self.graphicsView.scene().items() if
3417
                                type(item) is QEngineeringLineItem and item.owner is None]
3418

    
3419
            appDocData.symbols.clear()
3420
            appDocData.symbols = [item for item in self.graphicsView.scene().items() if
3421
                                  issubclass(type(item), SymbolSvgItem) and item.owner is None]
3422

    
3423
            appDocData.equipments.clear()
3424
            for item in self.graphicsView.scene().items():
3425
                if type(item) is QEngineeringEquipmentItem:
3426
                    appDocData.equipments.append(item)
3427

    
3428
            appDocData.texts.clear()
3429
            appDocData.texts = [item for item in self.graphicsView.scene().items() if
3430
                                issubclass(type(item), QEngineeringTextItem) and type(
3431
                                    item) is not QEngineeringLineNoTextItem]
3432
            # up to here
3433

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

    
3445
    '''
3446
        @brief      Check Number
3447
        @author     kyouho
3448
        @date       2018.08.20
3449
    '''
3450
    def isNumber(self, num):
3451
        p = re.compile('(^[0-9]+$)')
3452
        result = p.match(num)
3453

    
3454
        if result:
3455
            return True
3456
        else:
3457
            return False
3458

    
3459
    '''
3460
        @brief      find overlap Connector
3461
        @author     kyouho
3462
        @date       2018.08.28
3463
    '''
3464
    def findOverlapConnector(self, connectorItem):
3465
        from shapely.geometry import Point
3466
        from EngineeringConnectorItem import QEngineeringConnectorItem
3467
        itemList = []
3468

    
3469
        x = connectorItem.center()[0]
3470
        y = connectorItem.center()[1]
3471

    
3472
        connectors = [item for item in self.graphicsView.scene().items() if
3473
                      type(item) is QEngineeringConnectorItem and item != connectorItem]
3474
        for connector in connectors:
3475
            if Point(x, y).distance(Point(connector.center()[0], connector.center()[1])) < 5:
3476
                itemList.append(connector.parent)
3477

    
3478
        return itemList
3479

    
3480
    def make_diff_image(self):
3481
        """ make diff image """
3482
        # test
3483

    
3484
        from RecognitionDialog import Worker
3485
        from symbol import Symbol
3486
        import math
3487
        from PIL import Image
3488

    
3489
        app_doc_data = AppDocData.instance()
3490
        img = app_doc_data.imgSrc.copy()
3491

    
3492
        # check break
3493
        symbols = [item for item in self.graphicsView.scene().items() if issubclass(type(item), SymbolSvgItem)]
3494

    
3495
        for symbol in symbols:
3496
            rect = symbol.sceneBoundingRect()
3497
            sName = symbol.name
3498
            sType = symbol.type
3499
            sp = (rect.x(), rect.y())
3500
            w, h = rect.width(), rect.height()
3501
            rotatedAngle = round(math.degrees(symbol.angle))
3502
            detectFlip = symbol.flip
3503

    
3504
            dummySym = Symbol(sName, sType, sp, w, h, 0, 0, 0, rotatedAngle,
3505
                                   1, 0, 1, 0,
3506
                                   ','.join(str(x) for x in [0, 0]),
3507
                                   '/'.join('{},{},{},{}'.format(param[0], param[1], param[2], param[3]) for param in
3508
                                            []),
3509
                                   'dummy', 'dummy', 0, detectFlip=detectFlip,
3510
                                   hasInstrumentLabel=0, text_area='')
3511

    
3512
            Worker.remove_detected_symbol_image(dummySym, img, lock=False)
3513

    
3514
        Image.fromarray(img).show()
3515

    
3516
    #def paintEvent(self, event):
3517
    #    self.refresh_rate += 1
3518
    #    if self.refresh_rate == 3:
3519
    #        super(self.__class__, self).paintEvent(event)
3520
    #        self.refresh_rate = 0
3521

    
3522
if __name__ == '__main__':
3523
    import locale
3524
    from PyQt5.QtCore import QTranslator
3525
    from License import QLicenseDialog
3526
    from ProjectDialog import Ui_Dialog
3527
    from App import App
3528

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