프로젝트

일반

사용자정보

통계
| 개정판:

hytos / DTI_PID / DTI_PID / MainWindow.py @ 0e14457d

이력 | 보기 | 이력해설 | 다운로드 (202 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
from DrawingTreeWidget import QDrawingTreeWidget
60
import ItemTreeWidget
61
import ItemPropertyTableWidget
62
from UserInputAttribute import UserInputAttribute
63
from TextItemFactory import TextItemFactory
64
from TrainingImageListDialog import QTrainingImageListDialog
65
from TrainingSymbolImageListDialog import QTrainingSymbolImageListDialog
66
from TextDataListDialog import QTextDataListDialog
67
from ImportTextFromCADDialog import QImportTextFromCADDialog
68
from ImportTextFromPDFDialog import QImportTextFromPDFDialog
69
from SymbolThicknessDialog import QSymbolThicknessDialog
70
from DisplayColors import DisplayColors
71
from DisplayColors import DisplayOptions
72
from RecognitionDialog import QRecognitionDialog
73
import uuid
74
from TcpServer import TcpServer
75

    
76

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

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

    
84

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

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

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

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

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

    
118
        #self.refresh_rate = 0
119

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

    
128
        # save timer
129
        self.save_timer = None
130
        self.save_before_link = False
131

    
132
        self.drawing_reverse = False
133

    
134
        self._scene = QtImageViewerScene(self)
135

    
136
        self.graphicsView = QtImageViewer(self)
137
        self.graphicsView.setParent(self.centralwidget)
138
        self.graphicsView.useDefaultCommand()  # USE DEFAULT COMMAND
139
        self.graphicsView.setMouseTracking(True)
140
        self.graphicsView.viewport().installEventFilter(self)
141
        self.graphicsView.setScene(self._scene)
142
        self.verticalLayout.addWidget(self.graphicsView)
143

    
144
        # Add Symbol TreeWidget
145
        self.symbolTreeWidget = SymbolTreeWidget.QSymbolTreeWidget()
146
        self.symbolTreeWidget.header().hide()
147
        self.verticalLayoutSymbolTree.addWidget(self.symbolTreeWidget)
148
        self.lineEditFilter.textChanged.connect(self.on_search_text_changed)
149

    
150
        from LibraryItem import LibraryItemWidget
151
        self.libraryWidget = LibraryItemWidget(symbol_tree_widget=self.symbolTreeWidget)
152
        self.verticalLayoutLibrary.addWidget(self.libraryWidget)
153
        # Add Custom Property TableWidget
154
        self.propertyTableWidget = SymbolPropertyTableWidget.QSymbolPropertyTableWidget()
155
        self.verticalLayoutSymbolProperty.addWidget(self.propertyTableWidget)
156
        self.symbolTreeWidget.singleClicked.connect(self.propertyTableWidget.getClickedSymbol)
157

    
158
        self.splitterSymbol.setSizes([500, 300])
159

    
160
        # Add Custom Result Tree Widget (Symbol Explorer)
161
        self.itemTreeWidget = ItemTreeWidget.QItemTreeWidget(self.graphicsView)
162
        self.itemTreeWidget.header().hide()
163
        self.symbolExplorerVerticalLayout.addWidget(self.itemTreeWidget)
164

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

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

    
245
        self.delimiter = '"'
246

    
247
        self.resizeDocks({self.dockWidget}, {self.dockWidgetObjectExplorer.sizeHint().width()}, Qt.Horizontal)
248

    
249
        # drawing list
250
        self.verticalLayoutSymbolTree.addWidget(self.symbolTreeWidget)
251

    
252
        self.treeWidgetDrawingList = QDrawingTreeWidget()
253
        self.treeWidgetDrawingList.setHeaderHidden(False)
254
        self.treeWidgetDrawingList.header().setStretchLastSection(False)
255
        self.treeWidgetDrawingList.setHeaderLabels([self.tr('Name'), self.tr('DateTime')])
256
        self.treeWidgetDrawingList.header().setSectionResizeMode(0, QHeaderView.ResizeToContents)
257
        self.treeWidgetDrawingList.header().setSectionResizeMode(1, QHeaderView.ResizeToContents)
258
        self.treeWidgetDrawingList.header().setSectionsClickable(True)
259
        self.treeWidgetDrawingList.header().sectionClicked.connect(self.sort_drawing_list)
260
        self.treeWidgetDrawingList.itemDoubleClicked.connect(self.open_selected_drawing)
261
        self.load_drawing_list()
262
        self.drawingFilter.textChanged.connect(self.on_drawing_filter_changed)
263
        self.drawingLayout.addWidget(self.treeWidgetDrawingList)
264

    
265
        self.ribbon = AppRibbon()
266
        self.setMenuWidget(self.ribbon)
267

    
268
        if not self.ribbon.advanced_mode:
269
            self.pushButtonCreateSymbol.setVisible(False)
270
            self.pushButtonDetectSymbol.setVisible(False)
271

    
272
        configs = app_doc_data.getConfigs('Line List', 'Use Stream No')
273
        if configs and int(configs[0].value) == 1:
274
            pass
275
        else:
276
            self.ribbon.get_pane('Home Visualization').ui.radioButtonByStreamNo.setHidden(True)
277

    
278
        '''
279
        view_pane = self.ribbon.get_pane('View')
280
        shortcut = QShortcut(QKeySequence(Qt.Key_1), view_pane.ui.toolButtonViewImageDrawing)
281
        shortcut.activated.connect(partial(self.on_view_toggle, Qt.Key_1))
282
        shortcut = QShortcut(QKeySequence(Qt.Key_2), view_pane.ui.toolButtonViewText)
283
        shortcut.activated.connect(partial(self.on_view_toggle, Qt.Key_2))
284
        shortcut = QShortcut(QKeySequence(Qt.Key_3), view_pane.ui.toolButtonViewSymbol)
285
        shortcut.activated.connect(partial(self.on_view_toggle, Qt.Key_3))
286
        shortcut = QShortcut(QKeySequence(Qt.Key_4), view_pane.ui.toolButtonViewLine)
287
        shortcut.activated.connect(partial(self.on_view_toggle, Qt.Key_4))
288
        shortcut = QShortcut(QKeySequence(Qt.Key_5), view_pane.ui.toolButtonViewUnknown)
289
        shortcut.activated.connect(partial(self.on_view_toggle, Qt.Key_5))
290
        shortcut = QShortcut(QKeySequence(Qt.Key_6), view_pane.ui.toolButtonViewInconsistency)
291
        shortcut.activated.connect(partial(self.on_view_toggle, Qt.Key_6))
292
        shortcut = QShortcut(QKeySequence(Qt.Key_7), view_pane.ui.toolButtonViewVendorArea)
293
        shortcut.activated.connect(partial(self.on_view_toggle, Qt.Key_7))
294
        shortcut = QShortcut(QKeySequence(96), view_pane.ui.toolButtonViewDrawingOnly)
295
        shortcut.activated.connect(partial(self.on_view_toggle, 96))
296
        '''
297

    
298
        # inconsistency table
299
        self.tableWidgetInconsistency.setColumnCount(3)
300
        self.tableWidgetInconsistency.setHorizontalHeaderLabels(['Owner', 'Type', 'Message'])
301
        self.tableWidgetInconsistency.setEditTriggers(QAbstractItemView.NoEditTriggers)
302
        self.tableWidgetInconsistency.itemClicked.connect(self.inconsistencyItemClickEvent)
303
        self.tableWidgetInconsistency.keyPressEvent = self.inconsistencyTableKeyPressEvent
304
        self.tableWidgetInconsistency.setSortingEnabled(True)
305

    
306
        # memo tab
307
        self.on_memo_refresh_clicked()
308

    
309
        self.read_settings()
310

    
311
    @property
312
    def title(self) -> str:
313
        """return window title"""
314

    
315
        from App import App
316

    
317
        app_doc_data = AppDocData.instance()
318
        project = app_doc_data.getCurrentProject()
319
        version = QCoreApplication.applicationVersion()
320
        title = f"{App.NAME}({version}) - {project.name}: " \
321
                f"{app_doc_data.activeDrawing.name if app_doc_data.activeDrawing and not app_doc_data.readOnly else (app_doc_data.activeDrawing.name + '(read-only)' if app_doc_data.activeDrawing else '')}"
322
        #title = f"{App.NAME} : ID2 " \
323
        #        f"{app_doc_data.activeDrawing.name if app_doc_data.activeDrawing else ''}"
324

    
325
        return title
326

    
327
    @property
328
    def scene(self):
329
        """getter scene"""
330
        return self._scene
331

    
332
    def eventFilter(self, source, event):
333
        """display mouse position of graphics view"""
334
        try:
335
            if event.type() == QEvent.MouseMove:
336
                self.current_pos = self.graphicsView.mapToScene(event.pos())
337
                self._label_mouse.setText(
338
                    'mouse pos : ({},{})'.format(round(self.current_pos.x()), round(self.current_pos.y())))
339
        except Exception as ex:
340
            message = 'error occurred({}) in {}:{}'.format(ex, sys.exc_info()[-1].tb_frame.f_code.co_filename,
341
                                                           sys.exc_info()[-1].tb_lineno)
342
            self.addMessage.emit(MessageType.Error, message)
343

    
344
        return QWidget.eventFilter(self, source, event)
345

    
346
    def closeEvent(self, event):
347
        """save geometry and state and ask user to save drawing which is modified"""
348

    
349
        if self.save_drawing_if_necessary():
350
            event.ignore()
351
            return
352

    
353
        self.settings.setValue('geometry', self.saveGeometry())
354
        self.settings.setValue('windowState', self.saveState())
355
        # TODO: need to modify
356

    
357
        """save current view region"""
358
        app_doc_data = AppDocData.instance()
359
        if app_doc_data.activeDrawing:
360
            rect = self.graphicsView.viewport().rect()
361
            app_doc_data.activeDrawing.view_rect = self.graphicsView.mapToScene(rect).boundingRect()
362
            app_doc_data.update_view_region(app_doc_data.activeDrawing)
363
        """up to here"""
364

    
365
        AppDocData.instance().clear()
366
        event.accept()
367

    
368
    def on_memo_refresh_clicked(self):
369
        """refresh memo"""
370
        try:
371
            app_doc_data = AppDocData.instance()
372
            configs = app_doc_data.getConfigs('Memo', 'Global')
373
            if 1 == len(configs):
374
                self.textEditMemo.setText(configs[0].value)
375
            else:
376
                self.textEditMemo.setText("")
377

    
378
            self.pushButtonMemoEdit.setText('Edit')
379
            self.textEditMemo.setEnabled(False)
380
            self.pushButtonMemoEdit.setEnabled(True)
381
            self.pushButtonMemoSave.setEnabled(False)
382
        except Exception as ex:
383
            message = 'error occurred({}) in {}:{}'.format(ex, sys.exc_info()[-1].tb_frame.f_code.co_filename,
384
                                                           sys.exc_info()[-1].tb_lineno)
385
            self.addMessage.emit(MessageType.Error, message)
386

    
387
    def on_memo_edit_clicked(self):
388
        """edit memo"""
389
        try:
390
            if not self.textEditMemo.isEnabled():
391
                self.pushButtonMemoEdit.setText('Cancel')
392
                self.textEditMemo.setEnabled(True)
393
                self.pushButtonMemoSave.setEnabled(True)
394
            else:
395
                self.pushButtonMemoEdit.setText('Edit')
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 on_memo_save_clicked(self):
403
        """save memo"""
404
        try:
405
            app_doc_data = AppDocData.instance()
406
            app_doc_data.saveConfigs([Config('Memo', 'Global', self.textEditMemo.toPlainText())])
407
            self.on_memo_refresh_clicked()
408
        except Exception as ex:
409
            message = 'error occurred({}) in {}:{}'.format(ex, sys.exc_info()[-1].tb_frame.f_code.co_filename,
410
                                                           sys.exc_info()[-1].tb_lineno)
411
            self.addMessage.emit(MessageType.Error, message)
412

    
413
    def inconsistencyTableKeyPressEvent(self, event):
414
        try:
415
            row = self.tableWidgetInconsistency.selectedIndexes()[0].row()
416
            col = self.tableWidgetInconsistency.selectedIndexes()[0].column()
417
            from HighlightCommand import HighlightCommand
418
            if event.key() == Qt.Key_Up:
419
                if row is not 0:
420
                    errorItem = self.tableWidgetInconsistency.item(row - 1, 1).tag
421
                    HighlightCommand(self.graphicsView).execute(errorItem)
422
            elif event.key() == Qt.Key_Down:
423
                if row is not self.tableWidgetInconsistency.rowCount() - 1:
424
                    errorItem = self.tableWidgetInconsistency.item(row + 1, 1).tag
425
                    HighlightCommand(self.graphicsView).execute(errorItem)
426
            elif event.key() == Qt.Key_Delete:
427
                item = self.tableWidgetInconsistency.item(row, 0).tag
428
                if item and item.scene(): item.scene().removeItem(item)
429
                self.tableWidgetInconsistency.removeRow(row)
430

    
431
                self.tabWidget_2.setTabText(self.tabWidget_2.indexOf(self.tabInconsistency),
432
                                            self.tr('Inconsistency') + f"({self.tableWidgetInconsistency.rowCount()})")
433
        except Exception as ex:
434
            message = 'error occurred({}) in {}:{}'.format(ex, sys.exc_info()[-1].tb_frame.f_code.co_filename,
435
                                                           sys.exc_info()[-1].tb_lineno)
436
            self.addMessage.emit(MessageType.Error, message)
437
        # finally:
438
        #    return QTableView.keyPressEvent(self.tableWidgetInconsistency, event)
439

    
440
    def onValidation(self):
441
        """validation check"""
442
        from ValidationDialog import QValidationDialog
443
        from ValidateCommand import ValidateCommand
444

    
445
        if not self.graphicsView.hasImage():
446
            self.showImageSelectionMessageBox()
447
            return
448

    
449
        try:
450
            dlg = QValidationDialog(self)
451
            if QDialog.Accepted == dlg.exec_():
452
                # remove error items
453
                for item in self.graphicsView.scene().items():
454
                    if type(item) is QEngineeringErrorItem:
455
                        item.transfer.onRemoved.emit(item)
456
                # up to here
457

    
458
                self.progress_bar.setMaximum(len(self.graphicsView.scene().items()))
459
                self.progress_bar.setValue(0)
460

    
461
                cmd = ValidateCommand(self.graphicsView)
462
                cmd.show_progress.connect(self.progress_bar.setValue)
463
                errors = cmd.execute(self.graphicsView.scene().items())
464
                for error in errors:
465
                    error.transfer.onRemoved.connect(self.itemRemoved)
466
                    #self.graphicsView.scene().addItem(error)
467
                    error.addSvgItemToScene(self.graphicsView.scene())
468

    
469
                self.tableWidgetInconsistency.clearContents()
470
                self.tableWidgetInconsistency.setRowCount(len(errors))
471
                for index, error in enumerate(errors):
472
                    self.makeInconsistencyTableRow(index, error)
473

    
474
                self.tabWidget_2.setTabText(self.tabWidget_2.indexOf(self.tabInconsistency),
475
                                            self.tr('Inconsistency') + f"({len(errors)})")
476
                if errors:
477
                    self.tabWidget_2.tabBar().setTabTextColor(self.tabWidget_2.indexOf(self.tabInconsistency), Qt.red)
478
                else:
479
                    self.tabWidget_2.tabBar().setTabTextColor(self.tabWidget_2.indexOf(self.tabInconsistency), Qt.black)
480
        except Exception as ex:
481
            message = 'error occurred({}) in {}:{}'.format(ex, sys.exc_info()[-1].tb_frame.f_code.co_filename,
482
                                                           sys.exc_info()[-1].tb_lineno)
483
            self.addMessage.emit(MessageType.Error, message)
484
        finally:
485
            self.progress_bar.setValue(self.progress_bar.maximum())
486

    
487
    def makeInconsistencyTableRow(self, row, errorItem):
488
        '''
489
            @brief  make row data for inconsistency widget
490
            @author euisung
491
            @date   2019.04.16
492
        '''
493

    
494
        item = QTableWidgetItem(str(errorItem.parent))
495
        item.tag = errorItem
496
        self.tableWidgetInconsistency.setItem(row, 0, item)
497

    
498
        item = QTableWidgetItem(str(type(errorItem.parent)))
499
        item.tag = errorItem
500
        self.tableWidgetInconsistency.setItem(row, 1, item)
501

    
502
        item = QTableWidgetItem(errorItem.msg)
503
        item.tag = errorItem
504
        self.tableWidgetInconsistency.setItem(row, 2, item)
505

    
506
    def inconsistencyItemClickEvent(self, item):
507
        """
508
        @brief  inconsistency table item clicked
509
        @author euisung
510
        @date   2019.04.02
511
        """
512
        from HighlightCommand import HighlightCommand
513

    
514
        HighlightCommand(self.graphicsView).execute(item.tag)
515

    
516
    def read_settings(self):
517
        """read geometry and state"""
518
        from App import App
519

    
520
        try:
521
            self.settings = QSettings(App.COMPANY, App.NAME)
522
            self.restoreGeometry(self.settings.value("geometry", ""))
523
            self.restoreState(self.settings.value("windowState", ""))
524
        except Exception as ex:
525
            message = f"error occurred({repr(ex)}) in {sys.exc_info()[-1].tb_frame.f_code.co_filename}:" \
526
                      f"{sys.exc_info()[-1].tb_lineno}"
527

    
528
    def load_stylesheet(self, file):
529
        """load stylesheets"""
530

    
531
        QtWidgets.qApp.loadStyleSheet(os.path.join(os.path.dirname(os.path.realpath(__file__)), file))
532

    
533
        app_doc_data = AppDocData.instance()
534
        configs = [Config('app', 'stylesheet', file)]
535
        app_doc_data.saveAppConfigs(configs)
536

    
537
    def load_language(self, file):
538
        """load language file and then apply selected language"""
539
        try:
540
            qm_file = os.path.join(os.path.dirname(os.path.realpath(__file__)), 'translate', '{0}.qm'.format(file))
541
            QtWidgets.qApp.load_language(qm_file)
542

    
543
            app_doc_data = AppDocData.instance()
544
            configs = [Config('app', 'language', file)]
545
            app_doc_data.saveAppConfigs(configs)
546
        finally:
547
            self.retranslateUi(self)
548

    
549
    def refresh_item_list(self):
550
        """refresh item tree"""
551

    
552
        if not self.graphicsView.hasImage():
553
            self.showImageSelectionMessageBox()
554
            return
555
        
556
        app_doc_data = AppDocData.instance()
557
        
558
        '''
559
        self.itemTreeWidget.setCurrentPID(app_doc_data.activeDrawing.name)
560

561
        """update item tree widget"""
562
        line_no_items = [item for item in self.graphicsView.scene().items()
563
                            if type(item) is QEngineeringLineNoTextItem]
564
        for line_no in line_no_items:
565
            if (hasattr(line_no, 'treeItem')):
566
                line_no.treeItem = None
567

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

574
        line_no_items = [item for item in self.graphicsView.scene().items()
575
                            if type(item) is QEngineeringTrimLineNoTextItem]
576
        for line_no in line_no_items:
577
            line_no_tree_item = self.itemTreeWidget.addTreeItem(self.itemTreeWidget.root, line_no)
578
            for run in line_no.runs:
579
                for run_item in run.items:
580
                    if issubclass(type(run_item), SymbolSvgItem):
581
                        self.init_add_tree_item(line_no_tree_item, run_item)
582

583
        for trim_line_no in app_doc_data.tracerLineNos:
584
            line_no_tree_item = self.itemTreeWidget.addTreeItem(self.itemTreeWidget.root, trim_line_no)
585
            for run in trim_line_no.runs:
586
                for run_item in run.items:
587
                    if issubclass(type(run_item), SymbolSvgItem):
588
                        self.init_add_tree_item(line_no_tree_item, run_item)
589

590
        self.itemTreeWidget.update_item_count()
591
        self.itemTreeWidget.expandAll()
592
        """up to here"""
593
        '''
594

    
595
        self.itemTreeWidget.InitLineNoItems()
596

    
597
        line_nos = app_doc_data.tracerLineNos
598
        '''
599
        _line_nos = [line_no for line_no in line_nos if type(line_no) is QEngineeringLineNoTextItem]
600
        line_no_pairs = []
601
        line_no_texts = []
602
        for line_no in _line_nos:
603
            text = line_no.sort_order_text()
604
            line_no_pairs.append([line_no, text])
605
            line_no_texts.append(text)
606
        
607
        line_no_texts = app_doc_data.winsort(list(set(line_no_texts)))
608

609
        for line_no_text in line_no_texts:
610
            for line_no_pair in [line_no_pair for line_no_pair in line_no_pairs if line_no_pair[1] == line_no_text]:
611
                line_nos.remove(line_no_pair[0])
612
                line_nos.insert(0, line_no_pair[0])
613
        '''
614

    
615
        #line_nos = app_doc_data.tracerLineNos
616
        #line_nos.sort(key=lambda x: int(x.getAttributes(True)[[_key for _key in x.getAttributes(True).keys() if _key.Attribute == 'Tag Seq No'][0]]) if (x.getAttributes(True) and [_key for _key in x.getAttributes(True).keys() if _key.Attribute == 'Tag Seq No']) else -1 if type(x) is QEngineeringLineNoTextItem else 9999999)
617
        for line_no in line_nos:
618
            item = self.itemTreeWidget.addTreeItem(self.itemTreeWidget.root, line_no)
619
            connectedItems = line_no.getConnectedItems()
620
            for connectedItem in connectedItems:
621
                if issubclass(type(connectedItem), SymbolSvgItem):
622
                    self.itemTreeWidget.addTreeItem(item, connectedItem)
623
        
624
    def sort_drawing_list(self, index):
625
        """ sort drawing list """
626
        if index == 0:
627
            if self.drawing_reverse:
628
                self.load_drawing_list(reverse=False)
629
            else:
630
                self.load_drawing_list(reverse=True)
631
            self.drawing_reverse = not self.drawing_reverse
632

    
633
    def on_line_no_sort_setting(self):
634
        from PSNLineNoAttrTargetDialog import PSNLineNoAttrTargetDialog
635

    
636
        dialog = PSNLineNoAttrTargetDialog(self, 'Sort')
637
        (isAccept) = dialog.showDialog()        
638

    
639
    def load_drawing_list(self, reverse=False):
640
        """load p&id drawing list"""
641
        try:
642
            self.treeWidgetDrawingList.load_drawing_list(reverse)
643
        except Exception as ex:
644
            message = f'error occurred({repr(ex)}) in {sys.exc_info()[-1].tb_frame.f_code.co_filename}:' \
645
                      f'{sys.exc_info()[-1].tb_lineno}'
646
            self.addMessage.emit(MessageType.Error, message)
647
        finally:
648
            self.progress_bar.setValue(self.progress_bar.maximum())
649

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

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

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

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

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

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

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

    
692
        return
693

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

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

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

    
725
        from TextItemEditDialog import QTextItemEditDialog
726

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

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

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

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

    
745
        from ReplaceSymbolDialog import QReplaceSymbolDialog
746

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

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

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

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

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

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

    
774
    def on_connect_line_to_symbol(self):
775
        if not self.graphicsView.hasImage():
776
            self.showImageSelectionMessageBox()
777
            return
778
        
779
        items = [item for item in self.graphicsView.scene().items() if issubclass(type(item), QEngineeringAbstractItem)]
780
        for item in items:
781
            item.setVisible(False)
782
        QApplication.processEvents()
783
        
784
        app_doc_data = AppDocData.instance()
785
        configs = app_doc_data.getConfigs('Line Detector', 'Length to connect line')
786
        toler = int(configs[0].value) if configs else 20
787
        count = self.connect_line_to_symbol(10, True)
788
        #self.connect_line_to_symbol(toler, False, count)
789

    
790
        self.progress_bar.setValue(self.progress_bar.maximum())
791

    
792
        for item in items:
793
            item.setVisible(True)
794
        
795
        QApplication.processEvents()
796
        QMessageBox.information(self, self.tr('Information'), self.tr('Connecting between symbols and lines is completed'))
797

    
798
    def connect_line_to_symbol(self, toler=20, start=True, count=0):
799
        """connect line to symbol"""
800
        from LineDetector import LineDetector
801
        from shapely.geometry import Point
802
        #from RecognitionDialog import Worker
803

    
804
        app_doc_data = AppDocData.instance()
805
        #configs = app_doc_data.getConfigs('Project', 'Operation')
806
        detector = LineDetector(app_doc_data.imgSrc)
807

    
808
        lines = sorted([item for item in self.graphicsView.scene().items() if type(item) is QEngineeringLineItem], key=lambda param: param.length() + 1 if param.isHorizontal() else param.length(), reverse=True)# if item.length() > 50]
809
        lines_short = []#[item for item in self.graphicsView.scene().items() if type(item) is QEngineeringLineItem if item.length() <= 50]
810
        unknowns = [item for item in self.graphicsView.scene().items() if type(item) is QEngineeringUnknownItem]
811
        end_breaks = [item for item in self.graphicsView.scene().items() if type(item) is QEngineeringEndBreakItem]
812
        spec_breaks = [item for item in self.graphicsView.scene().items() if type(item) is QEngineeringSpecBreakItem]
813
        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]
814
        texts = [item for item in self.graphicsView.scene().items() if type(item) is QEngineeringTextItem and item.owner is None]
815

    
816
        for item in lines_short + unknowns:
817
            item.transfer.onRemoved.emit(item)
818

    
819
        if start:
820
            self.progress_bar.setMaximum((len(lines) + len(symbols)) * 2 + 3)
821
            count = 1
822
            self.progress_bar.setValue(count)
823
            QApplication.processEvents()
824

    
825
        # connect symbol to symbol
826
        try:
827
            for symbol in symbols:
828
                matches = [it for it in symbols if it is not symbol and symbol.is_connectable(it, toler=toler)]
829
                for match in matches:
830
                    symbol.connect_if_possible(match, toler=int(toler))
831
                
832
                count += 2
833
                self.progress_bar.setValue(count)
834
        except Exception as ex:
835
            message = f"error occurred({repr(ex)}) in {sys.exc_info()[-1].tb_frame.f_code.co_filename}:" \
836
                        f"{sys.exc_info()[-1].tb_lineno}"
837
            self.addMessage.emit(MessageType.Error, message)
838
        QApplication.processEvents()
839
        # up to here
840

    
841
        # create short line
842
        new_lines = []
843
        try:
844
            '''
845
            conns = []
846
            for sym in symbols:
847
                if sym.conn_type:
848
                    for index in range(len(sym.conn_type)):
849
                        if sym.conn_type[index] == 'Secondary' or sym.conn_type[index] == 'Primary':
850
                            item = sym.connectors[index].connectedItem
851
                            if item is None:
852
                                conns.append(sym.connectors[index])
853
            
854
            new_lines.extend(Worker.make_short_lines_sts(conns, None))
855

856
            conns = []
857
            for sym in symbols:
858
                if sym.conn_type:
859
                    for index in range(len(sym.conn_type)):
860
                        if sym.conn_type[index] == 'Secondary' or sym.conn_type[index] == 'Primary':
861
                            item = sym.connectors[index].connectedItem
862
                            if item is None and sym.connectors[index]:
863
                                conns.append(sym.connectors[index])
864
            
865
            new_lines.extend(Worker.make_short_lines_stl(lines, conns, None))
866

867
            for line in new_lines:
868
                self.graphicsView.scene().addItem(line)
869
                for conn in line.connectors:
870
                    conn.transfer.onPosChanged.connect(line.onConnectorPosChaned)
871
            '''
872
        except Exception as ex:
873
            message = f"error occurred({repr(ex)}) in {sys.exc_info()[-1].tb_frame.f_code.co_filename}:" \
874
                        f"{sys.exc_info()[-1].tb_lineno}"
875
            self.addMessage.emit(MessageType.Error, message)
876
        # up to here
877
                
878
        # connect line to symbol
879
        try:
880
            for line in lines:
881
                matches = [_symbol for _symbol in symbols if _symbol.is_connectable(line, toler=toler)]
882
                for _symbol in matches:
883
                    detector.connectLineToSymbol(line, _symbol, toler=toler)
884

    
885
                count += 1
886
                self.progress_bar.setValue(count)
887
        except Exception as ex:
888
            message = f"error occurred({repr(ex)}) in {sys.exc_info()[-1].tb_frame.f_code.co_filename}:" \
889
                        f"{sys.exc_info()[-1].tb_lineno}"
890
            self.addMessage.emit(MessageType.Error, message)
891
        QApplication.processEvents()
892
        # up to here
893

    
894
        # connect line to line
895
        try:
896
            for line in lines:
897
                #matches = [it for it in lines if (it is not line) and (not line.isParallel(it))]
898
                #for match in matches:
899
                for match in lines:
900
                    detector.connectLineToLine(match, line, toler)
901

    
902
                count += 1
903
                self.progress_bar.setValue(count)
904
        except Exception as ex:
905
            message = f"error occurred({repr(ex)}) in {sys.exc_info()[-1].tb_frame.f_code.co_filename}:" \
906
                        f"{sys.exc_info()[-1].tb_lineno}"
907
            self.addMessage.emit(MessageType.Error, message)
908
        QApplication.processEvents()
909
        # up to here
910

    
911
        try:
912
            # connect end break
913
            usedItemPairs = []
914
            for end_break in end_breaks:
915
                if end_break.prop('Freeze') or end_break.owner or end_break.prop('Connected Item'):
916
                    usedItemPairs.append([end_break.owner, end_break.prop('Connected Item')])
917

    
918
            for end_break in end_breaks:
919
                if end_break.prop('Freeze') or end_break.owner or end_break.prop('Connected Item'):
920
                    continue
921

    
922
                originPoint = Point(end_break.origin[0], end_break.origin[1])
923
                minD = sys.maxsize
924
                ownerItem = None
925
                connectedItem = None
926

    
927
                for symbol in symbols:
928
                    for conn in symbol.connectors:
929
                        dist = originPoint.distance(Point(conn.sceneConnectPoint[0], conn.sceneConnectPoint[1]))
930
                        if not conn.connectedItem or not issubclass(type(conn.connectedItem), QEngineeringAbstractItem) or \
931
                            [pair for pair in usedItemPairs if symbol in pair and conn.connectedItem in pair] or dist > 12 * toler or dist > minD:
932
                            continue
933

    
934
                        minD = dist
935
                        ownerItem = symbol
936
                        connectedItem = conn.connectedItem
937

    
938
                for line in lines:
939
                    for conn in line.connectors:
940
                        dist = originPoint.distance(Point(conn.sceneConnectPoint[0], conn.sceneConnectPoint[1]))
941
                        if not conn.connectedItem or not issubclass(type(conn.connectedItem), QEngineeringAbstractItem) or \
942
                            conn._connected_at != QEngineeringAbstractItem.CONNECTED_AT_BODY  or \
943
                            [pair for pair in usedItemPairs if line in pair and conn.connectedItem in pair] or dist > 12 * toler or dist > minD:
944
                            continue
945

    
946
                        minD = dist
947
                        ownerItem = line
948
                        connectedItem = conn.connectedItem
949

    
950
                if ownerItem and connectedItem:
951
                    end_break.set_property('Connected Item', connectedItem)
952
                    end_break.setToolTip('owner : ' + str(ownerItem))
953
                    end_break.owner = ownerItem
954
                    end_break.set_property('Freeze', True)
955

    
956
                    usedItemPairs.append([ownerItem, connectedItem])
957
            # up to here
958

    
959
            # connect spec break
960
            self.on_connect_spec_breaks(spec_breaks, texts, symbols, lines)
961
            # up to here
962
        
963
        except Exception as ex:
964
            message = f"error occurred({repr(ex)}) in {sys.exc_info()[-1].tb_frame.f_code.co_filename}:" \
965
                        f"{sys.exc_info()[-1].tb_lineno}"
966
            self.addMessage.emit(MessageType.Error, message)
967
        
968
        return count
969

    
970
    def on_connect_spec_breaks(self, spec_breaks, texts=None, symbols=None, lines=None):
971
        from CodeTables import CodeTable
972
        from shapely.geometry import Point
973

    
974
        app_doc_data = AppDocData.instance()
975
        
976
        try:
977
            if not texts or not symbols or not lines:
978
                texts = [item for item in self.graphicsView.scene().items() if type(item) is QEngineeringTextItem and item.owner is None]
979
                symbols = [item for item in self.graphicsView.scene().items() if issubclass(type(item), SymbolSvgItem) and type(item) is not QEngineeringEndBreakItem and item not in spec_breaks]
980
                lines = sorted([item for item in self.graphicsView.scene().items() if type(item) is QEngineeringLineItem], key=lambda param: param.length(), reverse=True)
981

    
982
            usedTexts = []
983
            attribute_table_item_list = []
984
            dist_range = None
985
            specBreakAttrsFull = [attr for attr in app_doc_data.getSymbolAttribute('Segment Breaks') if attr.AttributeType == 'Spec' or attr.AttributeType == 'String']
986

    
987
            for attr in specBreakAttrsFull:
988
                if attr.AttributeType != 'Spec' or attr.Attribute == 'NominalDiameter':
989
                    continue
990

    
991
                usedTexts = []
992

    
993
                table = CodeTable.instance(attr.Attribute)
994
                items = []
995
                for text in texts:
996
                    if text not in usedTexts and table.find_match_exactly(text.text()):
997
                        usedTexts.append(text)
998
                        items.append(text)
999

    
1000
                if len(items) >= 2:
1001
                    attribute_table_item_list.append([attr.Attribute, items])
1002

    
1003
            usedItemPairs = []
1004
            for spec_break in spec_breaks:
1005
                if not dist_range:
1006
                    dist_range = max(spec_break.sceneBoundingRect().height(), spec_break.sceneBoundingRect().width())
1007

    
1008
                attrs = spec_break.getAttributes()
1009
                up = [attr.AssocItem for attr in attrs if attr.Attribute == 'UpStream']
1010
                down = [attr.AssocItem for attr in attrs if attr.Attribute == 'DownStream']
1011
                if (up and up[0]) or (down and down[0]):
1012
                    usedItemPairs.append([up, down])
1013

    
1014
            for spec_break in spec_breaks:
1015
                attrs = spec_break.getAttributes()
1016
                up = [attr.AssocItem for attr in attrs if attr.Attribute == 'UpStream']
1017
                down = [attr.AssocItem for attr in attrs if attr.Attribute == 'DownStream']
1018
                if (up and up[0]) or (down and down[0]):
1019
                    continue
1020

    
1021
                originPoint = Point(spec_break.origin[0], spec_break.origin[1])
1022
                minD = sys.maxsize
1023
                upItem = None
1024
                downItem = None
1025

    
1026
                for symbol in symbols:
1027
                    for conn in symbol.connectors:
1028
                        dist = originPoint.distance(Point(conn.sceneConnectPoint[0], conn.sceneConnectPoint[1]))
1029
                        if not conn.connectedItem or not issubclass(type(conn.connectedItem), QEngineeringAbstractItem) or \
1030
                            [pair for pair in usedItemPairs if symbol in pair and conn.connectedItem in pair] or dist > dist_range or dist > minD:
1031
                            continue
1032

    
1033
                        minD = dist
1034
                        upItem = symbol
1035
                        downItem = conn.connectedItem
1036

    
1037
                for line in lines:
1038
                    for conn in line.connectors:
1039
                        dist = originPoint.distance(Point(conn.sceneConnectPoint[0], conn.sceneConnectPoint[1]))
1040
                        if not conn.connectedItem or not issubclass(type(conn.connectedItem), QEngineeringAbstractItem) or \
1041
                            conn._connected_at != QEngineeringAbstractItem.CONNECTED_AT_BODY  or \
1042
                            [pair for pair in usedItemPairs if line in pair and conn.connectedItem in pair] or dist > dist_range or dist > minD + 1:
1043
                            continue
1044

    
1045
                        minD = dist
1046
                        upItem = line
1047
                        downItem = conn.connectedItem
1048

    
1049
                if upItem and downItem:
1050
                    for key in attrs.keys():
1051
                        if key.Attribute == 'UpStream':
1052
                            attrs[key] = str(upItem)
1053
                            spec_break.add_assoc_item(upItem, key.AttrAt, force=True)
1054
                            key.AssocItem = upItem
1055
                            key.Freeze = True
1056
                        elif key.Attribute == 'DownStream':
1057
                            attrs[key] = str(downItem)
1058
                            spec_break.add_assoc_item(downItem, key.AttrAt, force=True)
1059
                            key.AssocItem = downItem
1060
                            key.Freeze = True
1061
                    spec_break.set_property('Freeze', True)
1062
                    spec_break.set_property('Show', True)
1063

    
1064
                    usedItemPairs.append([upItem, downItem])
1065

    
1066
                    for attribute_table_item in attribute_table_item_list:
1067
                        upText = None
1068
                        downText = None
1069
                        attribute_table_item[1].sort(key=lambda x: originPoint.distance(Point(x.center().x(), x.center().y())))
1070
                        if originPoint.distance(Point(attribute_table_item[1][1].center().x(), attribute_table_item[1][1].center().y())) < dist_range:
1071
                            if issubclass(type(upItem), SymbolSvgItem):
1072
                                symbolPoint = Point(upItem.origin[0], upItem.origin[1])
1073
                                #if symbolPoint.distance(Point(attribute_table_item[1][0].sceneBoundingRect().left(), attribute_table_item[1][0].sceneBoundingRect().top())) < \
1074
                                #    symbolPoint.distance(Point(attribute_table_item[1][1].sceneBoundingRect().left(), attribute_table_item[1][1].sceneBoundingRect().top())):
1075
                                if symbolPoint.distance(Point(attribute_table_item[1][0].center().x(), attribute_table_item[1][0].center().y())) < \
1076
                                    symbolPoint.distance(Point(attribute_table_item[1][1].center().x(), attribute_table_item[1][1].center().y())):
1077
                                    upText = attribute_table_item[1][0]
1078
                                    downText = attribute_table_item[1][1]
1079
                                else:
1080
                                    upText = attribute_table_item[1][1]
1081
                                    downText = attribute_table_item[1][0]
1082
                            elif issubclass(type(downItem), SymbolSvgItem):
1083
                                symbolPoint = Point(downItem.origin[0], downItem.origin[1])
1084
                                #if symbolPoint.distance(Point(attribute_table_item[1][0].sceneBoundingRect().left(), attribute_table_item[1][0].sceneBoundingRect().top())) < \
1085
                                #    symbolPoint.distance(Point(attribute_table_item[1][1].sceneBoundingRect().left(), attribute_table_item[1][1].sceneBoundingRect().top())):
1086
                                if symbolPoint.distance(Point(attribute_table_item[1][0].center().x(), attribute_table_item[1][0].center().y())) < \
1087
                                    symbolPoint.distance(Point(attribute_table_item[1][1].center().x(), attribute_table_item[1][1].center().y())):
1088
                                    downText = attribute_table_item[1][0]
1089
                                    upText = attribute_table_item[1][1]
1090
                                else:
1091
                                    downText = attribute_table_item[1][1]
1092
                                    upText = attribute_table_item[1][0]
1093
                            else:
1094
                                if upItem.length() < downItem.length():
1095
                                    linePoint = Point(upItem.center().x(), upItem.center().y())
1096
                                    if linePoint.distance(Point(attribute_table_item[1][0].center().x(), attribute_table_item[1][0].center().y())) < \
1097
                                        linePoint.distance(Point(attribute_table_item[1][1].center().x(), attribute_table_item[1][1].center().y())):
1098
                                        upText = attribute_table_item[1][0]
1099
                                        downText = attribute_table_item[1][1]
1100
                                    else:
1101
                                        upText = attribute_table_item[1][1]
1102
                                        downText = attribute_table_item[1][0]
1103
                                else:
1104
                                    linePoint = Point(downItem.center().x(), downItem.center().y())
1105
                                    if linePoint.distance(Point(attribute_table_item[1][0].center().x(), attribute_table_item[1][0].center().y())) < \
1106
                                        linePoint.distance(Point(attribute_table_item[1][1].center().x(), attribute_table_item[1][1].center().y())):
1107
                                        downText = attribute_table_item[1][0]
1108
                                        upText = attribute_table_item[1][1]
1109
                                    else:
1110
                                        downText = attribute_table_item[1][1]
1111
                                        upText = attribute_table_item[1][0]
1112

    
1113
                        if upText and downText:
1114
                            for full in specBreakAttrsFull:
1115
                                if full.Attribute == attribute_table_item[0]:
1116
                                    attrs[full] = [upText.text(), downText.text()]
1117
                                    attribute_table_item[1].remove(upText)
1118
                                    attribute_table_item[1].remove(downText)
1119
                                    break
1120

    
1121
                            stream_line = [upItem, downItem]
1122
                            stream_track = [downItem, upItem]
1123
                            stream_res = [False, False]
1124
                            for index in range(len(stream_line)):
1125
                                while True:
1126
                                    if type(stream_line[index]) is QEngineeringLineItem:
1127
                                        stream_res[index] = True
1128
                                        break
1129
                                    else:
1130
                                        find_next = False
1131
                                        connected_count = 0
1132
                                        for connectorr in stream_line[index].connectors:
1133
                                            connected_count += 1
1134
                                            if connectorr.connectedItem and stream_track[index] is not connectorr.connectedItem and \
1135
                                                    stream_line[index].next_connected(stream_track[index], connectorr.connectedItem):
1136
                                                stream_track[index] = stream_line[index]
1137
                                                stream_line[index] = connectorr.connectedItem
1138
                                                find_next = True
1139
                                                break
1140

    
1141
                                        if not find_next:
1142
                                            # prevent infinite loop
1143
                                            if connected_count == 2:
1144
                                                for connectorr in stream_line[index].connectors:
1145
                                                    if connectorr.connectedItem and not connectorr.connectedItem is stream_track[index]:
1146
                                                        stream_line[index] = connectorr.connectedItem
1147
                                                        stream_track[index] = stream_line[index]
1148
                                                        find_next = True
1149
                                                        break
1150
                                                if not find_next:
1151
                                                    break
1152
                                            else:
1153
                                                break
1154

    
1155
                            if stream_res[0] and stream_res[1]:
1156
                                up_down_find = [upText, downText]
1157

    
1158
                                for index in range(len(stream_line)):
1159
                                    _attrs = stream_line[index].getAttributes()
1160
                                    for key in _attrs.keys():
1161
                                        if key.Attribute == attribute_table_item[0]:
1162
                                            _attrs[key] = up_down_find[index].text()
1163
                                            key.AssocItem = up_down_find[index]
1164
                                            stream_line[index].add_assoc_item(up_down_find[index],
1165
                                                                                key.AttrAt, force=True)
1166
                                            up_down_find[index].owner = stream_line[index]
1167
                                            key.Freeze = True
1168
                                            break
1169

    
1170
            return True
1171
        except Exception as ex:
1172
            message = f"error occurred({repr(ex)}) in {sys.exc_info()[-1].tb_frame.f_code.co_filename}:" \
1173
                        f"{sys.exc_info()[-1].tb_lineno}"
1174
            self.addMessage.emit(MessageType.Error, message)
1175

    
1176
            return False
1177

    
1178

    
1179
    def on_recognize_line(self):
1180
        """recognize lines in selected area"""
1181
        from RecognizeLineCommand import RecognizeLineCommand
1182

    
1183
        if not self.graphicsView.hasImage():
1184
            self.actionOCR.setChecked(False)
1185
            self.showImageSelectionMessageBox()
1186
            return
1187

    
1188
        cmd = RecognizeLineCommand(self.graphicsView)
1189
        cmd.onSuccess.connect(self.on_success_to_recognize_line)
1190
        cmd.onRejected.connect(self.onCommandRejected)
1191
        self.graphicsView.command = cmd
1192

    
1193
    '''
1194
            @brief      show text recognition dialog
1195
            @author     humkyung
1196
            @date       2018.08.08
1197
    '''
1198
    def on_success_to_recognize_line(self, x, y, width, height):
1199
        import io
1200
        from LineDetector import LineDetector
1201
        from EngineeringGraphicsLineItem import QEngineeringGraphicsLineItem
1202

    
1203
        try:
1204
            image = self.graphicsView.image().copy(x, y, width, height)
1205
            buffer = QBuffer()
1206
            buffer.open(QBuffer.ReadWrite)
1207
            image.save(buffer, "PNG")
1208
            pyImage = Image.open(io.BytesIO(buffer.data()))
1209
            img = np.array(pyImage)
1210
            img = cv2.cvtColor(img, cv2.COLOR_BGR2GRAY)
1211

    
1212
            detector = LineDetector(img)
1213
            lines = detector.detect_line_without_symbol()
1214
            for line in lines:
1215
                vertices = [[line[0][0] + x, line[0][1] + y], [line[1][0] + x, line[1][1] + y]]
1216
                line_item = QEngineeringGraphicsLineItem(vertices)
1217
                self.graphicsView.scene().addItem(line_item)
1218

    
1219
        except Exception as ex:
1220
            message = 'error occurred({}) in {}:{}'.format(repr(ex), sys.exc_info()[-1].tb_frame.f_code.co_filename,
1221
                                                           sys.exc_info()[-1].tb_lineno)
1222
            self.addMessage.emit(MessageType.Error, message)
1223

    
1224
    def display_number_of_items(self):
1225
        """display count of symbol, line, text"""
1226

    
1227
        items = [item for item in self.graphicsView.scene().items() if type(item) is QEngineeringUnknownItem]
1228
        if len(items) > 0:
1229
            self.labelStatus.setText(
1230
                "<font color='red'>" + self.tr('Unrecognition') + " : {}</font>".format(len(items)))
1231
        else:
1232
            self.labelStatus.setText(
1233
                "<font color='black'>" + self.tr('Unrecognition') + " : {}</font>".format(len(items)))
1234

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

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

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

    
1245
        self.itemTreeWidget.sceneChanged(self.graphicsView.scene().items())
1246

    
1247
    def dbUpdate(self):
1248
        """ no more used """
1249
        """db update when save or recognition"""
1250

    
1251
        try:
1252
            appDocData = AppDocData.instance()
1253
            items = appDocData.allItems
1254

    
1255
            '''
1256
            titleBlockProps = appDocData.getTitleBlockProperties()
1257
            titleBlockItems = []
1258
            for item in items:
1259
                # if type(item) is QEngineeringLineNoTextItem:
1260
                #    item.saveLineData()
1261
                if type(item) is QEngineeringTextItem:
1262
                    for titleBlockProp in titleBlockProps:
1263
                        if item.area == titleBlockProp[0]:
1264
                            titleBlockItems.append(item)
1265
            '''
1266

    
1267
            # unknown item is not saved now for performance
1268
            db_items = [item for item in items if issubclass(type(item), QEngineeringAbstractItem) and
1269
                        type(item) is not QGraphicsBoundingBoxItem and
1270
                        type(item) is not QEngineeringErrorItem and
1271
                        type(item) is not QEngineeringLineNoTextItem and
1272
                        type(item) is not QEngineeringUnknownItem]
1273
            db_items.extend([item for item in items if type(item) is QEngineeringLineNoTextItem])
1274
            db_items.extend([line for line in appDocData.tracerLineNos if type(line) is QEngineeringTrimLineNoTextItem])
1275
            # db_items.extend(titleBlockItems)
1276
            configs = appDocData.getConfigs('Data Save', 'Unknown Xml Only')
1277
            if configs and int(configs[0].value) is -1:
1278
                db_items.extend([item for item in items if type(item) is QEngineeringUnknownItem])
1279

    
1280
            '''
1281
            dbItems = [item for item in items if
1282
                       type(item) is QEngineeringInstrumentItem or type(item) is QEngineeringEquipmentItem or type(
1283
                           item) is QEngineeringReducerItem or \
1284
                       type(item) is QEngineeringNoteItem or type(item) is SymbolSvgItem or type(
1285
                           item) is QEngineeringLineNoTextItem or type(
1286
                           item) is QEngineeringVendorItem] + titleBlockItems
1287
            '''
1288
            appDocData.saveToDatabase(db_items)
1289
        except Exception as ex:
1290
            message = 'error occurred({}) in {}:{}'.format(ex, sys.exc_info()[-1].tb_frame.f_code.co_filename,
1291
                                                           sys.exc_info()[-1].tb_lineno)
1292
            self.addMessage.emit(MessageType.Error, message)
1293

    
1294
    def save_drawing_if_necessary(self):
1295
        """ask to user to save drawing or not when drawing is modified"""
1296

    
1297
        app_doc_data = AppDocData.instance()
1298
        if app_doc_data.activeDrawing and app_doc_data.activeDrawing.modified and not app_doc_data.readOnly:
1299
            #if QMessageBox.Yes == QMessageBox.question(self, self.tr("Question"),
1300
            #                                           self.tr("Do you want to save drawing?"),
1301
            #                                           QMessageBox.Yes | QMessageBox.No):
1302
            #    self.actionSaveCliked()
1303
            #    return True
1304
            if QMessageBox.Ignore == QMessageBox.question(self, self.tr('Continue?'),
1305
                                                       self.tr('Changes may not have been saved.'),
1306
                                                       QMessageBox.Ignore | QMessageBox.Cancel):
1307
                return False
1308
            return True
1309

    
1310
    def actionSaveCliked(self, batch=False):
1311
        """
1312
        save current drawing
1313
        @return:
1314
        """
1315
        from EngineeringAbstractItem import QEngineeringAbstractItem
1316
        from SaveWorkCommand import SaveWorkCommand
1317

    
1318
        try:
1319
            app_doc_data = AppDocData.instance()
1320

    
1321
            # read-only
1322
            if app_doc_data.readOnly:
1323
                QMessageBox.warning(self, self.tr('Warning'), "We can't save because the drawing is read-only.")
1324
                return
1325

    
1326
            if app_doc_data.imgName is None:
1327
                self.showImageSelectionMessageBox()
1328
                return
1329

    
1330
            home_pane = self.ribbon.get_pane('Home File')
1331
            if not home_pane.ui.toolButtonFileSave.isEnabled():
1332
                return
1333

    
1334
            home_pane.ui.toolButtonFileSave.setEnabled(False)
1335

    
1336
            # save alarm
1337
            self.save_alarm_enable(False)    
1338

    
1339
            app_doc_data.clearItemList(False)
1340

    
1341
            #items = self.graphicsView.scene().items()
1342

    
1343
            self._save_work_cmd = SaveWorkCommand(self.graphicsView.scene())
1344
            self._save_work_cmd.show_progress.connect(self.progress_bar.setValue)
1345
            self._save_work_cmd.display_message.connect(self.onAddMessage)
1346
            if not batch:
1347
                self._save_work_cmd.finished.connect(self.save_finished)
1348
            else:
1349
                self._save_work_cmd.finished.connect(self.save_finished_batch)
1350

    
1351
            self._save_work_cmd.start()
1352
        except Exception as ex:
1353
            message = f"error occurred({repr(ex)}) in {sys.exc_info()[-1].tb_frame.f_code.co_filename}:" \
1354
                      f"{sys.exc_info()[-1].tb_lineno}"
1355
            self.addMessage.emit(MessageType.Error, message)
1356

    
1357
    def save_finished(self):
1358
        """
1359
        reload drawing list when save is finished
1360
        @return: None
1361
        """
1362

    
1363
        try:
1364
            self._save_work_cmd.show_progress.emit(100)
1365
            QMessageBox.about(self.graphicsView, self.tr('Information'), self._save_work_cmd.resultStr)
1366
            self.load_drawing_list()
1367

    
1368
            app_doc_data = AppDocData.instance()
1369
            app_doc_data.activeDrawing.modified = False
1370
            title = self.windowTitle()
1371
            self.setWindowTitle(title[:-1] if title[-1] == '*' else title)
1372

    
1373
            # save alarm
1374
            self.save_alarm_enable(True)
1375
        finally:
1376
            home_pane = self.ribbon.get_pane('Home File')
1377
            home_pane.ui.toolButtonFileSave.setEnabled(True)
1378
            if self.save_before_link:
1379
                self.connect_attributes()
1380
                self.save_before_link = False
1381

    
1382
    def save_finished_batch(self):
1383
        """
1384
        reload drawing list when save is finished
1385
        @return: None
1386
        """
1387

    
1388
        try:
1389
            self._save_work_cmd.show_progress.emit(100)
1390
            #QMessageBox.about(self.graphicsView, self.tr('Information'), self._save_work_cmd.resultStr)
1391
            self.load_drawing_list()
1392

    
1393
            app_doc_data = AppDocData.instance()
1394
            app_doc_data.activeDrawing.modified = False
1395
            title = self.windowTitle()
1396
            self.setWindowTitle(title[:-1] if title[-1] == '*' else title)
1397

    
1398
            # save alarm
1399
            #self.save_alarm_enable(True)
1400
        finally:
1401
            home_pane = self.ribbon.get_pane('Home File')
1402
            home_pane.ui.toolButtonFileSave.setEnabled(True)
1403
            #print('saved')
1404

    
1405
    '''
1406
        @brief      refresh resultPropertyTableWidget
1407
        @author     kyouho
1408
        @date       2018.07.19
1409
    '''
1410
    def refreshResultPropertyTableWidget(self):
1411
        items = self.graphicsView.scene().selectedItems()
1412
        if len(items) == 1:
1413
            self.resultPropertyTableWidget.show_item_property(items[0])
1414

    
1415
    '''
1416
        @brief  add message listwidget
1417
        @author humkyung
1418
        @date   2018.07.31
1419
    '''
1420
    def onAddMessage(self, messageType, message):
1421
        from AppDocData import MessageType
1422

    
1423
        try:
1424
            current = QDateTime.currentDateTime()
1425

    
1426
            item = QListWidgetItem('{}: {}'.format(current.toString('hh:mm:ss'), message))
1427
            item.setFlags(item.flags() | Qt.ItemIsEditable)
1428
            if messageType == MessageType.Error:
1429
                item.setBackground(Qt.red)
1430
            elif messageType == 'check':
1431
                item.setBackground(Qt.yellow)
1432

    
1433
            self.listWidgetLog.insertItem(0, item)
1434
        except Exception as ex:
1435
            print('error occurred({}) in {}:{}'.format(ex, sys.exc_info()[-1].tb_frame.f_code.co_filename,
1436
                                                       sys.exc_info()[-1].tb_lineno))
1437

    
1438
    def on_clear_log(self):
1439
        """clear log"""
1440
        self.listWidgetLog.clear()
1441

    
1442
    def onRotate(self, action):
1443
        """rotate a selected symbol"""
1444
        selected = [item for item in self.graphicsView.scene().selectedItems() if issubclass(type(item), SymbolSvgItem)]
1445
        if len(selected) == 1:
1446
            from RotateCommand import RotateCommand
1447
            self.graphicsView.scene()._undo_stack.push(RotateCommand(self.graphicsView.scene(), selected))
1448

    
1449
    def onAreaZoom(self):
1450
        """Area Zoom"""
1451
        visualization_pane = self.ribbon.get_pane('Home Visualization')
1452

    
1453
        self.update_action_group(visualization_pane.ui.toolButtonZoom)
1454
        if visualization_pane.ui.toolButtonZoom.isChecked():
1455
            cmd = AreaZoomCommand.AreaZoomCommand(self.graphicsView)
1456
            cmd.onRejected.connect(self.onCommandRejected)
1457
            self.graphicsView.command = cmd
1458

    
1459
    def onVendor(self, action):
1460
        """make vendor/equipment package area"""
1461

    
1462
        pane = self.ribbon.get_pane('Home')
1463
        if not self.graphicsView.hasImage():
1464
            pane.ui.toolButtonVendor.setChecked(False)
1465
            self.showImageSelectionMessageBox()
1466
            return
1467

    
1468
        pane = self.ribbon.get_pane('Home')
1469
        self.update_action_group(pane.ui.toolButtonVendor)
1470
        checked = pane.ui.toolButtonVendor.isChecked()
1471
        if not hasattr(pane.ui.toolButtonVendor, 'tag'):
1472
            pane.ui.toolButtonVendor.tag = PlacePolygonCommand.PlacePolygonCommand(self.graphicsView)
1473
            pane.ui.toolButtonVendor.tag.onSuccess.connect(self.onVendorCreated)
1474
            pane.ui.toolButtonVendor.tag.onRejected.connect(self.onCommandRejected)
1475

    
1476
        self.graphicsView.command = pane.ui.toolButtonVendor.tag
1477

    
1478
    def onVendorCreated(self):
1479
        """add created vendor polygon area to scene"""
1480

    
1481
        try:
1482
            vendor_tool = self.ribbon.get_pane('Home').ui.toolButtonVendor
1483
            package_combo = self.ribbon.get_pane('Home').ui.comboBoxPackage
1484
            count = len(vendor_tool.tag._polyline._vertices)
1485
            if count > 2:
1486
                points = []
1487
                for point in vendor_tool.tag._polyline._vertices:
1488
                    points.append(QPoint(round(point[0]), round(point[1])))
1489
                polygon = QPolygonF(points)
1490
                item = QEngineeringVendorItem(polygon, pack_type=package_combo.currentText())
1491
                item.area = 'Drawing'
1492
                #item.transfer.onRemoved.connect(self.itemRemoved)
1493
                self.graphicsView.scene().addItem(item)
1494
        finally:
1495
            self.graphicsView.scene().removeItem(vendor_tool.tag._polyline)
1496
            vendor_tool.tag.reset()
1497

    
1498
    def fitWindow(self, view_rect: QRectF = QRectF()):
1499
        """Fit Window"""
1500
        self.graphicsView.useDefaultCommand()
1501
        self.graphicsView.zoomImageInit()
1502

    
1503
        visualization_pane = self.ribbon.get_pane('Home Visualization')
1504
        self.update_action_group(visualization_pane.ui.toolButtonFitWindow)
1505
        if view_rect:
1506
            self.graphicsView.zoom_rect(view_rect)
1507

    
1508
    def on_toggle_lock_axis(self):
1509
        """toggle lock axis"""
1510
        from EngineeringPolylineItem import QEngineeringPolylineItem
1511

    
1512
        visualization_pane = self.ribbon.get_pane('Home Visualization')
1513
        if self.sender() is not visualization_pane.ui.toolButtonLockAxis:
1514
            checked = visualization_pane.ui.toolButtonLockAxis.isChecked()
1515
            visualization_pane.ui.toolButtonLockAxis.setChecked(not checked)
1516

    
1517
        checked = visualization_pane.ui.toolButtonLockAxis.isChecked()
1518
        QEngineeringPolylineItem.DRAWING_MODE = QEngineeringPolylineItem.AXIS_MODE if checked else \
1519
            QEngineeringPolylineItem.FREE_MODE
1520

    
1521
    def scene_changed(self):
1522
        """update modified flag"""
1523

    
1524
        self.display_number_of_items()
1525

    
1526
        app_doc_data = AppDocData.instance()
1527
        app_doc_data.activeDrawing.modified = True
1528
        title = self.windowTitle()
1529
        self.setWindowTitle(title if title[-1] == '*' else title + '*')
1530

    
1531
    def onConvertPDFToImage(self):
1532
        """convert to selected pdf to image"""
1533
        import os
1534

    
1535
        try:
1536
            file_path = os.path.join(os.path.dirname(os.path.realpath(__file__)), 'bin64', 'PDF_TO_IMAGE.exe')
1537
            os.startfile(file_path)
1538
        except Exception as ex:
1539
            message = 'error occurred({}) in {}:{}'.format(ex, sys.exc_info()[-1].tb_frame.f_code.co_filename,
1540
                                                           sys.exc_info()[-1].tb_lineno)
1541
            self.addMessage.emit(MessageType.Error, message)
1542

    
1543
    def on_import_text_from_cad_for_instrument(self):
1544
        """ import text from cad for instrument """
1545
        try:
1546
            self.onCommandRejected()
1547
            dialog = QImportTextFromPDFDialog(self)
1548
            dialog.show()
1549
            dialog.exec_()
1550
        except Exception as ex:
1551
            message = f"error occurred({repr(ex)}) in {sys.exc_info()[-1].tb_frame.f_code.co_filename}:" \
1552
                      f"{sys.exc_info()[-1].tb_lineno}"
1553
            self.addMessage.emit(MessageType.Error, message)
1554

    
1555
    def on_import_text_from_cad(self):
1556
        """ import text from cad """
1557
        try:
1558
            self.onCommandRejected()
1559
            dialog = QImportTextFromCADDialog(self)
1560
            dialog.show()
1561
            dialog.exec_()
1562
        except Exception as ex:
1563
            message = f"error occurred({repr(ex)}) in {sys.exc_info()[-1].tb_frame.f_code.co_filename}:" \
1564
                      f"{sys.exc_info()[-1].tb_lineno}"
1565
            self.addMessage.emit(MessageType.Error, message)
1566

    
1567
    def on_export_PDF_ARS(self, path):
1568
        drawingList = self.treeWidgetDrawingList.topLevelItem(0)
1569
        for idx in range(drawingList.childCount()):
1570
            child = drawingList.child(idx)
1571
            child.setCheckState(0, Qt.Checked)
1572

    
1573
        self.on_export_PDF(path)
1574
    
1575
    def copy_drawing(self):
1576
        from CopyDrawingDialog import QCopyDrawingDialog
1577

    
1578
        # save alarm
1579
        self.save_alarm_enable(False)
1580

    
1581
        try:
1582
            # get checked drawings
1583
            drawing_top = self.treeWidgetDrawingList.topLevelItem(0)
1584
            count = drawing_top.childCount()
1585
            checked_drawings = {}
1586
            for idx in range(count):
1587
                child = drawing_top.child(idx)
1588
                if child.checkState(0) == Qt.Checked and child.data(Qt.UserRole, 0):
1589
                    checked_drawings[child.data(Qt.UserRole, 0)] = child
1590
            # up to here
1591

    
1592
            if not checked_drawings or len(checked_drawings) != 1:
1593
                self.showImageSelectionMessageBox()
1594
                return
1595
            
1596
            dialog = QCopyDrawingDialog(self, list(checked_drawings.keys())[0])
1597
            if dialog.showDialog():
1598
                self.load_drawing_list()
1599

    
1600
        except Exception as ex:
1601
            message = 'error occurred({}) in {}:{}'.format(ex, sys.exc_info()[-1].tb_frame.f_code.co_filename,
1602
                                                           sys.exc_info()[-1].tb_lineno)
1603
            self.addMessage.emit(MessageType.Error, message)
1604

    
1605
    def connect_attributes_batch(self):
1606
        from ConnectAttrDialog import QConnectAttrDialog
1607

    
1608
        # save alarm
1609
        self.save_alarm_enable(False)
1610

    
1611
        try:
1612
            # get checked drawings
1613
            drawing_top = self.treeWidgetDrawingList.topLevelItem(0)
1614
            count = drawing_top.childCount()
1615
            checked_drawings = {}
1616
            for idx in range(count):
1617
                child = drawing_top.child(idx)
1618
                if child.checkState(0) == Qt.Checked and child.data(Qt.UserRole, 0):
1619
                    checked_drawings[child.data(Qt.UserRole, 0)] = child
1620
            # up to here
1621

    
1622
            if not checked_drawings:
1623
                self.showImageSelectionMessageBox()
1624
                return
1625
            
1626
            reply = QMessageBox.question(self, self.tr('Continue?'),
1627
                                         self.tr('Batch linking for selected drawings. '), QMessageBox.Yes,
1628
                                         QMessageBox.Cancel)
1629
            if reply != QMessageBox.Yes:
1630
                return
1631
            
1632
            self.progress_bar.setMaximum(len(checked_drawings) + 2)
1633
            count = 1
1634
            self.progress_bar.setValue(count)
1635

    
1636
            for drawing in checked_drawings.keys():
1637
                self.open_image_drawing(drawing, force=True, ocrUnknown=False, timer=False, pdf=False)
1638

    
1639
                dlg = QConnectAttrDialog(self, self.graphicsView.scene())
1640
                #print('start')
1641
                dlg.start_job()
1642
                #print('end')
1643
                self.actionSaveCliked(batch=True)
1644

    
1645
                count += 1
1646
                self.progress_bar.setValue(count)
1647

    
1648
            self.open_image_drawing(drawing, force=True, ocrUnknown=False) # for reset
1649
            self.progress_bar.setValue(self.progress_bar.maximum())
1650
                    
1651
            QMessageBox.about(self, self.tr("Information"), self.tr('Successfully updated.'))
1652

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

    
1658
    def on_export_PDF(self, path=None):
1659
        # save alarm
1660
        self.save_alarm_enable(False)
1661
        
1662
        #if not self.graphicsView.hasImage():
1663
        #    self.showImageSelectionMessageBox()
1664
        #    return
1665

    
1666
        try:
1667
            app_doc_data = AppDocData.instance()
1668
            current_drawing = None
1669

    
1670
            if self.graphicsView.hasImage():
1671
                current_drawing = app_doc_data.activeDrawing
1672

    
1673
            # get checked drawings
1674
            drawing_top = self.treeWidgetDrawingList.topLevelItem(0)
1675
            count = drawing_top.childCount()
1676
            checked_drawings = {}
1677
            for idx in range(count):
1678
                child = drawing_top.child(idx)
1679
                if child.checkState(0) == Qt.Checked and child.data(Qt.UserRole, 0):
1680
                    checked_drawings[child.data(Qt.UserRole, 0)] = child
1681
            # up to here
1682

    
1683
            # if there is no checked drawing
1684
            if current_drawing and not checked_drawings:
1685
                for idx in range(count):
1686
                    child = drawing_top.child(idx)
1687
                    if child.data(Qt.UserRole, 0) is current_drawing:
1688
                        checked_drawings[child.data(Qt.UserRole, 0)] = child
1689

    
1690
            if not checked_drawings:
1691
                self.showImageSelectionMessageBox()
1692
                return
1693
                
1694
            project = app_doc_data.getCurrentProject()
1695

    
1696
            if current_drawing and len(checked_drawings) == 1:
1697
                name = os.path.join(project.getTempPath(), os.path.splitext(app_doc_data.activeDrawing.name)[0])
1698
                
1699
                options = QFileDialog.Options()
1700
                options |= QFileDialog.DontUseNativeDialog
1701
                file_name, _ = QFileDialog.getSaveFileName(self, "Export PDF", name, "pdf files(*.pdf)", options=options)
1702
                if file_name:
1703
                    file_name += '.png'
1704
                    self.save_PDF(file_name)
1705

    
1706
                    QMessageBox.about(self, self.tr("Information"), self.tr('Successfully saved.'))
1707

    
1708
            elif len(checked_drawings) >= 1:
1709
                name = os.path.join(project.getTempPath(), 'Select a Folder')
1710
                
1711
                file_name = None
1712
                if not path:
1713
                    options = QFileDialog.Options()
1714
                    options |= QFileDialog.DontUseNativeDialog
1715
                    file_name, _ = QFileDialog.getSaveFileName(self, "Export PDF", name, "pdf files(*.pdf)", options=options)
1716

    
1717
                if file_name or path:
1718
                    if file_name:
1719
                        directory = os.path.dirname(file_name)
1720
                    else:
1721
                        directory = path
1722

    
1723
                    self.progress_bar.setMaximum(len(checked_drawings) + 2)
1724
                    count = 1
1725
                    self.progress_bar.setValue(count)
1726

    
1727
                    for drawing in checked_drawings.keys():
1728
                        self.open_image_drawing(drawing, force=True, ocrUnknown=False, timer=False, pdf=True)
1729

    
1730
                        self.save_PDF(os.path.join(directory, drawing.name))
1731

    
1732
                        count += 1
1733
                        self.progress_bar.setValue(count)
1734

    
1735
                    self.open_image_drawing(drawing, force=True, ocrUnknown=False) # for reset
1736
                    self.progress_bar.setValue(self.progress_bar.maximum())
1737
                    
1738
                    QMessageBox.about(self, self.tr("Information"), self.tr('Successfully saved.'))
1739

    
1740
            #self.save_alarm_enable(True, True)
1741

    
1742
            '''
1743
            #app_doc_data = AppDocData.instance()
1744
            #project = app_doc_data.getCurrentProject()
1745

1746
            printer = QPrinter(QPrinter.PrinterResolution)
1747
            #printer.setPageSize(QPrinter.A0)
1748
            printer.setOrientation(QPrinter.Orientation.Landscape)
1749
            #printer.setOutputFileName(os.path.join(project.getPDFFilePath(), os.path.splitext(app_doc_data.activeDrawing.name)[0]))
1750
            #printer.setOutputFormat(QPrinter.PdfFormat)
1751
            dialog = QPrintDialog(printer)
1752
            if (dialog.exec() == QDialog.Accepted):
1753
                painter = QPainter(printer)
1754
                isfull_print = False
1755

1756
                scene = self.graphicsView.scene()
1757

1758
                #for item in scene.items():
1759
                #    if not hasattr(item, 'connectors'): continue
1760
                #    for connector in item.connectors: connector.setVisible(False)
1761

1762
                canvasRect = scene.sceneRect() # or canvasRect = scene.border.boundingRect()
1763
                source = canvasRect
1764
                page = printer.pageRect(QPrinter.Unit.DevicePixel)
1765
                target = QRectF(QPointF(0, 0), QSizeF(page.width(), page.height()))
1766
                scene.render(painter, target, source)
1767
                painter.end()
1768

1769
                QMessageBox.about(self, self.tr("Information"), self.tr('Successfully saved.'))
1770
                #for item in scene.items():
1771
                #    if not hasattr(item, 'connectors'): continue
1772
                #    for connector in item.connectors: connector.setVisible(True)
1773
            '''
1774

    
1775
        except Exception as ex:
1776
            message = 'error occurred({}) in {}:{}'.format(ex, sys.exc_info()[-1].tb_frame.f_code.co_filename,
1777
                                                           sys.exc_info()[-1].tb_lineno)
1778
            self.addMessage.emit(MessageType.Error, message)
1779

    
1780
    def save_PDF(self, file_name):
1781
        #pixMap = self.graphicsView.grab(QRect(QPoint(0, 0), QSize(int(self.graphicsView.scene().sceneRect().width()), int(self.graphicsView.scene().sceneRect().height()))))
1782
        #pixMap.save(name)
1783
        #return
1784

    
1785
        image = QImage(QSize(int(self.graphicsView.scene().sceneRect().width()), int(self.graphicsView.scene().sceneRect().height())), QImage.Format_ARGB32_Premultiplied)
1786
        painter = QPainter(image)
1787
        scene = self.graphicsView.scene()
1788
        canvasRect = scene.sceneRect() # or canvasRect = scene.border.boundingRect()
1789
        source = canvasRect
1790
        scene.render(painter, QRectF(image.rect()), source)
1791
        painter.end()
1792
        image.save(file_name)
1793
        image = Image.open(file_name)
1794
        image = image.convert('RGB')
1795
        image.save(file_name.replace('.png', '.pdf'))
1796
        os.remove(file_name)
1797
        painter.device()
1798

    
1799
    def onSymbolThickness(self):
1800
        """ symbol thickness reinforcement by using configuration filter drawing dilate size """
1801
        try:
1802
            self.onCommandRejected()
1803
            dialog = QSymbolThicknessDialog(self)
1804
            dialog.exec_()
1805
        except Exception as ex:
1806
            message = 'error occurred({}) in {}:{}'.format(ex, sys.exc_info()[-1].tb_frame.f_code.co_filename,
1807
                                                           sys.exc_info()[-1].tb_lineno)
1808
            self.addMessage.emit(MessageType.Error, message)
1809

    
1810
    def on_help(self):
1811
        """ open help file """
1812
        import os
1813

    
1814
        try:
1815
            help_file_path = os.path.join(os.path.dirname(os.path.realpath(__file__)), 'ID2 User Manual.pdf')
1816
            if os.path.exists(help_file_path):
1817
                os.startfile(f"\"{help_file_path}\"")
1818
            else:
1819
                QMessageBox.warning(self, self.tr('Warning'), self.tr('There is no help file'))
1820
        except Exception as ex:
1821
            message = f"error occurred({repr(ex)}) in {sys.exc_info()[-1].tb_frame.f_code.co_filename}:" \
1822
                      f"{sys.exc_info()[-1].tb_lineno}"
1823
            self.addMessage.emit(MessageType.Error, message)
1824

    
1825
    def on_readme(self):
1826
        """open readme.html"""
1827

    
1828
        file_path = os.path.join(os.path.dirname(os.path.realpath(__file__)), 'readme.html')
1829
        if os.path.exists(file_path):
1830
            os.startfile(f"\"{file_path}\"")
1831
        else:
1832
            QMessageBox.warning(self, self.tr('Warning'), self.tr('There is no readme file'))
1833

    
1834
    def onSelectionChanged(self):
1835
        """selection changed"""
1836
        items = [item for item in self.graphicsView.scene().selectedItems() if issubclass(type(item), SymbolSvgItem) or
1837
                 type(item) is QEngineeringLineItem or issubclass(type(item), QEngineeringTextItem) or
1838
                 type(item) is QEngineeringUnknownItem or type(item) is QEngineeringVendorItem]
1839
        if items:
1840
            lineNos = [item for item in items if type(item) is QEngineeringLineNoTextItem]
1841
            item = items[-1] if not lineNos else lineNos[0]
1842
            self.itemTreeWidget.findItem(item)
1843
            self.resultPropertyTableWidget.show_item_property(item)
1844
            if type(item) is QEngineeringErrorItem:
1845
                for index in range(self.tableWidgetInconsistency.rowCount()):
1846
                    if self.tableWidgetInconsistency.item(index, 1).tag is item:
1847
                        self.tableWidgetInconsistency.selectRow(index)
1848
                        break
1849
            if issubclass(type(item), SymbolSvgItem):
1850
                pass
1851
                #self.symbolTreeWidget.select_symbol(item)
1852
        else:
1853
            self.resultPropertyTableWidget.show_item_property(None)
1854

    
1855
    '''
1856
        @brief      Initialize scene and itemTreeWidget
1857
        @author     Jeongwoo
1858
        @date       2018.06.14
1859
        @history    humkyung 2018.08.16 ask to delete recognized items before remove
1860
    '''
1861
    def on_initialize_scene(self, action):
1862
        if not self.graphicsView.hasImage():
1863
            self.showImageSelectionMessageBox()
1864

    
1865
            return
1866

    
1867
        try:
1868
            msg = QMessageBox()
1869
            msg.setIcon(QMessageBox.Critical)
1870
            msg.setText(self.tr('Do you want to remove all items?\nThis work cannot be recovered.'))
1871
            msg.setWindowTitle(self.tr("Initialize"))
1872
            msg.setStandardButtons(QMessageBox.Ok | QMessageBox.Cancel)
1873
            if QMessageBox.Ok == msg.exec_():
1874
                app_doc_data = AppDocData.instance()
1875
                app_doc_data.clearItemList(True)
1876

    
1877
                scene = self.graphicsView.scene()
1878
                pixmap = self.graphicsView.getPixmapHandle()
1879
                scene.removeItem(pixmap)    # disconnect pixmap from scene
1880
                scene.clear()               # remove all items from scene and then delete them
1881
                scene.addItem(pixmap)       # add pixmap
1882

    
1883
                if self.path is not None:
1884
                    baseName = os.path.basename(self.path)
1885
                    self.itemTreeWidget.setCurrentPID(baseName)
1886

    
1887
        except Exception as ex:
1888
            message = 'error occurred({}) in {}:{}'.format(ex, sys.exc_info()[-1].tb_frame.f_code.co_filename,
1889
                                                           sys.exc_info()[-1].tb_lineno)
1890
            self.addMessage.emit(MessageType.Error, message)
1891

    
1892
    def checked_action(self):
1893
        """return checked action"""
1894
        home_file_pane = self.ribbon.get_pane('Home File')
1895
        home_pane = self.ribbon.get_pane('Home')
1896
        visualization_pane = self.ribbon.get_pane('Home Visualization')
1897
        actions = [home_pane.ui.toolButtonRecognition, home_pane.ui.toolButtonLinkAttribute,
1898
                   home_pane.ui.toolButtonLine, home_pane.ui.toolButtonOCR, visualization_pane.ui.toolButtonZoom,
1899
                   visualization_pane.ui.toolButtonFitWindow, home_pane.ui.toolButtonVendor]
1900

    
1901
        checked = [ui_ for ui_ in actions if ui_.isChecked()]
1902
        return checked[0] if checked else None
1903

    
1904
    def update_action_group(self, ui):
1905
        """Manage Checkable Action statement"""
1906
        home_file_pane = self.ribbon.get_pane('Home File')
1907
        home_pane = self.ribbon.get_pane('Home')
1908
        visualization_pane = self.ribbon.get_pane('Home Visualization')
1909
        actions = [home_pane.ui.toolButtonRecognition, home_pane.ui.toolButtonLinkAttribute, home_pane.ui.toolButtonLine,
1910
                   home_pane.ui.toolButtonOCR, visualization_pane.ui.toolButtonZoom,
1911
                   visualization_pane.ui.toolButtonFitWindow, home_file_pane.ui.toolButtonFileSave,
1912
                   home_pane.ui.toolButtonValidate, home_pane.ui.toolButtonVendor]
1913

    
1914
        if hasattr(ui, 'tag'):
1915
            ui.tag.onRejected.emit(None)
1916

    
1917
        if self.graphicsView.command is not None:
1918
            self.graphicsView.useDefaultCommand()
1919

    
1920
        for ui_ in actions:
1921
            ui_.setChecked(False)
1922

    
1923
        ui.setChecked(True)
1924

    
1925
    '''
1926
        @brief      Create Equipment
1927
        @author     Jeongwoo
1928
        @date       18.05.03
1929
        @history    2018.05.04  Jeongwoo    Add Parameter on CreateSymbolCommand
1930
    '''
1931
    def createEquipment(self):
1932
        if not self.graphicsView.hasImage():
1933
            self.actionEquipment.setChecked(False)
1934
            self.showImageSelectionMessageBox()
1935
            return
1936
        if self.actionEquipment.isChecked():
1937
            self.graphicsView.command = CreateSymbolCommand.CreateSymbolCommand(self.graphicsView, self.itemTreeWidget,
1938
                                                                                self.symbolTreeWidget)
1939
        else:
1940
            self.graphicsView.useDefaultCommand()
1941

    
1942
    '''
1943
        @brief      Create Nozzle
1944
        @author     Jeongwoo
1945
        @date       2018.05.03
1946
        @history    2018.05.04  Jeongwoo    Add Parameter on CreateSymbolCommand
1947
    '''
1948
    def createNozzle(self):
1949
        if not self.graphicsView.hasImage():
1950
            self.actionNozzle.setChecked(False)
1951
            self.showImageSelectionMessageBox()
1952
            return
1953
        if self.actionNozzle.isChecked():
1954
            self.graphicsView.command = CreateSymbolCommand.CreateSymbolCommand(self.graphicsView, self.itemTreeWidget,
1955
                                                                                self.symbolTreeWidget)
1956
        else:
1957
            self.graphicsView.useDefaultCommand()
1958

    
1959
    def onAreaOcr(self):
1960
        """Area OCR"""
1961
        if not self.graphicsView.hasImage():
1962
            self.actionOCR.setChecked(False)
1963
            self.showImageSelectionMessageBox()
1964
            return
1965

    
1966
        pane = self.ribbon.get_pane('Home')
1967
        ui = pane.ui.toolButtonOCR
1968
        self.update_action_group(ui=ui)
1969
        checked = ui.isChecked()
1970
        if checked:
1971
            cmd = AreaOcrCommand.AreaOcrCommand(self.graphicsView)
1972
            cmd.onSuccess.connect(self.onRecognizeText)
1973
            cmd.onRejected.connect(self.onCommandRejected)
1974
            self.graphicsView.command = cmd
1975
        else:
1976
            self.graphicsView.useDefaultCommand()
1977

    
1978
    def onRecognizeText(self, x, y, width, height, show=True):
1979
        """show text recognition dialog"""
1980
        from OcrResultDialog import QOcrResultDialog
1981
        from Area import Area
1982

    
1983
        try:
1984
            app_doc_data = AppDocData.instance()
1985

    
1986
            modifiers = QApplication.keyboardModifiers()
1987
            image = self.graphicsView.image().copy(x, y, width, height)
1988
            dialog = QOcrResultDialog(self, image, QRectF(x, y, width, height),
1989
                                      format=QOcrResultDialog.Format.Table if modifiers == Qt.AltModifier else QOcrResultDialog.Format.Normal)
1990
            if modifiers == Qt.ControlModifier:
1991
                return
1992
            
1993
            if show:
1994
                (res, textInfoList) = dialog.showDialog()
1995
            else:
1996
                dialog.accept(show=False)
1997
                (res, textInfoList) = QDialog.Accepted, dialog.textInfoList
1998

    
1999
            if QDialog.Accepted == res and textInfoList:
2000
                for textInfo in textInfoList:
2001
                    item = QEngineeringTextItem.create_text_with(self.graphicsView.scene(), textInfo)
2002
                    if item:
2003
                        #item.setDefaultTextColor(Qt.blue)
2004
                        item.transfer.onRemoved.connect(self.itemRemoved)
2005

    
2006
                        area_list = app_doc_data.getAreaList()
2007
                        title_area_list = app_doc_data.getTitleBlockProperties()
2008
                        title_list = []
2009
                        if title_area_list:
2010
                            for title_area in title_area_list:
2011
                                area = Area(title_area[0])
2012
                                area.parse(title_area[2])
2013
                                title_list.append(area)
2014
                        for area in area_list + title_list:
2015
                            pt = [item.sceneBoundingRect().center().x(), item.sceneBoundingRect().center().y()]
2016
                            if area.contains(pt):
2017
                                item.area = area.name
2018
                                break
2019
                    else:
2020
                        self.addMessage.emit(MessageType.Normal, self.tr('Fail to create text.'))
2021

    
2022
                return True
2023
            elif QDialog.Accepted == res and not textInfoList and show:
2024
                QMessageBox.about(self.graphicsView, self.tr("Notice"), self.tr("Fail to recognize text"))
2025
        except Exception as ex:
2026
            message = 'error occurred({}) in {}:{}'.format(ex, sys.exc_info()[-1].tb_frame.f_code.co_filename,
2027
                                                           sys.exc_info()[-1].tb_lineno)
2028
            self.addMessage.emit(MessageType.Error, message)
2029
        
2030
        return False
2031

    
2032
    '''
2033
        @brief  area configuration
2034
    '''
2035
    def areaConfiguration(self):
2036
        from ConfigurationAreaDialog import QConfigurationAreaDialog
2037
        if not self.graphicsView.hasImage():
2038
            self.showImageSelectionMessageBox()
2039
            return
2040
        self.onCommandRejected()
2041
        dlgConfigurationArea = QConfigurationAreaDialog(self)
2042
        dlgConfigurationArea.show()
2043
        dlgConfigurationArea.exec_()
2044

    
2045
    '''
2046
        @brief  configuration
2047
    '''
2048
    def configuration(self):
2049
        from ConfigurationDialog import QConfigurationDialog
2050

    
2051
        dlgConfiguration = QConfigurationDialog(self)
2052
        if QDialog.Accepted == dlgConfiguration.exec_():
2053
            QEngineeringLineItem.LINE_TYPE_COLORS.clear()
2054
            QEngineeringInstrumentItem.INST_COLOR = None
2055

    
2056
    '''
2057
        @brief  show special item types dialog 
2058
        @author humkyung
2059
        @date   2019.08.10
2060
    '''
2061
    def on_show_special_item_types(self):
2062
        from SpecialItemTypesDialog import QSpecialItemTypesDialog
2063

    
2064
        dlg = QSpecialItemTypesDialog(self)
2065
        dlg.exec_()
2066

    
2067
    def on_show_data_transfer(self):
2068
        """ show data transfer dialog """
2069
        from DataTransferDialog import QDataTransferDialog
2070

    
2071
        dlg = QDataTransferDialog(self)
2072
        dlg.exec_()
2073

    
2074
    def on_show_data_export(self):
2075
        """ show data export dialog """
2076
        from DataExportDialog import QDataExportDialog
2077

    
2078
        dlg = QDataExportDialog(self)
2079
        dlg.exec_()
2080

    
2081
    def on_show_eqp_datasheet_export(self):
2082
        """ show eqp datasheet export dialog """
2083
        from EqpDatasheetExportDialog import QEqpDatasheetExportDialog
2084

    
2085
        dlg = QEqpDatasheetExportDialog(self)
2086
        dlg.exec_()
2087

    
2088
    def on_show_opc_relation(self):
2089
        """ show opc relation dialog """
2090
        from OPCRelationDialog import QOPCRelationDialog
2091

    
2092
        dlg = QOPCRelationDialog(self)
2093
        dlg.exec_()
2094

    
2095
    '''
2096
        @brief  show nominal diameter dialog 
2097
        @author humkyung
2098
        @date   2018.06.28
2099
    '''
2100
    def onShowCodeTable(self):
2101
        from CodeTableDialog import QCodeTableDialog
2102

    
2103
        dlg = QCodeTableDialog(self)
2104
        dlg.show()
2105
        dlg.exec_()
2106
        if dlg.code_area:
2107
            if dlg.code_area.scene():
2108
                self.graphicsView.scene().removeItem(dlg.code_area)
2109
        if dlg.desc_area:
2110
            if dlg.desc_area.scene():
2111
                self.graphicsView.scene().removeItem(dlg.desc_area)
2112
        self.graphicsView.useDefaultCommand()
2113

    
2114
    def on_ext_app_connection(self):
2115
        app_doc_data = AppDocData.instance()
2116

    
2117
        tool_pane = self.ribbon.get_pane('Tool')
2118
        if tool_pane.ui.toolButtonConnection.isChecked():
2119
            if not hasattr(self, '_tcpserver'):
2120
                configs = app_doc_data.getAppConfigs('app', 'port')
2121
                port = 2549
2122
                if configs and 1 == len(configs):
2123
                    port = int(configs[0].value)
2124
                self._tcpserver = TcpServer(port)
2125
                self._tcpserver.sessionOpened()
2126
        else:
2127
            self._tcpserver.sessionClosed()
2128
            del self._tcpserver
2129

    
2130
    def on_execute_ext_app(self):
2131
        """execute external application"""
2132
        from ExtAppsDialog import QExtAppsDialog
2133

    
2134
        dlg = QExtAppsDialog(self)
2135
        dlg.exec_()
2136

    
2137
    def on_show_project_info(self):
2138
        from ProjectInfoDialog import QProjectInfoDialog
2139

    
2140
        dlg = QProjectInfoDialog(self)
2141
        dlg.show()
2142
        dlg.exec_()
2143
        self.graphicsView.useDefaultCommand()
2144

    
2145
    def onShowCustomCodeTable(self):
2146
        from CustomCodeTablesDialog import CustomCodeTablesDialog
2147

    
2148
        dlg = CustomCodeTablesDialog(self)
2149
        dlg.show()
2150
        dlg.exec_()
2151
        self.graphicsView.useDefaultCommand()
2152

    
2153
    def onShowReplaceCodeTable(self):
2154
        from CustomCodeTablesDialog import CustomCodeTablesDialog
2155

    
2156
        dlg = CustomCodeTablesDialog(self, replace=True)
2157
        dlg.show()
2158
        dlg.exec_()
2159
        self.graphicsView.useDefaultCommand()
2160

    
2161
    def on_streamline(self):
2162
        """pop up stream line dialog"""
2163
        from StreamlineDialog import QStreamlineDialog
2164

    
2165
        if not self.graphicsView.hasImage():
2166
            self.showImageSelectionMessageBox()
2167
            return
2168

    
2169
        hmbs = AppDocData.instance().get_hmb_data(None)
2170
        if not hmbs:
2171
            return
2172

    
2173
        dlg = QStreamlineDialog(self)
2174
        dlg.show()
2175

    
2176
    def onHMBData(self):
2177
        """show HMB data"""
2178
        from HMBDialog import QHMBDialog
2179

    
2180
        dlg = QHMBDialog(self)
2181
        dlg.show()
2182
        dlg.exec_()
2183

    
2184
    '''
2185
        @brief  show line data list 
2186
        @author humkyung
2187
        @date   2018.05.03
2188
    '''
2189
    def showItemDataList(self):
2190
        from ItemDataExportDialog import QItemDataExportDialog
2191

    
2192
        dlg = QItemDataExportDialog(self)
2193
        dlg.exec_()
2194

    
2195
    def showTextDataList(self):
2196
        '''
2197
            @brief      show all text item in scene
2198
            @author     euisung
2199
            @date       2019.04.18
2200
        '''
2201
        try:
2202
            if not self.graphicsView.hasImage():
2203
                self.showImageSelectionMessageBox()
2204
                return
2205

    
2206
            self.onCommandRejected()
2207
            dialog = QTextDataListDialog(self)
2208
            dialog.show()
2209
        except Exception as ex:
2210
            message = 'error occurred({}) in {}:{}'.format(ex, sys.exc_info()[-1].tb_frame.f_code.co_filename,
2211
                                                           sys.exc_info()[-1].tb_lineno)
2212
            self.addMessage.emit(MessageType.Error, message)
2213

    
2214
    '''
2215
        @brief  Show Image Selection Guide MessageBox
2216
        @author Jeongwoo
2217
        @date   2018.05.02
2218
    '''
2219
    def showImageSelectionMessageBox(self):
2220
        QMessageBox.about(self.graphicsView, self.tr("Notice"), self.tr("First Select Drawing"))
2221

    
2222
    def on_drawing_filter_changed(self):
2223
        """filter drawing tree view"""
2224
        regexp = QRegExp(self.drawingFilter.text(), Qt.CaseInsensitive, QRegExp.FixedString)
2225

    
2226
        self.treeWidgetDrawingList.set_filter_regexp(regexp)
2227

    
2228
        self.treeWidgetDrawingList.expandAll()
2229

    
2230
    def on_search_text_changed(self):
2231
        """filter symbol tree view"""
2232
        regexp = QRegExp(self.lineEditFilter.text(), Qt.CaseInsensitive, QRegExp.FixedString)
2233

    
2234
        proxy_model = self.symbolTreeWidget.model()
2235
        proxy_model.text = self.lineEditFilter.text().lower()
2236
        proxy_model.setFilterRegExp(regexp)
2237

    
2238
        self.symbolTreeWidget.expandAll()
2239

    
2240
    def change_display_colors(self):
2241
        """ change display color mode """
2242
        visualization_pane = self.ribbon.get_pane('Home Visualization')
2243
        if visualization_pane.ui.radioButtonByGroup.isChecked():
2244
            visualization_pane.ui.radioButtonByType.setChecked(True)
2245
        else:
2246
            visualization_pane.ui.radioButtonByGroup.setChecked(True)
2247

    
2248
    def display_colors(self, value):
2249
        """ display colors """
2250
        from DisplayColors import DisplayColors, DisplayOptions
2251

    
2252
        if hasattr(self, 'ribbon'):
2253
            visualization_pane = self.ribbon.get_pane('Home Visualization')
2254
            if self.sender() is visualization_pane.ui.radioButtonByGroup and value is True:
2255
                DisplayColors.instance().option = DisplayOptions.DisplayByLineNo
2256
            elif self.sender() is visualization_pane.ui.radioButtonByType and value is True:
2257
                DisplayColors.instance().option = DisplayOptions.DisplayByLineType
2258
            elif self.sender() is visualization_pane.ui.radioButtonByStreamNo and value is True:
2259
                DisplayColors.instance().option = DisplayOptions.DisplayByStreamNo
2260

    
2261
            if hasattr(self, 'graphicsView') and value is True:
2262
                self.graphicsView.scene().update(self.graphicsView.sceneRect())
2263
                for item in self.graphicsView.scene().items():
2264
                    if issubclass(type(item), SymbolSvgItem):
2265
                        item.update()
2266
                DisplayColors.instance().save_data()
2267

    
2268
    def open_image_drawing(self, drawing, force=False, ocrUnknown=False, timer=True, pdf=False):
2269
        """open and display image drawing file"""
2270
        from Drawing import Drawing
2271
        from App import App
2272
        from LoadCommand import LoadCommand
2273
        import concurrent.futures as futures
2274

    
2275
        # Yield successive n-sized
2276
        # chunks from l.
2277
        def divide_chunks(l, n):
2278
            # looping till length l
2279
            for i in range(0, len(l), n):
2280
                yield l[i:i + n]
2281

    
2282
        def update_items(items):
2283
            for item in items:
2284
                # binding items
2285
                item.owner
2286
                for connector in item.connectors:
2287
                    connector.connectedItem
2288

    
2289
            return items
2290

    
2291
        try:
2292
            app_doc_data = AppDocData.instance()
2293

    
2294
            if not self.actionSave.isEnabled():
2295
                return
2296

    
2297
            if not force and self.save_drawing_if_necessary():
2298
                return
2299

    
2300
            if not force:
2301
                occupied = app_doc_data.set_occupying_drawing(drawing.UID)
2302
                if occupied:
2303
                    #QMessageBox.about(self.graphicsView, self.tr("Notice"),
2304
                    #                  self.tr(f"The drawing is locked for editing by another user({occupied})"))
2305
                    reply = QMessageBox.question(self, self.tr('Warning'),
2306
                                     self.tr(f"The drawing is locked for editing by another user({occupied}).\nDo you want to open as read-only?"),
2307
                                     QMessageBox.Yes, QMessageBox.No)
2308
                    if reply == QMessageBox.Yes:
2309
                        app_doc_data.readOnly = True
2310
                    else:
2311
                        return
2312
                else:
2313
                    app_doc_data.readOnly = False
2314

    
2315
            # save alarm
2316
            if timer:
2317
                self.save_alarm_enable(False)
2318

    
2319
            if hasattr(self, '_save_work_cmd'):
2320
                self._save_work_cmd.wait()
2321

    
2322
            project = app_doc_data.getCurrentProject()
2323

    
2324
            self.path = self.graphicsView.loadImageFromFile(drawing)
2325
            if os.path.isfile(self.path):
2326
                self.onCommandRejected()
2327
                app_doc_data.clear(past=drawing.UID)
2328

    
2329
                # load color for stream no coloring
2330
                configs = app_doc_data.getConfigs('Line List', 'Use Stream No')
2331
                if configs and int(configs[0].value) == 1:
2332
                    hmbs = app_doc_data.get_hmb_data(None)
2333
                    colors = {}
2334
                    if hmbs:
2335
                        for hmb in hmbs:
2336
                            rgb = app_doc_data.colors
2337
                            colors[hmb.stream_no] = QColor(rgb.red, rgb.green, rgb.blue).name()
2338
                        app_doc_data._hmbColors = colors
2339
                # up to here
2340

    
2341
                app_doc_data.setImgFilePath(self.path)
2342
                app_doc_data.activeDrawing = drawing
2343
                
2344
                #app_doc_data.activeDrawing.set_pid_source(Image.open(self.path))
2345
                self.itemTreeWidget.setCurrentPID(app_doc_data.activeDrawing.name)
2346

    
2347
                drawingList = self.treeWidgetDrawingList.topLevelItem(0)
2348
                for idx in range(drawingList.childCount()):
2349
                    child = drawingList.child(idx)
2350
                    if child.data(Qt.UserRole, 0) is drawing:
2351
                        child.setCheckState(0, Qt.Checked)
2352
                    else:
2353
                        child.setCheckState(0, Qt.Unchecked)
2354

    
2355
                try:
2356
                    self.show_Progress_bar()
2357

    
2358
                    # disconnect scene changed if signal is connected
2359
                    if self.graphicsView.scene().receivers(self.graphicsView.scene().contents_changed) > 0:
2360
                        self.graphicsView.scene().contents_changed.disconnect()
2361

    
2362
                    SymbolSvgItem.DOCUMENTS.clear()
2363

    
2364
                    # load data
2365
                    cmd = LoadCommand()
2366
                    cmd.display_message.connect(self.onAddMessage)
2367
                    cmd.set_maximum.connect(self.progress.setMaximum)
2368
                    cmd.show_progress.connect(self.progress.setValue)
2369
                    cmd.execute((drawing, self.graphicsView.scene()),
2370
                                symbol=True, text=True, line=True, unknown=True, package=True, update=not pdf)
2371

    
2372
                    configs = app_doc_data.getConfigs('Line List', 'Use Stream No')
2373
                    if configs and int(configs[0].value) == 1:
2374
                        app_doc_data._streamLineListModelDatas = app_doc_data.get_stream_line_list_data()
2375
                    # up to here
2376

    
2377
                    """update item tree widget"""
2378
                    line_no_items = [item for item in self.graphicsView.scene().items()
2379
                                     if type(item) is QEngineeringLineNoTextItem]
2380
                    
2381
                    # line No sort
2382
                    #line_no_items.sort(key=lambda x: int(x.getAttributes(True)[[_key for _key in x.getAttributes(True).keys() if _key.Attribute == 'Tag Seq No'][0]]) if (x.getAttributes(True) and [_key for _key in x.getAttributes(True).keys() if _key.Attribute == 'Tag Seq No']) else -1)
2383
                    line_no_pairs = []
2384
                    line_no_texts = []
2385
                    for line_no in line_no_items:
2386
                        text = line_no.sort_order_text()
2387
                        line_no_pairs.append([line_no, text])
2388
                        line_no_texts.append(text)
2389
                    
2390
                    line_no_texts = app_doc_data.winsort(list(set(line_no_texts)))
2391

    
2392
                    for line_no_text in line_no_texts:
2393
                        for line_no_pair in [line_no_pair for line_no_pair in line_no_pairs if line_no_pair[1] == line_no_text]:
2394
                            line_no_items.remove(line_no_pair[0])
2395
                            line_no_items.insert(-1, line_no_pair[0])
2396
                    # up to here
2397

    
2398
                    for line_no in line_no_items:
2399
                        line_no_tree_item = self.itemTreeWidget.addTreeItem(self.itemTreeWidget.root, line_no)
2400
                        for run in line_no.runs:
2401
                            for run_item in run.items:
2402
                                if issubclass(type(run_item), SymbolSvgItem):
2403
                                    self.init_add_tree_item(line_no_tree_item, run_item)
2404

    
2405
                    line_no_items = [item for item in self.graphicsView.scene().items()
2406
                                     if type(item) is QEngineeringTrimLineNoTextItem]
2407
                    for line_no in line_no_items:
2408
                        line_no_tree_item = self.itemTreeWidget.addTreeItem(self.itemTreeWidget.root, line_no)
2409
                        for run in line_no.runs:
2410
                            for run_item in run.items:
2411
                                if issubclass(type(run_item), SymbolSvgItem):
2412
                                    self.init_add_tree_item(line_no_tree_item, run_item)
2413

    
2414
                    for trim_line_no in app_doc_data.tracerLineNos:
2415
                        line_no_tree_item = self.itemTreeWidget.addTreeItem(self.itemTreeWidget.root, trim_line_no)
2416
                        for run in trim_line_no.runs:
2417
                            for run_item in run.items:
2418
                                if issubclass(type(run_item), SymbolSvgItem):
2419
                                    self.init_add_tree_item(line_no_tree_item, run_item)
2420

    
2421
                    self.itemTreeWidget.update_item_count()
2422
                    self.itemTreeWidget.expandAll()
2423
                    """up to here"""
2424

    
2425
                    """update scene"""
2426
                    for item in self._scene.items():
2427
                        item.setVisible(True)
2428

    
2429
                    self._scene.update(self._scene.sceneRect())
2430

    
2431
                    """
2432
                    # old open drawing
2433
                    path = os.path.join(app_doc_data.getCurrentProject().getTempPath(), app_doc_data.imgName + '.xml')
2434
                    configs = app_doc_data.getConfigs('Data Load', 'Xml First')
2435
                    if configs and int(configs[0].value) >= 1 and os.path.isfile(path):
2436
                        self.load_recognition_result_from_xml(drawing)
2437
                    elif configs and int(configs[0].value) <= 1:
2438
                        self.load_drawing(app_doc_data.activeDrawing)
2439
                    """
2440

    
2441
                    self.display_number_of_items()
2442
                    # connect scene changed signal
2443
                    self.graphicsView.scene().contents_changed.connect(self.scene_changed)
2444
                finally:
2445
                    if hasattr(self, 'progress'):
2446
                        self.progress.setValue(self.progress.maximum())
2447

    
2448
                self.changeViewCheckedState(None)
2449
                self.updateAsViewCheckedState()
2450
                self.setWindowTitle(self.title)
2451
                if not pdf:
2452
                    self.fitWindow(drawing.view_rect)
2453

    
2454
                if ocrUnknown:
2455
                    self.on_ocr_unknown_items()
2456

    
2457
                # save alarm
2458
                if timer and not app_doc_data.readOnly:
2459
                    self.save_alarm_enable(True, True)
2460
        except Exception as ex:
2461
            message = f"error occurred({repr(ex)}) in {sys.exc_info()[-1].tb_frame.f_code.co_filename}:" \
2462
                      f"{sys.exc_info()[-1].tb_lineno}"
2463
            self.addMessage.emit(MessageType.Error, message)
2464

    
2465
        return self.path
2466

    
2467
    def save_alarm_enable(self, enable, init=False):
2468
        from datetime import datetime
2469

    
2470
        try:
2471
            app_doc_data = AppDocData.instance()
2472
            configs = app_doc_data.getConfigs('Data Save', 'Time')
2473
            time_min = int(configs[0].value) if 1 == len(configs) else 0
2474

    
2475
            if enable and time_min > 0:
2476
                if not self.save_timer:
2477
                    self.save_timer = QTimer()
2478
                    self.save_timer.timeout.connect(self.save_alarm)
2479
                    self.save_timer.setInterval(60000)
2480

    
2481
                if init:
2482
                    self.save_timer._init_time = datetime.now()
2483
                    self.save_timer._stop_time = None
2484
                    self.save_timer._interval_time = datetime.now() - datetime.now()
2485

    
2486
                if self.save_timer._stop_time:
2487
                    self.save_timer._interval_time = datetime.now() - self.save_timer._stop_time
2488
                
2489
                #if 60000 * time_min != self.save_timer.interval():
2490
                #    self.save_timer.setInterval(60000)
2491

    
2492
                self.save_timer.start()
2493
            else:
2494
                if self.save_timer:
2495
                    self.save_timer.stop()
2496
                    self.save_timer._stop_time = datetime.now()
2497
        
2498
        except Exception as ex:
2499
            message = f"error occurred({repr(ex)}) in {sys.exc_info()[-1].tb_frame.f_code.co_filename}:" \
2500
                      f"{sys.exc_info()[-1].tb_lineno}"
2501
            self.addMessage.emit(MessageType.Error, message)
2502

    
2503
    def save_alarm(self):
2504
        from datetime import datetime
2505

    
2506
        app_doc_data = AppDocData.instance()
2507
        configs = app_doc_data.getConfigs('Data Save', 'Time')
2508
        time_min = int(configs[0].value) if 1 == len(configs) else 0
2509

    
2510
        self.save_timer.stop()
2511
        if self.graphicsView.hasFocus() and (datetime.now() - self.save_timer._init_time - self.save_timer._interval_time).seconds > time_min * 60:
2512
            QMessageBox.information(self, self.tr('Information'), self.tr('Please save Drawing'))
2513
            self.save_timer._init_time = datetime.now()
2514
            self.save_timer._interval_time = datetime.now() - datetime.now()
2515
        self.save_timer.start()
2516

    
2517
    def export_as_svg(self):
2518
        """export scene to svg file"""
2519
        from ExportCommand import ExportCommand
2520

    
2521
        options = QFileDialog.Options()
2522
        options |= QFileDialog.DontUseNativeDialog
2523
        file_path, _ = QFileDialog.getSaveFileName(self, "Export as svg", os.getcwd(), "svg file(*.svg)",
2524
                                                   options=options)
2525
        if file_path:
2526
            cmd = ExportCommand(self.graphicsView.scene(), 'svg')
2527
            cmd.display_message.connect(self.onAddMessage)
2528
            if cmd.execute(file_path):
2529
                QMessageBox.information(self, self.tr('Information'), self.tr('Successfully export to svg file'))
2530
            else:
2531
                QMessageBox.information(self, self.tr('Error'), self.tr('Fail to export to svg file'))
2532

    
2533
    def export_as_xml(self):
2534
        pass
2535

    
2536
    def export_as_image(self):
2537
        """export scene to image file"""
2538
        from ExportCommand import ExportCommand
2539

    
2540
        options = QFileDialog.Options()
2541
        options |= QFileDialog.DontUseNativeDialog
2542
        file_path, _ = QFileDialog.getSaveFileName(self, "Export as png", os.getcwd(), "png file(*.png)",
2543
                                                   options=options)
2544
        if file_path:
2545
            try:
2546
                # hide image drawing
2547
                self.onViewImageDrawing(False)
2548

    
2549
                cmd = ExportCommand(self.graphicsView.scene(), 'image')
2550
                cmd.display_message.connect(self.onAddMessage)
2551

    
2552
                if cmd.execute(file_path):
2553
                    QMessageBox.information(self, self.tr('Information'), self.tr('Successfully export to image file'))
2554
                else:
2555
                    QMessageBox.information(self, self.tr('Error'), self.tr('Fail to export to image file'))
2556
            finally:
2557
                if self.actionImage_Drawing.isChecked():
2558
                    self.onViewImageDrawing(True)
2559
                    self.actionImage_Drawing.setChecked(True)
2560

    
2561
    def show_Progress_bar(self):
2562
        """ show progress bar """
2563
        self.progress = QProgressDialog(self.tr("Please wait for a while"), self.tr("Cancel"), 0, 100,
2564
                                        self) if not hasattr(self, 'progress') else self.progress
2565
        self.progress.setWindowModality(Qt.WindowModal)
2566
        self.progress.setAutoReset(True)
2567
        self.progress.setAutoClose(True)
2568
        self.progress.setMinimum(0)
2569
        self.progress.setMaximum(100)
2570
        self.progress.resize(600, 100)
2571
        self.progress.setWindowTitle(self.tr("Reading file..."))
2572
        self.progress.show()
2573

    
2574
    def changeViewCheckedState(self, checked, clear=True):
2575
        """change view checked state"""
2576
        # self.actionImage_Drawing.setChecked(checked)
2577
        
2578
        '''
2579
        self.actionViewText.setChecked(checked)
2580
        self.actionViewSymbol.setChecked(checked)
2581
        self.actionViewLine.setChecked(checked)
2582
        self.actionViewUnknown.setChecked(checked)
2583
        self.actionViewInconsistency.setChecked(checked)
2584
        self.actionViewVendor_Area.setChecked(not checked)
2585
        self.actionDrawing_Only.setChecked(not checked)
2586
        '''
2587

    
2588
        if checked is not None:
2589
            view_pane = self.ribbon.get_pane('View')
2590
            view_pane.ui.toolButtonViewText.setChecked(checked)
2591
            view_pane.ui.toolButtonViewSymbol.setChecked(checked)
2592
            view_pane.ui.toolButtonViewLine.setChecked(checked)
2593
            view_pane.ui.toolButtonViewUnknown.setChecked(checked)
2594
            view_pane.ui.toolButtonViewInconsistency.setChecked(checked)
2595
            view_pane.ui.toolButtonViewVendorArea.setChecked(checked)
2596
            view_pane.ui.toolButtonViewDrawingOnly.setChecked(not checked)
2597

    
2598
        if clear:
2599
            self.tableWidgetInconsistency.clearContents()
2600
            self.tableWidgetInconsistency.setRowCount(0)
2601

    
2602
    def updateAsViewCheckedState(self):
2603
        view_pane = self.ribbon.get_pane('View')
2604
        self.onViewImageDrawing(view_pane.ui.toolButtonViewImageDrawing.isChecked())
2605
        self.onViewText(view_pane.ui.toolButtonViewText.isChecked())
2606
        self.onViewSymbol(view_pane.ui.toolButtonViewSymbol.isChecked())
2607
        self.onViewLine(view_pane.ui.toolButtonViewLine.isChecked())
2608
        self.onViewUnknown(view_pane.ui.toolButtonViewUnknown.isChecked())
2609
        self.onViewInconsistency(view_pane.ui.toolButtonViewInconsistency.isChecked())
2610
        self.onViewVendorArea(view_pane.ui.toolButtonViewVendorArea.isChecked())
2611
        #self.onViewDrawingOnly(view_pane.ui.toolButtonViewDrawingOnly.isChecked())
2612

    
2613
    def onViewDrawingOnly(self, isChecked):
2614
        '''
2615
            @brief  visible/invisible except image drawing
2616
            @author euisung
2617
            @date   2019.04.22
2618
        '''
2619
        self.changeViewCheckedState(not isChecked, False)
2620
        for item in self.graphicsView.scene().items():
2621
            if type(item) is not QGraphicsPixmapItem and issubclass(type(item), QEngineeringAbstractItem):
2622
                item.setVisible(not isChecked)
2623

    
2624
    '''
2625
        @brief  visible/invisible image drawing
2626
        @author humkyung
2627
        @date   2018.06.25
2628
    '''
2629
    def onViewImageDrawing(self, isChecked):
2630
        for item in self.graphicsView.scene().items():
2631
            if type(item) is QGraphicsPixmapItem:
2632
                item.setVisible(isChecked)
2633
                break
2634

    
2635
    def onViewText(self, checked):
2636
        """visible/invisible text"""
2637
        selected = [item for item in self.graphicsView.scene().items() if issubclass(type(item), QEngineeringTextItem)]
2638
        for item in selected:
2639
            item.setVisible(checked)
2640

    
2641
    def onViewSymbol(self, checked):
2642
        """visible/invisible symbol"""
2643
        selected = [item for item in self.graphicsView.scene().items() if issubclass(type(item), SymbolSvgItem)]
2644
        for item in selected:
2645
            item.setVisible(checked)
2646

    
2647
    def onViewLine(self, checked):
2648
        """visible/invisible line"""
2649
        '''
2650
        view_pane = self.ribbon.get_pane('View')
2651
        line_type = view_pane.ui.comboBoxLineType.currentText()
2652
        if line_type == 'All':
2653
            selected = [item for item in self.graphicsView.scene().items() if type(item) is QEngineeringLineItem]
2654
        else:
2655
            selected = [item for item in self.graphicsView.scene().items() if type(item) is QEngineeringLineItem and item.lineType == line_type]
2656
        '''
2657
        selected = [item for item in self.graphicsView.scene().items() if type(item) is QEngineeringLineItem]
2658
        for item in selected:
2659
            item.setVisible(checked)
2660

    
2661
    def onViewInconsistency(self, isChecked):
2662
        '''
2663
            @brief  visible/invisible Inconsistency
2664
            @author euisung
2665
            @date   2019.04.03
2666
        '''
2667
        selected = [item for item in self.graphicsView.scene().items() if type(item) is QEngineeringErrorItem]
2668
        for item in selected:
2669
            item.setVisible(isChecked)
2670

    
2671
    '''
2672
        @brief  visible/invisible Unknown 
2673
        @author humkyung
2674
        @date   2018.06.28
2675
    '''
2676
    def onViewUnknown(self, isChecked):
2677
        selected = [item for item in self.graphicsView.scene().items() if type(item) is QEngineeringUnknownItem]
2678
        for item in selected:
2679
            item.setVisible(isChecked)
2680

    
2681
    def onViewVendorArea(self, isChecked):
2682
        '''
2683
            @brief  visible/invisible Vendor Area
2684
            @author euisung
2685
            @date   2019.04.29
2686
        '''
2687
        selected = [item for item in self.graphicsView.scene().items() if issubclass(type(item), QEngineeringVendorItem)]
2688
        for item in selected:
2689
            item.setVisible(isChecked)
2690

    
2691
    def onViewLineTypeChanged(self, line_type):
2692
        if line_type != 'All':
2693
            selected = [item for item in self.graphicsView.scene().items() if type(item) is QEngineeringLineItem and item.lineType != line_type]
2694
            for item in selected:
2695
                item.setVisible(False)
2696
            selected = [item for item in self.graphicsView.scene().items() if type(item) is QEngineeringLineItem and item.lineType == line_type]
2697
            for item in selected:
2698
                item.setVisible(True)
2699

    
2700
    '''
2701
        @brief  create a symbol
2702
        @history    2018.05.02  Jeongwoo    Change return value of QSymbolEditorDialog (Single variable → Tuple)
2703
                                            Add SymbolSvgItem
2704
                    2018.05.03  Jeongwoo    Change method to draw Svg Item on Scene (svg.addSvgItemToScene)
2705
                                            Change method to make svg and image path
2706
                    2018.06.08  Jeongwoo    Add Paramter on SymbolSvgItem.buildItem()
2707
    '''
2708
    def onCreateSymbolClicked(self):
2709
        if not self.graphicsView.hasImage():
2710
            self.showImageSelectionMessageBox()
2711
            return
2712

    
2713
        selected = [item for item in self.graphicsView.scene().selectedItems() if issubclass(type(item), QEngineeringVendorItem)]
2714
        if len(selected) == 1:
2715
            symbol_image = AppDocData.instance().activeDrawing.image_origin
2716
            rect = selected[0].sceneBoundingRect()
2717

    
2718
            points = []
2719
            for conn in selected[0].connectors:
2720
                points.append([round(conn.center()[0] - rect.x()), round(conn.center()[1] - rect.y())])
2721
            poly = np.array(points, np.int32)
2722

    
2723
            #mask = np.zeros((int(rect.height()), int(rect.width())))
2724
            #cv2.fillPoly(mask, [poly], (255))
2725
            #poly_copied = np.multiply(mask, symbol_image[round(rect.y()):round(rect.y() + rect.height()),
2726
            #                   round(rect.x()):round(rect.x() + rect.width())])
2727
            #cv2.fillPoly(mask,[poly],0)
2728
            #src2 = np.multiply(mask,src2)
2729

    
2730
            mask = np.ones((int(rect.height()), int(rect.width())), dtype=np.uint8) * 255
2731
            cv2.fillPoly(mask, [poly], (0))
2732
            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())])
2733
            sym_img = cv2.merge((sym_img, sym_img, sym_img))
2734

    
2735
            h, w, c = sym_img.shape
2736
            qImg = QImage(sym_img.data, w, h, w * c, QImage.Format_RGB888)
2737
            #pixmap = QPixmap.fromImage(qImg)
2738

    
2739
            self.onAreaSelected(None, None, None, None, package=qImg, position=rect.topLeft(), package_item=selected[0])
2740
        else:
2741
            cmd = FenceCommand.FenceCommand(self.graphicsView)
2742
            cmd.onSuccess.connect(self.onAreaSelected)
2743
            self.graphicsView.command = cmd
2744
            QApplication.setOverrideCursor(Qt.CrossCursor)
2745

    
2746
    '''
2747
        @brief      show SymbolEditorDialog with image selected by user
2748
        @author     humkyung
2749
        @date       2018.07.20
2750
    '''
2751
    def onAreaSelected(self, x, y, width, height, package=False, position=None, package_item=None):
2752
        try:
2753
            image = self.graphicsView.image()
2754
            if image is not None:
2755
                if not package:
2756
                    symbolEditorDialog = SymbolEditorDialog.QSymbolEditorDialog(self, image.copy(x, y, width, height),
2757
                                                                                AppDocData.instance().getCurrentProject())
2758
                else:
2759
                    symbolEditorDialog = SymbolEditorDialog.QSymbolEditorDialog(self, package,
2760
                                                                                AppDocData.instance().getCurrentProject(), package=True)
2761
                (isAccepted, isImmediateInsert, offsetX, offsetY, newSym) = symbolEditorDialog.showDialog()
2762
                # TODO: not initialize symbol tree view when user reject to create a new symbol
2763
                self.symbolTreeWidget.initSymbolTreeView()
2764
                if isAccepted:
2765
                    if isImmediateInsert:
2766
                        svg = QtImageViewer.createSymbolObject(newSym.getName())
2767
                        offsetX, offsetY = [int(point) for point in newSym.getOriginalPoint().split(',')]
2768
                        QtImageViewer.matchSymbolToLine(self.graphicsView.scene(), svg, QPoint(position.x() + offsetX, position.y() + offsetY))
2769

    
2770
                        package_item.transfer.onRemoved.emit(package_item)
2771
        finally:
2772
            self.onCommandRejected()
2773
            QApplication.restoreOverrideCursor()
2774
            QApplication.restoreOverrideCursor()
2775

    
2776
    def on_line_list(self):
2777
        """ line list export dialog """
2778
        from LineListDialog import LineListDialog
2779

    
2780
        if not self.graphicsView.hasImage():
2781
            self.showImageSelectionMessageBox()
2782
            return
2783

    
2784
        dialog = LineListDialog(self)
2785
        dialog.showDialog()
2786

    
2787
    def on_make_label_data(self):
2788
        """ make label data from symbol info """
2789
        from xml.etree.ElementTree import Element, SubElement, dump, ElementTree, parse
2790

    
2791
        if not self.graphicsView.hasImage():
2792
            self.showImageSelectionMessageBox()
2793
            return
2794

    
2795
        app_doc_data = AppDocData.instance()
2796
        project = app_doc_data.getCurrentProject()
2797

    
2798
        smalls = []
2799
        bigs = []
2800

    
2801
        symbol_list = app_doc_data.getTargetSymbolList(all=True)
2802
        #symbol_list = app_doc_data.getTargetSymbolList(all=False)
2803
        for symbol in symbol_list:
2804
            if symbol.iType == 38 or symbol.iType == 33 or symbol.iType == 0 or symbol.iType == 40:
2805
                continue
2806
            elif symbol.width and symbol.height:
2807
                if symbol.width > 300 or symbol.height > 300:
2808
                    bigs.append(symbol.getName())
2809
                elif (symbol.width * symbol.height < 1500) or (symbol.width > 450 or symbol.height > 450):
2810
                    continue
2811
                else:
2812
                    smalls.append(symbol.getName())
2813

    
2814
        symbols = [item for item in self.graphicsView.scene().items() if issubclass(type(item), SymbolSvgItem)]
2815
        names = [smalls, bigs]
2816

    
2817
        img = app_doc_data.activeDrawing.image_origin
2818

    
2819
        small_size = 500
2820
        big_size = 850
2821

    
2822
        save_path = project.getTrainingSymbolFilePath()
2823

    
2824
        index = 0
2825
        for size in [small_size, big_size]:
2826
            offsets = [0, int(size / 2)]
2827

    
2828
            width, height = img.shape[1], img.shape[0]
2829
            width_count, height_count = width // size + 2, height // size + 2
2830
            b_width, b_height = width_count * size, height_count * size
2831
            b_img = np.zeros((b_height, b_width), np.uint8) + 255
2832
            b_img[:height, :width] = img[:, :]
2833

    
2834
            for offset in offsets:
2835
                for row in range(height_count):
2836
                    for col in range(width_count):
2837
                        x, y = col * size + offset, row * size + offset
2838
                        tile_rect = QRectF(x, y, size, size)
2839
                        tile_symbols = []
2840
                        for symbol in [symbol for symbol in symbols if symbol.name in names[index]]:
2841
                            if tile_rect.contains(symbol.sceneBoundingRect()):
2842
                                tile_symbols.append(symbol)
2843
                                symbols.remove(symbol)
2844

    
2845
                        if tile_symbols:
2846
                            training_uid = str(uuid.uuid4())
2847
                            training_image_path = os.path.join(save_path, training_uid + '.png')
2848
                            training_xml_path = os.path.join(save_path, training_uid + '.xml')
2849

    
2850
                            # save image
2851
                            #_img = b_img[round(tile_rect.top()):round(tile_rect.bottom()),
2852
                            #       round(tile_rect.left()):round(tile_rect.right())]
2853
                            #cv2.imwrite(training_image_path, _img)
2854
                            _img = self.graphicsView.image().copy(round(tile_rect.left()), round(tile_rect.top()), round(tile_rect.width()), round(tile_rect.height()))
2855
                            _img.save(training_image_path)
2856

    
2857
                            # save label
2858
                            xml = Element('annotation')
2859
                            SubElement(xml, 'folder').text = 'None'
2860
                            SubElement(xml, 'filename').text = os.path.basename(save_path)
2861

    
2862
                            pathNode = Element('path')
2863
                            pathNode.text = save_path.replace('/', '\\')
2864
                            xml.append(pathNode)
2865

    
2866
                            sourceNode = Element('source')
2867
                            databaseNode = Element('database')
2868
                            databaseNode.text = 'Unknown'
2869
                            sourceNode.append(databaseNode)
2870
                            xml.append(sourceNode)
2871

    
2872
                            sizeNode = Element('size')
2873
                            widthNode = Element('width')
2874
                            widthNode.text = str(int(tile_rect.width()))
2875
                            sizeNode.append(widthNode)
2876
                            heightNode = Element('height')
2877
                            heightNode.text = str(int(tile_rect.height()))
2878
                            sizeNode.append(heightNode)
2879
                            depthNode = Element('depth')
2880
                            depthNode.text = '3'
2881
                            sizeNode.append(depthNode)
2882
                            xml.append(sizeNode)
2883

    
2884
                            segmentedNode = Element('segmented')
2885
                            segmentedNode.text = '0'
2886
                            xml.append(segmentedNode)
2887

    
2888
                            labelContent = []
2889
                            counts = {}
2890
                            for item in tile_symbols:
2891
                                rect = item.sceneBoundingRect()
2892
                                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)
2893
                                #label = 'small' if index == 0 else 'big' # for single class test
2894
                                xMin = xMin if xMin > 0 else 0
2895
                                yMin = yMin if yMin > 0 else 0
2896
                                xMax = xMax if xMax < size else size
2897
                                yMax = yMax if yMax < size else size
2898

    
2899
                                if label == 'None' or label == '':
2900
                                    continue
2901
                                if label not in labelContent:
2902
                                    labelContent.append(label)
2903
                                    counts[label] = 1
2904
                                else:
2905
                                    counts[label] = counts[label] + 1
2906

    
2907
                                objectNode = Element('object')
2908
                                nameNode = Element('name')
2909
                                nameNode.text = label
2910
                                objectNode.append(nameNode)
2911
                                poseNode = Element('pose')
2912
                                poseNode.text = 'Unspecified'
2913
                                objectNode.append(poseNode)
2914
                                truncatedNode = Element('truncated')
2915
                                truncatedNode.text = '0'
2916
                                objectNode.append(truncatedNode)
2917
                                difficultNode = Element('difficult')
2918
                                difficultNode.text = '0'
2919
                                objectNode.append(difficultNode)
2920

    
2921
                                bndboxNode = Element('bndbox')
2922
                                xminNode = Element('xmin')
2923
                                xminNode.text = str(xMin)
2924
                                bndboxNode.append(xminNode)
2925
                                yminNode = Element('ymin')
2926
                                yminNode.text = str(yMin)
2927
                                bndboxNode.append(yminNode)
2928
                                xmaxNode = Element('xmax')
2929
                                xmaxNode.text = str(xMax)
2930
                                bndboxNode.append(xmaxNode)
2931
                                ymaxNode = Element('ymax')
2932
                                ymaxNode.text = str(yMax)
2933
                                bndboxNode.append(ymaxNode)
2934
                                objectNode.append(bndboxNode)
2935

    
2936
                                xml.append(objectNode)
2937

    
2938
                            ElementTree(xml).write(training_xml_path)
2939

    
2940
            index += 1
2941

    
2942
        QMessageBox.about(self, self.tr("Notice"), self.tr('Successfully applied. '))
2943

    
2944
    def onPlaceLineQuick(self):
2945
        """create a line"""
2946
        home_pane = self.ribbon.get_pane('Home')
2947

    
2948
        if not self.graphicsView.hasImage():
2949
            home_pane.ui.toolButtonLine.setChecked(False)
2950
            self.showImageSelectionMessageBox()
2951
            return
2952

    
2953
        self.update_action_group(home_pane.ui.toolButtonLine)
2954
        if not hasattr(home_pane.ui.toolButtonLine, 'tag'):
2955
            home_pane.ui.toolButtonLine.tag = PlaceLineCommand.PlaceLineCommand(self.graphicsView)
2956
            home_pane.ui.toolButtonLine.tag.onSuccess.connect(lambda: self.onLineCreated(Qt.Key_X))
2957
            home_pane.ui.toolButtonLine.tag.onRejected.connect(self.onCommandRejected)
2958
        else:
2959
            home_pane.ui.toolButtonLine.tag.onSuccess.disconnect()
2960
            home_pane.ui.toolButtonLine.tag.onSuccess.connect(lambda: self.onLineCreated(Qt.Key_X))
2961

    
2962
        self.graphicsView.command = home_pane.ui.toolButtonLine.tag
2963

    
2964
    def onPlaceLine(self):
2965
        """create a line"""
2966
        home_pane = self.ribbon.get_pane('Home')
2967

    
2968
        if not self.graphicsView.hasImage():
2969
            home_pane.ui.toolButtonLine.setChecked(False)
2970
            self.showImageSelectionMessageBox()
2971
            return
2972

    
2973
        self.update_action_group(home_pane.ui.toolButtonLine)
2974
        if not hasattr(home_pane.ui.toolButtonLine, 'tag'):
2975
            home_pane.ui.toolButtonLine.tag = PlaceLineCommand.PlaceLineCommand(self.graphicsView)
2976
            home_pane.ui.toolButtonLine.tag.onSuccess.connect(lambda: self.onLineCreated(Qt.Key_L))
2977
            home_pane.ui.toolButtonLine.tag.onRejected.connect(self.onCommandRejected)
2978
        else:
2979
            home_pane.ui.toolButtonLine.tag.onSuccess.disconnect()
2980
            home_pane.ui.toolButtonLine.tag.onSuccess.connect(lambda: self.onLineCreated(Qt.Key_L))
2981

    
2982
        self.graphicsView.command = home_pane.ui.toolButtonLine.tag
2983

    
2984
    def onLineCreated(self, inputKey):
2985
        """add created lines to scene"""
2986
        from EngineeringConnectorItem import QEngineeringConnectorItem
2987
        from LineDetector import LineDetector
2988

    
2989
        try:
2990
            app_doc_data = AppDocData.instance()
2991
            home_pane = self.ribbon.get_pane('Home')
2992
            configs = app_doc_data.getConfigs('Line', 'Drafting')
2993
            lineTypeMode = 1
2994
            if configs:
2995
                lineTypeMode = int(configs[0].value)
2996

    
2997
            count = len(home_pane.ui.toolButtonLine.tag._polyline._vertices)
2998
            if count > 1:
2999
                items = []
3000

    
3001
                detector = LineDetector(None)
3002

    
3003
                if inputKey == Qt.Key_X:
3004
                    line_type = home_pane.ui.comboBoxLineTypeQuick.currentText()
3005
                elif not home_pane.ui.toolButtonLine.tag.line_type or lineTypeMode == -1:
3006
                    line_type = home_pane.ui.comboBoxLineType.currentText()
3007
                elif lineTypeMode == 1:
3008
                    selected_line_type = home_pane.ui.comboBoxLineType.currentText()
3009
                    if selected_line_type == 'Connect To Process':
3010
                        line_type = selected_line_type
3011
                    elif not (QEngineeringLineItem.check_piping(home_pane.ui.toolButtonLine.tag.line_type) ^
3012
                              QEngineeringLineItem.check_piping(selected_line_type)):
3013
                        line_type = selected_line_type
3014
                    else:
3015
                        line_type = home_pane.ui.toolButtonLine.tag.line_type
3016
                elif lineTypeMode == 2 and home_pane.ui.toolButtonLine.tag.line_type:
3017
                    line_type = home_pane.ui.toolButtonLine.tag.line_type
3018

    
3019
                for index in range(count - 1):
3020
                    start = home_pane.ui.toolButtonLine.tag._polyline._vertices[index]
3021
                    end = home_pane.ui.toolButtonLine.tag._polyline._vertices[index + 1]
3022

    
3023
                    lineItem = QEngineeringLineItem(vertices=[start, end])
3024
                    lineItem.transfer.onRemoved.connect(self.itemRemoved)
3025
                    lineItem.lineType = line_type
3026
                    if items:
3027
                        lineItem.connect_if_possible(items[-1], 5)
3028
                    else:
3029
                        pt = lineItem.start_point()
3030
                        selected = [item for item in self.graphicsView.scene().items(QPointF(pt[0], pt[1])) if
3031
                                    type(item) is QEngineeringConnectorItem or type(item) is QEngineeringLineItem]
3032
                        if selected and selected[0] is not lineItem:
3033
                            if type(selected[0]) is QEngineeringConnectorItem:
3034
                                lineItem.connect_if_possible(selected[0].parent, 5)
3035
                            else:
3036
                                detector.connectLineToLine(selected[0], lineItem, 5)
3037

    
3038
                    items.append(lineItem)
3039
                    self.graphicsView.scene().addItem(lineItem)
3040

    
3041
                pt = items[-1].end_point()
3042
                selected = [item for item in self.graphicsView.scene().items(QPointF(pt[0], pt[1])) if
3043
                            (type(item) is QEngineeringConnectorItem and item.parentItem() is not items[-1]) or
3044
                            (type(item) is QEngineeringLineItem and item is not items[-1])]
3045
                if selected and selected[0] is not items[-1]:
3046
                    if type(selected[0]) is QEngineeringConnectorItem:
3047
                        items[-1].connect_if_possible(selected[0].parent, 5)
3048
                    else:
3049
                        detector.connectLineToLine(selected[0], items[-1], 5)
3050

    
3051
                self._scene.undo_stack.push(CreateCommand(self._scene, items))
3052
        finally:
3053
            self.graphicsView.scene().removeItem(home_pane.ui.toolButtonLine.tag._polyline)
3054
            home_pane.ui.toolButtonLine.tag.reset()
3055

    
3056
    def onCommandRejected(self, cmd=None):
3057
        """command is rejected"""
3058
        try:
3059
            home_pane = self.ribbon.get_pane('Home')
3060
            visualization_pane = self.ribbon.get_pane('Home Visualization')
3061
            if type(cmd) is PlaceLineCommand.PlaceLineCommand:
3062
                if home_pane.ui.toolButtonLine.tag._polyline:
3063
                    self.graphicsView.scene().removeItem(home_pane.ui.toolButtonLine.tag._polyline)
3064
                self.graphicsView.scene().update()
3065
                home_pane.ui.toolButtonLine.tag.reset()
3066

    
3067
                home_pane.ui.toolButtonLine.setChecked(False)
3068
            elif type(cmd) is AreaZoomCommand.AreaZoomCommand:
3069
                visualization_pane.ui.toolButtonZoom.setChecked(False)
3070
            elif type(cmd) is AreaOcrCommand.AreaOcrCommand:
3071
                home_pane.ui.toolButtonOCR.setChecked(False)
3072
            elif type(cmd) is PlacePolygonCommand.PlacePolygonCommand:
3073
                home_pane.ui.toolButtonVendor.setChecked(False)
3074
            else:
3075
                if hasattr(home_pane.ui.toolButtonVendor, 'tag') and home_pane.ui.toolButtonVendor.tag._polyline:
3076
                    self.graphicsView.scene().removeItem(home_pane.ui.toolButtonVendor.tag._polyline)
3077
                    self.graphicsView.scene().update()
3078
                    home_pane.ui.toolButtonVendor.tag.reset()
3079
                home_pane.ui.toolButtonLine.setChecked(False)
3080
                visualization_pane.ui.toolButtonZoom.setChecked(False)
3081
                home_pane.ui.toolButtonOCR.setChecked(False)
3082
                home_pane.ui.toolButtonVendor.setChecked(False)
3083
        finally:
3084
            self.graphicsView.useDefaultCommand()
3085

    
3086
    def on_view_toggle(self, key: int) -> None:
3087
        """view toggled"""
3088

    
3089
        view_pane = self.ribbon.get_pane('View')
3090
        if key == Qt.Key_1:
3091
            checked = view_pane.ui.toolButtonViewImageDrawing.isChecked()
3092
            self.onViewImageDrawing(not checked)
3093
            view_pane.ui.toolButtonViewImageDrawing.setChecked(not checked)
3094
        elif key == Qt.Key_2:
3095
            checked = view_pane.ui.toolButtonViewText.isChecked()
3096
            self.onViewText(not checked)
3097
            view_pane.ui.toolButtonViewText.setChecked(not checked)
3098
        elif key == Qt.Key_3:
3099
            checked = view_pane.ui.toolButtonViewSymbol.isChecked()
3100
            self.onViewSymbol(not checked)
3101
            view_pane.ui.toolButtonViewSymbol.setChecked(not checked)
3102
        elif key == Qt.Key_4:
3103
            checked = view_pane.ui.toolButtonViewLine.isChecked()
3104
            self.onViewLine(not checked)
3105
            view_pane.ui.toolButtonViewLine.setChecked(not checked)
3106
        elif key == Qt.Key_5:
3107
            checked = view_pane.ui.toolButtonViewUnknown.isChecked()
3108
            self.onViewUnknown(not checked)
3109
            view_pane.ui.toolButtonViewUnknown.setChecked(not checked)
3110
        elif key == Qt.Key_6:
3111
            checked = view_pane.ui.toolButtonViewInconsistency.isChecked()
3112
            self.onViewInconsistency(not checked)
3113
            view_pane.ui.toolButtonViewInconsistency.setChecked(not checked)
3114
        elif key == Qt.Key_7:
3115
            checked = view_pane.ui.toolButtonViewVendorArea.isChecked()
3116
            self.onViewVendorArea(not checked)
3117
            view_pane.ui.toolButtonViewVendorArea.setChecked(not checked)
3118
        elif key == 96:  # '~' key
3119
            checked = view_pane.ui.toolButtonViewDrawingOnly.isChecked()
3120
            self.onViewDrawingOnly(not checked)
3121
            view_pane.ui.toolButtonViewDrawingOnly.setChecked(not checked)
3122

    
3123
    def change_selected_line_type(self, line_type):
3124
        """ change line type that selected on scene"""
3125
        lineItems = [line for line in self.graphicsView.scene().selectedItems() if
3126
                             issubclass(type(line), QEngineeringLineItem)]
3127
        for line in lineItems:
3128
            line.lineType = line_type
3129

    
3130
    def keyPressEvent(self, event):
3131
        """restore to default command when user press Escape key"""
3132
        try:
3133
            #print('main : ' + str(event.key()))
3134
            modifiers = QApplication.keyboardModifiers()
3135

    
3136
            if event.key() == Qt.Key_Escape:
3137
                checked = self.checked_action()
3138
                if checked:
3139
                    checked.setChecked(False)
3140
                    self.graphicsView.useDefaultCommand()
3141

    
3142
            elif event.key() == Qt.Key_M:  # merge text, line
3143
                from TextInfo import TextInfo
3144
                from EngineeringConnectorItem import QEngineeringConnectorItem
3145
                from LineDetector import LineDetector
3146

    
3147
                # line merge
3148
                app_doc_data = AppDocData.instance()
3149
                configs = app_doc_data.getConfigs('Line Detector', 'Length to connect line')
3150
                toler = int(configs[0].value) if configs else 20
3151

    
3152
                lineItems = [line for line in self.graphicsView.scene().selectedItems() if
3153
                             issubclass(type(line), QEngineeringLineItem)]
3154

    
3155
                vLines = []
3156
                hLines = []
3157

    
3158
                for line in lineItems:
3159
                    if line.isVertical():
3160
                        vLines.append(line)
3161
                    elif line.isHorizontal():
3162
                        hLines.append(line)
3163

    
3164
                for lines in [vLines, hLines]:
3165
                    if len(lines) < 2:
3166
                        continue
3167

    
3168
                    mergeLineList = {}
3169
                    usedLine = []
3170

    
3171
                    for keyline in lines:
3172
                        if keyline in usedLine:
3173
                            continue
3174
                        else:
3175
                            mergeLineList[keyline] = [keyline]
3176
                            usedLine.append(keyline)
3177

    
3178
                        for line in lines:
3179
                            if keyline is line or line in usedLine:
3180
                                continue
3181

    
3182
                            for key, value in mergeLineList.items():
3183
                                standardPoint = key.sceneBoundingRect().center().x() if lines is vLines else key.sceneBoundingRect().center().y()
3184
                                point = line.sceneBoundingRect().center().x() if lines is vLines else line.sceneBoundingRect().center().y()
3185
                                if abs(standardPoint - point) < toler:
3186
                                    value.append(line)
3187
                                    usedLine.append(line)
3188

    
3189
                    for key, value in mergeLineList.items():
3190
                        if len(value) < 2:
3191
                            continue
3192

    
3193
                        lineItems = value
3194
                        x = []
3195
                        y = []
3196
                        connectedItems = []
3197
                        for line in lineItems:
3198
                            x.append(line.start_point()[0])
3199
                            y.append(line.start_point()[1])
3200
                            x.append(line.end_point()[0])
3201
                            y.append(line.end_point()[1])
3202

    
3203
                            if line.connectors[0].connectedItem:
3204
                                connectedItems.append(line.connectors[0].connectedItem)
3205
                            if line.connectors[1].connectedItem:
3206
                                connectedItems.append(line.connectors[1].connectedItem)
3207

    
3208
                        startPoint = [key.sceneBoundingRect().center().x(), min(y)] if lines is vLines else [min(x), key.sceneBoundingRect().center().y()]
3209
                        endPoint = [key.sceneBoundingRect().center().x(), max(y)] if lines is vLines else [max(x), key.sceneBoundingRect().center().y()]
3210
                        lineItem = QEngineeringLineItem(vertices=[startPoint, endPoint])
3211
                        lineItem.transfer.onRemoved.connect(self.itemRemoved)
3212
                        lineItem.lineType = lineItems[0].lineType
3213

    
3214
                        for line in lineItems:
3215
                            line.transfer.onRemoved.emit(line)
3216

    
3217
                        detector = LineDetector(None)
3218

    
3219
                        for pt in [startPoint, endPoint]:
3220
                            selected = [item for item in self.graphicsView.scene().items(QPointF(pt[0], pt[1])) if
3221
                                        type(item) is QEngineeringConnectorItem or type(item) is QEngineeringLineItem]
3222
                            if selected:
3223
                                res = []
3224
                                if type(selected[0]) is QEngineeringConnectorItem:
3225
                                    res = lineItem.connect_if_possible(selected[0].parent, 5)
3226
                                elif selected[0] in connectedItems:
3227
                                    res = lineItem.connect_if_possible(selected[0], 5)
3228
                                if not res:
3229
                                    detector.connectLineToLine(selected[0], lineItem, 5)
3230

    
3231
                        self.graphicsView.scene().addItem(lineItem)
3232
                # up to here
3233

    
3234
                # text merge
3235
                textItems = [text for text in self.graphicsView.scene().selectedItems() if issubclass(type(text), QEngineeringTextItem)]
3236

    
3237
                if len(textItems) > 1:
3238
                    angle = None
3239
                    for item in textItems:
3240
                        if angle is None:
3241
                            angle = item.angle
3242
                        else:
3243
                            if angle != item.angle:
3244
                                return
3245

    
3246
                    enter_or_space = ' ' if modifiers == Qt.ControlModifier else ('\n' if modifiers != Qt.AltModifier else '')
3247
                    x_or_y = 0 if (modifiers == Qt.ControlModifier and angle == 0) or (modifiers != Qt.ControlModifier and angle == 1.57) else 1
3248

    
3249
                    textItems = sorted(textItems, key=lambda text: text.loc[x_or_y]) if textItems[0].angle == 0 else ( \
3250
                        sorted(textItems, key=lambda text: text.loc[x_or_y]) if textItems[0].angle == 1.57 else ( \
3251
                            sorted(textItems, key=lambda text: text.loc[x_or_y], reverse=True) if textItems[0].angle == 4.71 else \
3252
                                sorted(textItems, key=lambda text: text.loc[x_or_y], reverse=True)))
3253

    
3254
                    if textItems[0].angle == 1.57 and modifiers == Qt.ControlModifier:
3255
                        textItems.reverse()
3256

    
3257
                    minX = sys.maxsize
3258
                    minY = sys.maxsize
3259
                    maxX = 0
3260
                    maxY = 0
3261
                    newText = ''
3262

    
3263
                    for text in textItems:
3264
                        if text.loc[0] < minX: minX = text.loc[0]
3265
                        if text.loc[1] < minY: minY = text.loc[1]
3266
                        if text.loc[0] + text.size[0] > maxX: maxX = text.loc[0] + text.size[0]
3267
                        if text.loc[1] + text.size[1] > maxY: maxY = text.loc[1] + text.size[1]
3268
                        newText = newText + text.text() + enter_or_space
3269
                        text.transfer.onRemoved.emit(text)
3270
                    newText = newText[:-1]
3271

    
3272
                    textInfo = TextInfo(newText, minX, minY, maxX - minX, maxY - minY, textItems[0].angle)
3273
                    item = QEngineeringTextItem.create_text_with(self.graphicsView.scene(), textInfo)
3274
                    if item is not None:
3275
                        item.area = textItems[0].area
3276
                        #item.setDefaultTextColor(Qt.blue)
3277
                        item.transfer.onRemoved.connect(self.itemRemoved)
3278
                # up to here
3279

    
3280
                # symbol merge = make line between symbols
3281
                symbolItems = [symbol for symbol in self.graphicsView.scene().selectedItems() if
3282
                             issubclass(type(symbol), SymbolSvgItem) and type(symbol) is not QEngineeringEquipmentItem]
3283
                
3284
                if len(symbolItems) >= 2:
3285
                    usedItem = []
3286
                    for symbolItem in symbolItems:
3287
                        if symbolItem in usedItem:
3288
                            continue
3289

    
3290
                        startConn = None
3291
                        endConn = None
3292
                        connItem = None
3293

    
3294
                        for conn in symbolItem.connectors:
3295
                            if conn.connectedItem and conn.connectedItem in symbolItems and conn.connectedItem is not symbolItem:
3296
                                startConn = conn
3297
                                connItem = conn.connectedItem
3298
                                break
3299

    
3300
                        if connItem:
3301
                            for conn in connItem.connectors:
3302
                                if conn.connectedItem and conn.connectedItem is symbolItem:
3303
                                    endConn = conn
3304
                                    break
3305

    
3306
                        if startConn and endConn:
3307
                            line = QEngineeringLineItem(vertices=[startConn.center(), endConn.center()])
3308
                            line.area = symbolItem.area
3309
                            line.transfer.onRemoved.connect(self.itemRemoved)
3310

    
3311
                            startConn.connect(line)
3312
                            endConn.connect(line)
3313
                            line.connectors[0].connect(startConn.parentItem())
3314
                            line.connectors[1].connect(endConn.parentItem())
3315

    
3316
                            line.lineType = symbolItem.conn_type[symbolItem.connectors.index(startConn)]
3317
                            self.graphicsView.scene().addItem(line)
3318

    
3319
                            usedItem.append(symbolItem)
3320
                            usedItem.append(connItem)
3321
                # up to here
3322
            elif event.key() == Qt.Key_D:
3323
                # pop up development toolkit dialog
3324
                from DevelopmentToolkitDialog import QDevelopmentToolkitDialog
3325

    
3326
                if modifiers == Qt.ControlModifier:
3327
                    dlg = QDevelopmentToolkitDialog(self, self.graphicsView)
3328
                    dlg.show()
3329
            elif event.key() == Qt.Key_I or event.key() == Qt.Key_Q:
3330
                # insert symbol item that is selected symbol in tree to main window if symbol already selected on main window, replace
3331
                index = self.symbolTreeWidget.currentIndex()
3332
                proxy_model = self.symbolTreeWidget.model()
3333
                items = [proxy_model.sourceModel().itemFromIndex(proxy_model.mapToSource(index))]
3334
                if items and hasattr(items[0], 'svgFilePath'):
3335
                    symData = items[0].data(self.symbolTreeWidget.TREE_DATA_ROLE)
3336
                    symName = symData.getName()
3337
                else:
3338
                    return
3339

    
3340
                symbolItems = [symbol for symbol in self.graphicsView.scene().selectedItems() if
3341
                               issubclass(type(symbol), SymbolSvgItem)]
3342
                old_symbols = []
3343
                if symbolItems and len(symbolItems) >= 1:
3344
                    for old_symbol in symbolItems:
3345
                        #old_symbol = symbolItems[0]
3346
                        #scenePos = QPoint(old_symbol.origin[0], old_symbol.origin[1])
3347
                        scenePos = old_symbol.mapToScene(old_symbol.transformOriginPoint())
3348
                        old_symbols.append([old_symbol, scenePos])
3349
                        old_symbol.transfer.onRemoved.emit(old_symbol)
3350
                else:
3351
                    scenePos = self.current_pos
3352
                    old_symbols.append([None, scenePos])
3353

    
3354
                for old_symbol in old_symbols:
3355
                    svg = QtImageViewer.createSymbolObject(symName)
3356
                    QtImageViewer.matchSymbolToLine(self.graphicsView.scene(), svg, old_symbol[1], angle=old_symbol[0].angle if old_symbol[0] else 0.0)
3357
                    svg.bind_close_items()
3358

    
3359
                if old_symbols and svg:
3360
                    from ReplaceCommand import ReplaceCommand
3361

    
3362
                    for old_symbol in old_symbols:
3363
                        cmd = ReplaceCommand(self.graphicsView.scene(), old_symbol, svg)
3364
                        self._scene.undo_stack.push(cmd)
3365
                    return
3366
            elif event.key() == Qt.Key_J:
3367
                # insert and connect symbol item that is selected symbol in tree to selected symbol
3368
                index = self.symbolTreeWidget.currentIndex()
3369
                proxy_model = self.symbolTreeWidget.model()
3370
                items = [proxy_model.sourceModel().itemFromIndex(proxy_model.mapToSource(index))]
3371
                if items and hasattr(items[0], 'svgFilePath'):
3372
                    symData = items[0].data(self.symbolTreeWidget.TREE_DATA_ROLE)
3373
                    symName = symData.getName()
3374
                else:
3375
                    return
3376

    
3377
                symbolItems = [symbol for symbol in self.graphicsView.scene().selectedItems() if
3378
                               issubclass(type(symbol), SymbolSvgItem)]
3379
                
3380
                for symbolItem in symbolItems:
3381
                    target_symbol = symbolItem
3382
                    index =  [index for index in range(len(target_symbol.conn_type)) \
3383
                                if QEngineeringLineItem.check_piping(target_symbol.conn_type[index], True)]
3384
                    for connector in target_symbol.connectors:
3385
                        svg = QtImageViewer.createSymbolObject(symName)
3386
                        if len(svg.connectors) > 1: 
3387
                            if ((target_symbol.conn_type and target_symbol.connectors.index(connector) in index) or not target_symbol.conn_type) and \
3388
                                        (not connector.connectedItem or (connector.connectedItem and type(connector.connectedItem) is QEngineeringLineItem)):
3389
                                QtImageViewer.matchSymbolToLine(self.graphicsView.scene(), svg, connector.sceneBoundingRect().center())
3390
                        elif len(svg.connectors) == 1:
3391
                            if ((target_symbol.conn_type and target_symbol.connectors.index(connector) in index) or not target_symbol.conn_type) and \
3392
                                        not connector.connectedItem:
3393
                                QtImageViewer.matchSymbolToLine(self.graphicsView.scene(), svg, connector.sceneBoundingRect().center())
3394

    
3395
                if symbolItems:
3396
                    return
3397
            elif event.key() == Qt.Key_X:
3398
                pass
3399
                '''
3400
                app_doc_data = AppDocData.instance()
3401
                configs = app_doc_data.getAppConfigs('app', 'mode')
3402
                if configs and 1 == len(configs) and 'advanced' == configs[0].value:
3403
                    advanced = True
3404
                    items = self.graphicsView.scene().selectedItems()
3405
                    if items:
3406
                        item = self.symbolTreeWidget.currentItem()
3407
                        if item:
3408
                            self.symbolTreeWidget.showSymbolEditorDialog(item, 0)
3409
                '''
3410
            elif event.key() == Qt.Key_F6:
3411
                from DEXPI import scene_to_dexpi
3412

    
3413
                app_doc_data = AppDocData.instance()
3414
                scene_to_dexpi('D:\\Temp\\DEXPI.xml', app_doc_data.activeDrawing.name, self.graphicsView.scene())
3415

    
3416
            QMainWindow.keyPressEvent(self, event)
3417
        except Exception as ex:
3418
            message = f"error occurred({repr(ex)}) in {sys.exc_info()[-1].tb_frame.f_code.co_filename}:" \
3419
                      f"{sys.exc_info()[-1].tb_lineno}"
3420
            self.addMessage.emit(MessageType.Error, message)
3421

    
3422
    def recognizeSymbol(self):
3423
        # save alarm
3424
        self.save_alarm_enable(False)
3425

    
3426
        if not self.graphicsView.hasImage():
3427
            self.showImageSelectionMessageBox()
3428
            return
3429
        
3430
        app_doc_data = AppDocData.instance()
3431
        
3432
        current_drawing = app_doc_data.activeDrawing
3433
        checked_drawings = {}
3434
        drawing_top = self.treeWidgetDrawingList.topLevelItem(0)
3435

    
3436
        for idx in range(drawing_top.childCount()):
3437
            child = drawing_top.child(idx)
3438
            if child.data(Qt.UserRole, 0) is current_drawing:
3439
                checked_drawings[child.data(Qt.UserRole, 0)] = child
3440

    
3441
        try:
3442
            self.on_clear_log()
3443
            dlg = QRecognitionDialog(self, [drawing for drawing in checked_drawings.keys()], symbolOnly=True)
3444
            dlg.exec_()
3445

    
3446
            self.changeViewCheckedState(True)
3447
        except Exception as ex:
3448
            message = f"error occurred({repr(ex)}) in {sys.exc_info()[-1].tb_frame.f_code.co_filename}:" \
3449
                      f"{sys.exc_info()[-1].tb_lineno}"
3450
            self.addMessage.emit(MessageType.Error, message)
3451

    
3452
        # save alarm
3453
        self.save_alarm_enable(True, True)
3454
        
3455
        self.graphicsView.useDefaultCommand()
3456

    
3457
    def recognize(self):
3458
        """recognize symbol, text and line for selected drawings"""
3459
        from datetime import datetime
3460
        from License import QLicenseDialog
3461

    
3462
        app_doc_data = AppDocData.instance()
3463

    
3464
        # read-only
3465
        if app_doc_data.readOnly:
3466
            QMessageBox.warning(self, self.tr('Warning'), "We can't recognize because the drawing is read-only.")
3467
            return
3468

    
3469
        # save alarm
3470
        self.save_alarm_enable(False)
3471

    
3472
        current_drawing, currentPid = None, None
3473

    
3474
        if self.graphicsView.hasImage():
3475
            current_drawing = app_doc_data.activeDrawing
3476
            currentPid = app_doc_data.activeDrawing.name
3477

    
3478
        # get checked drawings
3479
        drawing_top = self.treeWidgetDrawingList.topLevelItem(0)
3480
        count = drawing_top.childCount()
3481
        checked_drawings = {}
3482
        for idx in range(count):
3483
            child = drawing_top.child(idx)
3484
            if child.checkState(0) == Qt.Checked and child.data(Qt.UserRole, 0):
3485
                checked_drawings[child.data(Qt.UserRole, 0)] = child
3486
        # up to here
3487

    
3488
        # if there is no checked drawing
3489
        if current_drawing and currentPid and not checked_drawings:
3490
            for idx in range(count):
3491
                child = drawing_top.child(idx)
3492
                if child.data(Qt.UserRole, 0) is current_drawing:
3493
                    checked_drawings[child.data(Qt.UserRole, 0)] = child
3494

    
3495
        if not checked_drawings:
3496
            self.showImageSelectionMessageBox()
3497
            return
3498

    
3499
        try:
3500
            self.on_clear_log()
3501
            dlg = QRecognitionDialog(self, [drawing for drawing in checked_drawings.keys()])
3502
            dlg.exec_()
3503

    
3504
            if current_drawing and current_drawing in checked_drawings.keys() and dlg.isTreated:
3505
                self.open_image_drawing(current_drawing, force=True, ocrUnknown=dlg.ui.checkBoxOCRUnknown.isChecked())
3506

    
3507
            # save working date-time
3508
            _now = datetime.now().strftime('%Y-%m-%d %H:%M:%S')
3509
            for drawing, tree_item in checked_drawings.items():
3510
                drawing.datetime = _now
3511
                tree_item.setText(1, _now)
3512
            #app_doc_data.saveDrawings(checked_drawings.keys())
3513
            # up to here
3514

    
3515
            self.changeViewCheckedState(True)
3516

    
3517
            # count up for recognition
3518
            QLicenseDialog.count_up()
3519
            # up to here
3520
        except Exception as ex:
3521
            message = f"error occurred({repr(ex)}) in {sys.exc_info()[-1].tb_frame.f_code.co_filename}:" \
3522
                      f"{sys.exc_info()[-1].tb_lineno}"
3523
            self.addMessage.emit(MessageType.Error, message)
3524

    
3525
        # save alarm
3526
        self.save_alarm_enable(True, True)
3527

    
3528
    '''
3529
        @brief      remove item from tree widget and then remove from scene
3530
        @date       2018.05.25
3531
        @author     Jeongwoo
3532
    '''
3533
    def itemRemoved(self, item):
3534
        try:
3535
            if type(item) is QEngineeringErrorItem:
3536
                # remove error item from inconsistency list
3537
                for row in range(self.tableWidgetInconsistency.rowCount()):
3538
                    if item is self.tableWidgetInconsistency.item(row, 0).tag:
3539
                        self.tableWidgetInconsistency.removeRow(row)
3540
                        break
3541

    
3542
                if item.scene() is not None:
3543
                    item.scene().removeItem(item)
3544
                del item
3545
            else:
3546
                remove_scene = item.scene()
3547

    
3548
                if remove_scene:
3549
                    matches = [_item for _item in remove_scene.items() if
3550
                            hasattr(_item, 'connectors') and [connector for connector in _item.connectors if
3551
                                                                connector.connectedItem is item]]
3552
                    for match in matches:
3553
                        for connector in match.connectors:
3554
                            if connector.connectedItem is item:
3555
                                connector.connectedItem = None
3556
                                connector.highlight(False)
3557

    
3558
                # matches = [_item for _item in self.graphicsView.scene().items() if hasattr(_item, 'remove_assoc_item')]
3559
                # for _item in matches:
3560
                #    _item.remove_assoc_item(item)
3561

    
3562
                app_doc_data = AppDocData.instance()
3563
                if type(item) is QEngineeringLineNoTextItem:
3564
                    self.itemTreeWidget.explode_line_no_from_context(item)
3565

    
3566
                if type(item) is QEngineeringLineNoTextItem and item in app_doc_data.tracerLineNos:
3567
                    app_doc_data.tracerLineNos.pop(app_doc_data.tracerLineNos.index(item))
3568

    
3569
                if type(item) is QEngineeringLineItem and item in app_doc_data.lines:
3570
                    app_doc_data.lines.remove(item)
3571

    
3572
                if remove_scene:
3573
                    matches = [_item for _item in remove_scene.items() if type(_item) is QEngineeringLineNoTextItem]
3574
                    matches.extend([lineNo for lineNo in app_doc_data.tracerLineNos if
3575
                                    type(lineNo) is QEngineeringTrimLineNoTextItem])
3576
                    for match in matches:
3577
                        if item is match.prop('From'):
3578
                            match.set_property('From', None)
3579
                        if item is match.prop('To'):
3580
                            match.set_property('To', None)
3581

    
3582
                        for run_index in reversed(range(len(match.runs))):
3583
                            run = match.runs[run_index]
3584
                            if item in run.items:
3585
                                index = run.items.index(item)
3586
                                run.items.pop(index)
3587
                                if not run.items:
3588
                                    run.explode()
3589
                                    if type(match) is QEngineeringTrimLineNoTextItem and not match.runs:
3590
                                        app_doc_data.tracerLineNos.pop(app_doc_data.tracerLineNos.index(match))
3591
                                # break
3592

    
3593
                if remove_scene:
3594
                    matches = [_item for _item in remove_scene.items() if hasattr(_item, 'owner')]
3595
                    for match in matches:
3596
                        if match.owner is item:
3597
                            match.owner = None
3598

    
3599
                    matches = [_item for _item in remove_scene.items() if hasattr(_item, 'attrs')]
3600
                    # done = False
3601
                    for match in matches:
3602
                        assocs = match.associations()
3603
                        for assoc in assocs:
3604
                            if item is assoc:
3605
                                keys = match.attrs.keys()
3606
                                for attr in keys:
3607
                                    if attr.AssocItem and str(item.uid) == str(attr.AssocItem.uid):
3608
                                        attr.AssocItem = None
3609
                                        match.attrs[attr] = ''
3610
                                        # done = True
3611
                                match.remove_assoc_item(item)
3612
                                break
3613
                        # if done: break
3614

    
3615
                if remove_scene:
3616
                    #if type(item) is QEngineeringLineNoTextItem and item._labels:
3617
                    #    for _label in item._labels:
3618
                    #        item.scene().removeItem(_label)
3619
                    #    item._labels = []
3620
                    
3621
                    item.hoverLeaveEvent(None)
3622
                    if hasattr(item, 'lineNoFromToIndicator') and item.lineNoFromToIndicator:
3623
                        remove_scene.removeItem(item.lineNoFromToIndicator[0])
3624
                        if len(item.lineNoFromToIndicator) > 1:
3625
                            remove_scene.removeItem(item.lineNoFromToIndicator[1])
3626
                    remove_scene.removeItem(item)
3627

    
3628
                self.itemTreeWidget.itemRemoved(item)
3629
        except Exception as ex:
3630
            message = 'error occurred({}) in {}:{}'.format(ex, sys.exc_info()[-1].tb_frame.f_code.co_filename,
3631
                                                           sys.exc_info()[-1].tb_lineno)
3632
            self.addMessage.emit(MessageType.Error, message)
3633
        '''
3634
        finally:
3635
            if hasattr(item, '_cond'):
3636
                item._cond.wakeAll()
3637
        '''
3638

    
3639
    def connect_attributes_check_save(self):
3640
        app_doc_data = AppDocData.instance()
3641
        configs = app_doc_data.getConfigs('Data Save', 'Before Link')
3642
        if configs and int(configs[0].value) == 1:
3643
            if QMessageBox.Yes == QMessageBox.question(self, self.tr('Save?'),
3644
                                                self.tr('Do you want to save before link attribute?'),
3645
                                                QMessageBox.Yes | QMessageBox.No):
3646
                self.save_before_link = True
3647
                self.actionSaveCliked()
3648
            else:
3649
                self.connect_attributes()
3650
        else:
3651
            self.connect_attributes()
3652

    
3653
    def connect_attributes(self):
3654
        """connect attributes to symbol"""
3655
        from ConnectAttrDialog import QConnectAttrDialog
3656

    
3657
        if not self.graphicsView.hasImage():
3658
            self.showImageSelectionMessageBox()
3659
            return
3660

    
3661
        # save alarm
3662
        self.save_alarm_enable(False)
3663

    
3664
        try:
3665
            dlg = QConnectAttrDialog(self, self.graphicsView.scene())
3666
            dlg.setWindowFlags(self.windowFlags() & ~Qt.WindowCloseButtonHint & ~Qt.WindowContextHelpButtonHint)
3667
            dlg.exec_()
3668
            if dlg.isRunned:
3669
                self.refresh_item_list()
3670

    
3671
                if dlg.validation_checked:
3672
                    self.onValidation()
3673

    
3674
                self.graphicsView.invalidateScene()
3675
                
3676
        except Exception as ex:
3677
            message = 'error occurred({}) in {}:{}'.format(ex, sys.exc_info()[-1].tb_frame.f_code.co_filename,
3678
                                                           sys.exc_info()[-1].tb_lineno)
3679
            self.addMessage.emit(MessageType.Error, message)
3680
        finally:
3681
            # save alarm
3682
            self.save_alarm_enable(True)
3683

    
3684
    def postDetectLineProcess(self):
3685
        '''
3686
            @brief  check allowables among undetected items
3687
            @author euisung
3688
            @date   2018.11.15
3689
            @history    2018.11.15  euisung    no more used, moved to TextItemFactoy isLineNo()
3690
        '''
3691

    
3692
        appDocData = AppDocData.instance()
3693

    
3694
        tableNames = ["Fluid Code", "Insulation Purpose", "PnID Number", "Piping Materials Class", "Unit Number"]
3695
        tableDatas = []
3696
        for tableName in tableNames:
3697
            tableNameFormat = tableName.replace(' ', '').replace('&&', 'n')
3698
            tableDatas.append(appDocData.getCodeTable(tableNameFormat))
3699

    
3700
        items = self.graphicsView.scene().items()
3701
        for item in items:
3702
            if type(item) is not QEngineeringTextItem:
3703
                continue
3704
            text = item.text()
3705
            for tableData in tableDatas:
3706
                for data in tableData:
3707
                    if data[3] == '':
3708
                        continue
3709
                    else:
3710
                        allows = data[3].split(',')
3711
                        for allow in allows:
3712
                            text = text.replace(allow, data[1])
3713

    
3714
            lineItem = TextItemFactory.instance().createTextItem(text)
3715
            if type(lineItem) is QEngineeringLineNoTextItem:
3716
                lineItem.loc = item.loc
3717
                lineItem.size = item.size
3718
                lineItem.angle = item.angle
3719
                lineItem.area = item.area
3720
                # lineItem.addTextItemToScene(self.graphicsView.scene())
3721
                lineItem.transfer.onRemoved.connect(self.itemRemoved)
3722
                item.transfer.onRemoved.emit(item)
3723
                appDocData.lineNos.append(lineItem)
3724

    
3725
    def init_add_tree_item(self, line_no_tree_item, run_item):
3726
        """ insert symbol item and find line no as owner """
3727
        # insert
3728
        self.itemTreeWidget.addTreeItem(line_no_tree_item, run_item)
3729
        # find
3730
        self.itemTreeWidget.addTreeItem(line_no_tree_item, run_item)
3731

    
3732
    def load_drawing(self, drawing):
3733
        """ load drawing """
3734
        """ no more used """
3735
        from EngineeringRunItem import QEngineeringRunItem
3736
        from QEngineeringTrimLineNoTextItem import QEngineeringTrimLineNoTextItem
3737

    
3738
        app_doc_data = AppDocData.instance()
3739
        try:
3740
            symbols = []
3741
            lines = []
3742

    
3743
            components = app_doc_data.get_components(drawing.UID)
3744
            maxValue = len(components) * 2
3745
            self.progress.setMaximum(maxValue) if maxValue > 0 else None
3746

    
3747
            """ parsing all symbols """
3748
            for symbol in [component for component in components if int(component['SymbolType_UID']) != -1]:
3749
                item = SymbolSvgItem.from_database(symbol)
3750
                if item is not None:
3751
                    item.transfer.onRemoved.connect(self.itemRemoved)
3752
                    symbols.append(item)
3753
                    app_doc_data.symbols.append(item)
3754
                    item.addSvgItemToScene(self.graphicsView.scene())
3755
                else:
3756
                    pt = [float(symbol['X']), float(symbol['Y'])]
3757
                    size = [float(symbol['Width']), float(symbol['Height'])]
3758
                    angle = float(symbol['Rotation'])
3759
                    item = QGraphicsBoundingBoxItem(pt[0], pt[1], size[0], size[1])
3760
                    item.isSymbol = True
3761
                    item.angle = angle
3762
                    item.setPen(QPen(Qt.red, 5, Qt.SolidLine))
3763
                    self.graphicsView.scene().addItem(item)
3764
                    item.transfer.onRemoved.connect(self.itemRemoved)
3765

    
3766
                self.progress.setValue(self.progress.value() + 1)
3767

    
3768
            QApplication.processEvents()
3769

    
3770
            # parse texts
3771
            for text in [component for component in components if
3772
                         component['Name'] == 'Text' and component['SymbolType_UID'] == -1]:
3773
                item = QEngineeringTextItem.from_database(text)
3774
                if item is not None:
3775
                    item.uid = text['UID']
3776
                    item.attribute = text['Value']
3777
                    name = text['Name']
3778
                    item.transfer.onRemoved.connect(self.itemRemoved)
3779
                    item.addTextItemToScene(self.graphicsView.scene())
3780

    
3781
                self.progress.setValue(self.progress.value() + 1)
3782

    
3783
            QApplication.processEvents()
3784

    
3785
            # note
3786
            for note in [component for component in components if
3787
                         component['Name'] == 'Note' and component['SymbolType_UID'] == -1]:
3788
                item = QEngineeringTextItem.from_database(note)
3789
                if item is not None:
3790
                    item.uid = note['UID']
3791
                    attributeValue = note['Value']
3792
                    name = note['Name']
3793
                    item.transfer.onRemoved.connect(self.itemRemoved)
3794
                    item.addTextItemToScene(self.graphicsView.scene())
3795

    
3796
                self.progress.setValue(self.progress.value() + 1)
3797

    
3798
            QApplication.processEvents()
3799

    
3800
            for line in [component for component in components if
3801
                         component['Name'] == 'Line' and component['SymbolType_UID'] == -1]:
3802
                item = QEngineeringLineItem.from_database(line)
3803
                if item:
3804
                    item.transfer.onRemoved.connect(self.itemRemoved)
3805
                    self.graphicsView.scene().addItem(item)
3806
                    lines.append(item)
3807

    
3808
                self.progress.setValue(self.progress.value() + 1)
3809

    
3810
            QApplication.processEvents()
3811

    
3812
            for unknown in [component for component in components if
3813
                            component['Name'] == 'Unknown' and component['SymbolType_UID'] == -1]:
3814
                item = QEngineeringUnknownItem.from_database(unknown)
3815
                item.transfer.onRemoved.connect(self.itemRemoved)
3816
                if item is not None:
3817
                    item.transfer.onRemoved.connect(self.itemRemoved)
3818
                    self.graphicsView.scene().addItem(item)
3819

    
3820
                self.progress.setValue(self.progress.value() + 1)
3821

    
3822
            QApplication.processEvents()
3823

    
3824
            for component in [component for component in components if
3825
                              component['Name'] == 'Line NO' and component['SymbolType_UID'] == -1]:
3826
                line_no = QEngineeringLineNoTextItem.from_database(component)
3827
                if type(line_no) is QEngineeringLineNoTextItem:
3828
                    line_no.transfer.onRemoved.connect(self.itemRemoved)
3829
                    self.addTextItemToScene(line_no)
3830
                    line_no_tree_item = self.itemTreeWidget.addTreeItem(self.itemTreeWidget.root, line_no)
3831

    
3832
                    runs = app_doc_data.get_pipe_runs(str(line_no.uid))
3833
                    if not runs: continue
3834
                    for run in runs:
3835
                        line_run = QEngineeringRunItem()
3836
                        run_items = app_doc_data.get_pipe_run_items(run['UID'])
3837
                        for record in run_items:
3838
                            uid = record['Components_UID']
3839
                            run_item = self.graphicsView.findItemByUid(uid)
3840
                            if run_item is not None:
3841
                                run_item._owner = line_no
3842
                                line_run.items.append(run_item)
3843
                        line_run.owner = line_no
3844
                        line_no.runs.append(line_run)
3845

    
3846
                        for run_item in line_run.items:
3847
                            if issubclass(type(run_item), SymbolSvgItem):
3848
                                self.init_add_tree_item(line_no_tree_item, run_item)
3849

    
3850
                self.progress.setValue(self.progress.value() + 1)
3851
            QApplication.processEvents()
3852

    
3853
            for component in [component for component in components if
3854
                              component['Name'] == 'Trim Line NO' and component['SymbolType_UID'] == -1]:
3855
                line_no = QEngineeringTrimLineNoTextItem()
3856
                line_no.uid = uuid.UUID(component['UID'])
3857

    
3858
                runs = app_doc_data.get_pipe_runs(str(line_no.uid))
3859
                if not runs: continue
3860

    
3861
                line_no_tree_item = self.itemTreeWidget.addTreeItem(self.itemTreeWidget.root, line_no)
3862

    
3863
                for run in runs:
3864
                    line_run = QEngineeringRunItem()
3865
                    run_items = app_doc_data.get_pipe_run_items(run['UID'])
3866
                    for record in run_items:
3867
                        uid = record['Components_UID']
3868
                        run_item = self.graphicsView.findItemByUid(uid)
3869
                        if run_item is not None:
3870
                            run_item.owner = line_no
3871
                            line_run.items.append(run_item)
3872
                    line_run.owner = line_no
3873
                    line_no.runs.append(line_run)
3874

    
3875
                    for run_item in line_run.items:
3876
                        if issubclass(type(run_item), SymbolSvgItem):
3877
                            self.init_add_tree_item(line_no_tree_item, run_item)
3878

    
3879
                app_doc_data.tracerLineNos.append(line_no)
3880

    
3881
                self.progress.setValue(self.progress.value() + 1)
3882

    
3883
            for component in [component for component in components if
3884
                              component['Name'] == 'VendorPackage' and component['SymbolType_UID'] == -1]:
3885
                item = QEngineeringVendorItem.from_database(component)
3886
                if item is not None:
3887
                    item.transfer.onRemoved.connect(self.itemRemoved)
3888
                    self.graphicsView.scene().addItem(item)
3889

    
3890
            # connect flow item to line
3891
            for line in lines:
3892
                line.update_arrow()
3893
                app_doc_data.lines.append(line)
3894
            # for flowMark in [item for item in symbols if type(item) is QEngineeringFlowMarkItem]:
3895
            #    for line in lines:
3896
            #        if flowMark.owner is line:
3897
            #            line._flowMark.append(flowMark)
3898
            #            flowMark.setParentItem(line)
3899
            # up to here
3900

    
3901
            """ update scene """
3902
            self.graphicsView.scene().update(self.graphicsView.sceneRect())
3903
            for item in self.graphicsView.scene().items():
3904
                up_progress = False
3905
                # binding items
3906
                if hasattr(item, 'owner'):
3907
                    item.owner
3908
                    up_progress = True
3909
                if hasattr(item, 'connectors'):
3910
                    for connector in item.connectors:
3911
                        connector.connectedItem
3912
                    up_progress = True
3913

    
3914
                if up_progress:
3915
                    self.progress.setValue(self.progress.value() + 1)
3916
            
3917
            for item in self.graphicsView.scene().items():
3918
                item.setVisible(True)
3919

    
3920
        except Exception as ex:
3921
            message = 'error occurred({}) in {}:{}'.format(ex, sys.exc_info()[-1].tb_frame.f_code.co_filename,
3922
                                                           sys.exc_info()[-1].tb_lineno)
3923
            self.addMessage.emit(MessageType.Error, message)
3924
        finally:
3925
            app_doc_data.clearTempDBData()
3926
            self.itemTreeWidget.update_item_count()
3927
            self.itemTreeWidget.expandAll()
3928
            # self.graphicsView.scene().blockSignals(False)
3929

    
3930
    '''
3931
        @brief      load recognition result
3932
        @author     humkyung
3933
        @date       2018.04.??
3934
        @history    humkyung 2018.01.12 parse originalpoint and connectionpoint
3935
                    Jeongwoo 2018.04.17 add QGraphicItem with Rotated text
3936
                    Jeongwoo 2018.04.23 Change to Draw texts on QEngineeringTextItem
3937
                    humkyung 2018.04.23 connect item remove slot to result tree
3938
                    Jeongwoo 2018.04.25 Add if state with QEngineeringNoteItem
3939
                    Jeongwoo 2018.04.26 Change method to create TextItem object with TextItemFactory
3940
                    Jeongwoo 2018.05.03 Change method to draw Svg Item on Scene (svg.addSvgItemToScene)
3941
                    Jeongwoo 2018.05.29 Change method name / Change method to add item / Add Line item
3942
                    Jeongwoo 2018.05.30 Add parameters on SymbolSvgItem.__init__() (parentSymbol, childSymbol) / Change method name / Change XML NODE NAMES
3943
                    Jeongwoo 2018.06.12 Add LineNoTextItem from LINE_NO
3944
                    Jeongwoo 2018.06.14 Add UnknownItem from UNKNOWN
3945
                    Jeongwoo 2018.06.18 Update Scene after all item added
3946
                                        Add connect on unknown item
3947
                                        Add [transfer] for using pyqtSignal
3948
                    kyouho  2018.07.12  Add line property logic
3949
                    humkyung 2018.08.22 show progress while loading xml file
3950
                    2018.11.22      euisung     fix note road
3951
    '''
3952
    def load_recognition_result_from_xml(self, drawing):
3953
        ''' no more used '''
3954
        # Yield successive n-sized
3955
        # chunks from l.
3956
        def divide_chunks(l, n):
3957
            # looping till length l
3958
            for i in range(0, len(l), n):
3959
                yield l[i:i + n]
3960

    
3961
        def update_items(items):
3962
            for item in items:
3963
                # binding items
3964
                item.owner
3965
                for connector in item.connectors:
3966
                    connector.connectedItem
3967

    
3968
            return items
3969

    
3970
        import concurrent.futures as futures
3971
        from xml.etree.ElementTree import Element, SubElement, dump, ElementTree, parse
3972
        from App import App
3973
        from EngineeringRunItem import QEngineeringRunItem
3974
        from QEngineeringTrimLineNoTextItem import QEngineeringTrimLineNoTextItem
3975
        from EngineeringGraphicsLineItem import QEngineeringGraphicsLineItem
3976

    
3977
        app_doc_data = AppDocData.instance()
3978

    
3979
        try:
3980
            file_name = os.path.splitext(os.path.basename(drawing.file_path))[0]
3981
            path = os.path.join(app_doc_data.getCurrentProject().getTempPath(), file_name + '.xml')
3982
            self.graphicsView.scene().blockSignals(True)
3983

    
3984
            symbols = []
3985
            lines = []
3986

    
3987
            xml = parse(path)
3988
            root = xml.getroot()
3989

    
3990
            maxValue = 0
3991
            maxValue = maxValue + len(list(root.iter('SYMBOL'))) - \
3992
                       len(list(root.iterfind('LINENOS/LINE_NO/RUN/SYMBOL'))) - \
3993
                       len(list(root.iterfind('TRIMLINENOS/TRIM_LINE_NO/RUN/SYMBOL')))
3994
            maxValue = maxValue + len(list(root.iterfind('TEXTINFOS/ATTRIBUTE')))
3995
            maxValue = maxValue + len(list(root.iterfind('NOTES/ATTRIBUTE')))
3996
            maxValue = maxValue + len(list(root.iter('LINE_NO')))
3997
            maxValue = maxValue + len(list(root.iter('LINE'))) - \
3998
                       len(list(root.iterfind('LINENOS/LINE_NO/RUN/LINE'))) - \
3999
                       len(list(root.iterfind('TRIMLINENOS/TRIM_LINE_NO/RUN/LINE')))
4000
            maxValue = maxValue + len(list(root.iter('GRAPHICS_LINE')))
4001
            maxValue = maxValue + len(list(root.iter('UNKNOWN')))
4002
            # maxValue = maxValue + len(list(root.iter('SIZETEXT')))
4003
            maxValue = maxValue + len(list(root.iter('TRIM_LINE_NO')))
4004
            maxValue *= 2
4005
            self.progress.setMaximum(maxValue) if maxValue > 0 else None
4006

    
4007
            """ parsing all symbols """
4008
            """
4009
            with futures.ThreadPoolExecutor(max_workers=App.THREAD_MAX_WORKER) as pool:
4010
                future_symbol = {pool.submit(SymbolSvgItem.fromXml, symbol): symbol for symbol in root.find('SYMBOLS').iter('SYMBOL')}
4011

4012
                for future in futures.as_completed(future_symbol):
4013
                    try:
4014
                        item = future.result()
4015
                        if item:
4016
                            if item is not None:
4017
                                item.transfer.onRemoved.connect(self.itemRemoved)
4018
                                symbols.append(item)
4019
                                docData.symbols.append(item)
4020
                                self.addSvgItemToScene(item)
4021
                            else:
4022
                                pt = [float(x) for x in symbol.find('LOCATION').text.split(',')]
4023
                                size = [float(x) for x in symbol.find('SIZE').text.split(',')]
4024
                                angle = float(symbol.find('ANGLE').text)
4025
                                item = QGraphicsBoundingBoxItem(pt[0], pt[1], size[0], size[1])
4026
                                item.isSymbol = True
4027
                                item.angle = angle
4028
                                item.setPen(QPen(Qt.red, 5, Qt.SolidLine))
4029
                                self.graphicsView.scene().addItem(item)
4030
                                item.transfer.onRemoved.connect(self.itemRemoved)
4031
                    except Exception as ex:
4032
                        message = 'error occurred({}) in {}:{}'.format(repr(ex), sys.exc_info()[-1].tb_frame.f_code.co_filename,
4033
                                                                       sys.exc_info()[-1].tb_lineno)
4034

4035
            """
4036
            for symbol in root.find('SYMBOLS').iter('SYMBOL'):
4037
                item = SymbolSvgItem.fromXml(symbol)
4038
                if item is not None:
4039
                    item.transfer.onRemoved.connect(self.itemRemoved)
4040
                    symbols.append(item)
4041
                    #app_doc_data.symbols.append(item)
4042
                    item.addSvgItemToScene(self.graphicsView.scene())
4043
                else:
4044
                    pt = [float(x) for x in symbol.find('LOCATION').text.split(',')]
4045
                    size = [float(x) for x in symbol.find('SIZE').text.split(',')]
4046
                    angle = float(symbol.find('ANGLE').text)
4047
                    item = QGraphicsBoundingBoxItem(pt[0], pt[1], size[0], size[1])
4048
                    item.isSymbol = True
4049
                    item.angle = angle
4050
                    item.setPen(QPen(Qt.red, 5, Qt.SolidLine))
4051
                    self.graphicsView.scene().addItem(item)
4052
                    item.transfer.onRemoved.connect(self.itemRemoved)
4053

    
4054
                self.progress.setValue(self.progress.value() + 1)
4055

    
4056
            QApplication.processEvents()
4057

    
4058
            # parse texts
4059
            for text in root.find('TEXTINFOS').iter('ATTRIBUTE'):
4060
                item = QEngineeringTextItem.fromXml(text)
4061
                if item is not None:
4062
                    uid = text.find('UID')
4063
                    attributeValue = text.find('ATTRIBUTEVALUE')
4064
                    name = text.find('NAME').text
4065
                    item.transfer.onRemoved.connect(self.itemRemoved)
4066
                    item.addTextItemToScene(self.graphicsView.scene())
4067
                    # docData.texts.append(item)
4068

    
4069
                    if name == 'TEXT':
4070
                        if uid is not None and attributeValue is not None:
4071
                            item.uid = uid.text
4072
                            item.attribute = attributeValue.text
4073

    
4074
                self.progress.setValue(self.progress.value() + 1)
4075

    
4076
            QApplication.processEvents()
4077

    
4078
            # note
4079
            for text in root.find('NOTES').iter('ATTRIBUTE'):
4080
                item = QEngineeringTextItem.fromXml(text)
4081
                if item is not None:
4082
                    uid = text.find('UID')
4083
                    attributeValue = text.find('ATTRIBUTEVALUE')
4084
                    name = text.find('NAME').text
4085
                    item.transfer.onRemoved.connect(self.itemRemoved)
4086
                    item.addTextItemToScene(self.graphicsView.scene())
4087

    
4088
                    if name == 'NOTE':
4089
                        if uid is not None:
4090
                            item.uid = uid.text
4091

    
4092
                self.progress.setValue(self.progress.value() + 1)
4093

    
4094
            QApplication.processEvents()
4095

    
4096
            for line in root.find('LINEINFOS').iter('LINE'):
4097
                item = QEngineeringLineItem.fromXml(line)
4098
                if item:
4099
                    item.transfer.onRemoved.connect(self.itemRemoved)
4100
                    self.graphicsView.scene().addItem(item)
4101
                    lines.append(item)
4102

    
4103
                self.progress.setValue(self.progress.value() + 1)
4104

    
4105
            for line in root.find('LINEINFOS').iter('GRAPHICS_LINE'):
4106
                item = QEngineeringGraphicsLineItem.fromXml(line)
4107
                if item:
4108
                    item.transfer.onRemoved.connect(self.itemRemoved)
4109
                    self.graphicsView.scene().addItem(item)
4110

    
4111
                self.progress.setValue(self.progress.value() + 1)
4112

    
4113
            QApplication.processEvents()
4114

    
4115
            for unknown in root.iter('UNKNOWN'):
4116
                item = QEngineeringUnknownItem.fromXml(unknown)
4117
                if item is not None:
4118
                    item.transfer.onRemoved.connect(self.itemRemoved)
4119
                    self.graphicsView.scene().addItem(item)
4120

    
4121
                self.progress.setValue(self.progress.value() + 1)
4122

    
4123
            QApplication.processEvents()
4124

    
4125
            # """ add tree widget """
4126
            # for item in symbols:
4127
            #    docData.symbols.append(item)
4128
            #    self.addSvgItemToScene(item)
4129
            #    self.itemTreeWidget.addTreeItem(self.itemTreeWidget.root, item)
4130

    
4131
            for line_no_node in root.find('LINENOS').iter('LINE_NO'):
4132
                line_no = QEngineeringLineNoTextItem.fromXml(line_no_node)
4133
                if line_no is None: continue
4134
                line_no.transfer.onRemoved.connect(self.itemRemoved)
4135
                line_no.addTextItemToScene(self.graphicsView.scene())
4136
                line_no_tree_item = self.itemTreeWidget.addTreeItem(self.itemTreeWidget.root, line_no)
4137
                if type(line_no) is not QEngineeringLineNoTextItem: continue
4138

    
4139
                runs_node = line_no_node.findall('RUN')
4140
                if runs_node is None: continue
4141

    
4142
                for run_node in runs_node:
4143
                    line_run = QEngineeringRunItem()
4144
                    for child_node in run_node:
4145
                        uidElement = child_node.find('UID')
4146
                        if uidElement is not None:
4147
                            uid = uidElement.text
4148
                            run_item = self.graphicsView.findItemByUid(uid)
4149
                            if run_item is not None:
4150
                                run_item._owner = line_no
4151
                                line_run.items.append(run_item)
4152
                    line_run.owner = line_no
4153
                    line_no.runs.append(line_run)
4154

    
4155
                    for run_item in line_run.items:
4156
                        if issubclass(type(run_item), SymbolSvgItem):
4157
                            self.init_add_tree_item(line_no_tree_item, run_item)
4158

    
4159
                # docData.tracerLineNos.append(line_no)
4160

    
4161
                self.progress.setValue(self.progress.value() + 1)
4162
            QApplication.processEvents()
4163

    
4164
            for trimLineNo in root.iter('TRIM_LINE_NO'):
4165
                line_no = QEngineeringTrimLineNoTextItem()
4166
                line_no.uid = uuid.UUID(trimLineNo.find('UID').text)
4167

    
4168
                runs_node = trimLineNo.findall('RUN')
4169
                if runs_node is None: continue
4170
                line_no_tree_item = self.itemTreeWidget.addTreeItem(self.itemTreeWidget.root, line_no)
4171

    
4172
                for run in runs_node:
4173
                    line_run = QEngineeringRunItem()
4174
                    for child in run:
4175
                        uidElement = child.find('UID')
4176
                        if uidElement is not None:
4177
                            uid = uidElement.text
4178
                            run_item = self.graphicsView.findItemByUid(uid)
4179
                            if run_item is not None:
4180
                                run_item.owner = line_no
4181
                                line_run.items.append(run_item)
4182
                    line_run.owner = line_no
4183
                    line_no.runs.append(line_run)
4184

    
4185
                    for run_item in line_run.items:
4186
                        if issubclass(type(run_item), SymbolSvgItem):
4187
                            self.init_add_tree_item(line_no_tree_item, run_item)
4188

    
4189
                app_doc_data.tracerLineNos.append(line_no)
4190

    
4191
                self.progress.setValue(self.progress.value() + 1)
4192
            QApplication.processEvents()
4193

    
4194
            if root.find('VENDORS') is not None:
4195
                for vendor in root.find('VENDORS').iter('VENDOR'):
4196
                    item = QEngineeringVendorItem.fromXml(vendor)
4197
                    item.transfer.onRemoved.connect(self.itemRemoved)
4198
                    self.graphicsView.scene().addItem(item)
4199

    
4200
            # connect flow item to line
4201
            for line in lines:
4202
                line.update_arrow()
4203
                app_doc_data.lines.append(line)
4204
            # for flowMark in [item for item in symbols if type(item) is QEngineeringFlowMarkItem]:
4205
            #    for line in lines:
4206
            #        if flowMark.owner is line:
4207
            #            line._flowMark.append(flowMark)
4208
            #            flowMark.setParentItem(line)
4209
            # up to here
4210

    
4211
            """
4212
            group_box = QGroupBox("Contact Details")
4213
            number_label = QLabel("Telephone number");
4214
            number_edit = QTextEdit('hello\nthis is ....')
4215
            layout = QFormLayout()
4216
            layout.addRow(number_label, number_edit)
4217
            group_box.setLayout(layout)
4218

4219
            proxy =  ㅐ()
4220
            proxy.setWidget(group_box)
4221
            self.graphicsView.scene().addItem(proxy)  # (group_box, QGraphicsItem.ItemIgnoresTransformations)
4222
            """
4223

    
4224
            """ update scene """
4225
            _items = [_item for _item in self.graphicsView.scene().items() if hasattr(_item, 'owner') or hasattr(_item, 'connectors')]
4226
            if _items:
4227
                items = divide_chunks(_items, App.THREAD_MAX_WORKER if len(_items) > App.THREAD_MAX_WORKER else len(_items))
4228
                with futures.ThreadPoolExecutor(max_workers=App.THREAD_MAX_WORKER) as pool:
4229
                    future_items = {pool.submit(update_items, _items): _items for _items in items}
4230
                    for future in futures.as_completed(future_items):
4231
                        _items = future.result()
4232
                        self.progress.setValue(self.progress.value() + len(_items))
4233

    
4234
            """
4235
            for item in [_item for _item in self.graphicsView.scene().items() if hasattr(_item, 'owner') or hasattr(_item, 'connectors')]:
4236
                up_progress = False
4237
                # binding items
4238
                item.owner
4239
                for connector in item.connectors:
4240
                    connector.connectedItem
4241

4242
                self.progress.setValue(self.progress.value() + 1)
4243
            """
4244

    
4245
            for item in self.graphicsView.scene().items():
4246
                item.setVisible(True)
4247

    
4248
            self.graphicsView.scene().update(self.graphicsView.sceneRect())
4249
        except Exception as ex:
4250
            message = 'error occurred({}) in {}:{}'.format(ex, sys.exc_info()[-1].tb_frame.f_code.co_filename,
4251
                                                           sys.exc_info()[-1].tb_lineno)
4252
            self.addMessage.emit(MessageType.Error, message)
4253
        finally:
4254
            self.itemTreeWidget.update_item_count()
4255
            self.itemTreeWidget.expandAll()
4256
            self.graphicsView.scene().blockSignals(False)
4257

    
4258
    '''
4259
        @brief      Remove added item on same place and Add GraphicsItem
4260
        @author     Jeongwoo
4261
        @date       2018.05.29
4262
        @history    2018.06.18  Jeongwoo    Set Z-index
4263
    '''
4264
    def addLineItemToScene(self, lineItem):
4265
        self.graphicsView.scene().addItem(lineItem)
4266

    
4267
    '''
4268
        @brief      generate output xml file
4269
        @author     humkyung
4270
        @date       2018.04.23
4271
        @history    2018.05.02  Jeongwoo    Show MessageBox when imageviewer doesn't have image
4272
    '''
4273
    def generateOutput(self):
4274
        import XmlGenerator as xg
4275

    
4276
        if not self.graphicsView.hasImage():
4277
            self.showImageSelectionMessageBox()
4278
            return
4279

    
4280
        try:
4281
            appDocData = AppDocData.instance()
4282

    
4283
            # collect items
4284
            appDocData.lines.clear()
4285
            appDocData.lines = [item for item in self.graphicsView.scene().items() if
4286
                                type(item) is QEngineeringLineItem and item.owner is None]
4287

    
4288
            appDocData.symbols.clear()
4289
            appDocData.symbols = [item for item in self.graphicsView.scene().items() if
4290
                                  issubclass(type(item), SymbolSvgItem) and item.owner is None]
4291

    
4292
            appDocData.equipments.clear()
4293
            for item in self.graphicsView.scene().items():
4294
                if type(item) is QEngineeringEquipmentItem:
4295
                    appDocData.equipments.append(item)
4296

    
4297
            appDocData.texts.clear()
4298
            appDocData.texts = [item for item in self.graphicsView.scene().items() if
4299
                                issubclass(type(item), QEngineeringTextItem) and type(
4300
                                    item) is not QEngineeringLineNoTextItem]
4301
            # up to here
4302

    
4303
            appDocData.imgOutput = np.ones((appDocData.activeDrawing.height, appDocData.activeDrawing.width),
4304
                                           np.uint8) * 255
4305
            xg.writeOutputXml(appDocData.imgName, appDocData.activeDrawing.width,
4306
                              appDocData.activeDrawing.height)  # TODO: check
4307
            project = appDocData.getCurrentProject()
4308
            cv2.imwrite(os.path.join(project.getTempPath(), 'OUTPUT.png'), appDocData.imgOutput)
4309
        except Exception as ex:
4310
            message = 'error occurred({}) in {}:{}'.format(ex, sys.exc_info()[-1].tb_frame.f_code.co_filename,
4311
                                                           sys.exc_info()[-1].tb_lineno)
4312
            self.addMessage.emit(MessageType.Error, message)
4313

    
4314
    '''
4315
        @brief      Check Number
4316
        @author     kyouho
4317
        @date       2018.08.20
4318
    '''
4319
    def isNumber(self, num):
4320
        p = re.compile('(^[0-9]+$)')
4321
        result = p.match(num)
4322

    
4323
        if result:
4324
            return True
4325
        else:
4326
            return False
4327

    
4328
    '''
4329
        @brief      find overlap Connector
4330
        @author     kyouho
4331
        @date       2018.08.28
4332
    '''
4333
    def findOverlapConnector(self, connectorItem):
4334
        from shapely.geometry import Point
4335
        from EngineeringConnectorItem import QEngineeringConnectorItem
4336
        itemList = []
4337

    
4338
        x = connectorItem.center()[0]
4339
        y = connectorItem.center()[1]
4340

    
4341
        connectors = [item for item in self.graphicsView.scene().items() if
4342
                      type(item) is QEngineeringConnectorItem and item != connectorItem]
4343
        for connector in connectors:
4344
            if Point(x, y).distance(Point(connector.center()[0], connector.center()[1])) < 5:
4345
                itemList.append(connector.parent)
4346

    
4347
        return itemList
4348

    
4349
    def make_diff_image(self):
4350
        """ make diff image """
4351
        # test
4352

    
4353
        from RecognitionDialog import Worker
4354
        from symbol import Symbol
4355
        import math
4356
        from PIL import Image
4357

    
4358
        app_doc_data = AppDocData.instance()
4359
        img = app_doc_data.imgSrc.copy()
4360

    
4361
        # check break
4362
        symbols = [item for item in self.graphicsView.scene().items() if issubclass(type(item), SymbolSvgItem)]
4363

    
4364
        for symbol in symbols:
4365
            rect = symbol.sceneBoundingRect()
4366
            sName = symbol.name
4367
            sType = symbol.type
4368
            sp = (rect.x(), rect.y())
4369
            w, h = rect.width(), rect.height()
4370
            rotatedAngle = round(math.degrees(symbol.angle))
4371
            detectFlip = symbol.flip
4372

    
4373
            dummySym = Symbol(sName, sType, sp, w, h, 0, 0, 0, rotatedAngle,
4374
                                   1, 0, 1, 0,
4375
                                   ','.join(str(x) for x in [0, 0]),
4376
                                   '/'.join('{},{},{},{}'.format(param[0], param[1], param[2], param[3]) for param in
4377
                                            []),
4378
                                   'dummy', 'dummy', 0, detectFlip=detectFlip,
4379
                                   hasInstrumentLabel=0, text_area='')
4380

    
4381
            Worker.remove_detected_symbol_image(dummySym, img, lock=False)
4382

    
4383
        Image.fromarray(img).show()
4384

    
4385
    #def paintEvent(self, event):
4386
    #    self.refresh_rate += 1
4387
    #    if self.refresh_rate == 3:
4388
    #        super(self.__class__, self).paintEvent(event)
4389
    #        self.refresh_rate = 0
4390

    
4391
if __name__ == '__main__':
4392
    import locale
4393
    from PyQt5.QtCore import QTranslator
4394
    from License import QLicenseDialog
4395
    from ProjectDialog import Ui_Dialog
4396
    from App import App
4397

    
4398
    app = App(sys.argv)
4399
    try:
4400
        if True == QLicenseDialog.check_license_key():
4401
            dlg = Ui_Dialog()
4402
            selectedProject = dlg.showDialog()
4403
            if selectedProject is not None:
4404
                AppDocData.instance().setCurrentProject(selectedProject)
4405
                app._mainWnd = MainWindow.instance()
4406
                app._mainWnd.show()
4407
                sys.exit(app.exec_())
4408
    except Exception as ex:
4409
        print('error occurred({}) in {}:{}'.format(ex, sys.exc_info()[-1].tb_frame.f_code.co_filename,
4410
                                                   sys.exc_info()[-1].tb_lineno))
4411
    finally:
4412
        pass
클립보드 이미지 추가 (최대 크기: 500 MB)