프로젝트

일반

사용자정보

통계
| 개정판:

hytos / DTI_PID / DTI_PID / MainWindow.py @ 38320b62

이력 | 보기 | 이력해설 | 다운로드 (162 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
        drawing = item.data(Qt.UserRole, 0)
655
        if drawing:
656
            # uncheck all drawing tree item
657
            drawing_top = self.treeWidgetDrawingList.topLevelItem(0)
658
            count = drawing_top.childCount()
659
            for idx in range(count):
660
                child = drawing_top.child(idx)
661
                child.setCheckState(column, Qt.Unchecked)
662
            # up to here
663

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

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

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

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

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

    
693
        return
694

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

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

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

    
726
        from TextItemEditDialog import QTextItemEditDialog
727

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

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

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

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

    
746
        from ReplaceSymbolDialog import QReplaceSymbolDialog
747

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

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

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

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

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

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

    
775
    def on_connect_line_to_symbol(self):
776
        """connect line to symbol"""
777
        from LineDetector import LineDetector
778
        from shapely.geometry import Point
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 = sorted([item for item in self.graphicsView.scene().items() if type(item) is QEngineeringLineItem], key=lambda param: param.length(), reverse=True)# 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
        end_breaks = [item for item in self.graphicsView.scene().items() if type(item) is QEngineeringEndBreakItem]
795
        symbols = [item for item in self.graphicsView.scene().items() if issubclass(type(item), SymbolSvgItem) and item not in end_breaks]
796

    
797
        for item in lines_short + unknowns:
798
            item.transfer.onRemoved.emit(item)
799

    
800
        # connect symbol to symbol
801
        try:
802
            for symbol in symbols:
803
                matches = [it for it in symbols if it is not symbol and symbol.is_connectable(it, toler=toler)]
804
                for match in matches:
805
                    symbol.connect_if_possible(match, toler=int(toler / 5 * 3))
806
        except Exception as ex:
807
            message = f"error occurred({repr(ex)}) in {sys.exc_info()[-1].tb_frame.f_code.co_filename}:" \
808
                        f"{sys.exc_info()[-1].tb_lineno}"
809
            self.addMessage.emit(MessageType.Error, message)
810
        # up to here
811

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

    
826
                conns = []
827
                for sym in symbols:
828
                    if sym.conn_type:
829
                        for index in range(len(sym.conn_type)):
830
                            if sym.conn_type[index] == 'Secondary' or sym.conn_type[index] == 'Primary':
831
                                item = sym.connectors[index].connectedItem
832
                                if item is None and sym.connectors[index]:
833
                                    conns.append(sym.connectors[index])
834
                
835
                #new_lines.extend(Worker.make_short_lines_stl(lines, conns, None))
836

    
837
                for line in new_lines:
838
                    self.graphicsView.scene().addItem(line)
839
                    for conn in line.connectors:
840
                        conn.transfer.onPosChanged.connect(line.onConnectorPosChaned)
841
            except Exception as ex:
842
                message = f"error occurred({repr(ex)}) in {sys.exc_info()[-1].tb_frame.f_code.co_filename}:" \
843
                          f"{sys.exc_info()[-1].tb_lineno}"
844
                self.addMessage.emit(MessageType.Error, message)
845
                
846
            # connect line to symbol
847
            try:
848
                for line in lines:
849
                    matches = [_symbol for _symbol in symbols if _symbol.is_connectable(line, toler=toler)]
850
                    for _symbol in matches:
851
                        detector.connectLineToSymbol(line, _symbol, toler=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
            # connect line to line
859
            try:
860
                for line in lines:
861
                    matches = [it for it in lines if (it is not line) and (not line.isParallel(it))]
862

    
863
                    for match in matches:
864
                        detector.connectLineToLine(match, line, toler)
865
            except Exception as ex:
866
                message = f"error occurred({repr(ex)}) in {sys.exc_info()[-1].tb_frame.f_code.co_filename}:" \
867
                          f"{sys.exc_info()[-1].tb_lineno}"
868
                self.addMessage.emit(MessageType.Error, message)
869
            # up to here
870

    
871
            # connect end break
872
            usedItemPairs = []
873
            for end_break in end_breaks:
874
                if end_break.prop('Freeze') or end_break.owner or end_break.prop('Connected Item'):
875
                    usedItemPairs.append([end_break.owner, end_break.prop('Connected Item')])
876

    
877
            for end_break in end_breaks:
878
                if end_break.prop('Freeze') or end_break.owner or end_break.prop('Connected Item'):
879
                    continue
880

    
881
                originPoint = Point(end_break.origin[0], end_break.origin[1])
882
                minD = sys.maxsize
883
                ownerItem = None
884
                connectedItem = None
885

    
886
                for symbol in symbols:
887
                    for conn in symbol.connectors:
888
                        dist = originPoint.distance(Point(conn.sceneConnectPoint[0], conn.sceneConnectPoint[1]))
889
                        if not conn.connectedItem or not issubclass(type(conn.connectedItem), QEngineeringAbstractItem) or \
890
                            [pair for pair in usedItemPairs if symbol in pair and conn.connectedItem in pair] or dist > 2.5 * toler or dist > minD:
891
                            continue
892

    
893
                        minD = dist
894
                        ownerItem = symbol
895
                        connectedItem = conn.connectedItem
896

    
897
                for line in lines:
898
                    for conn in line.connectors:
899
                        dist = originPoint.distance(Point(conn.sceneConnectPoint[0], conn.sceneConnectPoint[1]))
900
                        if not conn.connectedItem or not issubclass(type(conn.connectedItem), QEngineeringAbstractItem) or \
901
                            conn._connected_at != QEngineeringAbstractItem.CONNECTED_AT_BODY  or \
902
                            [pair for pair in usedItemPairs if line in pair and conn.connectedItem in pair] or dist > 2.5 * toler or dist > minD:
903
                            continue
904

    
905
                        minD = dist
906
                        ownerItem = line
907
                        connectedItem = conn.connectedItem
908

    
909
                if ownerItem and connectedItem:
910
                    end_break.set_property('Connected Item', connectedItem)
911
                    end_break.setToolTip('owner : ' + str(ownerItem))
912
                    end_break.owner = ownerItem
913
                    end_break.set_property('Freeze', True)
914

    
915
                    usedItemPairs.append([ownerItem, connectedItem])
916
            # up to here
917

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

    
920
    def on_recognize_line(self):
921
        """recognize lines in selected area"""
922
        from RecognizeLineCommand import RecognizeLineCommand
923

    
924
        if not self.graphicsView.hasImage():
925
            self.actionOCR.setChecked(False)
926
            self.showImageSelectionMessageBox()
927
            return
928

    
929
        cmd = RecognizeLineCommand(self.graphicsView)
930
        cmd.onSuccess.connect(self.on_success_to_recognize_line)
931
        cmd.onRejected.connect(self.onCommandRejected)
932
        self.graphicsView.command = cmd
933

    
934
    '''
935
            @brief      show text recognition dialog
936
            @author     humkyung
937
            @date       2018.08.08
938
    '''
939
    def on_success_to_recognize_line(self, x, y, width, height):
940
        import io
941
        from LineDetector import LineDetector
942
        from EngineeringGraphicsLineItem import QEngineeringGraphicsLineItem
943

    
944
        try:
945
            image = self.graphicsView.image().copy(x, y, width, height)
946
            buffer = QBuffer()
947
            buffer.open(QBuffer.ReadWrite)
948
            image.save(buffer, "PNG")
949
            pyImage = Image.open(io.BytesIO(buffer.data()))
950
            img = np.array(pyImage)
951
            img = cv2.cvtColor(img, cv2.COLOR_BGR2GRAY)
952

    
953
            detector = LineDetector(img)
954
            lines = detector.detect_line_without_symbol()
955
            for line in lines:
956
                vertices = [[line[0][0] + x, line[0][1] + y], [line[1][0] + x, line[1][1] + y]]
957
                line_item = QEngineeringGraphicsLineItem(vertices)
958
                self.graphicsView.scene().addItem(line_item)
959

    
960
        except Exception as ex:
961
            message = 'error occurred({}) in {}:{}'.format(repr(ex), sys.exc_info()[-1].tb_frame.f_code.co_filename,
962
                                                           sys.exc_info()[-1].tb_lineno)
963
            self.addMessage.emit(MessageType.Error, message)
964

    
965
    def display_number_of_items(self):
966
        """display count of symbol, line, text"""
967

    
968
        items = [item for item in self.graphicsView.scene().items() if type(item) is QEngineeringUnknownItem]
969
        if len(items) > 0:
970
            self.labelStatus.setText(
971
                "<font color='red'>" + self.tr('Unrecognition') + " : {}</font>".format(len(items)))
972
        else:
973
            self.labelStatus.setText(
974
                "<font color='black'>" + self.tr('Unrecognition') + " : {}</font>".format(len(items)))
975

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

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

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

    
986
        self.itemTreeWidget.sceneChanged(self.graphicsView.scene().items())
987

    
988
    def dbUpdate(self):
989
        """ no more used """
990
        """db update when save or recognition"""
991

    
992
        try:
993
            appDocData = AppDocData.instance()
994
            items = appDocData.allItems
995

    
996
            '''
997
            titleBlockProps = appDocData.getTitleBlockProperties()
998
            titleBlockItems = []
999
            for item in items:
1000
                # if type(item) is QEngineeringLineNoTextItem:
1001
                #    item.saveLineData()
1002
                if type(item) is QEngineeringTextItem:
1003
                    for titleBlockProp in titleBlockProps:
1004
                        if item.area == titleBlockProp[0]:
1005
                            titleBlockItems.append(item)
1006
            '''
1007

    
1008
            # unknown item is not saved now for performance
1009
            db_items = [item for item in items if issubclass(type(item), QEngineeringAbstractItem) and
1010
                        type(item) is not QGraphicsBoundingBoxItem and
1011
                        type(item) is not QEngineeringErrorItem and
1012
                        type(item) is not QEngineeringLineNoTextItem and
1013
                        type(item) is not QEngineeringUnknownItem]
1014
            db_items.extend([item for item in items if type(item) is QEngineeringLineNoTextItem])
1015
            db_items.extend([line for line in appDocData.tracerLineNos if type(line) is QEngineeringTrimLineNoTextItem])
1016
            # db_items.extend(titleBlockItems)
1017
            configs = appDocData.getConfigs('Data Save', 'Unknown Xml Only')
1018
            if configs and int(configs[0].value) is -1:
1019
                db_items.extend([item for item in items if type(item) is QEngineeringUnknownItem])
1020

    
1021
            '''
1022
            dbItems = [item for item in items if
1023
                       type(item) is QEngineeringInstrumentItem or type(item) is QEngineeringEquipmentItem or type(
1024
                           item) is QEngineeringReducerItem or \
1025
                       type(item) is QEngineeringNoteItem or type(item) is SymbolSvgItem or type(
1026
                           item) is QEngineeringLineNoTextItem or type(
1027
                           item) is QEngineeringVendorItem] + titleBlockItems
1028
            '''
1029
            appDocData.saveToDatabase(db_items)
1030
        except Exception as ex:
1031
            message = 'error occurred({}) in {}:{}'.format(ex, sys.exc_info()[-1].tb_frame.f_code.co_filename,
1032
                                                           sys.exc_info()[-1].tb_lineno)
1033
            self.addMessage.emit(MessageType.Error, message)
1034

    
1035
    def save_drawing_if_necessary(self):
1036
        """ask to user to save drawing or not when drawing is modified"""
1037

    
1038
        app_doc_data = AppDocData.instance()
1039
        if app_doc_data.activeDrawing and app_doc_data.activeDrawing.modified:
1040
            #if QMessageBox.Yes == QMessageBox.question(self, self.tr("Question"),
1041
            #                                           self.tr("Do you want to save drawing?"),
1042
            #                                           QMessageBox.Yes | QMessageBox.No):
1043
            #    self.actionSaveCliked()
1044
            #    return True
1045
            if QMessageBox.Ignore == QMessageBox.question(self, self.tr('Continue?'),
1046
                                                       self.tr('Changes may not have been saved.'),
1047
                                                       QMessageBox.Ignore | QMessageBox.Cancel):
1048
                return False
1049
            return True
1050

    
1051
    def actionSaveCliked(self):
1052
        """
1053
        save current drawing
1054
        @return:
1055
        """
1056
        from EngineeringAbstractItem import QEngineeringAbstractItem
1057
        from SaveWorkCommand import SaveWorkCommand
1058

    
1059
        try:
1060
            home_pane = self.ribbon.get_pane('Home File')
1061
            if not home_pane.ui.toolButtonFileSave.isEnabled():
1062
                return
1063

    
1064
            home_pane.ui.toolButtonFileSave.setEnabled(False)
1065

    
1066
            # save alarm
1067
            self.save_alarm_enable(False)
1068

    
1069
            app_doc_data = AppDocData.instance()
1070
            if app_doc_data.imgName is None:
1071
                self.showImageSelectionMessageBox()
1072
                return
1073

    
1074
            app_doc_data.clearItemList(False)
1075

    
1076
            items = self.graphicsView.scene().items()
1077

    
1078
            self._save_work_cmd = SaveWorkCommand(self.graphicsView.scene())
1079
            self._save_work_cmd.show_progress.connect(self.progress_bar.setValue)
1080
            self._save_work_cmd.display_message.connect(self.onAddMessage)
1081
            self._save_work_cmd.finished.connect(self.save_finished)
1082

    
1083
            self._save_work_cmd.start()
1084
        except Exception as ex:
1085
            message = f"error occurred({repr(ex)}) in {sys.exc_info()[-1].tb_frame.f_code.co_filename}:" \
1086
                      f"{sys.exc_info()[-1].tb_lineno}"
1087
            self.addMessage.emit(MessageType.Error, message)
1088

    
1089
    def save_finished(self):
1090
        """
1091
        reload drawing list when save is finished
1092
        @return: None
1093
        """
1094

    
1095
        try:
1096
            self._save_work_cmd.show_progress.emit(100)
1097
            QMessageBox.about(self.graphicsView, self.tr('Information'), self._save_work_cmd.resultStr)
1098
            self.load_drawing_list()
1099

    
1100
            app_doc_data = AppDocData.instance()
1101
            app_doc_data.activeDrawing.modified = False
1102
            title = self.windowTitle()
1103
            self.setWindowTitle(title[:-1] if title[-1] == '*' else title)
1104

    
1105
            # save alarm
1106
            self.save_alarm_enable(True)
1107
        finally:
1108
            home_pane = self.ribbon.get_pane('Home File')
1109
            home_pane.ui.toolButtonFileSave.setEnabled(True)
1110

    
1111
    '''
1112
        @brief      refresh resultPropertyTableWidget
1113
        @author     kyouho
1114
        @date       2018.07.19
1115
    '''
1116
    def refreshResultPropertyTableWidget(self):
1117
        items = self.graphicsView.scene().selectedItems()
1118
        if len(items) == 1:
1119
            self.resultPropertyTableWidget.show_item_property(items[0])
1120

    
1121
    '''
1122
        @brief  add message listwidget
1123
        @author humkyung
1124
        @date   2018.07.31
1125
    '''
1126
    def onAddMessage(self, messageType, message):
1127
        from AppDocData import MessageType
1128

    
1129
        try:
1130
            current = QDateTime.currentDateTime()
1131

    
1132
            item = QListWidgetItem('{}: {}'.format(current.toString('hh:mm:ss'), message))
1133
            item.setFlags(item.flags() | Qt.ItemIsEditable)
1134
            if messageType == MessageType.Error:
1135
                item.setBackground(Qt.red)
1136
            elif messageType == 'check':
1137
                item.setBackground(Qt.yellow)
1138

    
1139
            self.listWidgetLog.insertItem(0, item)
1140
        except Exception as ex:
1141
            print('error occurred({}) in {}:{}'.format(ex, sys.exc_info()[-1].tb_frame.f_code.co_filename,
1142
                                                       sys.exc_info()[-1].tb_lineno))
1143

    
1144
    def on_clear_log(self):
1145
        """clear log"""
1146
        self.listWidgetLog.clear()
1147

    
1148
    def onRotate(self, action):
1149
        """rotate a selected symbol"""
1150
        selected = [item for item in self.graphicsView.scene().selectedItems() if issubclass(type(item), SymbolSvgItem)]
1151
        if len(selected) == 1:
1152
            from RotateCommand import RotateCommand
1153
            self.graphicsView.scene()._undo_stack.push(RotateCommand(self.graphicsView.scene(), selected))
1154

    
1155
    def onAreaZoom(self):
1156
        """Area Zoom"""
1157
        visualization_pane = self.ribbon.get_pane('Home Visualization')
1158

    
1159
        self.update_action_group(visualization_pane.ui.toolButtonZoom)
1160
        if visualization_pane.ui.toolButtonZoom.isChecked():
1161
            cmd = AreaZoomCommand.AreaZoomCommand(self.graphicsView)
1162
            cmd.onRejected.connect(self.onCommandRejected)
1163
            self.graphicsView.command = cmd
1164

    
1165
    def onVendor(self, action):
1166
        """make vendor/equipment package area"""
1167

    
1168
        pane = self.ribbon.get_pane('Home')
1169
        if not self.graphicsView.hasImage():
1170
            pane.ui.toolButtonVendor.setChecked(False)
1171
            self.showImageSelectionMessageBox()
1172
            return
1173

    
1174
        pane = self.ribbon.get_pane('Home')
1175
        self.update_action_group(pane.ui.toolButtonVendor)
1176
        checked = pane.ui.toolButtonVendor.isChecked()
1177
        if not hasattr(pane.ui.toolButtonVendor, 'tag'):
1178
            pane.ui.toolButtonVendor.tag = PlacePolygonCommand.PlacePolygonCommand(self.graphicsView)
1179
            pane.ui.toolButtonVendor.tag.onSuccess.connect(self.onVendorCreated)
1180
            pane.ui.toolButtonVendor.tag.onRejected.connect(self.onCommandRejected)
1181

    
1182
        self.graphicsView.command = pane.ui.toolButtonVendor.tag
1183

    
1184
    def onVendorCreated(self):
1185
        """add created vendor polygon area to scene"""
1186

    
1187
        try:
1188
            vendor_tool = self.ribbon.get_pane('Home').ui.toolButtonVendor
1189
            package_combo = self.ribbon.get_pane('Home').ui.comboBoxPackage
1190
            count = len(vendor_tool.tag._polyline._vertices)
1191
            if count > 2:
1192
                points = []
1193
                for point in vendor_tool.tag._polyline._vertices:
1194
                    points.append(QPoint(round(point[0]), round(point[1])))
1195
                polygon = QPolygonF(points)
1196
                item = QEngineeringVendorItem(polygon, pack_type=package_combo.currentText())
1197
                item.area = 'Drawing'
1198
                item.transfer.onRemoved.connect(self.itemRemoved)
1199
                self.graphicsView.scene().addItem(item)
1200
        finally:
1201
            self.graphicsView.scene().removeItem(vendor_tool.tag._polyline)
1202
            vendor_tool.tag.reset()
1203

    
1204
    def fitWindow(self, view_rect: QRectF = QRectF()):
1205
        """Fit Window"""
1206
        self.graphicsView.useDefaultCommand()
1207
        self.graphicsView.zoomImageInit()
1208

    
1209
        visualization_pane = self.ribbon.get_pane('Home Visualization')
1210
        self.update_action_group(visualization_pane.ui.toolButtonFitWindow)
1211
        if view_rect:
1212
            self.graphicsView.zoom_rect(view_rect)
1213

    
1214
    def on_toggle_lock_axis(self):
1215
        """toggle lock axis"""
1216
        from EngineeringPolylineItem import QEngineeringPolylineItem
1217

    
1218
        visualization_pane = self.ribbon.get_pane('Home Visualization')
1219
        if self.sender() is not visualization_pane.ui.toolButtonLockAxis:
1220
            checked = visualization_pane.ui.toolButtonLockAxis.isChecked()
1221
            visualization_pane.ui.toolButtonLockAxis.setChecked(not checked)
1222

    
1223
        checked = visualization_pane.ui.toolButtonLockAxis.isChecked()
1224
        QEngineeringPolylineItem.DRAWING_MODE = QEngineeringPolylineItem.AXIS_MODE if checked else \
1225
            QEngineeringPolylineItem.FREE_MODE
1226

    
1227
    def scene_changed(self):
1228
        """update modified flag"""
1229

    
1230
        self.display_number_of_items()
1231

    
1232
        app_doc_data = AppDocData.instance()
1233
        app_doc_data.activeDrawing.modified = True
1234
        title = self.windowTitle()
1235
        self.setWindowTitle(title if title[-1] == '*' else title + '*')
1236

    
1237
    def onConvertPDFToImage(self):
1238
        """convert to selected pdf to image"""
1239
        import os
1240

    
1241
        try:
1242
            file_path = os.path.join(os.path.dirname(os.path.realpath(__file__)), 'bin64', 'PDF_TO_IMAGE.exe')
1243
            os.startfile(file_path)
1244
        except Exception as ex:
1245
            message = 'error occurred({}) in {}:{}'.format(ex, sys.exc_info()[-1].tb_frame.f_code.co_filename,
1246
                                                           sys.exc_info()[-1].tb_lineno)
1247
            self.addMessage.emit(MessageType.Error, message)
1248

    
1249
    def on_import_text_from_cad_for_instrument(self):
1250
        """ import text from cad for instrument """
1251
        try:
1252
            self.onCommandRejected()
1253
            dialog = QImportTextFromPDFDialog(self)
1254
            dialog.show()
1255
            dialog.exec_()
1256
        except Exception as ex:
1257
            message = f"error occurred({repr(ex)}) in {sys.exc_info()[-1].tb_frame.f_code.co_filename}:" \
1258
                      f"{sys.exc_info()[-1].tb_lineno}"
1259
            self.addMessage.emit(MessageType.Error, message)
1260

    
1261
    def on_import_text_from_cad(self):
1262
        """ import text from cad """
1263
        try:
1264
            self.onCommandRejected()
1265
            dialog = QImportTextFromCADDialog(self)
1266
            dialog.show()
1267
            dialog.exec_()
1268
        except Exception as ex:
1269
            message = f"error occurred({repr(ex)}) in {sys.exc_info()[-1].tb_frame.f_code.co_filename}:" \
1270
                      f"{sys.exc_info()[-1].tb_lineno}"
1271
            self.addMessage.emit(MessageType.Error, message)
1272

    
1273
    def on_export_PDF(self):
1274
        if not self.graphicsView.hasImage():
1275
            self.showImageSelectionMessageBox()
1276
            return
1277

    
1278
        try:
1279
            printer = QPrinter(QPrinter.HighResolution)
1280
            #printer.setPageSize(QPrinter.A4)
1281
            printer.setOrientation(QPrinter.Orientation.Landscape)
1282
            dialog = QPrintDialog(printer)
1283
            if (dialog.exec() == QDialog.Accepted):
1284
                painter = QPainter(printer)
1285
                isfull_print = False
1286

    
1287
                scene = self.graphicsView.scene()
1288

    
1289
                #for item in scene.items():
1290
                #    if not hasattr(item, 'connectors'): continue
1291
                #    for connector in item.connectors: connector.setVisible(False)
1292

    
1293
                canvasRect = scene.sceneRect() # or canvasRect = scene.border.boundingRect()
1294
                source = canvasRect
1295
                page = printer.pageRect(QPrinter.Unit.DevicePixel)
1296
                target = QRectF(QPointF(0, 0), QSizeF(page.width(), page.height()))
1297
                scene.render(painter, target, source)
1298
                painter.end()
1299

    
1300
                QMessageBox.about(self, self.tr("Information"), self.tr('Successfully saved.'))
1301
                #for item in scene.items():
1302
                #    if not hasattr(item, 'connectors'): continue
1303
                #    for connector in item.connectors: connector.setVisible(True)
1304

    
1305
        except Exception as ex:
1306
            message = 'error occurred({}) in {}:{}'.format(ex, sys.exc_info()[-1].tb_frame.f_code.co_filename,
1307
                                                           sys.exc_info()[-1].tb_lineno)
1308
            self.addMessage.emit(MessageType.Error, message)
1309

    
1310
    def onSymbolThickness(self):
1311
        """ symbol thickness reinforcement by using configuration filter drawing dilate size """
1312
        try:
1313
            self.onCommandRejected()
1314
            dialog = QSymbolThicknessDialog(self)
1315
            dialog.exec_()
1316
        except Exception as ex:
1317
            message = 'error occurred({}) in {}:{}'.format(ex, sys.exc_info()[-1].tb_frame.f_code.co_filename,
1318
                                                           sys.exc_info()[-1].tb_lineno)
1319
            self.addMessage.emit(MessageType.Error, message)
1320

    
1321
    def on_help(self):
1322
        """ open help file """
1323
        import os
1324

    
1325
        try:
1326
            help_file_path = os.path.join(os.path.dirname(os.path.realpath(__file__)), 'ID2 User Manual.pdf')
1327
            if os.path.exists(help_file_path):
1328
                os.startfile(f"\"{help_file_path}\"")
1329
            else:
1330
                QMessageBox.warning(self, self.tr('Warning'), self.tr('There is no help file'))
1331
        except Exception as ex:
1332
            message = f"error occurred({repr(ex)}) in {sys.exc_info()[-1].tb_frame.f_code.co_filename}:" \
1333
                      f"{sys.exc_info()[-1].tb_lineno}"
1334
            self.addMessage.emit(MessageType.Error, message)
1335

    
1336
    def on_readme(self):
1337
        """open readme.html"""
1338

    
1339
        file_path = os.path.join(os.path.dirname(os.path.realpath(__file__)), 'readme.html')
1340
        if os.path.exists(file_path):
1341
            os.startfile(f"\"{file_path}\"")
1342
        else:
1343
            QMessageBox.warning(self, self.tr('Warning'), self.tr('There is no readme file'))
1344

    
1345
    def onSelectionChanged(self):
1346
        """selection changed"""
1347
        items = [item for item in self.graphicsView.scene().selectedItems() if issubclass(type(item), SymbolSvgItem) or
1348
                 type(item) is QEngineeringLineItem or issubclass(type(item), QEngineeringTextItem) or
1349
                 type(item) is QEngineeringUnknownItem or type(item) is QEngineeringVendorItem]
1350
        if items:
1351
            lineNos = [item for item in items if type(item) is QEngineeringLineNoTextItem]
1352
            item = items[-1] if not lineNos else lineNos[0]
1353
            self.itemTreeWidget.findItem(item)
1354
            self.resultPropertyTableWidget.show_item_property(item)
1355
            if type(item) is QEngineeringErrorItem:
1356
                for index in range(self.tableWidgetInconsistency.rowCount()):
1357
                    if self.tableWidgetInconsistency.item(index, 1).tag is item:
1358
                        self.tableWidgetInconsistency.selectRow(index)
1359
                        break
1360
            if issubclass(type(item), SymbolSvgItem):
1361
                pass
1362
                #self.symbolTreeWidget.select_symbol(item)
1363
        else:
1364
            self.resultPropertyTableWidget.show_item_property(None)
1365

    
1366
    '''
1367
        @brief      Initialize scene and itemTreeWidget
1368
        @author     Jeongwoo
1369
        @date       2018.06.14
1370
        @history    humkyung 2018.08.16 ask to delete recognized items before remove
1371
    '''
1372
    def on_initialize_scene(self, action):
1373
        if not self.graphicsView.hasImage():
1374
            self.showImageSelectionMessageBox()
1375

    
1376
            return
1377

    
1378
        try:
1379
            msg = QMessageBox()
1380
            msg.setIcon(QMessageBox.Critical)
1381
            msg.setText(self.tr('Do you want to remove all items?\nThis work cannot be recovered.'))
1382
            msg.setWindowTitle(self.tr("Initialize"))
1383
            msg.setStandardButtons(QMessageBox.Ok | QMessageBox.Cancel)
1384
            if QMessageBox.Ok == msg.exec_():
1385
                app_doc_data = AppDocData.instance()
1386
                app_doc_data.clearItemList(True)
1387

    
1388
                scene = self.graphicsView.scene()
1389
                pixmap = self.graphicsView.getPixmapHandle()
1390
                scene.removeItem(pixmap)    # disconnect pixmap from scene
1391
                scene.clear()               # remove all items from scene and then delete them
1392
                scene.addItem(pixmap)       # add pixmap
1393

    
1394
                if self.path is not None:
1395
                    baseName = os.path.basename(self.path)
1396
                    self.itemTreeWidget.setCurrentPID(baseName)
1397

    
1398
        except Exception as ex:
1399
            message = 'error occurred({}) in {}:{}'.format(ex, sys.exc_info()[-1].tb_frame.f_code.co_filename,
1400
                                                           sys.exc_info()[-1].tb_lineno)
1401
            self.addMessage.emit(MessageType.Error, message)
1402

    
1403
    def checked_action(self):
1404
        """return checked action"""
1405
        home_file_pane = self.ribbon.get_pane('Home File')
1406
        home_pane = self.ribbon.get_pane('Home')
1407
        visualization_pane = self.ribbon.get_pane('Home Visualization')
1408
        actions = [home_pane.ui.toolButtonRecognition, home_pane.ui.toolButtonLinkAttribute,
1409
                   home_pane.ui.toolButtonLine, home_pane.ui.toolButtonOCR, visualization_pane.ui.toolButtonZoom,
1410
                   visualization_pane.ui.toolButtonFitWindow, home_pane.ui.toolButtonVendor]
1411

    
1412
        checked = [ui_ for ui_ in actions if ui_.isChecked()]
1413
        return checked[0] if checked else None
1414

    
1415
    def update_action_group(self, ui):
1416
        """Manage Checkable Action statement"""
1417
        home_file_pane = self.ribbon.get_pane('Home File')
1418
        home_pane = self.ribbon.get_pane('Home')
1419
        visualization_pane = self.ribbon.get_pane('Home Visualization')
1420
        actions = [home_pane.ui.toolButtonRecognition, home_pane.ui.toolButtonLinkAttribute, home_pane.ui.toolButtonLine,
1421
                   home_pane.ui.toolButtonOCR, visualization_pane.ui.toolButtonZoom,
1422
                   visualization_pane.ui.toolButtonFitWindow, home_file_pane.ui.toolButtonFileSave,
1423
                   home_pane.ui.toolButtonValidate, home_pane.ui.toolButtonVendor]
1424

    
1425
        if hasattr(ui, 'tag'):
1426
            ui.tag.onRejected.emit(None)
1427

    
1428
        if self.graphicsView.command is not None:
1429
            self.graphicsView.useDefaultCommand()
1430

    
1431
        for ui_ in actions:
1432
            ui_.setChecked(False)
1433

    
1434
        ui.setChecked(True)
1435

    
1436
    '''
1437
        @brief      Create Equipment
1438
        @author     Jeongwoo
1439
        @date       18.05.03
1440
        @history    2018.05.04  Jeongwoo    Add Parameter on CreateSymbolCommand
1441
    '''
1442
    def createEquipment(self):
1443
        if not self.graphicsView.hasImage():
1444
            self.actionEquipment.setChecked(False)
1445
            self.showImageSelectionMessageBox()
1446
            return
1447
        if self.actionEquipment.isChecked():
1448
            self.graphicsView.command = CreateSymbolCommand.CreateSymbolCommand(self.graphicsView, self.itemTreeWidget,
1449
                                                                                self.symbolTreeWidget)
1450
        else:
1451
            self.graphicsView.useDefaultCommand()
1452

    
1453
    '''
1454
        @brief      Create Nozzle
1455
        @author     Jeongwoo
1456
        @date       2018.05.03
1457
        @history    2018.05.04  Jeongwoo    Add Parameter on CreateSymbolCommand
1458
    '''
1459
    def createNozzle(self):
1460
        if not self.graphicsView.hasImage():
1461
            self.actionNozzle.setChecked(False)
1462
            self.showImageSelectionMessageBox()
1463
            return
1464
        if self.actionNozzle.isChecked():
1465
            self.graphicsView.command = CreateSymbolCommand.CreateSymbolCommand(self.graphicsView, self.itemTreeWidget,
1466
                                                                                self.symbolTreeWidget)
1467
        else:
1468
            self.graphicsView.useDefaultCommand()
1469

    
1470
    def onAreaOcr(self):
1471
        """Area OCR"""
1472
        if not self.graphicsView.hasImage():
1473
            self.actionOCR.setChecked(False)
1474
            self.showImageSelectionMessageBox()
1475
            return
1476

    
1477
        pane = self.ribbon.get_pane('Home')
1478
        ui = pane.ui.toolButtonOCR
1479
        self.update_action_group(ui=ui)
1480
        checked = ui.isChecked()
1481
        if checked:
1482
            cmd = AreaOcrCommand.AreaOcrCommand(self.graphicsView)
1483
            cmd.onSuccess.connect(self.onRecognizeText)
1484
            cmd.onRejected.connect(self.onCommandRejected)
1485
            self.graphicsView.command = cmd
1486
        else:
1487
            self.graphicsView.useDefaultCommand()
1488

    
1489
    def onRecognizeText(self, x, y, width, height, show=True):
1490
        """show text recognition dialog"""
1491
        from OcrResultDialog import QOcrResultDialog
1492
        from Area import Area
1493

    
1494
        try:
1495
            app_doc_data = AppDocData.instance()
1496

    
1497
            modifiers = QApplication.keyboardModifiers()
1498
            image = self.graphicsView.image().copy(x, y, width, height)
1499
            dialog = QOcrResultDialog(self, image, QRectF(x, y, width, height),
1500
                                      format=QOcrResultDialog.Format.Table if modifiers == Qt.AltModifier else QOcrResultDialog.Format.Normal)
1501
            if modifiers == Qt.ControlModifier:
1502
                return
1503
            
1504
            if show:
1505
                (res, textInfoList) = dialog.showDialog()
1506
            else:
1507
                dialog.accept(show=False)
1508
                (res, textInfoList) = QDialog.Accepted, dialog.textInfoList
1509

    
1510
            if QDialog.Accepted == res and textInfoList:
1511
                for textInfo in textInfoList:
1512
                    item = QEngineeringTextItem.create_text_with(self.graphicsView.scene(), textInfo)
1513
                    if item:
1514
                        item.setDefaultTextColor(Qt.blue)
1515
                        item.transfer.onRemoved.connect(self.itemRemoved)
1516

    
1517
                        area_list = app_doc_data.getAreaList()
1518
                        title_area_list = app_doc_data.getTitleBlockProperties()
1519
                        title_list = []
1520
                        if title_area_list:
1521
                            for title_area in title_area_list:
1522
                                area = Area(title_area[0])
1523
                                area.parse(title_area[2])
1524
                                title_list.append(area)
1525
                        for area in area_list + title_list:
1526
                            pt = [item.sceneBoundingRect().center().x(), item.sceneBoundingRect().center().y()]
1527
                            if area.contains(pt):
1528
                                item.area = area.name
1529
                                break
1530
                    else:
1531
                        self.addMessage.emit(MessageType.Normal, self.tr('Fail to create text.'))
1532

    
1533
                return True
1534
            elif QDialog.Accepted == res and not textInfoList and show:
1535
                QMessageBox.about(self.graphicsView, self.tr("Notice"), self.tr("Fail to recognize text"))
1536
        except Exception as ex:
1537
            message = 'error occurred({}) in {}:{}'.format(ex, sys.exc_info()[-1].tb_frame.f_code.co_filename,
1538
                                                           sys.exc_info()[-1].tb_lineno)
1539
            self.addMessage.emit(MessageType.Error, message)
1540
        
1541
        return False
1542

    
1543
    '''
1544
        @brief  area configuration
1545
    '''
1546
    def areaConfiguration(self):
1547
        from ConfigurationAreaDialog import QConfigurationAreaDialog
1548
        if not self.graphicsView.hasImage():
1549
            self.showImageSelectionMessageBox()
1550
            return
1551
        self.onCommandRejected()
1552
        dlgConfigurationArea = QConfigurationAreaDialog(self)
1553
        dlgConfigurationArea.show()
1554
        dlgConfigurationArea.exec_()
1555

    
1556
    '''
1557
        @brief  configuration
1558
    '''
1559
    def configuration(self):
1560
        from ConfigurationDialog import QConfigurationDialog
1561

    
1562
        dlgConfiguration = QConfigurationDialog(self)
1563
        if QDialog.Accepted == dlgConfiguration.exec_():
1564
            QEngineeringLineItem.LINE_TYPE_COLORS.clear()
1565
            QEngineeringInstrumentItem.INST_COLOR = None
1566

    
1567
    '''
1568
        @brief  show special item types dialog 
1569
        @author humkyung
1570
        @date   2019.08.10
1571
    '''
1572
    def on_show_special_item_types(self):
1573
        from SpecialItemTypesDialog import QSpecialItemTypesDialog
1574

    
1575
        dlg = QSpecialItemTypesDialog(self)
1576
        dlg.exec_()
1577

    
1578
    def on_show_data_transfer(self):
1579
        """ show data transfer dialog """
1580
        from DataTransferDialog import QDataTransferDialog
1581

    
1582
        dlg = QDataTransferDialog(self)
1583
        dlg.exec_()
1584

    
1585
    def on_show_data_export(self):
1586
        """ show data export dialog """
1587
        from DataExportDialog import QDataExportDialog
1588

    
1589
        dlg = QDataExportDialog(self)
1590
        dlg.exec_()
1591

    
1592
    def on_show_eqp_datasheet_export(self):
1593
        """ show eqp datasheet export dialog """
1594
        from EqpDatasheetExportDialog import QEqpDatasheetExportDialog
1595

    
1596
        dlg = QEqpDatasheetExportDialog(self)
1597
        dlg.exec_()
1598

    
1599
    def on_show_opc_relation(self):
1600
        """ show opc relation dialog """
1601
        from OPCRelationDialog import QOPCRelationDialog
1602

    
1603
        dlg = QOPCRelationDialog(self)
1604
        dlg.exec_()
1605

    
1606
    '''
1607
        @brief  show nominal diameter dialog 
1608
        @author humkyung
1609
        @date   2018.06.28
1610
    '''
1611
    def onShowCodeTable(self):
1612
        from CodeTableDialog import QCodeTableDialog
1613

    
1614
        dlg = QCodeTableDialog(self)
1615
        dlg.show()
1616
        dlg.exec_()
1617
        if dlg.code_area:
1618
            if dlg.code_area.scene():
1619
                self.graphicsView.scene().removeItem(dlg.code_area)
1620
        if dlg.desc_area:
1621
            if dlg.desc_area.scene():
1622
                self.graphicsView.scene().removeItem(dlg.desc_area)
1623
        self.graphicsView.useDefaultCommand()
1624

    
1625
    def on_ext_app_connection(self):
1626
        from TcpServer import TcpServer
1627

    
1628
        app_doc_data = AppDocData.instance()
1629

    
1630
        tool_pane = self.ribbon.get_pane('Tool')
1631
        if tool_pane.ui.toolButtonConnection.isChecked():
1632
            if not hasattr(self, '_tcpserver'):
1633
                configs = app_doc_data.getAppConfigs('app', 'port')
1634
                port = 2549
1635
                if configs and 1 == len(configs):
1636
                    port = int(configs[0].value)
1637
                self._tcpserver = TcpServer(port)
1638
                self._tcpserver.sessionOpened()
1639
        else:
1640
            self._tcpserver.sessionClosed()
1641
            del self._tcpserver
1642

    
1643
    def on_execute_ext_app(self):
1644
        """execute external application"""
1645
        from ExtAppsDialog import QExtAppsDialog
1646

    
1647
        dlg = QExtAppsDialog(self)
1648
        dlg.exec_()
1649

    
1650
    def onShowCustomCodeTable(self):
1651
        from CustomCodeTablesDialog import CustomCodeTablesDialog
1652

    
1653
        dlg = CustomCodeTablesDialog(self)
1654
        dlg.show()
1655
        dlg.exec_()
1656
        self.graphicsView.useDefaultCommand()
1657

    
1658
    def onShowReplaceCodeTable(self):
1659
        from CustomCodeTablesDialog import CustomCodeTablesDialog
1660

    
1661
        dlg = CustomCodeTablesDialog(self, replace=True)
1662
        dlg.show()
1663
        dlg.exec_()
1664
        self.graphicsView.useDefaultCommand()
1665

    
1666
    def on_streamline(self):
1667
        """pop up stream line dialog"""
1668
        from StreamlineDialog import QStreamlineDialog
1669

    
1670
        if not self.graphicsView.hasImage():
1671
            self.showImageSelectionMessageBox()
1672
            return
1673

    
1674
        hmbs = AppDocData.instance().get_hmb_data(None)
1675
        if not hmbs:
1676
            return
1677

    
1678
        dlg = QStreamlineDialog(self)
1679
        dlg.show()
1680

    
1681
    def onHMBData(self):
1682
        """show HMB data"""
1683
        from HMBDialog import QHMBDialog
1684

    
1685
        dlg = QHMBDialog(self)
1686
        dlg.show()
1687
        dlg.exec_()
1688

    
1689
    '''
1690
        @brief  show line data list 
1691
        @author humkyung
1692
        @date   2018.05.03
1693
    '''
1694
    def showItemDataList(self):
1695
        from ItemDataExportDialog import QItemDataExportDialog
1696

    
1697
        dlg = QItemDataExportDialog(self)
1698
        dlg.exec_()
1699

    
1700
    def showTextDataList(self):
1701
        '''
1702
            @brief      show all text item in scene
1703
            @author     euisung
1704
            @date       2019.04.18
1705
        '''
1706
        try:
1707
            if not self.graphicsView.hasImage():
1708
                self.showImageSelectionMessageBox()
1709
                return
1710

    
1711
            self.onCommandRejected()
1712
            dialog = QTextDataListDialog(self)
1713
            dialog.show()
1714
        except Exception as ex:
1715
            message = 'error occurred({}) in {}:{}'.format(ex, sys.exc_info()[-1].tb_frame.f_code.co_filename,
1716
                                                           sys.exc_info()[-1].tb_lineno)
1717
            self.addMessage.emit(MessageType.Error, message)
1718

    
1719
    '''
1720
        @brief  Show Image Selection Guide MessageBox
1721
        @author Jeongwoo
1722
        @date   2018.05.02
1723
    '''
1724
    def showImageSelectionMessageBox(self):
1725
        QMessageBox.about(self.graphicsView, self.tr("Notice"), self.tr("First select image drawing"))
1726

    
1727
    def on_search_text_changed(self):
1728
        """filter symbol tree view"""
1729
        regexp = QRegExp(self.lineEditFilter.text(), Qt.CaseInsensitive, QRegExp.FixedString)
1730

    
1731
        proxy_model = self.symbolTreeWidget.model()
1732
        proxy_model.text = self.lineEditFilter.text().lower()
1733
        proxy_model.setFilterRegExp(regexp)
1734

    
1735
        self.symbolTreeWidget.expandAll()
1736

    
1737
    def change_display_colors(self):
1738
        """ change display color mode """
1739
        visualization_pane = self.ribbon.get_pane('Home Visualization')
1740
        if visualization_pane.ui.radioButtonByGroup.isChecked():
1741
            visualization_pane.ui.radioButtonByType.setChecked(True)
1742
        else:
1743
            visualization_pane.ui.radioButtonByGroup.setChecked(True)
1744

    
1745
    def display_colors(self, value):
1746
        """ display colors """
1747
        from DisplayColors import DisplayColors
1748
        from DisplayColors import DisplayOptions
1749

    
1750
        if hasattr(self, 'ribbon'):
1751
            visualization_pane = self.ribbon.get_pane('Home Visualization')
1752
            if self.sender() is visualization_pane.ui.radioButtonByGroup and value is True:
1753
                DisplayColors.instance().option = DisplayOptions.DisplayByLineNo
1754
            elif self.sender() is visualization_pane.ui.radioButtonByType and value is True:
1755
                DisplayColors.instance().option = DisplayOptions.DisplayByLineType
1756
            elif self.sender() is visualization_pane.ui.radioButtonByStreamNo and value is True:
1757
                DisplayColors.instance().option = DisplayOptions.DisplayByStreamNo
1758

    
1759
            if hasattr(self, 'graphicsView') and value is True:
1760
                self.graphicsView.scene().update(self.graphicsView.sceneRect())
1761
                for item in self.graphicsView.scene().items():
1762
                    if issubclass(type(item), SymbolSvgItem):
1763
                        item.update()
1764
                DisplayColors.instance().save_data()
1765

    
1766
    def open_image_drawing(self, drawing, force=False, ocrUnknown=False):
1767
        """open and display image drawing file"""
1768
        from Drawing import Drawing
1769
        from App import App
1770
        from LoadCommand import LoadCommand
1771
        import concurrent.futures as futures
1772

    
1773
        # Yield successive n-sized
1774
        # chunks from l.
1775
        def divide_chunks(l, n):
1776
            # looping till length l
1777
            for i in range(0, len(l), n):
1778
                yield l[i:i + n]
1779

    
1780
        def update_items(items):
1781
            for item in items:
1782
                # binding items
1783
                item.owner
1784
                for connector in item.connectors:
1785
                    connector.connectedItem
1786

    
1787
            return items
1788

    
1789
        try:
1790
            app_doc_data = AppDocData.instance()
1791

    
1792
            if not self.actionSave.isEnabled():
1793
                return
1794

    
1795
            if not force and self.save_drawing_if_necessary():
1796
                return
1797

    
1798
            occupied = app_doc_data.set_occupying_drawing(drawing.UID)
1799
            if occupied:
1800
                QMessageBox.about(self.graphicsView, self.tr("Notice"),
1801
                                  self.tr(f"The drawing is locked for editing by another user({occupied})"))
1802
                return
1803

    
1804
            # save alarm
1805
            self.save_alarm_enable(False)
1806

    
1807
            if hasattr(self, '_save_work_cmd'):
1808
                self._save_work_cmd.wait()
1809

    
1810
            project = app_doc_data.getCurrentProject()
1811

    
1812
            self.path = self.graphicsView.loadImageFromFile(drawing)
1813
            if os.path.isfile(self.path):
1814
                self.onCommandRejected()
1815
                app_doc_data.clear(past=drawing.UID)
1816

    
1817
                # load color for stream no coloring
1818
                configs = app_doc_data.getConfigs('Line List', 'Use Stream No')
1819
                if configs and int(configs[0].value) == 1:
1820
                    hmbs = app_doc_data.get_hmb_data(None)
1821
                    colors = {}
1822
                    if hmbs:
1823
                        for hmb in hmbs:
1824
                            rgb = app_doc_data.colors
1825
                            colors[hmb.stream_no] = QColor(rgb.red, rgb.green, rgb.blue).name()
1826
                        app_doc_data._hmbColors = colors
1827
                # up to here
1828

    
1829
                app_doc_data.setImgFilePath(self.path)
1830
                app_doc_data.activeDrawing = drawing
1831
                
1832
                #app_doc_data.activeDrawing.set_pid_source(Image.open(self.path))
1833
                self.itemTreeWidget.setCurrentPID(app_doc_data.activeDrawing.name)
1834

    
1835
                drawingList = self.treeWidgetDrawingList.topLevelItem(0)
1836
                for idx in range(drawingList.childCount()):
1837
                    child = drawingList.child(idx)
1838
                    if child.data(Qt.UserRole, 0) is drawing:
1839
                        child.setCheckState(0, Qt.Checked)
1840
                    else:
1841
                        child.setCheckState(0, Qt.Unchecked)
1842

    
1843
                try:
1844
                    self.show_Progress_bar()
1845

    
1846
                    # disconnect scene changed if signal is connected
1847
                    if self.graphicsView.scene().receivers(self.graphicsView.scene().contents_changed) > 0:
1848
                        self.graphicsView.scene().contents_changed.disconnect()
1849

    
1850
                    SymbolSvgItem.DOCUMENTS.clear()
1851

    
1852
                    # load data
1853
                    cmd = LoadCommand()
1854
                    cmd.display_message.connect(self.onAddMessage)
1855
                    cmd.set_maximum.connect(self.progress.setMaximum)
1856
                    cmd.show_progress.connect(self.progress.setValue)
1857
                    cmd.execute((drawing, self.graphicsView.scene()),
1858
                                symbol=True, text=True, line=True, unknown=True, package=True, update=True)
1859

    
1860
                    configs = app_doc_data.getConfigs('Line List', 'Use Stream No')
1861
                    if configs and int(configs[0].value) == 1:
1862
                        app_doc_data._streamLineListModelDatas = app_doc_data.get_stream_line_list_data()
1863
                    # up to here
1864

    
1865
                    """update item tree widget"""
1866
                    line_no_items = [item for item in self.graphicsView.scene().items()
1867
                                     if type(item) is QEngineeringLineNoTextItem]
1868
                    for line_no in line_no_items:
1869
                        line_no_tree_item = self.itemTreeWidget.addTreeItem(self.itemTreeWidget.root, line_no)
1870
                        for run in line_no.runs:
1871
                            for run_item in run.items:
1872
                                if issubclass(type(run_item), SymbolSvgItem):
1873
                                    self.init_add_tree_item(line_no_tree_item, run_item)
1874

    
1875
                    line_no_items = [item for item in self.graphicsView.scene().items()
1876
                                     if type(item) is QEngineeringTrimLineNoTextItem]
1877
                    for line_no in line_no_items:
1878
                        line_no_tree_item = self.itemTreeWidget.addTreeItem(self.itemTreeWidget.root, line_no)
1879
                        for run in line_no.runs:
1880
                            for run_item in run.items:
1881
                                if issubclass(type(run_item), SymbolSvgItem):
1882
                                    self.init_add_tree_item(line_no_tree_item, run_item)
1883

    
1884
                    for trim_line_no in app_doc_data.tracerLineNos:
1885
                        line_no_tree_item = self.itemTreeWidget.addTreeItem(self.itemTreeWidget.root, trim_line_no)
1886
                        for run in trim_line_no.runs:
1887
                            for run_item in run.items:
1888
                                if issubclass(type(run_item), SymbolSvgItem):
1889
                                    self.init_add_tree_item(line_no_tree_item, run_item)
1890

    
1891
                    self.itemTreeWidget.update_item_count()
1892
                    self.itemTreeWidget.expandAll()
1893
                    """up to here"""
1894

    
1895
                    """update scene"""
1896
                    for item in self._scene.items():
1897
                        item.setVisible(True)
1898

    
1899
                    self._scene.update(self._scene.sceneRect())
1900

    
1901
                    """
1902
                    # old open drawing
1903
                    path = os.path.join(app_doc_data.getCurrentProject().getTempPath(), app_doc_data.imgName + '.xml')
1904
                    configs = app_doc_data.getConfigs('Data Load', 'Xml First')
1905
                    if configs and int(configs[0].value) >= 1 and os.path.isfile(path):
1906
                        self.load_recognition_result_from_xml(drawing)
1907
                    elif configs and int(configs[0].value) <= 1:
1908
                        self.load_drawing(app_doc_data.activeDrawing)
1909
                    """
1910

    
1911
                    self.display_number_of_items()
1912
                    # connect scene changed signal
1913
                    self.graphicsView.scene().contents_changed.connect(self.scene_changed)
1914
                finally:
1915
                    if hasattr(self, 'progress'):
1916
                        self.progress.setValue(self.progress.maximum())
1917

    
1918
                self.changeViewCheckedState(True)
1919
                self.setWindowTitle(self.title)
1920
                self.fitWindow(drawing.view_rect)
1921

    
1922
                if ocrUnknown:
1923
                    self.on_ocr_unknown_items()
1924

    
1925
                # save alarm
1926
                self.save_alarm_enable(True, True)
1927
        except Exception as ex:
1928
            message = f"error occurred({repr(ex)}) in {sys.exc_info()[-1].tb_frame.f_code.co_filename}:" \
1929
                      f"{sys.exc_info()[-1].tb_lineno}"
1930
            self.addMessage.emit(MessageType.Error, message)
1931

    
1932
        return self.path
1933

    
1934
    def save_alarm_enable(self, enable, init=False):
1935
        from datetime import datetime
1936

    
1937
        try:
1938
            app_doc_data = AppDocData.instance()
1939
            configs = app_doc_data.getConfigs('Data Save', 'Time')
1940
            time_min = int(configs[0].value) if 1 == len(configs) else 0
1941

    
1942
            if enable and time_min > 0:
1943
                if not self.save_timer:
1944
                    self.save_timer = QTimer()
1945
                    self.save_timer.timeout.connect(self.save_alarm)
1946
                    self.save_timer.setInterval(60000)
1947

    
1948
                if init:
1949
                    self.save_timer._init_time = datetime.now()
1950
                    self.save_timer._stop_time = None
1951
                    self.save_timer._interval_time = datetime.now() - datetime.now()
1952

    
1953
                if self.save_timer._stop_time:
1954
                    self.save_timer._interval_time = datetime.now() - self.save_timer._stop_time
1955
                
1956
                #if 60000 * time_min != self.save_timer.interval():
1957
                #    self.save_timer.setInterval(60000)
1958

    
1959
                self.save_timer.start()
1960
            else:
1961
                if self.save_timer:
1962
                    self.save_timer.stop()
1963
                    self.save_timer._stop_time = datetime.now()
1964
        
1965
        except Exception as ex:
1966
            message = f"error occurred({repr(ex)}) in {sys.exc_info()[-1].tb_frame.f_code.co_filename}:" \
1967
                      f"{sys.exc_info()[-1].tb_lineno}"
1968
            self.addMessage.emit(MessageType.Error, message)
1969

    
1970
    def save_alarm(self):
1971
        from datetime import datetime
1972

    
1973
        app_doc_data = AppDocData.instance()
1974
        configs = app_doc_data.getConfigs('Data Save', 'Time')
1975
        time_min = int(configs[0].value) if 1 == len(configs) else 0
1976

    
1977
        self.save_timer.stop()
1978
        if self.graphicsView.hasFocus() and (datetime.now() - self.save_timer._init_time - self.save_timer._interval_time).seconds > time_min * 60:
1979
            QMessageBox.information(self, self.tr('Information'), self.tr('Please save Drawing'))
1980
            self.save_timer._init_time = datetime.now()
1981
            self.save_timer._interval_time = datetime.now() - datetime.now()
1982
        self.save_timer.start()
1983

    
1984
    def export_as_svg(self):
1985
        """export scene to svg file"""
1986
        from ExportCommand import ExportCommand
1987

    
1988
        options = QFileDialog.Options()
1989
        options |= QFileDialog.DontUseNativeDialog
1990
        file_path, _ = QFileDialog.getSaveFileName(self, "Export as svg", os.getcwd(), "svg file(*.svg)",
1991
                                                   options=options)
1992
        if file_path:
1993
            cmd = ExportCommand(self.graphicsView.scene(), 'svg')
1994
            cmd.display_message.connect(self.onAddMessage)
1995
            if cmd.execute(file_path):
1996
                QMessageBox.information(self, self.tr('Information'), self.tr('Successfully export to svg file'))
1997
            else:
1998
                QMessageBox.information(self, self.tr('Error'), self.tr('Fail to export to svg file'))
1999

    
2000
    def export_as_xml(self):
2001
        pass
2002

    
2003
    def export_as_image(self):
2004
        """export scene to image file"""
2005
        from ExportCommand import ExportCommand
2006

    
2007
        options = QFileDialog.Options()
2008
        options |= QFileDialog.DontUseNativeDialog
2009
        file_path, _ = QFileDialog.getSaveFileName(self, "Export as png", os.getcwd(), "png file(*.png)",
2010
                                                   options=options)
2011
        if file_path:
2012
            try:
2013
                # hide image drawing
2014
                self.onViewImageDrawing(False)
2015

    
2016
                cmd = ExportCommand(self.graphicsView.scene(), 'image')
2017
                cmd.display_message.connect(self.onAddMessage)
2018

    
2019
                if cmd.execute(file_path):
2020
                    QMessageBox.information(self, self.tr('Information'), self.tr('Successfully export to image file'))
2021
                else:
2022
                    QMessageBox.information(self, self.tr('Error'), self.tr('Fail to export to image file'))
2023
            finally:
2024
                if self.actionImage_Drawing.isChecked():
2025
                    self.onViewImageDrawing(True)
2026
                    self.actionImage_Drawing.setChecked(True)
2027

    
2028
    def show_Progress_bar(self):
2029
        """ show progress bar """
2030
        self.progress = QProgressDialog(self.tr("Please wait for a while"), self.tr("Cancel"), 0, 100,
2031
                                        self) if not hasattr(self, 'progress') else self.progress
2032
        self.progress.setWindowModality(Qt.WindowModal)
2033
        self.progress.setAutoReset(True)
2034
        self.progress.setAutoClose(True)
2035
        self.progress.setMinimum(0)
2036
        self.progress.setMaximum(100)
2037
        self.progress.resize(600, 100)
2038
        self.progress.setWindowTitle(self.tr("Reading file..."))
2039
        self.progress.show()
2040

    
2041
    def changeViewCheckedState(self, checked, clear=True):
2042
        """change view checked state"""
2043
        # self.actionImage_Drawing.setChecked(checked)
2044
        self.actionViewText.setChecked(checked)
2045
        self.actionViewSymbol.setChecked(checked)
2046
        self.actionViewLine.setChecked(checked)
2047
        self.actionViewUnknown.setChecked(checked)
2048
        self.actionViewInconsistency.setChecked(checked)
2049
        self.actionViewVendor_Area.setChecked(not checked)
2050
        self.actionDrawing_Only.setChecked(not checked)
2051
        if clear:
2052
            self.tableWidgetInconsistency.clearContents()
2053
            self.tableWidgetInconsistency.setRowCount(0)
2054

    
2055
    def onViewDrawingOnly(self, isChecked):
2056
        '''
2057
            @brief  visible/invisible except image drawing
2058
            @author euisung
2059
            @date   2019.04.22
2060
        '''
2061
        self.changeViewCheckedState(not isChecked, False)
2062
        for item in self.graphicsView.scene().items():
2063
            if type(item) is not QGraphicsPixmapItem:
2064
                item.setVisible(not isChecked)
2065

    
2066
    '''
2067
        @brief  visible/invisible image drawing
2068
        @author humkyung
2069
        @date   2018.06.25
2070
    '''
2071
    def onViewImageDrawing(self, isChecked):
2072
        for item in self.graphicsView.scene().items():
2073
            if type(item) is QGraphicsPixmapItem:
2074
                item.setVisible(isChecked)
2075
                break
2076

    
2077
    def onViewText(self, checked):
2078
        """visible/invisible text"""
2079
        selected = [item for item in self.graphicsView.scene().items() if issubclass(type(item), QEngineeringTextItem)
2080
                    and type(item) is not QEngineeringLineNoTextItem]
2081
        for item in selected:
2082
            item.setVisible(checked)
2083

    
2084
    def onViewSymbol(self, checked):
2085
        """visible/invisible symbol"""
2086
        selected = [item for item in self.graphicsView.scene().items() if
2087
                    (issubclass(type(item), SymbolSvgItem) and type(item) is not QEngineeringErrorItem)]
2088
        for item in selected:
2089
            item.setVisible(checked)
2090

    
2091
    def onViewLine(self, checked):
2092
        """visible/invisible line"""
2093
        selected = [item for item in self.graphicsView.scene().items() if type(item) is QEngineeringLineItem]
2094
        for item in selected:
2095
            item.setVisible(checked)
2096

    
2097
    def onViewInconsistency(self, isChecked):
2098
        '''
2099
            @brief  visible/invisible Inconsistency
2100
            @author euisung
2101
            @date   2019.04.03
2102
        '''
2103
        selected = [item for item in self.graphicsView.scene().items() if type(item) is QEngineeringErrorItem]
2104
        for item in selected:
2105
            item.setVisible(isChecked)
2106

    
2107
    '''
2108
        @brief  visible/invisible Unknown 
2109
        @author humkyung
2110
        @date   2018.06.28
2111
    '''
2112
    def onViewUnknown(self, isChecked):
2113
        selected = [item for item in self.graphicsView.scene().items() if type(item) is QEngineeringUnknownItem]
2114
        for item in selected:
2115
            item.setVisible(isChecked)
2116

    
2117
    def onViewVendorArea(self, isChecked):
2118
        '''
2119
            @brief  visible/invisible Vendor Area
2120
            @author euisung
2121
            @date   2019.04.29
2122
        '''
2123
        selected = [item for item in self.graphicsView.scene().items() if issubclass(type(item), QEngineeringVendorItem)]
2124
        for item in selected:
2125
            item.setVisible(isChecked)
2126

    
2127
    '''
2128
        @brief  create a symbol
2129
        @history    2018.05.02  Jeongwoo    Change return value of QSymbolEditorDialog (Single variable → Tuple)
2130
                                            Add SymbolSvgItem
2131
                    2018.05.03  Jeongwoo    Change method to draw Svg Item on Scene (svg.addSvgItemToScene)
2132
                                            Change method to make svg and image path
2133
                    2018.06.08  Jeongwoo    Add Paramter on SymbolSvgItem.buildItem()
2134
    '''
2135
    def onCreateSymbolClicked(self):
2136
        selected = [item for item in self.graphicsView.scene().selectedItems() if issubclass(type(item), QEngineeringVendorItem)]
2137
        if len(selected) == 1:
2138
            symbol_image = AppDocData.instance().activeDrawing.image_origin
2139
            rect = selected[0].sceneBoundingRect()
2140

    
2141
            points = []
2142
            for conn in selected[0].connectors:
2143
                points.append([round(conn.center()[0] - rect.x()), round(conn.center()[1] - rect.y())])
2144
            poly = np.array(points, np.int32)
2145

    
2146
            #mask = np.zeros((int(rect.height()), int(rect.width())))
2147
            #cv2.fillPoly(mask, [poly], (255))
2148
            #poly_copied = np.multiply(mask, symbol_image[round(rect.y()):round(rect.y() + rect.height()),
2149
            #                   round(rect.x()):round(rect.x() + rect.width())])
2150
            #cv2.fillPoly(mask,[poly],0)
2151
            #src2 = np.multiply(mask,src2)
2152

    
2153
            mask = np.ones((int(rect.height()), int(rect.width())), dtype=np.uint8) * 255
2154
            cv2.fillPoly(mask, [poly], (0))
2155
            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())])
2156
            sym_img = cv2.merge((sym_img, sym_img, sym_img))
2157

    
2158
            h, w, c = sym_img.shape
2159
            qImg = QImage(sym_img.data, w, h, w * c, QImage.Format_RGB888)
2160
            #pixmap = QPixmap.fromImage(qImg)
2161

    
2162
            self.onAreaSelected(None, None, None, None, package=qImg, position=rect.topLeft(), package_item=selected[0])
2163
        else:
2164
            cmd = FenceCommand.FenceCommand(self.graphicsView)
2165
            cmd.onSuccess.connect(self.onAreaSelected)
2166
            self.graphicsView.command = cmd
2167
            QApplication.setOverrideCursor(Qt.CrossCursor)
2168

    
2169
    '''
2170
        @brief      show SymbolEditorDialog with image selected by user
2171
        @author     humkyung
2172
        @date       2018.07.20
2173
    '''
2174
    def onAreaSelected(self, x, y, width, height, package=False, position=None, package_item=None):
2175
        try:
2176
            image = self.graphicsView.image()
2177
            if image is not None:
2178
                if not package:
2179
                    symbolEditorDialog = SymbolEditorDialog.QSymbolEditorDialog(self, image.copy(x, y, width, height),
2180
                                                                                AppDocData.instance().getCurrentProject())
2181
                else:
2182
                    symbolEditorDialog = SymbolEditorDialog.QSymbolEditorDialog(self, package,
2183
                                                                                AppDocData.instance().getCurrentProject(), package=True)
2184
                (isAccepted, isImmediateInsert, offsetX, offsetY, newSym) = symbolEditorDialog.showDialog()
2185
                # TODO: not initialize symbol tree view when user reject to create a new symbol
2186
                self.symbolTreeWidget.initSymbolTreeView()
2187
                if isAccepted:
2188
                    if isImmediateInsert:
2189
                        svg = QtImageViewer.createSymbolObject(newSym.getName())
2190
                        offsetX, offsetY = [int(point) for point in newSym.getOriginalPoint().split(',')]
2191
                        QtImageViewer.matchSymbolToLine(self.graphicsView.scene(), svg, QPoint(position.x() + offsetX, position.y() + offsetY))
2192

    
2193
                        package_item.transfer.onRemoved.emit(package_item)
2194
        finally:
2195
            self.onCommandRejected()
2196
            QApplication.restoreOverrideCursor()
2197
            QApplication.restoreOverrideCursor()
2198

    
2199
    def on_line_list(self):
2200
        """ line list export dialog """
2201
        from LineListDialog import LineListDialog
2202

    
2203
        if not self.graphicsView.hasImage():
2204
            self.showImageSelectionMessageBox()
2205
            return
2206

    
2207
        dialog = LineListDialog(self)
2208
        dialog.showDialog()
2209

    
2210
    def on_make_label_data(self):
2211
        """ make label data from symbol info """
2212
        from xml.etree.ElementTree import Element, SubElement, dump, ElementTree, parse
2213

    
2214
        if not self.graphicsView.hasImage():
2215
            self.showImageSelectionMessageBox()
2216
            return
2217

    
2218
        app_doc_data = AppDocData.instance()
2219
        project = app_doc_data.getCurrentProject()
2220

    
2221
        smalls = []
2222
        bigs = []
2223

    
2224
        symbol_list = app_doc_data.getTargetSymbolList(all=True)
2225
        #symbol_list = app_doc_data.getTargetSymbolList(all=False)
2226
        for symbol in symbol_list:
2227
            if symbol.iType == 38 or symbol.iType == 33 or symbol.iType == 0 or symbol.iType == 40:
2228
                continue
2229
            elif symbol.width and symbol.height:
2230
                if symbol.width > 300 or symbol.height > 300:
2231
                    bigs.append(symbol.getName())
2232
                elif (symbol.width * symbol.height < 1500) or (symbol.width > 450 or symbol.height > 450):
2233
                    continue
2234
                else:
2235
                    smalls.append(symbol.getName())
2236

    
2237
        symbols = [item for item in self.graphicsView.scene().items() if issubclass(type(item), SymbolSvgItem)]
2238
        names = [smalls, bigs]
2239

    
2240
        img = app_doc_data.activeDrawing.image_origin
2241

    
2242
        small_size = 500
2243
        big_size = 850
2244

    
2245
        save_path = project.getTrainingSymbolFilePath()
2246

    
2247
        index = 0
2248
        for size in [small_size, big_size]:
2249
            offsets = [0, int(size / 2)]
2250

    
2251
            width, height = img.shape[1], img.shape[0]
2252
            width_count, height_count = width // size + 2, height // size + 2
2253
            b_width, b_height = width_count * size, height_count * size
2254
            b_img = np.zeros((b_height, b_width), np.uint8) + 255
2255
            b_img[:height, :width] = img[:, :]
2256

    
2257
            for offset in offsets:
2258
                for row in range(height_count):
2259
                    for col in range(width_count):
2260
                        x, y = col * size + offset, row * size + offset
2261
                        tile_rect = QRectF(x, y, size, size)
2262
                        tile_symbols = []
2263
                        for symbol in [symbol for symbol in symbols if symbol.name in names[index]]:
2264
                            if tile_rect.contains(symbol.sceneBoundingRect()):
2265
                                tile_symbols.append(symbol)
2266
                                symbols.remove(symbol)
2267

    
2268
                        if tile_symbols:
2269
                            training_uid = str(uuid.uuid4())
2270
                            training_image_path = os.path.join(save_path, training_uid + '.png')
2271
                            training_xml_path = os.path.join(save_path, training_uid + '.xml')
2272

    
2273
                            # save image
2274
                            #_img = b_img[round(tile_rect.top()):round(tile_rect.bottom()),
2275
                            #       round(tile_rect.left()):round(tile_rect.right())]
2276
                            #cv2.imwrite(training_image_path, _img)
2277
                            _img = self.graphicsView.image().copy(round(tile_rect.left()), round(tile_rect.top()), round(tile_rect.width()), round(tile_rect.height()))
2278
                            _img.save(training_image_path)
2279

    
2280
                            # save label
2281
                            xml = Element('annotation')
2282
                            SubElement(xml, 'folder').text = 'None'
2283
                            SubElement(xml, 'filename').text = os.path.basename(save_path)
2284

    
2285
                            pathNode = Element('path')
2286
                            pathNode.text = save_path.replace('/', '\\')
2287
                            xml.append(pathNode)
2288

    
2289
                            sourceNode = Element('source')
2290
                            databaseNode = Element('database')
2291
                            databaseNode.text = 'Unknown'
2292
                            sourceNode.append(databaseNode)
2293
                            xml.append(sourceNode)
2294

    
2295
                            sizeNode = Element('size')
2296
                            widthNode = Element('width')
2297
                            widthNode.text = str(int(tile_rect.width()))
2298
                            sizeNode.append(widthNode)
2299
                            heightNode = Element('height')
2300
                            heightNode.text = str(int(tile_rect.height()))
2301
                            sizeNode.append(heightNode)
2302
                            depthNode = Element('depth')
2303
                            depthNode.text = '3'
2304
                            sizeNode.append(depthNode)
2305
                            xml.append(sizeNode)
2306

    
2307
                            segmentedNode = Element('segmented')
2308
                            segmentedNode.text = '0'
2309
                            xml.append(segmentedNode)
2310

    
2311
                            labelContent = []
2312
                            counts = {}
2313
                            for item in tile_symbols:
2314
                                rect = item.sceneBoundingRect()
2315
                                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)
2316
                                #label = 'small' if index == 0 else 'big' # for single class test
2317
                                xMin = xMin if xMin > 0 else 0
2318
                                yMin = yMin if yMin > 0 else 0
2319
                                xMax = xMax if xMax < size else size
2320
                                yMax = yMax if yMax < size else size
2321

    
2322
                                if label == 'None' or label == '':
2323
                                    continue
2324
                                if label not in labelContent:
2325
                                    labelContent.append(label)
2326
                                    counts[label] = 1
2327
                                else:
2328
                                    counts[label] = counts[label] + 1
2329

    
2330
                                objectNode = Element('object')
2331
                                nameNode = Element('name')
2332
                                nameNode.text = label
2333
                                objectNode.append(nameNode)
2334
                                poseNode = Element('pose')
2335
                                poseNode.text = 'Unspecified'
2336
                                objectNode.append(poseNode)
2337
                                truncatedNode = Element('truncated')
2338
                                truncatedNode.text = '0'
2339
                                objectNode.append(truncatedNode)
2340
                                difficultNode = Element('difficult')
2341
                                difficultNode.text = '0'
2342
                                objectNode.append(difficultNode)
2343

    
2344
                                bndboxNode = Element('bndbox')
2345
                                xminNode = Element('xmin')
2346
                                xminNode.text = str(xMin)
2347
                                bndboxNode.append(xminNode)
2348
                                yminNode = Element('ymin')
2349
                                yminNode.text = str(yMin)
2350
                                bndboxNode.append(yminNode)
2351
                                xmaxNode = Element('xmax')
2352
                                xmaxNode.text = str(xMax)
2353
                                bndboxNode.append(xmaxNode)
2354
                                ymaxNode = Element('ymax')
2355
                                ymaxNode.text = str(yMax)
2356
                                bndboxNode.append(ymaxNode)
2357
                                objectNode.append(bndboxNode)
2358

    
2359
                                xml.append(objectNode)
2360

    
2361
                            ElementTree(xml).write(training_xml_path)
2362

    
2363
            index += 1
2364

    
2365
        QMessageBox.about(self, self.tr("Notice"), self.tr('Successfully applied. '))
2366

    
2367
    def onPlaceLine(self):
2368
        """create a line"""
2369
        home_pane = self.ribbon.get_pane('Home')
2370

    
2371
        if not self.graphicsView.hasImage():
2372
            home_pane.ui.toolButtonLine.setChecked(False)
2373
            self.showImageSelectionMessageBox()
2374
            return
2375

    
2376
        self.update_action_group(home_pane.ui.toolButtonLine)
2377
        if not hasattr(home_pane.ui.toolButtonLine, 'tag'):
2378
            home_pane.ui.toolButtonLine.tag = PlaceLineCommand.PlaceLineCommand(self.graphicsView)
2379
            home_pane.ui.toolButtonLine.tag.onSuccess.connect(self.onLineCreated)
2380
            home_pane.ui.toolButtonLine.tag.onRejected.connect(self.onCommandRejected)
2381

    
2382
        self.graphicsView.command = home_pane.ui.toolButtonLine.tag
2383

    
2384
    def onLineCreated(self):
2385
        """add created lines to scene"""
2386
        from EngineeringConnectorItem import QEngineeringConnectorItem
2387
        from LineDetector import LineDetector
2388

    
2389
        try:
2390
            app_doc_data = AppDocData.instance()
2391
            home_pane = self.ribbon.get_pane('Home')
2392

    
2393
            count = len(home_pane.ui.toolButtonLine.tag._polyline._vertices)
2394
            if count > 1:
2395
                items = []
2396

    
2397
                detector = LineDetector(None)
2398

    
2399
                if not home_pane.ui.toolButtonLine.tag.line_type:
2400
                    line_type = home_pane.ui.comboBoxLineType.currentText()
2401
                else:
2402
                    pane = self.ribbon.get_pane('Home')
2403
                    selected_line_type = pane.ui.comboBoxLineType.currentText()
2404
                    if selected_line_type == 'Connect To Process':
2405
                        line_type = selected_line_type
2406
                    elif not (QEngineeringLineItem.check_piping(home_pane.ui.toolButtonLine.tag.line_type) ^
2407
                              QEngineeringLineItem.check_piping(selected_line_type)):
2408
                        line_type = selected_line_type
2409
                    else:
2410
                        line_type = home_pane.ui.toolButtonLine.tag.line_type
2411
                for index in range(count - 1):
2412
                    start = home_pane.ui.toolButtonLine.tag._polyline._vertices[index]
2413
                    end = home_pane.ui.toolButtonLine.tag._polyline._vertices[index + 1]
2414

    
2415
                    lineItem = QEngineeringLineItem(vertices=[start, end])
2416
                    lineItem.transfer.onRemoved.connect(self.itemRemoved)
2417
                    lineItem.lineType = line_type
2418
                    if items:
2419
                        lineItem.connect_if_possible(items[-1], 5)
2420
                    else:
2421
                        pt = lineItem.start_point()
2422
                        selected = [item for item in self.graphicsView.scene().items(QPointF(pt[0], pt[1])) if
2423
                                    type(item) is QEngineeringConnectorItem or type(item) is QEngineeringLineItem]
2424
                        if selected and selected[0] is not lineItem:
2425
                            if type(selected[0]) is QEngineeringConnectorItem:
2426
                                lineItem.connect_if_possible(selected[0].parent, 5)
2427
                            else:
2428
                                detector.connectLineToLine(selected[0], lineItem, 5)
2429

    
2430
                    items.append(lineItem)
2431
                    self.graphicsView.scene().addItem(lineItem)
2432

    
2433
                pt = items[-1].end_point()
2434
                selected = [item for item in self.graphicsView.scene().items(QPointF(pt[0], pt[1])) if
2435
                            (type(item) is QEngineeringConnectorItem and item.parentItem() is not items[-1]) or
2436
                            (type(item) is QEngineeringLineItem and item is not items[-1])]
2437
                if selected and selected[0] is not items[-1]:
2438
                    if type(selected[0]) is QEngineeringConnectorItem:
2439
                        items[-1].connect_if_possible(selected[0].parent, 5)
2440
                    else:
2441
                        detector.connectLineToLine(selected[0], items[-1], 5)
2442

    
2443
                self._scene.undo_stack.push(CreateCommand(self._scene, items))
2444
        finally:
2445
            self.graphicsView.scene().removeItem(home_pane.ui.toolButtonLine.tag._polyline)
2446
            home_pane.ui.toolButtonLine.tag.reset()
2447

    
2448
    def onCommandRejected(self, cmd=None):
2449
        """command is rejected"""
2450
        try:
2451
            home_pane = self.ribbon.get_pane('Home')
2452
            visualization_pane = self.ribbon.get_pane('Home Visualization')
2453
            if type(cmd) is PlaceLineCommand.PlaceLineCommand:
2454
                if home_pane.ui.toolButtonLine.tag._polyline:
2455
                    self.graphicsView.scene().removeItem(home_pane.ui.toolButtonLine.tag._polyline)
2456
                self.graphicsView.scene().update()
2457
                home_pane.ui.toolButtonLine.tag.reset()
2458

    
2459
                home_pane.ui.toolButtonLine.setChecked(False)
2460
            elif type(cmd) is AreaZoomCommand.AreaZoomCommand:
2461
                visualization_pane.ui.toolButtonZoom.setChecked(False)
2462
            elif type(cmd) is AreaOcrCommand.AreaOcrCommand:
2463
                home_pane.ui.toolButtonOCR.setChecked(False)
2464
            elif type(cmd) is PlacePolygonCommand.PlacePolygonCommand:
2465
                home_pane.ui.toolButtonVendor.setChecked(False)
2466
            else:
2467
                if hasattr(home_pane.ui.toolButtonVendor, 'tag') and home_pane.ui.toolButtonVendor.tag._polyline:
2468
                    self.graphicsView.scene().removeItem(home_pane.ui.toolButtonVendor.tag._polyline)
2469
                    self.graphicsView.scene().update()
2470
                    home_pane.ui.toolButtonVendor.tag.reset()
2471
                home_pane.ui.toolButtonLine.setChecked(False)
2472
                visualization_pane.ui.toolButtonZoom.setChecked(False)
2473
                home_pane.ui.toolButtonOCR.setChecked(False)
2474
                home_pane.ui.toolButtonVendor.setChecked(False)
2475
        finally:
2476
            self.graphicsView.useDefaultCommand()
2477

    
2478
    def on_view_toggle(self, key: int) -> None:
2479
        """view toggled"""
2480

    
2481
        view_pane = self.ribbon.get_pane('View')
2482
        if key == Qt.Key_1:
2483
            checked = view_pane.ui.toolButtonViewImageDrawing.isChecked()
2484
            self.onViewImageDrawing(not checked)
2485
            view_pane.ui.toolButtonViewImageDrawing.setChecked(not checked)
2486
        elif key == Qt.Key_2:
2487
            checked = view_pane.ui.toolButtonViewText.isChecked()
2488
            self.onViewText(not checked)
2489
            view_pane.ui.toolButtonViewText.setChecked(not checked)
2490
        elif key == Qt.Key_3:
2491
            checked = view_pane.ui.toolButtonViewSymbol.isChecked()
2492
            self.onViewSymbol(not checked)
2493
            view_pane.ui.toolButtonViewSymbol.setChecked(not checked)
2494
        elif key == Qt.Key_4:
2495
            checked = view_pane.ui.toolButtonViewLine.isChecked()
2496
            self.onViewLine(not checked)
2497
            view_pane.ui.toolButtonViewLine.setChecked(not checked)
2498
        elif key == Qt.Key_5:
2499
            checked = view_pane.ui.toolButtonViewUnknown.isChecked()
2500
            self.onViewUnknown(not checked)
2501
            view_pane.ui.toolButtonViewUnknown.setChecked(not checked)
2502
        elif key == Qt.Key_6:
2503
            checked = view_pane.ui.toolButtonViewInconsistency.isChecked()
2504
            self.onViewInconsistency(not checked)
2505
            view_pane.ui.toolButtonViewInconsistency.setChecked(not checked)
2506
        elif key == Qt.Key_7:
2507
            checked = view_pane.ui.toolButtonViewVendorArea.isChecked()
2508
            self.onViewVendorArea(not checked)
2509
            view_pane.ui.toolButtonViewVendorArea.setChecked(not checked)
2510
        elif key == 96:  # '~' key
2511
            checked = view_pane.ui.toolButtonViewDrawingOnly.isChecked()
2512
            self.onViewDrawingOnly(not checked)
2513
            view_pane.ui.toolButtonViewDrawingOnly.setChecked(not checked)
2514

    
2515
    def keyPressEvent(self, event):
2516
        """restore to default command when user press Escape key"""
2517
        try:
2518
            if event.key() == Qt.Key_Escape:
2519
                checked = self.checked_action()
2520
                if checked:
2521
                    checked.setChecked(False)
2522
                    self.graphicsView.useDefaultCommand()
2523
            elif event.key() == Qt.Key_M:  # merge text as vertical
2524
                from TextInfo import TextInfo
2525

    
2526
                textItems = [text for text in self.graphicsView.scene().selectedItems() if
2527
                             issubclass(type(text), QEngineeringTextItem)]
2528
                if not textItems or len(textItems) is 1:
2529
                    return
2530

    
2531
                angle = None
2532
                for item in textItems:
2533
                    if angle is None:
2534
                        angle = item.angle
2535
                    else:
2536
                        if angle != item.angle:
2537
                            return
2538

    
2539
                modifiers = QApplication.keyboardModifiers()
2540
                enter_or_space = ' ' if modifiers == Qt.ControlModifier else '\n'
2541
                x_or_y = 0 if (modifiers == Qt.ControlModifier and angle == 0) or (modifiers != Qt.ControlModifier and angle == 1.57) else 1
2542

    
2543
                textItems = sorted(textItems, key=lambda text: text.loc[x_or_y]) if textItems[0].angle == 0 else ( \
2544
                    sorted(textItems, key=lambda text: text.loc[x_or_y]) if textItems[0].angle == 1.57 else ( \
2545
                        sorted(textItems, key=lambda text: text.loc[x_or_y], reverse=True) if textItems[0].angle == 4.71 else \
2546
                            sorted(textItems, key=lambda text: text.loc[x_or_y], reverse=True)))
2547

    
2548
                if textItems[0].angle == 1.57 and modifiers == Qt.ControlModifier:
2549
                    textItems.reverse()
2550

    
2551
                minX = sys.maxsize
2552
                minY = sys.maxsize
2553
                maxX = 0
2554
                maxY = 0
2555
                newText = ''
2556

    
2557
                for text in textItems:
2558
                    if text.loc[0] < minX: minX = text.loc[0]
2559
                    if text.loc[1] < minY: minY = text.loc[1]
2560
                    if text.loc[0] + text.size[0] > maxX: maxX = text.loc[0] + text.size[0]
2561
                    if text.loc[1] + text.size[1] > maxY: maxY = text.loc[1] + text.size[1]
2562
                    newText = newText + text.text() + enter_or_space
2563
                    text.transfer.onRemoved.emit(text)
2564
                newText = newText[:-1]
2565

    
2566
                textInfo = TextInfo(newText, minX, minY, maxX - minX, maxY - minY, textItems[0].angle)
2567
                x = textInfo.getX()
2568
                y = textInfo.getY()
2569
                angle = textInfo.getAngle()
2570
                text = textInfo.getText()
2571
                width = textInfo.getW()
2572
                height = textInfo.getH()
2573
                item = TextItemFactory.instance().createTextItem(textInfo)
2574
                if item is not None:
2575
                    item.loc = [x, y]
2576
                    item.size = (width, height)
2577
                    item.angle = angle
2578
                    item.area = textItems[0].area
2579
                    item.setDefaultTextColor(Qt.blue)
2580
                    item.addTextItemToScene(self.graphicsView.scene())
2581
                    item.transfer.onRemoved.connect(self.itemRemoved)
2582
            elif event.key() == Qt.Key_D:
2583
                # pop up development toolkit dialog
2584
                from DevelopmentToolkitDialog import QDevelopmentToolkitDialog
2585

    
2586
                modifiers = QApplication.keyboardModifiers()
2587
                if modifiers == Qt.ControlModifier:
2588
                    dlg = QDevelopmentToolkitDialog(self, self.graphicsView)
2589
                    dlg.show()
2590
            elif event.key() == Qt.Key_I:
2591
                # insert symbol item that is selected symbol in tree to main window if symbol already selected on main window, replace
2592
                index = self.symbolTreeWidget.currentIndex()
2593
                proxy_model = self.symbolTreeWidget.model()
2594
                items = [proxy_model.sourceModel().itemFromIndex(proxy_model.mapToSource(index))]
2595
                if items and hasattr(items[0], 'svgFilePath'):
2596
                    symData = items[0].data(self.symbolTreeWidget.TREE_DATA_ROLE)
2597
                    symName = symData.getName()
2598
                else:
2599
                    return
2600

    
2601
                symbolItems = [symbol for symbol in self.graphicsView.scene().selectedItems() if
2602
                               issubclass(type(symbol), SymbolSvgItem)]
2603
                old_symbol = None
2604
                if symbolItems and len(symbolItems) is 1:
2605
                    old_symbol = symbolItems[0]
2606
                    #scenePos = QPoint(old_symbol.origin[0], old_symbol.origin[1])
2607
                    scenePos = old_symbol.mapToScene(old_symbol.transformOriginPoint())
2608
                    old_symbol.transfer.onRemoved.emit(old_symbol)
2609
                else:
2610
                    scenePos = self.current_pos
2611

    
2612
                svg = QtImageViewer.createSymbolObject(symName)
2613
                QtImageViewer.matchSymbolToLine(self.graphicsView.scene(), svg, scenePos, angle=old_symbol.angle if old_symbol else 0.0)
2614

    
2615
                if old_symbol and svg:
2616
                    from ReplaceCommand import ReplaceCommand
2617

    
2618
                    cmd = ReplaceCommand(self.graphicsView.scene(), old_symbol, svg)
2619
                    self._scene.undo_stack.push(cmd)
2620
                    return
2621
            elif event.key() == Qt.Key_J:
2622
                # insert and connect symbol item that is selected symbol in tree to selected symbol
2623
                index = self.symbolTreeWidget.currentIndex()
2624
                proxy_model = self.symbolTreeWidget.model()
2625
                items = [proxy_model.sourceModel().itemFromIndex(proxy_model.mapToSource(index))]
2626
                if items and hasattr(items[0], 'svgFilePath'):
2627
                    symData = items[0].data(self.symbolTreeWidget.TREE_DATA_ROLE)
2628
                    symName = symData.getName()
2629
                else:
2630
                    return
2631

    
2632
                symbolItems = [symbol for symbol in self.graphicsView.scene().selectedItems() if
2633
                               issubclass(type(symbol), SymbolSvgItem)]
2634
                if symbolItems and len(symbolItems) is not 1:
2635
                    return
2636
                    
2637
                target_symbol = symbolItems[0]
2638
                index =  [index for index in range(len(target_symbol.conn_type)) \
2639
                            if target_symbol.conn_type[index] == 'Primary' or target_symbol.conn_type[index] == 'Secondary']
2640
                for connector in target_symbol.connectors:
2641
                    svg = QtImageViewer.createSymbolObject(symName)
2642
                    if len(svg.connectors) > 1: 
2643
                        if ((target_symbol.conn_type and target_symbol.connectors.index(connector) in index) or not target_symbol.conn_type) and \
2644
                                    (not connector.connectedItem or (connector.connectedItem and type(connector.connectedItem) is QEngineeringLineItem)):
2645
                            QtImageViewer.matchSymbolToLine(self.graphicsView.scene(), svg, connector.sceneBoundingRect().center())
2646
                    elif len(svg.connectors) == 1:
2647
                        if ((target_symbol.conn_type and target_symbol.connectors.index(connector) in index) or not target_symbol.conn_type) and \
2648
                                    not connector.connectedItem:
2649
                            QtImageViewer.matchSymbolToLine(self.graphicsView.scene(), svg, connector.sceneBoundingRect().center())
2650

    
2651
                if target_symbol:
2652
                    return
2653
            elif event.key() == Qt.Key_X:
2654
                pass
2655
                '''
2656
                app_doc_data = AppDocData.instance()
2657
                configs = app_doc_data.getAppConfigs('app', 'mode')
2658
                if configs and 1 == len(configs) and 'advanced' == configs[0].value:
2659
                    advanced = True
2660
                    items = self.graphicsView.scene().selectedItems()
2661
                    if items:
2662
                        item = self.symbolTreeWidget.currentItem()
2663
                        if item:
2664
                            self.symbolTreeWidget.showSymbolEditorDialog(item, 0)
2665
                '''
2666
            elif event.key() == Qt.Key_F6:
2667
                from DEXPI import scene_to_dexpi
2668

    
2669
                app_doc_data = AppDocData.instance()
2670
                scene_to_dexpi('D:\\Temp\\DEXPI.xml', app_doc_data.activeDrawing.name, self.graphicsView.scene())
2671

    
2672
            QMainWindow.keyPressEvent(self, event)
2673
        except Exception as ex:
2674
            message = f"error occurred({repr(ex)}) in {sys.exc_info()[-1].tb_frame.f_code.co_filename}:" \
2675
                      f"{sys.exc_info()[-1].tb_lineno}"
2676
            self.addMessage.emit(MessageType.Error, message)
2677

    
2678
    def recognize(self):
2679
        """recognize symbol, text and line for selected drawings"""
2680
        from datetime import datetime
2681
        from License import QLicenseDialog
2682

    
2683
        # save alarm
2684
        self.save_alarm_enable(False)
2685

    
2686
        app_doc_data = AppDocData.instance()
2687
        current_drawing, currentPid = None, None
2688

    
2689
        if self.graphicsView.hasImage():
2690
            current_drawing = app_doc_data.activeDrawing
2691
            currentPid = app_doc_data.activeDrawing.name
2692

    
2693
        # get checked drawings
2694
        drawing_top = self.treeWidgetDrawingList.topLevelItem(0)
2695
        count = drawing_top.childCount()
2696
        checked_drawings = {}
2697
        for idx in range(count):
2698
            child = drawing_top.child(idx)
2699
            if child.checkState(0) == Qt.Checked and child.data(Qt.UserRole, 0):
2700
                checked_drawings[child.data(Qt.UserRole, 0)] = child
2701
        # up to here
2702

    
2703
        # if there is no checked drawing
2704
        if current_drawing and currentPid and not checked_drawings:
2705
            for idx in range(count):
2706
                child = drawing_top.child(idx)
2707
                if child.data(Qt.UserRole, 0) is current_drawing:
2708
                    checked_drawings[child.data(Qt.UserRole, 0)] = child
2709

    
2710
        if not checked_drawings:
2711
            self.showImageSelectionMessageBox()
2712
            return
2713

    
2714
        try:
2715
            self.on_clear_log()
2716
            dlg = QRecognitionDialog(self, [drawing for drawing in checked_drawings.keys()])
2717
            dlg.exec_()
2718

    
2719
            if current_drawing and current_drawing in checked_drawings.keys() and dlg.isTreated:
2720
                self.open_image_drawing(current_drawing, force=True, ocrUnknown=dlg.ui.checkBoxOCRUnknown.isChecked())
2721

    
2722
            # save working date-time
2723
            _now = datetime.now().strftime('%Y-%m-%d %H:%M:%S')
2724
            for drawing, tree_item in checked_drawings.items():
2725
                drawing.datetime = _now
2726
                tree_item.setText(1, _now)
2727
            #app_doc_data.saveDrawings(checked_drawings.keys())
2728
            self.changeViewCheckedState(True)
2729
            # count up for recognition
2730
            QLicenseDialog.count_up()
2731
            # up to here
2732
        except Exception as ex:
2733
            message = f"error occurred({repr(ex)}) in {sys.exc_info()[-1].tb_frame.f_code.co_filename}:" \
2734
                      f"{sys.exc_info()[-1].tb_lineno}"
2735
            self.addMessage.emit(MessageType.Error, message)
2736

    
2737
        # save alarm
2738
        self.save_alarm_enable(True, True)
2739

    
2740
    '''
2741
        @brief      remove item from tree widget and then remove from scene
2742
        @date       2018.05.25
2743
        @author     Jeongwoo
2744
    '''
2745
    def itemRemoved(self, item):
2746
        try:
2747
            if type(item) is QEngineeringErrorItem:
2748
                # remove error item from inconsistency list
2749
                for row in range(self.tableWidgetInconsistency.rowCount()):
2750
                    if item is self.tableWidgetInconsistency.item(row, 0).tag:
2751
                        self.tableWidgetInconsistency.removeRow(row)
2752
                        break
2753

    
2754
                if item.scene() is not None:
2755
                    item.scene().removeItem(item)
2756
                del item
2757
            else:
2758
                remove_scene = item.scene()
2759
                self.itemTreeWidget.itemRemoved(item)
2760

    
2761
                if remove_scene:
2762
                    matches = [_item for _item in remove_scene.items() if
2763
                            hasattr(_item, 'connectors') and [connector for connector in _item.connectors if
2764
                                                                connector.connectedItem is item]]
2765
                    for match in matches:
2766
                        for connector in match.connectors:
2767
                            if connector.connectedItem is item:
2768
                                connector.connectedItem = None
2769
                                connector.highlight(False)
2770

    
2771
                # matches = [_item for _item in self.graphicsView.scene().items() if hasattr(_item, 'remove_assoc_item')]
2772
                # for _item in matches:
2773
                #    _item.remove_assoc_item(item)
2774

    
2775
                app_doc_data = AppDocData.instance()
2776
                if type(item) is QEngineeringLineNoTextItem and item in app_doc_data.tracerLineNos:
2777
                    app_doc_data.tracerLineNos.pop(app_doc_data.tracerLineNos.index(item))
2778

    
2779
                if type(item) is QEngineeringLineItem and item in app_doc_data.lines:
2780
                    app_doc_data.lines.remove(item)
2781

    
2782
                if remove_scene:
2783
                    matches = [_item for _item in remove_scene.items() if
2784
                            type(_item) is QEngineeringLineNoTextItem]
2785
                    matches.extend([lineNo for lineNo in app_doc_data.tracerLineNos if
2786
                                    type(lineNo) is QEngineeringTrimLineNoTextItem])
2787
                    for match in matches:
2788
                        if item is match.prop('From'):
2789
                            match.set_property('From', None)
2790
                        if item is match.prop('To'):
2791
                            match.set_property('To', None)
2792

    
2793
                        for run_index in reversed(range(len(match.runs))):
2794
                            run = match.runs[run_index]
2795
                            if item in run.items:
2796
                                index = run.items.index(item)
2797
                                run.items.pop(index)
2798
                                if not run.items:
2799
                                    run.explode()
2800
                                    if type(match) is QEngineeringTrimLineNoTextItem and not match.runs:
2801
                                        app_doc_data.tracerLineNos.pop(app_doc_data.tracerLineNos.index(match))
2802
                                # break
2803

    
2804
                if remove_scene:
2805
                    matches = [_item for _item in remove_scene.items() if hasattr(_item, 'owner')]
2806
                    for match in matches:
2807
                        if match.owner is item:
2808
                            match.owner = None
2809

    
2810
                    matches = [_item for _item in remove_scene.items() if hasattr(_item, 'attrs')]
2811
                    # done = False
2812
                    for match in matches:
2813
                        assocs = match.associations()
2814
                        for assoc in assocs:
2815
                            if item is assoc:
2816
                                keys = match.attrs.keys()
2817
                                for attr in keys:
2818
                                    if attr.AssocItem and str(item.uid) == str(attr.AssocItem.uid):
2819
                                        attr.AssocItem = None
2820
                                        match.attrs[attr] = ''
2821
                                        # done = True
2822
                                match.remove_assoc_item(item)
2823
                                break
2824
                        # if done: break
2825

    
2826
                if item.scene() is not None:
2827
                    #if type(item) is QEngineeringLineNoTextItem and item._labels:
2828
                    #    for _label in item._labels:
2829
                    #        item.scene().removeItem(_label)
2830
                    #    item._labels = []
2831

    
2832
                    item.scene().removeItem(item)
2833
        except Exception as ex:
2834
            message = 'error occurred({}) in {}:{}'.format(ex, sys.exc_info()[-1].tb_frame.f_code.co_filename,
2835
                                                           sys.exc_info()[-1].tb_lineno)
2836
            self.addMessage.emit(MessageType.Error, message)
2837
        '''
2838
        finally:
2839
            if hasattr(item, '_cond'):
2840
                item._cond.wakeAll()
2841
        '''
2842

    
2843

    
2844
    def connect_attributes(self, MainWindow):
2845
        """connect attributes to symbol"""
2846
        from LineNoTracer import LineNoTracer
2847
        from ConnectAttrDialog import QConnectAttrDialog
2848

    
2849
        if not self.graphicsView.hasImage():
2850
            self.showImageSelectionMessageBox()
2851
            return
2852

    
2853
        # save alarm
2854
        self.save_alarm_enable(False)
2855

    
2856
        try:
2857
            dlg = QConnectAttrDialog(self, self.graphicsView.scene())
2858
            dlg.setWindowFlags(self.windowFlags() & ~Qt.WindowCloseButtonHint & ~Qt.WindowContextHelpButtonHint)
2859
            dlg.exec_()
2860
            if dlg.isRunned:
2861
                self.refresh_item_list()
2862

    
2863
                if dlg.validation_checked:
2864
                    self.onValidation()
2865

    
2866
                self.graphicsView.invalidateScene()
2867
        except Exception as ex:
2868
            message = 'error occurred({}) in {}:{}'.format(ex, sys.exc_info()[-1].tb_frame.f_code.co_filename,
2869
                                                           sys.exc_info()[-1].tb_lineno)
2870
            self.addMessage.emit(MessageType.Error, message)
2871
        finally:
2872
            # save alarm
2873
            self.save_alarm_enable(True)
2874

    
2875
    def postDetectLineProcess(self):
2876
        '''
2877
            @brief  check allowables among undetected items
2878
            @author euisung
2879
            @date   2018.11.15
2880
            @history    2018.11.15  euisung    no more used, moved to TextItemFactoy isLineNo()
2881
        '''
2882
        from TextItemFactory import TextItemFactory
2883

    
2884
        appDocData = AppDocData.instance()
2885

    
2886
        tableNames = ["Fluid Code", "Insulation Purpose", "PnID Number", "Piping Materials Class", "Unit Number"]
2887
        tableDatas = []
2888
        for tableName in tableNames:
2889
            tableNameFormat = tableName.replace(' ', '').replace('&&', 'n')
2890
            tableDatas.append(appDocData.getCodeTable(tableNameFormat))
2891

    
2892
        items = self.graphicsView.scene().items()
2893
        for item in items:
2894
            if type(item) is not QEngineeringTextItem:
2895
                continue
2896
            text = item.text()
2897
            for tableData in tableDatas:
2898
                for data in tableData:
2899
                    if data[3] == '':
2900
                        continue
2901
                    else:
2902
                        allows = data[3].split(',')
2903
                        for allow in allows:
2904
                            text = text.replace(allow, data[1])
2905

    
2906
            lineItem = TextItemFactory.instance().createTextItem(text)
2907
            if type(lineItem) is QEngineeringLineNoTextItem:
2908
                lineItem.loc = item.loc
2909
                lineItem.size = item.size
2910
                lineItem.angle = item.angle
2911
                lineItem.area = item.area
2912
                # lineItem.addTextItemToScene(self.graphicsView.scene())
2913
                lineItem.transfer.onRemoved.connect(self.itemRemoved)
2914
                item.transfer.onRemoved.emit(item)
2915
                appDocData.lineNos.append(lineItem)
2916

    
2917
    def init_add_tree_item(self, line_no_tree_item, run_item):
2918
        """ insert symbol item and find line no as owner """
2919
        # insert
2920
        self.itemTreeWidget.addTreeItem(line_no_tree_item, run_item)
2921
        # find
2922
        self.itemTreeWidget.addTreeItem(line_no_tree_item, run_item)
2923

    
2924
    def load_drawing(self, drawing):
2925
        """ load drawing """
2926
        """ no more used """
2927
        from EngineeringRunItem import QEngineeringRunItem
2928
        from QEngineeringTrimLineNoTextItem import QEngineeringTrimLineNoTextItem
2929

    
2930
        app_doc_data = AppDocData.instance()
2931
        try:
2932
            symbols = []
2933
            lines = []
2934

    
2935
            components = app_doc_data.get_components(drawing.UID)
2936
            maxValue = len(components) * 2
2937
            self.progress.setMaximum(maxValue) if maxValue > 0 else None
2938

    
2939
            """ parsing all symbols """
2940
            for symbol in [component for component in components if int(component['SymbolType_UID']) != -1]:
2941
                item = SymbolSvgItem.from_database(symbol)
2942
                if item is not None:
2943
                    item.transfer.onRemoved.connect(self.itemRemoved)
2944
                    symbols.append(item)
2945
                    app_doc_data.symbols.append(item)
2946
                    item.addSvgItemToScene(self.graphicsView.scene())
2947
                else:
2948
                    pt = [float(symbol['X']), float(symbol['Y'])]
2949
                    size = [float(symbol['Width']), float(symbol['Height'])]
2950
                    angle = float(symbol['Rotation'])
2951
                    item = QGraphicsBoundingBoxItem(pt[0], pt[1], size[0], size[1])
2952
                    item.isSymbol = True
2953
                    item.angle = angle
2954
                    item.setPen(QPen(Qt.red, 5, Qt.SolidLine))
2955
                    self.graphicsView.scene().addItem(item)
2956
                    item.transfer.onRemoved.connect(self.itemRemoved)
2957

    
2958
                self.progress.setValue(self.progress.value() + 1)
2959

    
2960
            QApplication.processEvents()
2961

    
2962
            # parse texts
2963
            for text in [component for component in components if
2964
                         component['Name'] == 'Text' and component['SymbolType_UID'] == -1]:
2965
                item = QEngineeringTextItem.from_database(text)
2966
                if item is not None:
2967
                    item.uid = text['UID']
2968
                    item.attribute = text['Value']
2969
                    name = text['Name']
2970
                    item.transfer.onRemoved.connect(self.itemRemoved)
2971
                    item.addTextItemToScene(self.graphicsView.scene())
2972

    
2973
                self.progress.setValue(self.progress.value() + 1)
2974

    
2975
            QApplication.processEvents()
2976

    
2977
            # note
2978
            for note in [component for component in components if
2979
                         component['Name'] == 'Note' and component['SymbolType_UID'] == -1]:
2980
                item = QEngineeringTextItem.from_database(note)
2981
                if item is not None:
2982
                    item.uid = note['UID']
2983
                    attributeValue = note['Value']
2984
                    name = note['Name']
2985
                    item.transfer.onRemoved.connect(self.itemRemoved)
2986
                    item.addTextItemToScene(self.graphicsView.scene())
2987

    
2988
                self.progress.setValue(self.progress.value() + 1)
2989

    
2990
            QApplication.processEvents()
2991

    
2992
            for line in [component for component in components if
2993
                         component['Name'] == 'Line' and component['SymbolType_UID'] == -1]:
2994
                item = QEngineeringLineItem.from_database(line)
2995
                if item:
2996
                    item.transfer.onRemoved.connect(self.itemRemoved)
2997
                    self.graphicsView.scene().addItem(item)
2998
                    lines.append(item)
2999

    
3000
                self.progress.setValue(self.progress.value() + 1)
3001

    
3002
            QApplication.processEvents()
3003

    
3004
            for unknown in [component for component in components if
3005
                            component['Name'] == 'Unknown' and component['SymbolType_UID'] == -1]:
3006
                item = QEngineeringUnknownItem.from_database(unknown)
3007
                item.transfer.onRemoved.connect(self.itemRemoved)
3008
                if item is not None:
3009
                    item.transfer.onRemoved.connect(self.itemRemoved)
3010
                    self.graphicsView.scene().addItem(item)
3011

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

    
3014
            QApplication.processEvents()
3015

    
3016
            for component in [component for component in components if
3017
                              component['Name'] == 'Line NO' and component['SymbolType_UID'] == -1]:
3018
                line_no = QEngineeringLineNoTextItem.from_database(component)
3019
                if type(line_no) is QEngineeringLineNoTextItem:
3020
                    line_no.transfer.onRemoved.connect(self.itemRemoved)
3021
                    self.addTextItemToScene(line_no)
3022
                    line_no_tree_item = self.itemTreeWidget.addTreeItem(self.itemTreeWidget.root, line_no)
3023

    
3024
                    runs = app_doc_data.get_pipe_runs(str(line_no.uid))
3025
                    if not runs: continue
3026
                    for run in runs:
3027
                        line_run = QEngineeringRunItem()
3028
                        run_items = app_doc_data.get_pipe_run_items(run['UID'])
3029
                        for record in run_items:
3030
                            uid = record['Components_UID']
3031
                            run_item = self.graphicsView.findItemByUid(uid)
3032
                            if run_item is not None:
3033
                                run_item._owner = line_no
3034
                                line_run.items.append(run_item)
3035
                        line_run.owner = line_no
3036
                        line_no.runs.append(line_run)
3037

    
3038
                        for run_item in line_run.items:
3039
                            if issubclass(type(run_item), SymbolSvgItem):
3040
                                self.init_add_tree_item(line_no_tree_item, run_item)
3041

    
3042
                self.progress.setValue(self.progress.value() + 1)
3043
            QApplication.processEvents()
3044

    
3045
            for component in [component for component in components if
3046
                              component['Name'] == 'Trim Line NO' and component['SymbolType_UID'] == -1]:
3047
                line_no = QEngineeringTrimLineNoTextItem()
3048
                line_no.uid = uuid.UUID(component['UID'])
3049

    
3050
                runs = app_doc_data.get_pipe_runs(str(line_no.uid))
3051
                if not runs: continue
3052

    
3053
                line_no_tree_item = self.itemTreeWidget.addTreeItem(self.itemTreeWidget.root, line_no)
3054

    
3055
                for run in runs:
3056
                    line_run = QEngineeringRunItem()
3057
                    run_items = app_doc_data.get_pipe_run_items(run['UID'])
3058
                    for record in run_items:
3059
                        uid = record['Components_UID']
3060
                        run_item = self.graphicsView.findItemByUid(uid)
3061
                        if run_item is not None:
3062
                            run_item.owner = line_no
3063
                            line_run.items.append(run_item)
3064
                    line_run.owner = line_no
3065
                    line_no.runs.append(line_run)
3066

    
3067
                    for run_item in line_run.items:
3068
                        if issubclass(type(run_item), SymbolSvgItem):
3069
                            self.init_add_tree_item(line_no_tree_item, run_item)
3070

    
3071
                app_doc_data.tracerLineNos.append(line_no)
3072

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

    
3075
            for component in [component for component in components if
3076
                              component['Name'] == 'VendorPackage' and component['SymbolType_UID'] == -1]:
3077
                item = QEngineeringVendorItem.from_database(component)
3078
                if item is not None:
3079
                    item.transfer.onRemoved.connect(self.itemRemoved)
3080
                    self.graphicsView.scene().addItem(item)
3081

    
3082
            # connect flow item to line
3083
            for line in lines:
3084
                line.update_arrow()
3085
                app_doc_data.lines.append(line)
3086
            # for flowMark in [item for item in symbols if type(item) is QEngineeringFlowMarkItem]:
3087
            #    for line in lines:
3088
            #        if flowMark.owner is line:
3089
            #            line._flowMark.append(flowMark)
3090
            #            flowMark.setParentItem(line)
3091
            # up to here
3092

    
3093
            """ update scene """
3094
            self.graphicsView.scene().update(self.graphicsView.sceneRect())
3095
            for item in self.graphicsView.scene().items():
3096
                up_progress = False
3097
                # binding items
3098
                if hasattr(item, 'owner'):
3099
                    item.owner
3100
                    up_progress = True
3101
                if hasattr(item, 'connectors'):
3102
                    for connector in item.connectors:
3103
                        connector.connectedItem
3104
                    up_progress = True
3105

    
3106
                if up_progress:
3107
                    self.progress.setValue(self.progress.value() + 1)
3108
            
3109
            for item in self.graphicsView.scene().items():
3110
                item.setVisible(True)
3111

    
3112
        except Exception as ex:
3113
            message = 'error occurred({}) in {}:{}'.format(ex, sys.exc_info()[-1].tb_frame.f_code.co_filename,
3114
                                                           sys.exc_info()[-1].tb_lineno)
3115
            self.addMessage.emit(MessageType.Error, message)
3116
        finally:
3117
            app_doc_data.clearTempDBData()
3118
            self.itemTreeWidget.update_item_count()
3119
            self.itemTreeWidget.expandAll()
3120
            # self.graphicsView.scene().blockSignals(False)
3121

    
3122
    '''
3123
        @brief      load recognition result
3124
        @author     humkyung
3125
        @date       2018.04.??
3126
        @history    humkyung 2018.01.12 parse originalpoint and connectionpoint
3127
                    Jeongwoo 2018.04.17 add QGraphicItem with Rotated text
3128
                    Jeongwoo 2018.04.23 Change to Draw texts on QEngineeringTextItem
3129
                    humkyung 2018.04.23 connect item remove slot to result tree
3130
                    Jeongwoo 2018.04.25 Add if state with QEngineeringNoteItem
3131
                    Jeongwoo 2018.04.26 Change method to create TextItem object with TextItemFactory
3132
                    Jeongwoo 2018.05.03 Change method to draw Svg Item on Scene (svg.addSvgItemToScene)
3133
                    Jeongwoo 2018.05.29 Change method name / Change method to add item / Add Line item
3134
                    Jeongwoo 2018.05.30 Add parameters on SymbolSvgItem.__init__() (parentSymbol, childSymbol) / Change method name / Change XML NODE NAMES
3135
                    Jeongwoo 2018.06.12 Add LineNoTextItem from LINE_NO
3136
                    Jeongwoo 2018.06.14 Add UnknownItem from UNKNOWN
3137
                    Jeongwoo 2018.06.18 Update Scene after all item added
3138
                                        Add connect on unknown item
3139
                                        Add [transfer] for using pyqtSignal
3140
                    kyouho  2018.07.12  Add line property logic
3141
                    humkyung 2018.08.22 show progress while loading xml file
3142
                    2018.11.22      euisung     fix note road
3143
    '''
3144
    def load_recognition_result_from_xml(self, drawing):
3145
        # Yield successive n-sized
3146
        # chunks from l.
3147
        def divide_chunks(l, n):
3148
            # looping till length l
3149
            for i in range(0, len(l), n):
3150
                yield l[i:i + n]
3151

    
3152
        def update_items(items):
3153
            for item in items:
3154
                # binding items
3155
                item.owner
3156
                for connector in item.connectors:
3157
                    connector.connectedItem
3158

    
3159
            return items
3160

    
3161
        import concurrent.futures as futures
3162
        from xml.etree.ElementTree import Element, SubElement, dump, ElementTree, parse
3163
        from App import App
3164
        from EngineeringRunItem import QEngineeringRunItem
3165
        from QEngineeringTrimLineNoTextItem import QEngineeringTrimLineNoTextItem
3166
        from EngineeringGraphicsLineItem import QEngineeringGraphicsLineItem
3167

    
3168
        app_doc_data = AppDocData.instance()
3169

    
3170
        try:
3171
            file_name = os.path.splitext(os.path.basename(drawing.file_path))[0]
3172
            path = os.path.join(app_doc_data.getCurrentProject().getTempPath(), file_name + '.xml')
3173
            self.graphicsView.scene().blockSignals(True)
3174

    
3175
            symbols = []
3176
            lines = []
3177

    
3178
            xml = parse(path)
3179
            root = xml.getroot()
3180

    
3181
            maxValue = 0
3182
            maxValue = maxValue + len(list(root.iter('SYMBOL'))) - \
3183
                       len(list(root.iterfind('LINENOS/LINE_NO/RUN/SYMBOL'))) - \
3184
                       len(list(root.iterfind('TRIMLINENOS/TRIM_LINE_NO/RUN/SYMBOL')))
3185
            maxValue = maxValue + len(list(root.iterfind('TEXTINFOS/ATTRIBUTE')))
3186
            maxValue = maxValue + len(list(root.iterfind('NOTES/ATTRIBUTE')))
3187
            maxValue = maxValue + len(list(root.iter('LINE_NO')))
3188
            maxValue = maxValue + len(list(root.iter('LINE'))) - \
3189
                       len(list(root.iterfind('LINENOS/LINE_NO/RUN/LINE'))) - \
3190
                       len(list(root.iterfind('TRIMLINENOS/TRIM_LINE_NO/RUN/LINE')))
3191
            maxValue = maxValue + len(list(root.iter('GRAPHICS_LINE')))
3192
            maxValue = maxValue + len(list(root.iter('UNKNOWN')))
3193
            # maxValue = maxValue + len(list(root.iter('SIZETEXT')))
3194
            maxValue = maxValue + len(list(root.iter('TRIM_LINE_NO')))
3195
            maxValue *= 2
3196
            self.progress.setMaximum(maxValue) if maxValue > 0 else None
3197

    
3198
            """ parsing all symbols """
3199
            """
3200
            with futures.ThreadPoolExecutor(max_workers=App.THREAD_MAX_WORKER) as pool:
3201
                future_symbol = {pool.submit(SymbolSvgItem.fromXml, symbol): symbol for symbol in root.find('SYMBOLS').iter('SYMBOL')}
3202

3203
                for future in futures.as_completed(future_symbol):
3204
                    try:
3205
                        item = future.result()
3206
                        if item:
3207
                            if item is not None:
3208
                                item.transfer.onRemoved.connect(self.itemRemoved)
3209
                                symbols.append(item)
3210
                                docData.symbols.append(item)
3211
                                self.addSvgItemToScene(item)
3212
                            else:
3213
                                pt = [float(x) for x in symbol.find('LOCATION').text.split(',')]
3214
                                size = [float(x) for x in symbol.find('SIZE').text.split(',')]
3215
                                angle = float(symbol.find('ANGLE').text)
3216
                                item = QGraphicsBoundingBoxItem(pt[0], pt[1], size[0], size[1])
3217
                                item.isSymbol = True
3218
                                item.angle = angle
3219
                                item.setPen(QPen(Qt.red, 5, Qt.SolidLine))
3220
                                self.graphicsView.scene().addItem(item)
3221
                                item.transfer.onRemoved.connect(self.itemRemoved)
3222
                    except Exception as ex:
3223
                        message = 'error occurred({}) in {}:{}'.format(repr(ex), sys.exc_info()[-1].tb_frame.f_code.co_filename,
3224
                                                                       sys.exc_info()[-1].tb_lineno)
3225

3226
            """
3227
            for symbol in root.find('SYMBOLS').iter('SYMBOL'):
3228
                item = SymbolSvgItem.fromXml(symbol)
3229
                if item is not None:
3230
                    item.transfer.onRemoved.connect(self.itemRemoved)
3231
                    symbols.append(item)
3232
                    #app_doc_data.symbols.append(item)
3233
                    item.addSvgItemToScene(self.graphicsView.scene())
3234
                else:
3235
                    pt = [float(x) for x in symbol.find('LOCATION').text.split(',')]
3236
                    size = [float(x) for x in symbol.find('SIZE').text.split(',')]
3237
                    angle = float(symbol.find('ANGLE').text)
3238
                    item = QGraphicsBoundingBoxItem(pt[0], pt[1], size[0], size[1])
3239
                    item.isSymbol = True
3240
                    item.angle = angle
3241
                    item.setPen(QPen(Qt.red, 5, Qt.SolidLine))
3242
                    self.graphicsView.scene().addItem(item)
3243
                    item.transfer.onRemoved.connect(self.itemRemoved)
3244

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

    
3247
            QApplication.processEvents()
3248

    
3249
            # parse texts
3250
            for text in root.find('TEXTINFOS').iter('ATTRIBUTE'):
3251
                item = QEngineeringTextItem.fromXml(text)
3252
                if item is not None:
3253
                    uid = text.find('UID')
3254
                    attributeValue = text.find('ATTRIBUTEVALUE')
3255
                    name = text.find('NAME').text
3256
                    item.transfer.onRemoved.connect(self.itemRemoved)
3257
                    item.addTextItemToScene(self.graphicsView.scene())
3258
                    # docData.texts.append(item)
3259

    
3260
                    if name == 'TEXT':
3261
                        if uid is not None and attributeValue is not None:
3262
                            item.uid = uid.text
3263
                            item.attribute = attributeValue.text
3264

    
3265
                self.progress.setValue(self.progress.value() + 1)
3266

    
3267
            QApplication.processEvents()
3268

    
3269
            # note
3270
            for text in root.find('NOTES').iter('ATTRIBUTE'):
3271
                item = QEngineeringTextItem.fromXml(text)
3272
                if item is not None:
3273
                    uid = text.find('UID')
3274
                    attributeValue = text.find('ATTRIBUTEVALUE')
3275
                    name = text.find('NAME').text
3276
                    item.transfer.onRemoved.connect(self.itemRemoved)
3277
                    item.addTextItemToScene(self.graphicsView.scene())
3278

    
3279
                    if name == 'NOTE':
3280
                        if uid is not None:
3281
                            item.uid = uid.text
3282

    
3283
                self.progress.setValue(self.progress.value() + 1)
3284

    
3285
            QApplication.processEvents()
3286

    
3287
            for line in root.find('LINEINFOS').iter('LINE'):
3288
                item = QEngineeringLineItem.fromXml(line)
3289
                if item:
3290
                    item.transfer.onRemoved.connect(self.itemRemoved)
3291
                    self.graphicsView.scene().addItem(item)
3292
                    lines.append(item)
3293

    
3294
                self.progress.setValue(self.progress.value() + 1)
3295

    
3296
            for line in root.find('LINEINFOS').iter('GRAPHICS_LINE'):
3297
                item = QEngineeringGraphicsLineItem.fromXml(line)
3298
                if item:
3299
                    item.transfer.onRemoved.connect(self.itemRemoved)
3300
                    self.graphicsView.scene().addItem(item)
3301

    
3302
                self.progress.setValue(self.progress.value() + 1)
3303

    
3304
            QApplication.processEvents()
3305

    
3306
            for unknown in root.iter('UNKNOWN'):
3307
                item = QEngineeringUnknownItem.fromXml(unknown)
3308
                if item is not None:
3309
                    item.transfer.onRemoved.connect(self.itemRemoved)
3310
                    self.graphicsView.scene().addItem(item)
3311

    
3312
                self.progress.setValue(self.progress.value() + 1)
3313

    
3314
            QApplication.processEvents()
3315

    
3316
            # """ add tree widget """
3317
            # for item in symbols:
3318
            #    docData.symbols.append(item)
3319
            #    self.addSvgItemToScene(item)
3320
            #    self.itemTreeWidget.addTreeItem(self.itemTreeWidget.root, item)
3321

    
3322
            for line_no_node in root.find('LINENOS').iter('LINE_NO'):
3323
                line_no = QEngineeringLineNoTextItem.fromXml(line_no_node)
3324
                if line_no is None: continue
3325
                line_no.transfer.onRemoved.connect(self.itemRemoved)
3326
                line_no.addTextItemToScene(self.graphicsView.scene())
3327
                line_no_tree_item = self.itemTreeWidget.addTreeItem(self.itemTreeWidget.root, line_no)
3328
                if type(line_no) is not QEngineeringLineNoTextItem: continue
3329

    
3330
                runs_node = line_no_node.findall('RUN')
3331
                if runs_node is None: continue
3332

    
3333
                for run_node in runs_node:
3334
                    line_run = QEngineeringRunItem()
3335
                    for child_node in run_node:
3336
                        uidElement = child_node.find('UID')
3337
                        if uidElement is not None:
3338
                            uid = uidElement.text
3339
                            run_item = self.graphicsView.findItemByUid(uid)
3340
                            if run_item is not None:
3341
                                run_item._owner = line_no
3342
                                line_run.items.append(run_item)
3343
                    line_run.owner = line_no
3344
                    line_no.runs.append(line_run)
3345

    
3346
                    for run_item in line_run.items:
3347
                        if issubclass(type(run_item), SymbolSvgItem):
3348
                            self.init_add_tree_item(line_no_tree_item, run_item)
3349

    
3350
                # docData.tracerLineNos.append(line_no)
3351

    
3352
                self.progress.setValue(self.progress.value() + 1)
3353
            QApplication.processEvents()
3354

    
3355
            for trimLineNo in root.iter('TRIM_LINE_NO'):
3356
                line_no = QEngineeringTrimLineNoTextItem()
3357
                line_no.uid = uuid.UUID(trimLineNo.find('UID').text)
3358

    
3359
                runs_node = trimLineNo.findall('RUN')
3360
                if runs_node is None: continue
3361
                line_no_tree_item = self.itemTreeWidget.addTreeItem(self.itemTreeWidget.root, line_no)
3362

    
3363
                for run in runs_node:
3364
                    line_run = QEngineeringRunItem()
3365
                    for child in run:
3366
                        uidElement = child.find('UID')
3367
                        if uidElement is not None:
3368
                            uid = uidElement.text
3369
                            run_item = self.graphicsView.findItemByUid(uid)
3370
                            if run_item is not None:
3371
                                run_item.owner = line_no
3372
                                line_run.items.append(run_item)
3373
                    line_run.owner = line_no
3374
                    line_no.runs.append(line_run)
3375

    
3376
                    for run_item in line_run.items:
3377
                        if issubclass(type(run_item), SymbolSvgItem):
3378
                            self.init_add_tree_item(line_no_tree_item, run_item)
3379

    
3380
                app_doc_data.tracerLineNos.append(line_no)
3381

    
3382
                self.progress.setValue(self.progress.value() + 1)
3383
            QApplication.processEvents()
3384

    
3385
            if root.find('VENDORS') is not None:
3386
                for vendor in root.find('VENDORS').iter('VENDOR'):
3387
                    item = QEngineeringVendorItem.fromXml(vendor)
3388
                    item.transfer.onRemoved.connect(self.itemRemoved)
3389
                    self.graphicsView.scene().addItem(item)
3390

    
3391
            # connect flow item to line
3392
            for line in lines:
3393
                line.update_arrow()
3394
                app_doc_data.lines.append(line)
3395
            # for flowMark in [item for item in symbols if type(item) is QEngineeringFlowMarkItem]:
3396
            #    for line in lines:
3397
            #        if flowMark.owner is line:
3398
            #            line._flowMark.append(flowMark)
3399
            #            flowMark.setParentItem(line)
3400
            # up to here
3401

    
3402
            """
3403
            group_box = QGroupBox("Contact Details")
3404
            number_label = QLabel("Telephone number");
3405
            number_edit = QTextEdit('hello\nthis is ....')
3406
            layout = QFormLayout()
3407
            layout.addRow(number_label, number_edit)
3408
            group_box.setLayout(layout)
3409

3410
            proxy =  ㅐ()
3411
            proxy.setWidget(group_box)
3412
            self.graphicsView.scene().addItem(proxy)  # (group_box, QGraphicsItem.ItemIgnoresTransformations)
3413
            """
3414

    
3415
            """ update scene """
3416
            _items = [_item for _item in self.graphicsView.scene().items() if hasattr(_item, 'owner') or hasattr(_item, 'connectors')]
3417
            if _items:
3418
                items = divide_chunks(_items, App.THREAD_MAX_WORKER if len(_items) > App.THREAD_MAX_WORKER else len(_items))
3419
                with futures.ThreadPoolExecutor(max_workers=App.THREAD_MAX_WORKER) as pool:
3420
                    future_items = {pool.submit(update_items, _items): _items for _items in items}
3421
                    for future in futures.as_completed(future_items):
3422
                        _items = future.result()
3423
                        self.progress.setValue(self.progress.value() + len(_items))
3424

    
3425
            """
3426
            for item in [_item for _item in self.graphicsView.scene().items() if hasattr(_item, 'owner') or hasattr(_item, 'connectors')]:
3427
                up_progress = False
3428
                # binding items
3429
                item.owner
3430
                for connector in item.connectors:
3431
                    connector.connectedItem
3432

3433
                self.progress.setValue(self.progress.value() + 1)
3434
            """
3435

    
3436
            for item in self.graphicsView.scene().items():
3437
                item.setVisible(True)
3438

    
3439
            self.graphicsView.scene().update(self.graphicsView.sceneRect())
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
        finally:
3445
            self.itemTreeWidget.update_item_count()
3446
            self.itemTreeWidget.expandAll()
3447
            self.graphicsView.scene().blockSignals(False)
3448

    
3449
    '''
3450
        @brief      Remove added item on same place and Add GraphicsItem
3451
        @author     Jeongwoo
3452
        @date       2018.05.29
3453
        @history    2018.06.18  Jeongwoo    Set Z-index
3454
    '''
3455
    def addLineItemToScene(self, lineItem):
3456
        self.graphicsView.scene().addItem(lineItem)
3457

    
3458
    '''
3459
        @brief      generate output xml file
3460
        @author     humkyung
3461
        @date       2018.04.23
3462
        @history    2018.05.02  Jeongwoo    Show MessageBox when imageviewer doesn't have image
3463
    '''
3464
    def generateOutput(self):
3465
        import XmlGenerator as xg
3466

    
3467
        if not self.graphicsView.hasImage():
3468
            self.showImageSelectionMessageBox()
3469
            return
3470

    
3471
        try:
3472
            appDocData = AppDocData.instance()
3473

    
3474
            # collect items
3475
            appDocData.lines.clear()
3476
            appDocData.lines = [item for item in self.graphicsView.scene().items() if
3477
                                type(item) is QEngineeringLineItem and item.owner is None]
3478

    
3479
            appDocData.symbols.clear()
3480
            appDocData.symbols = [item for item in self.graphicsView.scene().items() if
3481
                                  issubclass(type(item), SymbolSvgItem) and item.owner is None]
3482

    
3483
            appDocData.equipments.clear()
3484
            for item in self.graphicsView.scene().items():
3485
                if type(item) is QEngineeringEquipmentItem:
3486
                    appDocData.equipments.append(item)
3487

    
3488
            appDocData.texts.clear()
3489
            appDocData.texts = [item for item in self.graphicsView.scene().items() if
3490
                                issubclass(type(item), QEngineeringTextItem) and type(
3491
                                    item) is not QEngineeringLineNoTextItem]
3492
            # up to here
3493

    
3494
            appDocData.imgOutput = np.ones((appDocData.activeDrawing.height, appDocData.activeDrawing.width),
3495
                                           np.uint8) * 255
3496
            xg.writeOutputXml(appDocData.imgName, appDocData.activeDrawing.width,
3497
                              appDocData.activeDrawing.height)  # TODO: check
3498
            project = appDocData.getCurrentProject()
3499
            cv2.imwrite(os.path.join(project.getTempPath(), 'OUTPUT.png'), appDocData.imgOutput)
3500
        except Exception as ex:
3501
            message = 'error occurred({}) in {}:{}'.format(ex, sys.exc_info()[-1].tb_frame.f_code.co_filename,
3502
                                                           sys.exc_info()[-1].tb_lineno)
3503
            self.addMessage.emit(MessageType.Error, message)
3504

    
3505
    '''
3506
        @brief      Check Number
3507
        @author     kyouho
3508
        @date       2018.08.20
3509
    '''
3510
    def isNumber(self, num):
3511
        p = re.compile('(^[0-9]+$)')
3512
        result = p.match(num)
3513

    
3514
        if result:
3515
            return True
3516
        else:
3517
            return False
3518

    
3519
    '''
3520
        @brief      find overlap Connector
3521
        @author     kyouho
3522
        @date       2018.08.28
3523
    '''
3524
    def findOverlapConnector(self, connectorItem):
3525
        from shapely.geometry import Point
3526
        from EngineeringConnectorItem import QEngineeringConnectorItem
3527
        itemList = []
3528

    
3529
        x = connectorItem.center()[0]
3530
        y = connectorItem.center()[1]
3531

    
3532
        connectors = [item for item in self.graphicsView.scene().items() if
3533
                      type(item) is QEngineeringConnectorItem and item != connectorItem]
3534
        for connector in connectors:
3535
            if Point(x, y).distance(Point(connector.center()[0], connector.center()[1])) < 5:
3536
                itemList.append(connector.parent)
3537

    
3538
        return itemList
3539

    
3540
    def make_diff_image(self):
3541
        """ make diff image """
3542
        # test
3543

    
3544
        from RecognitionDialog import Worker
3545
        from symbol import Symbol
3546
        import math
3547
        from PIL import Image
3548

    
3549
        app_doc_data = AppDocData.instance()
3550
        img = app_doc_data.imgSrc.copy()
3551

    
3552
        # check break
3553
        symbols = [item for item in self.graphicsView.scene().items() if issubclass(type(item), SymbolSvgItem)]
3554

    
3555
        for symbol in symbols:
3556
            rect = symbol.sceneBoundingRect()
3557
            sName = symbol.name
3558
            sType = symbol.type
3559
            sp = (rect.x(), rect.y())
3560
            w, h = rect.width(), rect.height()
3561
            rotatedAngle = round(math.degrees(symbol.angle))
3562
            detectFlip = symbol.flip
3563

    
3564
            dummySym = Symbol(sName, sType, sp, w, h, 0, 0, 0, rotatedAngle,
3565
                                   1, 0, 1, 0,
3566
                                   ','.join(str(x) for x in [0, 0]),
3567
                                   '/'.join('{},{},{},{}'.format(param[0], param[1], param[2], param[3]) for param in
3568
                                            []),
3569
                                   'dummy', 'dummy', 0, detectFlip=detectFlip,
3570
                                   hasInstrumentLabel=0, text_area='')
3571

    
3572
            Worker.remove_detected_symbol_image(dummySym, img, lock=False)
3573

    
3574
        Image.fromarray(img).show()
3575

    
3576
    #def paintEvent(self, event):
3577
    #    self.refresh_rate += 1
3578
    #    if self.refresh_rate == 3:
3579
    #        super(self.__class__, self).paintEvent(event)
3580
    #        self.refresh_rate = 0
3581

    
3582
if __name__ == '__main__':
3583
    import locale
3584
    from PyQt5.QtCore import QTranslator
3585
    from License import QLicenseDialog
3586
    from ProjectDialog import Ui_Dialog
3587
    from App import App
3588

    
3589
    app = App(sys.argv)
3590
    try:
3591
        if True == QLicenseDialog.check_license_key():
3592
            dlg = Ui_Dialog()
3593
            selectedProject = dlg.showDialog()
3594
            if selectedProject is not None:
3595
                AppDocData.instance().setCurrentProject(selectedProject)
3596
                app._mainWnd = MainWindow.instance()
3597
                app._mainWnd.show()
3598
                sys.exit(app.exec_())
3599
    except Exception as ex:
3600
        print('error occurred({}) in {}:{}'.format(ex, sys.exc_info()[-1].tb_frame.f_code.co_filename,
3601
                                                   sys.exc_info()[-1].tb_lineno))
3602
    finally:
3603
        pass
클립보드 이미지 추가 (최대 크기: 500 MB)