프로젝트

일반

사용자정보

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

hytos / DTI_PID / DTI_PID / MainWindow.py @ 82bbc6bc

이력 | 보기 | 이력해설 | 다운로드 (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
        # create short line
813
        if lines:
814
            new_lines = []
815
            try:
816
                '''
817
                conns = []
818
                for sym in symbols:
819
                    if sym.conn_type:
820
                        for index in range(len(sym.conn_type)):
821
                            if sym.conn_type[index] == 'Secondary' or sym.conn_type[index] == 'Primary':
822
                                item = sym.connectors[index].connectedItem
823
                                if item is None:
824
                                    conns.append(sym.connectors[index])
825
                
826
                new_lines.extend(Worker.make_short_lines_sts(conns, None))
827

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

839
                for line in new_lines:
840
                    self.graphicsView.scene().addItem(line)
841
                    for conn in line.connectors:
842
                        conn.transfer.onPosChanged.connect(line.onConnectorPosChaned)
843
                '''
844
            except Exception as ex:
845
                message = f"error occurred({repr(ex)}) in {sys.exc_info()[-1].tb_frame.f_code.co_filename}:" \
846
                          f"{sys.exc_info()[-1].tb_lineno}"
847
                self.addMessage.emit(MessageType.Error, message)
848
        # up to here
849
                
850
            # connect line to symbol
851
            try:
852
                for line in lines:
853
                    matches = [_symbol for _symbol in symbols if _symbol.is_connectable(line, toler=toler)]
854
                    for _symbol in matches:
855
                        detector.connectLineToSymbol(line, _symbol, toler=toler)
856
            except Exception as ex:
857
                message = f"error occurred({repr(ex)}) in {sys.exc_info()[-1].tb_frame.f_code.co_filename}:" \
858
                          f"{sys.exc_info()[-1].tb_lineno}"
859
                self.addMessage.emit(MessageType.Error, message)
860
            # up to here
861

    
862
            # connect line to line
863
            try:
864
                for line in lines:
865
                    matches = [it for it in lines if (it is not line) and (not line.isParallel(it))]
866

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

    
875
            # connect end break
876
            usedItemPairs = []
877
            for end_break in end_breaks:
878
                if end_break.prop('Freeze') or end_break.owner or end_break.prop('Connected Item'):
879
                    usedItemPairs.append([end_break.owner, end_break.prop('Connected Item')])
880

    
881
            for end_break in end_breaks:
882
                if end_break.prop('Freeze') or end_break.owner or end_break.prop('Connected Item'):
883
                    continue
884

    
885
                originPoint = Point(end_break.origin[0], end_break.origin[1])
886
                minD = sys.maxsize
887
                ownerItem = None
888
                connectedItem = None
889

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

    
897
                        minD = dist
898
                        ownerItem = symbol
899
                        connectedItem = conn.connectedItem
900

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

    
909
                        minD = dist
910
                        ownerItem = line
911
                        connectedItem = conn.connectedItem
912

    
913
                if ownerItem and connectedItem:
914
                    end_break.set_property('Connected Item', connectedItem)
915
                    end_break.setToolTip('owner : ' + str(ownerItem))
916
                    end_break.owner = ownerItem
917
                    end_break.set_property('Freeze', True)
918

    
919
                    usedItemPairs.append([ownerItem, connectedItem])
920
            # up to here
921

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

    
924
    def on_recognize_line(self):
925
        """recognize lines in selected area"""
926
        from RecognizeLineCommand import RecognizeLineCommand
927

    
928
        if not self.graphicsView.hasImage():
929
            self.actionOCR.setChecked(False)
930
            self.showImageSelectionMessageBox()
931
            return
932

    
933
        cmd = RecognizeLineCommand(self.graphicsView)
934
        cmd.onSuccess.connect(self.on_success_to_recognize_line)
935
        cmd.onRejected.connect(self.onCommandRejected)
936
        self.graphicsView.command = cmd
937

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

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

    
957
            detector = LineDetector(img)
958
            lines = detector.detect_line_without_symbol()
959
            for line in lines:
960
                vertices = [[line[0][0] + x, line[0][1] + y], [line[1][0] + x, line[1][1] + y]]
961
                line_item = QEngineeringGraphicsLineItem(vertices)
962
                self.graphicsView.scene().addItem(line_item)
963

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

    
969
    def display_number_of_items(self):
970
        """display count of symbol, line, text"""
971

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

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

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

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

    
990
        self.itemTreeWidget.sceneChanged(self.graphicsView.scene().items())
991

    
992
    def dbUpdate(self):
993
        """ no more used """
994
        """db update when save or recognition"""
995

    
996
        try:
997
            appDocData = AppDocData.instance()
998
            items = appDocData.allItems
999

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

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

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

    
1039
    def save_drawing_if_necessary(self):
1040
        """ask to user to save drawing or not when drawing is modified"""
1041

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

    
1055
    def actionSaveCliked(self):
1056
        """
1057
        save current drawing
1058
        @return:
1059
        """
1060
        from EngineeringAbstractItem import QEngineeringAbstractItem
1061
        from SaveWorkCommand import SaveWorkCommand
1062

    
1063
        try:
1064
            home_pane = self.ribbon.get_pane('Home File')
1065
            if not home_pane.ui.toolButtonFileSave.isEnabled():
1066
                return
1067

    
1068
            home_pane.ui.toolButtonFileSave.setEnabled(False)
1069

    
1070
            # save alarm
1071
            self.save_alarm_enable(False)
1072

    
1073
            app_doc_data = AppDocData.instance()
1074
            if app_doc_data.imgName is None:
1075
                self.showImageSelectionMessageBox()
1076
                return
1077

    
1078
            app_doc_data.clearItemList(False)
1079

    
1080
            items = self.graphicsView.scene().items()
1081

    
1082
            self._save_work_cmd = SaveWorkCommand(self.graphicsView.scene())
1083
            self._save_work_cmd.show_progress.connect(self.progress_bar.setValue)
1084
            self._save_work_cmd.display_message.connect(self.onAddMessage)
1085
            self._save_work_cmd.finished.connect(self.save_finished)
1086

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

    
1093
    def save_finished(self):
1094
        """
1095
        reload drawing list when save is finished
1096
        @return: None
1097
        """
1098

    
1099
        try:
1100
            self._save_work_cmd.show_progress.emit(100)
1101
            QMessageBox.about(self.graphicsView, self.tr('Information'), self._save_work_cmd.resultStr)
1102
            self.load_drawing_list()
1103

    
1104
            app_doc_data = AppDocData.instance()
1105
            app_doc_data.activeDrawing.modified = False
1106
            title = self.windowTitle()
1107
            self.setWindowTitle(title[:-1] if title[-1] == '*' else title)
1108

    
1109
            # save alarm
1110
            self.save_alarm_enable(True)
1111
        finally:
1112
            home_pane = self.ribbon.get_pane('Home File')
1113
            home_pane.ui.toolButtonFileSave.setEnabled(True)
1114

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

    
1125
    '''
1126
        @brief  add message listwidget
1127
        @author humkyung
1128
        @date   2018.07.31
1129
    '''
1130
    def onAddMessage(self, messageType, message):
1131
        from AppDocData import MessageType
1132

    
1133
        try:
1134
            current = QDateTime.currentDateTime()
1135

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

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

    
1148
    def on_clear_log(self):
1149
        """clear log"""
1150
        self.listWidgetLog.clear()
1151

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

    
1159
    def onAreaZoom(self):
1160
        """Area Zoom"""
1161
        visualization_pane = self.ribbon.get_pane('Home Visualization')
1162

    
1163
        self.update_action_group(visualization_pane.ui.toolButtonZoom)
1164
        if visualization_pane.ui.toolButtonZoom.isChecked():
1165
            cmd = AreaZoomCommand.AreaZoomCommand(self.graphicsView)
1166
            cmd.onRejected.connect(self.onCommandRejected)
1167
            self.graphicsView.command = cmd
1168

    
1169
    def onVendor(self, action):
1170
        """make vendor/equipment package area"""
1171

    
1172
        pane = self.ribbon.get_pane('Home')
1173
        if not self.graphicsView.hasImage():
1174
            pane.ui.toolButtonVendor.setChecked(False)
1175
            self.showImageSelectionMessageBox()
1176
            return
1177

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

    
1186
        self.graphicsView.command = pane.ui.toolButtonVendor.tag
1187

    
1188
    def onVendorCreated(self):
1189
        """add created vendor polygon area to scene"""
1190

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

    
1208
    def fitWindow(self, view_rect: QRectF = QRectF()):
1209
        """Fit Window"""
1210
        self.graphicsView.useDefaultCommand()
1211
        self.graphicsView.zoomImageInit()
1212

    
1213
        visualization_pane = self.ribbon.get_pane('Home Visualization')
1214
        self.update_action_group(visualization_pane.ui.toolButtonFitWindow)
1215
        if view_rect:
1216
            self.graphicsView.zoom_rect(view_rect)
1217

    
1218
    def on_toggle_lock_axis(self):
1219
        """toggle lock axis"""
1220
        from EngineeringPolylineItem import QEngineeringPolylineItem
1221

    
1222
        visualization_pane = self.ribbon.get_pane('Home Visualization')
1223
        if self.sender() is not visualization_pane.ui.toolButtonLockAxis:
1224
            checked = visualization_pane.ui.toolButtonLockAxis.isChecked()
1225
            visualization_pane.ui.toolButtonLockAxis.setChecked(not checked)
1226

    
1227
        checked = visualization_pane.ui.toolButtonLockAxis.isChecked()
1228
        QEngineeringPolylineItem.DRAWING_MODE = QEngineeringPolylineItem.AXIS_MODE if checked else \
1229
            QEngineeringPolylineItem.FREE_MODE
1230

    
1231
    def scene_changed(self):
1232
        """update modified flag"""
1233

    
1234
        self.display_number_of_items()
1235

    
1236
        app_doc_data = AppDocData.instance()
1237
        app_doc_data.activeDrawing.modified = True
1238
        title = self.windowTitle()
1239
        self.setWindowTitle(title if title[-1] == '*' else title + '*')
1240

    
1241
    def onConvertPDFToImage(self):
1242
        """convert to selected pdf to image"""
1243
        import os
1244

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

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

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

    
1277
    def on_export_PDF(self):
1278
        if not self.graphicsView.hasImage():
1279
            self.showImageSelectionMessageBox()
1280
            return
1281

    
1282
        try:
1283
            printer = QPrinter(QPrinter.HighResolution)
1284
            #printer.setPageSize(QPrinter.A4)
1285
            printer.setOrientation(QPrinter.Orientation.Landscape)
1286
            dialog = QPrintDialog(printer)
1287
            if (dialog.exec() == QDialog.Accepted):
1288
                painter = QPainter(printer)
1289
                isfull_print = False
1290

    
1291
                scene = self.graphicsView.scene()
1292

    
1293
                #for item in scene.items():
1294
                #    if not hasattr(item, 'connectors'): continue
1295
                #    for connector in item.connectors: connector.setVisible(False)
1296

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

    
1304
                QMessageBox.about(self, self.tr("Information"), self.tr('Successfully saved.'))
1305
                #for item in scene.items():
1306
                #    if not hasattr(item, 'connectors'): continue
1307
                #    for connector in item.connectors: connector.setVisible(True)
1308

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

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

    
1325
    def on_help(self):
1326
        """ open help file """
1327
        import os
1328

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

    
1340
    def on_readme(self):
1341
        """open readme.html"""
1342

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

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

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

    
1380
            return
1381

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

    
1392
                scene = self.graphicsView.scene()
1393
                pixmap = self.graphicsView.getPixmapHandle()
1394
                scene.removeItem(pixmap)    # disconnect pixmap from scene
1395
                scene.clear()               # remove all items from scene and then delete them
1396
                scene.addItem(pixmap)       # add pixmap
1397

    
1398
                if self.path is not None:
1399
                    baseName = os.path.basename(self.path)
1400
                    self.itemTreeWidget.setCurrentPID(baseName)
1401

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

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

    
1416
        checked = [ui_ for ui_ in actions if ui_.isChecked()]
1417
        return checked[0] if checked else None
1418

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

    
1429
        if hasattr(ui, 'tag'):
1430
            ui.tag.onRejected.emit(None)
1431

    
1432
        if self.graphicsView.command is not None:
1433
            self.graphicsView.useDefaultCommand()
1434

    
1435
        for ui_ in actions:
1436
            ui_.setChecked(False)
1437

    
1438
        ui.setChecked(True)
1439

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

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

    
1474
    def onAreaOcr(self):
1475
        """Area OCR"""
1476
        if not self.graphicsView.hasImage():
1477
            self.actionOCR.setChecked(False)
1478
            self.showImageSelectionMessageBox()
1479
            return
1480

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

    
1493
    def onRecognizeText(self, x, y, width, height, show=True):
1494
        """show text recognition dialog"""
1495
        from OcrResultDialog import QOcrResultDialog
1496
        from Area import Area
1497

    
1498
        try:
1499
            app_doc_data = AppDocData.instance()
1500

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

    
1514
            if QDialog.Accepted == res and textInfoList:
1515
                for textInfo in textInfoList:
1516
                    item = QEngineeringTextItem.create_text_with(self.graphicsView.scene(), textInfo)
1517
                    if item:
1518
                        item.setDefaultTextColor(Qt.blue)
1519
                        item.transfer.onRemoved.connect(self.itemRemoved)
1520

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

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

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

    
1560
    '''
1561
        @brief  configuration
1562
    '''
1563
    def configuration(self):
1564
        from ConfigurationDialog import QConfigurationDialog
1565

    
1566
        dlgConfiguration = QConfigurationDialog(self)
1567
        if QDialog.Accepted == dlgConfiguration.exec_():
1568
            QEngineeringLineItem.LINE_TYPE_COLORS.clear()
1569
            QEngineeringInstrumentItem.INST_COLOR = None
1570

    
1571
    '''
1572
        @brief  show special item types dialog 
1573
        @author humkyung
1574
        @date   2019.08.10
1575
    '''
1576
    def on_show_special_item_types(self):
1577
        from SpecialItemTypesDialog import QSpecialItemTypesDialog
1578

    
1579
        dlg = QSpecialItemTypesDialog(self)
1580
        dlg.exec_()
1581

    
1582
    def on_show_data_transfer(self):
1583
        """ show data transfer dialog """
1584
        from DataTransferDialog import QDataTransferDialog
1585

    
1586
        dlg = QDataTransferDialog(self)
1587
        dlg.exec_()
1588

    
1589
    def on_show_data_export(self):
1590
        """ show data export dialog """
1591
        from DataExportDialog import QDataExportDialog
1592

    
1593
        dlg = QDataExportDialog(self)
1594
        dlg.exec_()
1595

    
1596
    def on_show_eqp_datasheet_export(self):
1597
        """ show eqp datasheet export dialog """
1598
        from EqpDatasheetExportDialog import QEqpDatasheetExportDialog
1599

    
1600
        dlg = QEqpDatasheetExportDialog(self)
1601
        dlg.exec_()
1602

    
1603
    def on_show_opc_relation(self):
1604
        """ show opc relation dialog """
1605
        from OPCRelationDialog import QOPCRelationDialog
1606

    
1607
        dlg = QOPCRelationDialog(self)
1608
        dlg.exec_()
1609

    
1610
    '''
1611
        @brief  show nominal diameter dialog 
1612
        @author humkyung
1613
        @date   2018.06.28
1614
    '''
1615
    def onShowCodeTable(self):
1616
        from CodeTableDialog import QCodeTableDialog
1617

    
1618
        dlg = QCodeTableDialog(self)
1619
        dlg.show()
1620
        dlg.exec_()
1621
        if dlg.code_area:
1622
            if dlg.code_area.scene():
1623
                self.graphicsView.scene().removeItem(dlg.code_area)
1624
        if dlg.desc_area:
1625
            if dlg.desc_area.scene():
1626
                self.graphicsView.scene().removeItem(dlg.desc_area)
1627
        self.graphicsView.useDefaultCommand()
1628

    
1629
    def on_ext_app_connection(self):
1630
        from TcpServer import TcpServer
1631

    
1632
        app_doc_data = AppDocData.instance()
1633

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

    
1647
    def on_execute_ext_app(self):
1648
        """execute external application"""
1649
        from ExtAppsDialog import QExtAppsDialog
1650

    
1651
        dlg = QExtAppsDialog(self)
1652
        dlg.exec_()
1653

    
1654
    def onShowCustomCodeTable(self):
1655
        from CustomCodeTablesDialog import CustomCodeTablesDialog
1656

    
1657
        dlg = CustomCodeTablesDialog(self)
1658
        dlg.show()
1659
        dlg.exec_()
1660
        self.graphicsView.useDefaultCommand()
1661

    
1662
    def onShowReplaceCodeTable(self):
1663
        from CustomCodeTablesDialog import CustomCodeTablesDialog
1664

    
1665
        dlg = CustomCodeTablesDialog(self, replace=True)
1666
        dlg.show()
1667
        dlg.exec_()
1668
        self.graphicsView.useDefaultCommand()
1669

    
1670
    def on_streamline(self):
1671
        """pop up stream line dialog"""
1672
        from StreamlineDialog import QStreamlineDialog
1673

    
1674
        if not self.graphicsView.hasImage():
1675
            self.showImageSelectionMessageBox()
1676
            return
1677

    
1678
        hmbs = AppDocData.instance().get_hmb_data(None)
1679
        if not hmbs:
1680
            return
1681

    
1682
        dlg = QStreamlineDialog(self)
1683
        dlg.show()
1684

    
1685
    def onHMBData(self):
1686
        """show HMB data"""
1687
        from HMBDialog import QHMBDialog
1688

    
1689
        dlg = QHMBDialog(self)
1690
        dlg.show()
1691
        dlg.exec_()
1692

    
1693
    '''
1694
        @brief  show line data list 
1695
        @author humkyung
1696
        @date   2018.05.03
1697
    '''
1698
    def showItemDataList(self):
1699
        from ItemDataExportDialog import QItemDataExportDialog
1700

    
1701
        dlg = QItemDataExportDialog(self)
1702
        dlg.exec_()
1703

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

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

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

    
1731
    def on_search_text_changed(self):
1732
        """filter symbol tree view"""
1733
        regexp = QRegExp(self.lineEditFilter.text(), Qt.CaseInsensitive, QRegExp.FixedString)
1734

    
1735
        proxy_model = self.symbolTreeWidget.model()
1736
        proxy_model.text = self.lineEditFilter.text().lower()
1737
        proxy_model.setFilterRegExp(regexp)
1738

    
1739
        self.symbolTreeWidget.expandAll()
1740

    
1741
    def change_display_colors(self):
1742
        """ change display color mode """
1743
        visualization_pane = self.ribbon.get_pane('Home Visualization')
1744
        if visualization_pane.ui.radioButtonByGroup.isChecked():
1745
            visualization_pane.ui.radioButtonByType.setChecked(True)
1746
        else:
1747
            visualization_pane.ui.radioButtonByGroup.setChecked(True)
1748

    
1749
    def display_colors(self, value):
1750
        """ display colors """
1751
        from DisplayColors import DisplayColors
1752
        from DisplayColors import DisplayOptions
1753

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

    
1763
            if hasattr(self, 'graphicsView') and value is True:
1764
                self.graphicsView.scene().update(self.graphicsView.sceneRect())
1765
                for item in self.graphicsView.scene().items():
1766
                    if issubclass(type(item), SymbolSvgItem):
1767
                        item.update()
1768
                DisplayColors.instance().save_data()
1769

    
1770
    def open_image_drawing(self, drawing, force=False, ocrUnknown=False):
1771
        """open and display image drawing file"""
1772
        from Drawing import Drawing
1773
        from App import App
1774
        from LoadCommand import LoadCommand
1775
        import concurrent.futures as futures
1776

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

    
1784
        def update_items(items):
1785
            for item in items:
1786
                # binding items
1787
                item.owner
1788
                for connector in item.connectors:
1789
                    connector.connectedItem
1790

    
1791
            return items
1792

    
1793
        try:
1794
            app_doc_data = AppDocData.instance()
1795

    
1796
            if not self.actionSave.isEnabled():
1797
                return
1798

    
1799
            if not force and self.save_drawing_if_necessary():
1800
                return
1801

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

    
1808
            # save alarm
1809
            self.save_alarm_enable(False)
1810

    
1811
            if hasattr(self, '_save_work_cmd'):
1812
                self._save_work_cmd.wait()
1813

    
1814
            project = app_doc_data.getCurrentProject()
1815

    
1816
            self.path = self.graphicsView.loadImageFromFile(drawing)
1817
            if os.path.isfile(self.path):
1818
                self.onCommandRejected()
1819
                app_doc_data.clear(past=drawing.UID)
1820

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

    
1833
                app_doc_data.setImgFilePath(self.path)
1834
                app_doc_data.activeDrawing = drawing
1835
                
1836
                #app_doc_data.activeDrawing.set_pid_source(Image.open(self.path))
1837
                self.itemTreeWidget.setCurrentPID(app_doc_data.activeDrawing.name)
1838

    
1839
                drawingList = self.treeWidgetDrawingList.topLevelItem(0)
1840
                for idx in range(drawingList.childCount()):
1841
                    child = drawingList.child(idx)
1842
                    if child.data(Qt.UserRole, 0) is drawing:
1843
                        child.setCheckState(0, Qt.Checked)
1844
                    else:
1845
                        child.setCheckState(0, Qt.Unchecked)
1846

    
1847
                try:
1848
                    self.show_Progress_bar()
1849

    
1850
                    # disconnect scene changed if signal is connected
1851
                    if self.graphicsView.scene().receivers(self.graphicsView.scene().contents_changed) > 0:
1852
                        self.graphicsView.scene().contents_changed.disconnect()
1853

    
1854
                    SymbolSvgItem.DOCUMENTS.clear()
1855

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

    
1864
                    configs = app_doc_data.getConfigs('Line List', 'Use Stream No')
1865
                    if configs and int(configs[0].value) == 1:
1866
                        app_doc_data._streamLineListModelDatas = app_doc_data.get_stream_line_list_data()
1867
                    # up to here
1868

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

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

    
1888
                    for trim_line_no in app_doc_data.tracerLineNos:
1889
                        line_no_tree_item = self.itemTreeWidget.addTreeItem(self.itemTreeWidget.root, trim_line_no)
1890
                        for run in trim_line_no.runs:
1891
                            for run_item in run.items:
1892
                                if issubclass(type(run_item), SymbolSvgItem):
1893
                                    self.init_add_tree_item(line_no_tree_item, run_item)
1894

    
1895
                    self.itemTreeWidget.update_item_count()
1896
                    self.itemTreeWidget.expandAll()
1897
                    """up to here"""
1898

    
1899
                    """update scene"""
1900
                    for item in self._scene.items():
1901
                        item.setVisible(True)
1902

    
1903
                    self._scene.update(self._scene.sceneRect())
1904

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

    
1915
                    self.display_number_of_items()
1916
                    # connect scene changed signal
1917
                    self.graphicsView.scene().contents_changed.connect(self.scene_changed)
1918
                finally:
1919
                    if hasattr(self, 'progress'):
1920
                        self.progress.setValue(self.progress.maximum())
1921

    
1922
                self.changeViewCheckedState(True)
1923
                self.setWindowTitle(self.title)
1924
                self.fitWindow(drawing.view_rect)
1925

    
1926
                if ocrUnknown:
1927
                    self.on_ocr_unknown_items()
1928

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

    
1936
        return self.path
1937

    
1938
    def save_alarm_enable(self, enable, init=False):
1939
        from datetime import datetime
1940

    
1941
        try:
1942
            app_doc_data = AppDocData.instance()
1943
            configs = app_doc_data.getConfigs('Data Save', 'Time')
1944
            time_min = int(configs[0].value) if 1 == len(configs) else 0
1945

    
1946
            if enable and time_min > 0:
1947
                if not self.save_timer:
1948
                    self.save_timer = QTimer()
1949
                    self.save_timer.timeout.connect(self.save_alarm)
1950
                    self.save_timer.setInterval(60000)
1951

    
1952
                if init:
1953
                    self.save_timer._init_time = datetime.now()
1954
                    self.save_timer._stop_time = None
1955
                    self.save_timer._interval_time = datetime.now() - datetime.now()
1956

    
1957
                if self.save_timer._stop_time:
1958
                    self.save_timer._interval_time = datetime.now() - self.save_timer._stop_time
1959
                
1960
                #if 60000 * time_min != self.save_timer.interval():
1961
                #    self.save_timer.setInterval(60000)
1962

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

    
1974
    def save_alarm(self):
1975
        from datetime import datetime
1976

    
1977
        app_doc_data = AppDocData.instance()
1978
        configs = app_doc_data.getConfigs('Data Save', 'Time')
1979
        time_min = int(configs[0].value) if 1 == len(configs) else 0
1980

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

    
1988
    def export_as_svg(self):
1989
        """export scene to svg file"""
1990
        from ExportCommand import ExportCommand
1991

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

    
2004
    def export_as_xml(self):
2005
        pass
2006

    
2007
    def export_as_image(self):
2008
        """export scene to image file"""
2009
        from ExportCommand import ExportCommand
2010

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

    
2020
                cmd = ExportCommand(self.graphicsView.scene(), 'image')
2021
                cmd.display_message.connect(self.onAddMessage)
2022

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

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

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

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

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

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

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

    
2095
    def onViewLine(self, checked):
2096
        """visible/invisible line"""
2097
        selected = [item for item in self.graphicsView.scene().items() if type(item) is QEngineeringLineItem]
2098
        for item in selected:
2099
            item.setVisible(checked)
2100

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

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

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

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

    
2145
            points = []
2146
            for conn in selected[0].connectors:
2147
                points.append([round(conn.center()[0] - rect.x()), round(conn.center()[1] - rect.y())])
2148
            poly = np.array(points, np.int32)
2149

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

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

    
2162
            h, w, c = sym_img.shape
2163
            qImg = QImage(sym_img.data, w, h, w * c, QImage.Format_RGB888)
2164
            #pixmap = QPixmap.fromImage(qImg)
2165

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

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

    
2197
                        package_item.transfer.onRemoved.emit(package_item)
2198
        finally:
2199
            self.onCommandRejected()
2200
            QApplication.restoreOverrideCursor()
2201
            QApplication.restoreOverrideCursor()
2202

    
2203
    def on_line_list(self):
2204
        """ line list export dialog """
2205
        from LineListDialog import LineListDialog
2206

    
2207
        if not self.graphicsView.hasImage():
2208
            self.showImageSelectionMessageBox()
2209
            return
2210

    
2211
        dialog = LineListDialog(self)
2212
        dialog.showDialog()
2213

    
2214
    def on_make_label_data(self):
2215
        """ make label data from symbol info """
2216
        from xml.etree.ElementTree import Element, SubElement, dump, ElementTree, parse
2217

    
2218
        if not self.graphicsView.hasImage():
2219
            self.showImageSelectionMessageBox()
2220
            return
2221

    
2222
        app_doc_data = AppDocData.instance()
2223
        project = app_doc_data.getCurrentProject()
2224

    
2225
        smalls = []
2226
        bigs = []
2227

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

    
2241
        symbols = [item for item in self.graphicsView.scene().items() if issubclass(type(item), SymbolSvgItem)]
2242
        names = [smalls, bigs]
2243

    
2244
        img = app_doc_data.activeDrawing.image_origin
2245

    
2246
        small_size = 500
2247
        big_size = 850
2248

    
2249
        save_path = project.getTrainingSymbolFilePath()
2250

    
2251
        index = 0
2252
        for size in [small_size, big_size]:
2253
            offsets = [0, int(size / 2)]
2254

    
2255
            width, height = img.shape[1], img.shape[0]
2256
            width_count, height_count = width // size + 2, height // size + 2
2257
            b_width, b_height = width_count * size, height_count * size
2258
            b_img = np.zeros((b_height, b_width), np.uint8) + 255
2259
            b_img[:height, :width] = img[:, :]
2260

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

    
2272
                        if tile_symbols:
2273
                            training_uid = str(uuid.uuid4())
2274
                            training_image_path = os.path.join(save_path, training_uid + '.png')
2275
                            training_xml_path = os.path.join(save_path, training_uid + '.xml')
2276

    
2277
                            # save image
2278
                            #_img = b_img[round(tile_rect.top()):round(tile_rect.bottom()),
2279
                            #       round(tile_rect.left()):round(tile_rect.right())]
2280
                            #cv2.imwrite(training_image_path, _img)
2281
                            _img = self.graphicsView.image().copy(round(tile_rect.left()), round(tile_rect.top()), round(tile_rect.width()), round(tile_rect.height()))
2282
                            _img.save(training_image_path)
2283

    
2284
                            # save label
2285
                            xml = Element('annotation')
2286
                            SubElement(xml, 'folder').text = 'None'
2287
                            SubElement(xml, 'filename').text = os.path.basename(save_path)
2288

    
2289
                            pathNode = Element('path')
2290
                            pathNode.text = save_path.replace('/', '\\')
2291
                            xml.append(pathNode)
2292

    
2293
                            sourceNode = Element('source')
2294
                            databaseNode = Element('database')
2295
                            databaseNode.text = 'Unknown'
2296
                            sourceNode.append(databaseNode)
2297
                            xml.append(sourceNode)
2298

    
2299
                            sizeNode = Element('size')
2300
                            widthNode = Element('width')
2301
                            widthNode.text = str(int(tile_rect.width()))
2302
                            sizeNode.append(widthNode)
2303
                            heightNode = Element('height')
2304
                            heightNode.text = str(int(tile_rect.height()))
2305
                            sizeNode.append(heightNode)
2306
                            depthNode = Element('depth')
2307
                            depthNode.text = '3'
2308
                            sizeNode.append(depthNode)
2309
                            xml.append(sizeNode)
2310

    
2311
                            segmentedNode = Element('segmented')
2312
                            segmentedNode.text = '0'
2313
                            xml.append(segmentedNode)
2314

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

    
2326
                                if label == 'None' or label == '':
2327
                                    continue
2328
                                if label not in labelContent:
2329
                                    labelContent.append(label)
2330
                                    counts[label] = 1
2331
                                else:
2332
                                    counts[label] = counts[label] + 1
2333

    
2334
                                objectNode = Element('object')
2335
                                nameNode = Element('name')
2336
                                nameNode.text = label
2337
                                objectNode.append(nameNode)
2338
                                poseNode = Element('pose')
2339
                                poseNode.text = 'Unspecified'
2340
                                objectNode.append(poseNode)
2341
                                truncatedNode = Element('truncated')
2342
                                truncatedNode.text = '0'
2343
                                objectNode.append(truncatedNode)
2344
                                difficultNode = Element('difficult')
2345
                                difficultNode.text = '0'
2346
                                objectNode.append(difficultNode)
2347

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

    
2363
                                xml.append(objectNode)
2364

    
2365
                            ElementTree(xml).write(training_xml_path)
2366

    
2367
            index += 1
2368

    
2369
        QMessageBox.about(self, self.tr("Notice"), self.tr('Successfully applied. '))
2370

    
2371
    def onPlaceLine(self):
2372
        """create a line"""
2373
        home_pane = self.ribbon.get_pane('Home')
2374

    
2375
        if not self.graphicsView.hasImage():
2376
            home_pane.ui.toolButtonLine.setChecked(False)
2377
            self.showImageSelectionMessageBox()
2378
            return
2379

    
2380
        self.update_action_group(home_pane.ui.toolButtonLine)
2381
        if not hasattr(home_pane.ui.toolButtonLine, 'tag'):
2382
            home_pane.ui.toolButtonLine.tag = PlaceLineCommand.PlaceLineCommand(self.graphicsView)
2383
            home_pane.ui.toolButtonLine.tag.onSuccess.connect(self.onLineCreated)
2384
            home_pane.ui.toolButtonLine.tag.onRejected.connect(self.onCommandRejected)
2385

    
2386
        self.graphicsView.command = home_pane.ui.toolButtonLine.tag
2387

    
2388
    def onLineCreated(self):
2389
        """add created lines to scene"""
2390
        from EngineeringConnectorItem import QEngineeringConnectorItem
2391
        from LineDetector import LineDetector
2392

    
2393
        try:
2394
            app_doc_data = AppDocData.instance()
2395
            home_pane = self.ribbon.get_pane('Home')
2396

    
2397
            count = len(home_pane.ui.toolButtonLine.tag._polyline._vertices)
2398
            if count > 1:
2399
                items = []
2400

    
2401
                detector = LineDetector(None)
2402

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

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

    
2434
                    items.append(lineItem)
2435
                    self.graphicsView.scene().addItem(lineItem)
2436

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

    
2447
                self._scene.undo_stack.push(CreateCommand(self._scene, items))
2448
        finally:
2449
            self.graphicsView.scene().removeItem(home_pane.ui.toolButtonLine.tag._polyline)
2450
            home_pane.ui.toolButtonLine.tag.reset()
2451

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

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

    
2482
    def on_view_toggle(self, key: int) -> None:
2483
        """view toggled"""
2484

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

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

    
2530
                textItems = [text for text in self.graphicsView.scene().selectedItems() if
2531
                             issubclass(type(text), QEngineeringTextItem)]
2532
                if not textItems or len(textItems) is 1:
2533
                    return
2534

    
2535
                angle = None
2536
                for item in textItems:
2537
                    if angle is None:
2538
                        angle = item.angle
2539
                    else:
2540
                        if angle != item.angle:
2541
                            return
2542

    
2543
                modifiers = QApplication.keyboardModifiers()
2544
                enter_or_space = ' ' if modifiers == Qt.ControlModifier else '\n'
2545
                x_or_y = 0 if (modifiers == Qt.ControlModifier and angle == 0) or (modifiers != Qt.ControlModifier and angle == 1.57) else 1
2546

    
2547
                textItems = sorted(textItems, key=lambda text: text.loc[x_or_y]) if textItems[0].angle == 0 else ( \
2548
                    sorted(textItems, key=lambda text: text.loc[x_or_y]) if textItems[0].angle == 1.57 else ( \
2549
                        sorted(textItems, key=lambda text: text.loc[x_or_y], reverse=True) if textItems[0].angle == 4.71 else \
2550
                            sorted(textItems, key=lambda text: text.loc[x_or_y], reverse=True)))
2551

    
2552
                if textItems[0].angle == 1.57 and modifiers == Qt.ControlModifier:
2553
                    textItems.reverse()
2554

    
2555
                minX = sys.maxsize
2556
                minY = sys.maxsize
2557
                maxX = 0
2558
                maxY = 0
2559
                newText = ''
2560

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

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

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

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

    
2616
                svg = QtImageViewer.createSymbolObject(symName)
2617
                QtImageViewer.matchSymbolToLine(self.graphicsView.scene(), svg, scenePos, angle=old_symbol.angle if old_symbol else 0.0)
2618

    
2619
                if old_symbol and svg:
2620
                    from ReplaceCommand import ReplaceCommand
2621

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

    
2636
                symbolItems = [symbol for symbol in self.graphicsView.scene().selectedItems() if
2637
                               issubclass(type(symbol), SymbolSvgItem)]
2638
                if symbolItems and len(symbolItems) is not 1:
2639
                    return
2640
                    
2641
                target_symbol = symbolItems[0]
2642
                index =  [index for index in range(len(target_symbol.conn_type)) \
2643
                            if target_symbol.conn_type[index] == 'Primary' or target_symbol.conn_type[index] == 'Secondary']
2644
                for connector in target_symbol.connectors:
2645
                    svg = QtImageViewer.createSymbolObject(symName)
2646
                    if 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 or (connector.connectedItem and type(connector.connectedItem) is QEngineeringLineItem)):
2649
                            QtImageViewer.matchSymbolToLine(self.graphicsView.scene(), svg, connector.sceneBoundingRect().center())
2650
                    elif len(svg.connectors) == 1:
2651
                        if ((target_symbol.conn_type and target_symbol.connectors.index(connector) in index) or not target_symbol.conn_type) and \
2652
                                    not connector.connectedItem:
2653
                            QtImageViewer.matchSymbolToLine(self.graphicsView.scene(), svg, connector.sceneBoundingRect().center())
2654

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

    
2673
                app_doc_data = AppDocData.instance()
2674
                scene_to_dexpi('D:\\Temp\\DEXPI.xml', app_doc_data.activeDrawing.name, self.graphicsView.scene())
2675

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

    
2682
    def recognize(self):
2683
        """recognize symbol, text and line for selected drawings"""
2684
        from datetime import datetime
2685
        from License import QLicenseDialog
2686

    
2687
        # save alarm
2688
        self.save_alarm_enable(False)
2689

    
2690
        app_doc_data = AppDocData.instance()
2691
        current_drawing, currentPid = None, None
2692

    
2693
        if self.graphicsView.hasImage():
2694
            current_drawing = app_doc_data.activeDrawing
2695
            currentPid = app_doc_data.activeDrawing.name
2696

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

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

    
2714
        if not checked_drawings:
2715
            self.showImageSelectionMessageBox()
2716
            return
2717

    
2718
        try:
2719
            self.on_clear_log()
2720
            dlg = QRecognitionDialog(self, [drawing for drawing in checked_drawings.keys()])
2721
            dlg.exec_()
2722

    
2723
            if current_drawing and current_drawing in checked_drawings.keys() and dlg.isTreated:
2724
                self.open_image_drawing(current_drawing, force=True, ocrUnknown=dlg.ui.checkBoxOCRUnknown.isChecked())
2725

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

    
2741
        # save alarm
2742
        self.save_alarm_enable(True, True)
2743

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

    
2758
                if item.scene() is not None:
2759
                    item.scene().removeItem(item)
2760
                del item
2761
            else:
2762
                remove_scene = item.scene()
2763
                self.itemTreeWidget.itemRemoved(item)
2764

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

    
2775
                # matches = [_item for _item in self.graphicsView.scene().items() if hasattr(_item, 'remove_assoc_item')]
2776
                # for _item in matches:
2777
                #    _item.remove_assoc_item(item)
2778

    
2779
                app_doc_data = AppDocData.instance()
2780
                if type(item) is QEngineeringLineNoTextItem and item in app_doc_data.tracerLineNos:
2781
                    app_doc_data.tracerLineNos.pop(app_doc_data.tracerLineNos.index(item))
2782

    
2783
                if type(item) is QEngineeringLineItem and item in app_doc_data.lines:
2784
                    app_doc_data.lines.remove(item)
2785

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

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

    
2808
                if remove_scene:
2809
                    matches = [_item for _item in remove_scene.items() if hasattr(_item, 'owner')]
2810
                    for match in matches:
2811
                        if match.owner is item:
2812
                            match.owner = None
2813

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

    
2830
                if item.scene() is not None:
2831
                    #if type(item) is QEngineeringLineNoTextItem and item._labels:
2832
                    #    for _label in item._labels:
2833
                    #        item.scene().removeItem(_label)
2834
                    #    item._labels = []
2835

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

    
2847

    
2848
    def connect_attributes(self, MainWindow):
2849
        """connect attributes to symbol"""
2850
        from LineNoTracer import LineNoTracer
2851
        from ConnectAttrDialog import QConnectAttrDialog
2852

    
2853
        if not self.graphicsView.hasImage():
2854
            self.showImageSelectionMessageBox()
2855
            return
2856

    
2857
        # save alarm
2858
        self.save_alarm_enable(False)
2859

    
2860
        try:
2861
            dlg = QConnectAttrDialog(self, self.graphicsView.scene())
2862
            dlg.setWindowFlags(self.windowFlags() & ~Qt.WindowCloseButtonHint & ~Qt.WindowContextHelpButtonHint)
2863
            dlg.exec_()
2864
            if dlg.isRunned:
2865
                self.refresh_item_list()
2866

    
2867
                if dlg.validation_checked:
2868
                    self.onValidation()
2869

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

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

    
2888
        appDocData = AppDocData.instance()
2889

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

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

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

    
2921
    def init_add_tree_item(self, line_no_tree_item, run_item):
2922
        """ insert symbol item and find line no as owner """
2923
        # insert
2924
        self.itemTreeWidget.addTreeItem(line_no_tree_item, run_item)
2925
        # find
2926
        self.itemTreeWidget.addTreeItem(line_no_tree_item, run_item)
2927

    
2928
    def load_drawing(self, drawing):
2929
        """ load drawing """
2930
        """ no more used """
2931
        from EngineeringRunItem import QEngineeringRunItem
2932
        from QEngineeringTrimLineNoTextItem import QEngineeringTrimLineNoTextItem
2933

    
2934
        app_doc_data = AppDocData.instance()
2935
        try:
2936
            symbols = []
2937
            lines = []
2938

    
2939
            components = app_doc_data.get_components(drawing.UID)
2940
            maxValue = len(components) * 2
2941
            self.progress.setMaximum(maxValue) if maxValue > 0 else None
2942

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

    
2962
                self.progress.setValue(self.progress.value() + 1)
2963

    
2964
            QApplication.processEvents()
2965

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

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

    
2979
            QApplication.processEvents()
2980

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

    
2992
                self.progress.setValue(self.progress.value() + 1)
2993

    
2994
            QApplication.processEvents()
2995

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

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

    
3006
            QApplication.processEvents()
3007

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

    
3016
                self.progress.setValue(self.progress.value() + 1)
3017

    
3018
            QApplication.processEvents()
3019

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

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

    
3042
                        for run_item in line_run.items:
3043
                            if issubclass(type(run_item), SymbolSvgItem):
3044
                                self.init_add_tree_item(line_no_tree_item, run_item)
3045

    
3046
                self.progress.setValue(self.progress.value() + 1)
3047
            QApplication.processEvents()
3048

    
3049
            for component in [component for component in components if
3050
                              component['Name'] == 'Trim Line NO' and component['SymbolType_UID'] == -1]:
3051
                line_no = QEngineeringTrimLineNoTextItem()
3052
                line_no.uid = uuid.UUID(component['UID'])
3053

    
3054
                runs = app_doc_data.get_pipe_runs(str(line_no.uid))
3055
                if not runs: continue
3056

    
3057
                line_no_tree_item = self.itemTreeWidget.addTreeItem(self.itemTreeWidget.root, line_no)
3058

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

    
3071
                    for run_item in line_run.items:
3072
                        if issubclass(type(run_item), SymbolSvgItem):
3073
                            self.init_add_tree_item(line_no_tree_item, run_item)
3074

    
3075
                app_doc_data.tracerLineNos.append(line_no)
3076

    
3077
                self.progress.setValue(self.progress.value() + 1)
3078

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

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

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

    
3110
                if up_progress:
3111
                    self.progress.setValue(self.progress.value() + 1)
3112
            
3113
            for item in self.graphicsView.scene().items():
3114
                item.setVisible(True)
3115

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

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

    
3156
        def update_items(items):
3157
            for item in items:
3158
                # binding items
3159
                item.owner
3160
                for connector in item.connectors:
3161
                    connector.connectedItem
3162

    
3163
            return items
3164

    
3165
        import concurrent.futures as futures
3166
        from xml.etree.ElementTree import Element, SubElement, dump, ElementTree, parse
3167
        from App import App
3168
        from EngineeringRunItem import QEngineeringRunItem
3169
        from QEngineeringTrimLineNoTextItem import QEngineeringTrimLineNoTextItem
3170
        from EngineeringGraphicsLineItem import QEngineeringGraphicsLineItem
3171

    
3172
        app_doc_data = AppDocData.instance()
3173

    
3174
        try:
3175
            file_name = os.path.splitext(os.path.basename(drawing.file_path))[0]
3176
            path = os.path.join(app_doc_data.getCurrentProject().getTempPath(), file_name + '.xml')
3177
            self.graphicsView.scene().blockSignals(True)
3178

    
3179
            symbols = []
3180
            lines = []
3181

    
3182
            xml = parse(path)
3183
            root = xml.getroot()
3184

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

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

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

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

    
3249
                self.progress.setValue(self.progress.value() + 1)
3250

    
3251
            QApplication.processEvents()
3252

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

    
3264
                    if name == 'TEXT':
3265
                        if uid is not None and attributeValue is not None:
3266
                            item.uid = uid.text
3267
                            item.attribute = attributeValue.text
3268

    
3269
                self.progress.setValue(self.progress.value() + 1)
3270

    
3271
            QApplication.processEvents()
3272

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

    
3283
                    if name == 'NOTE':
3284
                        if uid is not None:
3285
                            item.uid = uid.text
3286

    
3287
                self.progress.setValue(self.progress.value() + 1)
3288

    
3289
            QApplication.processEvents()
3290

    
3291
            for line in root.find('LINEINFOS').iter('LINE'):
3292
                item = QEngineeringLineItem.fromXml(line)
3293
                if item:
3294
                    item.transfer.onRemoved.connect(self.itemRemoved)
3295
                    self.graphicsView.scene().addItem(item)
3296
                    lines.append(item)
3297

    
3298
                self.progress.setValue(self.progress.value() + 1)
3299

    
3300
            for line in root.find('LINEINFOS').iter('GRAPHICS_LINE'):
3301
                item = QEngineeringGraphicsLineItem.fromXml(line)
3302
                if item:
3303
                    item.transfer.onRemoved.connect(self.itemRemoved)
3304
                    self.graphicsView.scene().addItem(item)
3305

    
3306
                self.progress.setValue(self.progress.value() + 1)
3307

    
3308
            QApplication.processEvents()
3309

    
3310
            for unknown in root.iter('UNKNOWN'):
3311
                item = QEngineeringUnknownItem.fromXml(unknown)
3312
                if item is not None:
3313
                    item.transfer.onRemoved.connect(self.itemRemoved)
3314
                    self.graphicsView.scene().addItem(item)
3315

    
3316
                self.progress.setValue(self.progress.value() + 1)
3317

    
3318
            QApplication.processEvents()
3319

    
3320
            # """ add tree widget """
3321
            # for item in symbols:
3322
            #    docData.symbols.append(item)
3323
            #    self.addSvgItemToScene(item)
3324
            #    self.itemTreeWidget.addTreeItem(self.itemTreeWidget.root, item)
3325

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

    
3334
                runs_node = line_no_node.findall('RUN')
3335
                if runs_node is None: continue
3336

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

    
3350
                    for run_item in line_run.items:
3351
                        if issubclass(type(run_item), SymbolSvgItem):
3352
                            self.init_add_tree_item(line_no_tree_item, run_item)
3353

    
3354
                # docData.tracerLineNos.append(line_no)
3355

    
3356
                self.progress.setValue(self.progress.value() + 1)
3357
            QApplication.processEvents()
3358

    
3359
            for trimLineNo in root.iter('TRIM_LINE_NO'):
3360
                line_no = QEngineeringTrimLineNoTextItem()
3361
                line_no.uid = uuid.UUID(trimLineNo.find('UID').text)
3362

    
3363
                runs_node = trimLineNo.findall('RUN')
3364
                if runs_node is None: continue
3365
                line_no_tree_item = self.itemTreeWidget.addTreeItem(self.itemTreeWidget.root, line_no)
3366

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

    
3380
                    for run_item in line_run.items:
3381
                        if issubclass(type(run_item), SymbolSvgItem):
3382
                            self.init_add_tree_item(line_no_tree_item, run_item)
3383

    
3384
                app_doc_data.tracerLineNos.append(line_no)
3385

    
3386
                self.progress.setValue(self.progress.value() + 1)
3387
            QApplication.processEvents()
3388

    
3389
            if root.find('VENDORS') is not None:
3390
                for vendor in root.find('VENDORS').iter('VENDOR'):
3391
                    item = QEngineeringVendorItem.fromXml(vendor)
3392
                    item.transfer.onRemoved.connect(self.itemRemoved)
3393
                    self.graphicsView.scene().addItem(item)
3394

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

    
3406
            """
3407
            group_box = QGroupBox("Contact Details")
3408
            number_label = QLabel("Telephone number");
3409
            number_edit = QTextEdit('hello\nthis is ....')
3410
            layout = QFormLayout()
3411
            layout.addRow(number_label, number_edit)
3412
            group_box.setLayout(layout)
3413

3414
            proxy =  ㅐ()
3415
            proxy.setWidget(group_box)
3416
            self.graphicsView.scene().addItem(proxy)  # (group_box, QGraphicsItem.ItemIgnoresTransformations)
3417
            """
3418

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

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

3437
                self.progress.setValue(self.progress.value() + 1)
3438
            """
3439

    
3440
            for item in self.graphicsView.scene().items():
3441
                item.setVisible(True)
3442

    
3443
            self.graphicsView.scene().update(self.graphicsView.sceneRect())
3444
        except Exception as ex:
3445
            message = 'error occurred({}) in {}:{}'.format(ex, sys.exc_info()[-1].tb_frame.f_code.co_filename,
3446
                                                           sys.exc_info()[-1].tb_lineno)
3447
            self.addMessage.emit(MessageType.Error, message)
3448
        finally:
3449
            self.itemTreeWidget.update_item_count()
3450
            self.itemTreeWidget.expandAll()
3451
            self.graphicsView.scene().blockSignals(False)
3452

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

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

    
3471
        if not self.graphicsView.hasImage():
3472
            self.showImageSelectionMessageBox()
3473
            return
3474

    
3475
        try:
3476
            appDocData = AppDocData.instance()
3477

    
3478
            # collect items
3479
            appDocData.lines.clear()
3480
            appDocData.lines = [item for item in self.graphicsView.scene().items() if
3481
                                type(item) is QEngineeringLineItem and item.owner is None]
3482

    
3483
            appDocData.symbols.clear()
3484
            appDocData.symbols = [item for item in self.graphicsView.scene().items() if
3485
                                  issubclass(type(item), SymbolSvgItem) and item.owner is None]
3486

    
3487
            appDocData.equipments.clear()
3488
            for item in self.graphicsView.scene().items():
3489
                if type(item) is QEngineeringEquipmentItem:
3490
                    appDocData.equipments.append(item)
3491

    
3492
            appDocData.texts.clear()
3493
            appDocData.texts = [item for item in self.graphicsView.scene().items() if
3494
                                issubclass(type(item), QEngineeringTextItem) and type(
3495
                                    item) is not QEngineeringLineNoTextItem]
3496
            # up to here
3497

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

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

    
3518
        if result:
3519
            return True
3520
        else:
3521
            return False
3522

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

    
3533
        x = connectorItem.center()[0]
3534
        y = connectorItem.center()[1]
3535

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

    
3542
        return itemList
3543

    
3544
    def make_diff_image(self):
3545
        """ make diff image """
3546
        # test
3547

    
3548
        from RecognitionDialog import Worker
3549
        from symbol import Symbol
3550
        import math
3551
        from PIL import Image
3552

    
3553
        app_doc_data = AppDocData.instance()
3554
        img = app_doc_data.imgSrc.copy()
3555

    
3556
        # check break
3557
        symbols = [item for item in self.graphicsView.scene().items() if issubclass(type(item), SymbolSvgItem)]
3558

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

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

    
3576
            Worker.remove_detected_symbol_image(dummySym, img, lock=False)
3577

    
3578
        Image.fromarray(img).show()
3579

    
3580
    #def paintEvent(self, event):
3581
    #    self.refresh_rate += 1
3582
    #    if self.refresh_rate == 3:
3583
    #        super(self.__class__, self).paintEvent(event)
3584
    #        self.refresh_rate = 0
3585

    
3586
if __name__ == '__main__':
3587
    import locale
3588
    from PyQt5.QtCore import QTranslator
3589
    from License import QLicenseDialog
3590
    from ProjectDialog import Ui_Dialog
3591
    from App import App
3592

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