프로젝트

일반

사용자정보

통계
| 개정판:

hytos / DTI_PID / DTI_PID / MainWindow.py @ 992406b9

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

    
240
        self.delimiter = '"'
241

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

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

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

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

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

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

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

    
296
        # memo tab
297
        self.on_memo_refresh_clicked()
298

    
299
        self.read_settings()
300

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

    
305
        from App import App
306

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

    
315
        return title
316

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

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

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

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

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

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

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

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

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

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

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

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

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

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

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

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

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

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

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

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

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

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

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

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

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

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

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

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

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

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

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

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

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

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

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

    
542
        if not self.graphicsView.hasImage():
543
            self.showImageSelectionMessageBox()
544
            return
545
        
546
        app_doc_data = AppDocData.instance()
547
        
548
        '''
549
        self.itemTreeWidget.setCurrentPID(app_doc_data.activeDrawing.name)
550

551
        """update item tree widget"""
552
        line_no_items = [item for item in self.graphicsView.scene().items()
553
                            if type(item) is QEngineeringLineNoTextItem]
554
        for line_no in line_no_items:
555
            if (hasattr(line_no, 'treeItem')):
556
                line_no.treeItem = None
557

558
            line_no_tree_item = self.itemTreeWidget.addTreeItem(self.itemTreeWidget.root, line_no)
559
            for run in line_no.runs:
560
                for run_item in run.items:
561
                    if issubclass(type(run_item), SymbolSvgItem):
562
                        self.init_add_tree_item(line_no_tree_item, run_item)
563

564
        line_no_items = [item for item in self.graphicsView.scene().items()
565
                            if type(item) is QEngineeringTrimLineNoTextItem]
566
        for line_no in line_no_items:
567
            line_no_tree_item = self.itemTreeWidget.addTreeItem(self.itemTreeWidget.root, line_no)
568
            for run in line_no.runs:
569
                for run_item in run.items:
570
                    if issubclass(type(run_item), SymbolSvgItem):
571
                        self.init_add_tree_item(line_no_tree_item, run_item)
572

573
        for trim_line_no in app_doc_data.tracerLineNos:
574
            line_no_tree_item = self.itemTreeWidget.addTreeItem(self.itemTreeWidget.root, trim_line_no)
575
            for run in trim_line_no.runs:
576
                for run_item in run.items:
577
                    if issubclass(type(run_item), SymbolSvgItem):
578
                        self.init_add_tree_item(line_no_tree_item, run_item)
579

580
        self.itemTreeWidget.update_item_count()
581
        self.itemTreeWidget.expandAll()
582
        """up to here"""
583
        '''
584

    
585
        self.itemTreeWidget.InitLineNoItems()
586

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

    
605

    
606
    def load_drawing_list(self, reverse=False):
607
        """load p&id drawing list"""
608
        from Drawing import Drawing
609

    
610
        try:
611
            app_doc_data = AppDocData.instance()
612
            drawings = app_doc_data.getDrawings()
613
            new_drawings = []
614

    
615
            self.treeWidgetDrawingList.clear()
616
            self.treeWidgetDrawingList.root = QTreeWidgetItem(self.treeWidgetDrawingList,
617
                                                              [self.tr('P&ID Drawings'), ''])
618
            self.treeWidgetDrawingList.root.setFlags(
619
                self.treeWidgetDrawingList.root.flags() | Qt.ItemIsTristate | Qt.ItemIsUserCheckable)
620
            self.treeWidgetDrawingList.root.setCheckState(0, Qt.Unchecked)
621
            files = app_doc_data.getDrawingFileList()
622

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

    
635
                item = QTreeWidgetItem(self.treeWidgetDrawingList.root, [file, drawing.datetime])
636
                item.setIcon(0, QIcon(':newPrefix/image.png'))
637
                item.setFlags(item.flags() | Qt.ItemIsUserCheckable)
638
                item.setCheckState(0, Qt.Unchecked)
639
                item.setData(Qt.UserRole, 0, drawing)
640

    
641
                count += 1
642
                # self.progress_bar.setValue(count)
643
                # QApplication.processEvents()
644

    
645
            self.treeWidgetDrawingList.root.setText(0, self.tr('P&ID Drawings') +
646
                                                    f"({self.treeWidgetDrawingList.root.childCount()})")
647
            self.treeWidgetDrawingList.expandItem(self.treeWidgetDrawingList.root)
648
            #self.treeWidgetDrawingList.root.sortChildren(0, Qt.AscendingOrder)
649
            self.treeWidgetDrawingList.resizeColumnToContents(0)
650

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

    
659
    def open_selected_drawing(self, item, column):
660
        """open selected p&id drawing"""
661

    
662
        drawing = item.data(Qt.UserRole, 0)
663
        if drawing:
664
            # uncheck all drawing tree item
665
            drawing_top = self.treeWidgetDrawingList.topLevelItem(0)
666
            count = drawing_top.childCount()
667
            for idx in range(count):
668
                child = drawing_top.child(idx)
669
                child.setCheckState(0, Qt.Unchecked)
670
            # up to here
671

    
672
            drawing.image = None
673
            self.open_image_drawing(drawing)
674
            item.setCheckState(0, Qt.Checked)
675

    
676
    def show_detect_symbol_dialog(self):
677
        from DetectSymbolDialog import QDetectSymbolDialog
678

    
679
        dlg = QDetectSymbolDialog(self)
680
        dlg.exec_()
681
        
682
        self.symbolTreeWidget.initSymbolTreeView()
683

    
684
    '''
685
        @brief      OCR Editor
686
        @author     euisung
687
        @date       2018.10.05
688
        @history    2018.10.16 euisung      no more used, Integrated with oCRTrainingClicked
689
    '''
690
    def oCRTrainingEdidorClicked(self):
691
        from TrainingEditorDialog import QTrainingEditorDialog
692

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

    
701
        return
702

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

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

    
728
    def findReplaceTextClicked(self):
729
        """pop up find and replace dialog"""
730
        if not self.graphicsView.hasImage():
731
            self.showImageSelectionMessageBox()
732
            return
733

    
734
        from TextItemEditDialog import QTextItemEditDialog
735

    
736
        dlgTextItemEdit = QTextItemEditDialog(self)
737
        dlgTextItemEdit.show()
738
        dlgTextItemEdit.exec_()
739

    
740
    def on_validation_global_clicked(self):
741
        """ global validation dialog """
742
        from ValidationGlobalDialog import QValidationGlobalDialog
743

    
744
        dlg = QValidationGlobalDialog(self)
745
        dlg.show()
746
        dlg.exec_()
747

    
748
    def replaceInsertSymbolClicked(self):
749
        """pop up replace and insert dialog"""
750
        if not self.graphicsView.hasImage():
751
            self.showImageSelectionMessageBox()
752
            return
753

    
754
        from ReplaceSymbolDialog import QReplaceSymbolDialog
755

    
756
        dlg = QReplaceSymbolDialog(self)
757
        dlg.show()
758
        dlg.exec_()
759

    
760
    def on_ocr_unknown_items(self):
761
        """ try to ocr for unknown items """
762
        from OcrResultDialog import QOcrResultDialog
763

    
764
        if not self.graphicsView.hasImage():
765
            self.showImageSelectionMessageBox()
766
            return
767

    
768
        app_doc_data = AppDocData.instance()
769
        configs = app_doc_data.getConfigs('Text Size', 'Max Text Size')
770
        maxSize = int(configs[0].value) if 1 == len(configs) else 100
771
        configs = app_doc_data.getConfigs('Text Size', 'Min Text Size')
772
        minSize = int(configs[0].value) if 1 == len(configs) else 15
773

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

    
776
        for unknown in unknowns:
777
            rect = unknown.sceneBoundingRect()
778
            if rect.width() < minSize or rect.height() < minSize or rect.width() > maxSize or rect.height() > maxSize:
779
                continue
780
            if self.onRecognizeText(round(rect.left()), round(rect.top()), round(rect.width()), round(rect.height()), show=False):
781
                unknown.transfer.onRemoved.emit(unknown)
782

    
783
    def on_connect_line_to_symbol(self):
784
        if not self.graphicsView.hasImage():
785
            self.showImageSelectionMessageBox()
786
            return
787
        
788
        items = [item for item in self.graphicsView.scene().items() if issubclass(type(item), QEngineeringAbstractItem)]
789
        for item in items:
790
            item.setVisible(False)
791
        QApplication.processEvents()
792
        
793
        app_doc_data = AppDocData.instance()
794
        configs = app_doc_data.getConfigs('Line Detector', 'Length to connect line')
795
        toler = int(configs[0].value) if configs else 20
796
        count = self.connect_line_to_symbol(10, True)
797
        #self.connect_line_to_symbol(toler, False, count)
798

    
799
        self.progress_bar.setValue(self.progress_bar.maximum())
800

    
801
        for item in items:
802
            item.setVisible(True)
803
        
804
        QApplication.processEvents()
805
        QMessageBox.information(self, self.tr('Information'), self.tr('Connecting between symbols and lines is completed'))
806

    
807
    def connect_line_to_symbol(self, toler=20, start=True, count=0):
808
        """connect line to symbol"""
809
        from LineDetector import LineDetector
810
        from shapely.geometry import Point
811
        #from RecognitionDialog import Worker
812

    
813
        app_doc_data = AppDocData.instance()
814
        #configs = app_doc_data.getConfigs('Project', 'Operation')
815
        detector = LineDetector(app_doc_data.imgSrc)
816

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

    
825
        for item in lines_short + unknowns:
826
            item.transfer.onRemoved.emit(item)
827

    
828
        if start:
829
            self.progress_bar.setMaximum((len(lines) + len(symbols)) * 2 + 3)
830
            count = 1
831
            self.progress_bar.setValue(count)
832
            QApplication.processEvents()
833

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

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

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

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

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

    
903
        # connect line to line
904
        try:
905
            for line in lines:
906
                #matches = [it for it in lines if (it is not line) and (not line.isParallel(it))]
907
                #for match in matches:
908
                for match in lines:
909
                    detector.connectLineToLine(match, line, toler)
910

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

    
920
        try:
921
            # connect end break
922
            usedItemPairs = []
923
            for end_break in end_breaks:
924
                if end_break.prop('Freeze') or end_break.owner or end_break.prop('Connected Item'):
925
                    usedItemPairs.append([end_break.owner, end_break.prop('Connected Item')])
926

    
927
            for end_break in end_breaks:
928
                if end_break.prop('Freeze') or end_break.owner or end_break.prop('Connected Item'):
929
                    continue
930

    
931
                originPoint = Point(end_break.origin[0], end_break.origin[1])
932
                minD = sys.maxsize
933
                ownerItem = None
934
                connectedItem = None
935

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

    
943
                        minD = dist
944
                        ownerItem = symbol
945
                        connectedItem = conn.connectedItem
946

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

    
955
                        minD = dist
956
                        ownerItem = line
957
                        connectedItem = conn.connectedItem
958

    
959
                if ownerItem and connectedItem:
960
                    end_break.set_property('Connected Item', connectedItem)
961
                    end_break.setToolTip('owner : ' + str(ownerItem))
962
                    end_break.owner = ownerItem
963
                    end_break.set_property('Freeze', True)
964

    
965
                    usedItemPairs.append([ownerItem, connectedItem])
966
            # up to here
967

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

    
979
    def on_connect_spec_breaks(self, spec_breaks, texts=None, symbols=None, lines=None):
980
        from CodeTables import CodeTable
981
        from shapely.geometry import Point
982

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

    
991
            usedTexts = []
992
            attribute_table_item_list = []
993
            dist_range = None
994
            specBreakAttrsFull = [attr for attr in app_doc_data.getSymbolAttribute('Segment Breaks') if attr.AttributeType == 'Spec' or attr.AttributeType == 'String']
995

    
996
            for attr in specBreakAttrsFull:
997
                if attr.AttributeType != 'Spec' or attr.Attribute == 'NominalDiameter':
998
                    continue
999

    
1000
                usedTexts = []
1001

    
1002
                table = CodeTable.instance(attr.Attribute)
1003
                items = []
1004
                for text in texts:
1005
                    if text not in usedTexts and table.find_match_exactly(text.text()):
1006
                        usedTexts.append(text)
1007
                        items.append(text)
1008

    
1009
                if len(items) >= 2:
1010
                    attribute_table_item_list.append([attr.Attribute, items])
1011

    
1012
            usedItemPairs = []
1013
            for spec_break in spec_breaks:
1014
                if not dist_range:
1015
                    dist_range = max(spec_break.sceneBoundingRect().height(), spec_break.sceneBoundingRect().width())
1016

    
1017
                attrs = spec_break.getAttributes()
1018
                up = [attr.AssocItem for attr in attrs if attr.Attribute == 'UpStream']
1019
                down = [attr.AssocItem for attr in attrs if attr.Attribute == 'DownStream']
1020
                if (up and up[0]) or (down and down[0]):
1021
                    usedItemPairs.append([up, down])
1022

    
1023
            for spec_break in spec_breaks:
1024
                attrs = spec_break.getAttributes()
1025
                up = [attr.AssocItem for attr in attrs if attr.Attribute == 'UpStream']
1026
                down = [attr.AssocItem for attr in attrs if attr.Attribute == 'DownStream']
1027
                if (up and up[0]) or (down and down[0]):
1028
                    continue
1029

    
1030
                originPoint = Point(spec_break.origin[0], spec_break.origin[1])
1031
                minD = sys.maxsize
1032
                upItem = None
1033
                downItem = None
1034

    
1035
                for symbol in symbols:
1036
                    for conn in symbol.connectors:
1037
                        dist = originPoint.distance(Point(conn.sceneConnectPoint[0], conn.sceneConnectPoint[1]))
1038
                        if not conn.connectedItem or not issubclass(type(conn.connectedItem), QEngineeringAbstractItem) or \
1039
                            [pair for pair in usedItemPairs if symbol in pair and conn.connectedItem in pair] or dist > dist_range or dist > minD:
1040
                            continue
1041

    
1042
                        minD = dist
1043
                        upItem = symbol
1044
                        downItem = conn.connectedItem
1045

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

    
1054
                        minD = dist
1055
                        upItem = line
1056
                        downItem = conn.connectedItem
1057

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

    
1073
                    usedItemPairs.append([upItem, downItem])
1074

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

    
1122
                        if upText and downText:
1123
                            for full in specBreakAttrsFull:
1124
                                if full.Attribute == attribute_table_item[0]:
1125
                                    attrs[full] = [upText.text(), downText.text()]
1126
                                    attribute_table_item[1].remove(upText)
1127
                                    attribute_table_item[1].remove(downText)
1128
                                    break
1129

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

    
1150
                                        if not find_next:
1151
                                            # prevent infinite loop
1152
                                            if connected_count == 2:
1153
                                                for connectorr in stream_line[index].connectors:
1154
                                                    if connectorr.connectedItem and not connectorr.connectedItem is stream_track[index]:
1155
                                                        stream_line[index] = connectorr.connectedItem
1156
                                                        stream_track[index] = stream_line[index]
1157
                                                        find_next = True
1158
                                                        break
1159
                                                if not find_next:
1160
                                                    break
1161
                                            else:
1162
                                                break
1163

    
1164
                            if stream_res[0] and stream_res[1]:
1165
                                up_down_find = [upText, downText]
1166

    
1167
                                for index in range(len(stream_line)):
1168
                                    _attrs = stream_line[index].getAttributes()
1169
                                    for key in _attrs.keys():
1170
                                        if key.Attribute == attribute_table_item[0]:
1171
                                            _attrs[key] = up_down_find[index].text()
1172
                                            key.AssocItem = up_down_find[index]
1173
                                            stream_line[index].add_assoc_item(up_down_find[index],
1174
                                                                                key.AttrAt, force=True)
1175
                                            up_down_find[index].owner = stream_line[index]
1176
                                            key.Freeze = True
1177
                                            break
1178

    
1179
            return True
1180
        except Exception as ex:
1181
            message = f"error occurred({repr(ex)}) in {sys.exc_info()[-1].tb_frame.f_code.co_filename}:" \
1182
                        f"{sys.exc_info()[-1].tb_lineno}"
1183
            self.addMessage.emit(MessageType.Error, message)
1184

    
1185
            return False
1186

    
1187

    
1188
    def on_recognize_line(self):
1189
        """recognize lines in selected area"""
1190
        from RecognizeLineCommand import RecognizeLineCommand
1191

    
1192
        if not self.graphicsView.hasImage():
1193
            self.actionOCR.setChecked(False)
1194
            self.showImageSelectionMessageBox()
1195
            return
1196

    
1197
        cmd = RecognizeLineCommand(self.graphicsView)
1198
        cmd.onSuccess.connect(self.on_success_to_recognize_line)
1199
        cmd.onRejected.connect(self.onCommandRejected)
1200
        self.graphicsView.command = cmd
1201

    
1202
    '''
1203
            @brief      show text recognition dialog
1204
            @author     humkyung
1205
            @date       2018.08.08
1206
    '''
1207
    def on_success_to_recognize_line(self, x, y, width, height):
1208
        import io
1209
        from LineDetector import LineDetector
1210
        from EngineeringGraphicsLineItem import QEngineeringGraphicsLineItem
1211

    
1212
        try:
1213
            image = self.graphicsView.image().copy(x, y, width, height)
1214
            buffer = QBuffer()
1215
            buffer.open(QBuffer.ReadWrite)
1216
            image.save(buffer, "PNG")
1217
            pyImage = Image.open(io.BytesIO(buffer.data()))
1218
            img = np.array(pyImage)
1219
            img = cv2.cvtColor(img, cv2.COLOR_BGR2GRAY)
1220

    
1221
            detector = LineDetector(img)
1222
            lines = detector.detect_line_without_symbol()
1223
            for line in lines:
1224
                vertices = [[line[0][0] + x, line[0][1] + y], [line[1][0] + x, line[1][1] + y]]
1225
                line_item = QEngineeringGraphicsLineItem(vertices)
1226
                self.graphicsView.scene().addItem(line_item)
1227

    
1228
        except Exception as ex:
1229
            message = 'error occurred({}) in {}:{}'.format(repr(ex), sys.exc_info()[-1].tb_frame.f_code.co_filename,
1230
                                                           sys.exc_info()[-1].tb_lineno)
1231
            self.addMessage.emit(MessageType.Error, message)
1232

    
1233
    def display_number_of_items(self):
1234
        """display count of symbol, line, text"""
1235

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

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

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

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

    
1254
        self.itemTreeWidget.sceneChanged(self.graphicsView.scene().items())
1255

    
1256
    def dbUpdate(self):
1257
        """ no more used """
1258
        """db update when save or recognition"""
1259

    
1260
        try:
1261
            appDocData = AppDocData.instance()
1262
            items = appDocData.allItems
1263

    
1264
            '''
1265
            titleBlockProps = appDocData.getTitleBlockProperties()
1266
            titleBlockItems = []
1267
            for item in items:
1268
                # if type(item) is QEngineeringLineNoTextItem:
1269
                #    item.saveLineData()
1270
                if type(item) is QEngineeringTextItem:
1271
                    for titleBlockProp in titleBlockProps:
1272
                        if item.area == titleBlockProp[0]:
1273
                            titleBlockItems.append(item)
1274
            '''
1275

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

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

    
1303
    def save_drawing_if_necessary(self):
1304
        """ask to user to save drawing or not when drawing is modified"""
1305

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

    
1319
    def actionSaveCliked(self, batch=False):
1320
        """
1321
        save current drawing
1322
        @return:
1323
        """
1324
        from EngineeringAbstractItem import QEngineeringAbstractItem
1325
        from SaveWorkCommand import SaveWorkCommand
1326

    
1327
        try:
1328
            app_doc_data = AppDocData.instance()
1329

    
1330
            if app_doc_data.imgName is None:
1331
                self.showImageSelectionMessageBox()
1332
                return
1333

    
1334
            home_pane = self.ribbon.get_pane('Home File')
1335
            if not home_pane.ui.toolButtonFileSave.isEnabled():
1336
                return
1337

    
1338
            home_pane.ui.toolButtonFileSave.setEnabled(False)
1339

    
1340
            # save alarm
1341
            self.save_alarm_enable(False)    
1342

    
1343
            app_doc_data.clearItemList(False)
1344

    
1345
            #items = self.graphicsView.scene().items()
1346

    
1347
            self._save_work_cmd = SaveWorkCommand(self.graphicsView.scene())
1348
            self._save_work_cmd.show_progress.connect(self.progress_bar.setValue)
1349
            self._save_work_cmd.display_message.connect(self.onAddMessage)
1350
            if not batch:
1351
                self._save_work_cmd.finished.connect(self.save_finished)
1352
            else:
1353
                self._save_work_cmd.finished.connect(self.save_finished_batch)
1354

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

    
1361
    def save_finished(self):
1362
        """
1363
        reload drawing list when save is finished
1364
        @return: None
1365
        """
1366

    
1367
        try:
1368
            self._save_work_cmd.show_progress.emit(100)
1369
            QMessageBox.about(self.graphicsView, self.tr('Information'), self._save_work_cmd.resultStr)
1370
            self.load_drawing_list()
1371

    
1372
            app_doc_data = AppDocData.instance()
1373
            app_doc_data.activeDrawing.modified = False
1374
            title = self.windowTitle()
1375
            self.setWindowTitle(title[:-1] if title[-1] == '*' else title)
1376

    
1377
            # save alarm
1378
            self.save_alarm_enable(True)
1379
        finally:
1380
            home_pane = self.ribbon.get_pane('Home File')
1381
            home_pane.ui.toolButtonFileSave.setEnabled(True)
1382

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

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

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

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

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

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

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

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

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

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

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

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

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

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

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

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

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

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

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

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

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

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

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

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

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

    
1525
        self.display_number_of_items()
1526

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

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

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

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

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

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

    
1574
        self.on_export_PDF(path)
1575

    
1576
    def connect_attributes_batch(self):
1577
        from ConnectAttrDialog import QConnectAttrDialog
1578

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

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

    
1593
            if not checked_drawings:
1594
                self.showImageSelectionMessageBox()
1595
                return
1596
            
1597
            reply = QMessageBox.question(self, self.tr('Continue?'),
1598
                                         self.tr('Batch linking for selected drawings. '), QMessageBox.Yes,
1599
                                         QMessageBox.Cancel)
1600
            if reply != QMessageBox.Yes:
1601
                return
1602
            
1603
            self.progress_bar.setMaximum(len(checked_drawings) + 2)
1604
            count = 1
1605
            self.progress_bar.setValue(count)
1606

    
1607
            for drawing in checked_drawings.keys():
1608
                self.open_image_drawing(drawing, force=True, ocrUnknown=False, timer=False, pdf=False)
1609

    
1610
                dlg = QConnectAttrDialog(self, self.graphicsView.scene())
1611
                #print('start')
1612
                dlg.start_job()
1613
                #print('end')
1614
                self.actionSaveCliked(batch=True)
1615

    
1616
                count += 1
1617
                self.progress_bar.setValue(count)
1618

    
1619
            self.open_image_drawing(drawing, force=True, ocrUnknown=False) # for reset
1620
            self.progress_bar.setValue(self.progress_bar.maximum())
1621
                    
1622
            QMessageBox.about(self, self.tr("Information"), self.tr('Successfully updated.'))
1623

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

    
1629
    def on_export_PDF(self, path=None):
1630
        # save alarm
1631
        self.save_alarm_enable(False)
1632
        
1633
        #if not self.graphicsView.hasImage():
1634
        #    self.showImageSelectionMessageBox()
1635
        #    return
1636

    
1637
        try:
1638
            app_doc_data = AppDocData.instance()
1639
            current_drawing = None
1640

    
1641
            if self.graphicsView.hasImage():
1642
                current_drawing = app_doc_data.activeDrawing
1643

    
1644
            # get checked drawings
1645
            drawing_top = self.treeWidgetDrawingList.topLevelItem(0)
1646
            count = drawing_top.childCount()
1647
            checked_drawings = {}
1648
            for idx in range(count):
1649
                child = drawing_top.child(idx)
1650
                if child.checkState(0) == Qt.Checked and child.data(Qt.UserRole, 0):
1651
                    checked_drawings[child.data(Qt.UserRole, 0)] = child
1652
            # up to here
1653

    
1654
            # if there is no checked drawing
1655
            if current_drawing and not checked_drawings:
1656
                for idx in range(count):
1657
                    child = drawing_top.child(idx)
1658
                    if child.data(Qt.UserRole, 0) is current_drawing:
1659
                        checked_drawings[child.data(Qt.UserRole, 0)] = child
1660

    
1661
            if not checked_drawings:
1662
                self.showImageSelectionMessageBox()
1663
                return
1664
                
1665
            project = app_doc_data.getCurrentProject()
1666

    
1667
            if current_drawing and len(checked_drawings) == 1:
1668
                name = os.path.join(project.getTempPath(), os.path.splitext(app_doc_data.activeDrawing.name)[0])
1669
                
1670
                options = QFileDialog.Options()
1671
                options |= QFileDialog.DontUseNativeDialog
1672
                file_name, _ = QFileDialog.getSaveFileName(self, "Export PDF", name, "pdf files(*.pdf)", options=options)
1673
                if file_name:
1674
                    file_name += '.png'
1675
                    self.save_PDF(file_name)
1676

    
1677
            elif len(checked_drawings) >= 1:
1678
                name = os.path.join(project.getTempPath(), 'Select a Folder')
1679
                
1680
                file_name = None
1681
                if not path:
1682
                    options = QFileDialog.Options()
1683
                    options |= QFileDialog.DontUseNativeDialog
1684
                    file_name, _ = QFileDialog.getSaveFileName(self, "Export PDF", name, "pdf files(*.pdf)", options=options)
1685

    
1686
                if file_name or path:
1687
                    if file_name:
1688
                        directory = os.path.dirname(file_name)
1689
                    else:
1690
                        directory = path
1691

    
1692
                    self.progress_bar.setMaximum(len(checked_drawings) + 2)
1693
                    count = 1
1694
                    self.progress_bar.setValue(count)
1695

    
1696
                    for drawing in checked_drawings.keys():
1697
                        self.open_image_drawing(drawing, force=True, ocrUnknown=False, timer=False, pdf=True)
1698

    
1699
                        self.save_PDF(os.path.join(directory, drawing.name))
1700

    
1701
                        count += 1
1702
                        self.progress_bar.setValue(count)
1703

    
1704
                    self.open_image_drawing(drawing, force=True, ocrUnknown=False) # for reset
1705
                    self.progress_bar.setValue(self.progress_bar.maximum())
1706
                    
1707
            QMessageBox.about(self, self.tr("Information"), self.tr('Successfully saved.'))
1708

    
1709
            #self.save_alarm_enable(True, True)
1710

    
1711
            '''
1712
            #app_doc_data = AppDocData.instance()
1713
            #project = app_doc_data.getCurrentProject()
1714

1715
            printer = QPrinter(QPrinter.PrinterResolution)
1716
            #printer.setPageSize(QPrinter.A0)
1717
            printer.setOrientation(QPrinter.Orientation.Landscape)
1718
            #printer.setOutputFileName(os.path.join(project.getPDFFilePath(), os.path.splitext(app_doc_data.activeDrawing.name)[0]))
1719
            #printer.setOutputFormat(QPrinter.PdfFormat)
1720
            dialog = QPrintDialog(printer)
1721
            if (dialog.exec() == QDialog.Accepted):
1722
                painter = QPainter(printer)
1723
                isfull_print = False
1724

1725
                scene = self.graphicsView.scene()
1726

1727
                #for item in scene.items():
1728
                #    if not hasattr(item, 'connectors'): continue
1729
                #    for connector in item.connectors: connector.setVisible(False)
1730

1731
                canvasRect = scene.sceneRect() # or canvasRect = scene.border.boundingRect()
1732
                source = canvasRect
1733
                page = printer.pageRect(QPrinter.Unit.DevicePixel)
1734
                target = QRectF(QPointF(0, 0), QSizeF(page.width(), page.height()))
1735
                scene.render(painter, target, source)
1736
                painter.end()
1737

1738
                QMessageBox.about(self, self.tr("Information"), self.tr('Successfully saved.'))
1739
                #for item in scene.items():
1740
                #    if not hasattr(item, 'connectors'): continue
1741
                #    for connector in item.connectors: connector.setVisible(True)
1742
            '''
1743

    
1744
        except Exception as ex:
1745
            message = 'error occurred({}) in {}:{}'.format(ex, sys.exc_info()[-1].tb_frame.f_code.co_filename,
1746
                                                           sys.exc_info()[-1].tb_lineno)
1747
            self.addMessage.emit(MessageType.Error, message)
1748

    
1749
    def save_PDF(self, file_name):
1750
        #pixMap = self.graphicsView.grab(QRect(QPoint(0, 0), QSize(int(self.graphicsView.scene().sceneRect().width()), int(self.graphicsView.scene().sceneRect().height()))))
1751
        #pixMap.save(name)
1752
        #return
1753

    
1754
        image = QImage(QSize(int(self.graphicsView.scene().sceneRect().width()), int(self.graphicsView.scene().sceneRect().height())), QImage.Format_ARGB32_Premultiplied)
1755
        painter = QPainter(image)
1756
        scene = self.graphicsView.scene()
1757
        canvasRect = scene.sceneRect() # or canvasRect = scene.border.boundingRect()
1758
        source = canvasRect
1759
        scene.render(painter, QRectF(image.rect()), source)
1760
        painter.end()
1761
        image.save(file_name)
1762
        image = Image.open(file_name)
1763
        image = image.convert('RGB')
1764
        image.save(file_name.replace('.png', '.pdf'))
1765
        os.remove(file_name)
1766
        painter.device()
1767

    
1768
    def onSymbolThickness(self):
1769
        """ symbol thickness reinforcement by using configuration filter drawing dilate size """
1770
        try:
1771
            self.onCommandRejected()
1772
            dialog = QSymbolThicknessDialog(self)
1773
            dialog.exec_()
1774
        except Exception as ex:
1775
            message = 'error occurred({}) in {}:{}'.format(ex, sys.exc_info()[-1].tb_frame.f_code.co_filename,
1776
                                                           sys.exc_info()[-1].tb_lineno)
1777
            self.addMessage.emit(MessageType.Error, message)
1778

    
1779
    def on_help(self):
1780
        """ open help file """
1781
        import os
1782

    
1783
        try:
1784
            help_file_path = os.path.join(os.path.dirname(os.path.realpath(__file__)), 'ID2 User Manual.pdf')
1785
            if os.path.exists(help_file_path):
1786
                os.startfile(f"\"{help_file_path}\"")
1787
            else:
1788
                QMessageBox.warning(self, self.tr('Warning'), self.tr('There is no help file'))
1789
        except Exception as ex:
1790
            message = f"error occurred({repr(ex)}) in {sys.exc_info()[-1].tb_frame.f_code.co_filename}:" \
1791
                      f"{sys.exc_info()[-1].tb_lineno}"
1792
            self.addMessage.emit(MessageType.Error, message)
1793

    
1794
    def on_readme(self):
1795
        """open readme.html"""
1796

    
1797
        file_path = os.path.join(os.path.dirname(os.path.realpath(__file__)), 'readme.html')
1798
        if os.path.exists(file_path):
1799
            os.startfile(f"\"{file_path}\"")
1800
        else:
1801
            QMessageBox.warning(self, self.tr('Warning'), self.tr('There is no readme file'))
1802

    
1803
    def onSelectionChanged(self):
1804
        """selection changed"""
1805
        items = [item for item in self.graphicsView.scene().selectedItems() if issubclass(type(item), SymbolSvgItem) or
1806
                 type(item) is QEngineeringLineItem or issubclass(type(item), QEngineeringTextItem) or
1807
                 type(item) is QEngineeringUnknownItem or type(item) is QEngineeringVendorItem]
1808
        if items:
1809
            lineNos = [item for item in items if type(item) is QEngineeringLineNoTextItem]
1810
            item = items[-1] if not lineNos else lineNos[0]
1811
            self.itemTreeWidget.findItem(item)
1812
            self.resultPropertyTableWidget.show_item_property(item)
1813
            if type(item) is QEngineeringErrorItem:
1814
                for index in range(self.tableWidgetInconsistency.rowCount()):
1815
                    if self.tableWidgetInconsistency.item(index, 1).tag is item:
1816
                        self.tableWidgetInconsistency.selectRow(index)
1817
                        break
1818
            if issubclass(type(item), SymbolSvgItem):
1819
                pass
1820
                #self.symbolTreeWidget.select_symbol(item)
1821
        else:
1822
            self.resultPropertyTableWidget.show_item_property(None)
1823

    
1824
    '''
1825
        @brief      Initialize scene and itemTreeWidget
1826
        @author     Jeongwoo
1827
        @date       2018.06.14
1828
        @history    humkyung 2018.08.16 ask to delete recognized items before remove
1829
    '''
1830
    def on_initialize_scene(self, action):
1831
        if not self.graphicsView.hasImage():
1832
            self.showImageSelectionMessageBox()
1833

    
1834
            return
1835

    
1836
        try:
1837
            msg = QMessageBox()
1838
            msg.setIcon(QMessageBox.Critical)
1839
            msg.setText(self.tr('Do you want to remove all items?\nThis work cannot be recovered.'))
1840
            msg.setWindowTitle(self.tr("Initialize"))
1841
            msg.setStandardButtons(QMessageBox.Ok | QMessageBox.Cancel)
1842
            if QMessageBox.Ok == msg.exec_():
1843
                app_doc_data = AppDocData.instance()
1844
                app_doc_data.clearItemList(True)
1845

    
1846
                scene = self.graphicsView.scene()
1847
                pixmap = self.graphicsView.getPixmapHandle()
1848
                scene.removeItem(pixmap)    # disconnect pixmap from scene
1849
                scene.clear()               # remove all items from scene and then delete them
1850
                scene.addItem(pixmap)       # add pixmap
1851

    
1852
                if self.path is not None:
1853
                    baseName = os.path.basename(self.path)
1854
                    self.itemTreeWidget.setCurrentPID(baseName)
1855

    
1856
        except Exception as ex:
1857
            message = 'error occurred({}) in {}:{}'.format(ex, sys.exc_info()[-1].tb_frame.f_code.co_filename,
1858
                                                           sys.exc_info()[-1].tb_lineno)
1859
            self.addMessage.emit(MessageType.Error, message)
1860

    
1861
    def checked_action(self):
1862
        """return checked action"""
1863
        home_file_pane = self.ribbon.get_pane('Home File')
1864
        home_pane = self.ribbon.get_pane('Home')
1865
        visualization_pane = self.ribbon.get_pane('Home Visualization')
1866
        actions = [home_pane.ui.toolButtonRecognition, home_pane.ui.toolButtonLinkAttribute,
1867
                   home_pane.ui.toolButtonLine, home_pane.ui.toolButtonOCR, visualization_pane.ui.toolButtonZoom,
1868
                   visualization_pane.ui.toolButtonFitWindow, home_pane.ui.toolButtonVendor]
1869

    
1870
        checked = [ui_ for ui_ in actions if ui_.isChecked()]
1871
        return checked[0] if checked else None
1872

    
1873
    def update_action_group(self, ui):
1874
        """Manage Checkable Action statement"""
1875
        home_file_pane = self.ribbon.get_pane('Home File')
1876
        home_pane = self.ribbon.get_pane('Home')
1877
        visualization_pane = self.ribbon.get_pane('Home Visualization')
1878
        actions = [home_pane.ui.toolButtonRecognition, home_pane.ui.toolButtonLinkAttribute, home_pane.ui.toolButtonLine,
1879
                   home_pane.ui.toolButtonOCR, visualization_pane.ui.toolButtonZoom,
1880
                   visualization_pane.ui.toolButtonFitWindow, home_file_pane.ui.toolButtonFileSave,
1881
                   home_pane.ui.toolButtonValidate, home_pane.ui.toolButtonVendor]
1882

    
1883
        if hasattr(ui, 'tag'):
1884
            ui.tag.onRejected.emit(None)
1885

    
1886
        if self.graphicsView.command is not None:
1887
            self.graphicsView.useDefaultCommand()
1888

    
1889
        for ui_ in actions:
1890
            ui_.setChecked(False)
1891

    
1892
        ui.setChecked(True)
1893

    
1894
    '''
1895
        @brief      Create Equipment
1896
        @author     Jeongwoo
1897
        @date       18.05.03
1898
        @history    2018.05.04  Jeongwoo    Add Parameter on CreateSymbolCommand
1899
    '''
1900
    def createEquipment(self):
1901
        if not self.graphicsView.hasImage():
1902
            self.actionEquipment.setChecked(False)
1903
            self.showImageSelectionMessageBox()
1904
            return
1905
        if self.actionEquipment.isChecked():
1906
            self.graphicsView.command = CreateSymbolCommand.CreateSymbolCommand(self.graphicsView, self.itemTreeWidget,
1907
                                                                                self.symbolTreeWidget)
1908
        else:
1909
            self.graphicsView.useDefaultCommand()
1910

    
1911
    '''
1912
        @brief      Create Nozzle
1913
        @author     Jeongwoo
1914
        @date       2018.05.03
1915
        @history    2018.05.04  Jeongwoo    Add Parameter on CreateSymbolCommand
1916
    '''
1917
    def createNozzle(self):
1918
        if not self.graphicsView.hasImage():
1919
            self.actionNozzle.setChecked(False)
1920
            self.showImageSelectionMessageBox()
1921
            return
1922
        if self.actionNozzle.isChecked():
1923
            self.graphicsView.command = CreateSymbolCommand.CreateSymbolCommand(self.graphicsView, self.itemTreeWidget,
1924
                                                                                self.symbolTreeWidget)
1925
        else:
1926
            self.graphicsView.useDefaultCommand()
1927

    
1928
    def onAreaOcr(self):
1929
        """Area OCR"""
1930
        if not self.graphicsView.hasImage():
1931
            self.actionOCR.setChecked(False)
1932
            self.showImageSelectionMessageBox()
1933
            return
1934

    
1935
        pane = self.ribbon.get_pane('Home')
1936
        ui = pane.ui.toolButtonOCR
1937
        self.update_action_group(ui=ui)
1938
        checked = ui.isChecked()
1939
        if checked:
1940
            cmd = AreaOcrCommand.AreaOcrCommand(self.graphicsView)
1941
            cmd.onSuccess.connect(self.onRecognizeText)
1942
            cmd.onRejected.connect(self.onCommandRejected)
1943
            self.graphicsView.command = cmd
1944
        else:
1945
            self.graphicsView.useDefaultCommand()
1946

    
1947
    def onRecognizeText(self, x, y, width, height, show=True):
1948
        """show text recognition dialog"""
1949
        from OcrResultDialog import QOcrResultDialog
1950
        from Area import Area
1951

    
1952
        try:
1953
            app_doc_data = AppDocData.instance()
1954

    
1955
            modifiers = QApplication.keyboardModifiers()
1956
            image = self.graphicsView.image().copy(x, y, width, height)
1957
            dialog = QOcrResultDialog(self, image, QRectF(x, y, width, height),
1958
                                      format=QOcrResultDialog.Format.Table if modifiers == Qt.AltModifier else QOcrResultDialog.Format.Normal)
1959
            if modifiers == Qt.ControlModifier:
1960
                return
1961
            
1962
            if show:
1963
                (res, textInfoList) = dialog.showDialog()
1964
            else:
1965
                dialog.accept(show=False)
1966
                (res, textInfoList) = QDialog.Accepted, dialog.textInfoList
1967

    
1968
            if QDialog.Accepted == res and textInfoList:
1969
                for textInfo in textInfoList:
1970
                    item = QEngineeringTextItem.create_text_with(self.graphicsView.scene(), textInfo)
1971
                    if item:
1972
                        #item.setDefaultTextColor(Qt.blue)
1973
                        item.transfer.onRemoved.connect(self.itemRemoved)
1974

    
1975
                        area_list = app_doc_data.getAreaList()
1976
                        title_area_list = app_doc_data.getTitleBlockProperties()
1977
                        title_list = []
1978
                        if title_area_list:
1979
                            for title_area in title_area_list:
1980
                                area = Area(title_area[0])
1981
                                area.parse(title_area[2])
1982
                                title_list.append(area)
1983
                        for area in area_list + title_list:
1984
                            pt = [item.sceneBoundingRect().center().x(), item.sceneBoundingRect().center().y()]
1985
                            if area.contains(pt):
1986
                                item.area = area.name
1987
                                break
1988
                    else:
1989
                        self.addMessage.emit(MessageType.Normal, self.tr('Fail to create text.'))
1990

    
1991
                return True
1992
            elif QDialog.Accepted == res and not textInfoList and show:
1993
                QMessageBox.about(self.graphicsView, self.tr("Notice"), self.tr("Fail to recognize text"))
1994
        except Exception as ex:
1995
            message = 'error occurred({}) in {}:{}'.format(ex, sys.exc_info()[-1].tb_frame.f_code.co_filename,
1996
                                                           sys.exc_info()[-1].tb_lineno)
1997
            self.addMessage.emit(MessageType.Error, message)
1998
        
1999
        return False
2000

    
2001
    '''
2002
        @brief  area configuration
2003
    '''
2004
    def areaConfiguration(self):
2005
        from ConfigurationAreaDialog import QConfigurationAreaDialog
2006
        if not self.graphicsView.hasImage():
2007
            self.showImageSelectionMessageBox()
2008
            return
2009
        self.onCommandRejected()
2010
        dlgConfigurationArea = QConfigurationAreaDialog(self)
2011
        dlgConfigurationArea.show()
2012
        dlgConfigurationArea.exec_()
2013

    
2014
    '''
2015
        @brief  configuration
2016
    '''
2017
    def configuration(self):
2018
        from ConfigurationDialog import QConfigurationDialog
2019

    
2020
        dlgConfiguration = QConfigurationDialog(self)
2021
        if QDialog.Accepted == dlgConfiguration.exec_():
2022
            QEngineeringLineItem.LINE_TYPE_COLORS.clear()
2023
            QEngineeringInstrumentItem.INST_COLOR = None
2024

    
2025
    '''
2026
        @brief  show special item types dialog 
2027
        @author humkyung
2028
        @date   2019.08.10
2029
    '''
2030
    def on_show_special_item_types(self):
2031
        from SpecialItemTypesDialog import QSpecialItemTypesDialog
2032

    
2033
        dlg = QSpecialItemTypesDialog(self)
2034
        dlg.exec_()
2035

    
2036
    def on_show_data_transfer(self):
2037
        """ show data transfer dialog """
2038
        from DataTransferDialog import QDataTransferDialog
2039

    
2040
        dlg = QDataTransferDialog(self)
2041
        dlg.exec_()
2042

    
2043
    def on_show_data_export(self):
2044
        """ show data export dialog """
2045
        from DataExportDialog import QDataExportDialog
2046

    
2047
        dlg = QDataExportDialog(self)
2048
        dlg.exec_()
2049

    
2050
    def on_show_eqp_datasheet_export(self):
2051
        """ show eqp datasheet export dialog """
2052
        from EqpDatasheetExportDialog import QEqpDatasheetExportDialog
2053

    
2054
        dlg = QEqpDatasheetExportDialog(self)
2055
        dlg.exec_()
2056

    
2057
    def on_show_opc_relation(self):
2058
        """ show opc relation dialog """
2059
        from OPCRelationDialog import QOPCRelationDialog
2060

    
2061
        dlg = QOPCRelationDialog(self)
2062
        dlg.exec_()
2063

    
2064
    '''
2065
        @brief  show nominal diameter dialog 
2066
        @author humkyung
2067
        @date   2018.06.28
2068
    '''
2069
    def onShowCodeTable(self):
2070
        from CodeTableDialog import QCodeTableDialog
2071

    
2072
        dlg = QCodeTableDialog(self)
2073
        dlg.show()
2074
        dlg.exec_()
2075
        if dlg.code_area:
2076
            if dlg.code_area.scene():
2077
                self.graphicsView.scene().removeItem(dlg.code_area)
2078
        if dlg.desc_area:
2079
            if dlg.desc_area.scene():
2080
                self.graphicsView.scene().removeItem(dlg.desc_area)
2081
        self.graphicsView.useDefaultCommand()
2082

    
2083
    def on_ext_app_connection(self):
2084
        app_doc_data = AppDocData.instance()
2085

    
2086
        tool_pane = self.ribbon.get_pane('Tool')
2087
        if tool_pane.ui.toolButtonConnection.isChecked():
2088
            if not hasattr(self, '_tcpserver'):
2089
                configs = app_doc_data.getAppConfigs('app', 'port')
2090
                port = 2549
2091
                if configs and 1 == len(configs):
2092
                    port = int(configs[0].value)
2093
                self._tcpserver = TcpServer(port)
2094
                self._tcpserver.sessionOpened()
2095
        else:
2096
            self._tcpserver.sessionClosed()
2097
            del self._tcpserver
2098

    
2099
    def on_execute_ext_app(self):
2100
        """execute external application"""
2101
        from ExtAppsDialog import QExtAppsDialog
2102

    
2103
        dlg = QExtAppsDialog(self)
2104
        dlg.exec_()
2105

    
2106
    def onShowCustomCodeTable(self):
2107
        from CustomCodeTablesDialog import CustomCodeTablesDialog
2108

    
2109
        dlg = CustomCodeTablesDialog(self)
2110
        dlg.show()
2111
        dlg.exec_()
2112
        self.graphicsView.useDefaultCommand()
2113

    
2114
    def onShowReplaceCodeTable(self):
2115
        from CustomCodeTablesDialog import CustomCodeTablesDialog
2116

    
2117
        dlg = CustomCodeTablesDialog(self, replace=True)
2118
        dlg.show()
2119
        dlg.exec_()
2120
        self.graphicsView.useDefaultCommand()
2121

    
2122
    def on_streamline(self):
2123
        """pop up stream line dialog"""
2124
        from StreamlineDialog import QStreamlineDialog
2125

    
2126
        if not self.graphicsView.hasImage():
2127
            self.showImageSelectionMessageBox()
2128
            return
2129

    
2130
        hmbs = AppDocData.instance().get_hmb_data(None)
2131
        if not hmbs:
2132
            return
2133

    
2134
        dlg = QStreamlineDialog(self)
2135
        dlg.show()
2136

    
2137
    def onHMBData(self):
2138
        """show HMB data"""
2139
        from HMBDialog import QHMBDialog
2140

    
2141
        dlg = QHMBDialog(self)
2142
        dlg.show()
2143
        dlg.exec_()
2144

    
2145
    '''
2146
        @brief  show line data list 
2147
        @author humkyung
2148
        @date   2018.05.03
2149
    '''
2150
    def showItemDataList(self):
2151
        from ItemDataExportDialog import QItemDataExportDialog
2152

    
2153
        dlg = QItemDataExportDialog(self)
2154
        dlg.exec_()
2155

    
2156
    def showTextDataList(self):
2157
        '''
2158
            @brief      show all text item in scene
2159
            @author     euisung
2160
            @date       2019.04.18
2161
        '''
2162
        try:
2163
            if not self.graphicsView.hasImage():
2164
                self.showImageSelectionMessageBox()
2165
                return
2166

    
2167
            self.onCommandRejected()
2168
            dialog = QTextDataListDialog(self)
2169
            dialog.show()
2170
        except Exception as ex:
2171
            message = 'error occurred({}) in {}:{}'.format(ex, sys.exc_info()[-1].tb_frame.f_code.co_filename,
2172
                                                           sys.exc_info()[-1].tb_lineno)
2173
            self.addMessage.emit(MessageType.Error, message)
2174

    
2175
    '''
2176
        @brief  Show Image Selection Guide MessageBox
2177
        @author Jeongwoo
2178
        @date   2018.05.02
2179
    '''
2180
    def showImageSelectionMessageBox(self):
2181
        QMessageBox.about(self.graphicsView, self.tr("Notice"), self.tr("First Select Drawing"))
2182

    
2183
    def on_search_text_changed(self):
2184
        """filter symbol tree view"""
2185
        regexp = QRegExp(self.lineEditFilter.text(), Qt.CaseInsensitive, QRegExp.FixedString)
2186

    
2187
        proxy_model = self.symbolTreeWidget.model()
2188
        proxy_model.text = self.lineEditFilter.text().lower()
2189
        proxy_model.setFilterRegExp(regexp)
2190

    
2191
        self.symbolTreeWidget.expandAll()
2192

    
2193
    def change_display_colors(self):
2194
        """ change display color mode """
2195
        visualization_pane = self.ribbon.get_pane('Home Visualization')
2196
        if visualization_pane.ui.radioButtonByGroup.isChecked():
2197
            visualization_pane.ui.radioButtonByType.setChecked(True)
2198
        else:
2199
            visualization_pane.ui.radioButtonByGroup.setChecked(True)
2200

    
2201
    def display_colors(self, value):
2202
        """ display colors """
2203
        from DisplayColors import DisplayColors, DisplayOptions
2204

    
2205
        if hasattr(self, 'ribbon'):
2206
            visualization_pane = self.ribbon.get_pane('Home Visualization')
2207
            if self.sender() is visualization_pane.ui.radioButtonByGroup and value is True:
2208
                DisplayColors.instance().option = DisplayOptions.DisplayByLineNo
2209
            elif self.sender() is visualization_pane.ui.radioButtonByType and value is True:
2210
                DisplayColors.instance().option = DisplayOptions.DisplayByLineType
2211
            elif self.sender() is visualization_pane.ui.radioButtonByStreamNo and value is True:
2212
                DisplayColors.instance().option = DisplayOptions.DisplayByStreamNo
2213

    
2214
            if hasattr(self, 'graphicsView') and value is True:
2215
                self.graphicsView.scene().update(self.graphicsView.sceneRect())
2216
                for item in self.graphicsView.scene().items():
2217
                    if issubclass(type(item), SymbolSvgItem):
2218
                        item.update()
2219
                DisplayColors.instance().save_data()
2220

    
2221
    def open_image_drawing(self, drawing, force=False, ocrUnknown=False, timer=True, pdf=False):
2222
        """open and display image drawing file"""
2223
        from Drawing import Drawing
2224
        from App import App
2225
        from LoadCommand import LoadCommand
2226
        import concurrent.futures as futures
2227

    
2228
        # Yield successive n-sized
2229
        # chunks from l.
2230
        def divide_chunks(l, n):
2231
            # looping till length l
2232
            for i in range(0, len(l), n):
2233
                yield l[i:i + n]
2234

    
2235
        def update_items(items):
2236
            for item in items:
2237
                # binding items
2238
                item.owner
2239
                for connector in item.connectors:
2240
                    connector.connectedItem
2241

    
2242
            return items
2243

    
2244
        try:
2245
            app_doc_data = AppDocData.instance()
2246

    
2247
            if not self.actionSave.isEnabled():
2248
                return
2249

    
2250
            if not force and self.save_drawing_if_necessary():
2251
                return
2252

    
2253
            if not pdf:
2254
                occupied = app_doc_data.set_occupying_drawing(drawing.UID)
2255
                if occupied:
2256
                    QMessageBox.about(self.graphicsView, self.tr("Notice"),
2257
                                      self.tr(f"The drawing is locked for editing by another user({occupied})"))
2258
                    return
2259

    
2260
            # save alarm
2261
            if timer:
2262
                self.save_alarm_enable(False)
2263

    
2264
            if hasattr(self, '_save_work_cmd'):
2265
                self._save_work_cmd.wait()
2266

    
2267
            project = app_doc_data.getCurrentProject()
2268

    
2269
            self.path = self.graphicsView.loadImageFromFile(drawing)
2270
            if os.path.isfile(self.path):
2271
                self.onCommandRejected()
2272
                app_doc_data.clear(past=drawing.UID)
2273

    
2274
                # load color for stream no coloring
2275
                configs = app_doc_data.getConfigs('Line List', 'Use Stream No')
2276
                if configs and int(configs[0].value) == 1:
2277
                    hmbs = app_doc_data.get_hmb_data(None)
2278
                    colors = {}
2279
                    if hmbs:
2280
                        for hmb in hmbs:
2281
                            rgb = app_doc_data.colors
2282
                            colors[hmb.stream_no] = QColor(rgb.red, rgb.green, rgb.blue).name()
2283
                        app_doc_data._hmbColors = colors
2284
                # up to here
2285

    
2286
                app_doc_data.setImgFilePath(self.path)
2287
                app_doc_data.activeDrawing = drawing
2288
                
2289
                #app_doc_data.activeDrawing.set_pid_source(Image.open(self.path))
2290
                self.itemTreeWidget.setCurrentPID(app_doc_data.activeDrawing.name)
2291

    
2292
                drawingList = self.treeWidgetDrawingList.topLevelItem(0)
2293
                for idx in range(drawingList.childCount()):
2294
                    child = drawingList.child(idx)
2295
                    if child.data(Qt.UserRole, 0) is drawing:
2296
                        child.setCheckState(0, Qt.Checked)
2297
                    else:
2298
                        child.setCheckState(0, Qt.Unchecked)
2299

    
2300
                try:
2301
                    self.show_Progress_bar()
2302

    
2303
                    # disconnect scene changed if signal is connected
2304
                    if self.graphicsView.scene().receivers(self.graphicsView.scene().contents_changed) > 0:
2305
                        self.graphicsView.scene().contents_changed.disconnect()
2306

    
2307
                    SymbolSvgItem.DOCUMENTS.clear()
2308

    
2309
                    # load data
2310
                    cmd = LoadCommand()
2311
                    cmd.display_message.connect(self.onAddMessage)
2312
                    cmd.set_maximum.connect(self.progress.setMaximum)
2313
                    cmd.show_progress.connect(self.progress.setValue)
2314
                    cmd.execute((drawing, self.graphicsView.scene()),
2315
                                symbol=True, text=True, line=True, unknown=True, package=True, update=not pdf)
2316

    
2317
                    configs = app_doc_data.getConfigs('Line List', 'Use Stream No')
2318
                    if configs and int(configs[0].value) == 1:
2319
                        app_doc_data._streamLineListModelDatas = app_doc_data.get_stream_line_list_data()
2320
                    # up to here
2321

    
2322
                    """update item tree widget"""
2323
                    line_no_items = [item for item in self.graphicsView.scene().items()
2324
                                     if type(item) is QEngineeringLineNoTextItem]
2325
                    for line_no in line_no_items:
2326
                        line_no_tree_item = self.itemTreeWidget.addTreeItem(self.itemTreeWidget.root, line_no)
2327
                        for run in line_no.runs:
2328
                            for run_item in run.items:
2329
                                if issubclass(type(run_item), SymbolSvgItem):
2330
                                    self.init_add_tree_item(line_no_tree_item, run_item)
2331

    
2332
                    line_no_items = [item for item in self.graphicsView.scene().items()
2333
                                     if type(item) is QEngineeringTrimLineNoTextItem]
2334
                    for line_no in line_no_items:
2335
                        line_no_tree_item = self.itemTreeWidget.addTreeItem(self.itemTreeWidget.root, line_no)
2336
                        for run in line_no.runs:
2337
                            for run_item in run.items:
2338
                                if issubclass(type(run_item), SymbolSvgItem):
2339
                                    self.init_add_tree_item(line_no_tree_item, run_item)
2340

    
2341
                    for trim_line_no in app_doc_data.tracerLineNos:
2342
                        line_no_tree_item = self.itemTreeWidget.addTreeItem(self.itemTreeWidget.root, trim_line_no)
2343
                        for run in trim_line_no.runs:
2344
                            for run_item in run.items:
2345
                                if issubclass(type(run_item), SymbolSvgItem):
2346
                                    self.init_add_tree_item(line_no_tree_item, run_item)
2347

    
2348
                    self.itemTreeWidget.update_item_count()
2349
                    self.itemTreeWidget.expandAll()
2350
                    """up to here"""
2351

    
2352
                    """update scene"""
2353
                    for item in self._scene.items():
2354
                        item.setVisible(True)
2355

    
2356
                    self._scene.update(self._scene.sceneRect())
2357

    
2358
                    """
2359
                    # old open drawing
2360
                    path = os.path.join(app_doc_data.getCurrentProject().getTempPath(), app_doc_data.imgName + '.xml')
2361
                    configs = app_doc_data.getConfigs('Data Load', 'Xml First')
2362
                    if configs and int(configs[0].value) >= 1 and os.path.isfile(path):
2363
                        self.load_recognition_result_from_xml(drawing)
2364
                    elif configs and int(configs[0].value) <= 1:
2365
                        self.load_drawing(app_doc_data.activeDrawing)
2366
                    """
2367

    
2368
                    self.display_number_of_items()
2369
                    # connect scene changed signal
2370
                    self.graphicsView.scene().contents_changed.connect(self.scene_changed)
2371
                finally:
2372
                    if hasattr(self, 'progress'):
2373
                        self.progress.setValue(self.progress.maximum())
2374

    
2375
                self.changeViewCheckedState(None)
2376
                self.updateAsViewCheckedState()
2377
                self.setWindowTitle(self.title)
2378
                if not pdf:
2379
                    self.fitWindow(drawing.view_rect)
2380

    
2381
                if ocrUnknown:
2382
                    self.on_ocr_unknown_items()
2383

    
2384
                # save alarm
2385
                if timer:
2386
                    self.save_alarm_enable(True, True)
2387
        except Exception as ex:
2388
            message = f"error occurred({repr(ex)}) in {sys.exc_info()[-1].tb_frame.f_code.co_filename}:" \
2389
                      f"{sys.exc_info()[-1].tb_lineno}"
2390
            self.addMessage.emit(MessageType.Error, message)
2391

    
2392
        return self.path
2393

    
2394
    def save_alarm_enable(self, enable, init=False):
2395
        from datetime import datetime
2396

    
2397
        try:
2398
            app_doc_data = AppDocData.instance()
2399
            configs = app_doc_data.getConfigs('Data Save', 'Time')
2400
            time_min = int(configs[0].value) if 1 == len(configs) else 0
2401

    
2402
            if enable and time_min > 0:
2403
                if not self.save_timer:
2404
                    self.save_timer = QTimer()
2405
                    self.save_timer.timeout.connect(self.save_alarm)
2406
                    self.save_timer.setInterval(60000)
2407

    
2408
                if init:
2409
                    self.save_timer._init_time = datetime.now()
2410
                    self.save_timer._stop_time = None
2411
                    self.save_timer._interval_time = datetime.now() - datetime.now()
2412

    
2413
                if self.save_timer._stop_time:
2414
                    self.save_timer._interval_time = datetime.now() - self.save_timer._stop_time
2415
                
2416
                #if 60000 * time_min != self.save_timer.interval():
2417
                #    self.save_timer.setInterval(60000)
2418

    
2419
                self.save_timer.start()
2420
            else:
2421
                if self.save_timer:
2422
                    self.save_timer.stop()
2423
                    self.save_timer._stop_time = datetime.now()
2424
        
2425
        except Exception as ex:
2426
            message = f"error occurred({repr(ex)}) in {sys.exc_info()[-1].tb_frame.f_code.co_filename}:" \
2427
                      f"{sys.exc_info()[-1].tb_lineno}"
2428
            self.addMessage.emit(MessageType.Error, message)
2429

    
2430
    def save_alarm(self):
2431
        from datetime import datetime
2432

    
2433
        app_doc_data = AppDocData.instance()
2434
        configs = app_doc_data.getConfigs('Data Save', 'Time')
2435
        time_min = int(configs[0].value) if 1 == len(configs) else 0
2436

    
2437
        self.save_timer.stop()
2438
        if self.graphicsView.hasFocus() and (datetime.now() - self.save_timer._init_time - self.save_timer._interval_time).seconds > time_min * 60:
2439
            QMessageBox.information(self, self.tr('Information'), self.tr('Please save Drawing'))
2440
            self.save_timer._init_time = datetime.now()
2441
            self.save_timer._interval_time = datetime.now() - datetime.now()
2442
        self.save_timer.start()
2443

    
2444
    def export_as_svg(self):
2445
        """export scene to svg file"""
2446
        from ExportCommand import ExportCommand
2447

    
2448
        options = QFileDialog.Options()
2449
        options |= QFileDialog.DontUseNativeDialog
2450
        file_path, _ = QFileDialog.getSaveFileName(self, "Export as svg", os.getcwd(), "svg file(*.svg)",
2451
                                                   options=options)
2452
        if file_path:
2453
            cmd = ExportCommand(self.graphicsView.scene(), 'svg')
2454
            cmd.display_message.connect(self.onAddMessage)
2455
            if cmd.execute(file_path):
2456
                QMessageBox.information(self, self.tr('Information'), self.tr('Successfully export to svg file'))
2457
            else:
2458
                QMessageBox.information(self, self.tr('Error'), self.tr('Fail to export to svg file'))
2459

    
2460
    def export_as_xml(self):
2461
        pass
2462

    
2463
    def export_as_image(self):
2464
        """export scene to image file"""
2465
        from ExportCommand import ExportCommand
2466

    
2467
        options = QFileDialog.Options()
2468
        options |= QFileDialog.DontUseNativeDialog
2469
        file_path, _ = QFileDialog.getSaveFileName(self, "Export as png", os.getcwd(), "png file(*.png)",
2470
                                                   options=options)
2471
        if file_path:
2472
            try:
2473
                # hide image drawing
2474
                self.onViewImageDrawing(False)
2475

    
2476
                cmd = ExportCommand(self.graphicsView.scene(), 'image')
2477
                cmd.display_message.connect(self.onAddMessage)
2478

    
2479
                if cmd.execute(file_path):
2480
                    QMessageBox.information(self, self.tr('Information'), self.tr('Successfully export to image file'))
2481
                else:
2482
                    QMessageBox.information(self, self.tr('Error'), self.tr('Fail to export to image file'))
2483
            finally:
2484
                if self.actionImage_Drawing.isChecked():
2485
                    self.onViewImageDrawing(True)
2486
                    self.actionImage_Drawing.setChecked(True)
2487

    
2488
    def show_Progress_bar(self):
2489
        """ show progress bar """
2490
        self.progress = QProgressDialog(self.tr("Please wait for a while"), self.tr("Cancel"), 0, 100,
2491
                                        self) if not hasattr(self, 'progress') else self.progress
2492
        self.progress.setWindowModality(Qt.WindowModal)
2493
        self.progress.setAutoReset(True)
2494
        self.progress.setAutoClose(True)
2495
        self.progress.setMinimum(0)
2496
        self.progress.setMaximum(100)
2497
        self.progress.resize(600, 100)
2498
        self.progress.setWindowTitle(self.tr("Reading file..."))
2499
        self.progress.show()
2500

    
2501
    def changeViewCheckedState(self, checked, clear=True):
2502
        """change view checked state"""
2503
        # self.actionImage_Drawing.setChecked(checked)
2504
        
2505
        '''
2506
        self.actionViewText.setChecked(checked)
2507
        self.actionViewSymbol.setChecked(checked)
2508
        self.actionViewLine.setChecked(checked)
2509
        self.actionViewUnknown.setChecked(checked)
2510
        self.actionViewInconsistency.setChecked(checked)
2511
        self.actionViewVendor_Area.setChecked(not checked)
2512
        self.actionDrawing_Only.setChecked(not checked)
2513
        '''
2514

    
2515
        if checked is not None:
2516
            view_pane = self.ribbon.get_pane('View')
2517
            view_pane.ui.toolButtonViewText.setChecked(checked)
2518
            view_pane.ui.toolButtonViewSymbol.setChecked(checked)
2519
            view_pane.ui.toolButtonViewLine.setChecked(checked)
2520
            view_pane.ui.toolButtonViewUnknown.setChecked(checked)
2521
            view_pane.ui.toolButtonViewInconsistency.setChecked(checked)
2522
            view_pane.ui.toolButtonViewVendorArea.setChecked(checked)
2523
            view_pane.ui.toolButtonViewDrawingOnly.setChecked(not checked)
2524

    
2525
        if clear:
2526
            self.tableWidgetInconsistency.clearContents()
2527
            self.tableWidgetInconsistency.setRowCount(0)
2528

    
2529
    def updateAsViewCheckedState(self):
2530
        view_pane = self.ribbon.get_pane('View')
2531
        self.onViewImageDrawing(view_pane.ui.toolButtonViewImageDrawing.isChecked())
2532
        self.onViewText(view_pane.ui.toolButtonViewText.isChecked())
2533
        self.onViewSymbol(view_pane.ui.toolButtonViewSymbol.isChecked())
2534
        self.onViewLine(view_pane.ui.toolButtonViewLine.isChecked())
2535
        self.onViewUnknown(view_pane.ui.toolButtonViewUnknown.isChecked())
2536
        self.onViewInconsistency(view_pane.ui.toolButtonViewInconsistency.isChecked())
2537
        self.onViewVendorArea(view_pane.ui.toolButtonViewVendorArea.isChecked())
2538
        #self.onViewDrawingOnly(view_pane.ui.toolButtonViewDrawingOnly.isChecked())
2539

    
2540
    def onViewDrawingOnly(self, isChecked):
2541
        '''
2542
            @brief  visible/invisible except image drawing
2543
            @author euisung
2544
            @date   2019.04.22
2545
        '''
2546
        self.changeViewCheckedState(not isChecked, False)
2547
        for item in self.graphicsView.scene().items():
2548
            if type(item) is not QGraphicsPixmapItem and issubclass(type(item), QEngineeringAbstractItem):
2549
                item.setVisible(not isChecked)
2550

    
2551
    '''
2552
        @brief  visible/invisible image drawing
2553
        @author humkyung
2554
        @date   2018.06.25
2555
    '''
2556
    def onViewImageDrawing(self, isChecked):
2557
        for item in self.graphicsView.scene().items():
2558
            if type(item) is QGraphicsPixmapItem:
2559
                item.setVisible(isChecked)
2560
                break
2561

    
2562
    def onViewText(self, checked):
2563
        """visible/invisible text"""
2564
        selected = [item for item in self.graphicsView.scene().items() if issubclass(type(item), QEngineeringTextItem)]
2565
        for item in selected:
2566
            item.setVisible(checked)
2567

    
2568
    def onViewSymbol(self, checked):
2569
        """visible/invisible symbol"""
2570
        selected = [item for item in self.graphicsView.scene().items() if issubclass(type(item), SymbolSvgItem)]
2571
        for item in selected:
2572
            item.setVisible(checked)
2573

    
2574
    def onViewLine(self, checked):
2575
        """visible/invisible line"""
2576
        selected = [item for item in self.graphicsView.scene().items() if type(item) is QEngineeringLineItem]
2577
        for item in selected:
2578
            item.setVisible(checked)
2579

    
2580
    def onViewInconsistency(self, isChecked):
2581
        '''
2582
            @brief  visible/invisible Inconsistency
2583
            @author euisung
2584
            @date   2019.04.03
2585
        '''
2586
        selected = [item for item in self.graphicsView.scene().items() if type(item) is QEngineeringErrorItem]
2587
        for item in selected:
2588
            item.setVisible(isChecked)
2589

    
2590
    '''
2591
        @brief  visible/invisible Unknown 
2592
        @author humkyung
2593
        @date   2018.06.28
2594
    '''
2595
    def onViewUnknown(self, isChecked):
2596
        selected = [item for item in self.graphicsView.scene().items() if type(item) is QEngineeringUnknownItem]
2597
        for item in selected:
2598
            item.setVisible(isChecked)
2599

    
2600
    def onViewVendorArea(self, isChecked):
2601
        '''
2602
            @brief  visible/invisible Vendor Area
2603
            @author euisung
2604
            @date   2019.04.29
2605
        '''
2606
        selected = [item for item in self.graphicsView.scene().items() if issubclass(type(item), QEngineeringVendorItem)]
2607
        for item in selected:
2608
            item.setVisible(isChecked)
2609

    
2610
    '''
2611
        @brief  create a symbol
2612
        @history    2018.05.02  Jeongwoo    Change return value of QSymbolEditorDialog (Single variable → Tuple)
2613
                                            Add SymbolSvgItem
2614
                    2018.05.03  Jeongwoo    Change method to draw Svg Item on Scene (svg.addSvgItemToScene)
2615
                                            Change method to make svg and image path
2616
                    2018.06.08  Jeongwoo    Add Paramter on SymbolSvgItem.buildItem()
2617
    '''
2618
    def onCreateSymbolClicked(self):
2619
        if not self.graphicsView.hasImage():
2620
            self.showImageSelectionMessageBox()
2621
            return
2622

    
2623
        selected = [item for item in self.graphicsView.scene().selectedItems() if issubclass(type(item), QEngineeringVendorItem)]
2624
        if len(selected) == 1:
2625
            symbol_image = AppDocData.instance().activeDrawing.image_origin
2626
            rect = selected[0].sceneBoundingRect()
2627

    
2628
            points = []
2629
            for conn in selected[0].connectors:
2630
                points.append([round(conn.center()[0] - rect.x()), round(conn.center()[1] - rect.y())])
2631
            poly = np.array(points, np.int32)
2632

    
2633
            #mask = np.zeros((int(rect.height()), int(rect.width())))
2634
            #cv2.fillPoly(mask, [poly], (255))
2635
            #poly_copied = np.multiply(mask, symbol_image[round(rect.y()):round(rect.y() + rect.height()),
2636
            #                   round(rect.x()):round(rect.x() + rect.width())])
2637
            #cv2.fillPoly(mask,[poly],0)
2638
            #src2 = np.multiply(mask,src2)
2639

    
2640
            mask = np.ones((int(rect.height()), int(rect.width())), dtype=np.uint8) * 255
2641
            cv2.fillPoly(mask, [poly], (0))
2642
            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())])
2643
            sym_img = cv2.merge((sym_img, sym_img, sym_img))
2644

    
2645
            h, w, c = sym_img.shape
2646
            qImg = QImage(sym_img.data, w, h, w * c, QImage.Format_RGB888)
2647
            #pixmap = QPixmap.fromImage(qImg)
2648

    
2649
            self.onAreaSelected(None, None, None, None, package=qImg, position=rect.topLeft(), package_item=selected[0])
2650
        else:
2651
            cmd = FenceCommand.FenceCommand(self.graphicsView)
2652
            cmd.onSuccess.connect(self.onAreaSelected)
2653
            self.graphicsView.command = cmd
2654
            QApplication.setOverrideCursor(Qt.CrossCursor)
2655

    
2656
    '''
2657
        @brief      show SymbolEditorDialog with image selected by user
2658
        @author     humkyung
2659
        @date       2018.07.20
2660
    '''
2661
    def onAreaSelected(self, x, y, width, height, package=False, position=None, package_item=None):
2662
        try:
2663
            image = self.graphicsView.image()
2664
            if image is not None:
2665
                if not package:
2666
                    symbolEditorDialog = SymbolEditorDialog.QSymbolEditorDialog(self, image.copy(x, y, width, height),
2667
                                                                                AppDocData.instance().getCurrentProject())
2668
                else:
2669
                    symbolEditorDialog = SymbolEditorDialog.QSymbolEditorDialog(self, package,
2670
                                                                                AppDocData.instance().getCurrentProject(), package=True)
2671
                (isAccepted, isImmediateInsert, offsetX, offsetY, newSym) = symbolEditorDialog.showDialog()
2672
                # TODO: not initialize symbol tree view when user reject to create a new symbol
2673
                self.symbolTreeWidget.initSymbolTreeView()
2674
                if isAccepted:
2675
                    if isImmediateInsert:
2676
                        svg = QtImageViewer.createSymbolObject(newSym.getName())
2677
                        offsetX, offsetY = [int(point) for point in newSym.getOriginalPoint().split(',')]
2678
                        QtImageViewer.matchSymbolToLine(self.graphicsView.scene(), svg, QPoint(position.x() + offsetX, position.y() + offsetY))
2679

    
2680
                        package_item.transfer.onRemoved.emit(package_item)
2681
        finally:
2682
            self.onCommandRejected()
2683
            QApplication.restoreOverrideCursor()
2684
            QApplication.restoreOverrideCursor()
2685

    
2686
    def on_line_list(self):
2687
        """ line list export dialog """
2688
        from LineListDialog import LineListDialog
2689

    
2690
        if not self.graphicsView.hasImage():
2691
            self.showImageSelectionMessageBox()
2692
            return
2693

    
2694
        dialog = LineListDialog(self)
2695
        dialog.showDialog()
2696

    
2697
    def on_make_label_data(self):
2698
        """ make label data from symbol info """
2699
        from xml.etree.ElementTree import Element, SubElement, dump, ElementTree, parse
2700

    
2701
        if not self.graphicsView.hasImage():
2702
            self.showImageSelectionMessageBox()
2703
            return
2704

    
2705
        app_doc_data = AppDocData.instance()
2706
        project = app_doc_data.getCurrentProject()
2707

    
2708
        smalls = []
2709
        bigs = []
2710

    
2711
        symbol_list = app_doc_data.getTargetSymbolList(all=True)
2712
        #symbol_list = app_doc_data.getTargetSymbolList(all=False)
2713
        for symbol in symbol_list:
2714
            if symbol.iType == 38 or symbol.iType == 33 or symbol.iType == 0 or symbol.iType == 40:
2715
                continue
2716
            elif symbol.width and symbol.height:
2717
                if symbol.width > 300 or symbol.height > 300:
2718
                    bigs.append(symbol.getName())
2719
                elif (symbol.width * symbol.height < 1500) or (symbol.width > 450 or symbol.height > 450):
2720
                    continue
2721
                else:
2722
                    smalls.append(symbol.getName())
2723

    
2724
        symbols = [item for item in self.graphicsView.scene().items() if issubclass(type(item), SymbolSvgItem)]
2725
        names = [smalls, bigs]
2726

    
2727
        img = app_doc_data.activeDrawing.image_origin
2728

    
2729
        small_size = 500
2730
        big_size = 850
2731

    
2732
        save_path = project.getTrainingSymbolFilePath()
2733

    
2734
        index = 0
2735
        for size in [small_size, big_size]:
2736
            offsets = [0, int(size / 2)]
2737

    
2738
            width, height = img.shape[1], img.shape[0]
2739
            width_count, height_count = width // size + 2, height // size + 2
2740
            b_width, b_height = width_count * size, height_count * size
2741
            b_img = np.zeros((b_height, b_width), np.uint8) + 255
2742
            b_img[:height, :width] = img[:, :]
2743

    
2744
            for offset in offsets:
2745
                for row in range(height_count):
2746
                    for col in range(width_count):
2747
                        x, y = col * size + offset, row * size + offset
2748
                        tile_rect = QRectF(x, y, size, size)
2749
                        tile_symbols = []
2750
                        for symbol in [symbol for symbol in symbols if symbol.name in names[index]]:
2751
                            if tile_rect.contains(symbol.sceneBoundingRect()):
2752
                                tile_symbols.append(symbol)
2753
                                symbols.remove(symbol)
2754

    
2755
                        if tile_symbols:
2756
                            training_uid = str(uuid.uuid4())
2757
                            training_image_path = os.path.join(save_path, training_uid + '.png')
2758
                            training_xml_path = os.path.join(save_path, training_uid + '.xml')
2759

    
2760
                            # save image
2761
                            #_img = b_img[round(tile_rect.top()):round(tile_rect.bottom()),
2762
                            #       round(tile_rect.left()):round(tile_rect.right())]
2763
                            #cv2.imwrite(training_image_path, _img)
2764
                            _img = self.graphicsView.image().copy(round(tile_rect.left()), round(tile_rect.top()), round(tile_rect.width()), round(tile_rect.height()))
2765
                            _img.save(training_image_path)
2766

    
2767
                            # save label
2768
                            xml = Element('annotation')
2769
                            SubElement(xml, 'folder').text = 'None'
2770
                            SubElement(xml, 'filename').text = os.path.basename(save_path)
2771

    
2772
                            pathNode = Element('path')
2773
                            pathNode.text = save_path.replace('/', '\\')
2774
                            xml.append(pathNode)
2775

    
2776
                            sourceNode = Element('source')
2777
                            databaseNode = Element('database')
2778
                            databaseNode.text = 'Unknown'
2779
                            sourceNode.append(databaseNode)
2780
                            xml.append(sourceNode)
2781

    
2782
                            sizeNode = Element('size')
2783
                            widthNode = Element('width')
2784
                            widthNode.text = str(int(tile_rect.width()))
2785
                            sizeNode.append(widthNode)
2786
                            heightNode = Element('height')
2787
                            heightNode.text = str(int(tile_rect.height()))
2788
                            sizeNode.append(heightNode)
2789
                            depthNode = Element('depth')
2790
                            depthNode.text = '3'
2791
                            sizeNode.append(depthNode)
2792
                            xml.append(sizeNode)
2793

    
2794
                            segmentedNode = Element('segmented')
2795
                            segmentedNode.text = '0'
2796
                            xml.append(segmentedNode)
2797

    
2798
                            labelContent = []
2799
                            counts = {}
2800
                            for item in tile_symbols:
2801
                                rect = item.sceneBoundingRect()
2802
                                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)
2803
                                #label = 'small' if index == 0 else 'big' # for single class test
2804
                                xMin = xMin if xMin > 0 else 0
2805
                                yMin = yMin if yMin > 0 else 0
2806
                                xMax = xMax if xMax < size else size
2807
                                yMax = yMax if yMax < size else size
2808

    
2809
                                if label == 'None' or label == '':
2810
                                    continue
2811
                                if label not in labelContent:
2812
                                    labelContent.append(label)
2813
                                    counts[label] = 1
2814
                                else:
2815
                                    counts[label] = counts[label] + 1
2816

    
2817
                                objectNode = Element('object')
2818
                                nameNode = Element('name')
2819
                                nameNode.text = label
2820
                                objectNode.append(nameNode)
2821
                                poseNode = Element('pose')
2822
                                poseNode.text = 'Unspecified'
2823
                                objectNode.append(poseNode)
2824
                                truncatedNode = Element('truncated')
2825
                                truncatedNode.text = '0'
2826
                                objectNode.append(truncatedNode)
2827
                                difficultNode = Element('difficult')
2828
                                difficultNode.text = '0'
2829
                                objectNode.append(difficultNode)
2830

    
2831
                                bndboxNode = Element('bndbox')
2832
                                xminNode = Element('xmin')
2833
                                xminNode.text = str(xMin)
2834
                                bndboxNode.append(xminNode)
2835
                                yminNode = Element('ymin')
2836
                                yminNode.text = str(yMin)
2837
                                bndboxNode.append(yminNode)
2838
                                xmaxNode = Element('xmax')
2839
                                xmaxNode.text = str(xMax)
2840
                                bndboxNode.append(xmaxNode)
2841
                                ymaxNode = Element('ymax')
2842
                                ymaxNode.text = str(yMax)
2843
                                bndboxNode.append(ymaxNode)
2844
                                objectNode.append(bndboxNode)
2845

    
2846
                                xml.append(objectNode)
2847

    
2848
                            ElementTree(xml).write(training_xml_path)
2849

    
2850
            index += 1
2851

    
2852
        QMessageBox.about(self, self.tr("Notice"), self.tr('Successfully applied. '))
2853

    
2854
    def onPlaceLine(self):
2855
        """create a line"""
2856
        home_pane = self.ribbon.get_pane('Home')
2857

    
2858
        if not self.graphicsView.hasImage():
2859
            home_pane.ui.toolButtonLine.setChecked(False)
2860
            self.showImageSelectionMessageBox()
2861
            return
2862

    
2863
        self.update_action_group(home_pane.ui.toolButtonLine)
2864
        if not hasattr(home_pane.ui.toolButtonLine, 'tag'):
2865
            home_pane.ui.toolButtonLine.tag = PlaceLineCommand.PlaceLineCommand(self.graphicsView)
2866
            home_pane.ui.toolButtonLine.tag.onSuccess.connect(self.onLineCreated)
2867
            home_pane.ui.toolButtonLine.tag.onRejected.connect(self.onCommandRejected)
2868

    
2869
        self.graphicsView.command = home_pane.ui.toolButtonLine.tag
2870

    
2871
    def onLineCreated(self):
2872
        """add created lines to scene"""
2873
        from EngineeringConnectorItem import QEngineeringConnectorItem
2874
        from LineDetector import LineDetector
2875

    
2876
        try:
2877
            app_doc_data = AppDocData.instance()
2878
            home_pane = self.ribbon.get_pane('Home')
2879

    
2880
            count = len(home_pane.ui.toolButtonLine.tag._polyline._vertices)
2881
            if count > 1:
2882
                items = []
2883

    
2884
                detector = LineDetector(None)
2885

    
2886
                if not home_pane.ui.toolButtonLine.tag.line_type:
2887
                    line_type = home_pane.ui.comboBoxLineType.currentText()
2888
                else:
2889
                    pane = self.ribbon.get_pane('Home')
2890
                    selected_line_type = pane.ui.comboBoxLineType.currentText()
2891
                    if selected_line_type == 'Connect To Process':
2892
                        line_type = selected_line_type
2893
                    elif not (QEngineeringLineItem.check_piping(home_pane.ui.toolButtonLine.tag.line_type) ^
2894
                              QEngineeringLineItem.check_piping(selected_line_type)):
2895
                        line_type = selected_line_type
2896
                    else:
2897
                        line_type = home_pane.ui.toolButtonLine.tag.line_type
2898
                for index in range(count - 1):
2899
                    start = home_pane.ui.toolButtonLine.tag._polyline._vertices[index]
2900
                    end = home_pane.ui.toolButtonLine.tag._polyline._vertices[index + 1]
2901

    
2902
                    lineItem = QEngineeringLineItem(vertices=[start, end])
2903
                    lineItem.transfer.onRemoved.connect(self.itemRemoved)
2904
                    lineItem.lineType = line_type
2905
                    if items:
2906
                        lineItem.connect_if_possible(items[-1], 5)
2907
                    else:
2908
                        pt = lineItem.start_point()
2909
                        selected = [item for item in self.graphicsView.scene().items(QPointF(pt[0], pt[1])) if
2910
                                    type(item) is QEngineeringConnectorItem or type(item) is QEngineeringLineItem]
2911
                        if selected and selected[0] is not lineItem:
2912
                            if type(selected[0]) is QEngineeringConnectorItem:
2913
                                lineItem.connect_if_possible(selected[0].parent, 5)
2914
                            else:
2915
                                detector.connectLineToLine(selected[0], lineItem, 5)
2916

    
2917
                    items.append(lineItem)
2918
                    self.graphicsView.scene().addItem(lineItem)
2919

    
2920
                pt = items[-1].end_point()
2921
                selected = [item for item in self.graphicsView.scene().items(QPointF(pt[0], pt[1])) if
2922
                            (type(item) is QEngineeringConnectorItem and item.parentItem() is not items[-1]) or
2923
                            (type(item) is QEngineeringLineItem and item is not items[-1])]
2924
                if selected and selected[0] is not items[-1]:
2925
                    if type(selected[0]) is QEngineeringConnectorItem:
2926
                        items[-1].connect_if_possible(selected[0].parent, 5)
2927
                    else:
2928
                        detector.connectLineToLine(selected[0], items[-1], 5)
2929

    
2930
                self._scene.undo_stack.push(CreateCommand(self._scene, items))
2931
        finally:
2932
            self.graphicsView.scene().removeItem(home_pane.ui.toolButtonLine.tag._polyline)
2933
            home_pane.ui.toolButtonLine.tag.reset()
2934

    
2935
    def onCommandRejected(self, cmd=None):
2936
        """command is rejected"""
2937
        try:
2938
            home_pane = self.ribbon.get_pane('Home')
2939
            visualization_pane = self.ribbon.get_pane('Home Visualization')
2940
            if type(cmd) is PlaceLineCommand.PlaceLineCommand:
2941
                if home_pane.ui.toolButtonLine.tag._polyline:
2942
                    self.graphicsView.scene().removeItem(home_pane.ui.toolButtonLine.tag._polyline)
2943
                self.graphicsView.scene().update()
2944
                home_pane.ui.toolButtonLine.tag.reset()
2945

    
2946
                home_pane.ui.toolButtonLine.setChecked(False)
2947
            elif type(cmd) is AreaZoomCommand.AreaZoomCommand:
2948
                visualization_pane.ui.toolButtonZoom.setChecked(False)
2949
            elif type(cmd) is AreaOcrCommand.AreaOcrCommand:
2950
                home_pane.ui.toolButtonOCR.setChecked(False)
2951
            elif type(cmd) is PlacePolygonCommand.PlacePolygonCommand:
2952
                home_pane.ui.toolButtonVendor.setChecked(False)
2953
            else:
2954
                if hasattr(home_pane.ui.toolButtonVendor, 'tag') and home_pane.ui.toolButtonVendor.tag._polyline:
2955
                    self.graphicsView.scene().removeItem(home_pane.ui.toolButtonVendor.tag._polyline)
2956
                    self.graphicsView.scene().update()
2957
                    home_pane.ui.toolButtonVendor.tag.reset()
2958
                home_pane.ui.toolButtonLine.setChecked(False)
2959
                visualization_pane.ui.toolButtonZoom.setChecked(False)
2960
                home_pane.ui.toolButtonOCR.setChecked(False)
2961
                home_pane.ui.toolButtonVendor.setChecked(False)
2962
        finally:
2963
            self.graphicsView.useDefaultCommand()
2964

    
2965
    def on_view_toggle(self, key: int) -> None:
2966
        """view toggled"""
2967

    
2968
        view_pane = self.ribbon.get_pane('View')
2969
        if key == Qt.Key_1:
2970
            checked = view_pane.ui.toolButtonViewImageDrawing.isChecked()
2971
            self.onViewImageDrawing(not checked)
2972
            view_pane.ui.toolButtonViewImageDrawing.setChecked(not checked)
2973
        elif key == Qt.Key_2:
2974
            checked = view_pane.ui.toolButtonViewText.isChecked()
2975
            self.onViewText(not checked)
2976
            view_pane.ui.toolButtonViewText.setChecked(not checked)
2977
        elif key == Qt.Key_3:
2978
            checked = view_pane.ui.toolButtonViewSymbol.isChecked()
2979
            self.onViewSymbol(not checked)
2980
            view_pane.ui.toolButtonViewSymbol.setChecked(not checked)
2981
        elif key == Qt.Key_4:
2982
            checked = view_pane.ui.toolButtonViewLine.isChecked()
2983
            self.onViewLine(not checked)
2984
            view_pane.ui.toolButtonViewLine.setChecked(not checked)
2985
        elif key == Qt.Key_5:
2986
            checked = view_pane.ui.toolButtonViewUnknown.isChecked()
2987
            self.onViewUnknown(not checked)
2988
            view_pane.ui.toolButtonViewUnknown.setChecked(not checked)
2989
        elif key == Qt.Key_6:
2990
            checked = view_pane.ui.toolButtonViewInconsistency.isChecked()
2991
            self.onViewInconsistency(not checked)
2992
            view_pane.ui.toolButtonViewInconsistency.setChecked(not checked)
2993
        elif key == Qt.Key_7:
2994
            checked = view_pane.ui.toolButtonViewVendorArea.isChecked()
2995
            self.onViewVendorArea(not checked)
2996
            view_pane.ui.toolButtonViewVendorArea.setChecked(not checked)
2997
        elif key == 96:  # '~' key
2998
            checked = view_pane.ui.toolButtonViewDrawingOnly.isChecked()
2999
            self.onViewDrawingOnly(not checked)
3000
            view_pane.ui.toolButtonViewDrawingOnly.setChecked(not checked)
3001

    
3002
    def keyPressEvent(self, event):
3003
        """restore to default command when user press Escape key"""
3004
        try:
3005
            #print('main : ' + str(event.key()))
3006
            if event.key() == Qt.Key_Escape:
3007
                checked = self.checked_action()
3008
                if checked:
3009
                    checked.setChecked(False)
3010
                    self.graphicsView.useDefaultCommand()
3011
            elif event.key() == Qt.Key_M:  # merge text, line
3012
                from TextInfo import TextInfo
3013
                from EngineeringConnectorItem import QEngineeringConnectorItem
3014
                from LineDetector import LineDetector
3015

    
3016
                # line merge
3017
                lineItems = [line for line in self.graphicsView.scene().selectedItems() if
3018
                             issubclass(type(line), QEngineeringLineItem)]
3019
                lineValidation = True
3020
                if len(lineItems) > 1:
3021
                    x = []
3022
                    y = []
3023
                    connectedItems = []
3024
                    isVertical = None
3025
                    for line in lineItems:
3026
                        if isVertical == None:
3027
                            isVertical = line.isVertical()
3028
                        elif isVertical != line.isVertical():
3029
                            lineValidation = False
3030

    
3031
                        x.append(line.start_point()[0])
3032
                        y.append(line.start_point()[1])
3033
                        x.append(line.end_point()[0])
3034
                        y.append(line.end_point()[1])
3035

    
3036
                        if line.connectors[0].connectedItem:
3037
                            connectedItems.append(line.connectors[0].connectedItem)
3038
                        if line.connectors[1].connectedItem:
3039
                            connectedItems.append(line.connectors[1].connectedItem)
3040

    
3041
                    if lineValidation:
3042
                        startPoint = [min(x), min(y)]
3043
                        endPoint = [max(x), max(y)]
3044
                        lineItem = QEngineeringLineItem(vertices=[startPoint, endPoint])
3045
                        lineItem.transfer.onRemoved.connect(self.itemRemoved)
3046
                        lineItem.lineType = lineItems[0].lineType
3047

    
3048
                        for line in lineItems:
3049
                            line.transfer.onRemoved.emit(line)
3050

    
3051
                        detector = LineDetector(None)
3052

    
3053
                        for pt in [startPoint, endPoint]:
3054
                            selected = [item for item in self.graphicsView.scene().items(QPointF(pt[0], pt[1])) if
3055
                                        type(item) is QEngineeringConnectorItem or type(item) is QEngineeringLineItem]
3056
                            if selected:
3057
                                if type(selected[0]) is QEngineeringConnectorItem:
3058
                                    lineItem.connect_if_possible(selected[0].parent, 5)
3059
                                elif selected[0] in connectedItems:
3060
                                    lineItem.connect_if_possible(selected[0], 5)
3061
                                else:
3062
                                    detector.connectLineToLine(selected[0], lineItem, 5)
3063

    
3064
                        self.graphicsView.scene().addItem(lineItem)
3065
                # up to here
3066

    
3067
                # text merge
3068
                textItems = [text for text in self.graphicsView.scene().selectedItems() if
3069
                             issubclass(type(text), QEngineeringTextItem)]
3070
                if len(textItems) > 1:
3071
                    angle = None
3072
                    for item in textItems:
3073
                        if angle is None:
3074
                            angle = item.angle
3075
                        else:
3076
                            if angle != item.angle:
3077
                                return
3078

    
3079
                    modifiers = QApplication.keyboardModifiers()
3080
                    enter_or_space = ' ' if modifiers == Qt.ControlModifier else ('\n' if modifiers != Qt.AltModifier else '')
3081
                    x_or_y = 0 if (modifiers == Qt.ControlModifier and angle == 0) or (modifiers != Qt.ControlModifier and angle == 1.57) else 1
3082

    
3083
                    textItems = sorted(textItems, key=lambda text: text.loc[x_or_y]) if textItems[0].angle == 0 else ( \
3084
                        sorted(textItems, key=lambda text: text.loc[x_or_y]) if textItems[0].angle == 1.57 else ( \
3085
                            sorted(textItems, key=lambda text: text.loc[x_or_y], reverse=True) if textItems[0].angle == 4.71 else \
3086
                                sorted(textItems, key=lambda text: text.loc[x_or_y], reverse=True)))
3087

    
3088
                    if textItems[0].angle == 1.57 and modifiers == Qt.ControlModifier:
3089
                        textItems.reverse()
3090

    
3091
                    minX = sys.maxsize
3092
                    minY = sys.maxsize
3093
                    maxX = 0
3094
                    maxY = 0
3095
                    newText = ''
3096

    
3097
                    for text in textItems:
3098
                        if text.loc[0] < minX: minX = text.loc[0]
3099
                        if text.loc[1] < minY: minY = text.loc[1]
3100
                        if text.loc[0] + text.size[0] > maxX: maxX = text.loc[0] + text.size[0]
3101
                        if text.loc[1] + text.size[1] > maxY: maxY = text.loc[1] + text.size[1]
3102
                        newText = newText + text.text() + enter_or_space
3103
                        text.transfer.onRemoved.emit(text)
3104
                    newText = newText[:-1]
3105

    
3106
                    textInfo = TextInfo(newText, minX, minY, maxX - minX, maxY - minY, textItems[0].angle)
3107
                    item = QEngineeringTextItem.create_text_with(self.graphicsView.scene(), textInfo)
3108
                    if item is not None:
3109
                        item.area = textItems[0].area
3110
                        #item.setDefaultTextColor(Qt.blue)
3111
                        item.transfer.onRemoved.connect(self.itemRemoved)
3112
                # up to here
3113
            elif event.key() == Qt.Key_D:
3114
                # pop up development toolkit dialog
3115
                from DevelopmentToolkitDialog import QDevelopmentToolkitDialog
3116

    
3117
                modifiers = QApplication.keyboardModifiers()
3118
                if modifiers == Qt.ControlModifier:
3119
                    dlg = QDevelopmentToolkitDialog(self, self.graphicsView)
3120
                    dlg.show()
3121
            elif event.key() == Qt.Key_I:
3122
                # insert symbol item that is selected symbol in tree to main window if symbol already selected on main window, replace
3123
                index = self.symbolTreeWidget.currentIndex()
3124
                proxy_model = self.symbolTreeWidget.model()
3125
                items = [proxy_model.sourceModel().itemFromIndex(proxy_model.mapToSource(index))]
3126
                if items and hasattr(items[0], 'svgFilePath'):
3127
                    symData = items[0].data(self.symbolTreeWidget.TREE_DATA_ROLE)
3128
                    symName = symData.getName()
3129
                else:
3130
                    return
3131

    
3132
                symbolItems = [symbol for symbol in self.graphicsView.scene().selectedItems() if
3133
                               issubclass(type(symbol), SymbolSvgItem)]
3134
                old_symbols = []
3135
                if symbolItems and len(symbolItems) >= 1:
3136
                    for old_symbol in symbolItems:
3137
                        #old_symbol = symbolItems[0]
3138
                        #scenePos = QPoint(old_symbol.origin[0], old_symbol.origin[1])
3139
                        scenePos = old_symbol.mapToScene(old_symbol.transformOriginPoint())
3140
                        old_symbols.append([old_symbol, scenePos])
3141
                        old_symbol.transfer.onRemoved.emit(old_symbol)
3142
                else:
3143
                    scenePos = self.current_pos
3144
                    old_symbols.append([None, scenePos])
3145

    
3146
                for old_symbol in old_symbols:
3147
                    svg = QtImageViewer.createSymbolObject(symName)
3148
                    QtImageViewer.matchSymbolToLine(self.graphicsView.scene(), svg, old_symbol[1], angle=old_symbol[0].angle if old_symbol[0] else 0.0)
3149
                    svg.bind_close_items()
3150

    
3151
                if old_symbols and svg:
3152
                    from ReplaceCommand import ReplaceCommand
3153

    
3154
                    for old_symbol in old_symbols:
3155
                        cmd = ReplaceCommand(self.graphicsView.scene(), old_symbol, svg)
3156
                        self._scene.undo_stack.push(cmd)
3157
                    return
3158
            elif event.key() == Qt.Key_J:
3159
                # insert and connect symbol item that is selected symbol in tree to selected symbol
3160
                index = self.symbolTreeWidget.currentIndex()
3161
                proxy_model = self.symbolTreeWidget.model()
3162
                items = [proxy_model.sourceModel().itemFromIndex(proxy_model.mapToSource(index))]
3163
                if items and hasattr(items[0], 'svgFilePath'):
3164
                    symData = items[0].data(self.symbolTreeWidget.TREE_DATA_ROLE)
3165
                    symName = symData.getName()
3166
                else:
3167
                    return
3168

    
3169
                symbolItems = [symbol for symbol in self.graphicsView.scene().selectedItems() if
3170
                               issubclass(type(symbol), SymbolSvgItem)]
3171
                if len(symbolItems) is not 1:
3172
                    return
3173
                    
3174
                target_symbol = symbolItems[0]
3175
                index =  [index for index in range(len(target_symbol.conn_type)) \
3176
                            if QEngineeringLineItem.check_piping(target_symbol.conn_type[index], True)]
3177
                for connector in target_symbol.connectors:
3178
                    svg = QtImageViewer.createSymbolObject(symName)
3179
                    if len(svg.connectors) > 1: 
3180
                        if ((target_symbol.conn_type and target_symbol.connectors.index(connector) in index) or not target_symbol.conn_type) and \
3181
                                    (not connector.connectedItem or (connector.connectedItem and type(connector.connectedItem) is QEngineeringLineItem)):
3182
                            QtImageViewer.matchSymbolToLine(self.graphicsView.scene(), svg, connector.sceneBoundingRect().center())
3183
                    elif len(svg.connectors) == 1:
3184
                        if ((target_symbol.conn_type and target_symbol.connectors.index(connector) in index) or not target_symbol.conn_type) and \
3185
                                    not connector.connectedItem:
3186
                            QtImageViewer.matchSymbolToLine(self.graphicsView.scene(), svg, connector.sceneBoundingRect().center())
3187

    
3188
                if target_symbol:
3189
                    return
3190
            elif event.key() == Qt.Key_X:
3191
                pass
3192
                '''
3193
                app_doc_data = AppDocData.instance()
3194
                configs = app_doc_data.getAppConfigs('app', 'mode')
3195
                if configs and 1 == len(configs) and 'advanced' == configs[0].value:
3196
                    advanced = True
3197
                    items = self.graphicsView.scene().selectedItems()
3198
                    if items:
3199
                        item = self.symbolTreeWidget.currentItem()
3200
                        if item:
3201
                            self.symbolTreeWidget.showSymbolEditorDialog(item, 0)
3202
                '''
3203
            elif event.key() == Qt.Key_F6:
3204
                from DEXPI import scene_to_dexpi
3205

    
3206
                app_doc_data = AppDocData.instance()
3207
                scene_to_dexpi('D:\\Temp\\DEXPI.xml', app_doc_data.activeDrawing.name, self.graphicsView.scene())
3208

    
3209
            QMainWindow.keyPressEvent(self, event)
3210
        except Exception as ex:
3211
            message = f"error occurred({repr(ex)}) in {sys.exc_info()[-1].tb_frame.f_code.co_filename}:" \
3212
                      f"{sys.exc_info()[-1].tb_lineno}"
3213
            self.addMessage.emit(MessageType.Error, message)
3214

    
3215
    def recognizeSymbol(self):
3216
        # save alarm
3217
        self.save_alarm_enable(False)
3218

    
3219
        if not self.graphicsView.hasImage():
3220
            self.showImageSelectionMessageBox()
3221
            return
3222
        
3223
        app_doc_data = AppDocData.instance()
3224
        
3225
        current_drawing = app_doc_data.activeDrawing
3226
        checked_drawings = {}
3227
        drawing_top = self.treeWidgetDrawingList.topLevelItem(0)
3228

    
3229
        for idx in range(drawing_top.childCount()):
3230
            child = drawing_top.child(idx)
3231
            if child.data(Qt.UserRole, 0) is current_drawing:
3232
                checked_drawings[child.data(Qt.UserRole, 0)] = child
3233

    
3234
        try:
3235
            self.on_clear_log()
3236
            dlg = QRecognitionDialog(self, [drawing for drawing in checked_drawings.keys()], symbolOnly=True)
3237
            dlg.exec_()
3238

    
3239
            self.changeViewCheckedState(True)
3240
        except Exception as ex:
3241
            message = f"error occurred({repr(ex)}) in {sys.exc_info()[-1].tb_frame.f_code.co_filename}:" \
3242
                      f"{sys.exc_info()[-1].tb_lineno}"
3243
            self.addMessage.emit(MessageType.Error, message)
3244

    
3245
        # save alarm
3246
        self.save_alarm_enable(True, True)
3247

    
3248
    def recognize(self):
3249
        """recognize symbol, text and line for selected drawings"""
3250
        from datetime import datetime
3251
        from License import QLicenseDialog
3252

    
3253
        # save alarm
3254
        self.save_alarm_enable(False)
3255

    
3256
        app_doc_data = AppDocData.instance()
3257
        current_drawing, currentPid = None, None
3258

    
3259
        if self.graphicsView.hasImage():
3260
            current_drawing = app_doc_data.activeDrawing
3261
            currentPid = app_doc_data.activeDrawing.name
3262

    
3263
        # get checked drawings
3264
        drawing_top = self.treeWidgetDrawingList.topLevelItem(0)
3265
        count = drawing_top.childCount()
3266
        checked_drawings = {}
3267
        for idx in range(count):
3268
            child = drawing_top.child(idx)
3269
            if child.checkState(0) == Qt.Checked and child.data(Qt.UserRole, 0):
3270
                checked_drawings[child.data(Qt.UserRole, 0)] = child
3271
        # up to here
3272

    
3273
        # if there is no checked drawing
3274
        if current_drawing and currentPid and not checked_drawings:
3275
            for idx in range(count):
3276
                child = drawing_top.child(idx)
3277
                if child.data(Qt.UserRole, 0) is current_drawing:
3278
                    checked_drawings[child.data(Qt.UserRole, 0)] = child
3279

    
3280
        if not checked_drawings:
3281
            self.showImageSelectionMessageBox()
3282
            return
3283

    
3284
        try:
3285
            self.on_clear_log()
3286
            dlg = QRecognitionDialog(self, [drawing for drawing in checked_drawings.keys()])
3287
            dlg.exec_()
3288

    
3289
            if current_drawing and current_drawing in checked_drawings.keys() and dlg.isTreated:
3290
                self.open_image_drawing(current_drawing, force=True, ocrUnknown=dlg.ui.checkBoxOCRUnknown.isChecked())
3291

    
3292
            # save working date-time
3293
            _now = datetime.now().strftime('%Y-%m-%d %H:%M:%S')
3294
            for drawing, tree_item in checked_drawings.items():
3295
                drawing.datetime = _now
3296
                tree_item.setText(1, _now)
3297
            #app_doc_data.saveDrawings(checked_drawings.keys())
3298
            # up to here
3299

    
3300
            self.changeViewCheckedState(True)
3301

    
3302
            # count up for recognition
3303
            QLicenseDialog.count_up()
3304
            # up to here
3305
        except Exception as ex:
3306
            message = f"error occurred({repr(ex)}) in {sys.exc_info()[-1].tb_frame.f_code.co_filename}:" \
3307
                      f"{sys.exc_info()[-1].tb_lineno}"
3308
            self.addMessage.emit(MessageType.Error, message)
3309

    
3310
        # save alarm
3311
        self.save_alarm_enable(True, True)
3312

    
3313
    '''
3314
        @brief      remove item from tree widget and then remove from scene
3315
        @date       2018.05.25
3316
        @author     Jeongwoo
3317
    '''
3318
    def itemRemoved(self, item):
3319
        try:
3320
            if type(item) is QEngineeringErrorItem:
3321
                # remove error item from inconsistency list
3322
                for row in range(self.tableWidgetInconsistency.rowCount()):
3323
                    if item is self.tableWidgetInconsistency.item(row, 0).tag:
3324
                        self.tableWidgetInconsistency.removeRow(row)
3325
                        break
3326

    
3327
                if item.scene() is not None:
3328
                    item.scene().removeItem(item)
3329
                del item
3330
            else:
3331
                remove_scene = item.scene()
3332

    
3333
                if remove_scene:
3334
                    matches = [_item for _item in remove_scene.items() if
3335
                            hasattr(_item, 'connectors') and [connector for connector in _item.connectors if
3336
                                                                connector.connectedItem is item]]
3337
                    for match in matches:
3338
                        for connector in match.connectors:
3339
                            if connector.connectedItem is item:
3340
                                connector.connectedItem = None
3341
                                connector.highlight(False)
3342

    
3343
                # matches = [_item for _item in self.graphicsView.scene().items() if hasattr(_item, 'remove_assoc_item')]
3344
                # for _item in matches:
3345
                #    _item.remove_assoc_item(item)
3346

    
3347
                app_doc_data = AppDocData.instance()
3348
                if type(item) is QEngineeringLineNoTextItem:
3349
                    self.itemTreeWidget.explode_line_no_from_context(item)
3350

    
3351
                if type(item) is QEngineeringLineNoTextItem and item in app_doc_data.tracerLineNos:
3352
                    app_doc_data.tracerLineNos.pop(app_doc_data.tracerLineNos.index(item))
3353

    
3354
                if type(item) is QEngineeringLineItem and item in app_doc_data.lines:
3355
                    app_doc_data.lines.remove(item)
3356

    
3357
                if remove_scene:
3358
                    matches = [_item for _item in remove_scene.items() if type(_item) is QEngineeringLineNoTextItem]
3359
                    matches.extend([lineNo for lineNo in app_doc_data.tracerLineNos if
3360
                                    type(lineNo) is QEngineeringTrimLineNoTextItem])
3361
                    for match in matches:
3362
                        if item is match.prop('From'):
3363
                            match.set_property('From', None)
3364
                        if item is match.prop('To'):
3365
                            match.set_property('To', None)
3366

    
3367
                        for run_index in reversed(range(len(match.runs))):
3368
                            run = match.runs[run_index]
3369
                            if item in run.items:
3370
                                index = run.items.index(item)
3371
                                run.items.pop(index)
3372
                                if not run.items:
3373
                                    run.explode()
3374
                                    if type(match) is QEngineeringTrimLineNoTextItem and not match.runs:
3375
                                        app_doc_data.tracerLineNos.pop(app_doc_data.tracerLineNos.index(match))
3376
                                # break
3377

    
3378
                if remove_scene:
3379
                    matches = [_item for _item in remove_scene.items() if hasattr(_item, 'owner')]
3380
                    for match in matches:
3381
                        if match.owner is item:
3382
                            match.owner = None
3383

    
3384
                    matches = [_item for _item in remove_scene.items() if hasattr(_item, 'attrs')]
3385
                    # done = False
3386
                    for match in matches:
3387
                        assocs = match.associations()
3388
                        for assoc in assocs:
3389
                            if item is assoc:
3390
                                keys = match.attrs.keys()
3391
                                for attr in keys:
3392
                                    if attr.AssocItem and str(item.uid) == str(attr.AssocItem.uid):
3393
                                        attr.AssocItem = None
3394
                                        match.attrs[attr] = ''
3395
                                        # done = True
3396
                                match.remove_assoc_item(item)
3397
                                break
3398
                        # if done: break
3399

    
3400
                if remove_scene:
3401
                    #if type(item) is QEngineeringLineNoTextItem and item._labels:
3402
                    #    for _label in item._labels:
3403
                    #        item.scene().removeItem(_label)
3404
                    #    item._labels = []
3405
                    
3406
                    item.hoverLeaveEvent(None)
3407
                    if hasattr(item, 'lineNoFromToIndicator') and item.lineNoFromToIndicator:
3408
                        remove_scene.removeItem(item.lineNoFromToIndicator[0])
3409
                        if len(item.lineNoFromToIndicator) > 1:
3410
                            remove_scene.removeItem(item.lineNoFromToIndicator[1])
3411
                    remove_scene.removeItem(item)
3412

    
3413
                self.itemTreeWidget.itemRemoved(item)
3414
        except Exception as ex:
3415
            message = 'error occurred({}) in {}:{}'.format(ex, sys.exc_info()[-1].tb_frame.f_code.co_filename,
3416
                                                           sys.exc_info()[-1].tb_lineno)
3417
            self.addMessage.emit(MessageType.Error, message)
3418
        '''
3419
        finally:
3420
            if hasattr(item, '_cond'):
3421
                item._cond.wakeAll()
3422
        '''
3423

    
3424
    def connect_attributes(self, MainWindow):
3425
        """connect attributes to symbol"""
3426
        from ConnectAttrDialog import QConnectAttrDialog
3427

    
3428
        if not self.graphicsView.hasImage():
3429
            self.showImageSelectionMessageBox()
3430
            return
3431

    
3432
        # save alarm
3433
        self.save_alarm_enable(False)
3434

    
3435
        try:
3436
            dlg = QConnectAttrDialog(self, self.graphicsView.scene())
3437
            dlg.setWindowFlags(self.windowFlags() & ~Qt.WindowCloseButtonHint & ~Qt.WindowContextHelpButtonHint)
3438
            dlg.exec_()
3439
            if dlg.isRunned:
3440
                self.refresh_item_list()
3441

    
3442
                if dlg.validation_checked:
3443
                    self.onValidation()
3444

    
3445
                self.graphicsView.invalidateScene()
3446
                
3447
        except Exception as ex:
3448
            message = 'error occurred({}) in {}:{}'.format(ex, sys.exc_info()[-1].tb_frame.f_code.co_filename,
3449
                                                           sys.exc_info()[-1].tb_lineno)
3450
            self.addMessage.emit(MessageType.Error, message)
3451
        finally:
3452
            # save alarm
3453
            self.save_alarm_enable(True)
3454

    
3455
    def postDetectLineProcess(self):
3456
        '''
3457
            @brief  check allowables among undetected items
3458
            @author euisung
3459
            @date   2018.11.15
3460
            @history    2018.11.15  euisung    no more used, moved to TextItemFactoy isLineNo()
3461
        '''
3462

    
3463
        appDocData = AppDocData.instance()
3464

    
3465
        tableNames = ["Fluid Code", "Insulation Purpose", "PnID Number", "Piping Materials Class", "Unit Number"]
3466
        tableDatas = []
3467
        for tableName in tableNames:
3468
            tableNameFormat = tableName.replace(' ', '').replace('&&', 'n')
3469
            tableDatas.append(appDocData.getCodeTable(tableNameFormat))
3470

    
3471
        items = self.graphicsView.scene().items()
3472
        for item in items:
3473
            if type(item) is not QEngineeringTextItem:
3474
                continue
3475
            text = item.text()
3476
            for tableData in tableDatas:
3477
                for data in tableData:
3478
                    if data[3] == '':
3479
                        continue
3480
                    else:
3481
                        allows = data[3].split(',')
3482
                        for allow in allows:
3483
                            text = text.replace(allow, data[1])
3484

    
3485
            lineItem = TextItemFactory.instance().createTextItem(text)
3486
            if type(lineItem) is QEngineeringLineNoTextItem:
3487
                lineItem.loc = item.loc
3488
                lineItem.size = item.size
3489
                lineItem.angle = item.angle
3490
                lineItem.area = item.area
3491
                # lineItem.addTextItemToScene(self.graphicsView.scene())
3492
                lineItem.transfer.onRemoved.connect(self.itemRemoved)
3493
                item.transfer.onRemoved.emit(item)
3494
                appDocData.lineNos.append(lineItem)
3495

    
3496
    def init_add_tree_item(self, line_no_tree_item, run_item):
3497
        """ insert symbol item and find line no as owner """
3498
        # insert
3499
        self.itemTreeWidget.addTreeItem(line_no_tree_item, run_item)
3500
        # find
3501
        self.itemTreeWidget.addTreeItem(line_no_tree_item, run_item)
3502

    
3503
    def load_drawing(self, drawing):
3504
        """ load drawing """
3505
        """ no more used """
3506
        from EngineeringRunItem import QEngineeringRunItem
3507
        from QEngineeringTrimLineNoTextItem import QEngineeringTrimLineNoTextItem
3508

    
3509
        app_doc_data = AppDocData.instance()
3510
        try:
3511
            symbols = []
3512
            lines = []
3513

    
3514
            components = app_doc_data.get_components(drawing.UID)
3515
            maxValue = len(components) * 2
3516
            self.progress.setMaximum(maxValue) if maxValue > 0 else None
3517

    
3518
            """ parsing all symbols """
3519
            for symbol in [component for component in components if int(component['SymbolType_UID']) != -1]:
3520
                item = SymbolSvgItem.from_database(symbol)
3521
                if item is not None:
3522
                    item.transfer.onRemoved.connect(self.itemRemoved)
3523
                    symbols.append(item)
3524
                    app_doc_data.symbols.append(item)
3525
                    item.addSvgItemToScene(self.graphicsView.scene())
3526
                else:
3527
                    pt = [float(symbol['X']), float(symbol['Y'])]
3528
                    size = [float(symbol['Width']), float(symbol['Height'])]
3529
                    angle = float(symbol['Rotation'])
3530
                    item = QGraphicsBoundingBoxItem(pt[0], pt[1], size[0], size[1])
3531
                    item.isSymbol = True
3532
                    item.angle = angle
3533
                    item.setPen(QPen(Qt.red, 5, Qt.SolidLine))
3534
                    self.graphicsView.scene().addItem(item)
3535
                    item.transfer.onRemoved.connect(self.itemRemoved)
3536

    
3537
                self.progress.setValue(self.progress.value() + 1)
3538

    
3539
            QApplication.processEvents()
3540

    
3541
            # parse texts
3542
            for text in [component for component in components if
3543
                         component['Name'] == 'Text' and component['SymbolType_UID'] == -1]:
3544
                item = QEngineeringTextItem.from_database(text)
3545
                if item is not None:
3546
                    item.uid = text['UID']
3547
                    item.attribute = text['Value']
3548
                    name = text['Name']
3549
                    item.transfer.onRemoved.connect(self.itemRemoved)
3550
                    item.addTextItemToScene(self.graphicsView.scene())
3551

    
3552
                self.progress.setValue(self.progress.value() + 1)
3553

    
3554
            QApplication.processEvents()
3555

    
3556
            # note
3557
            for note in [component for component in components if
3558
                         component['Name'] == 'Note' and component['SymbolType_UID'] == -1]:
3559
                item = QEngineeringTextItem.from_database(note)
3560
                if item is not None:
3561
                    item.uid = note['UID']
3562
                    attributeValue = note['Value']
3563
                    name = note['Name']
3564
                    item.transfer.onRemoved.connect(self.itemRemoved)
3565
                    item.addTextItemToScene(self.graphicsView.scene())
3566

    
3567
                self.progress.setValue(self.progress.value() + 1)
3568

    
3569
            QApplication.processEvents()
3570

    
3571
            for line in [component for component in components if
3572
                         component['Name'] == 'Line' and component['SymbolType_UID'] == -1]:
3573
                item = QEngineeringLineItem.from_database(line)
3574
                if item:
3575
                    item.transfer.onRemoved.connect(self.itemRemoved)
3576
                    self.graphicsView.scene().addItem(item)
3577
                    lines.append(item)
3578

    
3579
                self.progress.setValue(self.progress.value() + 1)
3580

    
3581
            QApplication.processEvents()
3582

    
3583
            for unknown in [component for component in components if
3584
                            component['Name'] == 'Unknown' and component['SymbolType_UID'] == -1]:
3585
                item = QEngineeringUnknownItem.from_database(unknown)
3586
                item.transfer.onRemoved.connect(self.itemRemoved)
3587
                if item is not None:
3588
                    item.transfer.onRemoved.connect(self.itemRemoved)
3589
                    self.graphicsView.scene().addItem(item)
3590

    
3591
                self.progress.setValue(self.progress.value() + 1)
3592

    
3593
            QApplication.processEvents()
3594

    
3595
            for component in [component for component in components if
3596
                              component['Name'] == 'Line NO' and component['SymbolType_UID'] == -1]:
3597
                line_no = QEngineeringLineNoTextItem.from_database(component)
3598
                if type(line_no) is QEngineeringLineNoTextItem:
3599
                    line_no.transfer.onRemoved.connect(self.itemRemoved)
3600
                    self.addTextItemToScene(line_no)
3601
                    line_no_tree_item = self.itemTreeWidget.addTreeItem(self.itemTreeWidget.root, line_no)
3602

    
3603
                    runs = app_doc_data.get_pipe_runs(str(line_no.uid))
3604
                    if not runs: continue
3605
                    for run in runs:
3606
                        line_run = QEngineeringRunItem()
3607
                        run_items = app_doc_data.get_pipe_run_items(run['UID'])
3608
                        for record in run_items:
3609
                            uid = record['Components_UID']
3610
                            run_item = self.graphicsView.findItemByUid(uid)
3611
                            if run_item is not None:
3612
                                run_item._owner = line_no
3613
                                line_run.items.append(run_item)
3614
                        line_run.owner = line_no
3615
                        line_no.runs.append(line_run)
3616

    
3617
                        for run_item in line_run.items:
3618
                            if issubclass(type(run_item), SymbolSvgItem):
3619
                                self.init_add_tree_item(line_no_tree_item, run_item)
3620

    
3621
                self.progress.setValue(self.progress.value() + 1)
3622
            QApplication.processEvents()
3623

    
3624
            for component in [component for component in components if
3625
                              component['Name'] == 'Trim Line NO' and component['SymbolType_UID'] == -1]:
3626
                line_no = QEngineeringTrimLineNoTextItem()
3627
                line_no.uid = uuid.UUID(component['UID'])
3628

    
3629
                runs = app_doc_data.get_pipe_runs(str(line_no.uid))
3630
                if not runs: continue
3631

    
3632
                line_no_tree_item = self.itemTreeWidget.addTreeItem(self.itemTreeWidget.root, line_no)
3633

    
3634
                for run in runs:
3635
                    line_run = QEngineeringRunItem()
3636
                    run_items = app_doc_data.get_pipe_run_items(run['UID'])
3637
                    for record in run_items:
3638
                        uid = record['Components_UID']
3639
                        run_item = self.graphicsView.findItemByUid(uid)
3640
                        if run_item is not None:
3641
                            run_item.owner = line_no
3642
                            line_run.items.append(run_item)
3643
                    line_run.owner = line_no
3644
                    line_no.runs.append(line_run)
3645

    
3646
                    for run_item in line_run.items:
3647
                        if issubclass(type(run_item), SymbolSvgItem):
3648
                            self.init_add_tree_item(line_no_tree_item, run_item)
3649

    
3650
                app_doc_data.tracerLineNos.append(line_no)
3651

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

    
3654
            for component in [component for component in components if
3655
                              component['Name'] == 'VendorPackage' and component['SymbolType_UID'] == -1]:
3656
                item = QEngineeringVendorItem.from_database(component)
3657
                if item is not None:
3658
                    item.transfer.onRemoved.connect(self.itemRemoved)
3659
                    self.graphicsView.scene().addItem(item)
3660

    
3661
            # connect flow item to line
3662
            for line in lines:
3663
                line.update_arrow()
3664
                app_doc_data.lines.append(line)
3665
            # for flowMark in [item for item in symbols if type(item) is QEngineeringFlowMarkItem]:
3666
            #    for line in lines:
3667
            #        if flowMark.owner is line:
3668
            #            line._flowMark.append(flowMark)
3669
            #            flowMark.setParentItem(line)
3670
            # up to here
3671

    
3672
            """ update scene """
3673
            self.graphicsView.scene().update(self.graphicsView.sceneRect())
3674
            for item in self.graphicsView.scene().items():
3675
                up_progress = False
3676
                # binding items
3677
                if hasattr(item, 'owner'):
3678
                    item.owner
3679
                    up_progress = True
3680
                if hasattr(item, 'connectors'):
3681
                    for connector in item.connectors:
3682
                        connector.connectedItem
3683
                    up_progress = True
3684

    
3685
                if up_progress:
3686
                    self.progress.setValue(self.progress.value() + 1)
3687
            
3688
            for item in self.graphicsView.scene().items():
3689
                item.setVisible(True)
3690

    
3691
        except Exception as ex:
3692
            message = 'error occurred({}) in {}:{}'.format(ex, sys.exc_info()[-1].tb_frame.f_code.co_filename,
3693
                                                           sys.exc_info()[-1].tb_lineno)
3694
            self.addMessage.emit(MessageType.Error, message)
3695
        finally:
3696
            app_doc_data.clearTempDBData()
3697
            self.itemTreeWidget.update_item_count()
3698
            self.itemTreeWidget.expandAll()
3699
            # self.graphicsView.scene().blockSignals(False)
3700

    
3701
    '''
3702
        @brief      load recognition result
3703
        @author     humkyung
3704
        @date       2018.04.??
3705
        @history    humkyung 2018.01.12 parse originalpoint and connectionpoint
3706
                    Jeongwoo 2018.04.17 add QGraphicItem with Rotated text
3707
                    Jeongwoo 2018.04.23 Change to Draw texts on QEngineeringTextItem
3708
                    humkyung 2018.04.23 connect item remove slot to result tree
3709
                    Jeongwoo 2018.04.25 Add if state with QEngineeringNoteItem
3710
                    Jeongwoo 2018.04.26 Change method to create TextItem object with TextItemFactory
3711
                    Jeongwoo 2018.05.03 Change method to draw Svg Item on Scene (svg.addSvgItemToScene)
3712
                    Jeongwoo 2018.05.29 Change method name / Change method to add item / Add Line item
3713
                    Jeongwoo 2018.05.30 Add parameters on SymbolSvgItem.__init__() (parentSymbol, childSymbol) / Change method name / Change XML NODE NAMES
3714
                    Jeongwoo 2018.06.12 Add LineNoTextItem from LINE_NO
3715
                    Jeongwoo 2018.06.14 Add UnknownItem from UNKNOWN
3716
                    Jeongwoo 2018.06.18 Update Scene after all item added
3717
                                        Add connect on unknown item
3718
                                        Add [transfer] for using pyqtSignal
3719
                    kyouho  2018.07.12  Add line property logic
3720
                    humkyung 2018.08.22 show progress while loading xml file
3721
                    2018.11.22      euisung     fix note road
3722
    '''
3723
    def load_recognition_result_from_xml(self, drawing):
3724
        # Yield successive n-sized
3725
        # chunks from l.
3726
        def divide_chunks(l, n):
3727
            # looping till length l
3728
            for i in range(0, len(l), n):
3729
                yield l[i:i + n]
3730

    
3731
        def update_items(items):
3732
            for item in items:
3733
                # binding items
3734
                item.owner
3735
                for connector in item.connectors:
3736
                    connector.connectedItem
3737

    
3738
            return items
3739

    
3740
        import concurrent.futures as futures
3741
        from xml.etree.ElementTree import Element, SubElement, dump, ElementTree, parse
3742
        from App import App
3743
        from EngineeringRunItem import QEngineeringRunItem
3744
        from QEngineeringTrimLineNoTextItem import QEngineeringTrimLineNoTextItem
3745
        from EngineeringGraphicsLineItem import QEngineeringGraphicsLineItem
3746

    
3747
        app_doc_data = AppDocData.instance()
3748

    
3749
        try:
3750
            file_name = os.path.splitext(os.path.basename(drawing.file_path))[0]
3751
            path = os.path.join(app_doc_data.getCurrentProject().getTempPath(), file_name + '.xml')
3752
            self.graphicsView.scene().blockSignals(True)
3753

    
3754
            symbols = []
3755
            lines = []
3756

    
3757
            xml = parse(path)
3758
            root = xml.getroot()
3759

    
3760
            maxValue = 0
3761
            maxValue = maxValue + len(list(root.iter('SYMBOL'))) - \
3762
                       len(list(root.iterfind('LINENOS/LINE_NO/RUN/SYMBOL'))) - \
3763
                       len(list(root.iterfind('TRIMLINENOS/TRIM_LINE_NO/RUN/SYMBOL')))
3764
            maxValue = maxValue + len(list(root.iterfind('TEXTINFOS/ATTRIBUTE')))
3765
            maxValue = maxValue + len(list(root.iterfind('NOTES/ATTRIBUTE')))
3766
            maxValue = maxValue + len(list(root.iter('LINE_NO')))
3767
            maxValue = maxValue + len(list(root.iter('LINE'))) - \
3768
                       len(list(root.iterfind('LINENOS/LINE_NO/RUN/LINE'))) - \
3769
                       len(list(root.iterfind('TRIMLINENOS/TRIM_LINE_NO/RUN/LINE')))
3770
            maxValue = maxValue + len(list(root.iter('GRAPHICS_LINE')))
3771
            maxValue = maxValue + len(list(root.iter('UNKNOWN')))
3772
            # maxValue = maxValue + len(list(root.iter('SIZETEXT')))
3773
            maxValue = maxValue + len(list(root.iter('TRIM_LINE_NO')))
3774
            maxValue *= 2
3775
            self.progress.setMaximum(maxValue) if maxValue > 0 else None
3776

    
3777
            """ parsing all symbols """
3778
            """
3779
            with futures.ThreadPoolExecutor(max_workers=App.THREAD_MAX_WORKER) as pool:
3780
                future_symbol = {pool.submit(SymbolSvgItem.fromXml, symbol): symbol for symbol in root.find('SYMBOLS').iter('SYMBOL')}
3781

3782
                for future in futures.as_completed(future_symbol):
3783
                    try:
3784
                        item = future.result()
3785
                        if item:
3786
                            if item is not None:
3787
                                item.transfer.onRemoved.connect(self.itemRemoved)
3788
                                symbols.append(item)
3789
                                docData.symbols.append(item)
3790
                                self.addSvgItemToScene(item)
3791
                            else:
3792
                                pt = [float(x) for x in symbol.find('LOCATION').text.split(',')]
3793
                                size = [float(x) for x in symbol.find('SIZE').text.split(',')]
3794
                                angle = float(symbol.find('ANGLE').text)
3795
                                item = QGraphicsBoundingBoxItem(pt[0], pt[1], size[0], size[1])
3796
                                item.isSymbol = True
3797
                                item.angle = angle
3798
                                item.setPen(QPen(Qt.red, 5, Qt.SolidLine))
3799
                                self.graphicsView.scene().addItem(item)
3800
                                item.transfer.onRemoved.connect(self.itemRemoved)
3801
                    except Exception as ex:
3802
                        message = 'error occurred({}) in {}:{}'.format(repr(ex), sys.exc_info()[-1].tb_frame.f_code.co_filename,
3803
                                                                       sys.exc_info()[-1].tb_lineno)
3804

3805
            """
3806
            for symbol in root.find('SYMBOLS').iter('SYMBOL'):
3807
                item = SymbolSvgItem.fromXml(symbol)
3808
                if item is not None:
3809
                    item.transfer.onRemoved.connect(self.itemRemoved)
3810
                    symbols.append(item)
3811
                    #app_doc_data.symbols.append(item)
3812
                    item.addSvgItemToScene(self.graphicsView.scene())
3813
                else:
3814
                    pt = [float(x) for x in symbol.find('LOCATION').text.split(',')]
3815
                    size = [float(x) for x in symbol.find('SIZE').text.split(',')]
3816
                    angle = float(symbol.find('ANGLE').text)
3817
                    item = QGraphicsBoundingBoxItem(pt[0], pt[1], size[0], size[1])
3818
                    item.isSymbol = True
3819
                    item.angle = angle
3820
                    item.setPen(QPen(Qt.red, 5, Qt.SolidLine))
3821
                    self.graphicsView.scene().addItem(item)
3822
                    item.transfer.onRemoved.connect(self.itemRemoved)
3823

    
3824
                self.progress.setValue(self.progress.value() + 1)
3825

    
3826
            QApplication.processEvents()
3827

    
3828
            # parse texts
3829
            for text in root.find('TEXTINFOS').iter('ATTRIBUTE'):
3830
                item = QEngineeringTextItem.fromXml(text)
3831
                if item is not None:
3832
                    uid = text.find('UID')
3833
                    attributeValue = text.find('ATTRIBUTEVALUE')
3834
                    name = text.find('NAME').text
3835
                    item.transfer.onRemoved.connect(self.itemRemoved)
3836
                    item.addTextItemToScene(self.graphicsView.scene())
3837
                    # docData.texts.append(item)
3838

    
3839
                    if name == 'TEXT':
3840
                        if uid is not None and attributeValue is not None:
3841
                            item.uid = uid.text
3842
                            item.attribute = attributeValue.text
3843

    
3844
                self.progress.setValue(self.progress.value() + 1)
3845

    
3846
            QApplication.processEvents()
3847

    
3848
            # note
3849
            for text in root.find('NOTES').iter('ATTRIBUTE'):
3850
                item = QEngineeringTextItem.fromXml(text)
3851
                if item is not None:
3852
                    uid = text.find('UID')
3853
                    attributeValue = text.find('ATTRIBUTEVALUE')
3854
                    name = text.find('NAME').text
3855
                    item.transfer.onRemoved.connect(self.itemRemoved)
3856
                    item.addTextItemToScene(self.graphicsView.scene())
3857

    
3858
                    if name == 'NOTE':
3859
                        if uid is not None:
3860
                            item.uid = uid.text
3861

    
3862
                self.progress.setValue(self.progress.value() + 1)
3863

    
3864
            QApplication.processEvents()
3865

    
3866
            for line in root.find('LINEINFOS').iter('LINE'):
3867
                item = QEngineeringLineItem.fromXml(line)
3868
                if item:
3869
                    item.transfer.onRemoved.connect(self.itemRemoved)
3870
                    self.graphicsView.scene().addItem(item)
3871
                    lines.append(item)
3872

    
3873
                self.progress.setValue(self.progress.value() + 1)
3874

    
3875
            for line in root.find('LINEINFOS').iter('GRAPHICS_LINE'):
3876
                item = QEngineeringGraphicsLineItem.fromXml(line)
3877
                if item:
3878
                    item.transfer.onRemoved.connect(self.itemRemoved)
3879
                    self.graphicsView.scene().addItem(item)
3880

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

    
3883
            QApplication.processEvents()
3884

    
3885
            for unknown in root.iter('UNKNOWN'):
3886
                item = QEngineeringUnknownItem.fromXml(unknown)
3887
                if item is not None:
3888
                    item.transfer.onRemoved.connect(self.itemRemoved)
3889
                    self.graphicsView.scene().addItem(item)
3890

    
3891
                self.progress.setValue(self.progress.value() + 1)
3892

    
3893
            QApplication.processEvents()
3894

    
3895
            # """ add tree widget """
3896
            # for item in symbols:
3897
            #    docData.symbols.append(item)
3898
            #    self.addSvgItemToScene(item)
3899
            #    self.itemTreeWidget.addTreeItem(self.itemTreeWidget.root, item)
3900

    
3901
            for line_no_node in root.find('LINENOS').iter('LINE_NO'):
3902
                line_no = QEngineeringLineNoTextItem.fromXml(line_no_node)
3903
                if line_no is None: continue
3904
                line_no.transfer.onRemoved.connect(self.itemRemoved)
3905
                line_no.addTextItemToScene(self.graphicsView.scene())
3906
                line_no_tree_item = self.itemTreeWidget.addTreeItem(self.itemTreeWidget.root, line_no)
3907
                if type(line_no) is not QEngineeringLineNoTextItem: continue
3908

    
3909
                runs_node = line_no_node.findall('RUN')
3910
                if runs_node is None: continue
3911

    
3912
                for run_node in runs_node:
3913
                    line_run = QEngineeringRunItem()
3914
                    for child_node in run_node:
3915
                        uidElement = child_node.find('UID')
3916
                        if uidElement is not None:
3917
                            uid = uidElement.text
3918
                            run_item = self.graphicsView.findItemByUid(uid)
3919
                            if run_item is not None:
3920
                                run_item._owner = line_no
3921
                                line_run.items.append(run_item)
3922
                    line_run.owner = line_no
3923
                    line_no.runs.append(line_run)
3924

    
3925
                    for run_item in line_run.items:
3926
                        if issubclass(type(run_item), SymbolSvgItem):
3927
                            self.init_add_tree_item(line_no_tree_item, run_item)
3928

    
3929
                # docData.tracerLineNos.append(line_no)
3930

    
3931
                self.progress.setValue(self.progress.value() + 1)
3932
            QApplication.processEvents()
3933

    
3934
            for trimLineNo in root.iter('TRIM_LINE_NO'):
3935
                line_no = QEngineeringTrimLineNoTextItem()
3936
                line_no.uid = uuid.UUID(trimLineNo.find('UID').text)
3937

    
3938
                runs_node = trimLineNo.findall('RUN')
3939
                if runs_node is None: continue
3940
                line_no_tree_item = self.itemTreeWidget.addTreeItem(self.itemTreeWidget.root, line_no)
3941

    
3942
                for run in runs_node:
3943
                    line_run = QEngineeringRunItem()
3944
                    for child in run:
3945
                        uidElement = child.find('UID')
3946
                        if uidElement is not None:
3947
                            uid = uidElement.text
3948
                            run_item = self.graphicsView.findItemByUid(uid)
3949
                            if run_item is not None:
3950
                                run_item.owner = line_no
3951
                                line_run.items.append(run_item)
3952
                    line_run.owner = line_no
3953
                    line_no.runs.append(line_run)
3954

    
3955
                    for run_item in line_run.items:
3956
                        if issubclass(type(run_item), SymbolSvgItem):
3957
                            self.init_add_tree_item(line_no_tree_item, run_item)
3958

    
3959
                app_doc_data.tracerLineNos.append(line_no)
3960

    
3961
                self.progress.setValue(self.progress.value() + 1)
3962
            QApplication.processEvents()
3963

    
3964
            if root.find('VENDORS') is not None:
3965
                for vendor in root.find('VENDORS').iter('VENDOR'):
3966
                    item = QEngineeringVendorItem.fromXml(vendor)
3967
                    item.transfer.onRemoved.connect(self.itemRemoved)
3968
                    self.graphicsView.scene().addItem(item)
3969

    
3970
            # connect flow item to line
3971
            for line in lines:
3972
                line.update_arrow()
3973
                app_doc_data.lines.append(line)
3974
            # for flowMark in [item for item in symbols if type(item) is QEngineeringFlowMarkItem]:
3975
            #    for line in lines:
3976
            #        if flowMark.owner is line:
3977
            #            line._flowMark.append(flowMark)
3978
            #            flowMark.setParentItem(line)
3979
            # up to here
3980

    
3981
            """
3982
            group_box = QGroupBox("Contact Details")
3983
            number_label = QLabel("Telephone number");
3984
            number_edit = QTextEdit('hello\nthis is ....')
3985
            layout = QFormLayout()
3986
            layout.addRow(number_label, number_edit)
3987
            group_box.setLayout(layout)
3988

3989
            proxy =  ㅐ()
3990
            proxy.setWidget(group_box)
3991
            self.graphicsView.scene().addItem(proxy)  # (group_box, QGraphicsItem.ItemIgnoresTransformations)
3992
            """
3993

    
3994
            """ update scene """
3995
            _items = [_item for _item in self.graphicsView.scene().items() if hasattr(_item, 'owner') or hasattr(_item, 'connectors')]
3996
            if _items:
3997
                items = divide_chunks(_items, App.THREAD_MAX_WORKER if len(_items) > App.THREAD_MAX_WORKER else len(_items))
3998
                with futures.ThreadPoolExecutor(max_workers=App.THREAD_MAX_WORKER) as pool:
3999
                    future_items = {pool.submit(update_items, _items): _items for _items in items}
4000
                    for future in futures.as_completed(future_items):
4001
                        _items = future.result()
4002
                        self.progress.setValue(self.progress.value() + len(_items))
4003

    
4004
            """
4005
            for item in [_item for _item in self.graphicsView.scene().items() if hasattr(_item, 'owner') or hasattr(_item, 'connectors')]:
4006
                up_progress = False
4007
                # binding items
4008
                item.owner
4009
                for connector in item.connectors:
4010
                    connector.connectedItem
4011

4012
                self.progress.setValue(self.progress.value() + 1)
4013
            """
4014

    
4015
            for item in self.graphicsView.scene().items():
4016
                item.setVisible(True)
4017

    
4018
            self.graphicsView.scene().update(self.graphicsView.sceneRect())
4019
        except Exception as ex:
4020
            message = 'error occurred({}) in {}:{}'.format(ex, sys.exc_info()[-1].tb_frame.f_code.co_filename,
4021
                                                           sys.exc_info()[-1].tb_lineno)
4022
            self.addMessage.emit(MessageType.Error, message)
4023
        finally:
4024
            self.itemTreeWidget.update_item_count()
4025
            self.itemTreeWidget.expandAll()
4026
            self.graphicsView.scene().blockSignals(False)
4027

    
4028
    '''
4029
        @brief      Remove added item on same place and Add GraphicsItem
4030
        @author     Jeongwoo
4031
        @date       2018.05.29
4032
        @history    2018.06.18  Jeongwoo    Set Z-index
4033
    '''
4034
    def addLineItemToScene(self, lineItem):
4035
        self.graphicsView.scene().addItem(lineItem)
4036

    
4037
    '''
4038
        @brief      generate output xml file
4039
        @author     humkyung
4040
        @date       2018.04.23
4041
        @history    2018.05.02  Jeongwoo    Show MessageBox when imageviewer doesn't have image
4042
    '''
4043
    def generateOutput(self):
4044
        import XmlGenerator as xg
4045

    
4046
        if not self.graphicsView.hasImage():
4047
            self.showImageSelectionMessageBox()
4048
            return
4049

    
4050
        try:
4051
            appDocData = AppDocData.instance()
4052

    
4053
            # collect items
4054
            appDocData.lines.clear()
4055
            appDocData.lines = [item for item in self.graphicsView.scene().items() if
4056
                                type(item) is QEngineeringLineItem and item.owner is None]
4057

    
4058
            appDocData.symbols.clear()
4059
            appDocData.symbols = [item for item in self.graphicsView.scene().items() if
4060
                                  issubclass(type(item), SymbolSvgItem) and item.owner is None]
4061

    
4062
            appDocData.equipments.clear()
4063
            for item in self.graphicsView.scene().items():
4064
                if type(item) is QEngineeringEquipmentItem:
4065
                    appDocData.equipments.append(item)
4066

    
4067
            appDocData.texts.clear()
4068
            appDocData.texts = [item for item in self.graphicsView.scene().items() if
4069
                                issubclass(type(item), QEngineeringTextItem) and type(
4070
                                    item) is not QEngineeringLineNoTextItem]
4071
            # up to here
4072

    
4073
            appDocData.imgOutput = np.ones((appDocData.activeDrawing.height, appDocData.activeDrawing.width),
4074
                                           np.uint8) * 255
4075
            xg.writeOutputXml(appDocData.imgName, appDocData.activeDrawing.width,
4076
                              appDocData.activeDrawing.height)  # TODO: check
4077
            project = appDocData.getCurrentProject()
4078
            cv2.imwrite(os.path.join(project.getTempPath(), 'OUTPUT.png'), appDocData.imgOutput)
4079
        except Exception as ex:
4080
            message = 'error occurred({}) in {}:{}'.format(ex, sys.exc_info()[-1].tb_frame.f_code.co_filename,
4081
                                                           sys.exc_info()[-1].tb_lineno)
4082
            self.addMessage.emit(MessageType.Error, message)
4083

    
4084
    '''
4085
        @brief      Check Number
4086
        @author     kyouho
4087
        @date       2018.08.20
4088
    '''
4089
    def isNumber(self, num):
4090
        p = re.compile('(^[0-9]+$)')
4091
        result = p.match(num)
4092

    
4093
        if result:
4094
            return True
4095
        else:
4096
            return False
4097

    
4098
    '''
4099
        @brief      find overlap Connector
4100
        @author     kyouho
4101
        @date       2018.08.28
4102
    '''
4103
    def findOverlapConnector(self, connectorItem):
4104
        from shapely.geometry import Point
4105
        from EngineeringConnectorItem import QEngineeringConnectorItem
4106
        itemList = []
4107

    
4108
        x = connectorItem.center()[0]
4109
        y = connectorItem.center()[1]
4110

    
4111
        connectors = [item for item in self.graphicsView.scene().items() if
4112
                      type(item) is QEngineeringConnectorItem and item != connectorItem]
4113
        for connector in connectors:
4114
            if Point(x, y).distance(Point(connector.center()[0], connector.center()[1])) < 5:
4115
                itemList.append(connector.parent)
4116

    
4117
        return itemList
4118

    
4119
    def make_diff_image(self):
4120
        """ make diff image """
4121
        # test
4122

    
4123
        from RecognitionDialog import Worker
4124
        from symbol import Symbol
4125
        import math
4126
        from PIL import Image
4127

    
4128
        app_doc_data = AppDocData.instance()
4129
        img = app_doc_data.imgSrc.copy()
4130

    
4131
        # check break
4132
        symbols = [item for item in self.graphicsView.scene().items() if issubclass(type(item), SymbolSvgItem)]
4133

    
4134
        for symbol in symbols:
4135
            rect = symbol.sceneBoundingRect()
4136
            sName = symbol.name
4137
            sType = symbol.type
4138
            sp = (rect.x(), rect.y())
4139
            w, h = rect.width(), rect.height()
4140
            rotatedAngle = round(math.degrees(symbol.angle))
4141
            detectFlip = symbol.flip
4142

    
4143
            dummySym = Symbol(sName, sType, sp, w, h, 0, 0, 0, rotatedAngle,
4144
                                   1, 0, 1, 0,
4145
                                   ','.join(str(x) for x in [0, 0]),
4146
                                   '/'.join('{},{},{},{}'.format(param[0], param[1], param[2], param[3]) for param in
4147
                                            []),
4148
                                   'dummy', 'dummy', 0, detectFlip=detectFlip,
4149
                                   hasInstrumentLabel=0, text_area='')
4150

    
4151
            Worker.remove_detected_symbol_image(dummySym, img, lock=False)
4152

    
4153
        Image.fromarray(img).show()
4154

    
4155
    #def paintEvent(self, event):
4156
    #    self.refresh_rate += 1
4157
    #    if self.refresh_rate == 3:
4158
    #        super(self.__class__, self).paintEvent(event)
4159
    #        self.refresh_rate = 0
4160

    
4161
if __name__ == '__main__':
4162
    import locale
4163
    from PyQt5.QtCore import QTranslator
4164
    from License import QLicenseDialog
4165
    from ProjectDialog import Ui_Dialog
4166
    from App import App
4167

    
4168
    app = App(sys.argv)
4169
    try:
4170
        if True == QLicenseDialog.check_license_key():
4171
            dlg = Ui_Dialog()
4172
            selectedProject = dlg.showDialog()
4173
            if selectedProject is not None:
4174
                AppDocData.instance().setCurrentProject(selectedProject)
4175
                app._mainWnd = MainWindow.instance()
4176
                app._mainWnd.show()
4177
                sys.exit(app.exec_())
4178
    except Exception as ex:
4179
        print('error occurred({}) in {}:{}'.format(ex, sys.exc_info()[-1].tb_frame.f_code.co_filename,
4180
                                                   sys.exc_info()[-1].tb_lineno))
4181
    finally:
4182
        pass
클립보드 이미지 추가 (최대 크기: 500 MB)