프로젝트

일반

사용자정보

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

hytos / DTI_PID / DTI_PID / MainWindow.py @ 02d8f189

이력 | 보기 | 이력해설 | 다운로드 (186 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(0, Qt.Unchecked)
665
            # up to here
666

    
667
            drawing.image = None
668
            self.open_image_drawing(drawing)
669
            item.setCheckState(0, 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
        if not self.graphicsView.hasImage():
780
            self.showImageSelectionMessageBox()
781
            return
782
        
783
        items = [item for item in self.graphicsView.scene().items() if issubclass(type(item), QEngineeringAbstractItem)]
784
        for item in items:
785
            item.setVisible(False)
786
        QApplication.processEvents()
787
        
788
        app_doc_data = AppDocData.instance()
789
        configs = app_doc_data.getConfigs('Line Detector', 'Length to connect line')
790
        toler = int(configs[0].value) if configs else 20
791
        count = self.connect_line_to_symbol(10, True)
792
        #self.connect_line_to_symbol(toler, False, count)
793

    
794
        self.progress_bar.setValue(self.progress_bar.maximum())
795

    
796
        for item in items:
797
            item.setVisible(True)
798
        
799
        QApplication.processEvents()
800
        QMessageBox.information(self, self.tr('Information'), self.tr('Connecting between symbols and lines is completed'))
801

    
802
    def connect_line_to_symbol(self, toler=20, start=True, count=0):
803
        """connect line to symbol"""
804
        from LineDetector import LineDetector
805
        from shapely.geometry import Point
806
        #from RecognitionDialog import Worker
807

    
808
        app_doc_data = AppDocData.instance()
809
        #configs = app_doc_data.getConfigs('Project', 'Operation')
810
        detector = LineDetector(app_doc_data.imgSrc)
811

    
812
        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]
813
        lines_short = []#[item for item in self.graphicsView.scene().items() if type(item) is QEngineeringLineItem if item.length() <= 50]
814
        unknowns = [item for item in self.graphicsView.scene().items() if type(item) is QEngineeringUnknownItem]
815
        end_breaks = [item for item in self.graphicsView.scene().items() if type(item) is QEngineeringEndBreakItem]
816
        spec_breaks = [item for item in self.graphicsView.scene().items() if type(item) is QEngineeringSpecBreakItem]
817
        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]
818
        texts = [item for item in self.graphicsView.scene().items() if type(item) is QEngineeringTextItem and item.owner is None]
819

    
820
        for item in lines_short + unknowns:
821
            item.transfer.onRemoved.emit(item)
822

    
823
        if start:
824
            self.progress_bar.setMaximum((len(lines) + len(symbols)) * 2 + 3)
825
            count = 1
826
            self.progress_bar.setValue(count)
827
            QApplication.processEvents()
828

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

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

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

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

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

    
898
        # connect line to line
899
        try:
900
            for line in lines:
901
                #matches = [it for it in lines if (it is not line) and (not line.isParallel(it))]
902
                #for match in matches:
903
                for match in lines:
904
                    detector.connectLineToLine(match, line, toler)
905

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

    
915
        try:
916
            # connect end break
917
            usedItemPairs = []
918
            for end_break in end_breaks:
919
                if end_break.prop('Freeze') or end_break.owner or end_break.prop('Connected Item'):
920
                    usedItemPairs.append([end_break.owner, end_break.prop('Connected Item')])
921

    
922
            for end_break in end_breaks:
923
                if end_break.prop('Freeze') or end_break.owner or end_break.prop('Connected Item'):
924
                    continue
925

    
926
                originPoint = Point(end_break.origin[0], end_break.origin[1])
927
                minD = sys.maxsize
928
                ownerItem = None
929
                connectedItem = None
930

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

    
938
                        minD = dist
939
                        ownerItem = symbol
940
                        connectedItem = conn.connectedItem
941

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

    
950
                        minD = dist
951
                        ownerItem = line
952
                        connectedItem = conn.connectedItem
953

    
954
                if ownerItem and connectedItem:
955
                    end_break.set_property('Connected Item', connectedItem)
956
                    end_break.setToolTip('owner : ' + str(ownerItem))
957
                    end_break.owner = ownerItem
958
                    end_break.set_property('Freeze', True)
959

    
960
                    usedItemPairs.append([ownerItem, connectedItem])
961
            # up to here
962

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

    
974
    def on_connect_spec_breaks(self, spec_breaks, texts=None, symbols=None, lines=None):
975
        from CodeTables import CodeTable
976
        from shapely.geometry import Point
977

    
978
        app_doc_data = AppDocData.instance()
979
        
980
        try:
981
            if not texts or not symbols or not lines:
982
                texts = [item for item in self.graphicsView.scene().items() if type(item) is QEngineeringTextItem and item.owner is None]
983
                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]
984
                lines = sorted([item for item in self.graphicsView.scene().items() if type(item) is QEngineeringLineItem], key=lambda param: param.length(), reverse=True)
985

    
986
            usedTexts = []
987
            attribute_table_item_list = []
988
            dist_range = None
989
            specBreakAttrsFull = [attr for attr in app_doc_data.getSymbolAttribute('Segment Breaks') if attr.AttributeType == 'Spec' or attr.AttributeType == 'String']
990

    
991
            for attr in specBreakAttrsFull:
992
                if attr.AttributeType != 'Spec' or attr.Attribute == 'NominalDiameter':
993
                    continue
994

    
995
                usedTexts = []
996

    
997
                table = CodeTable.instance(attr.Attribute)
998
                items = []
999
                for text in texts:
1000
                    if text not in usedTexts and table.find_match_exactly(text.text()):
1001
                        usedTexts.append(text)
1002
                        items.append(text)
1003

    
1004
                if len(items) >= 2:
1005
                    attribute_table_item_list.append([attr.Attribute, items])
1006

    
1007
            usedItemPairs = []
1008
            for spec_break in spec_breaks:
1009
                if not dist_range:
1010
                    dist_range = max(spec_break.sceneBoundingRect().height(), spec_break.sceneBoundingRect().width())
1011

    
1012
                attrs = spec_break.getAttributes()
1013
                up = [attr.AssocItem for attr in attrs if attr.Attribute == 'UpStream']
1014
                down = [attr.AssocItem for attr in attrs if attr.Attribute == 'DownStream']
1015
                if (up and up[0]) or (down and down[0]):
1016
                    usedItemPairs.append([up, down])
1017

    
1018
            for spec_break in spec_breaks:
1019
                attrs = spec_break.getAttributes()
1020
                up = [attr.AssocItem for attr in attrs if attr.Attribute == 'UpStream']
1021
                down = [attr.AssocItem for attr in attrs if attr.Attribute == 'DownStream']
1022
                if (up and up[0]) or (down and down[0]):
1023
                    continue
1024

    
1025
                originPoint = Point(spec_break.origin[0], spec_break.origin[1])
1026
                minD = sys.maxsize
1027
                upItem = None
1028
                downItem = None
1029

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

    
1037
                        minD = dist
1038
                        upItem = symbol
1039
                        downItem = conn.connectedItem
1040

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

    
1049
                        minD = dist
1050
                        upItem = line
1051
                        downItem = conn.connectedItem
1052

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

    
1068
                    usedItemPairs.append([upItem, downItem])
1069

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

    
1117
                        if upText and downText:
1118
                            for full in specBreakAttrsFull:
1119
                                if full.Attribute == attribute_table_item[0]:
1120
                                    attrs[full] = [upText.text(), downText.text()]
1121
                                    attribute_table_item[1].remove(upText)
1122
                                    attribute_table_item[1].remove(downText)
1123
                                    break
1124

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

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

    
1159
                            if stream_res[0] and stream_res[1]:
1160
                                up_down_find = [upText, downText]
1161

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

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

    
1180
            return False
1181

    
1182

    
1183
    def on_recognize_line(self):
1184
        """recognize lines in selected area"""
1185
        from RecognizeLineCommand import RecognizeLineCommand
1186

    
1187
        if not self.graphicsView.hasImage():
1188
            self.actionOCR.setChecked(False)
1189
            self.showImageSelectionMessageBox()
1190
            return
1191

    
1192
        cmd = RecognizeLineCommand(self.graphicsView)
1193
        cmd.onSuccess.connect(self.on_success_to_recognize_line)
1194
        cmd.onRejected.connect(self.onCommandRejected)
1195
        self.graphicsView.command = cmd
1196

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

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

    
1216
            detector = LineDetector(img)
1217
            lines = detector.detect_line_without_symbol()
1218
            for line in lines:
1219
                vertices = [[line[0][0] + x, line[0][1] + y], [line[1][0] + x, line[1][1] + y]]
1220
                line_item = QEngineeringGraphicsLineItem(vertices)
1221
                self.graphicsView.scene().addItem(line_item)
1222

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

    
1228
    def display_number_of_items(self):
1229
        """display count of symbol, line, text"""
1230

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

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

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

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

    
1249
        self.itemTreeWidget.sceneChanged(self.graphicsView.scene().items())
1250

    
1251
    def dbUpdate(self):
1252
        """ no more used """
1253
        """db update when save or recognition"""
1254

    
1255
        try:
1256
            appDocData = AppDocData.instance()
1257
            items = appDocData.allItems
1258

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

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

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

    
1298
    def save_drawing_if_necessary(self):
1299
        """ask to user to save drawing or not when drawing is modified"""
1300

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

    
1314
    def actionSaveCliked(self):
1315
        """
1316
        save current drawing
1317
        @return:
1318
        """
1319
        from EngineeringAbstractItem import QEngineeringAbstractItem
1320
        from SaveWorkCommand import SaveWorkCommand
1321

    
1322
        try:
1323
            home_pane = self.ribbon.get_pane('Home File')
1324
            if not home_pane.ui.toolButtonFileSave.isEnabled():
1325
                return
1326

    
1327
            home_pane.ui.toolButtonFileSave.setEnabled(False)
1328

    
1329
            # save alarm
1330
            self.save_alarm_enable(False)
1331

    
1332
            app_doc_data = AppDocData.instance()
1333
            if app_doc_data.imgName is None:
1334
                self.showImageSelectionMessageBox()
1335
                return
1336

    
1337
            app_doc_data.clearItemList(False)
1338

    
1339
            #items = self.graphicsView.scene().items()
1340

    
1341
            self._save_work_cmd = SaveWorkCommand(self.graphicsView.scene())
1342
            self._save_work_cmd.show_progress.connect(self.progress_bar.setValue)
1343
            self._save_work_cmd.display_message.connect(self.onAddMessage)
1344
            self._save_work_cmd.finished.connect(self.save_finished)
1345

    
1346
            self._save_work_cmd.start()
1347
        except Exception as ex:
1348
            message = f"error occurred({repr(ex)}) in {sys.exc_info()[-1].tb_frame.f_code.co_filename}:" \
1349
                      f"{sys.exc_info()[-1].tb_lineno}"
1350
            self.addMessage.emit(MessageType.Error, message)
1351

    
1352
    def save_finished(self):
1353
        """
1354
        reload drawing list when save is finished
1355
        @return: None
1356
        """
1357

    
1358
        try:
1359
            self._save_work_cmd.show_progress.emit(100)
1360
            QMessageBox.about(self.graphicsView, self.tr('Information'), self._save_work_cmd.resultStr)
1361
            self.load_drawing_list()
1362

    
1363
            app_doc_data = AppDocData.instance()
1364
            app_doc_data.activeDrawing.modified = False
1365
            title = self.windowTitle()
1366
            self.setWindowTitle(title[:-1] if title[-1] == '*' else title)
1367

    
1368
            # save alarm
1369
            self.save_alarm_enable(True)
1370
        finally:
1371
            home_pane = self.ribbon.get_pane('Home File')
1372
            home_pane.ui.toolButtonFileSave.setEnabled(True)
1373

    
1374
    '''
1375
        @brief      refresh resultPropertyTableWidget
1376
        @author     kyouho
1377
        @date       2018.07.19
1378
    '''
1379
    def refreshResultPropertyTableWidget(self):
1380
        items = self.graphicsView.scene().selectedItems()
1381
        if len(items) == 1:
1382
            self.resultPropertyTableWidget.show_item_property(items[0])
1383

    
1384
    '''
1385
        @brief  add message listwidget
1386
        @author humkyung
1387
        @date   2018.07.31
1388
    '''
1389
    def onAddMessage(self, messageType, message):
1390
        from AppDocData import MessageType
1391

    
1392
        try:
1393
            current = QDateTime.currentDateTime()
1394

    
1395
            item = QListWidgetItem('{}: {}'.format(current.toString('hh:mm:ss'), message))
1396
            item.setFlags(item.flags() | Qt.ItemIsEditable)
1397
            if messageType == MessageType.Error:
1398
                item.setBackground(Qt.red)
1399
            elif messageType == 'check':
1400
                item.setBackground(Qt.yellow)
1401

    
1402
            self.listWidgetLog.insertItem(0, item)
1403
        except Exception as ex:
1404
            print('error occurred({}) in {}:{}'.format(ex, sys.exc_info()[-1].tb_frame.f_code.co_filename,
1405
                                                       sys.exc_info()[-1].tb_lineno))
1406

    
1407
    def on_clear_log(self):
1408
        """clear log"""
1409
        self.listWidgetLog.clear()
1410

    
1411
    def onRotate(self, action):
1412
        """rotate a selected symbol"""
1413
        selected = [item for item in self.graphicsView.scene().selectedItems() if issubclass(type(item), SymbolSvgItem)]
1414
        if len(selected) == 1:
1415
            from RotateCommand import RotateCommand
1416
            self.graphicsView.scene()._undo_stack.push(RotateCommand(self.graphicsView.scene(), selected))
1417

    
1418
    def onAreaZoom(self):
1419
        """Area Zoom"""
1420
        visualization_pane = self.ribbon.get_pane('Home Visualization')
1421

    
1422
        self.update_action_group(visualization_pane.ui.toolButtonZoom)
1423
        if visualization_pane.ui.toolButtonZoom.isChecked():
1424
            cmd = AreaZoomCommand.AreaZoomCommand(self.graphicsView)
1425
            cmd.onRejected.connect(self.onCommandRejected)
1426
            self.graphicsView.command = cmd
1427

    
1428
    def onVendor(self, action):
1429
        """make vendor/equipment package area"""
1430

    
1431
        pane = self.ribbon.get_pane('Home')
1432
        if not self.graphicsView.hasImage():
1433
            pane.ui.toolButtonVendor.setChecked(False)
1434
            self.showImageSelectionMessageBox()
1435
            return
1436

    
1437
        pane = self.ribbon.get_pane('Home')
1438
        self.update_action_group(pane.ui.toolButtonVendor)
1439
        checked = pane.ui.toolButtonVendor.isChecked()
1440
        if not hasattr(pane.ui.toolButtonVendor, 'tag'):
1441
            pane.ui.toolButtonVendor.tag = PlacePolygonCommand.PlacePolygonCommand(self.graphicsView)
1442
            pane.ui.toolButtonVendor.tag.onSuccess.connect(self.onVendorCreated)
1443
            pane.ui.toolButtonVendor.tag.onRejected.connect(self.onCommandRejected)
1444

    
1445
        self.graphicsView.command = pane.ui.toolButtonVendor.tag
1446

    
1447
    def onVendorCreated(self):
1448
        """add created vendor polygon area to scene"""
1449

    
1450
        try:
1451
            vendor_tool = self.ribbon.get_pane('Home').ui.toolButtonVendor
1452
            package_combo = self.ribbon.get_pane('Home').ui.comboBoxPackage
1453
            count = len(vendor_tool.tag._polyline._vertices)
1454
            if count > 2:
1455
                points = []
1456
                for point in vendor_tool.tag._polyline._vertices:
1457
                    points.append(QPoint(round(point[0]), round(point[1])))
1458
                polygon = QPolygonF(points)
1459
                item = QEngineeringVendorItem(polygon, pack_type=package_combo.currentText())
1460
                item.area = 'Drawing'
1461
                item.transfer.onRemoved.connect(self.itemRemoved)
1462
                self.graphicsView.scene().addItem(item)
1463
        finally:
1464
            self.graphicsView.scene().removeItem(vendor_tool.tag._polyline)
1465
            vendor_tool.tag.reset()
1466

    
1467
    def fitWindow(self, view_rect: QRectF = QRectF()):
1468
        """Fit Window"""
1469
        self.graphicsView.useDefaultCommand()
1470
        self.graphicsView.zoomImageInit()
1471

    
1472
        visualization_pane = self.ribbon.get_pane('Home Visualization')
1473
        self.update_action_group(visualization_pane.ui.toolButtonFitWindow)
1474
        if view_rect:
1475
            self.graphicsView.zoom_rect(view_rect)
1476

    
1477
    def on_toggle_lock_axis(self):
1478
        """toggle lock axis"""
1479
        from EngineeringPolylineItem import QEngineeringPolylineItem
1480

    
1481
        visualization_pane = self.ribbon.get_pane('Home Visualization')
1482
        if self.sender() is not visualization_pane.ui.toolButtonLockAxis:
1483
            checked = visualization_pane.ui.toolButtonLockAxis.isChecked()
1484
            visualization_pane.ui.toolButtonLockAxis.setChecked(not checked)
1485

    
1486
        checked = visualization_pane.ui.toolButtonLockAxis.isChecked()
1487
        QEngineeringPolylineItem.DRAWING_MODE = QEngineeringPolylineItem.AXIS_MODE if checked else \
1488
            QEngineeringPolylineItem.FREE_MODE
1489

    
1490
    def scene_changed(self):
1491
        """update modified flag"""
1492

    
1493
        self.display_number_of_items()
1494

    
1495
        app_doc_data = AppDocData.instance()
1496
        app_doc_data.activeDrawing.modified = True
1497
        title = self.windowTitle()
1498
        self.setWindowTitle(title if title[-1] == '*' else title + '*')
1499

    
1500
    def onConvertPDFToImage(self):
1501
        """convert to selected pdf to image"""
1502
        import os
1503

    
1504
        try:
1505
            file_path = os.path.join(os.path.dirname(os.path.realpath(__file__)), 'bin64', 'PDF_TO_IMAGE.exe')
1506
            os.startfile(file_path)
1507
        except Exception as ex:
1508
            message = 'error occurred({}) in {}:{}'.format(ex, sys.exc_info()[-1].tb_frame.f_code.co_filename,
1509
                                                           sys.exc_info()[-1].tb_lineno)
1510
            self.addMessage.emit(MessageType.Error, message)
1511

    
1512
    def on_import_text_from_cad_for_instrument(self):
1513
        """ import text from cad for instrument """
1514
        try:
1515
            self.onCommandRejected()
1516
            dialog = QImportTextFromPDFDialog(self)
1517
            dialog.show()
1518
            dialog.exec_()
1519
        except Exception as ex:
1520
            message = f"error occurred({repr(ex)}) in {sys.exc_info()[-1].tb_frame.f_code.co_filename}:" \
1521
                      f"{sys.exc_info()[-1].tb_lineno}"
1522
            self.addMessage.emit(MessageType.Error, message)
1523

    
1524
    def on_import_text_from_cad(self):
1525
        """ import text from cad """
1526
        try:
1527
            self.onCommandRejected()
1528
            dialog = QImportTextFromCADDialog(self)
1529
            dialog.show()
1530
            dialog.exec_()
1531
        except Exception as ex:
1532
            message = f"error occurred({repr(ex)}) in {sys.exc_info()[-1].tb_frame.f_code.co_filename}:" \
1533
                      f"{sys.exc_info()[-1].tb_lineno}"
1534
            self.addMessage.emit(MessageType.Error, message)
1535

    
1536
    def on_export_PDF_ARS(self, path):
1537
        drawingList = self.treeWidgetDrawingList.topLevelItem(0)
1538
        for idx in range(drawingList.childCount()):
1539
            child = drawingList.child(idx)
1540
            child.setCheckState(0, Qt.Checked)
1541

    
1542
        self.on_export_PDF(path)
1543

    
1544
    def on_export_PDF(self, path=None):
1545
        # save alarm
1546
        self.save_alarm_enable(False)
1547
        
1548
        #if not self.graphicsView.hasImage():
1549
        #    self.showImageSelectionMessageBox()
1550
        #    return
1551

    
1552
        try:
1553
            app_doc_data = AppDocData.instance()
1554
            current_drawing = None
1555

    
1556
            if self.graphicsView.hasImage():
1557
                current_drawing = app_doc_data.activeDrawing
1558

    
1559
            # get checked drawings
1560
            drawing_top = self.treeWidgetDrawingList.topLevelItem(0)
1561
            count = drawing_top.childCount()
1562
            checked_drawings = {}
1563
            for idx in range(count):
1564
                child = drawing_top.child(idx)
1565
                if child.checkState(0) == Qt.Checked and child.data(Qt.UserRole, 0):
1566
                    checked_drawings[child.data(Qt.UserRole, 0)] = child
1567
            # up to here
1568

    
1569
            # if there is no checked drawing
1570
            if current_drawing and not checked_drawings:
1571
                for idx in range(count):
1572
                    child = drawing_top.child(idx)
1573
                    if child.data(Qt.UserRole, 0) is current_drawing:
1574
                        checked_drawings[child.data(Qt.UserRole, 0)] = child
1575

    
1576
            if not checked_drawings:
1577
                self.showImageSelectionMessageBox()
1578
                return
1579
                
1580
            project = app_doc_data.getCurrentProject()
1581

    
1582
            if current_drawing and len(checked_drawings) == 1:
1583
                name = os.path.join(project.getTempPath(), os.path.splitext(app_doc_data.activeDrawing.name)[0])
1584
                
1585
                options = QFileDialog.Options()
1586
                options |= QFileDialog.DontUseNativeDialog
1587
                file_name, _ = QFileDialog.getSaveFileName(self, "Export PDF", name, "pdf files(*.pdf)", options=options)
1588
                if file_name:
1589
                    file_name += '.png'
1590
                    self.save_PDF(file_name)
1591

    
1592
            elif len(checked_drawings) >= 1:
1593
                name = os.path.join(project.getTempPath(), 'Select a Folder')
1594
                
1595
                file_name = None
1596
                if not path:
1597
                    options = QFileDialog.Options()
1598
                    options |= QFileDialog.DontUseNativeDialog
1599
                    file_name, _ = QFileDialog.getSaveFileName(self, "Export PDF", name, "pdf files(*.pdf)", options=options)
1600

    
1601
                if file_name or path:
1602
                    if file_name:
1603
                        directory = os.path.dirname(file_name)
1604
                    else:
1605
                        directory = path
1606

    
1607
                    self.progress_bar.setMaximum(len(checked_drawings) + 2)
1608
                    count = 1
1609
                    self.progress_bar.setValue(count)
1610

    
1611
                    for drawing in checked_drawings.keys():
1612
                        self.open_image_drawing(drawing, force=True, ocrUnknown=False, timer=False, pdf=True)
1613

    
1614
                        self.save_PDF(os.path.join(directory, drawing.name))
1615

    
1616
                        count += 1
1617
                        self.progress_bar.setValue(count)
1618
                    self.open_image_drawing(drawing, force=True, ocrUnknown=False) # for reset
1619
                    self.progress_bar.setValue(self.progress_bar.maximum())
1620
                    
1621
            QMessageBox.about(self, self.tr("Information"), self.tr('Successfully saved.'))
1622

    
1623
            #self.save_alarm_enable(True, True)
1624

    
1625
            '''
1626
            #app_doc_data = AppDocData.instance()
1627
            #project = app_doc_data.getCurrentProject()
1628

1629
            printer = QPrinter(QPrinter.PrinterResolution)
1630
            #printer.setPageSize(QPrinter.A0)
1631
            printer.setOrientation(QPrinter.Orientation.Landscape)
1632
            #printer.setOutputFileName(os.path.join(project.getPDFFilePath(), os.path.splitext(app_doc_data.activeDrawing.name)[0]))
1633
            #printer.setOutputFormat(QPrinter.PdfFormat)
1634
            dialog = QPrintDialog(printer)
1635
            if (dialog.exec() == QDialog.Accepted):
1636
                painter = QPainter(printer)
1637
                isfull_print = False
1638

1639
                scene = self.graphicsView.scene()
1640

1641
                #for item in scene.items():
1642
                #    if not hasattr(item, 'connectors'): continue
1643
                #    for connector in item.connectors: connector.setVisible(False)
1644

1645
                canvasRect = scene.sceneRect() # or canvasRect = scene.border.boundingRect()
1646
                source = canvasRect
1647
                page = printer.pageRect(QPrinter.Unit.DevicePixel)
1648
                target = QRectF(QPointF(0, 0), QSizeF(page.width(), page.height()))
1649
                scene.render(painter, target, source)
1650
                painter.end()
1651

1652
                QMessageBox.about(self, self.tr("Information"), self.tr('Successfully saved.'))
1653
                #for item in scene.items():
1654
                #    if not hasattr(item, 'connectors'): continue
1655
                #    for connector in item.connectors: connector.setVisible(True)
1656
            '''
1657

    
1658
        except Exception as ex:
1659
            message = 'error occurred({}) in {}:{}'.format(ex, sys.exc_info()[-1].tb_frame.f_code.co_filename,
1660
                                                           sys.exc_info()[-1].tb_lineno)
1661
            self.addMessage.emit(MessageType.Error, message)
1662

    
1663
    def save_PDF(self, file_name):
1664
        #pixMap = self.graphicsView.grab(QRect(QPoint(0, 0), QSize(int(self.graphicsView.scene().sceneRect().width()), int(self.graphicsView.scene().sceneRect().height()))))
1665
        #pixMap.save(name)
1666
        #return
1667

    
1668
        image = QImage(QSize(int(self.graphicsView.scene().sceneRect().width()), int(self.graphicsView.scene().sceneRect().height())), QImage.Format_ARGB32_Premultiplied)
1669
        painter = QPainter(image)
1670
        scene = self.graphicsView.scene()
1671
        canvasRect = scene.sceneRect() # or canvasRect = scene.border.boundingRect()
1672
        source = canvasRect
1673
        scene.render(painter, QRectF(image.rect()), source)
1674
        painter.end()
1675
        image.save(file_name)
1676
        image = Image.open(file_name)
1677
        image = image.convert('RGB')
1678
        image.save(file_name.replace('.png', '.pdf'))
1679
        os.remove(file_name)
1680
        painter.device()
1681

    
1682
    def onSymbolThickness(self):
1683
        """ symbol thickness reinforcement by using configuration filter drawing dilate size """
1684
        try:
1685
            self.onCommandRejected()
1686
            dialog = QSymbolThicknessDialog(self)
1687
            dialog.exec_()
1688
        except Exception as ex:
1689
            message = 'error occurred({}) in {}:{}'.format(ex, sys.exc_info()[-1].tb_frame.f_code.co_filename,
1690
                                                           sys.exc_info()[-1].tb_lineno)
1691
            self.addMessage.emit(MessageType.Error, message)
1692

    
1693
    def on_help(self):
1694
        """ open help file """
1695
        import os
1696

    
1697
        try:
1698
            help_file_path = os.path.join(os.path.dirname(os.path.realpath(__file__)), 'ID2 User Manual.pdf')
1699
            if os.path.exists(help_file_path):
1700
                os.startfile(f"\"{help_file_path}\"")
1701
            else:
1702
                QMessageBox.warning(self, self.tr('Warning'), self.tr('There is no help file'))
1703
        except Exception as ex:
1704
            message = f"error occurred({repr(ex)}) in {sys.exc_info()[-1].tb_frame.f_code.co_filename}:" \
1705
                      f"{sys.exc_info()[-1].tb_lineno}"
1706
            self.addMessage.emit(MessageType.Error, message)
1707

    
1708
    def on_readme(self):
1709
        """open readme.html"""
1710

    
1711
        file_path = os.path.join(os.path.dirname(os.path.realpath(__file__)), 'readme.html')
1712
        if os.path.exists(file_path):
1713
            os.startfile(f"\"{file_path}\"")
1714
        else:
1715
            QMessageBox.warning(self, self.tr('Warning'), self.tr('There is no readme file'))
1716

    
1717
    def onSelectionChanged(self):
1718
        """selection changed"""
1719
        items = [item for item in self.graphicsView.scene().selectedItems() if issubclass(type(item), SymbolSvgItem) or
1720
                 type(item) is QEngineeringLineItem or issubclass(type(item), QEngineeringTextItem) or
1721
                 type(item) is QEngineeringUnknownItem or type(item) is QEngineeringVendorItem]
1722
        if items:
1723
            lineNos = [item for item in items if type(item) is QEngineeringLineNoTextItem]
1724
            item = items[-1] if not lineNos else lineNos[0]
1725
            self.itemTreeWidget.findItem(item)
1726
            self.resultPropertyTableWidget.show_item_property(item)
1727
            if type(item) is QEngineeringErrorItem:
1728
                for index in range(self.tableWidgetInconsistency.rowCount()):
1729
                    if self.tableWidgetInconsistency.item(index, 1).tag is item:
1730
                        self.tableWidgetInconsistency.selectRow(index)
1731
                        break
1732
            if issubclass(type(item), SymbolSvgItem):
1733
                pass
1734
                #self.symbolTreeWidget.select_symbol(item)
1735
        else:
1736
            self.resultPropertyTableWidget.show_item_property(None)
1737

    
1738
    '''
1739
        @brief      Initialize scene and itemTreeWidget
1740
        @author     Jeongwoo
1741
        @date       2018.06.14
1742
        @history    humkyung 2018.08.16 ask to delete recognized items before remove
1743
    '''
1744
    def on_initialize_scene(self, action):
1745
        if not self.graphicsView.hasImage():
1746
            self.showImageSelectionMessageBox()
1747

    
1748
            return
1749

    
1750
        try:
1751
            msg = QMessageBox()
1752
            msg.setIcon(QMessageBox.Critical)
1753
            msg.setText(self.tr('Do you want to remove all items?\nThis work cannot be recovered.'))
1754
            msg.setWindowTitle(self.tr("Initialize"))
1755
            msg.setStandardButtons(QMessageBox.Ok | QMessageBox.Cancel)
1756
            if QMessageBox.Ok == msg.exec_():
1757
                app_doc_data = AppDocData.instance()
1758
                app_doc_data.clearItemList(True)
1759

    
1760
                scene = self.graphicsView.scene()
1761
                pixmap = self.graphicsView.getPixmapHandle()
1762
                scene.removeItem(pixmap)    # disconnect pixmap from scene
1763
                scene.clear()               # remove all items from scene and then delete them
1764
                scene.addItem(pixmap)       # add pixmap
1765

    
1766
                if self.path is not None:
1767
                    baseName = os.path.basename(self.path)
1768
                    self.itemTreeWidget.setCurrentPID(baseName)
1769

    
1770
        except Exception as ex:
1771
            message = 'error occurred({}) in {}:{}'.format(ex, sys.exc_info()[-1].tb_frame.f_code.co_filename,
1772
                                                           sys.exc_info()[-1].tb_lineno)
1773
            self.addMessage.emit(MessageType.Error, message)
1774

    
1775
    def checked_action(self):
1776
        """return checked action"""
1777
        home_file_pane = self.ribbon.get_pane('Home File')
1778
        home_pane = self.ribbon.get_pane('Home')
1779
        visualization_pane = self.ribbon.get_pane('Home Visualization')
1780
        actions = [home_pane.ui.toolButtonRecognition, home_pane.ui.toolButtonLinkAttribute,
1781
                   home_pane.ui.toolButtonLine, home_pane.ui.toolButtonOCR, visualization_pane.ui.toolButtonZoom,
1782
                   visualization_pane.ui.toolButtonFitWindow, home_pane.ui.toolButtonVendor]
1783

    
1784
        checked = [ui_ for ui_ in actions if ui_.isChecked()]
1785
        return checked[0] if checked else None
1786

    
1787
    def update_action_group(self, ui):
1788
        """Manage Checkable Action statement"""
1789
        home_file_pane = self.ribbon.get_pane('Home File')
1790
        home_pane = self.ribbon.get_pane('Home')
1791
        visualization_pane = self.ribbon.get_pane('Home Visualization')
1792
        actions = [home_pane.ui.toolButtonRecognition, home_pane.ui.toolButtonLinkAttribute, home_pane.ui.toolButtonLine,
1793
                   home_pane.ui.toolButtonOCR, visualization_pane.ui.toolButtonZoom,
1794
                   visualization_pane.ui.toolButtonFitWindow, home_file_pane.ui.toolButtonFileSave,
1795
                   home_pane.ui.toolButtonValidate, home_pane.ui.toolButtonVendor]
1796

    
1797
        if hasattr(ui, 'tag'):
1798
            ui.tag.onRejected.emit(None)
1799

    
1800
        if self.graphicsView.command is not None:
1801
            self.graphicsView.useDefaultCommand()
1802

    
1803
        for ui_ in actions:
1804
            ui_.setChecked(False)
1805

    
1806
        ui.setChecked(True)
1807

    
1808
    '''
1809
        @brief      Create Equipment
1810
        @author     Jeongwoo
1811
        @date       18.05.03
1812
        @history    2018.05.04  Jeongwoo    Add Parameter on CreateSymbolCommand
1813
    '''
1814
    def createEquipment(self):
1815
        if not self.graphicsView.hasImage():
1816
            self.actionEquipment.setChecked(False)
1817
            self.showImageSelectionMessageBox()
1818
            return
1819
        if self.actionEquipment.isChecked():
1820
            self.graphicsView.command = CreateSymbolCommand.CreateSymbolCommand(self.graphicsView, self.itemTreeWidget,
1821
                                                                                self.symbolTreeWidget)
1822
        else:
1823
            self.graphicsView.useDefaultCommand()
1824

    
1825
    '''
1826
        @brief      Create Nozzle
1827
        @author     Jeongwoo
1828
        @date       2018.05.03
1829
        @history    2018.05.04  Jeongwoo    Add Parameter on CreateSymbolCommand
1830
    '''
1831
    def createNozzle(self):
1832
        if not self.graphicsView.hasImage():
1833
            self.actionNozzle.setChecked(False)
1834
            self.showImageSelectionMessageBox()
1835
            return
1836
        if self.actionNozzle.isChecked():
1837
            self.graphicsView.command = CreateSymbolCommand.CreateSymbolCommand(self.graphicsView, self.itemTreeWidget,
1838
                                                                                self.symbolTreeWidget)
1839
        else:
1840
            self.graphicsView.useDefaultCommand()
1841

    
1842
    def onAreaOcr(self):
1843
        """Area OCR"""
1844
        if not self.graphicsView.hasImage():
1845
            self.actionOCR.setChecked(False)
1846
            self.showImageSelectionMessageBox()
1847
            return
1848

    
1849
        pane = self.ribbon.get_pane('Home')
1850
        ui = pane.ui.toolButtonOCR
1851
        self.update_action_group(ui=ui)
1852
        checked = ui.isChecked()
1853
        if checked:
1854
            cmd = AreaOcrCommand.AreaOcrCommand(self.graphicsView)
1855
            cmd.onSuccess.connect(self.onRecognizeText)
1856
            cmd.onRejected.connect(self.onCommandRejected)
1857
            self.graphicsView.command = cmd
1858
        else:
1859
            self.graphicsView.useDefaultCommand()
1860

    
1861
    def onRecognizeText(self, x, y, width, height, show=True):
1862
        """show text recognition dialog"""
1863
        from OcrResultDialog import QOcrResultDialog
1864
        from Area import Area
1865

    
1866
        try:
1867
            app_doc_data = AppDocData.instance()
1868

    
1869
            modifiers = QApplication.keyboardModifiers()
1870
            image = self.graphicsView.image().copy(x, y, width, height)
1871
            dialog = QOcrResultDialog(self, image, QRectF(x, y, width, height),
1872
                                      format=QOcrResultDialog.Format.Table if modifiers == Qt.AltModifier else QOcrResultDialog.Format.Normal)
1873
            if modifiers == Qt.ControlModifier:
1874
                return
1875
            
1876
            if show:
1877
                (res, textInfoList) = dialog.showDialog()
1878
            else:
1879
                dialog.accept(show=False)
1880
                (res, textInfoList) = QDialog.Accepted, dialog.textInfoList
1881

    
1882
            if QDialog.Accepted == res and textInfoList:
1883
                for textInfo in textInfoList:
1884
                    item = QEngineeringTextItem.create_text_with(self.graphicsView.scene(), textInfo)
1885
                    if item:
1886
                        #item.setDefaultTextColor(Qt.blue)
1887
                        item.transfer.onRemoved.connect(self.itemRemoved)
1888

    
1889
                        area_list = app_doc_data.getAreaList()
1890
                        title_area_list = app_doc_data.getTitleBlockProperties()
1891
                        title_list = []
1892
                        if title_area_list:
1893
                            for title_area in title_area_list:
1894
                                area = Area(title_area[0])
1895
                                area.parse(title_area[2])
1896
                                title_list.append(area)
1897
                        for area in area_list + title_list:
1898
                            pt = [item.sceneBoundingRect().center().x(), item.sceneBoundingRect().center().y()]
1899
                            if area.contains(pt):
1900
                                item.area = area.name
1901
                                break
1902
                    else:
1903
                        self.addMessage.emit(MessageType.Normal, self.tr('Fail to create text.'))
1904

    
1905
                return True
1906
            elif QDialog.Accepted == res and not textInfoList and show:
1907
                QMessageBox.about(self.graphicsView, self.tr("Notice"), self.tr("Fail to recognize text"))
1908
        except Exception as ex:
1909
            message = 'error occurred({}) in {}:{}'.format(ex, sys.exc_info()[-1].tb_frame.f_code.co_filename,
1910
                                                           sys.exc_info()[-1].tb_lineno)
1911
            self.addMessage.emit(MessageType.Error, message)
1912
        
1913
        return False
1914

    
1915
    '''
1916
        @brief  area configuration
1917
    '''
1918
    def areaConfiguration(self):
1919
        from ConfigurationAreaDialog import QConfigurationAreaDialog
1920
        if not self.graphicsView.hasImage():
1921
            self.showImageSelectionMessageBox()
1922
            return
1923
        self.onCommandRejected()
1924
        dlgConfigurationArea = QConfigurationAreaDialog(self)
1925
        dlgConfigurationArea.show()
1926
        dlgConfigurationArea.exec_()
1927

    
1928
    '''
1929
        @brief  configuration
1930
    '''
1931
    def configuration(self):
1932
        from ConfigurationDialog import QConfigurationDialog
1933

    
1934
        dlgConfiguration = QConfigurationDialog(self)
1935
        if QDialog.Accepted == dlgConfiguration.exec_():
1936
            QEngineeringLineItem.LINE_TYPE_COLORS.clear()
1937
            QEngineeringInstrumentItem.INST_COLOR = None
1938

    
1939
    '''
1940
        @brief  show special item types dialog 
1941
        @author humkyung
1942
        @date   2019.08.10
1943
    '''
1944
    def on_show_special_item_types(self):
1945
        from SpecialItemTypesDialog import QSpecialItemTypesDialog
1946

    
1947
        dlg = QSpecialItemTypesDialog(self)
1948
        dlg.exec_()
1949

    
1950
    def on_show_data_transfer(self):
1951
        """ show data transfer dialog """
1952
        from DataTransferDialog import QDataTransferDialog
1953

    
1954
        dlg = QDataTransferDialog(self)
1955
        dlg.exec_()
1956

    
1957
    def on_show_data_export(self):
1958
        """ show data export dialog """
1959
        from DataExportDialog import QDataExportDialog
1960

    
1961
        dlg = QDataExportDialog(self)
1962
        dlg.exec_()
1963

    
1964
    def on_show_eqp_datasheet_export(self):
1965
        """ show eqp datasheet export dialog """
1966
        from EqpDatasheetExportDialog import QEqpDatasheetExportDialog
1967

    
1968
        dlg = QEqpDatasheetExportDialog(self)
1969
        dlg.exec_()
1970

    
1971
    def on_show_opc_relation(self):
1972
        """ show opc relation dialog """
1973
        from OPCRelationDialog import QOPCRelationDialog
1974

    
1975
        dlg = QOPCRelationDialog(self)
1976
        dlg.exec_()
1977

    
1978
    '''
1979
        @brief  show nominal diameter dialog 
1980
        @author humkyung
1981
        @date   2018.06.28
1982
    '''
1983
    def onShowCodeTable(self):
1984
        from CodeTableDialog import QCodeTableDialog
1985

    
1986
        dlg = QCodeTableDialog(self)
1987
        dlg.show()
1988
        dlg.exec_()
1989
        if dlg.code_area:
1990
            if dlg.code_area.scene():
1991
                self.graphicsView.scene().removeItem(dlg.code_area)
1992
        if dlg.desc_area:
1993
            if dlg.desc_area.scene():
1994
                self.graphicsView.scene().removeItem(dlg.desc_area)
1995
        self.graphicsView.useDefaultCommand()
1996

    
1997
    def on_ext_app_connection(self):
1998
        app_doc_data = AppDocData.instance()
1999

    
2000
        tool_pane = self.ribbon.get_pane('Tool')
2001
        if tool_pane.ui.toolButtonConnection.isChecked():
2002
            if not hasattr(self, '_tcpserver'):
2003
                configs = app_doc_data.getAppConfigs('app', 'port')
2004
                port = 2549
2005
                if configs and 1 == len(configs):
2006
                    port = int(configs[0].value)
2007
                self._tcpserver = TcpServer(port)
2008
                self._tcpserver.sessionOpened()
2009
        else:
2010
            self._tcpserver.sessionClosed()
2011
            del self._tcpserver
2012

    
2013
    def on_execute_ext_app(self):
2014
        """execute external application"""
2015
        from ExtAppsDialog import QExtAppsDialog
2016

    
2017
        dlg = QExtAppsDialog(self)
2018
        dlg.exec_()
2019

    
2020
    def onShowCustomCodeTable(self):
2021
        from CustomCodeTablesDialog import CustomCodeTablesDialog
2022

    
2023
        dlg = CustomCodeTablesDialog(self)
2024
        dlg.show()
2025
        dlg.exec_()
2026
        self.graphicsView.useDefaultCommand()
2027

    
2028
    def onShowReplaceCodeTable(self):
2029
        from CustomCodeTablesDialog import CustomCodeTablesDialog
2030

    
2031
        dlg = CustomCodeTablesDialog(self, replace=True)
2032
        dlg.show()
2033
        dlg.exec_()
2034
        self.graphicsView.useDefaultCommand()
2035

    
2036
    def on_streamline(self):
2037
        """pop up stream line dialog"""
2038
        from StreamlineDialog import QStreamlineDialog
2039

    
2040
        if not self.graphicsView.hasImage():
2041
            self.showImageSelectionMessageBox()
2042
            return
2043

    
2044
        hmbs = AppDocData.instance().get_hmb_data(None)
2045
        if not hmbs:
2046
            return
2047

    
2048
        dlg = QStreamlineDialog(self)
2049
        dlg.show()
2050

    
2051
    def onHMBData(self):
2052
        """show HMB data"""
2053
        from HMBDialog import QHMBDialog
2054

    
2055
        dlg = QHMBDialog(self)
2056
        dlg.show()
2057
        dlg.exec_()
2058

    
2059
    '''
2060
        @brief  show line data list 
2061
        @author humkyung
2062
        @date   2018.05.03
2063
    '''
2064
    def showItemDataList(self):
2065
        from ItemDataExportDialog import QItemDataExportDialog
2066

    
2067
        dlg = QItemDataExportDialog(self)
2068
        dlg.exec_()
2069

    
2070
    def showTextDataList(self):
2071
        '''
2072
            @brief      show all text item in scene
2073
            @author     euisung
2074
            @date       2019.04.18
2075
        '''
2076
        try:
2077
            if not self.graphicsView.hasImage():
2078
                self.showImageSelectionMessageBox()
2079
                return
2080

    
2081
            self.onCommandRejected()
2082
            dialog = QTextDataListDialog(self)
2083
            dialog.show()
2084
        except Exception as ex:
2085
            message = 'error occurred({}) in {}:{}'.format(ex, sys.exc_info()[-1].tb_frame.f_code.co_filename,
2086
                                                           sys.exc_info()[-1].tb_lineno)
2087
            self.addMessage.emit(MessageType.Error, message)
2088

    
2089
    '''
2090
        @brief  Show Image Selection Guide MessageBox
2091
        @author Jeongwoo
2092
        @date   2018.05.02
2093
    '''
2094
    def showImageSelectionMessageBox(self):
2095
        QMessageBox.about(self.graphicsView, self.tr("Notice"), self.tr("First select image drawing"))
2096

    
2097
    def on_search_text_changed(self):
2098
        """filter symbol tree view"""
2099
        regexp = QRegExp(self.lineEditFilter.text(), Qt.CaseInsensitive, QRegExp.FixedString)
2100

    
2101
        proxy_model = self.symbolTreeWidget.model()
2102
        proxy_model.text = self.lineEditFilter.text().lower()
2103
        proxy_model.setFilterRegExp(regexp)
2104

    
2105
        self.symbolTreeWidget.expandAll()
2106

    
2107
    def change_display_colors(self):
2108
        """ change display color mode """
2109
        visualization_pane = self.ribbon.get_pane('Home Visualization')
2110
        if visualization_pane.ui.radioButtonByGroup.isChecked():
2111
            visualization_pane.ui.radioButtonByType.setChecked(True)
2112
        else:
2113
            visualization_pane.ui.radioButtonByGroup.setChecked(True)
2114

    
2115
    def display_colors(self, value):
2116
        """ display colors """
2117
        from DisplayColors import DisplayColors, DisplayOptions
2118

    
2119
        if hasattr(self, 'ribbon'):
2120
            visualization_pane = self.ribbon.get_pane('Home Visualization')
2121
            if self.sender() is visualization_pane.ui.radioButtonByGroup and value is True:
2122
                DisplayColors.instance().option = DisplayOptions.DisplayByLineNo
2123
            elif self.sender() is visualization_pane.ui.radioButtonByType and value is True:
2124
                DisplayColors.instance().option = DisplayOptions.DisplayByLineType
2125
            elif self.sender() is visualization_pane.ui.radioButtonByStreamNo and value is True:
2126
                DisplayColors.instance().option = DisplayOptions.DisplayByStreamNo
2127

    
2128
            if hasattr(self, 'graphicsView') and value is True:
2129
                self.graphicsView.scene().update(self.graphicsView.sceneRect())
2130
                for item in self.graphicsView.scene().items():
2131
                    if issubclass(type(item), SymbolSvgItem):
2132
                        item.update()
2133
                DisplayColors.instance().save_data()
2134

    
2135
    def open_image_drawing(self, drawing, force=False, ocrUnknown=False, timer=True, pdf=False):
2136
        """open and display image drawing file"""
2137
        from Drawing import Drawing
2138
        from App import App
2139
        from LoadCommand import LoadCommand
2140
        import concurrent.futures as futures
2141

    
2142
        # Yield successive n-sized
2143
        # chunks from l.
2144
        def divide_chunks(l, n):
2145
            # looping till length l
2146
            for i in range(0, len(l), n):
2147
                yield l[i:i + n]
2148

    
2149
        def update_items(items):
2150
            for item in items:
2151
                # binding items
2152
                item.owner
2153
                for connector in item.connectors:
2154
                    connector.connectedItem
2155

    
2156
            return items
2157

    
2158
        try:
2159
            app_doc_data = AppDocData.instance()
2160

    
2161
            if not self.actionSave.isEnabled():
2162
                return
2163

    
2164
            if not force and self.save_drawing_if_necessary():
2165
                return
2166

    
2167
            if not pdf:
2168
                occupied = app_doc_data.set_occupying_drawing(drawing.UID)
2169
                if occupied:
2170
                    QMessageBox.about(self.graphicsView, self.tr("Notice"),
2171
                                      self.tr(f"The drawing is locked for editing by another user({occupied})"))
2172
                    return
2173

    
2174
            # save alarm
2175
            if timer:
2176
                self.save_alarm_enable(False)
2177

    
2178
            if hasattr(self, '_save_work_cmd'):
2179
                self._save_work_cmd.wait()
2180

    
2181
            project = app_doc_data.getCurrentProject()
2182

    
2183
            self.path = self.graphicsView.loadImageFromFile(drawing)
2184
            if os.path.isfile(self.path):
2185
                self.onCommandRejected()
2186
                app_doc_data.clear(past=drawing.UID)
2187

    
2188
                # load color for stream no coloring
2189
                configs = app_doc_data.getConfigs('Line List', 'Use Stream No')
2190
                if configs and int(configs[0].value) == 1:
2191
                    hmbs = app_doc_data.get_hmb_data(None)
2192
                    colors = {}
2193
                    if hmbs:
2194
                        for hmb in hmbs:
2195
                            rgb = app_doc_data.colors
2196
                            colors[hmb.stream_no] = QColor(rgb.red, rgb.green, rgb.blue).name()
2197
                        app_doc_data._hmbColors = colors
2198
                # up to here
2199

    
2200
                app_doc_data.setImgFilePath(self.path)
2201
                app_doc_data.activeDrawing = drawing
2202
                
2203
                #app_doc_data.activeDrawing.set_pid_source(Image.open(self.path))
2204
                self.itemTreeWidget.setCurrentPID(app_doc_data.activeDrawing.name)
2205

    
2206
                drawingList = self.treeWidgetDrawingList.topLevelItem(0)
2207
                for idx in range(drawingList.childCount()):
2208
                    child = drawingList.child(idx)
2209
                    if child.data(Qt.UserRole, 0) is drawing:
2210
                        child.setCheckState(0, Qt.Checked)
2211
                    else:
2212
                        child.setCheckState(0, Qt.Unchecked)
2213

    
2214
                try:
2215
                    self.show_Progress_bar()
2216

    
2217
                    # disconnect scene changed if signal is connected
2218
                    if self.graphicsView.scene().receivers(self.graphicsView.scene().contents_changed) > 0:
2219
                        self.graphicsView.scene().contents_changed.disconnect()
2220

    
2221
                    SymbolSvgItem.DOCUMENTS.clear()
2222

    
2223
                    # load data
2224
                    cmd = LoadCommand()
2225
                    cmd.display_message.connect(self.onAddMessage)
2226
                    cmd.set_maximum.connect(self.progress.setMaximum)
2227
                    cmd.show_progress.connect(self.progress.setValue)
2228
                    cmd.execute((drawing, self.graphicsView.scene()),
2229
                                symbol=True, text=True, line=True, unknown=True, package=True, update=not pdf)
2230

    
2231
                    configs = app_doc_data.getConfigs('Line List', 'Use Stream No')
2232
                    if configs and int(configs[0].value) == 1:
2233
                        app_doc_data._streamLineListModelDatas = app_doc_data.get_stream_line_list_data()
2234
                    # up to here
2235

    
2236
                    """update item tree widget"""
2237
                    line_no_items = [item for item in self.graphicsView.scene().items()
2238
                                     if type(item) is QEngineeringLineNoTextItem]
2239
                    for line_no in line_no_items:
2240
                        line_no_tree_item = self.itemTreeWidget.addTreeItem(self.itemTreeWidget.root, line_no)
2241
                        for run in line_no.runs:
2242
                            for run_item in run.items:
2243
                                if issubclass(type(run_item), SymbolSvgItem):
2244
                                    self.init_add_tree_item(line_no_tree_item, run_item)
2245

    
2246
                    line_no_items = [item for item in self.graphicsView.scene().items()
2247
                                     if type(item) is QEngineeringTrimLineNoTextItem]
2248
                    for line_no in line_no_items:
2249
                        line_no_tree_item = self.itemTreeWidget.addTreeItem(self.itemTreeWidget.root, line_no)
2250
                        for run in line_no.runs:
2251
                            for run_item in run.items:
2252
                                if issubclass(type(run_item), SymbolSvgItem):
2253
                                    self.init_add_tree_item(line_no_tree_item, run_item)
2254

    
2255
                    for trim_line_no in app_doc_data.tracerLineNos:
2256
                        line_no_tree_item = self.itemTreeWidget.addTreeItem(self.itemTreeWidget.root, trim_line_no)
2257
                        for run in trim_line_no.runs:
2258
                            for run_item in run.items:
2259
                                if issubclass(type(run_item), SymbolSvgItem):
2260
                                    self.init_add_tree_item(line_no_tree_item, run_item)
2261

    
2262
                    self.itemTreeWidget.update_item_count()
2263
                    self.itemTreeWidget.expandAll()
2264
                    """up to here"""
2265

    
2266
                    """update scene"""
2267
                    for item in self._scene.items():
2268
                        item.setVisible(True)
2269

    
2270
                    self._scene.update(self._scene.sceneRect())
2271

    
2272
                    """
2273
                    # old open drawing
2274
                    path = os.path.join(app_doc_data.getCurrentProject().getTempPath(), app_doc_data.imgName + '.xml')
2275
                    configs = app_doc_data.getConfigs('Data Load', 'Xml First')
2276
                    if configs and int(configs[0].value) >= 1 and os.path.isfile(path):
2277
                        self.load_recognition_result_from_xml(drawing)
2278
                    elif configs and int(configs[0].value) <= 1:
2279
                        self.load_drawing(app_doc_data.activeDrawing)
2280
                    """
2281

    
2282
                    self.display_number_of_items()
2283
                    # connect scene changed signal
2284
                    self.graphicsView.scene().contents_changed.connect(self.scene_changed)
2285
                finally:
2286
                    if hasattr(self, 'progress'):
2287
                        self.progress.setValue(self.progress.maximum())
2288

    
2289
                self.changeViewCheckedState(None)
2290
                self.updateAsViewCheckedState()
2291
                self.setWindowTitle(self.title)
2292
                if not pdf:
2293
                    self.fitWindow(drawing.view_rect)
2294

    
2295
                if ocrUnknown:
2296
                    self.on_ocr_unknown_items()
2297

    
2298
                # save alarm
2299
                if timer:
2300
                    self.save_alarm_enable(True, True)
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
        return self.path
2307

    
2308
    def save_alarm_enable(self, enable, init=False):
2309
        from datetime import datetime
2310

    
2311
        try:
2312
            app_doc_data = AppDocData.instance()
2313
            configs = app_doc_data.getConfigs('Data Save', 'Time')
2314
            time_min = int(configs[0].value) if 1 == len(configs) else 0
2315

    
2316
            if enable and time_min > 0:
2317
                if not self.save_timer:
2318
                    self.save_timer = QTimer()
2319
                    self.save_timer.timeout.connect(self.save_alarm)
2320
                    self.save_timer.setInterval(60000)
2321

    
2322
                if init:
2323
                    self.save_timer._init_time = datetime.now()
2324
                    self.save_timer._stop_time = None
2325
                    self.save_timer._interval_time = datetime.now() - datetime.now()
2326

    
2327
                if self.save_timer._stop_time:
2328
                    self.save_timer._interval_time = datetime.now() - self.save_timer._stop_time
2329
                
2330
                #if 60000 * time_min != self.save_timer.interval():
2331
                #    self.save_timer.setInterval(60000)
2332

    
2333
                self.save_timer.start()
2334
            else:
2335
                if self.save_timer:
2336
                    self.save_timer.stop()
2337
                    self.save_timer._stop_time = datetime.now()
2338
        
2339
        except Exception as ex:
2340
            message = f"error occurred({repr(ex)}) in {sys.exc_info()[-1].tb_frame.f_code.co_filename}:" \
2341
                      f"{sys.exc_info()[-1].tb_lineno}"
2342
            self.addMessage.emit(MessageType.Error, message)
2343

    
2344
    def save_alarm(self):
2345
        from datetime import datetime
2346

    
2347
        app_doc_data = AppDocData.instance()
2348
        configs = app_doc_data.getConfigs('Data Save', 'Time')
2349
        time_min = int(configs[0].value) if 1 == len(configs) else 0
2350

    
2351
        self.save_timer.stop()
2352
        if self.graphicsView.hasFocus() and (datetime.now() - self.save_timer._init_time - self.save_timer._interval_time).seconds > time_min * 60:
2353
            QMessageBox.information(self, self.tr('Information'), self.tr('Please save Drawing'))
2354
            self.save_timer._init_time = datetime.now()
2355
            self.save_timer._interval_time = datetime.now() - datetime.now()
2356
        self.save_timer.start()
2357

    
2358
    def export_as_svg(self):
2359
        """export scene to svg file"""
2360
        from ExportCommand import ExportCommand
2361

    
2362
        options = QFileDialog.Options()
2363
        options |= QFileDialog.DontUseNativeDialog
2364
        file_path, _ = QFileDialog.getSaveFileName(self, "Export as svg", os.getcwd(), "svg file(*.svg)",
2365
                                                   options=options)
2366
        if file_path:
2367
            cmd = ExportCommand(self.graphicsView.scene(), 'svg')
2368
            cmd.display_message.connect(self.onAddMessage)
2369
            if cmd.execute(file_path):
2370
                QMessageBox.information(self, self.tr('Information'), self.tr('Successfully export to svg file'))
2371
            else:
2372
                QMessageBox.information(self, self.tr('Error'), self.tr('Fail to export to svg file'))
2373

    
2374
    def export_as_xml(self):
2375
        pass
2376

    
2377
    def export_as_image(self):
2378
        """export scene to image file"""
2379
        from ExportCommand import ExportCommand
2380

    
2381
        options = QFileDialog.Options()
2382
        options |= QFileDialog.DontUseNativeDialog
2383
        file_path, _ = QFileDialog.getSaveFileName(self, "Export as png", os.getcwd(), "png file(*.png)",
2384
                                                   options=options)
2385
        if file_path:
2386
            try:
2387
                # hide image drawing
2388
                self.onViewImageDrawing(False)
2389

    
2390
                cmd = ExportCommand(self.graphicsView.scene(), 'image')
2391
                cmd.display_message.connect(self.onAddMessage)
2392

    
2393
                if cmd.execute(file_path):
2394
                    QMessageBox.information(self, self.tr('Information'), self.tr('Successfully export to image file'))
2395
                else:
2396
                    QMessageBox.information(self, self.tr('Error'), self.tr('Fail to export to image file'))
2397
            finally:
2398
                if self.actionImage_Drawing.isChecked():
2399
                    self.onViewImageDrawing(True)
2400
                    self.actionImage_Drawing.setChecked(True)
2401

    
2402
    def show_Progress_bar(self):
2403
        """ show progress bar """
2404
        self.progress = QProgressDialog(self.tr("Please wait for a while"), self.tr("Cancel"), 0, 100,
2405
                                        self) if not hasattr(self, 'progress') else self.progress
2406
        self.progress.setWindowModality(Qt.WindowModal)
2407
        self.progress.setAutoReset(True)
2408
        self.progress.setAutoClose(True)
2409
        self.progress.setMinimum(0)
2410
        self.progress.setMaximum(100)
2411
        self.progress.resize(600, 100)
2412
        self.progress.setWindowTitle(self.tr("Reading file..."))
2413
        self.progress.show()
2414

    
2415
    def changeViewCheckedState(self, checked, clear=True):
2416
        """change view checked state"""
2417
        # self.actionImage_Drawing.setChecked(checked)
2418
        
2419
        '''
2420
        self.actionViewText.setChecked(checked)
2421
        self.actionViewSymbol.setChecked(checked)
2422
        self.actionViewLine.setChecked(checked)
2423
        self.actionViewUnknown.setChecked(checked)
2424
        self.actionViewInconsistency.setChecked(checked)
2425
        self.actionViewVendor_Area.setChecked(not checked)
2426
        self.actionDrawing_Only.setChecked(not checked)
2427
        '''
2428

    
2429
        if checked is not None:
2430
            view_pane = self.ribbon.get_pane('View')
2431
            view_pane.ui.toolButtonViewText.setChecked(checked)
2432
            view_pane.ui.toolButtonViewSymbol.setChecked(checked)
2433
            view_pane.ui.toolButtonViewLine.setChecked(checked)
2434
            view_pane.ui.toolButtonViewUnknown.setChecked(checked)
2435
            view_pane.ui.toolButtonViewInconsistency.setChecked(checked)
2436
            view_pane.ui.toolButtonViewVendorArea.setChecked(checked)
2437
            view_pane.ui.toolButtonViewDrawingOnly.setChecked(not checked)
2438

    
2439
        if clear:
2440
            self.tableWidgetInconsistency.clearContents()
2441
            self.tableWidgetInconsistency.setRowCount(0)
2442

    
2443
    def updateAsViewCheckedState(self):
2444
        view_pane = self.ribbon.get_pane('View')
2445
        self.onViewImageDrawing(view_pane.ui.toolButtonViewImageDrawing.isChecked())
2446
        self.onViewText(view_pane.ui.toolButtonViewText.isChecked())
2447
        self.onViewSymbol(view_pane.ui.toolButtonViewSymbol.isChecked())
2448
        self.onViewLine(view_pane.ui.toolButtonViewLine.isChecked())
2449
        self.onViewUnknown(view_pane.ui.toolButtonViewUnknown.isChecked())
2450
        self.onViewInconsistency(view_pane.ui.toolButtonViewInconsistency.isChecked())
2451
        self.onViewVendorArea(view_pane.ui.toolButtonViewVendorArea.isChecked())
2452
        #self.onViewDrawingOnly(view_pane.ui.toolButtonViewDrawingOnly.isChecked())
2453

    
2454
    def onViewDrawingOnly(self, isChecked):
2455
        '''
2456
            @brief  visible/invisible except image drawing
2457
            @author euisung
2458
            @date   2019.04.22
2459
        '''
2460
        self.changeViewCheckedState(not isChecked, False)
2461
        for item in self.graphicsView.scene().items():
2462
            if type(item) is not QGraphicsPixmapItem and issubclass(type(item), QEngineeringAbstractItem):
2463
                item.setVisible(not isChecked)
2464

    
2465
    '''
2466
        @brief  visible/invisible image drawing
2467
        @author humkyung
2468
        @date   2018.06.25
2469
    '''
2470
    def onViewImageDrawing(self, isChecked):
2471
        for item in self.graphicsView.scene().items():
2472
            if type(item) is QGraphicsPixmapItem:
2473
                item.setVisible(isChecked)
2474
                break
2475

    
2476
    def onViewText(self, checked):
2477
        """visible/invisible text"""
2478
        selected = [item for item in self.graphicsView.scene().items() if issubclass(type(item), QEngineeringTextItem)]
2479
        for item in selected:
2480
            item.setVisible(checked)
2481

    
2482
    def onViewSymbol(self, checked):
2483
        """visible/invisible symbol"""
2484
        selected = [item for item in self.graphicsView.scene().items() if issubclass(type(item), SymbolSvgItem)]
2485
        for item in selected:
2486
            item.setVisible(checked)
2487

    
2488
    def onViewLine(self, checked):
2489
        """visible/invisible line"""
2490
        selected = [item for item in self.graphicsView.scene().items() if type(item) is QEngineeringLineItem]
2491
        for item in selected:
2492
            item.setVisible(checked)
2493

    
2494
    def onViewInconsistency(self, isChecked):
2495
        '''
2496
            @brief  visible/invisible Inconsistency
2497
            @author euisung
2498
            @date   2019.04.03
2499
        '''
2500
        selected = [item for item in self.graphicsView.scene().items() if type(item) is QEngineeringErrorItem]
2501
        for item in selected:
2502
            item.setVisible(isChecked)
2503

    
2504
    '''
2505
        @brief  visible/invisible Unknown 
2506
        @author humkyung
2507
        @date   2018.06.28
2508
    '''
2509
    def onViewUnknown(self, isChecked):
2510
        selected = [item for item in self.graphicsView.scene().items() if type(item) is QEngineeringUnknownItem]
2511
        for item in selected:
2512
            item.setVisible(isChecked)
2513

    
2514
    def onViewVendorArea(self, isChecked):
2515
        '''
2516
            @brief  visible/invisible Vendor Area
2517
            @author euisung
2518
            @date   2019.04.29
2519
        '''
2520
        selected = [item for item in self.graphicsView.scene().items() if issubclass(type(item), QEngineeringVendorItem)]
2521
        for item in selected:
2522
            item.setVisible(isChecked)
2523

    
2524
    '''
2525
        @brief  create a symbol
2526
        @history    2018.05.02  Jeongwoo    Change return value of QSymbolEditorDialog (Single variable → Tuple)
2527
                                            Add SymbolSvgItem
2528
                    2018.05.03  Jeongwoo    Change method to draw Svg Item on Scene (svg.addSvgItemToScene)
2529
                                            Change method to make svg and image path
2530
                    2018.06.08  Jeongwoo    Add Paramter on SymbolSvgItem.buildItem()
2531
    '''
2532
    def onCreateSymbolClicked(self):
2533
        selected = [item for item in self.graphicsView.scene().selectedItems() if issubclass(type(item), QEngineeringVendorItem)]
2534
        if len(selected) == 1:
2535
            symbol_image = AppDocData.instance().activeDrawing.image_origin
2536
            rect = selected[0].sceneBoundingRect()
2537

    
2538
            points = []
2539
            for conn in selected[0].connectors:
2540
                points.append([round(conn.center()[0] - rect.x()), round(conn.center()[1] - rect.y())])
2541
            poly = np.array(points, np.int32)
2542

    
2543
            #mask = np.zeros((int(rect.height()), int(rect.width())))
2544
            #cv2.fillPoly(mask, [poly], (255))
2545
            #poly_copied = np.multiply(mask, symbol_image[round(rect.y()):round(rect.y() + rect.height()),
2546
            #                   round(rect.x()):round(rect.x() + rect.width())])
2547
            #cv2.fillPoly(mask,[poly],0)
2548
            #src2 = np.multiply(mask,src2)
2549

    
2550
            mask = np.ones((int(rect.height()), int(rect.width())), dtype=np.uint8) * 255
2551
            cv2.fillPoly(mask, [poly], (0))
2552
            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())])
2553
            sym_img = cv2.merge((sym_img, sym_img, sym_img))
2554

    
2555
            h, w, c = sym_img.shape
2556
            qImg = QImage(sym_img.data, w, h, w * c, QImage.Format_RGB888)
2557
            #pixmap = QPixmap.fromImage(qImg)
2558

    
2559
            self.onAreaSelected(None, None, None, None, package=qImg, position=rect.topLeft(), package_item=selected[0])
2560
        else:
2561
            cmd = FenceCommand.FenceCommand(self.graphicsView)
2562
            cmd.onSuccess.connect(self.onAreaSelected)
2563
            self.graphicsView.command = cmd
2564
            QApplication.setOverrideCursor(Qt.CrossCursor)
2565

    
2566
    '''
2567
        @brief      show SymbolEditorDialog with image selected by user
2568
        @author     humkyung
2569
        @date       2018.07.20
2570
    '''
2571
    def onAreaSelected(self, x, y, width, height, package=False, position=None, package_item=None):
2572
        try:
2573
            image = self.graphicsView.image()
2574
            if image is not None:
2575
                if not package:
2576
                    symbolEditorDialog = SymbolEditorDialog.QSymbolEditorDialog(self, image.copy(x, y, width, height),
2577
                                                                                AppDocData.instance().getCurrentProject())
2578
                else:
2579
                    symbolEditorDialog = SymbolEditorDialog.QSymbolEditorDialog(self, package,
2580
                                                                                AppDocData.instance().getCurrentProject(), package=True)
2581
                (isAccepted, isImmediateInsert, offsetX, offsetY, newSym) = symbolEditorDialog.showDialog()
2582
                # TODO: not initialize symbol tree view when user reject to create a new symbol
2583
                self.symbolTreeWidget.initSymbolTreeView()
2584
                if isAccepted:
2585
                    if isImmediateInsert:
2586
                        svg = QtImageViewer.createSymbolObject(newSym.getName())
2587
                        offsetX, offsetY = [int(point) for point in newSym.getOriginalPoint().split(',')]
2588
                        QtImageViewer.matchSymbolToLine(self.graphicsView.scene(), svg, QPoint(position.x() + offsetX, position.y() + offsetY))
2589

    
2590
                        package_item.transfer.onRemoved.emit(package_item)
2591
        finally:
2592
            self.onCommandRejected()
2593
            QApplication.restoreOverrideCursor()
2594
            QApplication.restoreOverrideCursor()
2595

    
2596
    def on_line_list(self):
2597
        """ line list export dialog """
2598
        from LineListDialog import LineListDialog
2599

    
2600
        if not self.graphicsView.hasImage():
2601
            self.showImageSelectionMessageBox()
2602
            return
2603

    
2604
        dialog = LineListDialog(self)
2605
        dialog.showDialog()
2606

    
2607
    def on_make_label_data(self):
2608
        """ make label data from symbol info """
2609
        from xml.etree.ElementTree import Element, SubElement, dump, ElementTree, parse
2610

    
2611
        if not self.graphicsView.hasImage():
2612
            self.showImageSelectionMessageBox()
2613
            return
2614

    
2615
        app_doc_data = AppDocData.instance()
2616
        project = app_doc_data.getCurrentProject()
2617

    
2618
        smalls = []
2619
        bigs = []
2620

    
2621
        symbol_list = app_doc_data.getTargetSymbolList(all=True)
2622
        #symbol_list = app_doc_data.getTargetSymbolList(all=False)
2623
        for symbol in symbol_list:
2624
            if symbol.iType == 38 or symbol.iType == 33 or symbol.iType == 0 or symbol.iType == 40:
2625
                continue
2626
            elif symbol.width and symbol.height:
2627
                if symbol.width > 300 or symbol.height > 300:
2628
                    bigs.append(symbol.getName())
2629
                elif (symbol.width * symbol.height < 1500) or (symbol.width > 450 or symbol.height > 450):
2630
                    continue
2631
                else:
2632
                    smalls.append(symbol.getName())
2633

    
2634
        symbols = [item for item in self.graphicsView.scene().items() if issubclass(type(item), SymbolSvgItem)]
2635
        names = [smalls, bigs]
2636

    
2637
        img = app_doc_data.activeDrawing.image_origin
2638

    
2639
        small_size = 500
2640
        big_size = 850
2641

    
2642
        save_path = project.getTrainingSymbolFilePath()
2643

    
2644
        index = 0
2645
        for size in [small_size, big_size]:
2646
            offsets = [0, int(size / 2)]
2647

    
2648
            width, height = img.shape[1], img.shape[0]
2649
            width_count, height_count = width // size + 2, height // size + 2
2650
            b_width, b_height = width_count * size, height_count * size
2651
            b_img = np.zeros((b_height, b_width), np.uint8) + 255
2652
            b_img[:height, :width] = img[:, :]
2653

    
2654
            for offset in offsets:
2655
                for row in range(height_count):
2656
                    for col in range(width_count):
2657
                        x, y = col * size + offset, row * size + offset
2658
                        tile_rect = QRectF(x, y, size, size)
2659
                        tile_symbols = []
2660
                        for symbol in [symbol for symbol in symbols if symbol.name in names[index]]:
2661
                            if tile_rect.contains(symbol.sceneBoundingRect()):
2662
                                tile_symbols.append(symbol)
2663
                                symbols.remove(symbol)
2664

    
2665
                        if tile_symbols:
2666
                            training_uid = str(uuid.uuid4())
2667
                            training_image_path = os.path.join(save_path, training_uid + '.png')
2668
                            training_xml_path = os.path.join(save_path, training_uid + '.xml')
2669

    
2670
                            # save image
2671
                            #_img = b_img[round(tile_rect.top()):round(tile_rect.bottom()),
2672
                            #       round(tile_rect.left()):round(tile_rect.right())]
2673
                            #cv2.imwrite(training_image_path, _img)
2674
                            _img = self.graphicsView.image().copy(round(tile_rect.left()), round(tile_rect.top()), round(tile_rect.width()), round(tile_rect.height()))
2675
                            _img.save(training_image_path)
2676

    
2677
                            # save label
2678
                            xml = Element('annotation')
2679
                            SubElement(xml, 'folder').text = 'None'
2680
                            SubElement(xml, 'filename').text = os.path.basename(save_path)
2681

    
2682
                            pathNode = Element('path')
2683
                            pathNode.text = save_path.replace('/', '\\')
2684
                            xml.append(pathNode)
2685

    
2686
                            sourceNode = Element('source')
2687
                            databaseNode = Element('database')
2688
                            databaseNode.text = 'Unknown'
2689
                            sourceNode.append(databaseNode)
2690
                            xml.append(sourceNode)
2691

    
2692
                            sizeNode = Element('size')
2693
                            widthNode = Element('width')
2694
                            widthNode.text = str(int(tile_rect.width()))
2695
                            sizeNode.append(widthNode)
2696
                            heightNode = Element('height')
2697
                            heightNode.text = str(int(tile_rect.height()))
2698
                            sizeNode.append(heightNode)
2699
                            depthNode = Element('depth')
2700
                            depthNode.text = '3'
2701
                            sizeNode.append(depthNode)
2702
                            xml.append(sizeNode)
2703

    
2704
                            segmentedNode = Element('segmented')
2705
                            segmentedNode.text = '0'
2706
                            xml.append(segmentedNode)
2707

    
2708
                            labelContent = []
2709
                            counts = {}
2710
                            for item in tile_symbols:
2711
                                rect = item.sceneBoundingRect()
2712
                                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)
2713
                                #label = 'small' if index == 0 else 'big' # for single class test
2714
                                xMin = xMin if xMin > 0 else 0
2715
                                yMin = yMin if yMin > 0 else 0
2716
                                xMax = xMax if xMax < size else size
2717
                                yMax = yMax if yMax < size else size
2718

    
2719
                                if label == 'None' or label == '':
2720
                                    continue
2721
                                if label not in labelContent:
2722
                                    labelContent.append(label)
2723
                                    counts[label] = 1
2724
                                else:
2725
                                    counts[label] = counts[label] + 1
2726

    
2727
                                objectNode = Element('object')
2728
                                nameNode = Element('name')
2729
                                nameNode.text = label
2730
                                objectNode.append(nameNode)
2731
                                poseNode = Element('pose')
2732
                                poseNode.text = 'Unspecified'
2733
                                objectNode.append(poseNode)
2734
                                truncatedNode = Element('truncated')
2735
                                truncatedNode.text = '0'
2736
                                objectNode.append(truncatedNode)
2737
                                difficultNode = Element('difficult')
2738
                                difficultNode.text = '0'
2739
                                objectNode.append(difficultNode)
2740

    
2741
                                bndboxNode = Element('bndbox')
2742
                                xminNode = Element('xmin')
2743
                                xminNode.text = str(xMin)
2744
                                bndboxNode.append(xminNode)
2745
                                yminNode = Element('ymin')
2746
                                yminNode.text = str(yMin)
2747
                                bndboxNode.append(yminNode)
2748
                                xmaxNode = Element('xmax')
2749
                                xmaxNode.text = str(xMax)
2750
                                bndboxNode.append(xmaxNode)
2751
                                ymaxNode = Element('ymax')
2752
                                ymaxNode.text = str(yMax)
2753
                                bndboxNode.append(ymaxNode)
2754
                                objectNode.append(bndboxNode)
2755

    
2756
                                xml.append(objectNode)
2757

    
2758
                            ElementTree(xml).write(training_xml_path)
2759

    
2760
            index += 1
2761

    
2762
        QMessageBox.about(self, self.tr("Notice"), self.tr('Successfully applied. '))
2763

    
2764
    def onPlaceLine(self):
2765
        """create a line"""
2766
        home_pane = self.ribbon.get_pane('Home')
2767

    
2768
        if not self.graphicsView.hasImage():
2769
            home_pane.ui.toolButtonLine.setChecked(False)
2770
            self.showImageSelectionMessageBox()
2771
            return
2772

    
2773
        self.update_action_group(home_pane.ui.toolButtonLine)
2774
        if not hasattr(home_pane.ui.toolButtonLine, 'tag'):
2775
            home_pane.ui.toolButtonLine.tag = PlaceLineCommand.PlaceLineCommand(self.graphicsView)
2776
            home_pane.ui.toolButtonLine.tag.onSuccess.connect(self.onLineCreated)
2777
            home_pane.ui.toolButtonLine.tag.onRejected.connect(self.onCommandRejected)
2778

    
2779
        self.graphicsView.command = home_pane.ui.toolButtonLine.tag
2780

    
2781
    def onLineCreated(self):
2782
        """add created lines to scene"""
2783
        from EngineeringConnectorItem import QEngineeringConnectorItem
2784
        from LineDetector import LineDetector
2785

    
2786
        try:
2787
            app_doc_data = AppDocData.instance()
2788
            home_pane = self.ribbon.get_pane('Home')
2789

    
2790
            count = len(home_pane.ui.toolButtonLine.tag._polyline._vertices)
2791
            if count > 1:
2792
                items = []
2793

    
2794
                detector = LineDetector(None)
2795

    
2796
                if not home_pane.ui.toolButtonLine.tag.line_type:
2797
                    line_type = home_pane.ui.comboBoxLineType.currentText()
2798
                else:
2799
                    pane = self.ribbon.get_pane('Home')
2800
                    selected_line_type = pane.ui.comboBoxLineType.currentText()
2801
                    if selected_line_type == 'Connect To Process':
2802
                        line_type = selected_line_type
2803
                    elif not (QEngineeringLineItem.check_piping(home_pane.ui.toolButtonLine.tag.line_type) ^
2804
                              QEngineeringLineItem.check_piping(selected_line_type)):
2805
                        line_type = selected_line_type
2806
                    else:
2807
                        line_type = home_pane.ui.toolButtonLine.tag.line_type
2808
                for index in range(count - 1):
2809
                    start = home_pane.ui.toolButtonLine.tag._polyline._vertices[index]
2810
                    end = home_pane.ui.toolButtonLine.tag._polyline._vertices[index + 1]
2811

    
2812
                    lineItem = QEngineeringLineItem(vertices=[start, end])
2813
                    lineItem.transfer.onRemoved.connect(self.itemRemoved)
2814
                    lineItem.lineType = line_type
2815
                    if items:
2816
                        lineItem.connect_if_possible(items[-1], 5)
2817
                    else:
2818
                        pt = lineItem.start_point()
2819
                        selected = [item for item in self.graphicsView.scene().items(QPointF(pt[0], pt[1])) if
2820
                                    type(item) is QEngineeringConnectorItem or type(item) is QEngineeringLineItem]
2821
                        if selected and selected[0] is not lineItem:
2822
                            if type(selected[0]) is QEngineeringConnectorItem:
2823
                                lineItem.connect_if_possible(selected[0].parent, 5)
2824
                            else:
2825
                                detector.connectLineToLine(selected[0], lineItem, 5)
2826

    
2827
                    items.append(lineItem)
2828
                    self.graphicsView.scene().addItem(lineItem)
2829

    
2830
                pt = items[-1].end_point()
2831
                selected = [item for item in self.graphicsView.scene().items(QPointF(pt[0], pt[1])) if
2832
                            (type(item) is QEngineeringConnectorItem and item.parentItem() is not items[-1]) or
2833
                            (type(item) is QEngineeringLineItem and item is not items[-1])]
2834
                if selected and selected[0] is not items[-1]:
2835
                    if type(selected[0]) is QEngineeringConnectorItem:
2836
                        items[-1].connect_if_possible(selected[0].parent, 5)
2837
                    else:
2838
                        detector.connectLineToLine(selected[0], items[-1], 5)
2839

    
2840
                self._scene.undo_stack.push(CreateCommand(self._scene, items))
2841
        finally:
2842
            self.graphicsView.scene().removeItem(home_pane.ui.toolButtonLine.tag._polyline)
2843
            home_pane.ui.toolButtonLine.tag.reset()
2844

    
2845
    def onCommandRejected(self, cmd=None):
2846
        """command is rejected"""
2847
        try:
2848
            home_pane = self.ribbon.get_pane('Home')
2849
            visualization_pane = self.ribbon.get_pane('Home Visualization')
2850
            if type(cmd) is PlaceLineCommand.PlaceLineCommand:
2851
                if home_pane.ui.toolButtonLine.tag._polyline:
2852
                    self.graphicsView.scene().removeItem(home_pane.ui.toolButtonLine.tag._polyline)
2853
                self.graphicsView.scene().update()
2854
                home_pane.ui.toolButtonLine.tag.reset()
2855

    
2856
                home_pane.ui.toolButtonLine.setChecked(False)
2857
            elif type(cmd) is AreaZoomCommand.AreaZoomCommand:
2858
                visualization_pane.ui.toolButtonZoom.setChecked(False)
2859
            elif type(cmd) is AreaOcrCommand.AreaOcrCommand:
2860
                home_pane.ui.toolButtonOCR.setChecked(False)
2861
            elif type(cmd) is PlacePolygonCommand.PlacePolygonCommand:
2862
                home_pane.ui.toolButtonVendor.setChecked(False)
2863
            else:
2864
                if hasattr(home_pane.ui.toolButtonVendor, 'tag') and home_pane.ui.toolButtonVendor.tag._polyline:
2865
                    self.graphicsView.scene().removeItem(home_pane.ui.toolButtonVendor.tag._polyline)
2866
                    self.graphicsView.scene().update()
2867
                    home_pane.ui.toolButtonVendor.tag.reset()
2868
                home_pane.ui.toolButtonLine.setChecked(False)
2869
                visualization_pane.ui.toolButtonZoom.setChecked(False)
2870
                home_pane.ui.toolButtonOCR.setChecked(False)
2871
                home_pane.ui.toolButtonVendor.setChecked(False)
2872
        finally:
2873
            self.graphicsView.useDefaultCommand()
2874

    
2875
    def on_view_toggle(self, key: int) -> None:
2876
        """view toggled"""
2877

    
2878
        view_pane = self.ribbon.get_pane('View')
2879
        if key == Qt.Key_1:
2880
            checked = view_pane.ui.toolButtonViewImageDrawing.isChecked()
2881
            self.onViewImageDrawing(not checked)
2882
            view_pane.ui.toolButtonViewImageDrawing.setChecked(not checked)
2883
        elif key == Qt.Key_2:
2884
            checked = view_pane.ui.toolButtonViewText.isChecked()
2885
            self.onViewText(not checked)
2886
            view_pane.ui.toolButtonViewText.setChecked(not checked)
2887
        elif key == Qt.Key_3:
2888
            checked = view_pane.ui.toolButtonViewSymbol.isChecked()
2889
            self.onViewSymbol(not checked)
2890
            view_pane.ui.toolButtonViewSymbol.setChecked(not checked)
2891
        elif key == Qt.Key_4:
2892
            checked = view_pane.ui.toolButtonViewLine.isChecked()
2893
            self.onViewLine(not checked)
2894
            view_pane.ui.toolButtonViewLine.setChecked(not checked)
2895
        elif key == Qt.Key_5:
2896
            checked = view_pane.ui.toolButtonViewUnknown.isChecked()
2897
            self.onViewUnknown(not checked)
2898
            view_pane.ui.toolButtonViewUnknown.setChecked(not checked)
2899
        elif key == Qt.Key_6:
2900
            checked = view_pane.ui.toolButtonViewInconsistency.isChecked()
2901
            self.onViewInconsistency(not checked)
2902
            view_pane.ui.toolButtonViewInconsistency.setChecked(not checked)
2903
        elif key == Qt.Key_7:
2904
            checked = view_pane.ui.toolButtonViewVendorArea.isChecked()
2905
            self.onViewVendorArea(not checked)
2906
            view_pane.ui.toolButtonViewVendorArea.setChecked(not checked)
2907
        elif key == 96:  # '~' key
2908
            checked = view_pane.ui.toolButtonViewDrawingOnly.isChecked()
2909
            self.onViewDrawingOnly(not checked)
2910
            view_pane.ui.toolButtonViewDrawingOnly.setChecked(not checked)
2911

    
2912
    def keyPressEvent(self, event):
2913
        """restore to default command when user press Escape key"""
2914
        try:
2915
            #print('main : ' + str(event.key()))
2916
            if event.key() == Qt.Key_Escape:
2917
                checked = self.checked_action()
2918
                if checked:
2919
                    checked.setChecked(False)
2920
                    self.graphicsView.useDefaultCommand()
2921
            elif event.key() == Qt.Key_M:  # merge text, line
2922
                from TextInfo import TextInfo
2923
                from EngineeringConnectorItem import QEngineeringConnectorItem
2924
                from LineDetector import LineDetector
2925

    
2926
                # line merge
2927
                lineItems = [line for line in self.graphicsView.scene().selectedItems() if
2928
                             issubclass(type(line), QEngineeringLineItem)]
2929
                lineValidation = True
2930
                if len(lineItems) > 1:
2931
                    x = []
2932
                    y = []
2933
                    connectedItems = []
2934
                    isVertical = None
2935
                    for line in lineItems:
2936
                        if isVertical == None:
2937
                            isVertical = line.isVertical()
2938
                        elif isVertical != line.isVertical():
2939
                            lineValidation = False
2940

    
2941
                        x.append(line.start_point()[0])
2942
                        y.append(line.start_point()[1])
2943
                        x.append(line.end_point()[0])
2944
                        y.append(line.end_point()[1])
2945

    
2946
                        if line.connectors[0].connectedItem:
2947
                            connectedItems.append(line.connectors[0].connectedItem)
2948
                        if line.connectors[1].connectedItem:
2949
                            connectedItems.append(line.connectors[1].connectedItem)
2950

    
2951
                    if lineValidation:
2952
                        startPoint = [min(x), min(y)]
2953
                        endPoint = [max(x), max(y)]
2954
                        lineItem = QEngineeringLineItem(vertices=[startPoint, endPoint])
2955
                        lineItem.transfer.onRemoved.connect(self.itemRemoved)
2956
                        lineItem.lineType = lineItems[0].lineType
2957

    
2958
                        for line in lineItems:
2959
                            line.transfer.onRemoved.emit(line)
2960

    
2961
                        detector = LineDetector(None)
2962

    
2963
                        for pt in [startPoint, endPoint]:
2964
                            selected = [item for item in self.graphicsView.scene().items(QPointF(pt[0], pt[1])) if
2965
                                        type(item) is QEngineeringConnectorItem or type(item) is QEngineeringLineItem]
2966
                            if selected:
2967
                                if type(selected[0]) is QEngineeringConnectorItem:
2968
                                    lineItem.connect_if_possible(selected[0].parent, 5)
2969
                                elif selected[0] in connectedItems:
2970
                                    lineItem.connect_if_possible(selected[0], 5)
2971
                                else:
2972
                                    detector.connectLineToLine(selected[0], lineItem, 5)
2973

    
2974
                        self.graphicsView.scene().addItem(lineItem)
2975
                # up to here
2976

    
2977
                # text merge
2978
                textItems = [text for text in self.graphicsView.scene().selectedItems() if
2979
                             issubclass(type(text), QEngineeringTextItem)]
2980
                if len(textItems) > 1:
2981
                    angle = None
2982
                    for item in textItems:
2983
                        if angle is None:
2984
                            angle = item.angle
2985
                        else:
2986
                            if angle != item.angle:
2987
                                return
2988

    
2989
                    modifiers = QApplication.keyboardModifiers()
2990
                    enter_or_space = ' ' if modifiers == Qt.ControlModifier else ('\n' if modifiers != Qt.AltModifier else '')
2991
                    x_or_y = 0 if (modifiers == Qt.ControlModifier and angle == 0) or (modifiers != Qt.ControlModifier and angle == 1.57) else (1 \
2992
                                                                                                                )
2993

    
2994
                    textItems = sorted(textItems, key=lambda text: text.loc[x_or_y]) if textItems[0].angle == 0 else ( \
2995
                        sorted(textItems, key=lambda text: text.loc[x_or_y]) if textItems[0].angle == 1.57 else ( \
2996
                            sorted(textItems, key=lambda text: text.loc[x_or_y], reverse=True) if textItems[0].angle == 4.71 else \
2997
                                sorted(textItems, key=lambda text: text.loc[x_or_y], reverse=True)))
2998

    
2999
                    if textItems[0].angle == 1.57 and modifiers == Qt.ControlModifier:
3000
                        textItems.reverse()
3001

    
3002
                    minX = sys.maxsize
3003
                    minY = sys.maxsize
3004
                    maxX = 0
3005
                    maxY = 0
3006
                    newText = ''
3007

    
3008
                    for text in textItems:
3009
                        if text.loc[0] < minX: minX = text.loc[0]
3010
                        if text.loc[1] < minY: minY = text.loc[1]
3011
                        if text.loc[0] + text.size[0] > maxX: maxX = text.loc[0] + text.size[0]
3012
                        if text.loc[1] + text.size[1] > maxY: maxY = text.loc[1] + text.size[1]
3013
                        newText = newText + text.text() + enter_or_space
3014
                        text.transfer.onRemoved.emit(text)
3015
                    newText = newText[:-1]
3016

    
3017
                    textInfo = TextInfo(newText, minX, minY, maxX - minX, maxY - minY, textItems[0].angle)
3018
                    item = QEngineeringTextItem.create_text_with(self.graphicsView.scene(), textInfo)
3019
                    if item is not None:
3020
                        item.area = textItems[0].area
3021
                        #item.setDefaultTextColor(Qt.blue)
3022
                        item.transfer.onRemoved.connect(self.itemRemoved)
3023
                # up to here
3024
            elif event.key() == Qt.Key_D:
3025
                # pop up development toolkit dialog
3026
                from DevelopmentToolkitDialog import QDevelopmentToolkitDialog
3027

    
3028
                modifiers = QApplication.keyboardModifiers()
3029
                if modifiers == Qt.ControlModifier:
3030
                    dlg = QDevelopmentToolkitDialog(self, self.graphicsView)
3031
                    dlg.show()
3032
            elif event.key() == Qt.Key_I:
3033
                # insert symbol item that is selected symbol in tree to main window if symbol already selected on main window, replace
3034
                index = self.symbolTreeWidget.currentIndex()
3035
                proxy_model = self.symbolTreeWidget.model()
3036
                items = [proxy_model.sourceModel().itemFromIndex(proxy_model.mapToSource(index))]
3037
                if items and hasattr(items[0], 'svgFilePath'):
3038
                    symData = items[0].data(self.symbolTreeWidget.TREE_DATA_ROLE)
3039
                    symName = symData.getName()
3040
                else:
3041
                    return
3042

    
3043
                symbolItems = [symbol for symbol in self.graphicsView.scene().selectedItems() if
3044
                               issubclass(type(symbol), SymbolSvgItem)]
3045
                old_symbol = None
3046
                if symbolItems and len(symbolItems) is 1:
3047
                    old_symbol = symbolItems[0]
3048
                    #scenePos = QPoint(old_symbol.origin[0], old_symbol.origin[1])
3049
                    scenePos = old_symbol.mapToScene(old_symbol.transformOriginPoint())
3050
                    old_symbol.transfer.onRemoved.emit(old_symbol)
3051
                else:
3052
                    scenePos = self.current_pos
3053

    
3054
                svg = QtImageViewer.createSymbolObject(symName)
3055
                QtImageViewer.matchSymbolToLine(self.graphicsView.scene(), svg, scenePos, angle=old_symbol.angle if old_symbol else 0.0)
3056

    
3057
                if old_symbol and svg:
3058
                    from ReplaceCommand import ReplaceCommand
3059

    
3060
                    cmd = ReplaceCommand(self.graphicsView.scene(), old_symbol, svg)
3061
                    self._scene.undo_stack.push(cmd)
3062
                    return
3063
            elif event.key() == Qt.Key_J:
3064
                # insert and connect symbol item that is selected symbol in tree to selected symbol
3065
                index = self.symbolTreeWidget.currentIndex()
3066
                proxy_model = self.symbolTreeWidget.model()
3067
                items = [proxy_model.sourceModel().itemFromIndex(proxy_model.mapToSource(index))]
3068
                if items and hasattr(items[0], 'svgFilePath'):
3069
                    symData = items[0].data(self.symbolTreeWidget.TREE_DATA_ROLE)
3070
                    symName = symData.getName()
3071
                else:
3072
                    return
3073

    
3074
                symbolItems = [symbol for symbol in self.graphicsView.scene().selectedItems() if
3075
                               issubclass(type(symbol), SymbolSvgItem)]
3076
                if len(symbolItems) is not 1:
3077
                    return
3078
                    
3079
                target_symbol = symbolItems[0]
3080
                index =  [index for index in range(len(target_symbol.conn_type)) \
3081
                            if QEngineeringLineItem.check_piping(target_symbol.conn_type[index], True)]
3082
                for connector in target_symbol.connectors:
3083
                    svg = QtImageViewer.createSymbolObject(symName)
3084
                    if len(svg.connectors) > 1: 
3085
                        if ((target_symbol.conn_type and target_symbol.connectors.index(connector) in index) or not target_symbol.conn_type) and \
3086
                                    (not connector.connectedItem or (connector.connectedItem and type(connector.connectedItem) is QEngineeringLineItem)):
3087
                            QtImageViewer.matchSymbolToLine(self.graphicsView.scene(), svg, connector.sceneBoundingRect().center())
3088
                    elif len(svg.connectors) == 1:
3089
                        if ((target_symbol.conn_type and target_symbol.connectors.index(connector) in index) or not target_symbol.conn_type) and \
3090
                                    not connector.connectedItem:
3091
                            QtImageViewer.matchSymbolToLine(self.graphicsView.scene(), svg, connector.sceneBoundingRect().center())
3092

    
3093
                if target_symbol:
3094
                    return
3095
            elif event.key() == Qt.Key_X:
3096
                pass
3097
                '''
3098
                app_doc_data = AppDocData.instance()
3099
                configs = app_doc_data.getAppConfigs('app', 'mode')
3100
                if configs and 1 == len(configs) and 'advanced' == configs[0].value:
3101
                    advanced = True
3102
                    items = self.graphicsView.scene().selectedItems()
3103
                    if items:
3104
                        item = self.symbolTreeWidget.currentItem()
3105
                        if item:
3106
                            self.symbolTreeWidget.showSymbolEditorDialog(item, 0)
3107
                '''
3108
            elif event.key() == Qt.Key_F6:
3109
                from DEXPI import scene_to_dexpi
3110

    
3111
                app_doc_data = AppDocData.instance()
3112
                scene_to_dexpi('D:\\Temp\\DEXPI.xml', app_doc_data.activeDrawing.name, self.graphicsView.scene())
3113

    
3114
            QMainWindow.keyPressEvent(self, event)
3115
        except Exception as ex:
3116
            message = f"error occurred({repr(ex)}) in {sys.exc_info()[-1].tb_frame.f_code.co_filename}:" \
3117
                      f"{sys.exc_info()[-1].tb_lineno}"
3118
            self.addMessage.emit(MessageType.Error, message)
3119

    
3120
    def recognize(self):
3121
        """recognize symbol, text and line for selected drawings"""
3122
        from datetime import datetime
3123
        from License import QLicenseDialog
3124

    
3125
        # save alarm
3126
        self.save_alarm_enable(False)
3127

    
3128
        app_doc_data = AppDocData.instance()
3129
        current_drawing, currentPid = None, None
3130

    
3131
        if self.graphicsView.hasImage():
3132
            current_drawing = app_doc_data.activeDrawing
3133
            currentPid = app_doc_data.activeDrawing.name
3134

    
3135
        # get checked drawings
3136
        drawing_top = self.treeWidgetDrawingList.topLevelItem(0)
3137
        count = drawing_top.childCount()
3138
        checked_drawings = {}
3139
        for idx in range(count):
3140
            child = drawing_top.child(idx)
3141
            if child.checkState(0) == Qt.Checked and child.data(Qt.UserRole, 0):
3142
                checked_drawings[child.data(Qt.UserRole, 0)] = child
3143
        # up to here
3144

    
3145
        # if there is no checked drawing
3146
        if current_drawing and currentPid and not checked_drawings:
3147
            for idx in range(count):
3148
                child = drawing_top.child(idx)
3149
                if child.data(Qt.UserRole, 0) is current_drawing:
3150
                    checked_drawings[child.data(Qt.UserRole, 0)] = child
3151

    
3152
        if not checked_drawings:
3153
            self.showImageSelectionMessageBox()
3154
            return
3155

    
3156
        try:
3157
            self.on_clear_log()
3158
            dlg = QRecognitionDialog(self, [drawing for drawing in checked_drawings.keys()])
3159
            dlg.exec_()
3160

    
3161
            if current_drawing and current_drawing in checked_drawings.keys() and dlg.isTreated:
3162
                self.open_image_drawing(current_drawing, force=True, ocrUnknown=dlg.ui.checkBoxOCRUnknown.isChecked())
3163

    
3164
            # save working date-time
3165
            _now = datetime.now().strftime('%Y-%m-%d %H:%M:%S')
3166
            for drawing, tree_item in checked_drawings.items():
3167
                drawing.datetime = _now
3168
                tree_item.setText(1, _now)
3169
            #app_doc_data.saveDrawings(checked_drawings.keys())
3170
            self.changeViewCheckedState(True)
3171
            # count up for recognition
3172
            QLicenseDialog.count_up()
3173
            # up to here
3174
        except Exception as ex:
3175
            message = f"error occurred({repr(ex)}) in {sys.exc_info()[-1].tb_frame.f_code.co_filename}:" \
3176
                      f"{sys.exc_info()[-1].tb_lineno}"
3177
            self.addMessage.emit(MessageType.Error, message)
3178

    
3179
        # save alarm
3180
        self.save_alarm_enable(True, True)
3181

    
3182
    '''
3183
        @brief      remove item from tree widget and then remove from scene
3184
        @date       2018.05.25
3185
        @author     Jeongwoo
3186
    '''
3187
    def itemRemoved(self, item):
3188
        try:
3189
            if type(item) is QEngineeringErrorItem:
3190
                # remove error item from inconsistency list
3191
                for row in range(self.tableWidgetInconsistency.rowCount()):
3192
                    if item is self.tableWidgetInconsistency.item(row, 0).tag:
3193
                        self.tableWidgetInconsistency.removeRow(row)
3194
                        break
3195

    
3196
                if item.scene() is not None:
3197
                    item.scene().removeItem(item)
3198
                del item
3199
            else:
3200
                remove_scene = item.scene()
3201
                self.itemTreeWidget.itemRemoved(item)
3202

    
3203
                if remove_scene:
3204
                    matches = [_item for _item in remove_scene.items() if
3205
                            hasattr(_item, 'connectors') and [connector for connector in _item.connectors if
3206
                                                                connector.connectedItem is item]]
3207
                    for match in matches:
3208
                        for connector in match.connectors:
3209
                            if connector.connectedItem is item:
3210
                                connector.connectedItem = None
3211
                                connector.highlight(False)
3212

    
3213
                # matches = [_item for _item in self.graphicsView.scene().items() if hasattr(_item, 'remove_assoc_item')]
3214
                # for _item in matches:
3215
                #    _item.remove_assoc_item(item)
3216

    
3217
                app_doc_data = AppDocData.instance()
3218
                if type(item) is QEngineeringLineNoTextItem and item in app_doc_data.tracerLineNos:
3219
                    app_doc_data.tracerLineNos.pop(app_doc_data.tracerLineNos.index(item))
3220

    
3221
                if type(item) is QEngineeringLineItem and item in app_doc_data.lines:
3222
                    app_doc_data.lines.remove(item)
3223

    
3224
                if remove_scene:
3225
                    matches = [_item for _item in remove_scene.items() if
3226
                            type(_item) is QEngineeringLineNoTextItem]
3227
                    matches.extend([lineNo for lineNo in app_doc_data.tracerLineNos if
3228
                                    type(lineNo) is QEngineeringTrimLineNoTextItem])
3229
                    for match in matches:
3230
                        if item is match.prop('From'):
3231
                            match.set_property('From', None)
3232
                        if item is match.prop('To'):
3233
                            match.set_property('To', None)
3234

    
3235
                        for run_index in reversed(range(len(match.runs))):
3236
                            run = match.runs[run_index]
3237
                            if item in run.items:
3238
                                index = run.items.index(item)
3239
                                run.items.pop(index)
3240
                                if not run.items:
3241
                                    run.explode()
3242
                                    if type(match) is QEngineeringTrimLineNoTextItem and not match.runs:
3243
                                        app_doc_data.tracerLineNos.pop(app_doc_data.tracerLineNos.index(match))
3244
                                # break
3245

    
3246
                if remove_scene:
3247
                    matches = [_item for _item in remove_scene.items() if hasattr(_item, 'owner')]
3248
                    for match in matches:
3249
                        if match.owner is item:
3250
                            match.owner = None
3251

    
3252
                    matches = [_item for _item in remove_scene.items() if hasattr(_item, 'attrs')]
3253
                    # done = False
3254
                    for match in matches:
3255
                        assocs = match.associations()
3256
                        for assoc in assocs:
3257
                            if item is assoc:
3258
                                keys = match.attrs.keys()
3259
                                for attr in keys:
3260
                                    if attr.AssocItem and str(item.uid) == str(attr.AssocItem.uid):
3261
                                        attr.AssocItem = None
3262
                                        match.attrs[attr] = ''
3263
                                        # done = True
3264
                                match.remove_assoc_item(item)
3265
                                break
3266
                        # if done: break
3267

    
3268
                if item.scene() is not None:
3269
                    #if type(item) is QEngineeringLineNoTextItem and item._labels:
3270
                    #    for _label in item._labels:
3271
                    #        item.scene().removeItem(_label)
3272
                    #    item._labels = []
3273
                    
3274
                    item.hoverLeaveEvent(None)
3275
                    if hasattr(item, 'lineNoFromToIndicator') and item.lineNoFromToIndicator:
3276
                        item.scene().removeItem(item.lineNoFromToIndicator[0])
3277
                        item.scene().removeItem(item.lineNoFromToIndicator[1])
3278
                    item.scene().removeItem(item)
3279
        except Exception as ex:
3280
            message = 'error occurred({}) in {}:{}'.format(ex, sys.exc_info()[-1].tb_frame.f_code.co_filename,
3281
                                                           sys.exc_info()[-1].tb_lineno)
3282
            self.addMessage.emit(MessageType.Error, message)
3283
        '''
3284
        finally:
3285
            if hasattr(item, '_cond'):
3286
                item._cond.wakeAll()
3287
        '''
3288

    
3289

    
3290
    def connect_attributes(self, MainWindow):
3291
        """connect attributes to symbol"""
3292
        from LineNoTracer import LineNoTracer
3293
        from ConnectAttrDialog import QConnectAttrDialog
3294

    
3295
        if not self.graphicsView.hasImage():
3296
            self.showImageSelectionMessageBox()
3297
            return
3298

    
3299
        # save alarm
3300
        self.save_alarm_enable(False)
3301

    
3302
        try:
3303
            dlg = QConnectAttrDialog(self, self.graphicsView.scene())
3304
            dlg.setWindowFlags(self.windowFlags() & ~Qt.WindowCloseButtonHint & ~Qt.WindowContextHelpButtonHint)
3305
            dlg.exec_()
3306
            if dlg.isRunned:
3307
                self.refresh_item_list()
3308

    
3309
                if dlg.validation_checked:
3310
                    self.onValidation()
3311

    
3312
                self.graphicsView.invalidateScene()
3313
        except Exception as ex:
3314
            message = 'error occurred({}) in {}:{}'.format(ex, sys.exc_info()[-1].tb_frame.f_code.co_filename,
3315
                                                           sys.exc_info()[-1].tb_lineno)
3316
            self.addMessage.emit(MessageType.Error, message)
3317
        finally:
3318
            # save alarm
3319
            self.save_alarm_enable(True)
3320

    
3321
    def postDetectLineProcess(self):
3322
        '''
3323
            @brief  check allowables among undetected items
3324
            @author euisung
3325
            @date   2018.11.15
3326
            @history    2018.11.15  euisung    no more used, moved to TextItemFactoy isLineNo()
3327
        '''
3328

    
3329
        appDocData = AppDocData.instance()
3330

    
3331
        tableNames = ["Fluid Code", "Insulation Purpose", "PnID Number", "Piping Materials Class", "Unit Number"]
3332
        tableDatas = []
3333
        for tableName in tableNames:
3334
            tableNameFormat = tableName.replace(' ', '').replace('&&', 'n')
3335
            tableDatas.append(appDocData.getCodeTable(tableNameFormat))
3336

    
3337
        items = self.graphicsView.scene().items()
3338
        for item in items:
3339
            if type(item) is not QEngineeringTextItem:
3340
                continue
3341
            text = item.text()
3342
            for tableData in tableDatas:
3343
                for data in tableData:
3344
                    if data[3] == '':
3345
                        continue
3346
                    else:
3347
                        allows = data[3].split(',')
3348
                        for allow in allows:
3349
                            text = text.replace(allow, data[1])
3350

    
3351
            lineItem = TextItemFactory.instance().createTextItem(text)
3352
            if type(lineItem) is QEngineeringLineNoTextItem:
3353
                lineItem.loc = item.loc
3354
                lineItem.size = item.size
3355
                lineItem.angle = item.angle
3356
                lineItem.area = item.area
3357
                # lineItem.addTextItemToScene(self.graphicsView.scene())
3358
                lineItem.transfer.onRemoved.connect(self.itemRemoved)
3359
                item.transfer.onRemoved.emit(item)
3360
                appDocData.lineNos.append(lineItem)
3361

    
3362
    def init_add_tree_item(self, line_no_tree_item, run_item):
3363
        """ insert symbol item and find line no as owner """
3364
        # insert
3365
        self.itemTreeWidget.addTreeItem(line_no_tree_item, run_item)
3366
        # find
3367
        self.itemTreeWidget.addTreeItem(line_no_tree_item, run_item)
3368

    
3369
    def load_drawing(self, drawing):
3370
        """ load drawing """
3371
        """ no more used """
3372
        from EngineeringRunItem import QEngineeringRunItem
3373
        from QEngineeringTrimLineNoTextItem import QEngineeringTrimLineNoTextItem
3374

    
3375
        app_doc_data = AppDocData.instance()
3376
        try:
3377
            symbols = []
3378
            lines = []
3379

    
3380
            components = app_doc_data.get_components(drawing.UID)
3381
            maxValue = len(components) * 2
3382
            self.progress.setMaximum(maxValue) if maxValue > 0 else None
3383

    
3384
            """ parsing all symbols """
3385
            for symbol in [component for component in components if int(component['SymbolType_UID']) != -1]:
3386
                item = SymbolSvgItem.from_database(symbol)
3387
                if item is not None:
3388
                    item.transfer.onRemoved.connect(self.itemRemoved)
3389
                    symbols.append(item)
3390
                    app_doc_data.symbols.append(item)
3391
                    item.addSvgItemToScene(self.graphicsView.scene())
3392
                else:
3393
                    pt = [float(symbol['X']), float(symbol['Y'])]
3394
                    size = [float(symbol['Width']), float(symbol['Height'])]
3395
                    angle = float(symbol['Rotation'])
3396
                    item = QGraphicsBoundingBoxItem(pt[0], pt[1], size[0], size[1])
3397
                    item.isSymbol = True
3398
                    item.angle = angle
3399
                    item.setPen(QPen(Qt.red, 5, Qt.SolidLine))
3400
                    self.graphicsView.scene().addItem(item)
3401
                    item.transfer.onRemoved.connect(self.itemRemoved)
3402

    
3403
                self.progress.setValue(self.progress.value() + 1)
3404

    
3405
            QApplication.processEvents()
3406

    
3407
            # parse texts
3408
            for text in [component for component in components if
3409
                         component['Name'] == 'Text' and component['SymbolType_UID'] == -1]:
3410
                item = QEngineeringTextItem.from_database(text)
3411
                if item is not None:
3412
                    item.uid = text['UID']
3413
                    item.attribute = text['Value']
3414
                    name = text['Name']
3415
                    item.transfer.onRemoved.connect(self.itemRemoved)
3416
                    item.addTextItemToScene(self.graphicsView.scene())
3417

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

    
3420
            QApplication.processEvents()
3421

    
3422
            # note
3423
            for note in [component for component in components if
3424
                         component['Name'] == 'Note' and component['SymbolType_UID'] == -1]:
3425
                item = QEngineeringTextItem.from_database(note)
3426
                if item is not None:
3427
                    item.uid = note['UID']
3428
                    attributeValue = note['Value']
3429
                    name = note['Name']
3430
                    item.transfer.onRemoved.connect(self.itemRemoved)
3431
                    item.addTextItemToScene(self.graphicsView.scene())
3432

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

    
3435
            QApplication.processEvents()
3436

    
3437
            for line in [component for component in components if
3438
                         component['Name'] == 'Line' and component['SymbolType_UID'] == -1]:
3439
                item = QEngineeringLineItem.from_database(line)
3440
                if item:
3441
                    item.transfer.onRemoved.connect(self.itemRemoved)
3442
                    self.graphicsView.scene().addItem(item)
3443
                    lines.append(item)
3444

    
3445
                self.progress.setValue(self.progress.value() + 1)
3446

    
3447
            QApplication.processEvents()
3448

    
3449
            for unknown in [component for component in components if
3450
                            component['Name'] == 'Unknown' and component['SymbolType_UID'] == -1]:
3451
                item = QEngineeringUnknownItem.from_database(unknown)
3452
                item.transfer.onRemoved.connect(self.itemRemoved)
3453
                if item is not None:
3454
                    item.transfer.onRemoved.connect(self.itemRemoved)
3455
                    self.graphicsView.scene().addItem(item)
3456

    
3457
                self.progress.setValue(self.progress.value() + 1)
3458

    
3459
            QApplication.processEvents()
3460

    
3461
            for component in [component for component in components if
3462
                              component['Name'] == 'Line NO' and component['SymbolType_UID'] == -1]:
3463
                line_no = QEngineeringLineNoTextItem.from_database(component)
3464
                if type(line_no) is QEngineeringLineNoTextItem:
3465
                    line_no.transfer.onRemoved.connect(self.itemRemoved)
3466
                    self.addTextItemToScene(line_no)
3467
                    line_no_tree_item = self.itemTreeWidget.addTreeItem(self.itemTreeWidget.root, line_no)
3468

    
3469
                    runs = app_doc_data.get_pipe_runs(str(line_no.uid))
3470
                    if not runs: continue
3471
                    for run in runs:
3472
                        line_run = QEngineeringRunItem()
3473
                        run_items = app_doc_data.get_pipe_run_items(run['UID'])
3474
                        for record in run_items:
3475
                            uid = record['Components_UID']
3476
                            run_item = self.graphicsView.findItemByUid(uid)
3477
                            if run_item is not None:
3478
                                run_item._owner = line_no
3479
                                line_run.items.append(run_item)
3480
                        line_run.owner = line_no
3481
                        line_no.runs.append(line_run)
3482

    
3483
                        for run_item in line_run.items:
3484
                            if issubclass(type(run_item), SymbolSvgItem):
3485
                                self.init_add_tree_item(line_no_tree_item, run_item)
3486

    
3487
                self.progress.setValue(self.progress.value() + 1)
3488
            QApplication.processEvents()
3489

    
3490
            for component in [component for component in components if
3491
                              component['Name'] == 'Trim Line NO' and component['SymbolType_UID'] == -1]:
3492
                line_no = QEngineeringTrimLineNoTextItem()
3493
                line_no.uid = uuid.UUID(component['UID'])
3494

    
3495
                runs = app_doc_data.get_pipe_runs(str(line_no.uid))
3496
                if not runs: continue
3497

    
3498
                line_no_tree_item = self.itemTreeWidget.addTreeItem(self.itemTreeWidget.root, line_no)
3499

    
3500
                for run in runs:
3501
                    line_run = QEngineeringRunItem()
3502
                    run_items = app_doc_data.get_pipe_run_items(run['UID'])
3503
                    for record in run_items:
3504
                        uid = record['Components_UID']
3505
                        run_item = self.graphicsView.findItemByUid(uid)
3506
                        if run_item is not None:
3507
                            run_item.owner = line_no
3508
                            line_run.items.append(run_item)
3509
                    line_run.owner = line_no
3510
                    line_no.runs.append(line_run)
3511

    
3512
                    for run_item in line_run.items:
3513
                        if issubclass(type(run_item), SymbolSvgItem):
3514
                            self.init_add_tree_item(line_no_tree_item, run_item)
3515

    
3516
                app_doc_data.tracerLineNos.append(line_no)
3517

    
3518
                self.progress.setValue(self.progress.value() + 1)
3519

    
3520
            for component in [component for component in components if
3521
                              component['Name'] == 'VendorPackage' and component['SymbolType_UID'] == -1]:
3522
                item = QEngineeringVendorItem.from_database(component)
3523
                if item is not None:
3524
                    item.transfer.onRemoved.connect(self.itemRemoved)
3525
                    self.graphicsView.scene().addItem(item)
3526

    
3527
            # connect flow item to line
3528
            for line in lines:
3529
                line.update_arrow()
3530
                app_doc_data.lines.append(line)
3531
            # for flowMark in [item for item in symbols if type(item) is QEngineeringFlowMarkItem]:
3532
            #    for line in lines:
3533
            #        if flowMark.owner is line:
3534
            #            line._flowMark.append(flowMark)
3535
            #            flowMark.setParentItem(line)
3536
            # up to here
3537

    
3538
            """ update scene """
3539
            self.graphicsView.scene().update(self.graphicsView.sceneRect())
3540
            for item in self.graphicsView.scene().items():
3541
                up_progress = False
3542
                # binding items
3543
                if hasattr(item, 'owner'):
3544
                    item.owner
3545
                    up_progress = True
3546
                if hasattr(item, 'connectors'):
3547
                    for connector in item.connectors:
3548
                        connector.connectedItem
3549
                    up_progress = True
3550

    
3551
                if up_progress:
3552
                    self.progress.setValue(self.progress.value() + 1)
3553
            
3554
            for item in self.graphicsView.scene().items():
3555
                item.setVisible(True)
3556

    
3557
        except Exception as ex:
3558
            message = 'error occurred({}) in {}:{}'.format(ex, sys.exc_info()[-1].tb_frame.f_code.co_filename,
3559
                                                           sys.exc_info()[-1].tb_lineno)
3560
            self.addMessage.emit(MessageType.Error, message)
3561
        finally:
3562
            app_doc_data.clearTempDBData()
3563
            self.itemTreeWidget.update_item_count()
3564
            self.itemTreeWidget.expandAll()
3565
            # self.graphicsView.scene().blockSignals(False)
3566

    
3567
    '''
3568
        @brief      load recognition result
3569
        @author     humkyung
3570
        @date       2018.04.??
3571
        @history    humkyung 2018.01.12 parse originalpoint and connectionpoint
3572
                    Jeongwoo 2018.04.17 add QGraphicItem with Rotated text
3573
                    Jeongwoo 2018.04.23 Change to Draw texts on QEngineeringTextItem
3574
                    humkyung 2018.04.23 connect item remove slot to result tree
3575
                    Jeongwoo 2018.04.25 Add if state with QEngineeringNoteItem
3576
                    Jeongwoo 2018.04.26 Change method to create TextItem object with TextItemFactory
3577
                    Jeongwoo 2018.05.03 Change method to draw Svg Item on Scene (svg.addSvgItemToScene)
3578
                    Jeongwoo 2018.05.29 Change method name / Change method to add item / Add Line item
3579
                    Jeongwoo 2018.05.30 Add parameters on SymbolSvgItem.__init__() (parentSymbol, childSymbol) / Change method name / Change XML NODE NAMES
3580
                    Jeongwoo 2018.06.12 Add LineNoTextItem from LINE_NO
3581
                    Jeongwoo 2018.06.14 Add UnknownItem from UNKNOWN
3582
                    Jeongwoo 2018.06.18 Update Scene after all item added
3583
                                        Add connect on unknown item
3584
                                        Add [transfer] for using pyqtSignal
3585
                    kyouho  2018.07.12  Add line property logic
3586
                    humkyung 2018.08.22 show progress while loading xml file
3587
                    2018.11.22      euisung     fix note road
3588
    '''
3589
    def load_recognition_result_from_xml(self, drawing):
3590
        # Yield successive n-sized
3591
        # chunks from l.
3592
        def divide_chunks(l, n):
3593
            # looping till length l
3594
            for i in range(0, len(l), n):
3595
                yield l[i:i + n]
3596

    
3597
        def update_items(items):
3598
            for item in items:
3599
                # binding items
3600
                item.owner
3601
                for connector in item.connectors:
3602
                    connector.connectedItem
3603

    
3604
            return items
3605

    
3606
        import concurrent.futures as futures
3607
        from xml.etree.ElementTree import Element, SubElement, dump, ElementTree, parse
3608
        from App import App
3609
        from EngineeringRunItem import QEngineeringRunItem
3610
        from QEngineeringTrimLineNoTextItem import QEngineeringTrimLineNoTextItem
3611
        from EngineeringGraphicsLineItem import QEngineeringGraphicsLineItem
3612

    
3613
        app_doc_data = AppDocData.instance()
3614

    
3615
        try:
3616
            file_name = os.path.splitext(os.path.basename(drawing.file_path))[0]
3617
            path = os.path.join(app_doc_data.getCurrentProject().getTempPath(), file_name + '.xml')
3618
            self.graphicsView.scene().blockSignals(True)
3619

    
3620
            symbols = []
3621
            lines = []
3622

    
3623
            xml = parse(path)
3624
            root = xml.getroot()
3625

    
3626
            maxValue = 0
3627
            maxValue = maxValue + len(list(root.iter('SYMBOL'))) - \
3628
                       len(list(root.iterfind('LINENOS/LINE_NO/RUN/SYMBOL'))) - \
3629
                       len(list(root.iterfind('TRIMLINENOS/TRIM_LINE_NO/RUN/SYMBOL')))
3630
            maxValue = maxValue + len(list(root.iterfind('TEXTINFOS/ATTRIBUTE')))
3631
            maxValue = maxValue + len(list(root.iterfind('NOTES/ATTRIBUTE')))
3632
            maxValue = maxValue + len(list(root.iter('LINE_NO')))
3633
            maxValue = maxValue + len(list(root.iter('LINE'))) - \
3634
                       len(list(root.iterfind('LINENOS/LINE_NO/RUN/LINE'))) - \
3635
                       len(list(root.iterfind('TRIMLINENOS/TRIM_LINE_NO/RUN/LINE')))
3636
            maxValue = maxValue + len(list(root.iter('GRAPHICS_LINE')))
3637
            maxValue = maxValue + len(list(root.iter('UNKNOWN')))
3638
            # maxValue = maxValue + len(list(root.iter('SIZETEXT')))
3639
            maxValue = maxValue + len(list(root.iter('TRIM_LINE_NO')))
3640
            maxValue *= 2
3641
            self.progress.setMaximum(maxValue) if maxValue > 0 else None
3642

    
3643
            """ parsing all symbols """
3644
            """
3645
            with futures.ThreadPoolExecutor(max_workers=App.THREAD_MAX_WORKER) as pool:
3646
                future_symbol = {pool.submit(SymbolSvgItem.fromXml, symbol): symbol for symbol in root.find('SYMBOLS').iter('SYMBOL')}
3647

3648
                for future in futures.as_completed(future_symbol):
3649
                    try:
3650
                        item = future.result()
3651
                        if item:
3652
                            if item is not None:
3653
                                item.transfer.onRemoved.connect(self.itemRemoved)
3654
                                symbols.append(item)
3655
                                docData.symbols.append(item)
3656
                                self.addSvgItemToScene(item)
3657
                            else:
3658
                                pt = [float(x) for x in symbol.find('LOCATION').text.split(',')]
3659
                                size = [float(x) for x in symbol.find('SIZE').text.split(',')]
3660
                                angle = float(symbol.find('ANGLE').text)
3661
                                item = QGraphicsBoundingBoxItem(pt[0], pt[1], size[0], size[1])
3662
                                item.isSymbol = True
3663
                                item.angle = angle
3664
                                item.setPen(QPen(Qt.red, 5, Qt.SolidLine))
3665
                                self.graphicsView.scene().addItem(item)
3666
                                item.transfer.onRemoved.connect(self.itemRemoved)
3667
                    except Exception as ex:
3668
                        message = 'error occurred({}) in {}:{}'.format(repr(ex), sys.exc_info()[-1].tb_frame.f_code.co_filename,
3669
                                                                       sys.exc_info()[-1].tb_lineno)
3670

3671
            """
3672
            for symbol in root.find('SYMBOLS').iter('SYMBOL'):
3673
                item = SymbolSvgItem.fromXml(symbol)
3674
                if item is not None:
3675
                    item.transfer.onRemoved.connect(self.itemRemoved)
3676
                    symbols.append(item)
3677
                    #app_doc_data.symbols.append(item)
3678
                    item.addSvgItemToScene(self.graphicsView.scene())
3679
                else:
3680
                    pt = [float(x) for x in symbol.find('LOCATION').text.split(',')]
3681
                    size = [float(x) for x in symbol.find('SIZE').text.split(',')]
3682
                    angle = float(symbol.find('ANGLE').text)
3683
                    item = QGraphicsBoundingBoxItem(pt[0], pt[1], size[0], size[1])
3684
                    item.isSymbol = True
3685
                    item.angle = angle
3686
                    item.setPen(QPen(Qt.red, 5, Qt.SolidLine))
3687
                    self.graphicsView.scene().addItem(item)
3688
                    item.transfer.onRemoved.connect(self.itemRemoved)
3689

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

    
3692
            QApplication.processEvents()
3693

    
3694
            # parse texts
3695
            for text in root.find('TEXTINFOS').iter('ATTRIBUTE'):
3696
                item = QEngineeringTextItem.fromXml(text)
3697
                if item is not None:
3698
                    uid = text.find('UID')
3699
                    attributeValue = text.find('ATTRIBUTEVALUE')
3700
                    name = text.find('NAME').text
3701
                    item.transfer.onRemoved.connect(self.itemRemoved)
3702
                    item.addTextItemToScene(self.graphicsView.scene())
3703
                    # docData.texts.append(item)
3704

    
3705
                    if name == 'TEXT':
3706
                        if uid is not None and attributeValue is not None:
3707
                            item.uid = uid.text
3708
                            item.attribute = attributeValue.text
3709

    
3710
                self.progress.setValue(self.progress.value() + 1)
3711

    
3712
            QApplication.processEvents()
3713

    
3714
            # note
3715
            for text in root.find('NOTES').iter('ATTRIBUTE'):
3716
                item = QEngineeringTextItem.fromXml(text)
3717
                if item is not None:
3718
                    uid = text.find('UID')
3719
                    attributeValue = text.find('ATTRIBUTEVALUE')
3720
                    name = text.find('NAME').text
3721
                    item.transfer.onRemoved.connect(self.itemRemoved)
3722
                    item.addTextItemToScene(self.graphicsView.scene())
3723

    
3724
                    if name == 'NOTE':
3725
                        if uid is not None:
3726
                            item.uid = uid.text
3727

    
3728
                self.progress.setValue(self.progress.value() + 1)
3729

    
3730
            QApplication.processEvents()
3731

    
3732
            for line in root.find('LINEINFOS').iter('LINE'):
3733
                item = QEngineeringLineItem.fromXml(line)
3734
                if item:
3735
                    item.transfer.onRemoved.connect(self.itemRemoved)
3736
                    self.graphicsView.scene().addItem(item)
3737
                    lines.append(item)
3738

    
3739
                self.progress.setValue(self.progress.value() + 1)
3740

    
3741
            for line in root.find('LINEINFOS').iter('GRAPHICS_LINE'):
3742
                item = QEngineeringGraphicsLineItem.fromXml(line)
3743
                if item:
3744
                    item.transfer.onRemoved.connect(self.itemRemoved)
3745
                    self.graphicsView.scene().addItem(item)
3746

    
3747
                self.progress.setValue(self.progress.value() + 1)
3748

    
3749
            QApplication.processEvents()
3750

    
3751
            for unknown in root.iter('UNKNOWN'):
3752
                item = QEngineeringUnknownItem.fromXml(unknown)
3753
                if item is not None:
3754
                    item.transfer.onRemoved.connect(self.itemRemoved)
3755
                    self.graphicsView.scene().addItem(item)
3756

    
3757
                self.progress.setValue(self.progress.value() + 1)
3758

    
3759
            QApplication.processEvents()
3760

    
3761
            # """ add tree widget """
3762
            # for item in symbols:
3763
            #    docData.symbols.append(item)
3764
            #    self.addSvgItemToScene(item)
3765
            #    self.itemTreeWidget.addTreeItem(self.itemTreeWidget.root, item)
3766

    
3767
            for line_no_node in root.find('LINENOS').iter('LINE_NO'):
3768
                line_no = QEngineeringLineNoTextItem.fromXml(line_no_node)
3769
                if line_no is None: continue
3770
                line_no.transfer.onRemoved.connect(self.itemRemoved)
3771
                line_no.addTextItemToScene(self.graphicsView.scene())
3772
                line_no_tree_item = self.itemTreeWidget.addTreeItem(self.itemTreeWidget.root, line_no)
3773
                if type(line_no) is not QEngineeringLineNoTextItem: continue
3774

    
3775
                runs_node = line_no_node.findall('RUN')
3776
                if runs_node is None: continue
3777

    
3778
                for run_node in runs_node:
3779
                    line_run = QEngineeringRunItem()
3780
                    for child_node in run_node:
3781
                        uidElement = child_node.find('UID')
3782
                        if uidElement is not None:
3783
                            uid = uidElement.text
3784
                            run_item = self.graphicsView.findItemByUid(uid)
3785
                            if run_item is not None:
3786
                                run_item._owner = line_no
3787
                                line_run.items.append(run_item)
3788
                    line_run.owner = line_no
3789
                    line_no.runs.append(line_run)
3790

    
3791
                    for run_item in line_run.items:
3792
                        if issubclass(type(run_item), SymbolSvgItem):
3793
                            self.init_add_tree_item(line_no_tree_item, run_item)
3794

    
3795
                # docData.tracerLineNos.append(line_no)
3796

    
3797
                self.progress.setValue(self.progress.value() + 1)
3798
            QApplication.processEvents()
3799

    
3800
            for trimLineNo in root.iter('TRIM_LINE_NO'):
3801
                line_no = QEngineeringTrimLineNoTextItem()
3802
                line_no.uid = uuid.UUID(trimLineNo.find('UID').text)
3803

    
3804
                runs_node = trimLineNo.findall('RUN')
3805
                if runs_node is None: continue
3806
                line_no_tree_item = self.itemTreeWidget.addTreeItem(self.itemTreeWidget.root, line_no)
3807

    
3808
                for run in runs_node:
3809
                    line_run = QEngineeringRunItem()
3810
                    for child in run:
3811
                        uidElement = child.find('UID')
3812
                        if uidElement is not None:
3813
                            uid = uidElement.text
3814
                            run_item = self.graphicsView.findItemByUid(uid)
3815
                            if run_item is not None:
3816
                                run_item.owner = line_no
3817
                                line_run.items.append(run_item)
3818
                    line_run.owner = line_no
3819
                    line_no.runs.append(line_run)
3820

    
3821
                    for run_item in line_run.items:
3822
                        if issubclass(type(run_item), SymbolSvgItem):
3823
                            self.init_add_tree_item(line_no_tree_item, run_item)
3824

    
3825
                app_doc_data.tracerLineNos.append(line_no)
3826

    
3827
                self.progress.setValue(self.progress.value() + 1)
3828
            QApplication.processEvents()
3829

    
3830
            if root.find('VENDORS') is not None:
3831
                for vendor in root.find('VENDORS').iter('VENDOR'):
3832
                    item = QEngineeringVendorItem.fromXml(vendor)
3833
                    item.transfer.onRemoved.connect(self.itemRemoved)
3834
                    self.graphicsView.scene().addItem(item)
3835

    
3836
            # connect flow item to line
3837
            for line in lines:
3838
                line.update_arrow()
3839
                app_doc_data.lines.append(line)
3840
            # for flowMark in [item for item in symbols if type(item) is QEngineeringFlowMarkItem]:
3841
            #    for line in lines:
3842
            #        if flowMark.owner is line:
3843
            #            line._flowMark.append(flowMark)
3844
            #            flowMark.setParentItem(line)
3845
            # up to here
3846

    
3847
            """
3848
            group_box = QGroupBox("Contact Details")
3849
            number_label = QLabel("Telephone number");
3850
            number_edit = QTextEdit('hello\nthis is ....')
3851
            layout = QFormLayout()
3852
            layout.addRow(number_label, number_edit)
3853
            group_box.setLayout(layout)
3854

3855
            proxy =  ㅐ()
3856
            proxy.setWidget(group_box)
3857
            self.graphicsView.scene().addItem(proxy)  # (group_box, QGraphicsItem.ItemIgnoresTransformations)
3858
            """
3859

    
3860
            """ update scene """
3861
            _items = [_item for _item in self.graphicsView.scene().items() if hasattr(_item, 'owner') or hasattr(_item, 'connectors')]
3862
            if _items:
3863
                items = divide_chunks(_items, App.THREAD_MAX_WORKER if len(_items) > App.THREAD_MAX_WORKER else len(_items))
3864
                with futures.ThreadPoolExecutor(max_workers=App.THREAD_MAX_WORKER) as pool:
3865
                    future_items = {pool.submit(update_items, _items): _items for _items in items}
3866
                    for future in futures.as_completed(future_items):
3867
                        _items = future.result()
3868
                        self.progress.setValue(self.progress.value() + len(_items))
3869

    
3870
            """
3871
            for item in [_item for _item in self.graphicsView.scene().items() if hasattr(_item, 'owner') or hasattr(_item, 'connectors')]:
3872
                up_progress = False
3873
                # binding items
3874
                item.owner
3875
                for connector in item.connectors:
3876
                    connector.connectedItem
3877

3878
                self.progress.setValue(self.progress.value() + 1)
3879
            """
3880

    
3881
            for item in self.graphicsView.scene().items():
3882
                item.setVisible(True)
3883

    
3884
            self.graphicsView.scene().update(self.graphicsView.sceneRect())
3885
        except Exception as ex:
3886
            message = 'error occurred({}) in {}:{}'.format(ex, sys.exc_info()[-1].tb_frame.f_code.co_filename,
3887
                                                           sys.exc_info()[-1].tb_lineno)
3888
            self.addMessage.emit(MessageType.Error, message)
3889
        finally:
3890
            self.itemTreeWidget.update_item_count()
3891
            self.itemTreeWidget.expandAll()
3892
            self.graphicsView.scene().blockSignals(False)
3893

    
3894
    '''
3895
        @brief      Remove added item on same place and Add GraphicsItem
3896
        @author     Jeongwoo
3897
        @date       2018.05.29
3898
        @history    2018.06.18  Jeongwoo    Set Z-index
3899
    '''
3900
    def addLineItemToScene(self, lineItem):
3901
        self.graphicsView.scene().addItem(lineItem)
3902

    
3903
    '''
3904
        @brief      generate output xml file
3905
        @author     humkyung
3906
        @date       2018.04.23
3907
        @history    2018.05.02  Jeongwoo    Show MessageBox when imageviewer doesn't have image
3908
    '''
3909
    def generateOutput(self):
3910
        import XmlGenerator as xg
3911

    
3912
        if not self.graphicsView.hasImage():
3913
            self.showImageSelectionMessageBox()
3914
            return
3915

    
3916
        try:
3917
            appDocData = AppDocData.instance()
3918

    
3919
            # collect items
3920
            appDocData.lines.clear()
3921
            appDocData.lines = [item for item in self.graphicsView.scene().items() if
3922
                                type(item) is QEngineeringLineItem and item.owner is None]
3923

    
3924
            appDocData.symbols.clear()
3925
            appDocData.symbols = [item for item in self.graphicsView.scene().items() if
3926
                                  issubclass(type(item), SymbolSvgItem) and item.owner is None]
3927

    
3928
            appDocData.equipments.clear()
3929
            for item in self.graphicsView.scene().items():
3930
                if type(item) is QEngineeringEquipmentItem:
3931
                    appDocData.equipments.append(item)
3932

    
3933
            appDocData.texts.clear()
3934
            appDocData.texts = [item for item in self.graphicsView.scene().items() if
3935
                                issubclass(type(item), QEngineeringTextItem) and type(
3936
                                    item) is not QEngineeringLineNoTextItem]
3937
            # up to here
3938

    
3939
            appDocData.imgOutput = np.ones((appDocData.activeDrawing.height, appDocData.activeDrawing.width),
3940
                                           np.uint8) * 255
3941
            xg.writeOutputXml(appDocData.imgName, appDocData.activeDrawing.width,
3942
                              appDocData.activeDrawing.height)  # TODO: check
3943
            project = appDocData.getCurrentProject()
3944
            cv2.imwrite(os.path.join(project.getTempPath(), 'OUTPUT.png'), appDocData.imgOutput)
3945
        except Exception as ex:
3946
            message = 'error occurred({}) in {}:{}'.format(ex, sys.exc_info()[-1].tb_frame.f_code.co_filename,
3947
                                                           sys.exc_info()[-1].tb_lineno)
3948
            self.addMessage.emit(MessageType.Error, message)
3949

    
3950
    '''
3951
        @brief      Check Number
3952
        @author     kyouho
3953
        @date       2018.08.20
3954
    '''
3955
    def isNumber(self, num):
3956
        p = re.compile('(^[0-9]+$)')
3957
        result = p.match(num)
3958

    
3959
        if result:
3960
            return True
3961
        else:
3962
            return False
3963

    
3964
    '''
3965
        @brief      find overlap Connector
3966
        @author     kyouho
3967
        @date       2018.08.28
3968
    '''
3969
    def findOverlapConnector(self, connectorItem):
3970
        from shapely.geometry import Point
3971
        from EngineeringConnectorItem import QEngineeringConnectorItem
3972
        itemList = []
3973

    
3974
        x = connectorItem.center()[0]
3975
        y = connectorItem.center()[1]
3976

    
3977
        connectors = [item for item in self.graphicsView.scene().items() if
3978
                      type(item) is QEngineeringConnectorItem and item != connectorItem]
3979
        for connector in connectors:
3980
            if Point(x, y).distance(Point(connector.center()[0], connector.center()[1])) < 5:
3981
                itemList.append(connector.parent)
3982

    
3983
        return itemList
3984

    
3985
    def make_diff_image(self):
3986
        """ make diff image """
3987
        # test
3988

    
3989
        from RecognitionDialog import Worker
3990
        from symbol import Symbol
3991
        import math
3992
        from PIL import Image
3993

    
3994
        app_doc_data = AppDocData.instance()
3995
        img = app_doc_data.imgSrc.copy()
3996

    
3997
        # check break
3998
        symbols = [item for item in self.graphicsView.scene().items() if issubclass(type(item), SymbolSvgItem)]
3999

    
4000
        for symbol in symbols:
4001
            rect = symbol.sceneBoundingRect()
4002
            sName = symbol.name
4003
            sType = symbol.type
4004
            sp = (rect.x(), rect.y())
4005
            w, h = rect.width(), rect.height()
4006
            rotatedAngle = round(math.degrees(symbol.angle))
4007
            detectFlip = symbol.flip
4008

    
4009
            dummySym = Symbol(sName, sType, sp, w, h, 0, 0, 0, rotatedAngle,
4010
                                   1, 0, 1, 0,
4011
                                   ','.join(str(x) for x in [0, 0]),
4012
                                   '/'.join('{},{},{},{}'.format(param[0], param[1], param[2], param[3]) for param in
4013
                                            []),
4014
                                   'dummy', 'dummy', 0, detectFlip=detectFlip,
4015
                                   hasInstrumentLabel=0, text_area='')
4016

    
4017
            Worker.remove_detected_symbol_image(dummySym, img, lock=False)
4018

    
4019
        Image.fromarray(img).show()
4020

    
4021
    #def paintEvent(self, event):
4022
    #    self.refresh_rate += 1
4023
    #    if self.refresh_rate == 3:
4024
    #        super(self.__class__, self).paintEvent(event)
4025
    #        self.refresh_rate = 0
4026

    
4027
if __name__ == '__main__':
4028
    import locale
4029
    from PyQt5.QtCore import QTranslator
4030
    from License import QLicenseDialog
4031
    from ProjectDialog import Ui_Dialog
4032
    from App import App
4033

    
4034
    app = App(sys.argv)
4035
    try:
4036
        if True == QLicenseDialog.check_license_key():
4037
            dlg = Ui_Dialog()
4038
            selectedProject = dlg.showDialog()
4039
            if selectedProject is not None:
4040
                AppDocData.instance().setCurrentProject(selectedProject)
4041
                app._mainWnd = MainWindow.instance()
4042
                app._mainWnd.show()
4043
                sys.exit(app.exec_())
4044
    except Exception as ex:
4045
        print('error occurred({}) in {}:{}'.format(ex, sys.exc_info()[-1].tb_frame.f_code.co_filename,
4046
                                                   sys.exc_info()[-1].tb_lineno))
4047
    finally:
4048
        pass
클립보드 이미지 추가 (최대 크기: 500 MB)