프로젝트

일반

사용자정보

통계
| 개정판:

hytos / DTI_PID / DTI_PID / MainWindow.py @ 2ad3bc31

이력 | 보기 | 이력해설 | 다운로드 (185 KB)

1
# coding: utf-8
2
""" This is MainWindow module """
3

    
4
import sys
5
import os
6
import subprocess
7
from functools import partial
8
import asyncio
9

    
10
sys.path.insert(0, os.path.dirname(os.path.realpath(__file__)))
11
sys.path.insert(0, os.path.join(os.path.dirname(os.path.realpath(__file__)), 'Commands'))
12
from CreateCommand import CreateCommand
13
import CropCommand
14
import AreaOcrCommand
15
import CreateSymbolCommand
16
import AreaZoomCommand
17
import FenceCommand
18
import PlaceLineCommand
19
import PlacePolygonCommand
20

    
21
import cv2
22
import numpy as np
23

    
24
from PyQt5.QtCore import *
25
from PyQt5.QtGui import *
26
from PyQt5.QtWidgets import *
27
from PyQt5.QtSvg import *
28
from PyQt5.QtPrintSupport import QPrintDialog, QPrinter
29

    
30
from PIL import Image
31

    
32
import MainWindow_UI
33
from QtImageViewer import QtImageViewer
34
from SingletonInstance import SingletonInstance
35

    
36
sys.path.insert(0, os.path.dirname(os.path.realpath(__file__)) + '\\Shapes')
37
from EngineeringAbstractItem import QEngineeringAbstractItem
38
from EngineeringPolylineItem import QEngineeringPolylineItem
39
from EngineeringLineItem import QEngineeringLineItem
40
from SymbolSvgItem import SymbolSvgItem
41
from GraphicsBoundingBoxItem import QGraphicsBoundingBoxItem
42
from EngineeringTextItem import QEngineeringTextItem
43
from EngineeringLineNoTextItem import QEngineeringLineNoTextItem
44
from EngineeringNoteItem import QEngineeringNoteItem
45
from QEngineeringSizeTextItem import QEngineeringSizeTextItem
46
from EngineeringUnknownItem import QEngineeringUnknownItem
47
from EngineeringEquipmentItem import QEngineeringEquipmentItem
48
from EngineeringInstrumentItem import QEngineeringInstrumentItem
49
from EngineeringSpecBreakItem import QEngineeringSpecBreakItem
50
from EngineeringErrorItem import QEngineeringErrorItem
51
from EngineeringVendorItem import QEngineeringVendorItem
52
from EngineeringEndBreakItem import QEngineeringEndBreakItem
53
from EngineeringReducerItem import QEngineeringReducerItem
54
from EngineeringFlowMarkItem import QEngineeringFlowMarkItem
55
from QEngineeringTrimLineNoTextItem import QEngineeringTrimLineNoTextItem
56
from AppDocData import *
57
import SymbolTreeWidget, SymbolPropertyTableWidget
58
import SymbolEditorDialog
59
import ItemTreeWidget
60
import ItemPropertyTableWidget
61
from UserInputAttribute import UserInputAttribute
62
from TextItemFactory import TextItemFactory
63
from TrainingImageListDialog import QTrainingImageListDialog
64
from TrainingSymbolImageListDialog import QTrainingSymbolImageListDialog
65
from TextDataListDialog import QTextDataListDialog
66
from ImportTextFromCADDialog import QImportTextFromCADDialog
67
from ImportTextFromPDFDialog import QImportTextFromPDFDialog
68
from SymbolThicknessDialog import QSymbolThicknessDialog
69
from DisplayColors import DisplayColors
70
from DisplayColors import DisplayOptions
71
from RecognitionDialog import QRecognitionDialog
72
import uuid
73
from TcpServer import TcpServer
74

    
75

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

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

    
83

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

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

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

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

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

    
117
        #self.refresh_rate = 0
118

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

    
127
        # save timer
128
        self.save_timer = None
129

    
130
        self._scene = QtImageViewerScene(self)
131

    
132
        self.graphicsView = QtImageViewer(self)
133
        self.graphicsView.setParent(self.centralwidget)
134
        self.graphicsView.useDefaultCommand()  # USE DEFAULT COMMAND
135
        self.graphicsView.setMouseTracking(True)
136
        self.graphicsView.viewport().installEventFilter(self)
137
        self.graphicsView.setScene(self._scene)
138
        self.verticalLayout.addWidget(self.graphicsView)
139

    
140
        # Add Custom TreeWidget
141
        self.symbolTreeWidget = SymbolTreeWidget.QSymbolTreeWidget()
142
        self.symbolTreeWidget.header().hide()
143
        self.verticalLayoutSymbolTree.addWidget(self.symbolTreeWidget)
144
        self.lineEditFilter.textChanged.connect(self.on_search_text_changed)
145

    
146
        from LibraryItem import LibraryItemWidget
147
        self.libraryWidget = LibraryItemWidget(symbol_tree_widget=self.symbolTreeWidget)
148
        self.verticalLayoutLibrary.addWidget(self.libraryWidget)
149
        # Add Custom Property TableWidget
150
        self.propertyTableWidget = SymbolPropertyTableWidget.QSymbolPropertyTableWidget()
151
        self.verticalLayoutSymbolProperty.addWidget(self.propertyTableWidget)
152
        self.symbolTreeWidget.singleClicked.connect(self.propertyTableWidget.getClickedSymbol)
153

    
154
        self.splitterSymbol.setSizes([500, 300])
155

    
156
        # Add Custom Result Tree Widget (Symbol Explorer)
157
        self.itemTreeWidget = ItemTreeWidget.QItemTreeWidget(self.graphicsView)
158
        self.itemTreeWidget.header().hide()
159
        self.symbolExplorerVerticalLayout.addWidget(self.itemTreeWidget)
160

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

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

    
239
        self.delimiter = '"'
240

    
241
        self.resizeDocks({self.dockWidget}, {self.dockWidgetObjectExplorer.sizeHint().width()}, Qt.Horizontal)
242

    
243
        # drawing list
244
        self.treeWidgetDrawingList.setHeaderHidden(False)
245
        self.treeWidgetDrawingList.header().setStretchLastSection(False)
246
        self.treeWidgetDrawingList.setHeaderLabels([self.tr('Name'), self.tr('DateTime')])
247
        self.treeWidgetDrawingList.header().setSectionResizeMode(0, QHeaderView.ResizeToContents)
248
        self.treeWidgetDrawingList.header().setSectionResizeMode(1, QHeaderView.ResizeToContents)
249
        self.treeWidgetDrawingList.header().setSectionsClickable(True)
250
        self.treeWidgetDrawingList.header().sectionClicked.connect(self.sort_drawing_list)
251
        self.treeWidgetDrawingList.itemDoubleClicked.connect(self.open_selected_drawing)
252
        self.load_drawing_list()
253

    
254
        self.ribbon = AppRibbon()
255
        self.setMenuWidget(self.ribbon)
256

    
257
        if not self.ribbon.advanced_mode:
258
            self.pushButtonCreateSymbol.setVisible(False)
259
            self.pushButtonDetectSymbol.setVisible(False)
260

    
261
        configs = app_doc_data.getConfigs('Line List', 'Use Stream No')
262
        if configs and int(configs[0].value) == 1:
263
            pass
264
        else:
265
            self.ribbon.get_pane('Home Visualization').ui.radioButtonByStreamNo.setHidden(True)
266

    
267
        '''
268
        view_pane = self.ribbon.get_pane('View')
269
        shortcut = QShortcut(QKeySequence(Qt.Key_1), view_pane.ui.toolButtonViewImageDrawing)
270
        shortcut.activated.connect(partial(self.on_view_toggle, Qt.Key_1))
271
        shortcut = QShortcut(QKeySequence(Qt.Key_2), view_pane.ui.toolButtonViewText)
272
        shortcut.activated.connect(partial(self.on_view_toggle, Qt.Key_2))
273
        shortcut = QShortcut(QKeySequence(Qt.Key_3), view_pane.ui.toolButtonViewSymbol)
274
        shortcut.activated.connect(partial(self.on_view_toggle, Qt.Key_3))
275
        shortcut = QShortcut(QKeySequence(Qt.Key_4), view_pane.ui.toolButtonViewLine)
276
        shortcut.activated.connect(partial(self.on_view_toggle, Qt.Key_4))
277
        shortcut = QShortcut(QKeySequence(Qt.Key_5), view_pane.ui.toolButtonViewUnknown)
278
        shortcut.activated.connect(partial(self.on_view_toggle, Qt.Key_5))
279
        shortcut = QShortcut(QKeySequence(Qt.Key_6), view_pane.ui.toolButtonViewInconsistency)
280
        shortcut.activated.connect(partial(self.on_view_toggle, Qt.Key_6))
281
        shortcut = QShortcut(QKeySequence(Qt.Key_7), view_pane.ui.toolButtonViewVendorArea)
282
        shortcut.activated.connect(partial(self.on_view_toggle, Qt.Key_7))
283
        shortcut = QShortcut(QKeySequence(96), view_pane.ui.toolButtonViewDrawingOnly)
284
        shortcut.activated.connect(partial(self.on_view_toggle, 96))
285
        '''
286

    
287
        # inconsistency table
288
        self.tableWidgetInconsistency.setColumnCount(3)
289
        self.tableWidgetInconsistency.setHorizontalHeaderLabels(['Owner', 'Type', 'Message'])
290
        self.tableWidgetInconsistency.setEditTriggers(QAbstractItemView.NoEditTriggers)
291
        self.tableWidgetInconsistency.itemClicked.connect(self.inconsistencyItemClickEvent)
292
        self.tableWidgetInconsistency.keyPressEvent = self.inconsistencyTableKeyPressEvent
293
        self.tableWidgetInconsistency.setSortingEnabled(True)
294

    
295
        # memo tab
296
        self.on_memo_refresh_clicked()
297

    
298
        self.read_settings()
299

    
300
    @property
301
    def title(self) -> str:
302
        """return window title"""
303

    
304
        from App import App
305

    
306
        app_doc_data = AppDocData.instance()
307
        project = app_doc_data.getCurrentProject()
308
        version = QCoreApplication.applicationVersion()
309
        title = f"{App.NAME}({version}) - {project.name}: " \
310
                f"{app_doc_data.activeDrawing.name if app_doc_data.activeDrawing else ''}"
311
        #title = f"{App.NAME} : ID2 " \
312
        #        f"{app_doc_data.activeDrawing.name if app_doc_data.activeDrawing else ''}"
313

    
314
        return title
315

    
316
    @property
317
    def scene(self):
318
        """getter scene"""
319
        return self._scene
320

    
321
    def eventFilter(self, source, event):
322
        """display mouse position of graphics view"""
323
        try:
324
            if event.type() == QEvent.MouseMove:
325
                self.current_pos = self.graphicsView.mapToScene(event.pos())
326
                self._label_mouse.setText(
327
                    'mouse pos : ({},{})'.format(round(self.current_pos.x()), round(self.current_pos.y())))
328
        except Exception as ex:
329
            message = 'error occurred({}) in {}:{}'.format(ex, sys.exc_info()[-1].tb_frame.f_code.co_filename,
330
                                                           sys.exc_info()[-1].tb_lineno)
331
            self.addMessage.emit(MessageType.Error, message)
332

    
333
        return QWidget.eventFilter(self, source, event)
334

    
335
    def closeEvent(self, event):
336
        """save geometry and state and ask user to save drawing which is modified"""
337

    
338
        if self.save_drawing_if_necessary():
339
            event.ignore()
340
            return
341

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

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

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

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

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

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

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

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

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

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

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

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

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

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

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

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

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

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

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

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

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

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

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

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

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

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

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

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

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

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

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

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

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

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

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

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

    
580
        self.itemTreeWidget.InitLineNoItems()
581

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

    
600

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

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

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

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

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

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

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

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

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

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

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

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

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

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

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

    
696
        return
697

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

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

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

    
729
        from TextItemEditDialog import QTextItemEditDialog
730

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

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

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

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

    
749
        from ReplaceSymbolDialog import QReplaceSymbolDialog
750

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

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

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

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

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

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

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

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

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

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

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

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

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

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

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

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

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

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

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

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

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

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

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

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

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

    
928
                # connect spec break
929
                self.on_connect_spec_breaks(spec_breaks, texts, symbols, lines)
930
                # up to here
931
            except Exception as ex:
932
                message = f"error occurred({repr(ex)}) in {sys.exc_info()[-1].tb_frame.f_code.co_filename}:" \
933
                          f"{sys.exc_info()[-1].tb_lineno}"
934
                self.addMessage.emit(MessageType.Error, message)
935

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

    
938
    def on_connect_spec_breaks(self, spec_breaks, texts=None, symbols=None, lines=None):
939
        from CodeTables import CodeTable
940
        from shapely.geometry import Point
941

    
942
        app_doc_data = AppDocData.instance()
943
        
944
        try:
945
            if not texts or not symbols or not lines:
946
                texts = [item for item in self.graphicsView.scene().items() if type(item) is QEngineeringTextItem and item.owner is None]
947
                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]
948
                lines = sorted([item for item in self.graphicsView.scene().items() if type(item) is QEngineeringLineItem], key=lambda param: param.length(), reverse=True)
949

    
950
            usedTexts = []
951
            attribute_table_item_list = []
952
            dist_range = None
953
            specBreakAttrsFull = [attr for attr in app_doc_data.getSymbolAttribute('Segment Breaks') if attr.AttributeType == 'Spec' or attr.AttributeType == 'String']
954

    
955
            for attr in specBreakAttrsFull:
956
                if attr.AttributeType != 'Spec' or attr.Attribute == 'NominalDiameter':
957
                    continue
958

    
959
                table = CodeTable.instance(attr.Attribute)
960
                items = []
961
                for text in texts:
962
                    if text not in usedTexts and table.find_match_exactly(text.text()):
963
                        usedTexts.append(text)
964
                        items.append(text)
965

    
966
                if len(items) >= 2:
967
                    attribute_table_item_list.append([attr.Attribute, items])
968

    
969
            usedItemPairs = []
970
            for spec_break in spec_breaks:
971
                if not dist_range:
972
                    dist_range = max(spec_break.sceneBoundingRect().height(), spec_break.sceneBoundingRect().width())
973

    
974
                attrs = spec_break.getAttributes()
975
                up = [attr.AssocItem for attr in attrs if attr.Attribute == 'UpStream']
976
                down = [attr.AssocItem for attr in attrs if attr.Attribute == 'DownStream']
977
                if (up and up[0]) or (down and down[0]):
978
                    usedItemPairs.append([up, down])
979

    
980
            for spec_break in spec_breaks:
981
                attrs = spec_break.getAttributes()
982
                up = [attr.AssocItem for attr in attrs if attr.Attribute == 'UpStream']
983
                down = [attr.AssocItem for attr in attrs if attr.Attribute == 'DownStream']
984
                if (up and up[0]) or (down and down[0]):
985
                    continue
986

    
987
                originPoint = Point(spec_break.origin[0], spec_break.origin[1])
988
                minD = sys.maxsize
989
                upItem = None
990
                downItem = None
991

    
992
                for symbol in symbols:
993
                    for conn in symbol.connectors:
994
                        dist = originPoint.distance(Point(conn.sceneConnectPoint[0], conn.sceneConnectPoint[1]))
995
                        if not conn.connectedItem or not issubclass(type(conn.connectedItem), QEngineeringAbstractItem) or \
996
                            [pair for pair in usedItemPairs if symbol in pair and conn.connectedItem in pair] or dist > dist_range or dist > minD:
997
                            continue
998

    
999
                        minD = dist
1000
                        upItem = symbol
1001
                        downItem = conn.connectedItem
1002

    
1003
                for line in lines:
1004
                    for conn in line.connectors:
1005
                        dist = originPoint.distance(Point(conn.sceneConnectPoint[0], conn.sceneConnectPoint[1]))
1006
                        if not conn.connectedItem or not issubclass(type(conn.connectedItem), QEngineeringAbstractItem) or \
1007
                            conn._connected_at != QEngineeringAbstractItem.CONNECTED_AT_BODY  or \
1008
                            [pair for pair in usedItemPairs if line in pair and conn.connectedItem in pair] or dist > dist_range or dist > minD + 1:
1009
                            continue
1010

    
1011
                        minD = dist
1012
                        upItem = line
1013
                        downItem = conn.connectedItem
1014

    
1015
                if upItem and downItem:
1016
                    for key in attrs.keys():
1017
                        if key.Attribute == 'UpStream':
1018
                            attrs[key] = str(upItem)
1019
                            spec_break.add_assoc_item(upItem, key.AttrAt, force=True)
1020
                            key.AssocItem = upItem
1021
                            key.Freeze = True
1022
                        elif key.Attribute == 'DownStream':
1023
                            attrs[key] = str(downItem)
1024
                            spec_break.add_assoc_item(downItem, key.AttrAt, force=True)
1025
                            key.AssocItem = downItem
1026
                            key.Freeze = True
1027
                    spec_break.set_property('Freeze', True)
1028
                    spec_break.set_property('Show', True)
1029

    
1030
                    usedItemPairs.append([upItem, downItem])
1031

    
1032
                    for attribute_table_item in attribute_table_item_list:
1033
                        upText = None
1034
                        downText = None
1035
                        attribute_table_item[1].sort(key=lambda x: originPoint.distance(Point(x.center().x(), x.center().y())))
1036
                        if originPoint.distance(Point(attribute_table_item[1][1].center().x(), attribute_table_item[1][1].center().y())) < dist_range:
1037
                            if issubclass(type(upItem), SymbolSvgItem):
1038
                                symbolPoint = Point(upItem.origin[0], upItem.origin[1])
1039
                                #if symbolPoint.distance(Point(attribute_table_item[1][0].sceneBoundingRect().left(), attribute_table_item[1][0].sceneBoundingRect().top())) < \
1040
                                #    symbolPoint.distance(Point(attribute_table_item[1][1].sceneBoundingRect().left(), attribute_table_item[1][1].sceneBoundingRect().top())):
1041
                                if symbolPoint.distance(Point(attribute_table_item[1][0].center().x(), attribute_table_item[1][0].center().y())) < \
1042
                                    symbolPoint.distance(Point(attribute_table_item[1][1].center().x(), attribute_table_item[1][1].center().y())):
1043
                                    upText = attribute_table_item[1][0]
1044
                                    downText = attribute_table_item[1][1]
1045
                                else:
1046
                                    upText = attribute_table_item[1][1]
1047
                                    downText = attribute_table_item[1][0]
1048
                            elif issubclass(type(downItem), SymbolSvgItem):
1049
                                symbolPoint = Point(downItem.origin[0], downItem.origin[1])
1050
                                #if symbolPoint.distance(Point(attribute_table_item[1][0].sceneBoundingRect().left(), attribute_table_item[1][0].sceneBoundingRect().top())) < \
1051
                                #    symbolPoint.distance(Point(attribute_table_item[1][1].sceneBoundingRect().left(), attribute_table_item[1][1].sceneBoundingRect().top())):
1052
                                if symbolPoint.distance(Point(attribute_table_item[1][0].center().x(), attribute_table_item[1][0].center().y())) < \
1053
                                    symbolPoint.distance(Point(attribute_table_item[1][1].center().x(), attribute_table_item[1][1].center().y())):
1054
                                    downText = attribute_table_item[1][0]
1055
                                    upText = attribute_table_item[1][1]
1056
                                else:
1057
                                    downText = attribute_table_item[1][1]
1058
                                    upText = attribute_table_item[1][0]
1059
                            else:
1060
                                if upItem.length() < downItem.length():
1061
                                    linePoint = Point(upItem.center().x(), upItem.center().y())
1062
                                    if linePoint.distance(Point(attribute_table_item[1][0].center().x(), attribute_table_item[1][0].center().y())) < \
1063
                                        linePoint.distance(Point(attribute_table_item[1][1].center().x(), attribute_table_item[1][1].center().y())):
1064
                                        upText = attribute_table_item[1][0]
1065
                                        downText = attribute_table_item[1][1]
1066
                                    else:
1067
                                        upText = attribute_table_item[1][1]
1068
                                        downText = attribute_table_item[1][0]
1069
                                else:
1070
                                    linePoint = Point(downItem.center().x(), downItem.center().y())
1071
                                    if linePoint.distance(Point(attribute_table_item[1][0].center().x(), attribute_table_item[1][0].center().y())) < \
1072
                                        linePoint.distance(Point(attribute_table_item[1][1].center().x(), attribute_table_item[1][1].center().y())):
1073
                                        downText = attribute_table_item[1][0]
1074
                                        upText = attribute_table_item[1][1]
1075
                                    else:
1076
                                        downText = attribute_table_item[1][1]
1077
                                        upText = attribute_table_item[1][0]
1078

    
1079
                        if upText and downText:
1080
                            for full in specBreakAttrsFull:
1081
                                if full.Attribute == attribute_table_item[0]:
1082
                                    attrs[full] = [upText.text(), downText.text()]
1083
                                    attribute_table_item[1].remove(upText)
1084
                                    attribute_table_item[1].remove(downText)
1085
                                    break
1086

    
1087
                            stream_line = [upItem, downItem]
1088
                            stream_track = [downItem, upItem]
1089
                            stream_res = [False, False]
1090
                            for index in range(len(stream_line)):
1091
                                while True:
1092
                                    if type(stream_line[index]) is QEngineeringLineItem:
1093
                                        stream_res[index] = True
1094
                                        break
1095
                                    else:
1096
                                        find_next = False
1097
                                        connected_count = 0
1098
                                        for connectorr in stream_line[index].connectors:
1099
                                            connected_count += 1
1100
                                            if connectorr.connectedItem and stream_track[index] is not connectorr.connectedItem and \
1101
                                                    stream_line[index].next_connected(stream_track[index], connectorr.connectedItem):
1102
                                                stream_track[index] = stream_line[index]
1103
                                                stream_line[index] = connectorr.connectedItem
1104
                                                find_next = True
1105
                                                break
1106

    
1107
                                        if not find_next:
1108
                                            # prevent infinite loop
1109
                                            if connected_count == 2:
1110
                                                for connectorr in stream_line[index].connectors:
1111
                                                    if connectorr.connectedItem and not connectorr.connectedItem is stream_track[index]:
1112
                                                        stream_line[index] = connectorr.connectedItem
1113
                                                        stream_track[index] = stream_line[index]
1114
                                                        find_next = True
1115
                                                        break
1116
                                                if not find_next:
1117
                                                    break
1118
                                            else:
1119
                                                break
1120

    
1121
                            if stream_res[0] and stream_res[1]:
1122
                                up_down_find = [upText, downText]
1123

    
1124
                                for index in range(len(stream_line)):
1125
                                    _attrs = stream_line[index].getAttributes()
1126
                                    for key in _attrs.keys():
1127
                                        if key.Attribute == attribute_table_item[0]:
1128
                                            _attrs[key] = up_down_find[index].text()
1129
                                            key.AssocItem = up_down_find[index]
1130
                                            stream_line[index].add_assoc_item(up_down_find[index],
1131
                                                                                key.AttrAt, force=True)
1132
                                            up_down_find[index].owner = stream_line[index]
1133
                                            key.Freeze = True
1134
                                            break
1135

    
1136
            return True
1137
        except Exception as ex:
1138
            message = f"error occurred({repr(ex)}) in {sys.exc_info()[-1].tb_frame.f_code.co_filename}:" \
1139
                        f"{sys.exc_info()[-1].tb_lineno}"
1140
            self.addMessage.emit(MessageType.Error, message)
1141

    
1142
            return False
1143

    
1144

    
1145
    def on_recognize_line(self):
1146
        """recognize lines in selected area"""
1147
        from RecognizeLineCommand import RecognizeLineCommand
1148

    
1149
        if not self.graphicsView.hasImage():
1150
            self.actionOCR.setChecked(False)
1151
            self.showImageSelectionMessageBox()
1152
            return
1153

    
1154
        cmd = RecognizeLineCommand(self.graphicsView)
1155
        cmd.onSuccess.connect(self.on_success_to_recognize_line)
1156
        cmd.onRejected.connect(self.onCommandRejected)
1157
        self.graphicsView.command = cmd
1158

    
1159
    '''
1160
            @brief      show text recognition dialog
1161
            @author     humkyung
1162
            @date       2018.08.08
1163
    '''
1164
    def on_success_to_recognize_line(self, x, y, width, height):
1165
        import io
1166
        from LineDetector import LineDetector
1167
        from EngineeringGraphicsLineItem import QEngineeringGraphicsLineItem
1168

    
1169
        try:
1170
            image = self.graphicsView.image().copy(x, y, width, height)
1171
            buffer = QBuffer()
1172
            buffer.open(QBuffer.ReadWrite)
1173
            image.save(buffer, "PNG")
1174
            pyImage = Image.open(io.BytesIO(buffer.data()))
1175
            img = np.array(pyImage)
1176
            img = cv2.cvtColor(img, cv2.COLOR_BGR2GRAY)
1177

    
1178
            detector = LineDetector(img)
1179
            lines = detector.detect_line_without_symbol()
1180
            for line in lines:
1181
                vertices = [[line[0][0] + x, line[0][1] + y], [line[1][0] + x, line[1][1] + y]]
1182
                line_item = QEngineeringGraphicsLineItem(vertices)
1183
                self.graphicsView.scene().addItem(line_item)
1184

    
1185
        except Exception as ex:
1186
            message = 'error occurred({}) in {}:{}'.format(repr(ex), sys.exc_info()[-1].tb_frame.f_code.co_filename,
1187
                                                           sys.exc_info()[-1].tb_lineno)
1188
            self.addMessage.emit(MessageType.Error, message)
1189

    
1190
    def display_number_of_items(self):
1191
        """display count of symbol, line, text"""
1192

    
1193
        items = [item for item in self.graphicsView.scene().items() if type(item) is QEngineeringUnknownItem]
1194
        if len(items) > 0:
1195
            self.labelStatus.setText(
1196
                "<font color='red'>" + self.tr('Unrecognition') + " : {}</font>".format(len(items)))
1197
        else:
1198
            self.labelStatus.setText(
1199
                "<font color='black'>" + self.tr('Unrecognition') + " : {}</font>".format(len(items)))
1200

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

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

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

    
1211
        self.itemTreeWidget.sceneChanged(self.graphicsView.scene().items())
1212

    
1213
    def dbUpdate(self):
1214
        """ no more used """
1215
        """db update when save or recognition"""
1216

    
1217
        try:
1218
            appDocData = AppDocData.instance()
1219
            items = appDocData.allItems
1220

    
1221
            '''
1222
            titleBlockProps = appDocData.getTitleBlockProperties()
1223
            titleBlockItems = []
1224
            for item in items:
1225
                # if type(item) is QEngineeringLineNoTextItem:
1226
                #    item.saveLineData()
1227
                if type(item) is QEngineeringTextItem:
1228
                    for titleBlockProp in titleBlockProps:
1229
                        if item.area == titleBlockProp[0]:
1230
                            titleBlockItems.append(item)
1231
            '''
1232

    
1233
            # unknown item is not saved now for performance
1234
            db_items = [item for item in items if issubclass(type(item), QEngineeringAbstractItem) and
1235
                        type(item) is not QGraphicsBoundingBoxItem and
1236
                        type(item) is not QEngineeringErrorItem and
1237
                        type(item) is not QEngineeringLineNoTextItem and
1238
                        type(item) is not QEngineeringUnknownItem]
1239
            db_items.extend([item for item in items if type(item) is QEngineeringLineNoTextItem])
1240
            db_items.extend([line for line in appDocData.tracerLineNos if type(line) is QEngineeringTrimLineNoTextItem])
1241
            # db_items.extend(titleBlockItems)
1242
            configs = appDocData.getConfigs('Data Save', 'Unknown Xml Only')
1243
            if configs and int(configs[0].value) is -1:
1244
                db_items.extend([item for item in items if type(item) is QEngineeringUnknownItem])
1245

    
1246
            '''
1247
            dbItems = [item for item in items if
1248
                       type(item) is QEngineeringInstrumentItem or type(item) is QEngineeringEquipmentItem or type(
1249
                           item) is QEngineeringReducerItem or \
1250
                       type(item) is QEngineeringNoteItem or type(item) is SymbolSvgItem or type(
1251
                           item) is QEngineeringLineNoTextItem or type(
1252
                           item) is QEngineeringVendorItem] + titleBlockItems
1253
            '''
1254
            appDocData.saveToDatabase(db_items)
1255
        except Exception as ex:
1256
            message = 'error occurred({}) in {}:{}'.format(ex, sys.exc_info()[-1].tb_frame.f_code.co_filename,
1257
                                                           sys.exc_info()[-1].tb_lineno)
1258
            self.addMessage.emit(MessageType.Error, message)
1259

    
1260
    def save_drawing_if_necessary(self):
1261
        """ask to user to save drawing or not when drawing is modified"""
1262

    
1263
        app_doc_data = AppDocData.instance()
1264
        if app_doc_data.activeDrawing and app_doc_data.activeDrawing.modified:
1265
            #if QMessageBox.Yes == QMessageBox.question(self, self.tr("Question"),
1266
            #                                           self.tr("Do you want to save drawing?"),
1267
            #                                           QMessageBox.Yes | QMessageBox.No):
1268
            #    self.actionSaveCliked()
1269
            #    return True
1270
            if QMessageBox.Ignore == QMessageBox.question(self, self.tr('Continue?'),
1271
                                                       self.tr('Changes may not have been saved.'),
1272
                                                       QMessageBox.Ignore | QMessageBox.Cancel):
1273
                return False
1274
            return True
1275

    
1276
    def actionSaveCliked(self):
1277
        """
1278
        save current drawing
1279
        @return:
1280
        """
1281
        from EngineeringAbstractItem import QEngineeringAbstractItem
1282
        from SaveWorkCommand import SaveWorkCommand
1283

    
1284
        try:
1285
            home_pane = self.ribbon.get_pane('Home File')
1286
            if not home_pane.ui.toolButtonFileSave.isEnabled():
1287
                return
1288

    
1289
            home_pane.ui.toolButtonFileSave.setEnabled(False)
1290

    
1291
            # save alarm
1292
            self.save_alarm_enable(False)
1293

    
1294
            app_doc_data = AppDocData.instance()
1295
            if app_doc_data.imgName is None:
1296
                self.showImageSelectionMessageBox()
1297
                return
1298

    
1299
            app_doc_data.clearItemList(False)
1300

    
1301
            #items = self.graphicsView.scene().items()
1302

    
1303
            self._save_work_cmd = SaveWorkCommand(self.graphicsView.scene())
1304
            self._save_work_cmd.show_progress.connect(self.progress_bar.setValue)
1305
            self._save_work_cmd.display_message.connect(self.onAddMessage)
1306
            self._save_work_cmd.finished.connect(self.save_finished)
1307

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

    
1314
    def save_finished(self):
1315
        """
1316
        reload drawing list when save is finished
1317
        @return: None
1318
        """
1319

    
1320
        try:
1321
            self._save_work_cmd.show_progress.emit(100)
1322
            QMessageBox.about(self.graphicsView, self.tr('Information'), self._save_work_cmd.resultStr)
1323
            self.load_drawing_list()
1324

    
1325
            app_doc_data = AppDocData.instance()
1326
            app_doc_data.activeDrawing.modified = False
1327
            title = self.windowTitle()
1328
            self.setWindowTitle(title[:-1] if title[-1] == '*' else title)
1329

    
1330
            # save alarm
1331
            self.save_alarm_enable(True)
1332
        finally:
1333
            home_pane = self.ribbon.get_pane('Home File')
1334
            home_pane.ui.toolButtonFileSave.setEnabled(True)
1335

    
1336
    '''
1337
        @brief      refresh resultPropertyTableWidget
1338
        @author     kyouho
1339
        @date       2018.07.19
1340
    '''
1341
    def refreshResultPropertyTableWidget(self):
1342
        items = self.graphicsView.scene().selectedItems()
1343
        if len(items) == 1:
1344
            self.resultPropertyTableWidget.show_item_property(items[0])
1345

    
1346
    '''
1347
        @brief  add message listwidget
1348
        @author humkyung
1349
        @date   2018.07.31
1350
    '''
1351
    def onAddMessage(self, messageType, message):
1352
        from AppDocData import MessageType
1353

    
1354
        try:
1355
            current = QDateTime.currentDateTime()
1356

    
1357
            item = QListWidgetItem('{}: {}'.format(current.toString('hh:mm:ss'), message))
1358
            item.setFlags(item.flags() | Qt.ItemIsEditable)
1359
            if messageType == MessageType.Error:
1360
                item.setBackground(Qt.red)
1361
            elif messageType == 'check':
1362
                item.setBackground(Qt.yellow)
1363

    
1364
            self.listWidgetLog.insertItem(0, item)
1365
        except Exception as ex:
1366
            print('error occurred({}) in {}:{}'.format(ex, sys.exc_info()[-1].tb_frame.f_code.co_filename,
1367
                                                       sys.exc_info()[-1].tb_lineno))
1368

    
1369
    def on_clear_log(self):
1370
        """clear log"""
1371
        self.listWidgetLog.clear()
1372

    
1373
    def onRotate(self, action):
1374
        """rotate a selected symbol"""
1375
        selected = [item for item in self.graphicsView.scene().selectedItems() if issubclass(type(item), SymbolSvgItem)]
1376
        if len(selected) == 1:
1377
            from RotateCommand import RotateCommand
1378
            self.graphicsView.scene()._undo_stack.push(RotateCommand(self.graphicsView.scene(), selected))
1379

    
1380
    def onAreaZoom(self):
1381
        """Area Zoom"""
1382
        visualization_pane = self.ribbon.get_pane('Home Visualization')
1383

    
1384
        self.update_action_group(visualization_pane.ui.toolButtonZoom)
1385
        if visualization_pane.ui.toolButtonZoom.isChecked():
1386
            cmd = AreaZoomCommand.AreaZoomCommand(self.graphicsView)
1387
            cmd.onRejected.connect(self.onCommandRejected)
1388
            self.graphicsView.command = cmd
1389

    
1390
    def onVendor(self, action):
1391
        """make vendor/equipment package area"""
1392

    
1393
        pane = self.ribbon.get_pane('Home')
1394
        if not self.graphicsView.hasImage():
1395
            pane.ui.toolButtonVendor.setChecked(False)
1396
            self.showImageSelectionMessageBox()
1397
            return
1398

    
1399
        pane = self.ribbon.get_pane('Home')
1400
        self.update_action_group(pane.ui.toolButtonVendor)
1401
        checked = pane.ui.toolButtonVendor.isChecked()
1402
        if not hasattr(pane.ui.toolButtonVendor, 'tag'):
1403
            pane.ui.toolButtonVendor.tag = PlacePolygonCommand.PlacePolygonCommand(self.graphicsView)
1404
            pane.ui.toolButtonVendor.tag.onSuccess.connect(self.onVendorCreated)
1405
            pane.ui.toolButtonVendor.tag.onRejected.connect(self.onCommandRejected)
1406

    
1407
        self.graphicsView.command = pane.ui.toolButtonVendor.tag
1408

    
1409
    def onVendorCreated(self):
1410
        """add created vendor polygon area to scene"""
1411

    
1412
        try:
1413
            vendor_tool = self.ribbon.get_pane('Home').ui.toolButtonVendor
1414
            package_combo = self.ribbon.get_pane('Home').ui.comboBoxPackage
1415
            count = len(vendor_tool.tag._polyline._vertices)
1416
            if count > 2:
1417
                points = []
1418
                for point in vendor_tool.tag._polyline._vertices:
1419
                    points.append(QPoint(round(point[0]), round(point[1])))
1420
                polygon = QPolygonF(points)
1421
                item = QEngineeringVendorItem(polygon, pack_type=package_combo.currentText())
1422
                item.area = 'Drawing'
1423
                item.transfer.onRemoved.connect(self.itemRemoved)
1424
                self.graphicsView.scene().addItem(item)
1425
        finally:
1426
            self.graphicsView.scene().removeItem(vendor_tool.tag._polyline)
1427
            vendor_tool.tag.reset()
1428

    
1429
    def fitWindow(self, view_rect: QRectF = QRectF()):
1430
        """Fit Window"""
1431
        self.graphicsView.useDefaultCommand()
1432
        self.graphicsView.zoomImageInit()
1433

    
1434
        visualization_pane = self.ribbon.get_pane('Home Visualization')
1435
        self.update_action_group(visualization_pane.ui.toolButtonFitWindow)
1436
        if view_rect:
1437
            self.graphicsView.zoom_rect(view_rect)
1438

    
1439
    def on_toggle_lock_axis(self):
1440
        """toggle lock axis"""
1441
        from EngineeringPolylineItem import QEngineeringPolylineItem
1442

    
1443
        visualization_pane = self.ribbon.get_pane('Home Visualization')
1444
        if self.sender() is not visualization_pane.ui.toolButtonLockAxis:
1445
            checked = visualization_pane.ui.toolButtonLockAxis.isChecked()
1446
            visualization_pane.ui.toolButtonLockAxis.setChecked(not checked)
1447

    
1448
        checked = visualization_pane.ui.toolButtonLockAxis.isChecked()
1449
        QEngineeringPolylineItem.DRAWING_MODE = QEngineeringPolylineItem.AXIS_MODE if checked else \
1450
            QEngineeringPolylineItem.FREE_MODE
1451

    
1452
    def scene_changed(self):
1453
        """update modified flag"""
1454

    
1455
        self.display_number_of_items()
1456

    
1457
        app_doc_data = AppDocData.instance()
1458
        app_doc_data.activeDrawing.modified = True
1459
        title = self.windowTitle()
1460
        self.setWindowTitle(title if title[-1] == '*' else title + '*')
1461

    
1462
    def onConvertPDFToImage(self):
1463
        """convert to selected pdf to image"""
1464
        import os
1465

    
1466
        try:
1467
            file_path = os.path.join(os.path.dirname(os.path.realpath(__file__)), 'bin64', 'PDF_TO_IMAGE.exe')
1468
            os.startfile(file_path)
1469
        except Exception as ex:
1470
            message = 'error occurred({}) in {}:{}'.format(ex, sys.exc_info()[-1].tb_frame.f_code.co_filename,
1471
                                                           sys.exc_info()[-1].tb_lineno)
1472
            self.addMessage.emit(MessageType.Error, message)
1473

    
1474
    def on_import_text_from_cad_for_instrument(self):
1475
        """ import text from cad for instrument """
1476
        try:
1477
            self.onCommandRejected()
1478
            dialog = QImportTextFromPDFDialog(self)
1479
            dialog.show()
1480
            dialog.exec_()
1481
        except Exception as ex:
1482
            message = f"error occurred({repr(ex)}) in {sys.exc_info()[-1].tb_frame.f_code.co_filename}:" \
1483
                      f"{sys.exc_info()[-1].tb_lineno}"
1484
            self.addMessage.emit(MessageType.Error, message)
1485

    
1486
    def on_import_text_from_cad(self):
1487
        """ import text from cad """
1488
        try:
1489
            self.onCommandRejected()
1490
            dialog = QImportTextFromCADDialog(self)
1491
            dialog.show()
1492
            dialog.exec_()
1493
        except Exception as ex:
1494
            message = f"error occurred({repr(ex)}) in {sys.exc_info()[-1].tb_frame.f_code.co_filename}:" \
1495
                      f"{sys.exc_info()[-1].tb_lineno}"
1496
            self.addMessage.emit(MessageType.Error, message)
1497

    
1498
    def on_export_PDF_ARS(self, path):
1499
        drawingList = self.treeWidgetDrawingList.topLevelItem(0)
1500
        for idx in range(drawingList.childCount()):
1501
            child = drawingList.child(idx)
1502
            child.setCheckState(0, Qt.Checked)
1503

    
1504
        self.on_export_PDF(path)
1505

    
1506
    def on_export_PDF(self, path=None):
1507
        # save alarm
1508
        self.save_alarm_enable(False)
1509
        
1510
        #if not self.graphicsView.hasImage():
1511
        #    self.showImageSelectionMessageBox()
1512
        #    return
1513

    
1514
        try:
1515
            app_doc_data = AppDocData.instance()
1516
            current_drawing = None
1517

    
1518
            if self.graphicsView.hasImage():
1519
                current_drawing = app_doc_data.activeDrawing
1520

    
1521
            # get checked drawings
1522
            drawing_top = self.treeWidgetDrawingList.topLevelItem(0)
1523
            count = drawing_top.childCount()
1524
            checked_drawings = {}
1525
            for idx in range(count):
1526
                child = drawing_top.child(idx)
1527
                if child.checkState(0) == Qt.Checked and child.data(Qt.UserRole, 0):
1528
                    checked_drawings[child.data(Qt.UserRole, 0)] = child
1529
            # up to here
1530

    
1531
            # if there is no checked drawing
1532
            if current_drawing and not checked_drawings:
1533
                for idx in range(count):
1534
                    child = drawing_top.child(idx)
1535
                    if child.data(Qt.UserRole, 0) is current_drawing:
1536
                        checked_drawings[child.data(Qt.UserRole, 0)] = child
1537

    
1538
            if not checked_drawings:
1539
                self.showImageSelectionMessageBox()
1540
                return
1541
                
1542
            project = app_doc_data.getCurrentProject()
1543

    
1544
            if current_drawing and len(checked_drawings) == 1:
1545
                name = os.path.join(project.getTempPath(), os.path.splitext(app_doc_data.activeDrawing.name)[0])
1546
                
1547
                options = QFileDialog.Options()
1548
                options |= QFileDialog.DontUseNativeDialog
1549
                file_name, _ = QFileDialog.getSaveFileName(self, "Export PDF", name, "pdf files(*.pdf)", options=options)
1550
                name += '.png'
1551
                if file_name:
1552
                    self.save_PDF(name)
1553

    
1554
            elif len(checked_drawings) > 1:
1555
                name = os.path.join(project.getTempPath(), 'Select a Folder')
1556
                
1557
                file_name = None
1558
                if not path:
1559
                    options = QFileDialog.Options()
1560
                    options |= QFileDialog.DontUseNativeDialog
1561
                    file_name, _ = QFileDialog.getSaveFileName(self, "Export PDF", name, "pdf files(*.pdf)", options=options)
1562

    
1563
                if file_name or path:
1564
                    if file_name:
1565
                        directory = os.path.dirname(file_name)
1566
                    else:
1567
                        directory = path
1568

    
1569
                    self.progress_bar.setMaximum(len(checked_drawings) + 2)
1570
                    count = 1
1571
                    self.progress_bar.setValue(count)
1572

    
1573
                    for drawing in checked_drawings.keys():
1574
                        self.open_image_drawing(drawing, force=True, ocrUnknown=False, timer=False, pdf=True)
1575

    
1576
                        self.save_PDF(os.path.join(directory, drawing.name))
1577

    
1578
                        count += 1
1579
                        self.progress_bar.setValue(count)
1580
                    self.open_image_drawing(drawing, force=True, ocrUnknown=False) # for reset
1581
                    self.progress_bar.setValue(self.progress_bar.maximum())
1582
                    
1583
            QMessageBox.about(self, self.tr("Information"), self.tr('Successfully saved.'))
1584

    
1585
            #self.save_alarm_enable(True, True)
1586

    
1587
            '''
1588
            #app_doc_data = AppDocData.instance()
1589
            #project = app_doc_data.getCurrentProject()
1590

1591
            printer = QPrinter(QPrinter.PrinterResolution)
1592
            #printer.setPageSize(QPrinter.A0)
1593
            printer.setOrientation(QPrinter.Orientation.Landscape)
1594
            #printer.setOutputFileName(os.path.join(project.getPDFFilePath(), os.path.splitext(app_doc_data.activeDrawing.name)[0]))
1595
            #printer.setOutputFormat(QPrinter.PdfFormat)
1596
            dialog = QPrintDialog(printer)
1597
            if (dialog.exec() == QDialog.Accepted):
1598
                painter = QPainter(printer)
1599
                isfull_print = False
1600

1601
                scene = self.graphicsView.scene()
1602

1603
                #for item in scene.items():
1604
                #    if not hasattr(item, 'connectors'): continue
1605
                #    for connector in item.connectors: connector.setVisible(False)
1606

1607
                canvasRect = scene.sceneRect() # or canvasRect = scene.border.boundingRect()
1608
                source = canvasRect
1609
                page = printer.pageRect(QPrinter.Unit.DevicePixel)
1610
                target = QRectF(QPointF(0, 0), QSizeF(page.width(), page.height()))
1611
                scene.render(painter, target, source)
1612
                painter.end()
1613

1614
                QMessageBox.about(self, self.tr("Information"), self.tr('Successfully saved.'))
1615
                #for item in scene.items():
1616
                #    if not hasattr(item, 'connectors'): continue
1617
                #    for connector in item.connectors: connector.setVisible(True)
1618
            '''
1619

    
1620
        except Exception as ex:
1621
            message = 'error occurred({}) in {}:{}'.format(ex, sys.exc_info()[-1].tb_frame.f_code.co_filename,
1622
                                                           sys.exc_info()[-1].tb_lineno)
1623
            self.addMessage.emit(MessageType.Error, message)
1624

    
1625
    def save_PDF(self, file_name):
1626
        #pixMap = self.graphicsView.grab(QRect(QPoint(0, 0), QSize(int(self.graphicsView.scene().sceneRect().width()), int(self.graphicsView.scene().sceneRect().height()))))
1627
        #pixMap.save(name)
1628
        #return
1629

    
1630
        image = QImage(QSize(int(self.graphicsView.scene().sceneRect().width()), int(self.graphicsView.scene().sceneRect().height())), QImage.Format_ARGB32_Premultiplied)
1631
        painter = QPainter(image)
1632
        scene = self.graphicsView.scene()
1633
        canvasRect = scene.sceneRect() # or canvasRect = scene.border.boundingRect()
1634
        source = canvasRect
1635
        scene.render(painter, QRectF(image.rect()), source)
1636
        painter.end()
1637
        image.save(file_name)
1638
        image = Image.open(file_name)
1639
        image = image.convert('RGB')
1640
        image.save(file_name.replace('.png', '.pdf'))
1641
        os.remove(file_name)
1642
        painter.device()
1643

    
1644
    def onSymbolThickness(self):
1645
        """ symbol thickness reinforcement by using configuration filter drawing dilate size """
1646
        try:
1647
            self.onCommandRejected()
1648
            dialog = QSymbolThicknessDialog(self)
1649
            dialog.exec_()
1650
        except Exception as ex:
1651
            message = 'error occurred({}) in {}:{}'.format(ex, sys.exc_info()[-1].tb_frame.f_code.co_filename,
1652
                                                           sys.exc_info()[-1].tb_lineno)
1653
            self.addMessage.emit(MessageType.Error, message)
1654

    
1655
    def on_help(self):
1656
        """ open help file """
1657
        import os
1658

    
1659
        try:
1660
            help_file_path = os.path.join(os.path.dirname(os.path.realpath(__file__)), 'ID2 User Manual.pdf')
1661
            if os.path.exists(help_file_path):
1662
                os.startfile(f"\"{help_file_path}\"")
1663
            else:
1664
                QMessageBox.warning(self, self.tr('Warning'), self.tr('There is no help file'))
1665
        except Exception as ex:
1666
            message = f"error occurred({repr(ex)}) in {sys.exc_info()[-1].tb_frame.f_code.co_filename}:" \
1667
                      f"{sys.exc_info()[-1].tb_lineno}"
1668
            self.addMessage.emit(MessageType.Error, message)
1669

    
1670
    def on_readme(self):
1671
        """open readme.html"""
1672

    
1673
        file_path = os.path.join(os.path.dirname(os.path.realpath(__file__)), 'readme.html')
1674
        if os.path.exists(file_path):
1675
            os.startfile(f"\"{file_path}\"")
1676
        else:
1677
            QMessageBox.warning(self, self.tr('Warning'), self.tr('There is no readme file'))
1678

    
1679
    def onSelectionChanged(self):
1680
        """selection changed"""
1681
        items = [item for item in self.graphicsView.scene().selectedItems() if issubclass(type(item), SymbolSvgItem) or
1682
                 type(item) is QEngineeringLineItem or issubclass(type(item), QEngineeringTextItem) or
1683
                 type(item) is QEngineeringUnknownItem or type(item) is QEngineeringVendorItem]
1684
        if items:
1685
            lineNos = [item for item in items if type(item) is QEngineeringLineNoTextItem]
1686
            item = items[-1] if not lineNos else lineNos[0]
1687
            self.itemTreeWidget.findItem(item)
1688
            self.resultPropertyTableWidget.show_item_property(item)
1689
            if type(item) is QEngineeringErrorItem:
1690
                for index in range(self.tableWidgetInconsistency.rowCount()):
1691
                    if self.tableWidgetInconsistency.item(index, 1).tag is item:
1692
                        self.tableWidgetInconsistency.selectRow(index)
1693
                        break
1694
            if issubclass(type(item), SymbolSvgItem):
1695
                pass
1696
                #self.symbolTreeWidget.select_symbol(item)
1697
        else:
1698
            self.resultPropertyTableWidget.show_item_property(None)
1699

    
1700
    '''
1701
        @brief      Initialize scene and itemTreeWidget
1702
        @author     Jeongwoo
1703
        @date       2018.06.14
1704
        @history    humkyung 2018.08.16 ask to delete recognized items before remove
1705
    '''
1706
    def on_initialize_scene(self, action):
1707
        if not self.graphicsView.hasImage():
1708
            self.showImageSelectionMessageBox()
1709

    
1710
            return
1711

    
1712
        try:
1713
            msg = QMessageBox()
1714
            msg.setIcon(QMessageBox.Critical)
1715
            msg.setText(self.tr('Do you want to remove all items?\nThis work cannot be recovered.'))
1716
            msg.setWindowTitle(self.tr("Initialize"))
1717
            msg.setStandardButtons(QMessageBox.Ok | QMessageBox.Cancel)
1718
            if QMessageBox.Ok == msg.exec_():
1719
                app_doc_data = AppDocData.instance()
1720
                app_doc_data.clearItemList(True)
1721

    
1722
                scene = self.graphicsView.scene()
1723
                pixmap = self.graphicsView.getPixmapHandle()
1724
                scene.removeItem(pixmap)    # disconnect pixmap from scene
1725
                scene.clear()               # remove all items from scene and then delete them
1726
                scene.addItem(pixmap)       # add pixmap
1727

    
1728
                if self.path is not None:
1729
                    baseName = os.path.basename(self.path)
1730
                    self.itemTreeWidget.setCurrentPID(baseName)
1731

    
1732
        except Exception as ex:
1733
            message = 'error occurred({}) in {}:{}'.format(ex, sys.exc_info()[-1].tb_frame.f_code.co_filename,
1734
                                                           sys.exc_info()[-1].tb_lineno)
1735
            self.addMessage.emit(MessageType.Error, message)
1736

    
1737
    def checked_action(self):
1738
        """return checked action"""
1739
        home_file_pane = self.ribbon.get_pane('Home File')
1740
        home_pane = self.ribbon.get_pane('Home')
1741
        visualization_pane = self.ribbon.get_pane('Home Visualization')
1742
        actions = [home_pane.ui.toolButtonRecognition, home_pane.ui.toolButtonLinkAttribute,
1743
                   home_pane.ui.toolButtonLine, home_pane.ui.toolButtonOCR, visualization_pane.ui.toolButtonZoom,
1744
                   visualization_pane.ui.toolButtonFitWindow, home_pane.ui.toolButtonVendor]
1745

    
1746
        checked = [ui_ for ui_ in actions if ui_.isChecked()]
1747
        return checked[0] if checked else None
1748

    
1749
    def update_action_group(self, ui):
1750
        """Manage Checkable Action statement"""
1751
        home_file_pane = self.ribbon.get_pane('Home File')
1752
        home_pane = self.ribbon.get_pane('Home')
1753
        visualization_pane = self.ribbon.get_pane('Home Visualization')
1754
        actions = [home_pane.ui.toolButtonRecognition, home_pane.ui.toolButtonLinkAttribute, home_pane.ui.toolButtonLine,
1755
                   home_pane.ui.toolButtonOCR, visualization_pane.ui.toolButtonZoom,
1756
                   visualization_pane.ui.toolButtonFitWindow, home_file_pane.ui.toolButtonFileSave,
1757
                   home_pane.ui.toolButtonValidate, home_pane.ui.toolButtonVendor]
1758

    
1759
        if hasattr(ui, 'tag'):
1760
            ui.tag.onRejected.emit(None)
1761

    
1762
        if self.graphicsView.command is not None:
1763
            self.graphicsView.useDefaultCommand()
1764

    
1765
        for ui_ in actions:
1766
            ui_.setChecked(False)
1767

    
1768
        ui.setChecked(True)
1769

    
1770
    '''
1771
        @brief      Create Equipment
1772
        @author     Jeongwoo
1773
        @date       18.05.03
1774
        @history    2018.05.04  Jeongwoo    Add Parameter on CreateSymbolCommand
1775
    '''
1776
    def createEquipment(self):
1777
        if not self.graphicsView.hasImage():
1778
            self.actionEquipment.setChecked(False)
1779
            self.showImageSelectionMessageBox()
1780
            return
1781
        if self.actionEquipment.isChecked():
1782
            self.graphicsView.command = CreateSymbolCommand.CreateSymbolCommand(self.graphicsView, self.itemTreeWidget,
1783
                                                                                self.symbolTreeWidget)
1784
        else:
1785
            self.graphicsView.useDefaultCommand()
1786

    
1787
    '''
1788
        @brief      Create Nozzle
1789
        @author     Jeongwoo
1790
        @date       2018.05.03
1791
        @history    2018.05.04  Jeongwoo    Add Parameter on CreateSymbolCommand
1792
    '''
1793
    def createNozzle(self):
1794
        if not self.graphicsView.hasImage():
1795
            self.actionNozzle.setChecked(False)
1796
            self.showImageSelectionMessageBox()
1797
            return
1798
        if self.actionNozzle.isChecked():
1799
            self.graphicsView.command = CreateSymbolCommand.CreateSymbolCommand(self.graphicsView, self.itemTreeWidget,
1800
                                                                                self.symbolTreeWidget)
1801
        else:
1802
            self.graphicsView.useDefaultCommand()
1803

    
1804
    def onAreaOcr(self):
1805
        """Area OCR"""
1806
        if not self.graphicsView.hasImage():
1807
            self.actionOCR.setChecked(False)
1808
            self.showImageSelectionMessageBox()
1809
            return
1810

    
1811
        pane = self.ribbon.get_pane('Home')
1812
        ui = pane.ui.toolButtonOCR
1813
        self.update_action_group(ui=ui)
1814
        checked = ui.isChecked()
1815
        if checked:
1816
            cmd = AreaOcrCommand.AreaOcrCommand(self.graphicsView)
1817
            cmd.onSuccess.connect(self.onRecognizeText)
1818
            cmd.onRejected.connect(self.onCommandRejected)
1819
            self.graphicsView.command = cmd
1820
        else:
1821
            self.graphicsView.useDefaultCommand()
1822

    
1823
    def onRecognizeText(self, x, y, width, height, show=True):
1824
        """show text recognition dialog"""
1825
        from OcrResultDialog import QOcrResultDialog
1826
        from Area import Area
1827

    
1828
        try:
1829
            app_doc_data = AppDocData.instance()
1830

    
1831
            modifiers = QApplication.keyboardModifiers()
1832
            image = self.graphicsView.image().copy(x, y, width, height)
1833
            dialog = QOcrResultDialog(self, image, QRectF(x, y, width, height),
1834
                                      format=QOcrResultDialog.Format.Table if modifiers == Qt.AltModifier else QOcrResultDialog.Format.Normal)
1835
            if modifiers == Qt.ControlModifier:
1836
                return
1837
            
1838
            if show:
1839
                (res, textInfoList) = dialog.showDialog()
1840
            else:
1841
                dialog.accept(show=False)
1842
                (res, textInfoList) = QDialog.Accepted, dialog.textInfoList
1843

    
1844
            if QDialog.Accepted == res and textInfoList:
1845
                for textInfo in textInfoList:
1846
                    item = QEngineeringTextItem.create_text_with(self.graphicsView.scene(), textInfo)
1847
                    if item:
1848
                        #item.setDefaultTextColor(Qt.blue)
1849
                        item.transfer.onRemoved.connect(self.itemRemoved)
1850

    
1851
                        area_list = app_doc_data.getAreaList()
1852
                        title_area_list = app_doc_data.getTitleBlockProperties()
1853
                        title_list = []
1854
                        if title_area_list:
1855
                            for title_area in title_area_list:
1856
                                area = Area(title_area[0])
1857
                                area.parse(title_area[2])
1858
                                title_list.append(area)
1859
                        for area in area_list + title_list:
1860
                            pt = [item.sceneBoundingRect().center().x(), item.sceneBoundingRect().center().y()]
1861
                            if area.contains(pt):
1862
                                item.area = area.name
1863
                                break
1864
                    else:
1865
                        self.addMessage.emit(MessageType.Normal, self.tr('Fail to create text.'))
1866

    
1867
                return True
1868
            elif QDialog.Accepted == res and not textInfoList and show:
1869
                QMessageBox.about(self.graphicsView, self.tr("Notice"), self.tr("Fail to recognize text"))
1870
        except Exception as ex:
1871
            message = 'error occurred({}) in {}:{}'.format(ex, sys.exc_info()[-1].tb_frame.f_code.co_filename,
1872
                                                           sys.exc_info()[-1].tb_lineno)
1873
            self.addMessage.emit(MessageType.Error, message)
1874
        
1875
        return False
1876

    
1877
    '''
1878
        @brief  area configuration
1879
    '''
1880
    def areaConfiguration(self):
1881
        from ConfigurationAreaDialog import QConfigurationAreaDialog
1882
        if not self.graphicsView.hasImage():
1883
            self.showImageSelectionMessageBox()
1884
            return
1885
        self.onCommandRejected()
1886
        dlgConfigurationArea = QConfigurationAreaDialog(self)
1887
        dlgConfigurationArea.show()
1888
        dlgConfigurationArea.exec_()
1889

    
1890
    '''
1891
        @brief  configuration
1892
    '''
1893
    def configuration(self):
1894
        from ConfigurationDialog import QConfigurationDialog
1895

    
1896
        dlgConfiguration = QConfigurationDialog(self)
1897
        if QDialog.Accepted == dlgConfiguration.exec_():
1898
            QEngineeringLineItem.LINE_TYPE_COLORS.clear()
1899
            QEngineeringInstrumentItem.INST_COLOR = None
1900

    
1901
    '''
1902
        @brief  show special item types dialog 
1903
        @author humkyung
1904
        @date   2019.08.10
1905
    '''
1906
    def on_show_special_item_types(self):
1907
        from SpecialItemTypesDialog import QSpecialItemTypesDialog
1908

    
1909
        dlg = QSpecialItemTypesDialog(self)
1910
        dlg.exec_()
1911

    
1912
    def on_show_data_transfer(self):
1913
        """ show data transfer dialog """
1914
        from DataTransferDialog import QDataTransferDialog
1915

    
1916
        dlg = QDataTransferDialog(self)
1917
        dlg.exec_()
1918

    
1919
    def on_show_data_export(self):
1920
        """ show data export dialog """
1921
        from DataExportDialog import QDataExportDialog
1922

    
1923
        dlg = QDataExportDialog(self)
1924
        dlg.exec_()
1925

    
1926
    def on_show_eqp_datasheet_export(self):
1927
        """ show eqp datasheet export dialog """
1928
        from EqpDatasheetExportDialog import QEqpDatasheetExportDialog
1929

    
1930
        dlg = QEqpDatasheetExportDialog(self)
1931
        dlg.exec_()
1932

    
1933
    def on_show_opc_relation(self):
1934
        """ show opc relation dialog """
1935
        from OPCRelationDialog import QOPCRelationDialog
1936

    
1937
        dlg = QOPCRelationDialog(self)
1938
        dlg.exec_()
1939

    
1940
    '''
1941
        @brief  show nominal diameter dialog 
1942
        @author humkyung
1943
        @date   2018.06.28
1944
    '''
1945
    def onShowCodeTable(self):
1946
        from CodeTableDialog import QCodeTableDialog
1947

    
1948
        dlg = QCodeTableDialog(self)
1949
        dlg.show()
1950
        dlg.exec_()
1951
        if dlg.code_area:
1952
            if dlg.code_area.scene():
1953
                self.graphicsView.scene().removeItem(dlg.code_area)
1954
        if dlg.desc_area:
1955
            if dlg.desc_area.scene():
1956
                self.graphicsView.scene().removeItem(dlg.desc_area)
1957
        self.graphicsView.useDefaultCommand()
1958

    
1959
    def on_ext_app_connection(self):
1960
        app_doc_data = AppDocData.instance()
1961

    
1962
        tool_pane = self.ribbon.get_pane('Tool')
1963
        if tool_pane.ui.toolButtonConnection.isChecked():
1964
            if not hasattr(self, '_tcpserver'):
1965
                configs = app_doc_data.getAppConfigs('app', 'port')
1966
                port = 2549
1967
                if configs and 1 == len(configs):
1968
                    port = int(configs[0].value)
1969
                self._tcpserver = TcpServer(port)
1970
                self._tcpserver.sessionOpened()
1971
        else:
1972
            self._tcpserver.sessionClosed()
1973
            del self._tcpserver
1974

    
1975
    def on_execute_ext_app(self):
1976
        """execute external application"""
1977
        from ExtAppsDialog import QExtAppsDialog
1978

    
1979
        dlg = QExtAppsDialog(self)
1980
        dlg.exec_()
1981

    
1982
    def onShowCustomCodeTable(self):
1983
        from CustomCodeTablesDialog import CustomCodeTablesDialog
1984

    
1985
        dlg = CustomCodeTablesDialog(self)
1986
        dlg.show()
1987
        dlg.exec_()
1988
        self.graphicsView.useDefaultCommand()
1989

    
1990
    def onShowReplaceCodeTable(self):
1991
        from CustomCodeTablesDialog import CustomCodeTablesDialog
1992

    
1993
        dlg = CustomCodeTablesDialog(self, replace=True)
1994
        dlg.show()
1995
        dlg.exec_()
1996
        self.graphicsView.useDefaultCommand()
1997

    
1998
    def on_streamline(self):
1999
        """pop up stream line dialog"""
2000
        from StreamlineDialog import QStreamlineDialog
2001

    
2002
        if not self.graphicsView.hasImage():
2003
            self.showImageSelectionMessageBox()
2004
            return
2005

    
2006
        hmbs = AppDocData.instance().get_hmb_data(None)
2007
        if not hmbs:
2008
            return
2009

    
2010
        dlg = QStreamlineDialog(self)
2011
        dlg.show()
2012

    
2013
    def onHMBData(self):
2014
        """show HMB data"""
2015
        from HMBDialog import QHMBDialog
2016

    
2017
        dlg = QHMBDialog(self)
2018
        dlg.show()
2019
        dlg.exec_()
2020

    
2021
    '''
2022
        @brief  show line data list 
2023
        @author humkyung
2024
        @date   2018.05.03
2025
    '''
2026
    def showItemDataList(self):
2027
        from ItemDataExportDialog import QItemDataExportDialog
2028

    
2029
        dlg = QItemDataExportDialog(self)
2030
        dlg.exec_()
2031

    
2032
    def showTextDataList(self):
2033
        '''
2034
            @brief      show all text item in scene
2035
            @author     euisung
2036
            @date       2019.04.18
2037
        '''
2038
        try:
2039
            if not self.graphicsView.hasImage():
2040
                self.showImageSelectionMessageBox()
2041
                return
2042

    
2043
            self.onCommandRejected()
2044
            dialog = QTextDataListDialog(self)
2045
            dialog.show()
2046
        except Exception as ex:
2047
            message = 'error occurred({}) in {}:{}'.format(ex, sys.exc_info()[-1].tb_frame.f_code.co_filename,
2048
                                                           sys.exc_info()[-1].tb_lineno)
2049
            self.addMessage.emit(MessageType.Error, message)
2050

    
2051
    '''
2052
        @brief  Show Image Selection Guide MessageBox
2053
        @author Jeongwoo
2054
        @date   2018.05.02
2055
    '''
2056
    def showImageSelectionMessageBox(self):
2057
        QMessageBox.about(self.graphicsView, self.tr("Notice"), self.tr("First select image drawing"))
2058

    
2059
    def on_search_text_changed(self):
2060
        """filter symbol tree view"""
2061
        regexp = QRegExp(self.lineEditFilter.text(), Qt.CaseInsensitive, QRegExp.FixedString)
2062

    
2063
        proxy_model = self.symbolTreeWidget.model()
2064
        proxy_model.text = self.lineEditFilter.text().lower()
2065
        proxy_model.setFilterRegExp(regexp)
2066

    
2067
        self.symbolTreeWidget.expandAll()
2068

    
2069
    def change_display_colors(self):
2070
        """ change display color mode """
2071
        visualization_pane = self.ribbon.get_pane('Home Visualization')
2072
        if visualization_pane.ui.radioButtonByGroup.isChecked():
2073
            visualization_pane.ui.radioButtonByType.setChecked(True)
2074
        else:
2075
            visualization_pane.ui.radioButtonByGroup.setChecked(True)
2076

    
2077
    def display_colors(self, value):
2078
        """ display colors """
2079
        from DisplayColors import DisplayColors, DisplayOptions
2080

    
2081
        if hasattr(self, 'ribbon'):
2082
            visualization_pane = self.ribbon.get_pane('Home Visualization')
2083
            if self.sender() is visualization_pane.ui.radioButtonByGroup and value is True:
2084
                DisplayColors.instance().option = DisplayOptions.DisplayByLineNo
2085
            elif self.sender() is visualization_pane.ui.radioButtonByType and value is True:
2086
                DisplayColors.instance().option = DisplayOptions.DisplayByLineType
2087
            elif self.sender() is visualization_pane.ui.radioButtonByStreamNo and value is True:
2088
                DisplayColors.instance().option = DisplayOptions.DisplayByStreamNo
2089

    
2090
            if hasattr(self, 'graphicsView') and value is True:
2091
                self.graphicsView.scene().update(self.graphicsView.sceneRect())
2092
                for item in self.graphicsView.scene().items():
2093
                    if issubclass(type(item), SymbolSvgItem):
2094
                        item.update()
2095
                DisplayColors.instance().save_data()
2096

    
2097
    def open_image_drawing(self, drawing, force=False, ocrUnknown=False, timer=True, pdf=False):
2098
        """open and display image drawing file"""
2099
        from Drawing import Drawing
2100
        from App import App
2101
        from LoadCommand import LoadCommand
2102
        import concurrent.futures as futures
2103

    
2104
        # Yield successive n-sized
2105
        # chunks from l.
2106
        def divide_chunks(l, n):
2107
            # looping till length l
2108
            for i in range(0, len(l), n):
2109
                yield l[i:i + n]
2110

    
2111
        def update_items(items):
2112
            for item in items:
2113
                # binding items
2114
                item.owner
2115
                for connector in item.connectors:
2116
                    connector.connectedItem
2117

    
2118
            return items
2119

    
2120
        try:
2121
            app_doc_data = AppDocData.instance()
2122

    
2123
            if not self.actionSave.isEnabled():
2124
                return
2125

    
2126
            if not force and self.save_drawing_if_necessary():
2127
                return
2128

    
2129
            if not pdf:
2130
                occupied = app_doc_data.set_occupying_drawing(drawing.UID)
2131
                if occupied:
2132
                    QMessageBox.about(self.graphicsView, self.tr("Notice"),
2133
                                      self.tr(f"The drawing is locked for editing by another user({occupied})"))
2134
                    return
2135

    
2136
            # save alarm
2137
            if timer:
2138
                self.save_alarm_enable(False)
2139

    
2140
            if hasattr(self, '_save_work_cmd'):
2141
                self._save_work_cmd.wait()
2142

    
2143
            project = app_doc_data.getCurrentProject()
2144

    
2145
            self.path = self.graphicsView.loadImageFromFile(drawing)
2146
            if os.path.isfile(self.path):
2147
                self.onCommandRejected()
2148
                app_doc_data.clear(past=drawing.UID)
2149

    
2150
                # load color for stream no coloring
2151
                configs = app_doc_data.getConfigs('Line List', 'Use Stream No')
2152
                if configs and int(configs[0].value) == 1:
2153
                    hmbs = app_doc_data.get_hmb_data(None)
2154
                    colors = {}
2155
                    if hmbs:
2156
                        for hmb in hmbs:
2157
                            rgb = app_doc_data.colors
2158
                            colors[hmb.stream_no] = QColor(rgb.red, rgb.green, rgb.blue).name()
2159
                        app_doc_data._hmbColors = colors
2160
                # up to here
2161

    
2162
                app_doc_data.setImgFilePath(self.path)
2163
                app_doc_data.activeDrawing = drawing
2164
                
2165
                #app_doc_data.activeDrawing.set_pid_source(Image.open(self.path))
2166
                self.itemTreeWidget.setCurrentPID(app_doc_data.activeDrawing.name)
2167

    
2168
                drawingList = self.treeWidgetDrawingList.topLevelItem(0)
2169
                for idx in range(drawingList.childCount()):
2170
                    child = drawingList.child(idx)
2171
                    if child.data(Qt.UserRole, 0) is drawing:
2172
                        child.setCheckState(0, Qt.Checked)
2173
                    else:
2174
                        child.setCheckState(0, Qt.Unchecked)
2175

    
2176
                try:
2177
                    self.show_Progress_bar()
2178

    
2179
                    # disconnect scene changed if signal is connected
2180
                    if self.graphicsView.scene().receivers(self.graphicsView.scene().contents_changed) > 0:
2181
                        self.graphicsView.scene().contents_changed.disconnect()
2182

    
2183
                    SymbolSvgItem.DOCUMENTS.clear()
2184

    
2185
                    # load data
2186
                    cmd = LoadCommand()
2187
                    cmd.display_message.connect(self.onAddMessage)
2188
                    cmd.set_maximum.connect(self.progress.setMaximum)
2189
                    cmd.show_progress.connect(self.progress.setValue)
2190
                    cmd.execute((drawing, self.graphicsView.scene()),
2191
                                symbol=True, text=True, line=True, unknown=True, package=True, update=not pdf)
2192

    
2193
                    configs = app_doc_data.getConfigs('Line List', 'Use Stream No')
2194
                    if configs and int(configs[0].value) == 1:
2195
                        app_doc_data._streamLineListModelDatas = app_doc_data.get_stream_line_list_data()
2196
                    # up to here
2197

    
2198
                    """update item tree widget"""
2199
                    line_no_items = [item for item in self.graphicsView.scene().items()
2200
                                     if type(item) is QEngineeringLineNoTextItem]
2201
                    for line_no in line_no_items:
2202
                        line_no_tree_item = self.itemTreeWidget.addTreeItem(self.itemTreeWidget.root, line_no)
2203
                        for run in line_no.runs:
2204
                            for run_item in run.items:
2205
                                if issubclass(type(run_item), SymbolSvgItem):
2206
                                    self.init_add_tree_item(line_no_tree_item, run_item)
2207

    
2208
                    line_no_items = [item for item in self.graphicsView.scene().items()
2209
                                     if type(item) is QEngineeringTrimLineNoTextItem]
2210
                    for line_no in line_no_items:
2211
                        line_no_tree_item = self.itemTreeWidget.addTreeItem(self.itemTreeWidget.root, line_no)
2212
                        for run in line_no.runs:
2213
                            for run_item in run.items:
2214
                                if issubclass(type(run_item), SymbolSvgItem):
2215
                                    self.init_add_tree_item(line_no_tree_item, run_item)
2216

    
2217
                    for trim_line_no in app_doc_data.tracerLineNos:
2218
                        line_no_tree_item = self.itemTreeWidget.addTreeItem(self.itemTreeWidget.root, trim_line_no)
2219
                        for run in trim_line_no.runs:
2220
                            for run_item in run.items:
2221
                                if issubclass(type(run_item), SymbolSvgItem):
2222
                                    self.init_add_tree_item(line_no_tree_item, run_item)
2223

    
2224
                    self.itemTreeWidget.update_item_count()
2225
                    self.itemTreeWidget.expandAll()
2226
                    """up to here"""
2227

    
2228
                    """update scene"""
2229
                    for item in self._scene.items():
2230
                        item.setVisible(True)
2231

    
2232
                    self._scene.update(self._scene.sceneRect())
2233

    
2234
                    """
2235
                    # old open drawing
2236
                    path = os.path.join(app_doc_data.getCurrentProject().getTempPath(), app_doc_data.imgName + '.xml')
2237
                    configs = app_doc_data.getConfigs('Data Load', 'Xml First')
2238
                    if configs and int(configs[0].value) >= 1 and os.path.isfile(path):
2239
                        self.load_recognition_result_from_xml(drawing)
2240
                    elif configs and int(configs[0].value) <= 1:
2241
                        self.load_drawing(app_doc_data.activeDrawing)
2242
                    """
2243

    
2244
                    self.display_number_of_items()
2245
                    # connect scene changed signal
2246
                    self.graphicsView.scene().contents_changed.connect(self.scene_changed)
2247
                finally:
2248
                    if hasattr(self, 'progress'):
2249
                        self.progress.setValue(self.progress.maximum())
2250

    
2251
                self.changeViewCheckedState(None)
2252
                self.updateAsViewCheckedState()
2253
                self.setWindowTitle(self.title)
2254
                if not pdf:
2255
                    self.fitWindow(drawing.view_rect)
2256

    
2257
                if ocrUnknown:
2258
                    self.on_ocr_unknown_items()
2259

    
2260
                # save alarm
2261
                if timer:
2262
                    self.save_alarm_enable(True, True)
2263
        except Exception as ex:
2264
            message = f"error occurred({repr(ex)}) in {sys.exc_info()[-1].tb_frame.f_code.co_filename}:" \
2265
                      f"{sys.exc_info()[-1].tb_lineno}"
2266
            self.addMessage.emit(MessageType.Error, message)
2267

    
2268
        return self.path
2269

    
2270
    def save_alarm_enable(self, enable, init=False):
2271
        from datetime import datetime
2272

    
2273
        try:
2274
            app_doc_data = AppDocData.instance()
2275
            configs = app_doc_data.getConfigs('Data Save', 'Time')
2276
            time_min = int(configs[0].value) if 1 == len(configs) else 0
2277

    
2278
            if enable and time_min > 0:
2279
                if not self.save_timer:
2280
                    self.save_timer = QTimer()
2281
                    self.save_timer.timeout.connect(self.save_alarm)
2282
                    self.save_timer.setInterval(60000)
2283

    
2284
                if init:
2285
                    self.save_timer._init_time = datetime.now()
2286
                    self.save_timer._stop_time = None
2287
                    self.save_timer._interval_time = datetime.now() - datetime.now()
2288

    
2289
                if self.save_timer._stop_time:
2290
                    self.save_timer._interval_time = datetime.now() - self.save_timer._stop_time
2291
                
2292
                #if 60000 * time_min != self.save_timer.interval():
2293
                #    self.save_timer.setInterval(60000)
2294

    
2295
                self.save_timer.start()
2296
            else:
2297
                if self.save_timer:
2298
                    self.save_timer.stop()
2299
                    self.save_timer._stop_time = datetime.now()
2300
        
2301
        except Exception as ex:
2302
            message = f"error occurred({repr(ex)}) in {sys.exc_info()[-1].tb_frame.f_code.co_filename}:" \
2303
                      f"{sys.exc_info()[-1].tb_lineno}"
2304
            self.addMessage.emit(MessageType.Error, message)
2305

    
2306
    def save_alarm(self):
2307
        from datetime import datetime
2308

    
2309
        app_doc_data = AppDocData.instance()
2310
        configs = app_doc_data.getConfigs('Data Save', 'Time')
2311
        time_min = int(configs[0].value) if 1 == len(configs) else 0
2312

    
2313
        self.save_timer.stop()
2314
        if self.graphicsView.hasFocus() and (datetime.now() - self.save_timer._init_time - self.save_timer._interval_time).seconds > time_min * 60:
2315
            QMessageBox.information(self, self.tr('Information'), self.tr('Please save Drawing'))
2316
            self.save_timer._init_time = datetime.now()
2317
            self.save_timer._interval_time = datetime.now() - datetime.now()
2318
        self.save_timer.start()
2319

    
2320
    def export_as_svg(self):
2321
        """export scene to svg file"""
2322
        from ExportCommand import ExportCommand
2323

    
2324
        options = QFileDialog.Options()
2325
        options |= QFileDialog.DontUseNativeDialog
2326
        file_path, _ = QFileDialog.getSaveFileName(self, "Export as svg", os.getcwd(), "svg file(*.svg)",
2327
                                                   options=options)
2328
        if file_path:
2329
            cmd = ExportCommand(self.graphicsView.scene(), 'svg')
2330
            cmd.display_message.connect(self.onAddMessage)
2331
            if cmd.execute(file_path):
2332
                QMessageBox.information(self, self.tr('Information'), self.tr('Successfully export to svg file'))
2333
            else:
2334
                QMessageBox.information(self, self.tr('Error'), self.tr('Fail to export to svg file'))
2335

    
2336
    def export_as_xml(self):
2337
        pass
2338

    
2339
    def export_as_image(self):
2340
        """export scene to image file"""
2341
        from ExportCommand import ExportCommand
2342

    
2343
        options = QFileDialog.Options()
2344
        options |= QFileDialog.DontUseNativeDialog
2345
        file_path, _ = QFileDialog.getSaveFileName(self, "Export as png", os.getcwd(), "png file(*.png)",
2346
                                                   options=options)
2347
        if file_path:
2348
            try:
2349
                # hide image drawing
2350
                self.onViewImageDrawing(False)
2351

    
2352
                cmd = ExportCommand(self.graphicsView.scene(), 'image')
2353
                cmd.display_message.connect(self.onAddMessage)
2354

    
2355
                if cmd.execute(file_path):
2356
                    QMessageBox.information(self, self.tr('Information'), self.tr('Successfully export to image file'))
2357
                else:
2358
                    QMessageBox.information(self, self.tr('Error'), self.tr('Fail to export to image file'))
2359
            finally:
2360
                if self.actionImage_Drawing.isChecked():
2361
                    self.onViewImageDrawing(True)
2362
                    self.actionImage_Drawing.setChecked(True)
2363

    
2364
    def show_Progress_bar(self):
2365
        """ show progress bar """
2366
        self.progress = QProgressDialog(self.tr("Please wait for a while"), self.tr("Cancel"), 0, 100,
2367
                                        self) if not hasattr(self, 'progress') else self.progress
2368
        self.progress.setWindowModality(Qt.WindowModal)
2369
        self.progress.setAutoReset(True)
2370
        self.progress.setAutoClose(True)
2371
        self.progress.setMinimum(0)
2372
        self.progress.setMaximum(100)
2373
        self.progress.resize(600, 100)
2374
        self.progress.setWindowTitle(self.tr("Reading file..."))
2375
        self.progress.show()
2376

    
2377
    def changeViewCheckedState(self, checked, clear=True):
2378
        """change view checked state"""
2379
        # self.actionImage_Drawing.setChecked(checked)
2380
        
2381
        '''
2382
        self.actionViewText.setChecked(checked)
2383
        self.actionViewSymbol.setChecked(checked)
2384
        self.actionViewLine.setChecked(checked)
2385
        self.actionViewUnknown.setChecked(checked)
2386
        self.actionViewInconsistency.setChecked(checked)
2387
        self.actionViewVendor_Area.setChecked(not checked)
2388
        self.actionDrawing_Only.setChecked(not checked)
2389
        '''
2390

    
2391
        if checked is not None:
2392
            view_pane = self.ribbon.get_pane('View')
2393
            view_pane.ui.toolButtonViewText.setChecked(checked)
2394
            view_pane.ui.toolButtonViewSymbol.setChecked(checked)
2395
            view_pane.ui.toolButtonViewLine.setChecked(checked)
2396
            view_pane.ui.toolButtonViewUnknown.setChecked(checked)
2397
            view_pane.ui.toolButtonViewInconsistency.setChecked(checked)
2398
            view_pane.ui.toolButtonViewVendorArea.setChecked(checked)
2399
            view_pane.ui.toolButtonViewDrawingOnly.setChecked(not checked)
2400

    
2401
        if clear:
2402
            self.tableWidgetInconsistency.clearContents()
2403
            self.tableWidgetInconsistency.setRowCount(0)
2404

    
2405
    def updateAsViewCheckedState(self):
2406
        view_pane = self.ribbon.get_pane('View')
2407
        self.onViewImageDrawing(view_pane.ui.toolButtonViewImageDrawing.isChecked())
2408
        self.onViewText(view_pane.ui.toolButtonViewText.isChecked())
2409
        self.onViewSymbol(view_pane.ui.toolButtonViewSymbol.isChecked())
2410
        self.onViewLine(view_pane.ui.toolButtonViewLine.isChecked())
2411
        self.onViewUnknown(view_pane.ui.toolButtonViewUnknown.isChecked())
2412
        self.onViewInconsistency(view_pane.ui.toolButtonViewInconsistency.isChecked())
2413
        self.onViewVendorArea(view_pane.ui.toolButtonViewVendorArea.isChecked())
2414
        #self.onViewDrawingOnly(view_pane.ui.toolButtonViewDrawingOnly.isChecked())
2415

    
2416
    def onViewDrawingOnly(self, isChecked):
2417
        '''
2418
            @brief  visible/invisible except image drawing
2419
            @author euisung
2420
            @date   2019.04.22
2421
        '''
2422
        self.changeViewCheckedState(not isChecked, False)
2423
        for item in self.graphicsView.scene().items():
2424
            if type(item) is not QGraphicsPixmapItem and issubclass(type(item), QEngineeringAbstractItem):
2425
                item.setVisible(not isChecked)
2426

    
2427
    '''
2428
        @brief  visible/invisible image drawing
2429
        @author humkyung
2430
        @date   2018.06.25
2431
    '''
2432
    def onViewImageDrawing(self, isChecked):
2433
        for item in self.graphicsView.scene().items():
2434
            if type(item) is QGraphicsPixmapItem:
2435
                item.setVisible(isChecked)
2436
                break
2437

    
2438
    def onViewText(self, checked):
2439
        """visible/invisible text"""
2440
        selected = [item for item in self.graphicsView.scene().items() if issubclass(type(item), QEngineeringTextItem)]
2441
        for item in selected:
2442
            item.setVisible(checked)
2443

    
2444
    def onViewSymbol(self, checked):
2445
        """visible/invisible symbol"""
2446
        selected = [item for item in self.graphicsView.scene().items() if issubclass(type(item), SymbolSvgItem)]
2447
        for item in selected:
2448
            item.setVisible(checked)
2449

    
2450
    def onViewLine(self, checked):
2451
        """visible/invisible line"""
2452
        selected = [item for item in self.graphicsView.scene().items() if type(item) is QEngineeringLineItem]
2453
        for item in selected:
2454
            item.setVisible(checked)
2455

    
2456
    def onViewInconsistency(self, isChecked):
2457
        '''
2458
            @brief  visible/invisible Inconsistency
2459
            @author euisung
2460
            @date   2019.04.03
2461
        '''
2462
        selected = [item for item in self.graphicsView.scene().items() if type(item) is QEngineeringErrorItem]
2463
        for item in selected:
2464
            item.setVisible(isChecked)
2465

    
2466
    '''
2467
        @brief  visible/invisible Unknown 
2468
        @author humkyung
2469
        @date   2018.06.28
2470
    '''
2471
    def onViewUnknown(self, isChecked):
2472
        selected = [item for item in self.graphicsView.scene().items() if type(item) is QEngineeringUnknownItem]
2473
        for item in selected:
2474
            item.setVisible(isChecked)
2475

    
2476
    def onViewVendorArea(self, isChecked):
2477
        '''
2478
            @brief  visible/invisible Vendor Area
2479
            @author euisung
2480
            @date   2019.04.29
2481
        '''
2482
        selected = [item for item in self.graphicsView.scene().items() if issubclass(type(item), QEngineeringVendorItem)]
2483
        for item in selected:
2484
            item.setVisible(isChecked)
2485

    
2486
    '''
2487
        @brief  create a symbol
2488
        @history    2018.05.02  Jeongwoo    Change return value of QSymbolEditorDialog (Single variable → Tuple)
2489
                                            Add SymbolSvgItem
2490
                    2018.05.03  Jeongwoo    Change method to draw Svg Item on Scene (svg.addSvgItemToScene)
2491
                                            Change method to make svg and image path
2492
                    2018.06.08  Jeongwoo    Add Paramter on SymbolSvgItem.buildItem()
2493
    '''
2494
    def onCreateSymbolClicked(self):
2495
        selected = [item for item in self.graphicsView.scene().selectedItems() if issubclass(type(item), QEngineeringVendorItem)]
2496
        if len(selected) == 1:
2497
            symbol_image = AppDocData.instance().activeDrawing.image_origin
2498
            rect = selected[0].sceneBoundingRect()
2499

    
2500
            points = []
2501
            for conn in selected[0].connectors:
2502
                points.append([round(conn.center()[0] - rect.x()), round(conn.center()[1] - rect.y())])
2503
            poly = np.array(points, np.int32)
2504

    
2505
            #mask = np.zeros((int(rect.height()), int(rect.width())))
2506
            #cv2.fillPoly(mask, [poly], (255))
2507
            #poly_copied = np.multiply(mask, symbol_image[round(rect.y()):round(rect.y() + rect.height()),
2508
            #                   round(rect.x()):round(rect.x() + rect.width())])
2509
            #cv2.fillPoly(mask,[poly],0)
2510
            #src2 = np.multiply(mask,src2)
2511

    
2512
            mask = np.ones((int(rect.height()), int(rect.width())), dtype=np.uint8) * 255
2513
            cv2.fillPoly(mask, [poly], (0))
2514
            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())])
2515
            sym_img = cv2.merge((sym_img, sym_img, sym_img))
2516

    
2517
            h, w, c = sym_img.shape
2518
            qImg = QImage(sym_img.data, w, h, w * c, QImage.Format_RGB888)
2519
            #pixmap = QPixmap.fromImage(qImg)
2520

    
2521
            self.onAreaSelected(None, None, None, None, package=qImg, position=rect.topLeft(), package_item=selected[0])
2522
        else:
2523
            cmd = FenceCommand.FenceCommand(self.graphicsView)
2524
            cmd.onSuccess.connect(self.onAreaSelected)
2525
            self.graphicsView.command = cmd
2526
            QApplication.setOverrideCursor(Qt.CrossCursor)
2527

    
2528
    '''
2529
        @brief      show SymbolEditorDialog with image selected by user
2530
        @author     humkyung
2531
        @date       2018.07.20
2532
    '''
2533
    def onAreaSelected(self, x, y, width, height, package=False, position=None, package_item=None):
2534
        try:
2535
            image = self.graphicsView.image()
2536
            if image is not None:
2537
                if not package:
2538
                    symbolEditorDialog = SymbolEditorDialog.QSymbolEditorDialog(self, image.copy(x, y, width, height),
2539
                                                                                AppDocData.instance().getCurrentProject())
2540
                else:
2541
                    symbolEditorDialog = SymbolEditorDialog.QSymbolEditorDialog(self, package,
2542
                                                                                AppDocData.instance().getCurrentProject(), package=True)
2543
                (isAccepted, isImmediateInsert, offsetX, offsetY, newSym) = symbolEditorDialog.showDialog()
2544
                # TODO: not initialize symbol tree view when user reject to create a new symbol
2545
                self.symbolTreeWidget.initSymbolTreeView()
2546
                if isAccepted:
2547
                    if isImmediateInsert:
2548
                        svg = QtImageViewer.createSymbolObject(newSym.getName())
2549
                        offsetX, offsetY = [int(point) for point in newSym.getOriginalPoint().split(',')]
2550
                        QtImageViewer.matchSymbolToLine(self.graphicsView.scene(), svg, QPoint(position.x() + offsetX, position.y() + offsetY))
2551

    
2552
                        package_item.transfer.onRemoved.emit(package_item)
2553
        finally:
2554
            self.onCommandRejected()
2555
            QApplication.restoreOverrideCursor()
2556
            QApplication.restoreOverrideCursor()
2557

    
2558
    def on_line_list(self):
2559
        """ line list export dialog """
2560
        from LineListDialog import LineListDialog
2561

    
2562
        if not self.graphicsView.hasImage():
2563
            self.showImageSelectionMessageBox()
2564
            return
2565

    
2566
        dialog = LineListDialog(self)
2567
        dialog.showDialog()
2568

    
2569
    def on_make_label_data(self):
2570
        """ make label data from symbol info """
2571
        from xml.etree.ElementTree import Element, SubElement, dump, ElementTree, parse
2572

    
2573
        if not self.graphicsView.hasImage():
2574
            self.showImageSelectionMessageBox()
2575
            return
2576

    
2577
        app_doc_data = AppDocData.instance()
2578
        project = app_doc_data.getCurrentProject()
2579

    
2580
        smalls = []
2581
        bigs = []
2582

    
2583
        symbol_list = app_doc_data.getTargetSymbolList(all=True)
2584
        #symbol_list = app_doc_data.getTargetSymbolList(all=False)
2585
        for symbol in symbol_list:
2586
            if symbol.iType == 38 or symbol.iType == 33 or symbol.iType == 0 or symbol.iType == 40:
2587
                continue
2588
            elif symbol.width and symbol.height:
2589
                if symbol.width > 300 or symbol.height > 300:
2590
                    bigs.append(symbol.getName())
2591
                elif (symbol.width * symbol.height < 1500) or (symbol.width > 450 or symbol.height > 450):
2592
                    continue
2593
                else:
2594
                    smalls.append(symbol.getName())
2595

    
2596
        symbols = [item for item in self.graphicsView.scene().items() if issubclass(type(item), SymbolSvgItem)]
2597
        names = [smalls, bigs]
2598

    
2599
        img = app_doc_data.activeDrawing.image_origin
2600

    
2601
        small_size = 500
2602
        big_size = 850
2603

    
2604
        save_path = project.getTrainingSymbolFilePath()
2605

    
2606
        index = 0
2607
        for size in [small_size, big_size]:
2608
            offsets = [0, int(size / 2)]
2609

    
2610
            width, height = img.shape[1], img.shape[0]
2611
            width_count, height_count = width // size + 2, height // size + 2
2612
            b_width, b_height = width_count * size, height_count * size
2613
            b_img = np.zeros((b_height, b_width), np.uint8) + 255
2614
            b_img[:height, :width] = img[:, :]
2615

    
2616
            for offset in offsets:
2617
                for row in range(height_count):
2618
                    for col in range(width_count):
2619
                        x, y = col * size + offset, row * size + offset
2620
                        tile_rect = QRectF(x, y, size, size)
2621
                        tile_symbols = []
2622
                        for symbol in [symbol for symbol in symbols if symbol.name in names[index]]:
2623
                            if tile_rect.contains(symbol.sceneBoundingRect()):
2624
                                tile_symbols.append(symbol)
2625
                                symbols.remove(symbol)
2626

    
2627
                        if tile_symbols:
2628
                            training_uid = str(uuid.uuid4())
2629
                            training_image_path = os.path.join(save_path, training_uid + '.png')
2630
                            training_xml_path = os.path.join(save_path, training_uid + '.xml')
2631

    
2632
                            # save image
2633
                            #_img = b_img[round(tile_rect.top()):round(tile_rect.bottom()),
2634
                            #       round(tile_rect.left()):round(tile_rect.right())]
2635
                            #cv2.imwrite(training_image_path, _img)
2636
                            _img = self.graphicsView.image().copy(round(tile_rect.left()), round(tile_rect.top()), round(tile_rect.width()), round(tile_rect.height()))
2637
                            _img.save(training_image_path)
2638

    
2639
                            # save label
2640
                            xml = Element('annotation')
2641
                            SubElement(xml, 'folder').text = 'None'
2642
                            SubElement(xml, 'filename').text = os.path.basename(save_path)
2643

    
2644
                            pathNode = Element('path')
2645
                            pathNode.text = save_path.replace('/', '\\')
2646
                            xml.append(pathNode)
2647

    
2648
                            sourceNode = Element('source')
2649
                            databaseNode = Element('database')
2650
                            databaseNode.text = 'Unknown'
2651
                            sourceNode.append(databaseNode)
2652
                            xml.append(sourceNode)
2653

    
2654
                            sizeNode = Element('size')
2655
                            widthNode = Element('width')
2656
                            widthNode.text = str(int(tile_rect.width()))
2657
                            sizeNode.append(widthNode)
2658
                            heightNode = Element('height')
2659
                            heightNode.text = str(int(tile_rect.height()))
2660
                            sizeNode.append(heightNode)
2661
                            depthNode = Element('depth')
2662
                            depthNode.text = '3'
2663
                            sizeNode.append(depthNode)
2664
                            xml.append(sizeNode)
2665

    
2666
                            segmentedNode = Element('segmented')
2667
                            segmentedNode.text = '0'
2668
                            xml.append(segmentedNode)
2669

    
2670
                            labelContent = []
2671
                            counts = {}
2672
                            for item in tile_symbols:
2673
                                rect = item.sceneBoundingRect()
2674
                                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)
2675
                                #label = 'small' if index == 0 else 'big' # for single class test
2676
                                xMin = xMin if xMin > 0 else 0
2677
                                yMin = yMin if yMin > 0 else 0
2678
                                xMax = xMax if xMax < size else size
2679
                                yMax = yMax if yMax < size else size
2680

    
2681
                                if label == 'None' or label == '':
2682
                                    continue
2683
                                if label not in labelContent:
2684
                                    labelContent.append(label)
2685
                                    counts[label] = 1
2686
                                else:
2687
                                    counts[label] = counts[label] + 1
2688

    
2689
                                objectNode = Element('object')
2690
                                nameNode = Element('name')
2691
                                nameNode.text = label
2692
                                objectNode.append(nameNode)
2693
                                poseNode = Element('pose')
2694
                                poseNode.text = 'Unspecified'
2695
                                objectNode.append(poseNode)
2696
                                truncatedNode = Element('truncated')
2697
                                truncatedNode.text = '0'
2698
                                objectNode.append(truncatedNode)
2699
                                difficultNode = Element('difficult')
2700
                                difficultNode.text = '0'
2701
                                objectNode.append(difficultNode)
2702

    
2703
                                bndboxNode = Element('bndbox')
2704
                                xminNode = Element('xmin')
2705
                                xminNode.text = str(xMin)
2706
                                bndboxNode.append(xminNode)
2707
                                yminNode = Element('ymin')
2708
                                yminNode.text = str(yMin)
2709
                                bndboxNode.append(yminNode)
2710
                                xmaxNode = Element('xmax')
2711
                                xmaxNode.text = str(xMax)
2712
                                bndboxNode.append(xmaxNode)
2713
                                ymaxNode = Element('ymax')
2714
                                ymaxNode.text = str(yMax)
2715
                                bndboxNode.append(ymaxNode)
2716
                                objectNode.append(bndboxNode)
2717

    
2718
                                xml.append(objectNode)
2719

    
2720
                            ElementTree(xml).write(training_xml_path)
2721

    
2722
            index += 1
2723

    
2724
        QMessageBox.about(self, self.tr("Notice"), self.tr('Successfully applied. '))
2725

    
2726
    def onPlaceLine(self):
2727
        """create a line"""
2728
        home_pane = self.ribbon.get_pane('Home')
2729

    
2730
        if not self.graphicsView.hasImage():
2731
            home_pane.ui.toolButtonLine.setChecked(False)
2732
            self.showImageSelectionMessageBox()
2733
            return
2734

    
2735
        self.update_action_group(home_pane.ui.toolButtonLine)
2736
        if not hasattr(home_pane.ui.toolButtonLine, 'tag'):
2737
            home_pane.ui.toolButtonLine.tag = PlaceLineCommand.PlaceLineCommand(self.graphicsView)
2738
            home_pane.ui.toolButtonLine.tag.onSuccess.connect(self.onLineCreated)
2739
            home_pane.ui.toolButtonLine.tag.onRejected.connect(self.onCommandRejected)
2740

    
2741
        self.graphicsView.command = home_pane.ui.toolButtonLine.tag
2742

    
2743
    def onLineCreated(self):
2744
        """add created lines to scene"""
2745
        from EngineeringConnectorItem import QEngineeringConnectorItem
2746
        from LineDetector import LineDetector
2747

    
2748
        try:
2749
            app_doc_data = AppDocData.instance()
2750
            home_pane = self.ribbon.get_pane('Home')
2751

    
2752
            count = len(home_pane.ui.toolButtonLine.tag._polyline._vertices)
2753
            if count > 1:
2754
                items = []
2755

    
2756
                detector = LineDetector(None)
2757

    
2758
                if not home_pane.ui.toolButtonLine.tag.line_type:
2759
                    line_type = home_pane.ui.comboBoxLineType.currentText()
2760
                else:
2761
                    pane = self.ribbon.get_pane('Home')
2762
                    selected_line_type = pane.ui.comboBoxLineType.currentText()
2763
                    if selected_line_type == 'Connect To Process':
2764
                        line_type = selected_line_type
2765
                    elif not (QEngineeringLineItem.check_piping(home_pane.ui.toolButtonLine.tag.line_type) ^
2766
                              QEngineeringLineItem.check_piping(selected_line_type)):
2767
                        line_type = selected_line_type
2768
                    else:
2769
                        line_type = home_pane.ui.toolButtonLine.tag.line_type
2770
                for index in range(count - 1):
2771
                    start = home_pane.ui.toolButtonLine.tag._polyline._vertices[index]
2772
                    end = home_pane.ui.toolButtonLine.tag._polyline._vertices[index + 1]
2773

    
2774
                    lineItem = QEngineeringLineItem(vertices=[start, end])
2775
                    lineItem.transfer.onRemoved.connect(self.itemRemoved)
2776
                    lineItem.lineType = line_type
2777
                    if items:
2778
                        lineItem.connect_if_possible(items[-1], 5)
2779
                    else:
2780
                        pt = lineItem.start_point()
2781
                        selected = [item for item in self.graphicsView.scene().items(QPointF(pt[0], pt[1])) if
2782
                                    type(item) is QEngineeringConnectorItem or type(item) is QEngineeringLineItem]
2783
                        if selected and selected[0] is not lineItem:
2784
                            if type(selected[0]) is QEngineeringConnectorItem:
2785
                                lineItem.connect_if_possible(selected[0].parent, 5)
2786
                            else:
2787
                                detector.connectLineToLine(selected[0], lineItem, 5)
2788

    
2789
                    items.append(lineItem)
2790
                    self.graphicsView.scene().addItem(lineItem)
2791

    
2792
                pt = items[-1].end_point()
2793
                selected = [item for item in self.graphicsView.scene().items(QPointF(pt[0], pt[1])) if
2794
                            (type(item) is QEngineeringConnectorItem and item.parentItem() is not items[-1]) or
2795
                            (type(item) is QEngineeringLineItem and item is not items[-1])]
2796
                if selected and selected[0] is not items[-1]:
2797
                    if type(selected[0]) is QEngineeringConnectorItem:
2798
                        items[-1].connect_if_possible(selected[0].parent, 5)
2799
                    else:
2800
                        detector.connectLineToLine(selected[0], items[-1], 5)
2801

    
2802
                self._scene.undo_stack.push(CreateCommand(self._scene, items))
2803
        finally:
2804
            self.graphicsView.scene().removeItem(home_pane.ui.toolButtonLine.tag._polyline)
2805
            home_pane.ui.toolButtonLine.tag.reset()
2806

    
2807
    def onCommandRejected(self, cmd=None):
2808
        """command is rejected"""
2809
        try:
2810
            home_pane = self.ribbon.get_pane('Home')
2811
            visualization_pane = self.ribbon.get_pane('Home Visualization')
2812
            if type(cmd) is PlaceLineCommand.PlaceLineCommand:
2813
                if home_pane.ui.toolButtonLine.tag._polyline:
2814
                    self.graphicsView.scene().removeItem(home_pane.ui.toolButtonLine.tag._polyline)
2815
                self.graphicsView.scene().update()
2816
                home_pane.ui.toolButtonLine.tag.reset()
2817

    
2818
                home_pane.ui.toolButtonLine.setChecked(False)
2819
            elif type(cmd) is AreaZoomCommand.AreaZoomCommand:
2820
                visualization_pane.ui.toolButtonZoom.setChecked(False)
2821
            elif type(cmd) is AreaOcrCommand.AreaOcrCommand:
2822
                home_pane.ui.toolButtonOCR.setChecked(False)
2823
            elif type(cmd) is PlacePolygonCommand.PlacePolygonCommand:
2824
                home_pane.ui.toolButtonVendor.setChecked(False)
2825
            else:
2826
                if hasattr(home_pane.ui.toolButtonVendor, 'tag') and home_pane.ui.toolButtonVendor.tag._polyline:
2827
                    self.graphicsView.scene().removeItem(home_pane.ui.toolButtonVendor.tag._polyline)
2828
                    self.graphicsView.scene().update()
2829
                    home_pane.ui.toolButtonVendor.tag.reset()
2830
                home_pane.ui.toolButtonLine.setChecked(False)
2831
                visualization_pane.ui.toolButtonZoom.setChecked(False)
2832
                home_pane.ui.toolButtonOCR.setChecked(False)
2833
                home_pane.ui.toolButtonVendor.setChecked(False)
2834
        finally:
2835
            self.graphicsView.useDefaultCommand()
2836

    
2837
    def on_view_toggle(self, key: int) -> None:
2838
        """view toggled"""
2839

    
2840
        view_pane = self.ribbon.get_pane('View')
2841
        if key == Qt.Key_1:
2842
            checked = view_pane.ui.toolButtonViewImageDrawing.isChecked()
2843
            self.onViewImageDrawing(not checked)
2844
            view_pane.ui.toolButtonViewImageDrawing.setChecked(not checked)
2845
        elif key == Qt.Key_2:
2846
            checked = view_pane.ui.toolButtonViewText.isChecked()
2847
            self.onViewText(not checked)
2848
            view_pane.ui.toolButtonViewText.setChecked(not checked)
2849
        elif key == Qt.Key_3:
2850
            checked = view_pane.ui.toolButtonViewSymbol.isChecked()
2851
            self.onViewSymbol(not checked)
2852
            view_pane.ui.toolButtonViewSymbol.setChecked(not checked)
2853
        elif key == Qt.Key_4:
2854
            checked = view_pane.ui.toolButtonViewLine.isChecked()
2855
            self.onViewLine(not checked)
2856
            view_pane.ui.toolButtonViewLine.setChecked(not checked)
2857
        elif key == Qt.Key_5:
2858
            checked = view_pane.ui.toolButtonViewUnknown.isChecked()
2859
            self.onViewUnknown(not checked)
2860
            view_pane.ui.toolButtonViewUnknown.setChecked(not checked)
2861
        elif key == Qt.Key_6:
2862
            checked = view_pane.ui.toolButtonViewInconsistency.isChecked()
2863
            self.onViewInconsistency(not checked)
2864
            view_pane.ui.toolButtonViewInconsistency.setChecked(not checked)
2865
        elif key == Qt.Key_7:
2866
            checked = view_pane.ui.toolButtonViewVendorArea.isChecked()
2867
            self.onViewVendorArea(not checked)
2868
            view_pane.ui.toolButtonViewVendorArea.setChecked(not checked)
2869
        elif key == 96:  # '~' key
2870
            checked = view_pane.ui.toolButtonViewDrawingOnly.isChecked()
2871
            self.onViewDrawingOnly(not checked)
2872
            view_pane.ui.toolButtonViewDrawingOnly.setChecked(not checked)
2873

    
2874
    def keyPressEvent(self, event):
2875
        """restore to default command when user press Escape key"""
2876
        try:
2877
            #print('main : ' + str(event.key()))
2878
            if event.key() == Qt.Key_Escape:
2879
                checked = self.checked_action()
2880
                if checked:
2881
                    checked.setChecked(False)
2882
                    self.graphicsView.useDefaultCommand()
2883
            elif event.key() == Qt.Key_M:  # merge text, line
2884
                from TextInfo import TextInfo
2885
                from EngineeringConnectorItem import QEngineeringConnectorItem
2886
                from LineDetector import LineDetector
2887

    
2888
                # line merge
2889
                lineItems = [line for line in self.graphicsView.scene().selectedItems() if
2890
                             issubclass(type(line), QEngineeringLineItem)]
2891
                lineValidation = True
2892
                if len(lineItems) > 1:
2893
                    x = []
2894
                    y = []
2895
                    connectedItems = []
2896
                    isVertical = None
2897
                    for line in lineItems:
2898
                        if isVertical == None:
2899
                            isVertical = line.isVertical()
2900
                        elif isVertical != line.isVertical():
2901
                            lineValidation = False
2902

    
2903
                        x.append(line.start_point()[0])
2904
                        y.append(line.start_point()[1])
2905
                        x.append(line.end_point()[0])
2906
                        y.append(line.end_point()[1])
2907

    
2908
                        if line.connectors[0].connectedItem:
2909
                            connectedItems.append(line.connectors[0].connectedItem)
2910
                        if line.connectors[1].connectedItem:
2911
                            connectedItems.append(line.connectors[1].connectedItem)
2912

    
2913
                    if lineValidation:
2914
                        startPoint = [min(x), min(y)]
2915
                        endPoint = [max(x), max(y)]
2916
                        lineItem = QEngineeringLineItem(vertices=[startPoint, endPoint])
2917
                        lineItem.transfer.onRemoved.connect(self.itemRemoved)
2918
                        lineItem.lineType = lineItems[0].lineType
2919

    
2920
                        for line in lineItems:
2921
                            line.transfer.onRemoved.emit(line)
2922

    
2923
                        detector = LineDetector(None)
2924

    
2925
                        for pt in [startPoint, endPoint]:
2926
                            selected = [item for item in self.graphicsView.scene().items(QPointF(pt[0], pt[1])) if
2927
                                        type(item) is QEngineeringConnectorItem or type(item) is QEngineeringLineItem]
2928
                            if selected:
2929
                                if type(selected[0]) is QEngineeringConnectorItem:
2930
                                    lineItem.connect_if_possible(selected[0].parent, 5)
2931
                                elif selected[0] in connectedItems:
2932
                                    lineItem.connect_if_possible(selected[0], 5)
2933
                                else:
2934
                                    detector.connectLineToLine(selected[0], lineItem, 5)
2935

    
2936
                        self.graphicsView.scene().addItem(lineItem)
2937
                # up to here
2938

    
2939
                # text merge
2940
                textItems = [text for text in self.graphicsView.scene().selectedItems() if
2941
                             issubclass(type(text), QEngineeringTextItem)]
2942
                if len(textItems) > 1:
2943
                    angle = None
2944
                    for item in textItems:
2945
                        if angle is None:
2946
                            angle = item.angle
2947
                        else:
2948
                            if angle != item.angle:
2949
                                return
2950

    
2951
                    modifiers = QApplication.keyboardModifiers()
2952
                    enter_or_space = ' ' if modifiers == Qt.ControlModifier else '\n'
2953
                    x_or_y = 0 if (modifiers == Qt.ControlModifier and angle == 0) or (modifiers != Qt.ControlModifier and angle == 1.57) else 1
2954

    
2955
                    textItems = sorted(textItems, key=lambda text: text.loc[x_or_y]) if textItems[0].angle == 0 else ( \
2956
                        sorted(textItems, key=lambda text: text.loc[x_or_y]) if textItems[0].angle == 1.57 else ( \
2957
                            sorted(textItems, key=lambda text: text.loc[x_or_y], reverse=True) if textItems[0].angle == 4.71 else \
2958
                                sorted(textItems, key=lambda text: text.loc[x_or_y], reverse=True)))
2959

    
2960
                    if textItems[0].angle == 1.57 and modifiers == Qt.ControlModifier:
2961
                        textItems.reverse()
2962

    
2963
                    minX = sys.maxsize
2964
                    minY = sys.maxsize
2965
                    maxX = 0
2966
                    maxY = 0
2967
                    newText = ''
2968

    
2969
                    for text in textItems:
2970
                        if text.loc[0] < minX: minX = text.loc[0]
2971
                        if text.loc[1] < minY: minY = text.loc[1]
2972
                        if text.loc[0] + text.size[0] > maxX: maxX = text.loc[0] + text.size[0]
2973
                        if text.loc[1] + text.size[1] > maxY: maxY = text.loc[1] + text.size[1]
2974
                        newText = newText + text.text() + enter_or_space
2975
                        text.transfer.onRemoved.emit(text)
2976
                    newText = newText[:-1]
2977

    
2978
                    textInfo = TextInfo(newText, minX, minY, maxX - minX, maxY - minY, textItems[0].angle)
2979
                    item = QEngineeringTextItem.create_text_with(self.graphicsView.scene(), textInfo)
2980
                    if item is not None:
2981
                        item.area = textItems[0].area
2982
                        #item.setDefaultTextColor(Qt.blue)
2983
                        item.transfer.onRemoved.connect(self.itemRemoved)
2984
                # up to here
2985
            elif event.key() == Qt.Key_D:
2986
                # pop up development toolkit dialog
2987
                from DevelopmentToolkitDialog import QDevelopmentToolkitDialog
2988

    
2989
                modifiers = QApplication.keyboardModifiers()
2990
                if modifiers == Qt.ControlModifier:
2991
                    dlg = QDevelopmentToolkitDialog(self, self.graphicsView)
2992
                    dlg.show()
2993
            elif event.key() == Qt.Key_I:
2994
                # insert symbol item that is selected symbol in tree to main window if symbol already selected on main window, replace
2995
                index = self.symbolTreeWidget.currentIndex()
2996
                proxy_model = self.symbolTreeWidget.model()
2997
                items = [proxy_model.sourceModel().itemFromIndex(proxy_model.mapToSource(index))]
2998
                if items and hasattr(items[0], 'svgFilePath'):
2999
                    symData = items[0].data(self.symbolTreeWidget.TREE_DATA_ROLE)
3000
                    symName = symData.getName()
3001
                else:
3002
                    return
3003

    
3004
                symbolItems = [symbol for symbol in self.graphicsView.scene().selectedItems() if
3005
                               issubclass(type(symbol), SymbolSvgItem)]
3006
                old_symbol = None
3007
                if symbolItems and len(symbolItems) is 1:
3008
                    old_symbol = symbolItems[0]
3009
                    #scenePos = QPoint(old_symbol.origin[0], old_symbol.origin[1])
3010
                    scenePos = old_symbol.mapToScene(old_symbol.transformOriginPoint())
3011
                    old_symbol.transfer.onRemoved.emit(old_symbol)
3012
                else:
3013
                    scenePos = self.current_pos
3014

    
3015
                svg = QtImageViewer.createSymbolObject(symName)
3016
                QtImageViewer.matchSymbolToLine(self.graphicsView.scene(), svg, scenePos, angle=old_symbol.angle if old_symbol else 0.0)
3017

    
3018
                if old_symbol and svg:
3019
                    from ReplaceCommand import ReplaceCommand
3020

    
3021
                    cmd = ReplaceCommand(self.graphicsView.scene(), old_symbol, svg)
3022
                    self._scene.undo_stack.push(cmd)
3023
                    return
3024
            elif event.key() == Qt.Key_J:
3025
                # insert and connect symbol item that is selected symbol in tree to selected symbol
3026
                index = self.symbolTreeWidget.currentIndex()
3027
                proxy_model = self.symbolTreeWidget.model()
3028
                items = [proxy_model.sourceModel().itemFromIndex(proxy_model.mapToSource(index))]
3029
                if items and hasattr(items[0], 'svgFilePath'):
3030
                    symData = items[0].data(self.symbolTreeWidget.TREE_DATA_ROLE)
3031
                    symName = symData.getName()
3032
                else:
3033
                    return
3034

    
3035
                symbolItems = [symbol for symbol in self.graphicsView.scene().selectedItems() if
3036
                               issubclass(type(symbol), SymbolSvgItem)]
3037
                if len(symbolItems) is not 1:
3038
                    return
3039
                    
3040
                target_symbol = symbolItems[0]
3041
                index =  [index for index in range(len(target_symbol.conn_type)) \
3042
                            if target_symbol.conn_type[index] == 'Primary' or target_symbol.conn_type[index] == 'Secondary']
3043
                for connector in target_symbol.connectors:
3044
                    svg = QtImageViewer.createSymbolObject(symName)
3045
                    if len(svg.connectors) > 1: 
3046
                        if ((target_symbol.conn_type and target_symbol.connectors.index(connector) in index) or not target_symbol.conn_type) and \
3047
                                    (not connector.connectedItem or (connector.connectedItem and type(connector.connectedItem) is QEngineeringLineItem)):
3048
                            QtImageViewer.matchSymbolToLine(self.graphicsView.scene(), svg, connector.sceneBoundingRect().center())
3049
                    elif len(svg.connectors) == 1:
3050
                        if ((target_symbol.conn_type and target_symbol.connectors.index(connector) in index) or not target_symbol.conn_type) and \
3051
                                    not connector.connectedItem:
3052
                            QtImageViewer.matchSymbolToLine(self.graphicsView.scene(), svg, connector.sceneBoundingRect().center())
3053

    
3054
                if target_symbol:
3055
                    return
3056
            elif event.key() == Qt.Key_X:
3057
                pass
3058
                '''
3059
                app_doc_data = AppDocData.instance()
3060
                configs = app_doc_data.getAppConfigs('app', 'mode')
3061
                if configs and 1 == len(configs) and 'advanced' == configs[0].value:
3062
                    advanced = True
3063
                    items = self.graphicsView.scene().selectedItems()
3064
                    if items:
3065
                        item = self.symbolTreeWidget.currentItem()
3066
                        if item:
3067
                            self.symbolTreeWidget.showSymbolEditorDialog(item, 0)
3068
                '''
3069
            elif event.key() == Qt.Key_F6:
3070
                from DEXPI import scene_to_dexpi
3071

    
3072
                app_doc_data = AppDocData.instance()
3073
                scene_to_dexpi('D:\\Temp\\DEXPI.xml', app_doc_data.activeDrawing.name, self.graphicsView.scene())
3074

    
3075
            QMainWindow.keyPressEvent(self, event)
3076
        except Exception as ex:
3077
            message = f"error occurred({repr(ex)}) in {sys.exc_info()[-1].tb_frame.f_code.co_filename}:" \
3078
                      f"{sys.exc_info()[-1].tb_lineno}"
3079
            self.addMessage.emit(MessageType.Error, message)
3080

    
3081
    def recognize(self):
3082
        """recognize symbol, text and line for selected drawings"""
3083
        from datetime import datetime
3084
        from License import QLicenseDialog
3085

    
3086
        # save alarm
3087
        self.save_alarm_enable(False)
3088

    
3089
        app_doc_data = AppDocData.instance()
3090
        current_drawing, currentPid = None, None
3091

    
3092
        if self.graphicsView.hasImage():
3093
            current_drawing = app_doc_data.activeDrawing
3094
            currentPid = app_doc_data.activeDrawing.name
3095

    
3096
        # get checked drawings
3097
        drawing_top = self.treeWidgetDrawingList.topLevelItem(0)
3098
        count = drawing_top.childCount()
3099
        checked_drawings = {}
3100
        for idx in range(count):
3101
            child = drawing_top.child(idx)
3102
            if child.checkState(0) == Qt.Checked and child.data(Qt.UserRole, 0):
3103
                checked_drawings[child.data(Qt.UserRole, 0)] = child
3104
        # up to here
3105

    
3106
        # if there is no checked drawing
3107
        if current_drawing and currentPid and not checked_drawings:
3108
            for idx in range(count):
3109
                child = drawing_top.child(idx)
3110
                if child.data(Qt.UserRole, 0) is current_drawing:
3111
                    checked_drawings[child.data(Qt.UserRole, 0)] = child
3112

    
3113
        if not checked_drawings:
3114
            self.showImageSelectionMessageBox()
3115
            return
3116

    
3117
        try:
3118
            self.on_clear_log()
3119
            dlg = QRecognitionDialog(self, [drawing for drawing in checked_drawings.keys()])
3120
            dlg.exec_()
3121

    
3122
            if current_drawing and current_drawing in checked_drawings.keys() and dlg.isTreated:
3123
                self.open_image_drawing(current_drawing, force=True, ocrUnknown=dlg.ui.checkBoxOCRUnknown.isChecked())
3124

    
3125
            # save working date-time
3126
            _now = datetime.now().strftime('%Y-%m-%d %H:%M:%S')
3127
            for drawing, tree_item in checked_drawings.items():
3128
                drawing.datetime = _now
3129
                tree_item.setText(1, _now)
3130
            #app_doc_data.saveDrawings(checked_drawings.keys())
3131
            self.changeViewCheckedState(True)
3132
            # count up for recognition
3133
            QLicenseDialog.count_up()
3134
            # up to here
3135
        except Exception as ex:
3136
            message = f"error occurred({repr(ex)}) in {sys.exc_info()[-1].tb_frame.f_code.co_filename}:" \
3137
                      f"{sys.exc_info()[-1].tb_lineno}"
3138
            self.addMessage.emit(MessageType.Error, message)
3139

    
3140
        # save alarm
3141
        self.save_alarm_enable(True, True)
3142

    
3143
    '''
3144
        @brief      remove item from tree widget and then remove from scene
3145
        @date       2018.05.25
3146
        @author     Jeongwoo
3147
    '''
3148
    def itemRemoved(self, item):
3149
        try:
3150
            if type(item) is QEngineeringErrorItem:
3151
                # remove error item from inconsistency list
3152
                for row in range(self.tableWidgetInconsistency.rowCount()):
3153
                    if item is self.tableWidgetInconsistency.item(row, 0).tag:
3154
                        self.tableWidgetInconsistency.removeRow(row)
3155
                        break
3156

    
3157
                if item.scene() is not None:
3158
                    item.scene().removeItem(item)
3159
                del item
3160
            else:
3161
                remove_scene = item.scene()
3162
                self.itemTreeWidget.itemRemoved(item)
3163

    
3164
                if remove_scene:
3165
                    matches = [_item for _item in remove_scene.items() if
3166
                            hasattr(_item, 'connectors') and [connector for connector in _item.connectors if
3167
                                                                connector.connectedItem is item]]
3168
                    for match in matches:
3169
                        for connector in match.connectors:
3170
                            if connector.connectedItem is item:
3171
                                connector.connectedItem = None
3172
                                connector.highlight(False)
3173

    
3174
                # matches = [_item for _item in self.graphicsView.scene().items() if hasattr(_item, 'remove_assoc_item')]
3175
                # for _item in matches:
3176
                #    _item.remove_assoc_item(item)
3177

    
3178
                app_doc_data = AppDocData.instance()
3179
                if type(item) is QEngineeringLineNoTextItem and item in app_doc_data.tracerLineNos:
3180
                    app_doc_data.tracerLineNos.pop(app_doc_data.tracerLineNos.index(item))
3181

    
3182
                if type(item) is QEngineeringLineItem and item in app_doc_data.lines:
3183
                    app_doc_data.lines.remove(item)
3184

    
3185
                if remove_scene:
3186
                    matches = [_item for _item in remove_scene.items() if
3187
                            type(_item) is QEngineeringLineNoTextItem]
3188
                    matches.extend([lineNo for lineNo in app_doc_data.tracerLineNos if
3189
                                    type(lineNo) is QEngineeringTrimLineNoTextItem])
3190
                    for match in matches:
3191
                        if item is match.prop('From'):
3192
                            match.set_property('From', None)
3193
                        if item is match.prop('To'):
3194
                            match.set_property('To', None)
3195

    
3196
                        for run_index in reversed(range(len(match.runs))):
3197
                            run = match.runs[run_index]
3198
                            if item in run.items:
3199
                                index = run.items.index(item)
3200
                                run.items.pop(index)
3201
                                if not run.items:
3202
                                    run.explode()
3203
                                    if type(match) is QEngineeringTrimLineNoTextItem and not match.runs:
3204
                                        app_doc_data.tracerLineNos.pop(app_doc_data.tracerLineNos.index(match))
3205
                                # break
3206

    
3207
                if remove_scene:
3208
                    matches = [_item for _item in remove_scene.items() if hasattr(_item, 'owner')]
3209
                    for match in matches:
3210
                        if match.owner is item:
3211
                            match.owner = None
3212

    
3213
                    matches = [_item for _item in remove_scene.items() if hasattr(_item, 'attrs')]
3214
                    # done = False
3215
                    for match in matches:
3216
                        assocs = match.associations()
3217
                        for assoc in assocs:
3218
                            if item is assoc:
3219
                                keys = match.attrs.keys()
3220
                                for attr in keys:
3221
                                    if attr.AssocItem and str(item.uid) == str(attr.AssocItem.uid):
3222
                                        attr.AssocItem = None
3223
                                        match.attrs[attr] = ''
3224
                                        # done = True
3225
                                match.remove_assoc_item(item)
3226
                                break
3227
                        # if done: break
3228

    
3229
                if item.scene() is not None:
3230
                    #if type(item) is QEngineeringLineNoTextItem and item._labels:
3231
                    #    for _label in item._labels:
3232
                    #        item.scene().removeItem(_label)
3233
                    #    item._labels = []
3234
                    
3235
                    item.hoverLeaveEvent(None)
3236
                    if hasattr(item, 'lineNoFromToIndicator') and item.lineNoFromToIndicator:
3237
                        item.scene().removeItem(item.lineNoFromToIndicator[0])
3238
                        item.scene().removeItem(item.lineNoFromToIndicator[1])
3239
                    item.scene().removeItem(item)
3240
        except Exception as ex:
3241
            message = 'error occurred({}) in {}:{}'.format(ex, sys.exc_info()[-1].tb_frame.f_code.co_filename,
3242
                                                           sys.exc_info()[-1].tb_lineno)
3243
            self.addMessage.emit(MessageType.Error, message)
3244
        '''
3245
        finally:
3246
            if hasattr(item, '_cond'):
3247
                item._cond.wakeAll()
3248
        '''
3249

    
3250

    
3251
    def connect_attributes(self, MainWindow):
3252
        """connect attributes to symbol"""
3253
        from LineNoTracer import LineNoTracer
3254
        from ConnectAttrDialog import QConnectAttrDialog
3255

    
3256
        if not self.graphicsView.hasImage():
3257
            self.showImageSelectionMessageBox()
3258
            return
3259

    
3260
        # save alarm
3261
        self.save_alarm_enable(False)
3262

    
3263
        try:
3264
            dlg = QConnectAttrDialog(self, self.graphicsView.scene())
3265
            dlg.setWindowFlags(self.windowFlags() & ~Qt.WindowCloseButtonHint & ~Qt.WindowContextHelpButtonHint)
3266
            dlg.exec_()
3267
            if dlg.isRunned:
3268
                self.refresh_item_list()
3269

    
3270
                if dlg.validation_checked:
3271
                    self.onValidation()
3272

    
3273
                self.graphicsView.invalidateScene()
3274
        except Exception as ex:
3275
            message = 'error occurred({}) in {}:{}'.format(ex, sys.exc_info()[-1].tb_frame.f_code.co_filename,
3276
                                                           sys.exc_info()[-1].tb_lineno)
3277
            self.addMessage.emit(MessageType.Error, message)
3278
        finally:
3279
            # save alarm
3280
            self.save_alarm_enable(True)
3281

    
3282
    def postDetectLineProcess(self):
3283
        '''
3284
            @brief  check allowables among undetected items
3285
            @author euisung
3286
            @date   2018.11.15
3287
            @history    2018.11.15  euisung    no more used, moved to TextItemFactoy isLineNo()
3288
        '''
3289

    
3290
        appDocData = AppDocData.instance()
3291

    
3292
        tableNames = ["Fluid Code", "Insulation Purpose", "PnID Number", "Piping Materials Class", "Unit Number"]
3293
        tableDatas = []
3294
        for tableName in tableNames:
3295
            tableNameFormat = tableName.replace(' ', '').replace('&&', 'n')
3296
            tableDatas.append(appDocData.getCodeTable(tableNameFormat))
3297

    
3298
        items = self.graphicsView.scene().items()
3299
        for item in items:
3300
            if type(item) is not QEngineeringTextItem:
3301
                continue
3302
            text = item.text()
3303
            for tableData in tableDatas:
3304
                for data in tableData:
3305
                    if data[3] == '':
3306
                        continue
3307
                    else:
3308
                        allows = data[3].split(',')
3309
                        for allow in allows:
3310
                            text = text.replace(allow, data[1])
3311

    
3312
            lineItem = TextItemFactory.instance().createTextItem(text)
3313
            if type(lineItem) is QEngineeringLineNoTextItem:
3314
                lineItem.loc = item.loc
3315
                lineItem.size = item.size
3316
                lineItem.angle = item.angle
3317
                lineItem.area = item.area
3318
                # lineItem.addTextItemToScene(self.graphicsView.scene())
3319
                lineItem.transfer.onRemoved.connect(self.itemRemoved)
3320
                item.transfer.onRemoved.emit(item)
3321
                appDocData.lineNos.append(lineItem)
3322

    
3323
    def init_add_tree_item(self, line_no_tree_item, run_item):
3324
        """ insert symbol item and find line no as owner """
3325
        # insert
3326
        self.itemTreeWidget.addTreeItem(line_no_tree_item, run_item)
3327
        # find
3328
        self.itemTreeWidget.addTreeItem(line_no_tree_item, run_item)
3329

    
3330
    def load_drawing(self, drawing):
3331
        """ load drawing """
3332
        """ no more used """
3333
        from EngineeringRunItem import QEngineeringRunItem
3334
        from QEngineeringTrimLineNoTextItem import QEngineeringTrimLineNoTextItem
3335

    
3336
        app_doc_data = AppDocData.instance()
3337
        try:
3338
            symbols = []
3339
            lines = []
3340

    
3341
            components = app_doc_data.get_components(drawing.UID)
3342
            maxValue = len(components) * 2
3343
            self.progress.setMaximum(maxValue) if maxValue > 0 else None
3344

    
3345
            """ parsing all symbols """
3346
            for symbol in [component for component in components if int(component['SymbolType_UID']) != -1]:
3347
                item = SymbolSvgItem.from_database(symbol)
3348
                if item is not None:
3349
                    item.transfer.onRemoved.connect(self.itemRemoved)
3350
                    symbols.append(item)
3351
                    app_doc_data.symbols.append(item)
3352
                    item.addSvgItemToScene(self.graphicsView.scene())
3353
                else:
3354
                    pt = [float(symbol['X']), float(symbol['Y'])]
3355
                    size = [float(symbol['Width']), float(symbol['Height'])]
3356
                    angle = float(symbol['Rotation'])
3357
                    item = QGraphicsBoundingBoxItem(pt[0], pt[1], size[0], size[1])
3358
                    item.isSymbol = True
3359
                    item.angle = angle
3360
                    item.setPen(QPen(Qt.red, 5, Qt.SolidLine))
3361
                    self.graphicsView.scene().addItem(item)
3362
                    item.transfer.onRemoved.connect(self.itemRemoved)
3363

    
3364
                self.progress.setValue(self.progress.value() + 1)
3365

    
3366
            QApplication.processEvents()
3367

    
3368
            # parse texts
3369
            for text in [component for component in components if
3370
                         component['Name'] == 'Text' and component['SymbolType_UID'] == -1]:
3371
                item = QEngineeringTextItem.from_database(text)
3372
                if item is not None:
3373
                    item.uid = text['UID']
3374
                    item.attribute = text['Value']
3375
                    name = text['Name']
3376
                    item.transfer.onRemoved.connect(self.itemRemoved)
3377
                    item.addTextItemToScene(self.graphicsView.scene())
3378

    
3379
                self.progress.setValue(self.progress.value() + 1)
3380

    
3381
            QApplication.processEvents()
3382

    
3383
            # note
3384
            for note in [component for component in components if
3385
                         component['Name'] == 'Note' and component['SymbolType_UID'] == -1]:
3386
                item = QEngineeringTextItem.from_database(note)
3387
                if item is not None:
3388
                    item.uid = note['UID']
3389
                    attributeValue = note['Value']
3390
                    name = note['Name']
3391
                    item.transfer.onRemoved.connect(self.itemRemoved)
3392
                    item.addTextItemToScene(self.graphicsView.scene())
3393

    
3394
                self.progress.setValue(self.progress.value() + 1)
3395

    
3396
            QApplication.processEvents()
3397

    
3398
            for line in [component for component in components if
3399
                         component['Name'] == 'Line' and component['SymbolType_UID'] == -1]:
3400
                item = QEngineeringLineItem.from_database(line)
3401
                if item:
3402
                    item.transfer.onRemoved.connect(self.itemRemoved)
3403
                    self.graphicsView.scene().addItem(item)
3404
                    lines.append(item)
3405

    
3406
                self.progress.setValue(self.progress.value() + 1)
3407

    
3408
            QApplication.processEvents()
3409

    
3410
            for unknown in [component for component in components if
3411
                            component['Name'] == 'Unknown' and component['SymbolType_UID'] == -1]:
3412
                item = QEngineeringUnknownItem.from_database(unknown)
3413
                item.transfer.onRemoved.connect(self.itemRemoved)
3414
                if item is not None:
3415
                    item.transfer.onRemoved.connect(self.itemRemoved)
3416
                    self.graphicsView.scene().addItem(item)
3417

    
3418
                self.progress.setValue(self.progress.value() + 1)
3419

    
3420
            QApplication.processEvents()
3421

    
3422
            for component in [component for component in components if
3423
                              component['Name'] == 'Line NO' and component['SymbolType_UID'] == -1]:
3424
                line_no = QEngineeringLineNoTextItem.from_database(component)
3425
                if type(line_no) is QEngineeringLineNoTextItem:
3426
                    line_no.transfer.onRemoved.connect(self.itemRemoved)
3427
                    self.addTextItemToScene(line_no)
3428
                    line_no_tree_item = self.itemTreeWidget.addTreeItem(self.itemTreeWidget.root, line_no)
3429

    
3430
                    runs = app_doc_data.get_pipe_runs(str(line_no.uid))
3431
                    if not runs: continue
3432
                    for run in runs:
3433
                        line_run = QEngineeringRunItem()
3434
                        run_items = app_doc_data.get_pipe_run_items(run['UID'])
3435
                        for record in run_items:
3436
                            uid = record['Components_UID']
3437
                            run_item = self.graphicsView.findItemByUid(uid)
3438
                            if run_item is not None:
3439
                                run_item._owner = line_no
3440
                                line_run.items.append(run_item)
3441
                        line_run.owner = line_no
3442
                        line_no.runs.append(line_run)
3443

    
3444
                        for run_item in line_run.items:
3445
                            if issubclass(type(run_item), SymbolSvgItem):
3446
                                self.init_add_tree_item(line_no_tree_item, run_item)
3447

    
3448
                self.progress.setValue(self.progress.value() + 1)
3449
            QApplication.processEvents()
3450

    
3451
            for component in [component for component in components if
3452
                              component['Name'] == 'Trim Line NO' and component['SymbolType_UID'] == -1]:
3453
                line_no = QEngineeringTrimLineNoTextItem()
3454
                line_no.uid = uuid.UUID(component['UID'])
3455

    
3456
                runs = app_doc_data.get_pipe_runs(str(line_no.uid))
3457
                if not runs: continue
3458

    
3459
                line_no_tree_item = self.itemTreeWidget.addTreeItem(self.itemTreeWidget.root, line_no)
3460

    
3461
                for run in runs:
3462
                    line_run = QEngineeringRunItem()
3463
                    run_items = app_doc_data.get_pipe_run_items(run['UID'])
3464
                    for record in run_items:
3465
                        uid = record['Components_UID']
3466
                        run_item = self.graphicsView.findItemByUid(uid)
3467
                        if run_item is not None:
3468
                            run_item.owner = line_no
3469
                            line_run.items.append(run_item)
3470
                    line_run.owner = line_no
3471
                    line_no.runs.append(line_run)
3472

    
3473
                    for run_item in line_run.items:
3474
                        if issubclass(type(run_item), SymbolSvgItem):
3475
                            self.init_add_tree_item(line_no_tree_item, run_item)
3476

    
3477
                app_doc_data.tracerLineNos.append(line_no)
3478

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

    
3481
            for component in [component for component in components if
3482
                              component['Name'] == 'VendorPackage' and component['SymbolType_UID'] == -1]:
3483
                item = QEngineeringVendorItem.from_database(component)
3484
                if item is not None:
3485
                    item.transfer.onRemoved.connect(self.itemRemoved)
3486
                    self.graphicsView.scene().addItem(item)
3487

    
3488
            # connect flow item to line
3489
            for line in lines:
3490
                line.update_arrow()
3491
                app_doc_data.lines.append(line)
3492
            # for flowMark in [item for item in symbols if type(item) is QEngineeringFlowMarkItem]:
3493
            #    for line in lines:
3494
            #        if flowMark.owner is line:
3495
            #            line._flowMark.append(flowMark)
3496
            #            flowMark.setParentItem(line)
3497
            # up to here
3498

    
3499
            """ update scene """
3500
            self.graphicsView.scene().update(self.graphicsView.sceneRect())
3501
            for item in self.graphicsView.scene().items():
3502
                up_progress = False
3503
                # binding items
3504
                if hasattr(item, 'owner'):
3505
                    item.owner
3506
                    up_progress = True
3507
                if hasattr(item, 'connectors'):
3508
                    for connector in item.connectors:
3509
                        connector.connectedItem
3510
                    up_progress = True
3511

    
3512
                if up_progress:
3513
                    self.progress.setValue(self.progress.value() + 1)
3514
            
3515
            for item in self.graphicsView.scene().items():
3516
                item.setVisible(True)
3517

    
3518
        except Exception as ex:
3519
            message = 'error occurred({}) in {}:{}'.format(ex, sys.exc_info()[-1].tb_frame.f_code.co_filename,
3520
                                                           sys.exc_info()[-1].tb_lineno)
3521
            self.addMessage.emit(MessageType.Error, message)
3522
        finally:
3523
            app_doc_data.clearTempDBData()
3524
            self.itemTreeWidget.update_item_count()
3525
            self.itemTreeWidget.expandAll()
3526
            # self.graphicsView.scene().blockSignals(False)
3527

    
3528
    '''
3529
        @brief      load recognition result
3530
        @author     humkyung
3531
        @date       2018.04.??
3532
        @history    humkyung 2018.01.12 parse originalpoint and connectionpoint
3533
                    Jeongwoo 2018.04.17 add QGraphicItem with Rotated text
3534
                    Jeongwoo 2018.04.23 Change to Draw texts on QEngineeringTextItem
3535
                    humkyung 2018.04.23 connect item remove slot to result tree
3536
                    Jeongwoo 2018.04.25 Add if state with QEngineeringNoteItem
3537
                    Jeongwoo 2018.04.26 Change method to create TextItem object with TextItemFactory
3538
                    Jeongwoo 2018.05.03 Change method to draw Svg Item on Scene (svg.addSvgItemToScene)
3539
                    Jeongwoo 2018.05.29 Change method name / Change method to add item / Add Line item
3540
                    Jeongwoo 2018.05.30 Add parameters on SymbolSvgItem.__init__() (parentSymbol, childSymbol) / Change method name / Change XML NODE NAMES
3541
                    Jeongwoo 2018.06.12 Add LineNoTextItem from LINE_NO
3542
                    Jeongwoo 2018.06.14 Add UnknownItem from UNKNOWN
3543
                    Jeongwoo 2018.06.18 Update Scene after all item added
3544
                                        Add connect on unknown item
3545
                                        Add [transfer] for using pyqtSignal
3546
                    kyouho  2018.07.12  Add line property logic
3547
                    humkyung 2018.08.22 show progress while loading xml file
3548
                    2018.11.22      euisung     fix note road
3549
    '''
3550
    def load_recognition_result_from_xml(self, drawing):
3551
        # Yield successive n-sized
3552
        # chunks from l.
3553
        def divide_chunks(l, n):
3554
            # looping till length l
3555
            for i in range(0, len(l), n):
3556
                yield l[i:i + n]
3557

    
3558
        def update_items(items):
3559
            for item in items:
3560
                # binding items
3561
                item.owner
3562
                for connector in item.connectors:
3563
                    connector.connectedItem
3564

    
3565
            return items
3566

    
3567
        import concurrent.futures as futures
3568
        from xml.etree.ElementTree import Element, SubElement, dump, ElementTree, parse
3569
        from App import App
3570
        from EngineeringRunItem import QEngineeringRunItem
3571
        from QEngineeringTrimLineNoTextItem import QEngineeringTrimLineNoTextItem
3572
        from EngineeringGraphicsLineItem import QEngineeringGraphicsLineItem
3573

    
3574
        app_doc_data = AppDocData.instance()
3575

    
3576
        try:
3577
            file_name = os.path.splitext(os.path.basename(drawing.file_path))[0]
3578
            path = os.path.join(app_doc_data.getCurrentProject().getTempPath(), file_name + '.xml')
3579
            self.graphicsView.scene().blockSignals(True)
3580

    
3581
            symbols = []
3582
            lines = []
3583

    
3584
            xml = parse(path)
3585
            root = xml.getroot()
3586

    
3587
            maxValue = 0
3588
            maxValue = maxValue + len(list(root.iter('SYMBOL'))) - \
3589
                       len(list(root.iterfind('LINENOS/LINE_NO/RUN/SYMBOL'))) - \
3590
                       len(list(root.iterfind('TRIMLINENOS/TRIM_LINE_NO/RUN/SYMBOL')))
3591
            maxValue = maxValue + len(list(root.iterfind('TEXTINFOS/ATTRIBUTE')))
3592
            maxValue = maxValue + len(list(root.iterfind('NOTES/ATTRIBUTE')))
3593
            maxValue = maxValue + len(list(root.iter('LINE_NO')))
3594
            maxValue = maxValue + len(list(root.iter('LINE'))) - \
3595
                       len(list(root.iterfind('LINENOS/LINE_NO/RUN/LINE'))) - \
3596
                       len(list(root.iterfind('TRIMLINENOS/TRIM_LINE_NO/RUN/LINE')))
3597
            maxValue = maxValue + len(list(root.iter('GRAPHICS_LINE')))
3598
            maxValue = maxValue + len(list(root.iter('UNKNOWN')))
3599
            # maxValue = maxValue + len(list(root.iter('SIZETEXT')))
3600
            maxValue = maxValue + len(list(root.iter('TRIM_LINE_NO')))
3601
            maxValue *= 2
3602
            self.progress.setMaximum(maxValue) if maxValue > 0 else None
3603

    
3604
            """ parsing all symbols """
3605
            """
3606
            with futures.ThreadPoolExecutor(max_workers=App.THREAD_MAX_WORKER) as pool:
3607
                future_symbol = {pool.submit(SymbolSvgItem.fromXml, symbol): symbol for symbol in root.find('SYMBOLS').iter('SYMBOL')}
3608

3609
                for future in futures.as_completed(future_symbol):
3610
                    try:
3611
                        item = future.result()
3612
                        if item:
3613
                            if item is not None:
3614
                                item.transfer.onRemoved.connect(self.itemRemoved)
3615
                                symbols.append(item)
3616
                                docData.symbols.append(item)
3617
                                self.addSvgItemToScene(item)
3618
                            else:
3619
                                pt = [float(x) for x in symbol.find('LOCATION').text.split(',')]
3620
                                size = [float(x) for x in symbol.find('SIZE').text.split(',')]
3621
                                angle = float(symbol.find('ANGLE').text)
3622
                                item = QGraphicsBoundingBoxItem(pt[0], pt[1], size[0], size[1])
3623
                                item.isSymbol = True
3624
                                item.angle = angle
3625
                                item.setPen(QPen(Qt.red, 5, Qt.SolidLine))
3626
                                self.graphicsView.scene().addItem(item)
3627
                                item.transfer.onRemoved.connect(self.itemRemoved)
3628
                    except Exception as ex:
3629
                        message = 'error occurred({}) in {}:{}'.format(repr(ex), sys.exc_info()[-1].tb_frame.f_code.co_filename,
3630
                                                                       sys.exc_info()[-1].tb_lineno)
3631

3632
            """
3633
            for symbol in root.find('SYMBOLS').iter('SYMBOL'):
3634
                item = SymbolSvgItem.fromXml(symbol)
3635
                if item is not None:
3636
                    item.transfer.onRemoved.connect(self.itemRemoved)
3637
                    symbols.append(item)
3638
                    #app_doc_data.symbols.append(item)
3639
                    item.addSvgItemToScene(self.graphicsView.scene())
3640
                else:
3641
                    pt = [float(x) for x in symbol.find('LOCATION').text.split(',')]
3642
                    size = [float(x) for x in symbol.find('SIZE').text.split(',')]
3643
                    angle = float(symbol.find('ANGLE').text)
3644
                    item = QGraphicsBoundingBoxItem(pt[0], pt[1], size[0], size[1])
3645
                    item.isSymbol = True
3646
                    item.angle = angle
3647
                    item.setPen(QPen(Qt.red, 5, Qt.SolidLine))
3648
                    self.graphicsView.scene().addItem(item)
3649
                    item.transfer.onRemoved.connect(self.itemRemoved)
3650

    
3651
                self.progress.setValue(self.progress.value() + 1)
3652

    
3653
            QApplication.processEvents()
3654

    
3655
            # parse texts
3656
            for text in root.find('TEXTINFOS').iter('ATTRIBUTE'):
3657
                item = QEngineeringTextItem.fromXml(text)
3658
                if item is not None:
3659
                    uid = text.find('UID')
3660
                    attributeValue = text.find('ATTRIBUTEVALUE')
3661
                    name = text.find('NAME').text
3662
                    item.transfer.onRemoved.connect(self.itemRemoved)
3663
                    item.addTextItemToScene(self.graphicsView.scene())
3664
                    # docData.texts.append(item)
3665

    
3666
                    if name == 'TEXT':
3667
                        if uid is not None and attributeValue is not None:
3668
                            item.uid = uid.text
3669
                            item.attribute = attributeValue.text
3670

    
3671
                self.progress.setValue(self.progress.value() + 1)
3672

    
3673
            QApplication.processEvents()
3674

    
3675
            # note
3676
            for text in root.find('NOTES').iter('ATTRIBUTE'):
3677
                item = QEngineeringTextItem.fromXml(text)
3678
                if item is not None:
3679
                    uid = text.find('UID')
3680
                    attributeValue = text.find('ATTRIBUTEVALUE')
3681
                    name = text.find('NAME').text
3682
                    item.transfer.onRemoved.connect(self.itemRemoved)
3683
                    item.addTextItemToScene(self.graphicsView.scene())
3684

    
3685
                    if name == 'NOTE':
3686
                        if uid is not None:
3687
                            item.uid = uid.text
3688

    
3689
                self.progress.setValue(self.progress.value() + 1)
3690

    
3691
            QApplication.processEvents()
3692

    
3693
            for line in root.find('LINEINFOS').iter('LINE'):
3694
                item = QEngineeringLineItem.fromXml(line)
3695
                if item:
3696
                    item.transfer.onRemoved.connect(self.itemRemoved)
3697
                    self.graphicsView.scene().addItem(item)
3698
                    lines.append(item)
3699

    
3700
                self.progress.setValue(self.progress.value() + 1)
3701

    
3702
            for line in root.find('LINEINFOS').iter('GRAPHICS_LINE'):
3703
                item = QEngineeringGraphicsLineItem.fromXml(line)
3704
                if item:
3705
                    item.transfer.onRemoved.connect(self.itemRemoved)
3706
                    self.graphicsView.scene().addItem(item)
3707

    
3708
                self.progress.setValue(self.progress.value() + 1)
3709

    
3710
            QApplication.processEvents()
3711

    
3712
            for unknown in root.iter('UNKNOWN'):
3713
                item = QEngineeringUnknownItem.fromXml(unknown)
3714
                if item is not None:
3715
                    item.transfer.onRemoved.connect(self.itemRemoved)
3716
                    self.graphicsView.scene().addItem(item)
3717

    
3718
                self.progress.setValue(self.progress.value() + 1)
3719

    
3720
            QApplication.processEvents()
3721

    
3722
            # """ add tree widget """
3723
            # for item in symbols:
3724
            #    docData.symbols.append(item)
3725
            #    self.addSvgItemToScene(item)
3726
            #    self.itemTreeWidget.addTreeItem(self.itemTreeWidget.root, item)
3727

    
3728
            for line_no_node in root.find('LINENOS').iter('LINE_NO'):
3729
                line_no = QEngineeringLineNoTextItem.fromXml(line_no_node)
3730
                if line_no is None: continue
3731
                line_no.transfer.onRemoved.connect(self.itemRemoved)
3732
                line_no.addTextItemToScene(self.graphicsView.scene())
3733
                line_no_tree_item = self.itemTreeWidget.addTreeItem(self.itemTreeWidget.root, line_no)
3734
                if type(line_no) is not QEngineeringLineNoTextItem: continue
3735

    
3736
                runs_node = line_no_node.findall('RUN')
3737
                if runs_node is None: continue
3738

    
3739
                for run_node in runs_node:
3740
                    line_run = QEngineeringRunItem()
3741
                    for child_node in run_node:
3742
                        uidElement = child_node.find('UID')
3743
                        if uidElement is not None:
3744
                            uid = uidElement.text
3745
                            run_item = self.graphicsView.findItemByUid(uid)
3746
                            if run_item is not None:
3747
                                run_item._owner = line_no
3748
                                line_run.items.append(run_item)
3749
                    line_run.owner = line_no
3750
                    line_no.runs.append(line_run)
3751

    
3752
                    for run_item in line_run.items:
3753
                        if issubclass(type(run_item), SymbolSvgItem):
3754
                            self.init_add_tree_item(line_no_tree_item, run_item)
3755

    
3756
                # docData.tracerLineNos.append(line_no)
3757

    
3758
                self.progress.setValue(self.progress.value() + 1)
3759
            QApplication.processEvents()
3760

    
3761
            for trimLineNo in root.iter('TRIM_LINE_NO'):
3762
                line_no = QEngineeringTrimLineNoTextItem()
3763
                line_no.uid = uuid.UUID(trimLineNo.find('UID').text)
3764

    
3765
                runs_node = trimLineNo.findall('RUN')
3766
                if runs_node is None: continue
3767
                line_no_tree_item = self.itemTreeWidget.addTreeItem(self.itemTreeWidget.root, line_no)
3768

    
3769
                for run in runs_node:
3770
                    line_run = QEngineeringRunItem()
3771
                    for child in run:
3772
                        uidElement = child.find('UID')
3773
                        if uidElement is not None:
3774
                            uid = uidElement.text
3775
                            run_item = self.graphicsView.findItemByUid(uid)
3776
                            if run_item is not None:
3777
                                run_item.owner = line_no
3778
                                line_run.items.append(run_item)
3779
                    line_run.owner = line_no
3780
                    line_no.runs.append(line_run)
3781

    
3782
                    for run_item in line_run.items:
3783
                        if issubclass(type(run_item), SymbolSvgItem):
3784
                            self.init_add_tree_item(line_no_tree_item, run_item)
3785

    
3786
                app_doc_data.tracerLineNos.append(line_no)
3787

    
3788
                self.progress.setValue(self.progress.value() + 1)
3789
            QApplication.processEvents()
3790

    
3791
            if root.find('VENDORS') is not None:
3792
                for vendor in root.find('VENDORS').iter('VENDOR'):
3793
                    item = QEngineeringVendorItem.fromXml(vendor)
3794
                    item.transfer.onRemoved.connect(self.itemRemoved)
3795
                    self.graphicsView.scene().addItem(item)
3796

    
3797
            # connect flow item to line
3798
            for line in lines:
3799
                line.update_arrow()
3800
                app_doc_data.lines.append(line)
3801
            # for flowMark in [item for item in symbols if type(item) is QEngineeringFlowMarkItem]:
3802
            #    for line in lines:
3803
            #        if flowMark.owner is line:
3804
            #            line._flowMark.append(flowMark)
3805
            #            flowMark.setParentItem(line)
3806
            # up to here
3807

    
3808
            """
3809
            group_box = QGroupBox("Contact Details")
3810
            number_label = QLabel("Telephone number");
3811
            number_edit = QTextEdit('hello\nthis is ....')
3812
            layout = QFormLayout()
3813
            layout.addRow(number_label, number_edit)
3814
            group_box.setLayout(layout)
3815

3816
            proxy =  ㅐ()
3817
            proxy.setWidget(group_box)
3818
            self.graphicsView.scene().addItem(proxy)  # (group_box, QGraphicsItem.ItemIgnoresTransformations)
3819
            """
3820

    
3821
            """ update scene """
3822
            _items = [_item for _item in self.graphicsView.scene().items() if hasattr(_item, 'owner') or hasattr(_item, 'connectors')]
3823
            if _items:
3824
                items = divide_chunks(_items, App.THREAD_MAX_WORKER if len(_items) > App.THREAD_MAX_WORKER else len(_items))
3825
                with futures.ThreadPoolExecutor(max_workers=App.THREAD_MAX_WORKER) as pool:
3826
                    future_items = {pool.submit(update_items, _items): _items for _items in items}
3827
                    for future in futures.as_completed(future_items):
3828
                        _items = future.result()
3829
                        self.progress.setValue(self.progress.value() + len(_items))
3830

    
3831
            """
3832
            for item in [_item for _item in self.graphicsView.scene().items() if hasattr(_item, 'owner') or hasattr(_item, 'connectors')]:
3833
                up_progress = False
3834
                # binding items
3835
                item.owner
3836
                for connector in item.connectors:
3837
                    connector.connectedItem
3838

3839
                self.progress.setValue(self.progress.value() + 1)
3840
            """
3841

    
3842
            for item in self.graphicsView.scene().items():
3843
                item.setVisible(True)
3844

    
3845
            self.graphicsView.scene().update(self.graphicsView.sceneRect())
3846
        except Exception as ex:
3847
            message = 'error occurred({}) in {}:{}'.format(ex, sys.exc_info()[-1].tb_frame.f_code.co_filename,
3848
                                                           sys.exc_info()[-1].tb_lineno)
3849
            self.addMessage.emit(MessageType.Error, message)
3850
        finally:
3851
            self.itemTreeWidget.update_item_count()
3852
            self.itemTreeWidget.expandAll()
3853
            self.graphicsView.scene().blockSignals(False)
3854

    
3855
    '''
3856
        @brief      Remove added item on same place and Add GraphicsItem
3857
        @author     Jeongwoo
3858
        @date       2018.05.29
3859
        @history    2018.06.18  Jeongwoo    Set Z-index
3860
    '''
3861
    def addLineItemToScene(self, lineItem):
3862
        self.graphicsView.scene().addItem(lineItem)
3863

    
3864
    '''
3865
        @brief      generate output xml file
3866
        @author     humkyung
3867
        @date       2018.04.23
3868
        @history    2018.05.02  Jeongwoo    Show MessageBox when imageviewer doesn't have image
3869
    '''
3870
    def generateOutput(self):
3871
        import XmlGenerator as xg
3872

    
3873
        if not self.graphicsView.hasImage():
3874
            self.showImageSelectionMessageBox()
3875
            return
3876

    
3877
        try:
3878
            appDocData = AppDocData.instance()
3879

    
3880
            # collect items
3881
            appDocData.lines.clear()
3882
            appDocData.lines = [item for item in self.graphicsView.scene().items() if
3883
                                type(item) is QEngineeringLineItem and item.owner is None]
3884

    
3885
            appDocData.symbols.clear()
3886
            appDocData.symbols = [item for item in self.graphicsView.scene().items() if
3887
                                  issubclass(type(item), SymbolSvgItem) and item.owner is None]
3888

    
3889
            appDocData.equipments.clear()
3890
            for item in self.graphicsView.scene().items():
3891
                if type(item) is QEngineeringEquipmentItem:
3892
                    appDocData.equipments.append(item)
3893

    
3894
            appDocData.texts.clear()
3895
            appDocData.texts = [item for item in self.graphicsView.scene().items() if
3896
                                issubclass(type(item), QEngineeringTextItem) and type(
3897
                                    item) is not QEngineeringLineNoTextItem]
3898
            # up to here
3899

    
3900
            appDocData.imgOutput = np.ones((appDocData.activeDrawing.height, appDocData.activeDrawing.width),
3901
                                           np.uint8) * 255
3902
            xg.writeOutputXml(appDocData.imgName, appDocData.activeDrawing.width,
3903
                              appDocData.activeDrawing.height)  # TODO: check
3904
            project = appDocData.getCurrentProject()
3905
            cv2.imwrite(os.path.join(project.getTempPath(), 'OUTPUT.png'), appDocData.imgOutput)
3906
        except Exception as ex:
3907
            message = 'error occurred({}) in {}:{}'.format(ex, sys.exc_info()[-1].tb_frame.f_code.co_filename,
3908
                                                           sys.exc_info()[-1].tb_lineno)
3909
            self.addMessage.emit(MessageType.Error, message)
3910

    
3911
    '''
3912
        @brief      Check Number
3913
        @author     kyouho
3914
        @date       2018.08.20
3915
    '''
3916
    def isNumber(self, num):
3917
        p = re.compile('(^[0-9]+$)')
3918
        result = p.match(num)
3919

    
3920
        if result:
3921
            return True
3922
        else:
3923
            return False
3924

    
3925
    '''
3926
        @brief      find overlap Connector
3927
        @author     kyouho
3928
        @date       2018.08.28
3929
    '''
3930
    def findOverlapConnector(self, connectorItem):
3931
        from shapely.geometry import Point
3932
        from EngineeringConnectorItem import QEngineeringConnectorItem
3933
        itemList = []
3934

    
3935
        x = connectorItem.center()[0]
3936
        y = connectorItem.center()[1]
3937

    
3938
        connectors = [item for item in self.graphicsView.scene().items() if
3939
                      type(item) is QEngineeringConnectorItem and item != connectorItem]
3940
        for connector in connectors:
3941
            if Point(x, y).distance(Point(connector.center()[0], connector.center()[1])) < 5:
3942
                itemList.append(connector.parent)
3943

    
3944
        return itemList
3945

    
3946
    def make_diff_image(self):
3947
        """ make diff image """
3948
        # test
3949

    
3950
        from RecognitionDialog import Worker
3951
        from symbol import Symbol
3952
        import math
3953
        from PIL import Image
3954

    
3955
        app_doc_data = AppDocData.instance()
3956
        img = app_doc_data.imgSrc.copy()
3957

    
3958
        # check break
3959
        symbols = [item for item in self.graphicsView.scene().items() if issubclass(type(item), SymbolSvgItem)]
3960

    
3961
        for symbol in symbols:
3962
            rect = symbol.sceneBoundingRect()
3963
            sName = symbol.name
3964
            sType = symbol.type
3965
            sp = (rect.x(), rect.y())
3966
            w, h = rect.width(), rect.height()
3967
            rotatedAngle = round(math.degrees(symbol.angle))
3968
            detectFlip = symbol.flip
3969

    
3970
            dummySym = Symbol(sName, sType, sp, w, h, 0, 0, 0, rotatedAngle,
3971
                                   1, 0, 1, 0,
3972
                                   ','.join(str(x) for x in [0, 0]),
3973
                                   '/'.join('{},{},{},{}'.format(param[0], param[1], param[2], param[3]) for param in
3974
                                            []),
3975
                                   'dummy', 'dummy', 0, detectFlip=detectFlip,
3976
                                   hasInstrumentLabel=0, text_area='')
3977

    
3978
            Worker.remove_detected_symbol_image(dummySym, img, lock=False)
3979

    
3980
        Image.fromarray(img).show()
3981

    
3982
    #def paintEvent(self, event):
3983
    #    self.refresh_rate += 1
3984
    #    if self.refresh_rate == 3:
3985
    #        super(self.__class__, self).paintEvent(event)
3986
    #        self.refresh_rate = 0
3987

    
3988
if __name__ == '__main__':
3989
    import locale
3990
    from PyQt5.QtCore import QTranslator
3991
    from License import QLicenseDialog
3992
    from ProjectDialog import Ui_Dialog
3993
    from App import App
3994

    
3995
    app = App(sys.argv)
3996
    try:
3997
        if True == QLicenseDialog.check_license_key():
3998
            dlg = Ui_Dialog()
3999
            selectedProject = dlg.showDialog()
4000
            if selectedProject is not None:
4001
                AppDocData.instance().setCurrentProject(selectedProject)
4002
                app._mainWnd = MainWindow.instance()
4003
                app._mainWnd.show()
4004
                sys.exit(app.exec_())
4005
    except Exception as ex:
4006
        print('error occurred({}) in {}:{}'.format(ex, sys.exc_info()[-1].tb_frame.f_code.co_filename,
4007
                                                   sys.exc_info()[-1].tb_lineno))
4008
    finally:
4009
        pass