프로젝트

일반

사용자정보

통계
| 개정판:

hytos / DTI_PID / DTI_PID / MainWindow.py @ cf7f2a73

이력 | 보기 | 이력해설 | 다운로드 (173 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
        if self.save_drawing_if_necessary():
339
            event.ignore()
340
            return
341

    
342
        self.settings.setValue('geometry', self.saveGeometry())
343
        self.settings.setValue('windowState', self.saveState())
344
        # TODO: need to modify
345

    
346
        """save current view region"""
347
        app_doc_data = AppDocData.instance()
348
        if app_doc_data.activeDrawing:
349
            rect = self.graphicsView.viewport().rect()
350
            app_doc_data.activeDrawing.view_rect = self.graphicsView.mapToScene(rect).boundingRect()
351
            app_doc_data.update_view_region(app_doc_data.activeDrawing)
352
        """up to here"""
353

    
354
        AppDocData.instance().clear()
355
        event.accept()
356

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

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

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

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

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

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

    
429
    def onValidation(self):
430
        """validation check"""
431
        from ValidationDialog import QValidationDialog
432
        from ValidateCommand import ValidateCommand
433

    
434
        if not self.graphicsView.hasImage():
435
            self.showImageSelectionMessageBox()
436
            return
437

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

    
447
                self.progress_bar.setMaximum(len(self.graphicsView.scene().items()))
448
                self.progress_bar.setValue(0)
449

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

    
458
                self.tableWidgetInconsistency.clearContents()
459
                self.tableWidgetInconsistency.setRowCount(len(errors))
460
                for index, error in enumerate(errors):
461
                    self.makeInconsistencyTableRow(index, error)
462

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

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

    
483
        item = QTableWidgetItem(str(errorItem.parent))
484
        item.tag = errorItem
485
        self.tableWidgetInconsistency.setItem(row, 0, item)
486

    
487
        item = QTableWidgetItem(str(type(errorItem.parent)))
488
        item.tag = errorItem
489
        self.tableWidgetInconsistency.setItem(row, 1, item)
490

    
491
        item = QTableWidgetItem(errorItem.msg)
492
        item.tag = errorItem
493
        self.tableWidgetInconsistency.setItem(row, 2, item)
494

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

    
503
        HighlightCommand(self.graphicsView).execute(item.tag)
504

    
505
    def read_settings(self):
506
        """read geometry and state"""
507
        from App import App
508

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

    
517
    def load_stylesheet(self, file):
518
        """load stylesheets"""
519

    
520
        QtWidgets.qApp.loadStyleSheet(os.path.join(os.path.dirname(os.path.realpath(__file__)), file))
521

    
522
        app_doc_data = AppDocData.instance()
523
        configs = [Config('app', 'stylesheet', file)]
524
        app_doc_data.saveAppConfigs(configs)
525

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

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

    
538
    def refresh_item_list(self):
539
        """refresh item tree"""
540

    
541
        app_doc_data = AppDocData.instance()
542
        
543
        '''
544
        self.itemTreeWidget.setCurrentPID(app_doc_data.activeDrawing.name)
545

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

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

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

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

575
        self.itemTreeWidget.update_item_count()
576
        self.itemTreeWidget.expandAll()
577
        """up to here"""
578
        '''
579

    
580
        self.itemTreeWidget.InitLineNoItems()
581

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

    
600

    
601
    def load_drawing_list(self, reverse=False):
602
        """load p&id drawing list"""
603
        from Drawing import Drawing
604

    
605
        try:
606
            app_doc_data = AppDocData.instance()
607
            drawings = app_doc_data.getDrawings()
608
            new_drawings = []
609

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

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

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

    
636
                count += 1
637
                # self.progress_bar.setValue(count)
638
                # QApplication.processEvents()
639

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

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

    
654
    def open_selected_drawing(self, item, column):
655
        """open selected p&id drawing"""
656

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

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

    
671
    def show_detect_symbol_dialog(self):
672
        from DetectSymbolDialog import QDetectSymbolDialog
673

    
674
        dlg = QDetectSymbolDialog(self)
675
        dlg.exec_()
676
        
677
        self.symbolTreeWidget.initSymbolTreeView()
678

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

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

    
696
        return
697

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

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

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

    
729
        from TextItemEditDialog import QTextItemEditDialog
730

    
731
        dlgTextItemEdit = QTextItemEditDialog(self)
732
        dlgTextItemEdit.show()
733
        dlgTextItemEdit.exec_()
734

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

    
739
        dlg = QValidationGlobalDialog(self)
740
        dlg.show()
741
        dlg.exec_()
742

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

    
749
        from ReplaceSymbolDialog import QReplaceSymbolDialog
750

    
751
        dlg = QReplaceSymbolDialog(self)
752
        dlg.show()
753
        dlg.exec_()
754

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

    
759
        if not self.graphicsView.hasImage():
760
            self.showImageSelectionMessageBox()
761
            return
762

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

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

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

    
778
    def on_connect_line_to_symbol(self):
779
        """connect line to symbol"""
780
        from LineDetector import LineDetector
781
        from shapely.geometry import Point
782
        from CodeTables import CodeTable
783
        #from RecognitionDialog import Worker
784

    
785
        if not self.graphicsView.hasImage():
786
            self.showImageSelectionMessageBox()
787
            return
788

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

    
795
        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]
796
        lines_short = []#[item for item in self.graphicsView.scene().items() if type(item) is QEngineeringLineItem if item.length() <= 50]
797
        unknowns = [item for item in self.graphicsView.scene().items() if type(item) is QEngineeringUnknownItem]
798
        end_breaks = [item for item in self.graphicsView.scene().items() if type(item) is QEngineeringEndBreakItem]
799
        spec_breaks = [item for item in self.graphicsView.scene().items() if type(item) is QEngineeringSpecBreakItem]
800
        symbols = [item for item in self.graphicsView.scene().items() if issubclass(type(item), SymbolSvgItem) and item not in end_breaks and item not in spec_breaks]
801
        texts = [item for item in self.graphicsView.scene().items() if type(item) is QEngineeringTextItem and item.owner is None]
802

    
803
        for item in lines_short + unknowns:
804
            item.transfer.onRemoved.emit(item)
805

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

    
818
        # create short line
819
        if lines:
820
            new_lines = []
821
            try:
822
                '''
823
                conns = []
824
                for sym in symbols:
825
                    if sym.conn_type:
826
                        for index in range(len(sym.conn_type)):
827
                            if sym.conn_type[index] == 'Secondary' or sym.conn_type[index] == 'Primary':
828
                                item = sym.connectors[index].connectedItem
829
                                if item is None:
830
                                    conns.append(sym.connectors[index])
831
                
832
                new_lines.extend(Worker.make_short_lines_sts(conns, None))
833

834
                conns = []
835
                for sym in symbols:
836
                    if sym.conn_type:
837
                        for index in range(len(sym.conn_type)):
838
                            if sym.conn_type[index] == 'Secondary' or sym.conn_type[index] == 'Primary':
839
                                item = sym.connectors[index].connectedItem
840
                                if item is None and sym.connectors[index]:
841
                                    conns.append(sym.connectors[index])
842
                
843
                new_lines.extend(Worker.make_short_lines_stl(lines, conns, None))
844

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

    
868
            # connect line to line
869
            try:
870
                for line in lines:
871
                    #matches = [it for it in lines if (it is not line) and (not line.isParallel(it))]
872
                    #for match in matches:
873
                    for match in lines:
874
                        detector.connectLineToLine(match, line, toler)
875
            except Exception as ex:
876
                message = f"error occurred({repr(ex)}) in {sys.exc_info()[-1].tb_frame.f_code.co_filename}:" \
877
                          f"{sys.exc_info()[-1].tb_lineno}"
878
                self.addMessage.emit(MessageType.Error, message)
879
            # up to here
880

    
881
            # connect end break
882
            usedItemPairs = []
883
            for end_break in end_breaks:
884
                if end_break.prop('Freeze') or end_break.owner or end_break.prop('Connected Item'):
885
                    usedItemPairs.append([end_break.owner, end_break.prop('Connected Item')])
886

    
887
            for end_break in end_breaks:
888
                if end_break.prop('Freeze') or end_break.owner or end_break.prop('Connected Item'):
889
                    continue
890

    
891
                originPoint = Point(end_break.origin[0], end_break.origin[1])
892
                minD = sys.maxsize
893
                ownerItem = None
894
                connectedItem = None
895

    
896
                for symbol in symbols:
897
                    for conn in symbol.connectors:
898
                        dist = originPoint.distance(Point(conn.sceneConnectPoint[0], conn.sceneConnectPoint[1]))
899
                        if not conn.connectedItem or not issubclass(type(conn.connectedItem), QEngineeringAbstractItem) or \
900
                            [pair for pair in usedItemPairs if symbol in pair and conn.connectedItem in pair] or dist > 3 * toler or dist > minD:
901
                            continue
902

    
903
                        minD = dist
904
                        ownerItem = symbol
905
                        connectedItem = conn.connectedItem
906

    
907
                for line in lines:
908
                    for conn in line.connectors:
909
                        dist = originPoint.distance(Point(conn.sceneConnectPoint[0], conn.sceneConnectPoint[1]))
910
                        if not conn.connectedItem or not issubclass(type(conn.connectedItem), QEngineeringAbstractItem) or \
911
                            conn._connected_at != QEngineeringAbstractItem.CONNECTED_AT_BODY  or \
912
                            [pair for pair in usedItemPairs if line in pair and conn.connectedItem in pair] or dist > 3 * toler or dist > minD:
913
                            continue
914

    
915
                        minD = dist
916
                        ownerItem = line
917
                        connectedItem = conn.connectedItem
918

    
919
                if ownerItem and connectedItem:
920
                    end_break.set_property('Connected Item', connectedItem)
921
                    end_break.setToolTip('owner : ' + str(ownerItem))
922
                    end_break.owner = ownerItem
923
                    end_break.set_property('Freeze', True)
924

    
925
                    usedItemPairs.append([ownerItem, connectedItem])
926
            # up to here
927

    
928
            # connect spec break
929
            usedTexts = []
930
            attribute_table_item_list = []
931
            dist_range = None
932
            specBreakAttrsFull = [attr for attr in app_doc_data.getSymbolAttribute('Segment Breaks') if \
933
                attr.Target == 'ALL' and (attr.AttributeType == 'Spec' or attr.AttributeType == 'String')]
934

    
935
            for attr in specBreakAttrsFull:
936
                if attr.AttributeType != 'Spec' or attr.Attribute == 'NominalDiameter':
937
                    continue
938

    
939
                table = CodeTable.instance(attr.Attribute)
940
                items = []
941
                for text in texts:
942
                    if text not in usedTexts and table.find_match_exactly(text.text()):
943
                        usedTexts.append(text)
944
                        items.append(text)
945

    
946
                if len(items) >= 2:
947
                    attribute_table_item_list.append([attr.Attribute, items])
948

    
949
            usedItemPairs = []
950
            for spec_break in spec_breaks:
951
                if not dist_range:
952
                    dist_range = max(spec_break.sceneBoundingRect().height(), spec_break.sceneBoundingRect().width())
953

    
954
                attrs = spec_break.getAttributes()
955
                up = [attr.AssocItem for attr in attrs if attr.Attribute == 'UpStream']
956
                down = [attr.AssocItem for attr in attrs if attr.Attribute == 'DownStream']
957
                if spec_break.prop('Freeze') or (up and up[0]) or (down and down[0]):
958
                    usedItemPairs.append([up, down])
959

    
960
            for spec_break in spec_breaks:
961
                attrs = spec_break.getAttributes()
962
                up = [attr.AssocItem for attr in attrs if attr.Attribute == 'UpStream']
963
                down = [attr.AssocItem for attr in attrs if attr.Attribute == 'DownStream']
964
                if spec_break.prop('Freeze') or (up and up[0]) or (down and down[0]):
965
                    continue
966

    
967
                originPoint = Point(spec_break.origin[0], spec_break.origin[1])
968
                minD = sys.maxsize
969
                upItem = None
970
                downItem = None
971

    
972
                for symbol in symbols:
973
                    for conn in symbol.connectors:
974
                        dist = originPoint.distance(Point(conn.sceneConnectPoint[0], conn.sceneConnectPoint[1]))
975
                        if not conn.connectedItem or not issubclass(type(conn.connectedItem), QEngineeringAbstractItem) or \
976
                            [pair for pair in usedItemPairs if symbol in pair and conn.connectedItem in pair] or dist > dist_range or dist > minD:
977
                            continue
978

    
979
                        minD = dist
980
                        upItem = symbol
981
                        downItem = conn.connectedItem
982

    
983
                for line in lines:
984
                    for conn in line.connectors:
985
                        dist = originPoint.distance(Point(conn.sceneConnectPoint[0], conn.sceneConnectPoint[1]))
986
                        if not conn.connectedItem or not issubclass(type(conn.connectedItem), QEngineeringAbstractItem) or \
987
                            conn._connected_at != QEngineeringAbstractItem.CONNECTED_AT_BODY  or \
988
                            [pair for pair in usedItemPairs if line in pair and conn.connectedItem in pair] or dist > dist_range or dist > minD + 1:
989
                            continue
990

    
991
                        minD = dist
992
                        upItem = line
993
                        downItem = conn.connectedItem
994

    
995
                if upItem and downItem:
996
                    attrs = spec_break.getAttributes()
997
                    for key in attrs.keys():
998
                        if key.Attribute == 'UpStream':
999
                            attrs[key] = str(upItem)
1000
                            spec_break.add_assoc_item(upItem, key.AttrAt, force=True)
1001
                            key.AssocItem = upItem
1002
                            key.Freeze = True
1003
                        elif key.Attribute == 'DownStream':
1004
                            attrs[key] = str(downItem)
1005
                            spec_break.add_assoc_item(downItem, key.AttrAt, force=True)
1006
                            key.AssocItem = downItem
1007
                            key.Freeze = True
1008
                    spec_break.set_property('Freeze', True)
1009
                    spec_break.set_property('Show', True)
1010

    
1011
                    usedItemPairs.append([upItem, downItem])
1012

    
1013
                    for attribute_table_item in attribute_table_item_list:
1014
                        upText = None
1015
                        downText = None
1016
                        attribute_table_item[1].sort(key=lambda x: originPoint.distance(Point(x.center().x(), x.center().y())))
1017
                        if originPoint.distance(Point(attribute_table_item[1][1].center().x(), attribute_table_item[1][1].center().y())) < dist_range:
1018
                            if issubclass(type(upItem), SymbolSvgItem):
1019
                                symbolPoint = Point(upItem.origin[0], upItem.origin[1])
1020
                                if symbolPoint.distance(Point(attribute_table_item[1][0].center().x(), attribute_table_item[1][0].center().y())) < \
1021
                                    symbolPoint.distance(Point(attribute_table_item[1][1].center().x(), attribute_table_item[1][1].center().y())):
1022
                                    upText = attribute_table_item[1][0]
1023
                                    downText = attribute_table_item[1][1]
1024
                                else:
1025
                                    upText = attribute_table_item[1][1]
1026
                                    downText = attribute_table_item[1][0]
1027
                            elif issubclass(type(downItem), SymbolSvgItem):
1028
                                symbolPoint = Point(downItem.origin[0], downItem.origin[1])
1029
                                if symbolPoint.distance(Point(attribute_table_item[1][0].center().x(), attribute_table_item[1][0].center().y())) < \
1030
                                    symbolPoint.distance(Point(attribute_table_item[1][1].center().x(), attribute_table_item[1][1].center().y())):
1031
                                    downText = attribute_table_item[1][0]
1032
                                    upText = attribute_table_item[1][1]
1033
                                else:
1034
                                    downText = attribute_table_item[1][1]
1035
                                    upText = attribute_table_item[1][0]
1036
                            else:
1037
                                if upItem.length() < downItem.length():
1038
                                    linePoint = Point(upItem.center().x(), upItem.center().y())
1039
                                    if linePoint.distance(Point(attribute_table_item[1][0].center().x(), attribute_table_item[1][0].center().y())) < \
1040
                                        linePoint.distance(Point(attribute_table_item[1][1].center().x(), attribute_table_item[1][1].center().y())):
1041
                                        upText = attribute_table_item[1][0]
1042
                                        downText = attribute_table_item[1][1]
1043
                                    else:
1044
                                        upText = attribute_table_item[1][1]
1045
                                        downText = attribute_table_item[1][0]
1046
                                else:
1047
                                    linePoint = Point(downItem.center().x(), downItem.center().y())
1048
                                    if linePoint.distance(Point(attribute_table_item[1][0].center().x(), attribute_table_item[1][0].center().y())) < \
1049
                                        linePoint.distance(Point(attribute_table_item[1][1].center().x(), attribute_table_item[1][1].center().y())):
1050
                                        downText = attribute_table_item[1][0]
1051
                                        upText = attribute_table_item[1][1]
1052
                                    else:
1053
                                        downText = attribute_table_item[1][1]
1054
                                        upText = attribute_table_item[1][0]
1055

    
1056
                        if upText and downText:
1057
                            for full in specBreakAttrsFull:
1058
                                if full.Attribute == attribute_table_item[0]:
1059
                                    attrs[full] = [upText.text(), downText.text()]
1060
                                    attribute_table_item[1].remove(upText)
1061
                                    attribute_table_item[1].remove(downText)
1062
                                    break
1063

    
1064
                    stream_line = [upItem, downItem]
1065
                    stream_track = [downItem, upItem]
1066
                    stream_res = [False, False]
1067
                    for index in range(len(stream_line)):
1068
                        while True:
1069
                            if type(stream_line[index]) is QEngineeringLineItem:
1070
                                stream_res[index] = True
1071
                                break
1072
                            else:
1073
                                find_next = False
1074
                                connected_count = 0
1075
                                for connectorr in stream_line[index].connectors:
1076
                                    connected_count += 1
1077
                                    if connectorr.connectedItem and stream_track[index] is not connectorr.connectedItem and \
1078
                                            stream_line[index].next_connected(stream_track[index], connectorr.connectedItem):
1079
                                        stream_track[index] = stream_line[index]
1080
                                        stream_line[index] = connectorr.connectedItem
1081
                                        find_next = True
1082
                                        break
1083

    
1084
                                if not find_next:
1085
                                    # prevent infinite loop
1086
                                    if connected_count == 2:
1087
                                        for connectorr in stream_line[index].connectors:
1088
                                            if connectorr.connectedItem and not connectorr.connectedItem is stream_track[index]:
1089
                                                stream_line[index] = connectorr.connectedItem
1090
                                                stream_track[index] = stream_line[index]
1091
                                                find_next = True
1092
                                                break
1093
                                        if not find_next:
1094
                                            break
1095
                                    else:
1096
                                        break
1097

    
1098
                    if stream_res[0] and stream_res[1]:
1099
                        up_down_find = [upText, downText]
1100

    
1101
                        for index in range(len(stream_line)):
1102
                            attrs = stream_line[index].getAttributes()
1103
                            for key in attrs.keys():
1104
                                if key.Attribute == attribute_table_item[0]:
1105
                                    attrs[key] = up_down_find[index].text()
1106
                                    key.AssocItem = up_down_find[index]
1107
                                    stream_line[index].add_assoc_item(up_down_find[index],
1108
                                                                        key.AttrAt, force=True)
1109
                                    up_down_find[index].owner = stream_line[index]
1110
                                    key.Freeze = True
1111
                                    break
1112
            # up to here
1113

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

    
1116
    def on_recognize_line(self):
1117
        """recognize lines in selected area"""
1118
        from RecognizeLineCommand import RecognizeLineCommand
1119

    
1120
        if not self.graphicsView.hasImage():
1121
            self.actionOCR.setChecked(False)
1122
            self.showImageSelectionMessageBox()
1123
            return
1124

    
1125
        cmd = RecognizeLineCommand(self.graphicsView)
1126
        cmd.onSuccess.connect(self.on_success_to_recognize_line)
1127
        cmd.onRejected.connect(self.onCommandRejected)
1128
        self.graphicsView.command = cmd
1129

    
1130
    '''
1131
            @brief      show text recognition dialog
1132
            @author     humkyung
1133
            @date       2018.08.08
1134
    '''
1135
    def on_success_to_recognize_line(self, x, y, width, height):
1136
        import io
1137
        from LineDetector import LineDetector
1138
        from EngineeringGraphicsLineItem import QEngineeringGraphicsLineItem
1139

    
1140
        try:
1141
            image = self.graphicsView.image().copy(x, y, width, height)
1142
            buffer = QBuffer()
1143
            buffer.open(QBuffer.ReadWrite)
1144
            image.save(buffer, "PNG")
1145
            pyImage = Image.open(io.BytesIO(buffer.data()))
1146
            img = np.array(pyImage)
1147
            img = cv2.cvtColor(img, cv2.COLOR_BGR2GRAY)
1148

    
1149
            detector = LineDetector(img)
1150
            lines = detector.detect_line_without_symbol()
1151
            for line in lines:
1152
                vertices = [[line[0][0] + x, line[0][1] + y], [line[1][0] + x, line[1][1] + y]]
1153
                line_item = QEngineeringGraphicsLineItem(vertices)
1154
                self.graphicsView.scene().addItem(line_item)
1155

    
1156
        except Exception as ex:
1157
            message = 'error occurred({}) in {}:{}'.format(repr(ex), sys.exc_info()[-1].tb_frame.f_code.co_filename,
1158
                                                           sys.exc_info()[-1].tb_lineno)
1159
            self.addMessage.emit(MessageType.Error, message)
1160

    
1161
    def display_number_of_items(self):
1162
        """display count of symbol, line, text"""
1163

    
1164
        items = [item for item in self.graphicsView.scene().items() if type(item) is QEngineeringUnknownItem]
1165
        if len(items) > 0:
1166
            self.labelStatus.setText(
1167
                "<font color='red'>" + self.tr('Unrecognition') + " : {}</font>".format(len(items)))
1168
        else:
1169
            self.labelStatus.setText(
1170
                "<font color='black'>" + self.tr('Unrecognition') + " : {}</font>".format(len(items)))
1171

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

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

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

    
1182
        self.itemTreeWidget.sceneChanged(self.graphicsView.scene().items())
1183

    
1184
    def dbUpdate(self):
1185
        """ no more used """
1186
        """db update when save or recognition"""
1187

    
1188
        try:
1189
            appDocData = AppDocData.instance()
1190
            items = appDocData.allItems
1191

    
1192
            '''
1193
            titleBlockProps = appDocData.getTitleBlockProperties()
1194
            titleBlockItems = []
1195
            for item in items:
1196
                # if type(item) is QEngineeringLineNoTextItem:
1197
                #    item.saveLineData()
1198
                if type(item) is QEngineeringTextItem:
1199
                    for titleBlockProp in titleBlockProps:
1200
                        if item.area == titleBlockProp[0]:
1201
                            titleBlockItems.append(item)
1202
            '''
1203

    
1204
            # unknown item is not saved now for performance
1205
            db_items = [item for item in items if issubclass(type(item), QEngineeringAbstractItem) and
1206
                        type(item) is not QGraphicsBoundingBoxItem and
1207
                        type(item) is not QEngineeringErrorItem and
1208
                        type(item) is not QEngineeringLineNoTextItem and
1209
                        type(item) is not QEngineeringUnknownItem]
1210
            db_items.extend([item for item in items if type(item) is QEngineeringLineNoTextItem])
1211
            db_items.extend([line for line in appDocData.tracerLineNos if type(line) is QEngineeringTrimLineNoTextItem])
1212
            # db_items.extend(titleBlockItems)
1213
            configs = appDocData.getConfigs('Data Save', 'Unknown Xml Only')
1214
            if configs and int(configs[0].value) is -1:
1215
                db_items.extend([item for item in items if type(item) is QEngineeringUnknownItem])
1216

    
1217
            '''
1218
            dbItems = [item for item in items if
1219
                       type(item) is QEngineeringInstrumentItem or type(item) is QEngineeringEquipmentItem or type(
1220
                           item) is QEngineeringReducerItem or \
1221
                       type(item) is QEngineeringNoteItem or type(item) is SymbolSvgItem or type(
1222
                           item) is QEngineeringLineNoTextItem or type(
1223
                           item) is QEngineeringVendorItem] + titleBlockItems
1224
            '''
1225
            appDocData.saveToDatabase(db_items)
1226
        except Exception as ex:
1227
            message = 'error occurred({}) in {}:{}'.format(ex, sys.exc_info()[-1].tb_frame.f_code.co_filename,
1228
                                                           sys.exc_info()[-1].tb_lineno)
1229
            self.addMessage.emit(MessageType.Error, message)
1230

    
1231
    def save_drawing_if_necessary(self):
1232
        """ask to user to save drawing or not when drawing is modified"""
1233

    
1234
        app_doc_data = AppDocData.instance()
1235
        if app_doc_data.activeDrawing and app_doc_data.activeDrawing.modified:
1236
            #if QMessageBox.Yes == QMessageBox.question(self, self.tr("Question"),
1237
            #                                           self.tr("Do you want to save drawing?"),
1238
            #                                           QMessageBox.Yes | QMessageBox.No):
1239
            #    self.actionSaveCliked()
1240
            #    return True
1241
            if QMessageBox.Ignore == QMessageBox.question(self, self.tr('Continue?'),
1242
                                                       self.tr('Changes may not have been saved.'),
1243
                                                       QMessageBox.Ignore | QMessageBox.Cancel):
1244
                return False
1245
            return True
1246

    
1247
    def actionSaveCliked(self):
1248
        """
1249
        save current drawing
1250
        @return:
1251
        """
1252
        from EngineeringAbstractItem import QEngineeringAbstractItem
1253
        from SaveWorkCommand import SaveWorkCommand
1254

    
1255
        try:
1256
            home_pane = self.ribbon.get_pane('Home File')
1257
            if not home_pane.ui.toolButtonFileSave.isEnabled():
1258
                return
1259

    
1260
            home_pane.ui.toolButtonFileSave.setEnabled(False)
1261

    
1262
            # save alarm
1263
            self.save_alarm_enable(False)
1264

    
1265
            app_doc_data = AppDocData.instance()
1266
            if app_doc_data.imgName is None:
1267
                self.showImageSelectionMessageBox()
1268
                return
1269

    
1270
            app_doc_data.clearItemList(False)
1271

    
1272
            items = self.graphicsView.scene().items()
1273

    
1274
            self._save_work_cmd = SaveWorkCommand(self.graphicsView.scene())
1275
            self._save_work_cmd.show_progress.connect(self.progress_bar.setValue)
1276
            self._save_work_cmd.display_message.connect(self.onAddMessage)
1277
            self._save_work_cmd.finished.connect(self.save_finished)
1278

    
1279
            self._save_work_cmd.start()
1280
        except Exception as ex:
1281
            message = f"error occurred({repr(ex)}) in {sys.exc_info()[-1].tb_frame.f_code.co_filename}:" \
1282
                      f"{sys.exc_info()[-1].tb_lineno}"
1283
            self.addMessage.emit(MessageType.Error, message)
1284

    
1285
    def save_finished(self):
1286
        """
1287
        reload drawing list when save is finished
1288
        @return: None
1289
        """
1290

    
1291
        try:
1292
            self._save_work_cmd.show_progress.emit(100)
1293
            QMessageBox.about(self.graphicsView, self.tr('Information'), self._save_work_cmd.resultStr)
1294
            self.load_drawing_list()
1295

    
1296
            app_doc_data = AppDocData.instance()
1297
            app_doc_data.activeDrawing.modified = False
1298
            title = self.windowTitle()
1299
            self.setWindowTitle(title[:-1] if title[-1] == '*' else title)
1300

    
1301
            # save alarm
1302
            self.save_alarm_enable(True)
1303
        finally:
1304
            home_pane = self.ribbon.get_pane('Home File')
1305
            home_pane.ui.toolButtonFileSave.setEnabled(True)
1306

    
1307
    '''
1308
        @brief      refresh resultPropertyTableWidget
1309
        @author     kyouho
1310
        @date       2018.07.19
1311
    '''
1312
    def refreshResultPropertyTableWidget(self):
1313
        items = self.graphicsView.scene().selectedItems()
1314
        if len(items) == 1:
1315
            self.resultPropertyTableWidget.show_item_property(items[0])
1316

    
1317
    '''
1318
        @brief  add message listwidget
1319
        @author humkyung
1320
        @date   2018.07.31
1321
    '''
1322
    def onAddMessage(self, messageType, message):
1323
        from AppDocData import MessageType
1324

    
1325
        try:
1326
            current = QDateTime.currentDateTime()
1327

    
1328
            item = QListWidgetItem('{}: {}'.format(current.toString('hh:mm:ss'), message))
1329
            item.setFlags(item.flags() | Qt.ItemIsEditable)
1330
            if messageType == MessageType.Error:
1331
                item.setBackground(Qt.red)
1332
            elif messageType == 'check':
1333
                item.setBackground(Qt.yellow)
1334

    
1335
            self.listWidgetLog.insertItem(0, item)
1336
        except Exception as ex:
1337
            print('error occurred({}) in {}:{}'.format(ex, sys.exc_info()[-1].tb_frame.f_code.co_filename,
1338
                                                       sys.exc_info()[-1].tb_lineno))
1339

    
1340
    def on_clear_log(self):
1341
        """clear log"""
1342
        self.listWidgetLog.clear()
1343

    
1344
    def onRotate(self, action):
1345
        """rotate a selected symbol"""
1346
        selected = [item for item in self.graphicsView.scene().selectedItems() if issubclass(type(item), SymbolSvgItem)]
1347
        if len(selected) == 1:
1348
            from RotateCommand import RotateCommand
1349
            self.graphicsView.scene()._undo_stack.push(RotateCommand(self.graphicsView.scene(), selected))
1350

    
1351
    def onAreaZoom(self):
1352
        """Area Zoom"""
1353
        visualization_pane = self.ribbon.get_pane('Home Visualization')
1354

    
1355
        self.update_action_group(visualization_pane.ui.toolButtonZoom)
1356
        if visualization_pane.ui.toolButtonZoom.isChecked():
1357
            cmd = AreaZoomCommand.AreaZoomCommand(self.graphicsView)
1358
            cmd.onRejected.connect(self.onCommandRejected)
1359
            self.graphicsView.command = cmd
1360

    
1361
    def onVendor(self, action):
1362
        """make vendor/equipment package area"""
1363

    
1364
        pane = self.ribbon.get_pane('Home')
1365
        if not self.graphicsView.hasImage():
1366
            pane.ui.toolButtonVendor.setChecked(False)
1367
            self.showImageSelectionMessageBox()
1368
            return
1369

    
1370
        pane = self.ribbon.get_pane('Home')
1371
        self.update_action_group(pane.ui.toolButtonVendor)
1372
        checked = pane.ui.toolButtonVendor.isChecked()
1373
        if not hasattr(pane.ui.toolButtonVendor, 'tag'):
1374
            pane.ui.toolButtonVendor.tag = PlacePolygonCommand.PlacePolygonCommand(self.graphicsView)
1375
            pane.ui.toolButtonVendor.tag.onSuccess.connect(self.onVendorCreated)
1376
            pane.ui.toolButtonVendor.tag.onRejected.connect(self.onCommandRejected)
1377

    
1378
        self.graphicsView.command = pane.ui.toolButtonVendor.tag
1379

    
1380
    def onVendorCreated(self):
1381
        """add created vendor polygon area to scene"""
1382

    
1383
        try:
1384
            vendor_tool = self.ribbon.get_pane('Home').ui.toolButtonVendor
1385
            package_combo = self.ribbon.get_pane('Home').ui.comboBoxPackage
1386
            count = len(vendor_tool.tag._polyline._vertices)
1387
            if count > 2:
1388
                points = []
1389
                for point in vendor_tool.tag._polyline._vertices:
1390
                    points.append(QPoint(round(point[0]), round(point[1])))
1391
                polygon = QPolygonF(points)
1392
                item = QEngineeringVendorItem(polygon, pack_type=package_combo.currentText())
1393
                item.area = 'Drawing'
1394
                item.transfer.onRemoved.connect(self.itemRemoved)
1395
                self.graphicsView.scene().addItem(item)
1396
        finally:
1397
            self.graphicsView.scene().removeItem(vendor_tool.tag._polyline)
1398
            vendor_tool.tag.reset()
1399

    
1400
    def fitWindow(self, view_rect: QRectF = QRectF()):
1401
        """Fit Window"""
1402
        self.graphicsView.useDefaultCommand()
1403
        self.graphicsView.zoomImageInit()
1404

    
1405
        visualization_pane = self.ribbon.get_pane('Home Visualization')
1406
        self.update_action_group(visualization_pane.ui.toolButtonFitWindow)
1407
        if view_rect:
1408
            self.graphicsView.zoom_rect(view_rect)
1409

    
1410
    def on_toggle_lock_axis(self):
1411
        """toggle lock axis"""
1412
        from EngineeringPolylineItem import QEngineeringPolylineItem
1413

    
1414
        visualization_pane = self.ribbon.get_pane('Home Visualization')
1415
        if self.sender() is not visualization_pane.ui.toolButtonLockAxis:
1416
            checked = visualization_pane.ui.toolButtonLockAxis.isChecked()
1417
            visualization_pane.ui.toolButtonLockAxis.setChecked(not checked)
1418

    
1419
        checked = visualization_pane.ui.toolButtonLockAxis.isChecked()
1420
        QEngineeringPolylineItem.DRAWING_MODE = QEngineeringPolylineItem.AXIS_MODE if checked else \
1421
            QEngineeringPolylineItem.FREE_MODE
1422

    
1423
    def scene_changed(self):
1424
        """update modified flag"""
1425

    
1426
        self.display_number_of_items()
1427

    
1428
        app_doc_data = AppDocData.instance()
1429
        app_doc_data.activeDrawing.modified = True
1430
        title = self.windowTitle()
1431
        self.setWindowTitle(title if title[-1] == '*' else title + '*')
1432

    
1433
    def onConvertPDFToImage(self):
1434
        """convert to selected pdf to image"""
1435
        import os
1436

    
1437
        try:
1438
            file_path = os.path.join(os.path.dirname(os.path.realpath(__file__)), 'bin64', 'PDF_TO_IMAGE.exe')
1439
            os.startfile(file_path)
1440
        except Exception as ex:
1441
            message = 'error occurred({}) in {}:{}'.format(ex, sys.exc_info()[-1].tb_frame.f_code.co_filename,
1442
                                                           sys.exc_info()[-1].tb_lineno)
1443
            self.addMessage.emit(MessageType.Error, message)
1444

    
1445
    def on_import_text_from_cad_for_instrument(self):
1446
        """ import text from cad for instrument """
1447
        try:
1448
            self.onCommandRejected()
1449
            dialog = QImportTextFromPDFDialog(self)
1450
            dialog.show()
1451
            dialog.exec_()
1452
        except Exception as ex:
1453
            message = f"error occurred({repr(ex)}) in {sys.exc_info()[-1].tb_frame.f_code.co_filename}:" \
1454
                      f"{sys.exc_info()[-1].tb_lineno}"
1455
            self.addMessage.emit(MessageType.Error, message)
1456

    
1457
    def on_import_text_from_cad(self):
1458
        """ import text from cad """
1459
        try:
1460
            self.onCommandRejected()
1461
            dialog = QImportTextFromCADDialog(self)
1462
            dialog.show()
1463
            dialog.exec_()
1464
        except Exception as ex:
1465
            message = f"error occurred({repr(ex)}) in {sys.exc_info()[-1].tb_frame.f_code.co_filename}:" \
1466
                      f"{sys.exc_info()[-1].tb_lineno}"
1467
            self.addMessage.emit(MessageType.Error, message)
1468

    
1469
    def on_export_PDF(self):
1470
        if not self.graphicsView.hasImage():
1471
            self.showImageSelectionMessageBox()
1472
            return
1473

    
1474
        try:
1475
            printer = QPrinter(QPrinter.HighResolution)
1476
            #printer.setPageSize(QPrinter.A4)
1477
            printer.setOrientation(QPrinter.Orientation.Landscape)
1478
            dialog = QPrintDialog(printer)
1479
            if (dialog.exec() == QDialog.Accepted):
1480
                painter = QPainter(printer)
1481
                isfull_print = False
1482

    
1483
                scene = self.graphicsView.scene()
1484

    
1485
                #for item in scene.items():
1486
                #    if not hasattr(item, 'connectors'): continue
1487
                #    for connector in item.connectors: connector.setVisible(False)
1488

    
1489
                canvasRect = scene.sceneRect() # or canvasRect = scene.border.boundingRect()
1490
                source = canvasRect
1491
                page = printer.pageRect(QPrinter.Unit.DevicePixel)
1492
                target = QRectF(QPointF(0, 0), QSizeF(page.width(), page.height()))
1493
                scene.render(painter, target, source)
1494
                painter.end()
1495

    
1496
                QMessageBox.about(self, self.tr("Information"), self.tr('Successfully saved.'))
1497
                #for item in scene.items():
1498
                #    if not hasattr(item, 'connectors'): continue
1499
                #    for connector in item.connectors: connector.setVisible(True)
1500

    
1501
        except Exception as ex:
1502
            message = 'error occurred({}) in {}:{}'.format(ex, sys.exc_info()[-1].tb_frame.f_code.co_filename,
1503
                                                           sys.exc_info()[-1].tb_lineno)
1504
            self.addMessage.emit(MessageType.Error, message)
1505

    
1506
    def onSymbolThickness(self):
1507
        """ symbol thickness reinforcement by using configuration filter drawing dilate size """
1508
        try:
1509
            self.onCommandRejected()
1510
            dialog = QSymbolThicknessDialog(self)
1511
            dialog.exec_()
1512
        except Exception as ex:
1513
            message = 'error occurred({}) in {}:{}'.format(ex, sys.exc_info()[-1].tb_frame.f_code.co_filename,
1514
                                                           sys.exc_info()[-1].tb_lineno)
1515
            self.addMessage.emit(MessageType.Error, message)
1516

    
1517
    def on_help(self):
1518
        """ open help file """
1519
        import os
1520

    
1521
        try:
1522
            help_file_path = os.path.join(os.path.dirname(os.path.realpath(__file__)), 'ID2 User Manual.pdf')
1523
            if os.path.exists(help_file_path):
1524
                os.startfile(f"\"{help_file_path}\"")
1525
            else:
1526
                QMessageBox.warning(self, self.tr('Warning'), self.tr('There is no help file'))
1527
        except Exception as ex:
1528
            message = f"error occurred({repr(ex)}) in {sys.exc_info()[-1].tb_frame.f_code.co_filename}:" \
1529
                      f"{sys.exc_info()[-1].tb_lineno}"
1530
            self.addMessage.emit(MessageType.Error, message)
1531

    
1532
    def on_readme(self):
1533
        """open readme.html"""
1534

    
1535
        file_path = os.path.join(os.path.dirname(os.path.realpath(__file__)), 'readme.html')
1536
        if os.path.exists(file_path):
1537
            os.startfile(f"\"{file_path}\"")
1538
        else:
1539
            QMessageBox.warning(self, self.tr('Warning'), self.tr('There is no readme file'))
1540

    
1541
    def onSelectionChanged(self):
1542
        """selection changed"""
1543
        items = [item for item in self.graphicsView.scene().selectedItems() if issubclass(type(item), SymbolSvgItem) or
1544
                 type(item) is QEngineeringLineItem or issubclass(type(item), QEngineeringTextItem) or
1545
                 type(item) is QEngineeringUnknownItem or type(item) is QEngineeringVendorItem]
1546
        if items:
1547
            lineNos = [item for item in items if type(item) is QEngineeringLineNoTextItem]
1548
            item = items[-1] if not lineNos else lineNos[0]
1549
            self.itemTreeWidget.findItem(item)
1550
            self.resultPropertyTableWidget.show_item_property(item)
1551
            if type(item) is QEngineeringErrorItem:
1552
                for index in range(self.tableWidgetInconsistency.rowCount()):
1553
                    if self.tableWidgetInconsistency.item(index, 1).tag is item:
1554
                        self.tableWidgetInconsistency.selectRow(index)
1555
                        break
1556
            if issubclass(type(item), SymbolSvgItem):
1557
                pass
1558
                #self.symbolTreeWidget.select_symbol(item)
1559
        else:
1560
            self.resultPropertyTableWidget.show_item_property(None)
1561

    
1562
    '''
1563
        @brief      Initialize scene and itemTreeWidget
1564
        @author     Jeongwoo
1565
        @date       2018.06.14
1566
        @history    humkyung 2018.08.16 ask to delete recognized items before remove
1567
    '''
1568
    def on_initialize_scene(self, action):
1569
        if not self.graphicsView.hasImage():
1570
            self.showImageSelectionMessageBox()
1571

    
1572
            return
1573

    
1574
        try:
1575
            msg = QMessageBox()
1576
            msg.setIcon(QMessageBox.Critical)
1577
            msg.setText(self.tr('Do you want to remove all items?\nThis work cannot be recovered.'))
1578
            msg.setWindowTitle(self.tr("Initialize"))
1579
            msg.setStandardButtons(QMessageBox.Ok | QMessageBox.Cancel)
1580
            if QMessageBox.Ok == msg.exec_():
1581
                app_doc_data = AppDocData.instance()
1582
                app_doc_data.clearItemList(True)
1583

    
1584
                scene = self.graphicsView.scene()
1585
                pixmap = self.graphicsView.getPixmapHandle()
1586
                scene.removeItem(pixmap)    # disconnect pixmap from scene
1587
                scene.clear()               # remove all items from scene and then delete them
1588
                scene.addItem(pixmap)       # add pixmap
1589

    
1590
                if self.path is not None:
1591
                    baseName = os.path.basename(self.path)
1592
                    self.itemTreeWidget.setCurrentPID(baseName)
1593

    
1594
        except Exception as ex:
1595
            message = 'error occurred({}) in {}:{}'.format(ex, sys.exc_info()[-1].tb_frame.f_code.co_filename,
1596
                                                           sys.exc_info()[-1].tb_lineno)
1597
            self.addMessage.emit(MessageType.Error, message)
1598

    
1599
    def checked_action(self):
1600
        """return checked action"""
1601
        home_file_pane = self.ribbon.get_pane('Home File')
1602
        home_pane = self.ribbon.get_pane('Home')
1603
        visualization_pane = self.ribbon.get_pane('Home Visualization')
1604
        actions = [home_pane.ui.toolButtonRecognition, home_pane.ui.toolButtonLinkAttribute,
1605
                   home_pane.ui.toolButtonLine, home_pane.ui.toolButtonOCR, visualization_pane.ui.toolButtonZoom,
1606
                   visualization_pane.ui.toolButtonFitWindow, home_pane.ui.toolButtonVendor]
1607

    
1608
        checked = [ui_ for ui_ in actions if ui_.isChecked()]
1609
        return checked[0] if checked else None
1610

    
1611
    def update_action_group(self, ui):
1612
        """Manage Checkable Action statement"""
1613
        home_file_pane = self.ribbon.get_pane('Home File')
1614
        home_pane = self.ribbon.get_pane('Home')
1615
        visualization_pane = self.ribbon.get_pane('Home Visualization')
1616
        actions = [home_pane.ui.toolButtonRecognition, home_pane.ui.toolButtonLinkAttribute, home_pane.ui.toolButtonLine,
1617
                   home_pane.ui.toolButtonOCR, visualization_pane.ui.toolButtonZoom,
1618
                   visualization_pane.ui.toolButtonFitWindow, home_file_pane.ui.toolButtonFileSave,
1619
                   home_pane.ui.toolButtonValidate, home_pane.ui.toolButtonVendor]
1620

    
1621
        if hasattr(ui, 'tag'):
1622
            ui.tag.onRejected.emit(None)
1623

    
1624
        if self.graphicsView.command is not None:
1625
            self.graphicsView.useDefaultCommand()
1626

    
1627
        for ui_ in actions:
1628
            ui_.setChecked(False)
1629

    
1630
        ui.setChecked(True)
1631

    
1632
    '''
1633
        @brief      Create Equipment
1634
        @author     Jeongwoo
1635
        @date       18.05.03
1636
        @history    2018.05.04  Jeongwoo    Add Parameter on CreateSymbolCommand
1637
    '''
1638
    def createEquipment(self):
1639
        if not self.graphicsView.hasImage():
1640
            self.actionEquipment.setChecked(False)
1641
            self.showImageSelectionMessageBox()
1642
            return
1643
        if self.actionEquipment.isChecked():
1644
            self.graphicsView.command = CreateSymbolCommand.CreateSymbolCommand(self.graphicsView, self.itemTreeWidget,
1645
                                                                                self.symbolTreeWidget)
1646
        else:
1647
            self.graphicsView.useDefaultCommand()
1648

    
1649
    '''
1650
        @brief      Create Nozzle
1651
        @author     Jeongwoo
1652
        @date       2018.05.03
1653
        @history    2018.05.04  Jeongwoo    Add Parameter on CreateSymbolCommand
1654
    '''
1655
    def createNozzle(self):
1656
        if not self.graphicsView.hasImage():
1657
            self.actionNozzle.setChecked(False)
1658
            self.showImageSelectionMessageBox()
1659
            return
1660
        if self.actionNozzle.isChecked():
1661
            self.graphicsView.command = CreateSymbolCommand.CreateSymbolCommand(self.graphicsView, self.itemTreeWidget,
1662
                                                                                self.symbolTreeWidget)
1663
        else:
1664
            self.graphicsView.useDefaultCommand()
1665

    
1666
    def onAreaOcr(self):
1667
        """Area OCR"""
1668
        if not self.graphicsView.hasImage():
1669
            self.actionOCR.setChecked(False)
1670
            self.showImageSelectionMessageBox()
1671
            return
1672

    
1673
        pane = self.ribbon.get_pane('Home')
1674
        ui = pane.ui.toolButtonOCR
1675
        self.update_action_group(ui=ui)
1676
        checked = ui.isChecked()
1677
        if checked:
1678
            cmd = AreaOcrCommand.AreaOcrCommand(self.graphicsView)
1679
            cmd.onSuccess.connect(self.onRecognizeText)
1680
            cmd.onRejected.connect(self.onCommandRejected)
1681
            self.graphicsView.command = cmd
1682
        else:
1683
            self.graphicsView.useDefaultCommand()
1684

    
1685
    def onRecognizeText(self, x, y, width, height, show=True):
1686
        """show text recognition dialog"""
1687
        from OcrResultDialog import QOcrResultDialog
1688
        from Area import Area
1689

    
1690
        try:
1691
            app_doc_data = AppDocData.instance()
1692

    
1693
            modifiers = QApplication.keyboardModifiers()
1694
            image = self.graphicsView.image().copy(x, y, width, height)
1695
            dialog = QOcrResultDialog(self, image, QRectF(x, y, width, height),
1696
                                      format=QOcrResultDialog.Format.Table if modifiers == Qt.AltModifier else QOcrResultDialog.Format.Normal)
1697
            if modifiers == Qt.ControlModifier:
1698
                return
1699
            
1700
            if show:
1701
                (res, textInfoList) = dialog.showDialog()
1702
            else:
1703
                dialog.accept(show=False)
1704
                (res, textInfoList) = QDialog.Accepted, dialog.textInfoList
1705

    
1706
            if QDialog.Accepted == res and textInfoList:
1707
                for textInfo in textInfoList:
1708
                    item = QEngineeringTextItem.create_text_with(self.graphicsView.scene(), textInfo)
1709
                    if item:
1710
                        item.setDefaultTextColor(Qt.blue)
1711
                        item.transfer.onRemoved.connect(self.itemRemoved)
1712

    
1713
                        area_list = app_doc_data.getAreaList()
1714
                        title_area_list = app_doc_data.getTitleBlockProperties()
1715
                        title_list = []
1716
                        if title_area_list:
1717
                            for title_area in title_area_list:
1718
                                area = Area(title_area[0])
1719
                                area.parse(title_area[2])
1720
                                title_list.append(area)
1721
                        for area in area_list + title_list:
1722
                            pt = [item.sceneBoundingRect().center().x(), item.sceneBoundingRect().center().y()]
1723
                            if area.contains(pt):
1724
                                item.area = area.name
1725
                                break
1726
                    else:
1727
                        self.addMessage.emit(MessageType.Normal, self.tr('Fail to create text.'))
1728

    
1729
                return True
1730
            elif QDialog.Accepted == res and not textInfoList and show:
1731
                QMessageBox.about(self.graphicsView, self.tr("Notice"), self.tr("Fail to recognize text"))
1732
        except Exception as ex:
1733
            message = 'error occurred({}) in {}:{}'.format(ex, sys.exc_info()[-1].tb_frame.f_code.co_filename,
1734
                                                           sys.exc_info()[-1].tb_lineno)
1735
            self.addMessage.emit(MessageType.Error, message)
1736
        
1737
        return False
1738

    
1739
    '''
1740
        @brief  area configuration
1741
    '''
1742
    def areaConfiguration(self):
1743
        from ConfigurationAreaDialog import QConfigurationAreaDialog
1744
        if not self.graphicsView.hasImage():
1745
            self.showImageSelectionMessageBox()
1746
            return
1747
        self.onCommandRejected()
1748
        dlgConfigurationArea = QConfigurationAreaDialog(self)
1749
        dlgConfigurationArea.show()
1750
        dlgConfigurationArea.exec_()
1751

    
1752
    '''
1753
        @brief  configuration
1754
    '''
1755
    def configuration(self):
1756
        from ConfigurationDialog import QConfigurationDialog
1757

    
1758
        dlgConfiguration = QConfigurationDialog(self)
1759
        if QDialog.Accepted == dlgConfiguration.exec_():
1760
            QEngineeringLineItem.LINE_TYPE_COLORS.clear()
1761
            QEngineeringInstrumentItem.INST_COLOR = None
1762

    
1763
    '''
1764
        @brief  show special item types dialog 
1765
        @author humkyung
1766
        @date   2019.08.10
1767
    '''
1768
    def on_show_special_item_types(self):
1769
        from SpecialItemTypesDialog import QSpecialItemTypesDialog
1770

    
1771
        dlg = QSpecialItemTypesDialog(self)
1772
        dlg.exec_()
1773

    
1774
    def on_show_data_transfer(self):
1775
        """ show data transfer dialog """
1776
        from DataTransferDialog import QDataTransferDialog
1777

    
1778
        dlg = QDataTransferDialog(self)
1779
        dlg.exec_()
1780

    
1781
    def on_show_data_export(self):
1782
        """ show data export dialog """
1783
        from DataExportDialog import QDataExportDialog
1784

    
1785
        dlg = QDataExportDialog(self)
1786
        dlg.exec_()
1787

    
1788
    def on_show_eqp_datasheet_export(self):
1789
        """ show eqp datasheet export dialog """
1790
        from EqpDatasheetExportDialog import QEqpDatasheetExportDialog
1791

    
1792
        dlg = QEqpDatasheetExportDialog(self)
1793
        dlg.exec_()
1794

    
1795
    def on_show_opc_relation(self):
1796
        """ show opc relation dialog """
1797
        from OPCRelationDialog import QOPCRelationDialog
1798

    
1799
        dlg = QOPCRelationDialog(self)
1800
        dlg.exec_()
1801

    
1802
    '''
1803
        @brief  show nominal diameter dialog 
1804
        @author humkyung
1805
        @date   2018.06.28
1806
    '''
1807
    def onShowCodeTable(self):
1808
        from CodeTableDialog import QCodeTableDialog
1809

    
1810
        dlg = QCodeTableDialog(self)
1811
        dlg.show()
1812
        dlg.exec_()
1813
        if dlg.code_area:
1814
            if dlg.code_area.scene():
1815
                self.graphicsView.scene().removeItem(dlg.code_area)
1816
        if dlg.desc_area:
1817
            if dlg.desc_area.scene():
1818
                self.graphicsView.scene().removeItem(dlg.desc_area)
1819
        self.graphicsView.useDefaultCommand()
1820

    
1821
    def on_ext_app_connection(self):
1822
        from TcpServer import TcpServer
1823

    
1824
        app_doc_data = AppDocData.instance()
1825

    
1826
        tool_pane = self.ribbon.get_pane('Tool')
1827
        if tool_pane.ui.toolButtonConnection.isChecked():
1828
            if not hasattr(self, '_tcpserver'):
1829
                configs = app_doc_data.getAppConfigs('app', 'port')
1830
                port = 2549
1831
                if configs and 1 == len(configs):
1832
                    port = int(configs[0].value)
1833
                self._tcpserver = TcpServer(port)
1834
                self._tcpserver.sessionOpened()
1835
        else:
1836
            self._tcpserver.sessionClosed()
1837
            del self._tcpserver
1838

    
1839
    def on_execute_ext_app(self):
1840
        """execute external application"""
1841
        from ExtAppsDialog import QExtAppsDialog
1842

    
1843
        dlg = QExtAppsDialog(self)
1844
        dlg.exec_()
1845

    
1846
    def onShowCustomCodeTable(self):
1847
        from CustomCodeTablesDialog import CustomCodeTablesDialog
1848

    
1849
        dlg = CustomCodeTablesDialog(self)
1850
        dlg.show()
1851
        dlg.exec_()
1852
        self.graphicsView.useDefaultCommand()
1853

    
1854
    def onShowReplaceCodeTable(self):
1855
        from CustomCodeTablesDialog import CustomCodeTablesDialog
1856

    
1857
        dlg = CustomCodeTablesDialog(self, replace=True)
1858
        dlg.show()
1859
        dlg.exec_()
1860
        self.graphicsView.useDefaultCommand()
1861

    
1862
    def on_streamline(self):
1863
        """pop up stream line dialog"""
1864
        from StreamlineDialog import QStreamlineDialog
1865

    
1866
        if not self.graphicsView.hasImage():
1867
            self.showImageSelectionMessageBox()
1868
            return
1869

    
1870
        hmbs = AppDocData.instance().get_hmb_data(None)
1871
        if not hmbs:
1872
            return
1873

    
1874
        dlg = QStreamlineDialog(self)
1875
        dlg.show()
1876

    
1877
    def onHMBData(self):
1878
        """show HMB data"""
1879
        from HMBDialog import QHMBDialog
1880

    
1881
        dlg = QHMBDialog(self)
1882
        dlg.show()
1883
        dlg.exec_()
1884

    
1885
    '''
1886
        @brief  show line data list 
1887
        @author humkyung
1888
        @date   2018.05.03
1889
    '''
1890
    def showItemDataList(self):
1891
        from ItemDataExportDialog import QItemDataExportDialog
1892

    
1893
        dlg = QItemDataExportDialog(self)
1894
        dlg.exec_()
1895

    
1896
    def showTextDataList(self):
1897
        '''
1898
            @brief      show all text item in scene
1899
            @author     euisung
1900
            @date       2019.04.18
1901
        '''
1902
        try:
1903
            if not self.graphicsView.hasImage():
1904
                self.showImageSelectionMessageBox()
1905
                return
1906

    
1907
            self.onCommandRejected()
1908
            dialog = QTextDataListDialog(self)
1909
            dialog.show()
1910
        except Exception as ex:
1911
            message = 'error occurred({}) in {}:{}'.format(ex, sys.exc_info()[-1].tb_frame.f_code.co_filename,
1912
                                                           sys.exc_info()[-1].tb_lineno)
1913
            self.addMessage.emit(MessageType.Error, message)
1914

    
1915
    '''
1916
        @brief  Show Image Selection Guide MessageBox
1917
        @author Jeongwoo
1918
        @date   2018.05.02
1919
    '''
1920
    def showImageSelectionMessageBox(self):
1921
        QMessageBox.about(self.graphicsView, self.tr("Notice"), self.tr("First select image drawing"))
1922

    
1923
    def on_search_text_changed(self):
1924
        """filter symbol tree view"""
1925
        regexp = QRegExp(self.lineEditFilter.text(), Qt.CaseInsensitive, QRegExp.FixedString)
1926

    
1927
        proxy_model = self.symbolTreeWidget.model()
1928
        proxy_model.text = self.lineEditFilter.text().lower()
1929
        proxy_model.setFilterRegExp(regexp)
1930

    
1931
        self.symbolTreeWidget.expandAll()
1932

    
1933
    def change_display_colors(self):
1934
        """ change display color mode """
1935
        visualization_pane = self.ribbon.get_pane('Home Visualization')
1936
        if visualization_pane.ui.radioButtonByGroup.isChecked():
1937
            visualization_pane.ui.radioButtonByType.setChecked(True)
1938
        else:
1939
            visualization_pane.ui.radioButtonByGroup.setChecked(True)
1940

    
1941
    def display_colors(self, value):
1942
        """ display colors """
1943
        from DisplayColors import DisplayColors
1944
        from DisplayColors import DisplayOptions
1945

    
1946
        if hasattr(self, 'ribbon'):
1947
            visualization_pane = self.ribbon.get_pane('Home Visualization')
1948
            if self.sender() is visualization_pane.ui.radioButtonByGroup and value is True:
1949
                DisplayColors.instance().option = DisplayOptions.DisplayByLineNo
1950
            elif self.sender() is visualization_pane.ui.radioButtonByType and value is True:
1951
                DisplayColors.instance().option = DisplayOptions.DisplayByLineType
1952
            elif self.sender() is visualization_pane.ui.radioButtonByStreamNo and value is True:
1953
                DisplayColors.instance().option = DisplayOptions.DisplayByStreamNo
1954

    
1955
            if hasattr(self, 'graphicsView') and value is True:
1956
                self.graphicsView.scene().update(self.graphicsView.sceneRect())
1957
                for item in self.graphicsView.scene().items():
1958
                    if issubclass(type(item), SymbolSvgItem):
1959
                        item.update()
1960
                DisplayColors.instance().save_data()
1961

    
1962
    def open_image_drawing(self, drawing, force=False, ocrUnknown=False):
1963
        """open and display image drawing file"""
1964
        from Drawing import Drawing
1965
        from App import App
1966
        from LoadCommand import LoadCommand
1967
        import concurrent.futures as futures
1968

    
1969
        # Yield successive n-sized
1970
        # chunks from l.
1971
        def divide_chunks(l, n):
1972
            # looping till length l
1973
            for i in range(0, len(l), n):
1974
                yield l[i:i + n]
1975

    
1976
        def update_items(items):
1977
            for item in items:
1978
                # binding items
1979
                item.owner
1980
                for connector in item.connectors:
1981
                    connector.connectedItem
1982

    
1983
            return items
1984

    
1985
        try:
1986
            app_doc_data = AppDocData.instance()
1987

    
1988
            if not self.actionSave.isEnabled():
1989
                return
1990

    
1991
            if not force and self.save_drawing_if_necessary():
1992
                return
1993

    
1994
            occupied = app_doc_data.set_occupying_drawing(drawing.UID)
1995
            if occupied:
1996
                QMessageBox.about(self.graphicsView, self.tr("Notice"),
1997
                                  self.tr(f"The drawing is locked for editing by another user({occupied})"))
1998
                return
1999

    
2000
            # save alarm
2001
            self.save_alarm_enable(False)
2002

    
2003
            if hasattr(self, '_save_work_cmd'):
2004
                self._save_work_cmd.wait()
2005

    
2006
            project = app_doc_data.getCurrentProject()
2007

    
2008
            self.path = self.graphicsView.loadImageFromFile(drawing)
2009
            if os.path.isfile(self.path):
2010
                self.onCommandRejected()
2011
                app_doc_data.clear(past=drawing.UID)
2012

    
2013
                # load color for stream no coloring
2014
                configs = app_doc_data.getConfigs('Line List', 'Use Stream No')
2015
                if configs and int(configs[0].value) == 1:
2016
                    hmbs = app_doc_data.get_hmb_data(None)
2017
                    colors = {}
2018
                    if hmbs:
2019
                        for hmb in hmbs:
2020
                            rgb = app_doc_data.colors
2021
                            colors[hmb.stream_no] = QColor(rgb.red, rgb.green, rgb.blue).name()
2022
                        app_doc_data._hmbColors = colors
2023
                # up to here
2024

    
2025
                app_doc_data.setImgFilePath(self.path)
2026
                app_doc_data.activeDrawing = drawing
2027
                
2028
                #app_doc_data.activeDrawing.set_pid_source(Image.open(self.path))
2029
                self.itemTreeWidget.setCurrentPID(app_doc_data.activeDrawing.name)
2030

    
2031
                drawingList = self.treeWidgetDrawingList.topLevelItem(0)
2032
                for idx in range(drawingList.childCount()):
2033
                    child = drawingList.child(idx)
2034
                    if child.data(Qt.UserRole, 0) is drawing:
2035
                        child.setCheckState(0, Qt.Checked)
2036
                    else:
2037
                        child.setCheckState(0, Qt.Unchecked)
2038

    
2039
                try:
2040
                    self.show_Progress_bar()
2041

    
2042
                    # disconnect scene changed if signal is connected
2043
                    if self.graphicsView.scene().receivers(self.graphicsView.scene().contents_changed) > 0:
2044
                        self.graphicsView.scene().contents_changed.disconnect()
2045

    
2046
                    SymbolSvgItem.DOCUMENTS.clear()
2047

    
2048
                    # load data
2049
                    cmd = LoadCommand()
2050
                    cmd.display_message.connect(self.onAddMessage)
2051
                    cmd.set_maximum.connect(self.progress.setMaximum)
2052
                    cmd.show_progress.connect(self.progress.setValue)
2053
                    cmd.execute((drawing, self.graphicsView.scene()),
2054
                                symbol=True, text=True, line=True, unknown=True, package=True, update=True)
2055

    
2056
                    configs = app_doc_data.getConfigs('Line List', 'Use Stream No')
2057
                    if configs and int(configs[0].value) == 1:
2058
                        app_doc_data._streamLineListModelDatas = app_doc_data.get_stream_line_list_data()
2059
                    # up to here
2060

    
2061
                    """update item tree widget"""
2062
                    line_no_items = [item for item in self.graphicsView.scene().items()
2063
                                     if type(item) is QEngineeringLineNoTextItem]
2064
                    for line_no in line_no_items:
2065
                        line_no_tree_item = self.itemTreeWidget.addTreeItem(self.itemTreeWidget.root, line_no)
2066
                        for run in line_no.runs:
2067
                            for run_item in run.items:
2068
                                if issubclass(type(run_item), SymbolSvgItem):
2069
                                    self.init_add_tree_item(line_no_tree_item, run_item)
2070

    
2071
                    line_no_items = [item for item in self.graphicsView.scene().items()
2072
                                     if type(item) is QEngineeringTrimLineNoTextItem]
2073
                    for line_no in line_no_items:
2074
                        line_no_tree_item = self.itemTreeWidget.addTreeItem(self.itemTreeWidget.root, line_no)
2075
                        for run in line_no.runs:
2076
                            for run_item in run.items:
2077
                                if issubclass(type(run_item), SymbolSvgItem):
2078
                                    self.init_add_tree_item(line_no_tree_item, run_item)
2079

    
2080
                    for trim_line_no in app_doc_data.tracerLineNos:
2081
                        line_no_tree_item = self.itemTreeWidget.addTreeItem(self.itemTreeWidget.root, trim_line_no)
2082
                        for run in trim_line_no.runs:
2083
                            for run_item in run.items:
2084
                                if issubclass(type(run_item), SymbolSvgItem):
2085
                                    self.init_add_tree_item(line_no_tree_item, run_item)
2086

    
2087
                    self.itemTreeWidget.update_item_count()
2088
                    self.itemTreeWidget.expandAll()
2089
                    """up to here"""
2090

    
2091
                    """update scene"""
2092
                    for item in self._scene.items():
2093
                        item.setVisible(True)
2094

    
2095
                    self._scene.update(self._scene.sceneRect())
2096

    
2097
                    """
2098
                    # old open drawing
2099
                    path = os.path.join(app_doc_data.getCurrentProject().getTempPath(), app_doc_data.imgName + '.xml')
2100
                    configs = app_doc_data.getConfigs('Data Load', 'Xml First')
2101
                    if configs and int(configs[0].value) >= 1 and os.path.isfile(path):
2102
                        self.load_recognition_result_from_xml(drawing)
2103
                    elif configs and int(configs[0].value) <= 1:
2104
                        self.load_drawing(app_doc_data.activeDrawing)
2105
                    """
2106

    
2107
                    self.display_number_of_items()
2108
                    # connect scene changed signal
2109
                    self.graphicsView.scene().contents_changed.connect(self.scene_changed)
2110
                finally:
2111
                    if hasattr(self, 'progress'):
2112
                        self.progress.setValue(self.progress.maximum())
2113

    
2114
                self.changeViewCheckedState(True)
2115
                self.setWindowTitle(self.title)
2116
                self.fitWindow(drawing.view_rect)
2117

    
2118
                if ocrUnknown:
2119
                    self.on_ocr_unknown_items()
2120

    
2121
                # save alarm
2122
                self.save_alarm_enable(True, True)
2123
        except Exception as ex:
2124
            message = f"error occurred({repr(ex)}) in {sys.exc_info()[-1].tb_frame.f_code.co_filename}:" \
2125
                      f"{sys.exc_info()[-1].tb_lineno}"
2126
            self.addMessage.emit(MessageType.Error, message)
2127

    
2128
        return self.path
2129

    
2130
    def save_alarm_enable(self, enable, init=False):
2131
        from datetime import datetime
2132

    
2133
        try:
2134
            app_doc_data = AppDocData.instance()
2135
            configs = app_doc_data.getConfigs('Data Save', 'Time')
2136
            time_min = int(configs[0].value) if 1 == len(configs) else 0
2137

    
2138
            if enable and time_min > 0:
2139
                if not self.save_timer:
2140
                    self.save_timer = QTimer()
2141
                    self.save_timer.timeout.connect(self.save_alarm)
2142
                    self.save_timer.setInterval(60000)
2143

    
2144
                if init:
2145
                    self.save_timer._init_time = datetime.now()
2146
                    self.save_timer._stop_time = None
2147
                    self.save_timer._interval_time = datetime.now() - datetime.now()
2148

    
2149
                if self.save_timer._stop_time:
2150
                    self.save_timer._interval_time = datetime.now() - self.save_timer._stop_time
2151
                
2152
                #if 60000 * time_min != self.save_timer.interval():
2153
                #    self.save_timer.setInterval(60000)
2154

    
2155
                self.save_timer.start()
2156
            else:
2157
                if self.save_timer:
2158
                    self.save_timer.stop()
2159
                    self.save_timer._stop_time = datetime.now()
2160
        
2161
        except Exception as ex:
2162
            message = f"error occurred({repr(ex)}) in {sys.exc_info()[-1].tb_frame.f_code.co_filename}:" \
2163
                      f"{sys.exc_info()[-1].tb_lineno}"
2164
            self.addMessage.emit(MessageType.Error, message)
2165

    
2166
    def save_alarm(self):
2167
        from datetime import datetime
2168

    
2169
        app_doc_data = AppDocData.instance()
2170
        configs = app_doc_data.getConfigs('Data Save', 'Time')
2171
        time_min = int(configs[0].value) if 1 == len(configs) else 0
2172

    
2173
        self.save_timer.stop()
2174
        if self.graphicsView.hasFocus() and (datetime.now() - self.save_timer._init_time - self.save_timer._interval_time).seconds > time_min * 60:
2175
            QMessageBox.information(self, self.tr('Information'), self.tr('Please save Drawing'))
2176
            self.save_timer._init_time = datetime.now()
2177
            self.save_timer._interval_time = datetime.now() - datetime.now()
2178
        self.save_timer.start()
2179

    
2180
    def export_as_svg(self):
2181
        """export scene to svg file"""
2182
        from ExportCommand import ExportCommand
2183

    
2184
        options = QFileDialog.Options()
2185
        options |= QFileDialog.DontUseNativeDialog
2186
        file_path, _ = QFileDialog.getSaveFileName(self, "Export as svg", os.getcwd(), "svg file(*.svg)",
2187
                                                   options=options)
2188
        if file_path:
2189
            cmd = ExportCommand(self.graphicsView.scene(), 'svg')
2190
            cmd.display_message.connect(self.onAddMessage)
2191
            if cmd.execute(file_path):
2192
                QMessageBox.information(self, self.tr('Information'), self.tr('Successfully export to svg file'))
2193
            else:
2194
                QMessageBox.information(self, self.tr('Error'), self.tr('Fail to export to svg file'))
2195

    
2196
    def export_as_xml(self):
2197
        pass
2198

    
2199
    def export_as_image(self):
2200
        """export scene to image file"""
2201
        from ExportCommand import ExportCommand
2202

    
2203
        options = QFileDialog.Options()
2204
        options |= QFileDialog.DontUseNativeDialog
2205
        file_path, _ = QFileDialog.getSaveFileName(self, "Export as png", os.getcwd(), "png file(*.png)",
2206
                                                   options=options)
2207
        if file_path:
2208
            try:
2209
                # hide image drawing
2210
                self.onViewImageDrawing(False)
2211

    
2212
                cmd = ExportCommand(self.graphicsView.scene(), 'image')
2213
                cmd.display_message.connect(self.onAddMessage)
2214

    
2215
                if cmd.execute(file_path):
2216
                    QMessageBox.information(self, self.tr('Information'), self.tr('Successfully export to image file'))
2217
                else:
2218
                    QMessageBox.information(self, self.tr('Error'), self.tr('Fail to export to image file'))
2219
            finally:
2220
                if self.actionImage_Drawing.isChecked():
2221
                    self.onViewImageDrawing(True)
2222
                    self.actionImage_Drawing.setChecked(True)
2223

    
2224
    def show_Progress_bar(self):
2225
        """ show progress bar """
2226
        self.progress = QProgressDialog(self.tr("Please wait for a while"), self.tr("Cancel"), 0, 100,
2227
                                        self) if not hasattr(self, 'progress') else self.progress
2228
        self.progress.setWindowModality(Qt.WindowModal)
2229
        self.progress.setAutoReset(True)
2230
        self.progress.setAutoClose(True)
2231
        self.progress.setMinimum(0)
2232
        self.progress.setMaximum(100)
2233
        self.progress.resize(600, 100)
2234
        self.progress.setWindowTitle(self.tr("Reading file..."))
2235
        self.progress.show()
2236

    
2237
    def changeViewCheckedState(self, checked, clear=True):
2238
        """change view checked state"""
2239
        # self.actionImage_Drawing.setChecked(checked)
2240
        self.actionViewText.setChecked(checked)
2241
        self.actionViewSymbol.setChecked(checked)
2242
        self.actionViewLine.setChecked(checked)
2243
        self.actionViewUnknown.setChecked(checked)
2244
        self.actionViewInconsistency.setChecked(checked)
2245
        self.actionViewVendor_Area.setChecked(not checked)
2246
        self.actionDrawing_Only.setChecked(not checked)
2247
        if clear:
2248
            self.tableWidgetInconsistency.clearContents()
2249
            self.tableWidgetInconsistency.setRowCount(0)
2250

    
2251
    def onViewDrawingOnly(self, isChecked):
2252
        '''
2253
            @brief  visible/invisible except image drawing
2254
            @author euisung
2255
            @date   2019.04.22
2256
        '''
2257
        self.changeViewCheckedState(not isChecked, False)
2258
        for item in self.graphicsView.scene().items():
2259
            if type(item) is not QGraphicsPixmapItem:
2260
                item.setVisible(not isChecked)
2261

    
2262
    '''
2263
        @brief  visible/invisible image drawing
2264
        @author humkyung
2265
        @date   2018.06.25
2266
    '''
2267
    def onViewImageDrawing(self, isChecked):
2268
        for item in self.graphicsView.scene().items():
2269
            if type(item) is QGraphicsPixmapItem:
2270
                item.setVisible(isChecked)
2271
                break
2272

    
2273
    def onViewText(self, checked):
2274
        """visible/invisible text"""
2275
        selected = [item for item in self.graphicsView.scene().items() if issubclass(type(item), QEngineeringTextItem)
2276
                    and type(item) is not QEngineeringLineNoTextItem]
2277
        for item in selected:
2278
            item.setVisible(checked)
2279

    
2280
    def onViewSymbol(self, checked):
2281
        """visible/invisible symbol"""
2282
        selected = [item for item in self.graphicsView.scene().items() if
2283
                    (issubclass(type(item), SymbolSvgItem) and type(item) is not QEngineeringErrorItem)]
2284
        for item in selected:
2285
            item.setVisible(checked)
2286

    
2287
    def onViewLine(self, checked):
2288
        """visible/invisible line"""
2289
        selected = [item for item in self.graphicsView.scene().items() if type(item) is QEngineeringLineItem]
2290
        for item in selected:
2291
            item.setVisible(checked)
2292

    
2293
    def onViewInconsistency(self, isChecked):
2294
        '''
2295
            @brief  visible/invisible Inconsistency
2296
            @author euisung
2297
            @date   2019.04.03
2298
        '''
2299
        selected = [item for item in self.graphicsView.scene().items() if type(item) is QEngineeringErrorItem]
2300
        for item in selected:
2301
            item.setVisible(isChecked)
2302

    
2303
    '''
2304
        @brief  visible/invisible Unknown 
2305
        @author humkyung
2306
        @date   2018.06.28
2307
    '''
2308
    def onViewUnknown(self, isChecked):
2309
        selected = [item for item in self.graphicsView.scene().items() if type(item) is QEngineeringUnknownItem]
2310
        for item in selected:
2311
            item.setVisible(isChecked)
2312

    
2313
    def onViewVendorArea(self, isChecked):
2314
        '''
2315
            @brief  visible/invisible Vendor Area
2316
            @author euisung
2317
            @date   2019.04.29
2318
        '''
2319
        selected = [item for item in self.graphicsView.scene().items() if issubclass(type(item), QEngineeringVendorItem)]
2320
        for item in selected:
2321
            item.setVisible(isChecked)
2322

    
2323
    '''
2324
        @brief  create a symbol
2325
        @history    2018.05.02  Jeongwoo    Change return value of QSymbolEditorDialog (Single variable → Tuple)
2326
                                            Add SymbolSvgItem
2327
                    2018.05.03  Jeongwoo    Change method to draw Svg Item on Scene (svg.addSvgItemToScene)
2328
                                            Change method to make svg and image path
2329
                    2018.06.08  Jeongwoo    Add Paramter on SymbolSvgItem.buildItem()
2330
    '''
2331
    def onCreateSymbolClicked(self):
2332
        selected = [item for item in self.graphicsView.scene().selectedItems() if issubclass(type(item), QEngineeringVendorItem)]
2333
        if len(selected) == 1:
2334
            symbol_image = AppDocData.instance().activeDrawing.image_origin
2335
            rect = selected[0].sceneBoundingRect()
2336

    
2337
            points = []
2338
            for conn in selected[0].connectors:
2339
                points.append([round(conn.center()[0] - rect.x()), round(conn.center()[1] - rect.y())])
2340
            poly = np.array(points, np.int32)
2341

    
2342
            #mask = np.zeros((int(rect.height()), int(rect.width())))
2343
            #cv2.fillPoly(mask, [poly], (255))
2344
            #poly_copied = np.multiply(mask, symbol_image[round(rect.y()):round(rect.y() + rect.height()),
2345
            #                   round(rect.x()):round(rect.x() + rect.width())])
2346
            #cv2.fillPoly(mask,[poly],0)
2347
            #src2 = np.multiply(mask,src2)
2348

    
2349
            mask = np.ones((int(rect.height()), int(rect.width())), dtype=np.uint8) * 255
2350
            cv2.fillPoly(mask, [poly], (0))
2351
            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())])
2352
            sym_img = cv2.merge((sym_img, sym_img, sym_img))
2353

    
2354
            h, w, c = sym_img.shape
2355
            qImg = QImage(sym_img.data, w, h, w * c, QImage.Format_RGB888)
2356
            #pixmap = QPixmap.fromImage(qImg)
2357

    
2358
            self.onAreaSelected(None, None, None, None, package=qImg, position=rect.topLeft(), package_item=selected[0])
2359
        else:
2360
            cmd = FenceCommand.FenceCommand(self.graphicsView)
2361
            cmd.onSuccess.connect(self.onAreaSelected)
2362
            self.graphicsView.command = cmd
2363
            QApplication.setOverrideCursor(Qt.CrossCursor)
2364

    
2365
    '''
2366
        @brief      show SymbolEditorDialog with image selected by user
2367
        @author     humkyung
2368
        @date       2018.07.20
2369
    '''
2370
    def onAreaSelected(self, x, y, width, height, package=False, position=None, package_item=None):
2371
        try:
2372
            image = self.graphicsView.image()
2373
            if image is not None:
2374
                if not package:
2375
                    symbolEditorDialog = SymbolEditorDialog.QSymbolEditorDialog(self, image.copy(x, y, width, height),
2376
                                                                                AppDocData.instance().getCurrentProject())
2377
                else:
2378
                    symbolEditorDialog = SymbolEditorDialog.QSymbolEditorDialog(self, package,
2379
                                                                                AppDocData.instance().getCurrentProject(), package=True)
2380
                (isAccepted, isImmediateInsert, offsetX, offsetY, newSym) = symbolEditorDialog.showDialog()
2381
                # TODO: not initialize symbol tree view when user reject to create a new symbol
2382
                self.symbolTreeWidget.initSymbolTreeView()
2383
                if isAccepted:
2384
                    if isImmediateInsert:
2385
                        svg = QtImageViewer.createSymbolObject(newSym.getName())
2386
                        offsetX, offsetY = [int(point) for point in newSym.getOriginalPoint().split(',')]
2387
                        QtImageViewer.matchSymbolToLine(self.graphicsView.scene(), svg, QPoint(position.x() + offsetX, position.y() + offsetY))
2388

    
2389
                        package_item.transfer.onRemoved.emit(package_item)
2390
        finally:
2391
            self.onCommandRejected()
2392
            QApplication.restoreOverrideCursor()
2393
            QApplication.restoreOverrideCursor()
2394

    
2395
    def on_line_list(self):
2396
        """ line list export dialog """
2397
        from LineListDialog import LineListDialog
2398

    
2399
        if not self.graphicsView.hasImage():
2400
            self.showImageSelectionMessageBox()
2401
            return
2402

    
2403
        dialog = LineListDialog(self)
2404
        dialog.showDialog()
2405

    
2406
    def on_make_label_data(self):
2407
        """ make label data from symbol info """
2408
        from xml.etree.ElementTree import Element, SubElement, dump, ElementTree, parse
2409

    
2410
        if not self.graphicsView.hasImage():
2411
            self.showImageSelectionMessageBox()
2412
            return
2413

    
2414
        app_doc_data = AppDocData.instance()
2415
        project = app_doc_data.getCurrentProject()
2416

    
2417
        smalls = []
2418
        bigs = []
2419

    
2420
        symbol_list = app_doc_data.getTargetSymbolList(all=True)
2421
        #symbol_list = app_doc_data.getTargetSymbolList(all=False)
2422
        for symbol in symbol_list:
2423
            if symbol.iType == 38 or symbol.iType == 33 or symbol.iType == 0 or symbol.iType == 40:
2424
                continue
2425
            elif symbol.width and symbol.height:
2426
                if symbol.width > 300 or symbol.height > 300:
2427
                    bigs.append(symbol.getName())
2428
                elif (symbol.width * symbol.height < 1500) or (symbol.width > 450 or symbol.height > 450):
2429
                    continue
2430
                else:
2431
                    smalls.append(symbol.getName())
2432

    
2433
        symbols = [item for item in self.graphicsView.scene().items() if issubclass(type(item), SymbolSvgItem)]
2434
        names = [smalls, bigs]
2435

    
2436
        img = app_doc_data.activeDrawing.image_origin
2437

    
2438
        small_size = 500
2439
        big_size = 850
2440

    
2441
        save_path = project.getTrainingSymbolFilePath()
2442

    
2443
        index = 0
2444
        for size in [small_size, big_size]:
2445
            offsets = [0, int(size / 2)]
2446

    
2447
            width, height = img.shape[1], img.shape[0]
2448
            width_count, height_count = width // size + 2, height // size + 2
2449
            b_width, b_height = width_count * size, height_count * size
2450
            b_img = np.zeros((b_height, b_width), np.uint8) + 255
2451
            b_img[:height, :width] = img[:, :]
2452

    
2453
            for offset in offsets:
2454
                for row in range(height_count):
2455
                    for col in range(width_count):
2456
                        x, y = col * size + offset, row * size + offset
2457
                        tile_rect = QRectF(x, y, size, size)
2458
                        tile_symbols = []
2459
                        for symbol in [symbol for symbol in symbols if symbol.name in names[index]]:
2460
                            if tile_rect.contains(symbol.sceneBoundingRect()):
2461
                                tile_symbols.append(symbol)
2462
                                symbols.remove(symbol)
2463

    
2464
                        if tile_symbols:
2465
                            training_uid = str(uuid.uuid4())
2466
                            training_image_path = os.path.join(save_path, training_uid + '.png')
2467
                            training_xml_path = os.path.join(save_path, training_uid + '.xml')
2468

    
2469
                            # save image
2470
                            #_img = b_img[round(tile_rect.top()):round(tile_rect.bottom()),
2471
                            #       round(tile_rect.left()):round(tile_rect.right())]
2472
                            #cv2.imwrite(training_image_path, _img)
2473
                            _img = self.graphicsView.image().copy(round(tile_rect.left()), round(tile_rect.top()), round(tile_rect.width()), round(tile_rect.height()))
2474
                            _img.save(training_image_path)
2475

    
2476
                            # save label
2477
                            xml = Element('annotation')
2478
                            SubElement(xml, 'folder').text = 'None'
2479
                            SubElement(xml, 'filename').text = os.path.basename(save_path)
2480

    
2481
                            pathNode = Element('path')
2482
                            pathNode.text = save_path.replace('/', '\\')
2483
                            xml.append(pathNode)
2484

    
2485
                            sourceNode = Element('source')
2486
                            databaseNode = Element('database')
2487
                            databaseNode.text = 'Unknown'
2488
                            sourceNode.append(databaseNode)
2489
                            xml.append(sourceNode)
2490

    
2491
                            sizeNode = Element('size')
2492
                            widthNode = Element('width')
2493
                            widthNode.text = str(int(tile_rect.width()))
2494
                            sizeNode.append(widthNode)
2495
                            heightNode = Element('height')
2496
                            heightNode.text = str(int(tile_rect.height()))
2497
                            sizeNode.append(heightNode)
2498
                            depthNode = Element('depth')
2499
                            depthNode.text = '3'
2500
                            sizeNode.append(depthNode)
2501
                            xml.append(sizeNode)
2502

    
2503
                            segmentedNode = Element('segmented')
2504
                            segmentedNode.text = '0'
2505
                            xml.append(segmentedNode)
2506

    
2507
                            labelContent = []
2508
                            counts = {}
2509
                            for item in tile_symbols:
2510
                                rect = item.sceneBoundingRect()
2511
                                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)
2512
                                #label = 'small' if index == 0 else 'big' # for single class test
2513
                                xMin = xMin if xMin > 0 else 0
2514
                                yMin = yMin if yMin > 0 else 0
2515
                                xMax = xMax if xMax < size else size
2516
                                yMax = yMax if yMax < size else size
2517

    
2518
                                if label == 'None' or label == '':
2519
                                    continue
2520
                                if label not in labelContent:
2521
                                    labelContent.append(label)
2522
                                    counts[label] = 1
2523
                                else:
2524
                                    counts[label] = counts[label] + 1
2525

    
2526
                                objectNode = Element('object')
2527
                                nameNode = Element('name')
2528
                                nameNode.text = label
2529
                                objectNode.append(nameNode)
2530
                                poseNode = Element('pose')
2531
                                poseNode.text = 'Unspecified'
2532
                                objectNode.append(poseNode)
2533
                                truncatedNode = Element('truncated')
2534
                                truncatedNode.text = '0'
2535
                                objectNode.append(truncatedNode)
2536
                                difficultNode = Element('difficult')
2537
                                difficultNode.text = '0'
2538
                                objectNode.append(difficultNode)
2539

    
2540
                                bndboxNode = Element('bndbox')
2541
                                xminNode = Element('xmin')
2542
                                xminNode.text = str(xMin)
2543
                                bndboxNode.append(xminNode)
2544
                                yminNode = Element('ymin')
2545
                                yminNode.text = str(yMin)
2546
                                bndboxNode.append(yminNode)
2547
                                xmaxNode = Element('xmax')
2548
                                xmaxNode.text = str(xMax)
2549
                                bndboxNode.append(xmaxNode)
2550
                                ymaxNode = Element('ymax')
2551
                                ymaxNode.text = str(yMax)
2552
                                bndboxNode.append(ymaxNode)
2553
                                objectNode.append(bndboxNode)
2554

    
2555
                                xml.append(objectNode)
2556

    
2557
                            ElementTree(xml).write(training_xml_path)
2558

    
2559
            index += 1
2560

    
2561
        QMessageBox.about(self, self.tr("Notice"), self.tr('Successfully applied. '))
2562

    
2563
    def onPlaceLine(self):
2564
        """create a line"""
2565
        home_pane = self.ribbon.get_pane('Home')
2566

    
2567
        if not self.graphicsView.hasImage():
2568
            home_pane.ui.toolButtonLine.setChecked(False)
2569
            self.showImageSelectionMessageBox()
2570
            return
2571

    
2572
        self.update_action_group(home_pane.ui.toolButtonLine)
2573
        if not hasattr(home_pane.ui.toolButtonLine, 'tag'):
2574
            home_pane.ui.toolButtonLine.tag = PlaceLineCommand.PlaceLineCommand(self.graphicsView)
2575
            home_pane.ui.toolButtonLine.tag.onSuccess.connect(self.onLineCreated)
2576
            home_pane.ui.toolButtonLine.tag.onRejected.connect(self.onCommandRejected)
2577

    
2578
        self.graphicsView.command = home_pane.ui.toolButtonLine.tag
2579

    
2580
    def onLineCreated(self):
2581
        """add created lines to scene"""
2582
        from EngineeringConnectorItem import QEngineeringConnectorItem
2583
        from LineDetector import LineDetector
2584

    
2585
        try:
2586
            app_doc_data = AppDocData.instance()
2587
            home_pane = self.ribbon.get_pane('Home')
2588

    
2589
            count = len(home_pane.ui.toolButtonLine.tag._polyline._vertices)
2590
            if count > 1:
2591
                items = []
2592

    
2593
                detector = LineDetector(None)
2594

    
2595
                if not home_pane.ui.toolButtonLine.tag.line_type:
2596
                    line_type = home_pane.ui.comboBoxLineType.currentText()
2597
                else:
2598
                    pane = self.ribbon.get_pane('Home')
2599
                    selected_line_type = pane.ui.comboBoxLineType.currentText()
2600
                    if selected_line_type == 'Connect To Process':
2601
                        line_type = selected_line_type
2602
                    elif not (QEngineeringLineItem.check_piping(home_pane.ui.toolButtonLine.tag.line_type) ^
2603
                              QEngineeringLineItem.check_piping(selected_line_type)):
2604
                        line_type = selected_line_type
2605
                    else:
2606
                        line_type = home_pane.ui.toolButtonLine.tag.line_type
2607
                for index in range(count - 1):
2608
                    start = home_pane.ui.toolButtonLine.tag._polyline._vertices[index]
2609
                    end = home_pane.ui.toolButtonLine.tag._polyline._vertices[index + 1]
2610

    
2611
                    lineItem = QEngineeringLineItem(vertices=[start, end])
2612
                    lineItem.transfer.onRemoved.connect(self.itemRemoved)
2613
                    lineItem.lineType = line_type
2614
                    if items:
2615
                        lineItem.connect_if_possible(items[-1], 5)
2616
                    else:
2617
                        pt = lineItem.start_point()
2618
                        selected = [item for item in self.graphicsView.scene().items(QPointF(pt[0], pt[1])) if
2619
                                    type(item) is QEngineeringConnectorItem or type(item) is QEngineeringLineItem]
2620
                        if selected and selected[0] is not lineItem:
2621
                            if type(selected[0]) is QEngineeringConnectorItem:
2622
                                lineItem.connect_if_possible(selected[0].parent, 5)
2623
                            else:
2624
                                detector.connectLineToLine(selected[0], lineItem, 5)
2625

    
2626
                    items.append(lineItem)
2627
                    self.graphicsView.scene().addItem(lineItem)
2628

    
2629
                pt = items[-1].end_point()
2630
                selected = [item for item in self.graphicsView.scene().items(QPointF(pt[0], pt[1])) if
2631
                            (type(item) is QEngineeringConnectorItem and item.parentItem() is not items[-1]) or
2632
                            (type(item) is QEngineeringLineItem and item is not items[-1])]
2633
                if selected and selected[0] is not items[-1]:
2634
                    if type(selected[0]) is QEngineeringConnectorItem:
2635
                        items[-1].connect_if_possible(selected[0].parent, 5)
2636
                    else:
2637
                        detector.connectLineToLine(selected[0], items[-1], 5)
2638

    
2639
                self._scene.undo_stack.push(CreateCommand(self._scene, items))
2640
        finally:
2641
            self.graphicsView.scene().removeItem(home_pane.ui.toolButtonLine.tag._polyline)
2642
            home_pane.ui.toolButtonLine.tag.reset()
2643

    
2644
    def onCommandRejected(self, cmd=None):
2645
        """command is rejected"""
2646
        try:
2647
            home_pane = self.ribbon.get_pane('Home')
2648
            visualization_pane = self.ribbon.get_pane('Home Visualization')
2649
            if type(cmd) is PlaceLineCommand.PlaceLineCommand:
2650
                if home_pane.ui.toolButtonLine.tag._polyline:
2651
                    self.graphicsView.scene().removeItem(home_pane.ui.toolButtonLine.tag._polyline)
2652
                self.graphicsView.scene().update()
2653
                home_pane.ui.toolButtonLine.tag.reset()
2654

    
2655
                home_pane.ui.toolButtonLine.setChecked(False)
2656
            elif type(cmd) is AreaZoomCommand.AreaZoomCommand:
2657
                visualization_pane.ui.toolButtonZoom.setChecked(False)
2658
            elif type(cmd) is AreaOcrCommand.AreaOcrCommand:
2659
                home_pane.ui.toolButtonOCR.setChecked(False)
2660
            elif type(cmd) is PlacePolygonCommand.PlacePolygonCommand:
2661
                home_pane.ui.toolButtonVendor.setChecked(False)
2662
            else:
2663
                if hasattr(home_pane.ui.toolButtonVendor, 'tag') and home_pane.ui.toolButtonVendor.tag._polyline:
2664
                    self.graphicsView.scene().removeItem(home_pane.ui.toolButtonVendor.tag._polyline)
2665
                    self.graphicsView.scene().update()
2666
                    home_pane.ui.toolButtonVendor.tag.reset()
2667
                home_pane.ui.toolButtonLine.setChecked(False)
2668
                visualization_pane.ui.toolButtonZoom.setChecked(False)
2669
                home_pane.ui.toolButtonOCR.setChecked(False)
2670
                home_pane.ui.toolButtonVendor.setChecked(False)
2671
        finally:
2672
            self.graphicsView.useDefaultCommand()
2673

    
2674
    def on_view_toggle(self, key: int) -> None:
2675
        """view toggled"""
2676

    
2677
        view_pane = self.ribbon.get_pane('View')
2678
        if key == Qt.Key_1:
2679
            checked = view_pane.ui.toolButtonViewImageDrawing.isChecked()
2680
            self.onViewImageDrawing(not checked)
2681
            view_pane.ui.toolButtonViewImageDrawing.setChecked(not checked)
2682
        elif key == Qt.Key_2:
2683
            checked = view_pane.ui.toolButtonViewText.isChecked()
2684
            self.onViewText(not checked)
2685
            view_pane.ui.toolButtonViewText.setChecked(not checked)
2686
        elif key == Qt.Key_3:
2687
            checked = view_pane.ui.toolButtonViewSymbol.isChecked()
2688
            self.onViewSymbol(not checked)
2689
            view_pane.ui.toolButtonViewSymbol.setChecked(not checked)
2690
        elif key == Qt.Key_4:
2691
            checked = view_pane.ui.toolButtonViewLine.isChecked()
2692
            self.onViewLine(not checked)
2693
            view_pane.ui.toolButtonViewLine.setChecked(not checked)
2694
        elif key == Qt.Key_5:
2695
            checked = view_pane.ui.toolButtonViewUnknown.isChecked()
2696
            self.onViewUnknown(not checked)
2697
            view_pane.ui.toolButtonViewUnknown.setChecked(not checked)
2698
        elif key == Qt.Key_6:
2699
            checked = view_pane.ui.toolButtonViewInconsistency.isChecked()
2700
            self.onViewInconsistency(not checked)
2701
            view_pane.ui.toolButtonViewInconsistency.setChecked(not checked)
2702
        elif key == Qt.Key_7:
2703
            checked = view_pane.ui.toolButtonViewVendorArea.isChecked()
2704
            self.onViewVendorArea(not checked)
2705
            view_pane.ui.toolButtonViewVendorArea.setChecked(not checked)
2706
        elif key == 96:  # '~' key
2707
            checked = view_pane.ui.toolButtonViewDrawingOnly.isChecked()
2708
            self.onViewDrawingOnly(not checked)
2709
            view_pane.ui.toolButtonViewDrawingOnly.setChecked(not checked)
2710

    
2711
    def keyPressEvent(self, event):
2712
        """restore to default command when user press Escape key"""
2713
        try:
2714
            if event.key() == Qt.Key_Escape:
2715
                checked = self.checked_action()
2716
                if checked:
2717
                    checked.setChecked(False)
2718
                    self.graphicsView.useDefaultCommand()
2719
            elif event.key() == Qt.Key_M:  # merge text as vertical
2720
                from TextInfo import TextInfo
2721

    
2722
                textItems = [text for text in self.graphicsView.scene().selectedItems() if
2723
                             issubclass(type(text), QEngineeringTextItem)]
2724
                if not textItems or len(textItems) is 1:
2725
                    return
2726

    
2727
                angle = None
2728
                for item in textItems:
2729
                    if angle is None:
2730
                        angle = item.angle
2731
                    else:
2732
                        if angle != item.angle:
2733
                            return
2734

    
2735
                modifiers = QApplication.keyboardModifiers()
2736
                enter_or_space = ' ' if modifiers == Qt.ControlModifier else '\n'
2737
                x_or_y = 0 if (modifiers == Qt.ControlModifier and angle == 0) or (modifiers != Qt.ControlModifier and angle == 1.57) else 1
2738

    
2739
                textItems = sorted(textItems, key=lambda text: text.loc[x_or_y]) if textItems[0].angle == 0 else ( \
2740
                    sorted(textItems, key=lambda text: text.loc[x_or_y]) if textItems[0].angle == 1.57 else ( \
2741
                        sorted(textItems, key=lambda text: text.loc[x_or_y], reverse=True) if textItems[0].angle == 4.71 else \
2742
                            sorted(textItems, key=lambda text: text.loc[x_or_y], reverse=True)))
2743

    
2744
                if textItems[0].angle == 1.57 and modifiers == Qt.ControlModifier:
2745
                    textItems.reverse()
2746

    
2747
                minX = sys.maxsize
2748
                minY = sys.maxsize
2749
                maxX = 0
2750
                maxY = 0
2751
                newText = ''
2752

    
2753
                for text in textItems:
2754
                    if text.loc[0] < minX: minX = text.loc[0]
2755
                    if text.loc[1] < minY: minY = text.loc[1]
2756
                    if text.loc[0] + text.size[0] > maxX: maxX = text.loc[0] + text.size[0]
2757
                    if text.loc[1] + text.size[1] > maxY: maxY = text.loc[1] + text.size[1]
2758
                    newText = newText + text.text() + enter_or_space
2759
                    text.transfer.onRemoved.emit(text)
2760
                newText = newText[:-1]
2761

    
2762
                textInfo = TextInfo(newText, minX, minY, maxX - minX, maxY - minY, textItems[0].angle)
2763
                x = textInfo.getX()
2764
                y = textInfo.getY()
2765
                angle = textInfo.getAngle()
2766
                text = textInfo.getText()
2767
                width = textInfo.getW()
2768
                height = textInfo.getH()
2769
                item = TextItemFactory.instance().createTextItem(textInfo)
2770
                if item is not None:
2771
                    item.loc = [x, y]
2772
                    item.size = (width, height)
2773
                    item.angle = angle
2774
                    item.area = textItems[0].area
2775
                    item.setDefaultTextColor(Qt.blue)
2776
                    item.addTextItemToScene(self.graphicsView.scene())
2777
                    item.transfer.onRemoved.connect(self.itemRemoved)
2778
            elif event.key() == Qt.Key_D:
2779
                # pop up development toolkit dialog
2780
                from DevelopmentToolkitDialog import QDevelopmentToolkitDialog
2781

    
2782
                modifiers = QApplication.keyboardModifiers()
2783
                if modifiers == Qt.ControlModifier:
2784
                    dlg = QDevelopmentToolkitDialog(self, self.graphicsView)
2785
                    dlg.show()
2786
            elif event.key() == Qt.Key_I:
2787
                # insert symbol item that is selected symbol in tree to main window if symbol already selected on main window, replace
2788
                index = self.symbolTreeWidget.currentIndex()
2789
                proxy_model = self.symbolTreeWidget.model()
2790
                items = [proxy_model.sourceModel().itemFromIndex(proxy_model.mapToSource(index))]
2791
                if items and hasattr(items[0], 'svgFilePath'):
2792
                    symData = items[0].data(self.symbolTreeWidget.TREE_DATA_ROLE)
2793
                    symName = symData.getName()
2794
                else:
2795
                    return
2796

    
2797
                symbolItems = [symbol for symbol in self.graphicsView.scene().selectedItems() if
2798
                               issubclass(type(symbol), SymbolSvgItem)]
2799
                old_symbol = None
2800
                if symbolItems and len(symbolItems) is 1:
2801
                    old_symbol = symbolItems[0]
2802
                    #scenePos = QPoint(old_symbol.origin[0], old_symbol.origin[1])
2803
                    scenePos = old_symbol.mapToScene(old_symbol.transformOriginPoint())
2804
                    old_symbol.transfer.onRemoved.emit(old_symbol)
2805
                else:
2806
                    scenePos = self.current_pos
2807

    
2808
                svg = QtImageViewer.createSymbolObject(symName)
2809
                QtImageViewer.matchSymbolToLine(self.graphicsView.scene(), svg, scenePos, angle=old_symbol.angle if old_symbol else 0.0)
2810

    
2811
                if old_symbol and svg:
2812
                    from ReplaceCommand import ReplaceCommand
2813

    
2814
                    cmd = ReplaceCommand(self.graphicsView.scene(), old_symbol, svg)
2815
                    self._scene.undo_stack.push(cmd)
2816
                    return
2817
            elif event.key() == Qt.Key_J:
2818
                # insert and connect symbol item that is selected symbol in tree to selected symbol
2819
                index = self.symbolTreeWidget.currentIndex()
2820
                proxy_model = self.symbolTreeWidget.model()
2821
                items = [proxy_model.sourceModel().itemFromIndex(proxy_model.mapToSource(index))]
2822
                if items and hasattr(items[0], 'svgFilePath'):
2823
                    symData = items[0].data(self.symbolTreeWidget.TREE_DATA_ROLE)
2824
                    symName = symData.getName()
2825
                else:
2826
                    return
2827

    
2828
                symbolItems = [symbol for symbol in self.graphicsView.scene().selectedItems() if
2829
                               issubclass(type(symbol), SymbolSvgItem)]
2830
                if symbolItems and len(symbolItems) is not 1:
2831
                    return
2832
                    
2833
                target_symbol = symbolItems[0]
2834
                index =  [index for index in range(len(target_symbol.conn_type)) \
2835
                            if target_symbol.conn_type[index] == 'Primary' or target_symbol.conn_type[index] == 'Secondary']
2836
                for connector in target_symbol.connectors:
2837
                    svg = QtImageViewer.createSymbolObject(symName)
2838
                    if len(svg.connectors) > 1: 
2839
                        if ((target_symbol.conn_type and target_symbol.connectors.index(connector) in index) or not target_symbol.conn_type) and \
2840
                                    (not connector.connectedItem or (connector.connectedItem and type(connector.connectedItem) is QEngineeringLineItem)):
2841
                            QtImageViewer.matchSymbolToLine(self.graphicsView.scene(), svg, connector.sceneBoundingRect().center())
2842
                    elif len(svg.connectors) == 1:
2843
                        if ((target_symbol.conn_type and target_symbol.connectors.index(connector) in index) or not target_symbol.conn_type) and \
2844
                                    not connector.connectedItem:
2845
                            QtImageViewer.matchSymbolToLine(self.graphicsView.scene(), svg, connector.sceneBoundingRect().center())
2846

    
2847
                if target_symbol:
2848
                    return
2849
            elif event.key() == Qt.Key_X:
2850
                pass
2851
                '''
2852
                app_doc_data = AppDocData.instance()
2853
                configs = app_doc_data.getAppConfigs('app', 'mode')
2854
                if configs and 1 == len(configs) and 'advanced' == configs[0].value:
2855
                    advanced = True
2856
                    items = self.graphicsView.scene().selectedItems()
2857
                    if items:
2858
                        item = self.symbolTreeWidget.currentItem()
2859
                        if item:
2860
                            self.symbolTreeWidget.showSymbolEditorDialog(item, 0)
2861
                '''
2862
            elif event.key() == Qt.Key_F6:
2863
                from DEXPI import scene_to_dexpi
2864

    
2865
                app_doc_data = AppDocData.instance()
2866
                scene_to_dexpi('D:\\Temp\\DEXPI.xml', app_doc_data.activeDrawing.name, self.graphicsView.scene())
2867

    
2868
            QMainWindow.keyPressEvent(self, event)
2869
        except Exception as ex:
2870
            message = f"error occurred({repr(ex)}) in {sys.exc_info()[-1].tb_frame.f_code.co_filename}:" \
2871
                      f"{sys.exc_info()[-1].tb_lineno}"
2872
            self.addMessage.emit(MessageType.Error, message)
2873

    
2874
    def recognize(self):
2875
        """recognize symbol, text and line for selected drawings"""
2876
        from datetime import datetime
2877
        from License import QLicenseDialog
2878

    
2879
        # save alarm
2880
        self.save_alarm_enable(False)
2881

    
2882
        app_doc_data = AppDocData.instance()
2883
        current_drawing, currentPid = None, None
2884

    
2885
        if self.graphicsView.hasImage():
2886
            current_drawing = app_doc_data.activeDrawing
2887
            currentPid = app_doc_data.activeDrawing.name
2888

    
2889
        # get checked drawings
2890
        drawing_top = self.treeWidgetDrawingList.topLevelItem(0)
2891
        count = drawing_top.childCount()
2892
        checked_drawings = {}
2893
        for idx in range(count):
2894
            child = drawing_top.child(idx)
2895
            if child.checkState(0) == Qt.Checked and child.data(Qt.UserRole, 0):
2896
                checked_drawings[child.data(Qt.UserRole, 0)] = child
2897
        # up to here
2898

    
2899
        # if there is no checked drawing
2900
        if current_drawing and currentPid and not checked_drawings:
2901
            for idx in range(count):
2902
                child = drawing_top.child(idx)
2903
                if child.data(Qt.UserRole, 0) is current_drawing:
2904
                    checked_drawings[child.data(Qt.UserRole, 0)] = child
2905

    
2906
        if not checked_drawings:
2907
            self.showImageSelectionMessageBox()
2908
            return
2909

    
2910
        try:
2911
            self.on_clear_log()
2912
            dlg = QRecognitionDialog(self, [drawing for drawing in checked_drawings.keys()])
2913
            dlg.exec_()
2914

    
2915
            if current_drawing and current_drawing in checked_drawings.keys() and dlg.isTreated:
2916
                self.open_image_drawing(current_drawing, force=True, ocrUnknown=dlg.ui.checkBoxOCRUnknown.isChecked())
2917

    
2918
            # save working date-time
2919
            _now = datetime.now().strftime('%Y-%m-%d %H:%M:%S')
2920
            for drawing, tree_item in checked_drawings.items():
2921
                drawing.datetime = _now
2922
                tree_item.setText(1, _now)
2923
            #app_doc_data.saveDrawings(checked_drawings.keys())
2924
            self.changeViewCheckedState(True)
2925
            # count up for recognition
2926
            QLicenseDialog.count_up()
2927
            # up to here
2928
        except Exception as ex:
2929
            message = f"error occurred({repr(ex)}) in {sys.exc_info()[-1].tb_frame.f_code.co_filename}:" \
2930
                      f"{sys.exc_info()[-1].tb_lineno}"
2931
            self.addMessage.emit(MessageType.Error, message)
2932

    
2933
        # save alarm
2934
        self.save_alarm_enable(True, True)
2935

    
2936
    '''
2937
        @brief      remove item from tree widget and then remove from scene
2938
        @date       2018.05.25
2939
        @author     Jeongwoo
2940
    '''
2941
    def itemRemoved(self, item):
2942
        try:
2943
            if type(item) is QEngineeringErrorItem:
2944
                # remove error item from inconsistency list
2945
                for row in range(self.tableWidgetInconsistency.rowCount()):
2946
                    if item is self.tableWidgetInconsistency.item(row, 0).tag:
2947
                        self.tableWidgetInconsistency.removeRow(row)
2948
                        break
2949

    
2950
                if item.scene() is not None:
2951
                    item.scene().removeItem(item)
2952
                del item
2953
            else:
2954
                remove_scene = item.scene()
2955
                self.itemTreeWidget.itemRemoved(item)
2956

    
2957
                if remove_scene:
2958
                    matches = [_item for _item in remove_scene.items() if
2959
                            hasattr(_item, 'connectors') and [connector for connector in _item.connectors if
2960
                                                                connector.connectedItem is item]]
2961
                    for match in matches:
2962
                        for connector in match.connectors:
2963
                            if connector.connectedItem is item:
2964
                                connector.connectedItem = None
2965
                                connector.highlight(False)
2966

    
2967
                # matches = [_item for _item in self.graphicsView.scene().items() if hasattr(_item, 'remove_assoc_item')]
2968
                # for _item in matches:
2969
                #    _item.remove_assoc_item(item)
2970

    
2971
                app_doc_data = AppDocData.instance()
2972
                if type(item) is QEngineeringLineNoTextItem and item in app_doc_data.tracerLineNos:
2973
                    app_doc_data.tracerLineNos.pop(app_doc_data.tracerLineNos.index(item))
2974

    
2975
                if type(item) is QEngineeringLineItem and item in app_doc_data.lines:
2976
                    app_doc_data.lines.remove(item)
2977

    
2978
                if remove_scene:
2979
                    matches = [_item for _item in remove_scene.items() if
2980
                            type(_item) is QEngineeringLineNoTextItem]
2981
                    matches.extend([lineNo for lineNo in app_doc_data.tracerLineNos if
2982
                                    type(lineNo) is QEngineeringTrimLineNoTextItem])
2983
                    for match in matches:
2984
                        if item is match.prop('From'):
2985
                            match.set_property('From', None)
2986
                        if item is match.prop('To'):
2987
                            match.set_property('To', None)
2988

    
2989
                        for run_index in reversed(range(len(match.runs))):
2990
                            run = match.runs[run_index]
2991
                            if item in run.items:
2992
                                index = run.items.index(item)
2993
                                run.items.pop(index)
2994
                                if not run.items:
2995
                                    run.explode()
2996
                                    if type(match) is QEngineeringTrimLineNoTextItem and not match.runs:
2997
                                        app_doc_data.tracerLineNos.pop(app_doc_data.tracerLineNos.index(match))
2998
                                # break
2999

    
3000
                if remove_scene:
3001
                    matches = [_item for _item in remove_scene.items() if hasattr(_item, 'owner')]
3002
                    for match in matches:
3003
                        if match.owner is item:
3004
                            match.owner = None
3005

    
3006
                    matches = [_item for _item in remove_scene.items() if hasattr(_item, 'attrs')]
3007
                    # done = False
3008
                    for match in matches:
3009
                        assocs = match.associations()
3010
                        for assoc in assocs:
3011
                            if item is assoc:
3012
                                keys = match.attrs.keys()
3013
                                for attr in keys:
3014
                                    if attr.AssocItem and str(item.uid) == str(attr.AssocItem.uid):
3015
                                        attr.AssocItem = None
3016
                                        match.attrs[attr] = ''
3017
                                        # done = True
3018
                                match.remove_assoc_item(item)
3019
                                break
3020
                        # if done: break
3021

    
3022
                if item.scene() is not None:
3023
                    #if type(item) is QEngineeringLineNoTextItem and item._labels:
3024
                    #    for _label in item._labels:
3025
                    #        item.scene().removeItem(_label)
3026
                    #    item._labels = []
3027

    
3028
                    item.scene().removeItem(item)
3029
        except Exception as ex:
3030
            message = 'error occurred({}) in {}:{}'.format(ex, sys.exc_info()[-1].tb_frame.f_code.co_filename,
3031
                                                           sys.exc_info()[-1].tb_lineno)
3032
            self.addMessage.emit(MessageType.Error, message)
3033
        '''
3034
        finally:
3035
            if hasattr(item, '_cond'):
3036
                item._cond.wakeAll()
3037
        '''
3038

    
3039

    
3040
    def connect_attributes(self, MainWindow):
3041
        """connect attributes to symbol"""
3042
        from LineNoTracer import LineNoTracer
3043
        from ConnectAttrDialog import QConnectAttrDialog
3044

    
3045
        if not self.graphicsView.hasImage():
3046
            self.showImageSelectionMessageBox()
3047
            return
3048

    
3049
        # save alarm
3050
        self.save_alarm_enable(False)
3051

    
3052
        try:
3053
            dlg = QConnectAttrDialog(self, self.graphicsView.scene())
3054
            dlg.setWindowFlags(self.windowFlags() & ~Qt.WindowCloseButtonHint & ~Qt.WindowContextHelpButtonHint)
3055
            dlg.exec_()
3056
            if dlg.isRunned:
3057
                self.refresh_item_list()
3058

    
3059
                if dlg.validation_checked:
3060
                    self.onValidation()
3061

    
3062
                self.graphicsView.invalidateScene()
3063
        except Exception as ex:
3064
            message = 'error occurred({}) in {}:{}'.format(ex, sys.exc_info()[-1].tb_frame.f_code.co_filename,
3065
                                                           sys.exc_info()[-1].tb_lineno)
3066
            self.addMessage.emit(MessageType.Error, message)
3067
        finally:
3068
            # save alarm
3069
            self.save_alarm_enable(True)
3070

    
3071
    def postDetectLineProcess(self):
3072
        '''
3073
            @brief  check allowables among undetected items
3074
            @author euisung
3075
            @date   2018.11.15
3076
            @history    2018.11.15  euisung    no more used, moved to TextItemFactoy isLineNo()
3077
        '''
3078
        from TextItemFactory import TextItemFactory
3079

    
3080
        appDocData = AppDocData.instance()
3081

    
3082
        tableNames = ["Fluid Code", "Insulation Purpose", "PnID Number", "Piping Materials Class", "Unit Number"]
3083
        tableDatas = []
3084
        for tableName in tableNames:
3085
            tableNameFormat = tableName.replace(' ', '').replace('&&', 'n')
3086
            tableDatas.append(appDocData.getCodeTable(tableNameFormat))
3087

    
3088
        items = self.graphicsView.scene().items()
3089
        for item in items:
3090
            if type(item) is not QEngineeringTextItem:
3091
                continue
3092
            text = item.text()
3093
            for tableData in tableDatas:
3094
                for data in tableData:
3095
                    if data[3] == '':
3096
                        continue
3097
                    else:
3098
                        allows = data[3].split(',')
3099
                        for allow in allows:
3100
                            text = text.replace(allow, data[1])
3101

    
3102
            lineItem = TextItemFactory.instance().createTextItem(text)
3103
            if type(lineItem) is QEngineeringLineNoTextItem:
3104
                lineItem.loc = item.loc
3105
                lineItem.size = item.size
3106
                lineItem.angle = item.angle
3107
                lineItem.area = item.area
3108
                # lineItem.addTextItemToScene(self.graphicsView.scene())
3109
                lineItem.transfer.onRemoved.connect(self.itemRemoved)
3110
                item.transfer.onRemoved.emit(item)
3111
                appDocData.lineNos.append(lineItem)
3112

    
3113
    def init_add_tree_item(self, line_no_tree_item, run_item):
3114
        """ insert symbol item and find line no as owner """
3115
        # insert
3116
        self.itemTreeWidget.addTreeItem(line_no_tree_item, run_item)
3117
        # find
3118
        self.itemTreeWidget.addTreeItem(line_no_tree_item, run_item)
3119

    
3120
    def load_drawing(self, drawing):
3121
        """ load drawing """
3122
        """ no more used """
3123
        from EngineeringRunItem import QEngineeringRunItem
3124
        from QEngineeringTrimLineNoTextItem import QEngineeringTrimLineNoTextItem
3125

    
3126
        app_doc_data = AppDocData.instance()
3127
        try:
3128
            symbols = []
3129
            lines = []
3130

    
3131
            components = app_doc_data.get_components(drawing.UID)
3132
            maxValue = len(components) * 2
3133
            self.progress.setMaximum(maxValue) if maxValue > 0 else None
3134

    
3135
            """ parsing all symbols """
3136
            for symbol in [component for component in components if int(component['SymbolType_UID']) != -1]:
3137
                item = SymbolSvgItem.from_database(symbol)
3138
                if item is not None:
3139
                    item.transfer.onRemoved.connect(self.itemRemoved)
3140
                    symbols.append(item)
3141
                    app_doc_data.symbols.append(item)
3142
                    item.addSvgItemToScene(self.graphicsView.scene())
3143
                else:
3144
                    pt = [float(symbol['X']), float(symbol['Y'])]
3145
                    size = [float(symbol['Width']), float(symbol['Height'])]
3146
                    angle = float(symbol['Rotation'])
3147
                    item = QGraphicsBoundingBoxItem(pt[0], pt[1], size[0], size[1])
3148
                    item.isSymbol = True
3149
                    item.angle = angle
3150
                    item.setPen(QPen(Qt.red, 5, Qt.SolidLine))
3151
                    self.graphicsView.scene().addItem(item)
3152
                    item.transfer.onRemoved.connect(self.itemRemoved)
3153

    
3154
                self.progress.setValue(self.progress.value() + 1)
3155

    
3156
            QApplication.processEvents()
3157

    
3158
            # parse texts
3159
            for text in [component for component in components if
3160
                         component['Name'] == 'Text' and component['SymbolType_UID'] == -1]:
3161
                item = QEngineeringTextItem.from_database(text)
3162
                if item is not None:
3163
                    item.uid = text['UID']
3164
                    item.attribute = text['Value']
3165
                    name = text['Name']
3166
                    item.transfer.onRemoved.connect(self.itemRemoved)
3167
                    item.addTextItemToScene(self.graphicsView.scene())
3168

    
3169
                self.progress.setValue(self.progress.value() + 1)
3170

    
3171
            QApplication.processEvents()
3172

    
3173
            # note
3174
            for note in [component for component in components if
3175
                         component['Name'] == 'Note' and component['SymbolType_UID'] == -1]:
3176
                item = QEngineeringTextItem.from_database(note)
3177
                if item is not None:
3178
                    item.uid = note['UID']
3179
                    attributeValue = note['Value']
3180
                    name = note['Name']
3181
                    item.transfer.onRemoved.connect(self.itemRemoved)
3182
                    item.addTextItemToScene(self.graphicsView.scene())
3183

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

    
3186
            QApplication.processEvents()
3187

    
3188
            for line in [component for component in components if
3189
                         component['Name'] == 'Line' and component['SymbolType_UID'] == -1]:
3190
                item = QEngineeringLineItem.from_database(line)
3191
                if item:
3192
                    item.transfer.onRemoved.connect(self.itemRemoved)
3193
                    self.graphicsView.scene().addItem(item)
3194
                    lines.append(item)
3195

    
3196
                self.progress.setValue(self.progress.value() + 1)
3197

    
3198
            QApplication.processEvents()
3199

    
3200
            for unknown in [component for component in components if
3201
                            component['Name'] == 'Unknown' and component['SymbolType_UID'] == -1]:
3202
                item = QEngineeringUnknownItem.from_database(unknown)
3203
                item.transfer.onRemoved.connect(self.itemRemoved)
3204
                if item is not None:
3205
                    item.transfer.onRemoved.connect(self.itemRemoved)
3206
                    self.graphicsView.scene().addItem(item)
3207

    
3208
                self.progress.setValue(self.progress.value() + 1)
3209

    
3210
            QApplication.processEvents()
3211

    
3212
            for component in [component for component in components if
3213
                              component['Name'] == 'Line NO' and component['SymbolType_UID'] == -1]:
3214
                line_no = QEngineeringLineNoTextItem.from_database(component)
3215
                if type(line_no) is QEngineeringLineNoTextItem:
3216
                    line_no.transfer.onRemoved.connect(self.itemRemoved)
3217
                    self.addTextItemToScene(line_no)
3218
                    line_no_tree_item = self.itemTreeWidget.addTreeItem(self.itemTreeWidget.root, line_no)
3219

    
3220
                    runs = app_doc_data.get_pipe_runs(str(line_no.uid))
3221
                    if not runs: continue
3222
                    for run in runs:
3223
                        line_run = QEngineeringRunItem()
3224
                        run_items = app_doc_data.get_pipe_run_items(run['UID'])
3225
                        for record in run_items:
3226
                            uid = record['Components_UID']
3227
                            run_item = self.graphicsView.findItemByUid(uid)
3228
                            if run_item is not None:
3229
                                run_item._owner = line_no
3230
                                line_run.items.append(run_item)
3231
                        line_run.owner = line_no
3232
                        line_no.runs.append(line_run)
3233

    
3234
                        for run_item in line_run.items:
3235
                            if issubclass(type(run_item), SymbolSvgItem):
3236
                                self.init_add_tree_item(line_no_tree_item, run_item)
3237

    
3238
                self.progress.setValue(self.progress.value() + 1)
3239
            QApplication.processEvents()
3240

    
3241
            for component in [component for component in components if
3242
                              component['Name'] == 'Trim Line NO' and component['SymbolType_UID'] == -1]:
3243
                line_no = QEngineeringTrimLineNoTextItem()
3244
                line_no.uid = uuid.UUID(component['UID'])
3245

    
3246
                runs = app_doc_data.get_pipe_runs(str(line_no.uid))
3247
                if not runs: continue
3248

    
3249
                line_no_tree_item = self.itemTreeWidget.addTreeItem(self.itemTreeWidget.root, line_no)
3250

    
3251
                for run in runs:
3252
                    line_run = QEngineeringRunItem()
3253
                    run_items = app_doc_data.get_pipe_run_items(run['UID'])
3254
                    for record in run_items:
3255
                        uid = record['Components_UID']
3256
                        run_item = self.graphicsView.findItemByUid(uid)
3257
                        if run_item is not None:
3258
                            run_item.owner = line_no
3259
                            line_run.items.append(run_item)
3260
                    line_run.owner = line_no
3261
                    line_no.runs.append(line_run)
3262

    
3263
                    for run_item in line_run.items:
3264
                        if issubclass(type(run_item), SymbolSvgItem):
3265
                            self.init_add_tree_item(line_no_tree_item, run_item)
3266

    
3267
                app_doc_data.tracerLineNos.append(line_no)
3268

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

    
3271
            for component in [component for component in components if
3272
                              component['Name'] == 'VendorPackage' and component['SymbolType_UID'] == -1]:
3273
                item = QEngineeringVendorItem.from_database(component)
3274
                if item is not None:
3275
                    item.transfer.onRemoved.connect(self.itemRemoved)
3276
                    self.graphicsView.scene().addItem(item)
3277

    
3278
            # connect flow item to line
3279
            for line in lines:
3280
                line.update_arrow()
3281
                app_doc_data.lines.append(line)
3282
            # for flowMark in [item for item in symbols if type(item) is QEngineeringFlowMarkItem]:
3283
            #    for line in lines:
3284
            #        if flowMark.owner is line:
3285
            #            line._flowMark.append(flowMark)
3286
            #            flowMark.setParentItem(line)
3287
            # up to here
3288

    
3289
            """ update scene """
3290
            self.graphicsView.scene().update(self.graphicsView.sceneRect())
3291
            for item in self.graphicsView.scene().items():
3292
                up_progress = False
3293
                # binding items
3294
                if hasattr(item, 'owner'):
3295
                    item.owner
3296
                    up_progress = True
3297
                if hasattr(item, 'connectors'):
3298
                    for connector in item.connectors:
3299
                        connector.connectedItem
3300
                    up_progress = True
3301

    
3302
                if up_progress:
3303
                    self.progress.setValue(self.progress.value() + 1)
3304
            
3305
            for item in self.graphicsView.scene().items():
3306
                item.setVisible(True)
3307

    
3308
        except Exception as ex:
3309
            message = 'error occurred({}) in {}:{}'.format(ex, sys.exc_info()[-1].tb_frame.f_code.co_filename,
3310
                                                           sys.exc_info()[-1].tb_lineno)
3311
            self.addMessage.emit(MessageType.Error, message)
3312
        finally:
3313
            app_doc_data.clearTempDBData()
3314
            self.itemTreeWidget.update_item_count()
3315
            self.itemTreeWidget.expandAll()
3316
            # self.graphicsView.scene().blockSignals(False)
3317

    
3318
    '''
3319
        @brief      load recognition result
3320
        @author     humkyung
3321
        @date       2018.04.??
3322
        @history    humkyung 2018.01.12 parse originalpoint and connectionpoint
3323
                    Jeongwoo 2018.04.17 add QGraphicItem with Rotated text
3324
                    Jeongwoo 2018.04.23 Change to Draw texts on QEngineeringTextItem
3325
                    humkyung 2018.04.23 connect item remove slot to result tree
3326
                    Jeongwoo 2018.04.25 Add if state with QEngineeringNoteItem
3327
                    Jeongwoo 2018.04.26 Change method to create TextItem object with TextItemFactory
3328
                    Jeongwoo 2018.05.03 Change method to draw Svg Item on Scene (svg.addSvgItemToScene)
3329
                    Jeongwoo 2018.05.29 Change method name / Change method to add item / Add Line item
3330
                    Jeongwoo 2018.05.30 Add parameters on SymbolSvgItem.__init__() (parentSymbol, childSymbol) / Change method name / Change XML NODE NAMES
3331
                    Jeongwoo 2018.06.12 Add LineNoTextItem from LINE_NO
3332
                    Jeongwoo 2018.06.14 Add UnknownItem from UNKNOWN
3333
                    Jeongwoo 2018.06.18 Update Scene after all item added
3334
                                        Add connect on unknown item
3335
                                        Add [transfer] for using pyqtSignal
3336
                    kyouho  2018.07.12  Add line property logic
3337
                    humkyung 2018.08.22 show progress while loading xml file
3338
                    2018.11.22      euisung     fix note road
3339
    '''
3340
    def load_recognition_result_from_xml(self, drawing):
3341
        # Yield successive n-sized
3342
        # chunks from l.
3343
        def divide_chunks(l, n):
3344
            # looping till length l
3345
            for i in range(0, len(l), n):
3346
                yield l[i:i + n]
3347

    
3348
        def update_items(items):
3349
            for item in items:
3350
                # binding items
3351
                item.owner
3352
                for connector in item.connectors:
3353
                    connector.connectedItem
3354

    
3355
            return items
3356

    
3357
        import concurrent.futures as futures
3358
        from xml.etree.ElementTree import Element, SubElement, dump, ElementTree, parse
3359
        from App import App
3360
        from EngineeringRunItem import QEngineeringRunItem
3361
        from QEngineeringTrimLineNoTextItem import QEngineeringTrimLineNoTextItem
3362
        from EngineeringGraphicsLineItem import QEngineeringGraphicsLineItem
3363

    
3364
        app_doc_data = AppDocData.instance()
3365

    
3366
        try:
3367
            file_name = os.path.splitext(os.path.basename(drawing.file_path))[0]
3368
            path = os.path.join(app_doc_data.getCurrentProject().getTempPath(), file_name + '.xml')
3369
            self.graphicsView.scene().blockSignals(True)
3370

    
3371
            symbols = []
3372
            lines = []
3373

    
3374
            xml = parse(path)
3375
            root = xml.getroot()
3376

    
3377
            maxValue = 0
3378
            maxValue = maxValue + len(list(root.iter('SYMBOL'))) - \
3379
                       len(list(root.iterfind('LINENOS/LINE_NO/RUN/SYMBOL'))) - \
3380
                       len(list(root.iterfind('TRIMLINENOS/TRIM_LINE_NO/RUN/SYMBOL')))
3381
            maxValue = maxValue + len(list(root.iterfind('TEXTINFOS/ATTRIBUTE')))
3382
            maxValue = maxValue + len(list(root.iterfind('NOTES/ATTRIBUTE')))
3383
            maxValue = maxValue + len(list(root.iter('LINE_NO')))
3384
            maxValue = maxValue + len(list(root.iter('LINE'))) - \
3385
                       len(list(root.iterfind('LINENOS/LINE_NO/RUN/LINE'))) - \
3386
                       len(list(root.iterfind('TRIMLINENOS/TRIM_LINE_NO/RUN/LINE')))
3387
            maxValue = maxValue + len(list(root.iter('GRAPHICS_LINE')))
3388
            maxValue = maxValue + len(list(root.iter('UNKNOWN')))
3389
            # maxValue = maxValue + len(list(root.iter('SIZETEXT')))
3390
            maxValue = maxValue + len(list(root.iter('TRIM_LINE_NO')))
3391
            maxValue *= 2
3392
            self.progress.setMaximum(maxValue) if maxValue > 0 else None
3393

    
3394
            """ parsing all symbols """
3395
            """
3396
            with futures.ThreadPoolExecutor(max_workers=App.THREAD_MAX_WORKER) as pool:
3397
                future_symbol = {pool.submit(SymbolSvgItem.fromXml, symbol): symbol for symbol in root.find('SYMBOLS').iter('SYMBOL')}
3398

3399
                for future in futures.as_completed(future_symbol):
3400
                    try:
3401
                        item = future.result()
3402
                        if item:
3403
                            if item is not None:
3404
                                item.transfer.onRemoved.connect(self.itemRemoved)
3405
                                symbols.append(item)
3406
                                docData.symbols.append(item)
3407
                                self.addSvgItemToScene(item)
3408
                            else:
3409
                                pt = [float(x) for x in symbol.find('LOCATION').text.split(',')]
3410
                                size = [float(x) for x in symbol.find('SIZE').text.split(',')]
3411
                                angle = float(symbol.find('ANGLE').text)
3412
                                item = QGraphicsBoundingBoxItem(pt[0], pt[1], size[0], size[1])
3413
                                item.isSymbol = True
3414
                                item.angle = angle
3415
                                item.setPen(QPen(Qt.red, 5, Qt.SolidLine))
3416
                                self.graphicsView.scene().addItem(item)
3417
                                item.transfer.onRemoved.connect(self.itemRemoved)
3418
                    except Exception as ex:
3419
                        message = 'error occurred({}) in {}:{}'.format(repr(ex), sys.exc_info()[-1].tb_frame.f_code.co_filename,
3420
                                                                       sys.exc_info()[-1].tb_lineno)
3421

3422
            """
3423
            for symbol in root.find('SYMBOLS').iter('SYMBOL'):
3424
                item = SymbolSvgItem.fromXml(symbol)
3425
                if item is not None:
3426
                    item.transfer.onRemoved.connect(self.itemRemoved)
3427
                    symbols.append(item)
3428
                    #app_doc_data.symbols.append(item)
3429
                    item.addSvgItemToScene(self.graphicsView.scene())
3430
                else:
3431
                    pt = [float(x) for x in symbol.find('LOCATION').text.split(',')]
3432
                    size = [float(x) for x in symbol.find('SIZE').text.split(',')]
3433
                    angle = float(symbol.find('ANGLE').text)
3434
                    item = QGraphicsBoundingBoxItem(pt[0], pt[1], size[0], size[1])
3435
                    item.isSymbol = True
3436
                    item.angle = angle
3437
                    item.setPen(QPen(Qt.red, 5, Qt.SolidLine))
3438
                    self.graphicsView.scene().addItem(item)
3439
                    item.transfer.onRemoved.connect(self.itemRemoved)
3440

    
3441
                self.progress.setValue(self.progress.value() + 1)
3442

    
3443
            QApplication.processEvents()
3444

    
3445
            # parse texts
3446
            for text in root.find('TEXTINFOS').iter('ATTRIBUTE'):
3447
                item = QEngineeringTextItem.fromXml(text)
3448
                if item is not None:
3449
                    uid = text.find('UID')
3450
                    attributeValue = text.find('ATTRIBUTEVALUE')
3451
                    name = text.find('NAME').text
3452
                    item.transfer.onRemoved.connect(self.itemRemoved)
3453
                    item.addTextItemToScene(self.graphicsView.scene())
3454
                    # docData.texts.append(item)
3455

    
3456
                    if name == 'TEXT':
3457
                        if uid is not None and attributeValue is not None:
3458
                            item.uid = uid.text
3459
                            item.attribute = attributeValue.text
3460

    
3461
                self.progress.setValue(self.progress.value() + 1)
3462

    
3463
            QApplication.processEvents()
3464

    
3465
            # note
3466
            for text in root.find('NOTES').iter('ATTRIBUTE'):
3467
                item = QEngineeringTextItem.fromXml(text)
3468
                if item is not None:
3469
                    uid = text.find('UID')
3470
                    attributeValue = text.find('ATTRIBUTEVALUE')
3471
                    name = text.find('NAME').text
3472
                    item.transfer.onRemoved.connect(self.itemRemoved)
3473
                    item.addTextItemToScene(self.graphicsView.scene())
3474

    
3475
                    if name == 'NOTE':
3476
                        if uid is not None:
3477
                            item.uid = uid.text
3478

    
3479
                self.progress.setValue(self.progress.value() + 1)
3480

    
3481
            QApplication.processEvents()
3482

    
3483
            for line in root.find('LINEINFOS').iter('LINE'):
3484
                item = QEngineeringLineItem.fromXml(line)
3485
                if item:
3486
                    item.transfer.onRemoved.connect(self.itemRemoved)
3487
                    self.graphicsView.scene().addItem(item)
3488
                    lines.append(item)
3489

    
3490
                self.progress.setValue(self.progress.value() + 1)
3491

    
3492
            for line in root.find('LINEINFOS').iter('GRAPHICS_LINE'):
3493
                item = QEngineeringGraphicsLineItem.fromXml(line)
3494
                if item:
3495
                    item.transfer.onRemoved.connect(self.itemRemoved)
3496
                    self.graphicsView.scene().addItem(item)
3497

    
3498
                self.progress.setValue(self.progress.value() + 1)
3499

    
3500
            QApplication.processEvents()
3501

    
3502
            for unknown in root.iter('UNKNOWN'):
3503
                item = QEngineeringUnknownItem.fromXml(unknown)
3504
                if item is not None:
3505
                    item.transfer.onRemoved.connect(self.itemRemoved)
3506
                    self.graphicsView.scene().addItem(item)
3507

    
3508
                self.progress.setValue(self.progress.value() + 1)
3509

    
3510
            QApplication.processEvents()
3511

    
3512
            # """ add tree widget """
3513
            # for item in symbols:
3514
            #    docData.symbols.append(item)
3515
            #    self.addSvgItemToScene(item)
3516
            #    self.itemTreeWidget.addTreeItem(self.itemTreeWidget.root, item)
3517

    
3518
            for line_no_node in root.find('LINENOS').iter('LINE_NO'):
3519
                line_no = QEngineeringLineNoTextItem.fromXml(line_no_node)
3520
                if line_no is None: continue
3521
                line_no.transfer.onRemoved.connect(self.itemRemoved)
3522
                line_no.addTextItemToScene(self.graphicsView.scene())
3523
                line_no_tree_item = self.itemTreeWidget.addTreeItem(self.itemTreeWidget.root, line_no)
3524
                if type(line_no) is not QEngineeringLineNoTextItem: continue
3525

    
3526
                runs_node = line_no_node.findall('RUN')
3527
                if runs_node is None: continue
3528

    
3529
                for run_node in runs_node:
3530
                    line_run = QEngineeringRunItem()
3531
                    for child_node in run_node:
3532
                        uidElement = child_node.find('UID')
3533
                        if uidElement is not None:
3534
                            uid = uidElement.text
3535
                            run_item = self.graphicsView.findItemByUid(uid)
3536
                            if run_item is not None:
3537
                                run_item._owner = line_no
3538
                                line_run.items.append(run_item)
3539
                    line_run.owner = line_no
3540
                    line_no.runs.append(line_run)
3541

    
3542
                    for run_item in line_run.items:
3543
                        if issubclass(type(run_item), SymbolSvgItem):
3544
                            self.init_add_tree_item(line_no_tree_item, run_item)
3545

    
3546
                # docData.tracerLineNos.append(line_no)
3547

    
3548
                self.progress.setValue(self.progress.value() + 1)
3549
            QApplication.processEvents()
3550

    
3551
            for trimLineNo in root.iter('TRIM_LINE_NO'):
3552
                line_no = QEngineeringTrimLineNoTextItem()
3553
                line_no.uid = uuid.UUID(trimLineNo.find('UID').text)
3554

    
3555
                runs_node = trimLineNo.findall('RUN')
3556
                if runs_node is None: continue
3557
                line_no_tree_item = self.itemTreeWidget.addTreeItem(self.itemTreeWidget.root, line_no)
3558

    
3559
                for run in runs_node:
3560
                    line_run = QEngineeringRunItem()
3561
                    for child in run:
3562
                        uidElement = child.find('UID')
3563
                        if uidElement is not None:
3564
                            uid = uidElement.text
3565
                            run_item = self.graphicsView.findItemByUid(uid)
3566
                            if run_item is not None:
3567
                                run_item.owner = line_no
3568
                                line_run.items.append(run_item)
3569
                    line_run.owner = line_no
3570
                    line_no.runs.append(line_run)
3571

    
3572
                    for run_item in line_run.items:
3573
                        if issubclass(type(run_item), SymbolSvgItem):
3574
                            self.init_add_tree_item(line_no_tree_item, run_item)
3575

    
3576
                app_doc_data.tracerLineNos.append(line_no)
3577

    
3578
                self.progress.setValue(self.progress.value() + 1)
3579
            QApplication.processEvents()
3580

    
3581
            if root.find('VENDORS') is not None:
3582
                for vendor in root.find('VENDORS').iter('VENDOR'):
3583
                    item = QEngineeringVendorItem.fromXml(vendor)
3584
                    item.transfer.onRemoved.connect(self.itemRemoved)
3585
                    self.graphicsView.scene().addItem(item)
3586

    
3587
            # connect flow item to line
3588
            for line in lines:
3589
                line.update_arrow()
3590
                app_doc_data.lines.append(line)
3591
            # for flowMark in [item for item in symbols if type(item) is QEngineeringFlowMarkItem]:
3592
            #    for line in lines:
3593
            #        if flowMark.owner is line:
3594
            #            line._flowMark.append(flowMark)
3595
            #            flowMark.setParentItem(line)
3596
            # up to here
3597

    
3598
            """
3599
            group_box = QGroupBox("Contact Details")
3600
            number_label = QLabel("Telephone number");
3601
            number_edit = QTextEdit('hello\nthis is ....')
3602
            layout = QFormLayout()
3603
            layout.addRow(number_label, number_edit)
3604
            group_box.setLayout(layout)
3605

3606
            proxy =  ㅐ()
3607
            proxy.setWidget(group_box)
3608
            self.graphicsView.scene().addItem(proxy)  # (group_box, QGraphicsItem.ItemIgnoresTransformations)
3609
            """
3610

    
3611
            """ update scene """
3612
            _items = [_item for _item in self.graphicsView.scene().items() if hasattr(_item, 'owner') or hasattr(_item, 'connectors')]
3613
            if _items:
3614
                items = divide_chunks(_items, App.THREAD_MAX_WORKER if len(_items) > App.THREAD_MAX_WORKER else len(_items))
3615
                with futures.ThreadPoolExecutor(max_workers=App.THREAD_MAX_WORKER) as pool:
3616
                    future_items = {pool.submit(update_items, _items): _items for _items in items}
3617
                    for future in futures.as_completed(future_items):
3618
                        _items = future.result()
3619
                        self.progress.setValue(self.progress.value() + len(_items))
3620

    
3621
            """
3622
            for item in [_item for _item in self.graphicsView.scene().items() if hasattr(_item, 'owner') or hasattr(_item, 'connectors')]:
3623
                up_progress = False
3624
                # binding items
3625
                item.owner
3626
                for connector in item.connectors:
3627
                    connector.connectedItem
3628

3629
                self.progress.setValue(self.progress.value() + 1)
3630
            """
3631

    
3632
            for item in self.graphicsView.scene().items():
3633
                item.setVisible(True)
3634

    
3635
            self.graphicsView.scene().update(self.graphicsView.sceneRect())
3636
        except Exception as ex:
3637
            message = 'error occurred({}) in {}:{}'.format(ex, sys.exc_info()[-1].tb_frame.f_code.co_filename,
3638
                                                           sys.exc_info()[-1].tb_lineno)
3639
            self.addMessage.emit(MessageType.Error, message)
3640
        finally:
3641
            self.itemTreeWidget.update_item_count()
3642
            self.itemTreeWidget.expandAll()
3643
            self.graphicsView.scene().blockSignals(False)
3644

    
3645
    '''
3646
        @brief      Remove added item on same place and Add GraphicsItem
3647
        @author     Jeongwoo
3648
        @date       2018.05.29
3649
        @history    2018.06.18  Jeongwoo    Set Z-index
3650
    '''
3651
    def addLineItemToScene(self, lineItem):
3652
        self.graphicsView.scene().addItem(lineItem)
3653

    
3654
    '''
3655
        @brief      generate output xml file
3656
        @author     humkyung
3657
        @date       2018.04.23
3658
        @history    2018.05.02  Jeongwoo    Show MessageBox when imageviewer doesn't have image
3659
    '''
3660
    def generateOutput(self):
3661
        import XmlGenerator as xg
3662

    
3663
        if not self.graphicsView.hasImage():
3664
            self.showImageSelectionMessageBox()
3665
            return
3666

    
3667
        try:
3668
            appDocData = AppDocData.instance()
3669

    
3670
            # collect items
3671
            appDocData.lines.clear()
3672
            appDocData.lines = [item for item in self.graphicsView.scene().items() if
3673
                                type(item) is QEngineeringLineItem and item.owner is None]
3674

    
3675
            appDocData.symbols.clear()
3676
            appDocData.symbols = [item for item in self.graphicsView.scene().items() if
3677
                                  issubclass(type(item), SymbolSvgItem) and item.owner is None]
3678

    
3679
            appDocData.equipments.clear()
3680
            for item in self.graphicsView.scene().items():
3681
                if type(item) is QEngineeringEquipmentItem:
3682
                    appDocData.equipments.append(item)
3683

    
3684
            appDocData.texts.clear()
3685
            appDocData.texts = [item for item in self.graphicsView.scene().items() if
3686
                                issubclass(type(item), QEngineeringTextItem) and type(
3687
                                    item) is not QEngineeringLineNoTextItem]
3688
            # up to here
3689

    
3690
            appDocData.imgOutput = np.ones((appDocData.activeDrawing.height, appDocData.activeDrawing.width),
3691
                                           np.uint8) * 255
3692
            xg.writeOutputXml(appDocData.imgName, appDocData.activeDrawing.width,
3693
                              appDocData.activeDrawing.height)  # TODO: check
3694
            project = appDocData.getCurrentProject()
3695
            cv2.imwrite(os.path.join(project.getTempPath(), 'OUTPUT.png'), appDocData.imgOutput)
3696
        except Exception as ex:
3697
            message = 'error occurred({}) in {}:{}'.format(ex, sys.exc_info()[-1].tb_frame.f_code.co_filename,
3698
                                                           sys.exc_info()[-1].tb_lineno)
3699
            self.addMessage.emit(MessageType.Error, message)
3700

    
3701
    '''
3702
        @brief      Check Number
3703
        @author     kyouho
3704
        @date       2018.08.20
3705
    '''
3706
    def isNumber(self, num):
3707
        p = re.compile('(^[0-9]+$)')
3708
        result = p.match(num)
3709

    
3710
        if result:
3711
            return True
3712
        else:
3713
            return False
3714

    
3715
    '''
3716
        @brief      find overlap Connector
3717
        @author     kyouho
3718
        @date       2018.08.28
3719
    '''
3720
    def findOverlapConnector(self, connectorItem):
3721
        from shapely.geometry import Point
3722
        from EngineeringConnectorItem import QEngineeringConnectorItem
3723
        itemList = []
3724

    
3725
        x = connectorItem.center()[0]
3726
        y = connectorItem.center()[1]
3727

    
3728
        connectors = [item for item in self.graphicsView.scene().items() if
3729
                      type(item) is QEngineeringConnectorItem and item != connectorItem]
3730
        for connector in connectors:
3731
            if Point(x, y).distance(Point(connector.center()[0], connector.center()[1])) < 5:
3732
                itemList.append(connector.parent)
3733

    
3734
        return itemList
3735

    
3736
    def make_diff_image(self):
3737
        """ make diff image """
3738
        # test
3739

    
3740
        from RecognitionDialog import Worker
3741
        from symbol import Symbol
3742
        import math
3743
        from PIL import Image
3744

    
3745
        app_doc_data = AppDocData.instance()
3746
        img = app_doc_data.imgSrc.copy()
3747

    
3748
        # check break
3749
        symbols = [item for item in self.graphicsView.scene().items() if issubclass(type(item), SymbolSvgItem)]
3750

    
3751
        for symbol in symbols:
3752
            rect = symbol.sceneBoundingRect()
3753
            sName = symbol.name
3754
            sType = symbol.type
3755
            sp = (rect.x(), rect.y())
3756
            w, h = rect.width(), rect.height()
3757
            rotatedAngle = round(math.degrees(symbol.angle))
3758
            detectFlip = symbol.flip
3759

    
3760
            dummySym = Symbol(sName, sType, sp, w, h, 0, 0, 0, rotatedAngle,
3761
                                   1, 0, 1, 0,
3762
                                   ','.join(str(x) for x in [0, 0]),
3763
                                   '/'.join('{},{},{},{}'.format(param[0], param[1], param[2], param[3]) for param in
3764
                                            []),
3765
                                   'dummy', 'dummy', 0, detectFlip=detectFlip,
3766
                                   hasInstrumentLabel=0, text_area='')
3767

    
3768
            Worker.remove_detected_symbol_image(dummySym, img, lock=False)
3769

    
3770
        Image.fromarray(img).show()
3771

    
3772
    #def paintEvent(self, event):
3773
    #    self.refresh_rate += 1
3774
    #    if self.refresh_rate == 3:
3775
    #        super(self.__class__, self).paintEvent(event)
3776
    #        self.refresh_rate = 0
3777

    
3778
if __name__ == '__main__':
3779
    import locale
3780
    from PyQt5.QtCore import QTranslator
3781
    from License import QLicenseDialog
3782
    from ProjectDialog import Ui_Dialog
3783
    from App import App
3784

    
3785
    app = App(sys.argv)
3786
    try:
3787
        if True == QLicenseDialog.check_license_key():
3788
            dlg = Ui_Dialog()
3789
            selectedProject = dlg.showDialog()
3790
            if selectedProject is not None:
3791
                AppDocData.instance().setCurrentProject(selectedProject)
3792
                app._mainWnd = MainWindow.instance()
3793
                app._mainWnd.show()
3794
                sys.exit(app.exec_())
3795
    except Exception as ex:
3796
        print('error occurred({}) in {}:{}'.format(ex, sys.exc_info()[-1].tb_frame.f_code.co_filename,
3797
                                                   sys.exc_info()[-1].tb_lineno))
3798
    finally:
3799
        pass
클립보드 이미지 추가 (최대 크기: 500 MB)