프로젝트

일반

사용자정보

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

hytos / HYTOS / HYTOS / MainWindow.py @ 75ea0fd1

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

1
# -*- coding: utf-8 -*-
2
""" This is MainWindow module """
3
import shutil
4
import sys
5
import os
6
import subprocess
7
from functools import partial
8

    
9
# from openpyxl.drawing import colors
10
from FreezeTableWidget import FreezeTableWidget
11

    
12
sys.path.insert(0, os.path.dirname(os.path.realpath(__file__)))
13
sys.path.insert(0, os.path.dirname(os.path.realpath(__file__)) + '\\Commands')
14
import CreateCommand
15
import AreaZoomCommand
16
import PlaceStreamlineCommand
17
import LeftAlignmentCommand, RightAlignmentCommand, UpAlignmentCommand, DownAlignmentCommand
18

    
19
from PyQt5.QtCore import *
20
from PyQt5.QtGui import *
21
from PyQt5.QtWidgets import *
22
from PyQt5.QtSvg import *
23

    
24
import MainWindow_UI
25
import QtImageViewer
26
from SingletonInstance import SingletonInstane
27

    
28
sys.path.insert(0, os.path.dirname(os.path.realpath(__file__)) + '\\Shapes')
29
from SymbolSvgItem import SymbolSvgItem
30

    
31
from EngineeringErrorItem import QEngineeringErrorItem
32
from EngineeringStreamlineItem import QEngineeringStreamlineItem
33
from AppDocData import *
34
import SymbolTreeWidget
35
import uuid
36
import math
37

    
38

    
39
def is_blank(s):
40
    return not (s and s.strip())
41

    
42

    
43
def is_not_blank(s):
44
    return bool(s and s.strip())
45

    
46

    
47
def is_float(s):
48
    try:
49
        if s:
50
            float(s)
51
            return True
52
        else:
53
            return False
54
    except ValueError:
55
        return False
56

    
57

    
58
def set_item_properties(name: str, alignment, backgroundcolor=None, foregroundcolor=None) -> QStandardItem:
59
    if name is None:
60
        name = ''
61

    
62
    item = QStandardItem(str(name))
63
    item.setTextAlignment(alignment)
64
    if backgroundcolor:
65
        item.setBackground(backgroundcolor)
66
    if foregroundcolor:
67
        item.setForeground(foregroundcolor)  # QBrush(QColor(255, 0, 0)))
68
    return item
69

    
70

    
71
def convert_to_fixed_point(value):
72
    if is_float(str(value)):
73
        tokens = f"{float(value):.10f}".split('.')
74
        if len(tokens) == 2:
75
            # 소수점 아래가 있을 경우 소수점 아래의 trailing zero를 제거한다.
76
            if is_blank(tokens[1].rstrip('0')):
77
                return tokens[0]
78
            else:
79
                tokens[1] = tokens[1].rstrip('0')
80
                return '.'.join(tokens)
81
        else:
82
            return tokens[0]
83
    else:
84
        return value
85

    
86

    
87
class ItemDelegate(QStyledItemDelegate):
88
    def createEditor(self, parent, option, index):
89
        """
90
        create a editor for user input
91
        @param parent:
92
        @param option:
93
        @param index:
94
        @return:
95
        """
96
        editor = None
97
        if index.column() >= 2:
98
            if index.row() == 3:
99
                editor = QComboBox(parent)
100
                editor.addItems(['Liquid', 'Vapor', 'Mixed'])
101
            elif index.row() <= 23:
102
                editor = QLineEdit(parent)
103
                if index.row() in [4, 5]:
104
                    validator = QDoubleValidator(parent)
105
                    editor.setValidator(validator)
106

    
107
                value = editor.text()
108
                if type(value) is float:
109
                    validator = QDoubleValidator(parent)
110
                    editor.setValidator(validator)
111

    
112
        return editor
113

    
114
    def destroyEditor(self, editor, index):
115
        """
116
        change background if value is changed
117
        @param editor:
118
        @param index:
119
        @return:
120
        """
121
        editor.blockSignals(True)
122
        if type(editor) is QComboBox:
123
            changed = editor.currentText()
124
        else:
125
            changed = editor.text()
126
        item = editor.parentWidget().parentWidget().model().item(index.row(), index.column())
127
        value = item.data(Qt.UserRole)
128

    
129
        value_changed = False
130
        if type(value) is float and changed:
131
            value_changed = float(changed) != value
132
            item.setBackground(Qt.magenta if value_changed else Qt.white)
133
        else:
134
            value_changed = changed != value
135
            item.setBackground(Qt.magenta if value_changed else Qt.white)
136

    
137
        """clear value of other side"""
138
        if value_changed:
139
            if index.row() == 4:
140
                item = editor.parentWidget().parentWidget().model().item(5, index.column())
141
                item.setText('')
142
                item.setBackground(Qt.magenta)
143
            elif index.row() == 5:
144
                item = editor.parentWidget().parentWidget().model().item(4, index.column())
145
                item.setText('')
146
                item.setBackground(Qt.magenta)
147

    
148
        """
149
        if index.row() == 3:
150
            item = editor.parentWidget().parentWidget().item(5, index.column())
151
            if changed in ['Liquid', 'Mixed']:
152
                item.setFlags(item.flags() | Qt.ItemIsEditable)
153
            else:
154
                item.setFlags(Qt.ItemIsEnabled | Qt.ItemIsSelectable)
155
        """
156

    
157
        editor.blockSignals(False)
158

    
159

    
160
class MainWindow(QMainWindow, MainWindow_UI.Ui_MainWindow, SingletonInstane):
161
    """ This is MainWindow class """
162
    DEFAULT_SIZE = QSizeF(1188, 841)
163
    PAPER_SIZE = QSizeF(1500, 950)  # 엑셀에서 이미지 영역의 크기(픽셀 단위)
164
    USE_IMAGE = 'Use Image'
165
    addMessage = pyqtSignal(Enum, str)
166

    
167
    def __init__(self):
168
        """initialize"""
169

    
170
        try:
171
            super(self.__class__, self).__init__()
172
            self.setupUi(self)
173
            self.tableWidgetHMB = FreezeTableWidget(self, 2)
174
            self.horizontalLayoutStreamData.addWidget(self.tableWidgetHMB)
175

    
176
            self._label_mouse = QLabel(self.statusbar)
177
            self._label_mouse.setText(self.tr(f'mouse pos : ({0},{0})'))
178
            self.statusbar.addWidget(self._label_mouse)
179
            self.addMessage.connect(self.onAddMessage)
180

    
181
            self.setMainWindowTitle()
182

    
183
            self.graphicsView = QtImageViewer.QtImageViewer(self)
184
            self.graphicsView.setParent(self.centralwidget)
185
            self.graphicsView.useDefaultCommand()
186
            self.graphicsView.setMouseTracking(True)
187
            self.graphicsView.viewport().installEventFilter(self)
188
            self.verticalLayout.addWidget(self.graphicsView)
189

    
190
            # Add Symbol TreeWidget
191
            self.symbolTreeWidget = SymbolTreeWidget.QSymbolTreeWidget()
192
            self.symbolTreeWidget.header().hide()
193
            self.verticalLayoutSymbolList.addWidget(self.symbolTreeWidget)
194

    
195
            # Initialize Action group
196
            self.actionGroup = QActionGroup(self)
197
            self.actionGroup.addAction(self.actionLine)
198
            self.actionGroup.addAction(self.actionZoom)
199
            self.actionGroup.addAction(self.actionFitWindow)
200
            self.actionGroup.addAction(self.actionSave)
201

    
202
            # connect signals and slots
203
            self.actionGroup.triggered.connect(self.actionGroupTriggered)
204
            self.actionClose.triggered.connect(self.close)
205
            self.actionNew.triggered.connect(self.on_new_drawing)
206
            self.actionOpen.triggered.connect(self.on_open_drawing)
207
            self.actionSave.triggered.connect(self.on_save)
208
            self.actionSave_As.triggered.connect(self.on_save_as)
209
            self.actionUndo.triggered.connect(self.on_undo)
210
            self.actionRedo.triggered.connect(self.on_redo)
211
            self.actionCalculation.triggered.connect(partial(self.calculation, True))
212
            self.actionGenerateReport.triggered.connect(self.on_generate_report)
213
            self.actionLine.triggered.connect(self.onPlaceLine)
214
            self.actionConfiguration.triggered.connect(self.configuration)
215
            self.actionInitialize.triggered.connect(self.onInitializeScene)
216
            self.actionOptions.triggered.connect(self.onOptions)
217
            self.actionZoom.triggered.connect(self.onAreaZoom)
218
            self.actionFitWindow.triggered.connect(self.fitWindow)
219
            self.actionViewConnector.triggered.connect(self.on_view_connector)
220
            self.actionSymbol_Editor.triggered.connect(self.showSymbolEditor)
221
            self.actionPlaceTextBox.triggered.connect(self.on_place_callout_textbox)
222
            self.actionPlaceDimension.triggered.connect(self.on_place_dimension)
223
            self.actionPlaceCloud.triggered.connect(self.on_place_cloud)
224
            self.actionHelp.triggered.connect(self.on_help)
225
            self.actionAbout.triggered.connect(self.on_about)
226
            self.actionReadme.triggered.connect(self.on_readme)
227
            self.toolButton_ClearLog.clicked.connect(self.clearlogs)
228

    
229
            ''' add rotate and flip and polygon tool buttons'''
230
            self.actionRotate_L.triggered.connect(self.on_left_rotation_clicked)
231
            self.actionRotate_R.triggered.connect(self.on_right_rotation_clicked)
232
            self.actionFlip_horizontal.triggered.connect(self.on_horizontal_filp_clicked)
233
            self.actionFlip_vertical.triggered.connect(self.on_vertical_filp_clicked)
234
            self.actionSelectByPolygon.triggered.connect(self.on_select_polygon_clicked)
235

    
236
            self.graphicsView.scene.selectionChanged.connect(self.onSelectionChanged)
237

    
238
            self.actionLeftAlignment.triggered.connect(self.on_left_alignment)
239
            self.actionRightAlignment.triggered.connect(self.on_right_alignment)
240
            self.actionUpAlignment.triggered.connect(self.on_up_alignment)
241
            self.actionDownAlignment.triggered.connect(self.on_down_alignment)
242

    
243
            self.actionPush_to_PAP.triggered.connect(self.upload_to_pap)
244
            self.actionSave_and_Export_to_PAP.triggered.connect(self.upload_to_pap)
245

    
246
            self.treeViewDrawingList.setContextMenuPolicy(Qt.CustomContextMenu)
247
            self.treeViewDrawingList.customContextMenuRequested.connect(self.open_context_menu)
248
            self.treeViewDrawingList.doubleClicked.connect(self.open_selected_drawing)
249

    
250
            delegate = ItemDelegate(self.tableWidgetHMB)
251
            self.tableWidgetHMB.setItemDelegate(delegate)
252
            self.toolButtonSyncStreamData.clicked.connect(self.on_sync_stream_data)
253
            self.toolButtonRevertStreamData.clicked.connect(self.load_HMB)
254
            self.initTableWidgetHMB()
255

    
256
            self.load_drawing_list()
257
            self.load_stylesheet_file()
258
            self.load_language_file()
259

    
260
            self.tabifyDockWidget(self.dockWidgetDrawingExplorer, self.dockWidgetSymbolExplorer)
261
            self.dockWidgetDrawingExplorer.raise_()
262

    
263
            self.read_settings()
264

    
265
            # ToDo..
266
            # Menu bar - Admin Hide
267
            # Loop Tab Hide
268
        except Exception as ex:
269
            message = f"error occurred({repr(ex)}) in {sys.exc_info()[-1].tb_frame.f_code.co_filename}:" \
270
                      f"{sys.exc_info()[-1].tb_lineno}"
271
            self.addMessage.emit(MessageType.Error, message)
272

    
273
    def upload_to_pap(self):
274
        QMessageBox.information(self, "Error", "Not Implemented.")
275

    
276
    def read_settings(self):
277
        """read geometry and state"""
278
        from App import App
279

    
280
        try:
281
            self.settings = QSettings(App.COMPANY, App.NAME)
282
            self.restoreGeometry(self.settings.value("geometry", ""))
283
            self.restoreState(self.settings.value("windowState", ""))
284
        except Exception as ex:
285
            message = 'error occurred({}) in {}:{}'.format(ex, sys.exc_info()[-1].tb_frame.f_code.co_filename,
286
                                                           sys.exc_info()[-1].tb_lineno)
287
            self.addMessage.emit(MessageType.Error, message)
288

    
289
    def load_stylesheet_file(self):
290
        # load stylesheet file list
291
        stylesheet_name = QtWidgets.qApp.stylesheet_name
292
        files = [os.path.splitext(file)[0] for file in os.listdir(os.path.dirname(os.path.realpath(__file__))) if
293
                 os.path.splitext(file)[1] == '.qss']
294
        for file in files:
295
            action = self.menuTheme.addAction(file)
296
            action.setCheckable(True)
297
            action.setChecked(True) if stylesheet_name == file else action.setChecked(False)
298
            action.triggered.connect(partial(self.load_stylesheet, file))
299
        # up to here
300

    
301
    def load_language_file(self):
302
        # load language files
303
        language_name = QtWidgets.qApp.language_name
304
        files = ['en_us']  # englisgh is default language
305
        files.extend([os.path.splitext(file)[0] for file in
306
                      os.listdir(os.path.join(os.path.dirname(os.path.realpath(__file__)), 'translate')) if
307
                      os.path.splitext(file)[1] == '.qm'])
308
        for file in files:
309
            action = self.menuLanguage.addAction(file)
310
            action.setCheckable(True)
311
            action.setChecked(True) if language_name.lower() == file.lower() else action.setChecked(False)
312
            action.triggered.connect(partial(self.load_language, file))
313
        # up to here
314

    
315
    def setMainWindowTitle(self, drawingName=None):
316
        try:
317
            _translate = QCoreApplication.translate
318

    
319
            version = QCoreApplication.applicationVersion()
320
            if drawingName is None:
321
                self.setWindowTitle(_translate(App.NAME + f"({version})", App.NAME + f"({version})"))
322
            else:
323
                self.setWindowTitle(
324
                    _translate(App.NAME + f"({version})", App.NAME + f"({version})") + f" - {drawingName}")
325
        except Exception as ex:
326
            message = f"error occurred({repr(ex)}) in {sys.exc_info()[-1].tb_frame.f_code.co_filename}:" \
327
                      f"{sys.exc_info()[-1].tb_lineno}"
328
            self.addMessage.emit(MessageType.Error, message)
329

    
330
    def on_sync_stream_data(self):
331
        """
332
        sync stream data
333
        @return: None
334
        """
335

    
336
        drawing = AppDocData.instance().activeDrawing
337
        if drawing is None:
338
            return
339

    
340
        try:
341
            model = self.tableWidgetHMB.model()
342
            for col in range(2, model.columnCount()):
343
                hmb = None
344
                if self.tableWidgetHMB.isColumnHidden(col):
345
                    continue
346

    
347
                components_uid = model.item(1, col).text()
348
                hmb = drawing.hmbTable.get_hmb_data(components_uid)
349

    
350
                for row in range(2, 24):
351
                    item = model.item(row, col)
352
                    if Qt.magenta != item.background():
353
                        continue
354

    
355
                    value = item.text()
356
                    origin_value = item.data(Qt.UserRole)
357
                    """try to convert data type"""
358
                    value = float(value) if value and type(origin_value) is float else value
359

    
360
                    item.setBackground(Qt.white)
361
                    if row == 3:
362
                        hmb.phase_type = value
363
                    elif row == 4:  # Flowrate(Mass)
364
                        hmb.flowrate_mass = value
365
                        if value:
366
                            hmb.input_flowrate_type = 'Mass'
367
                    elif row == 5:  # Flowrate(Volume)
368
                        hmb.flowrate_volume = value
369
                        if value:
370
                            hmb.input_flowrate_type = 'Volume'
371
                    elif row == 6:
372
                        hmb.density = value
373
                    elif row == 7:
374
                        hmb.viscosity = value
375
                    elif row == 8:
376
                        hmb.temperature = value
377
                    elif row == 9:
378
                        hmb.molecular_weight = value
379
                    elif row == 10:
380
                        hmb.specific_heat_ratio = value
381
                    elif row == 11:
382
                        hmb.compress_factor = value
383
                    elif row == 12:
384
                        hmb.nominal_pipe_size = value
385
                    elif row == 13:
386
                        hmb.inside_pipe_size = value
387
                    elif row == 14:
388
                        hmb.schedule_no = value
389
                    elif row == 15:
390
                        hmb.straight_length = value
391
                    elif row == 16:
392
                        hmb.equivalent_length = value
393
                    elif row == 17:
394
                        hmb.equivalent_length_input = value
395
                    elif row == 18:
396
                        hmb.fitting_length = value
397
                    elif row == 19:
398
                        hmb.fitting_K = value
399
                    elif row == 20:
400
                        hmb.equivalent_length_cal = value
401
                    elif row == 21:
402
                        hmb.roughness = value
403
                    elif row == 22:
404
                        hmb.limitation_velocity = value
405
                    elif row == 23:
406
                        hmb.limitation_pressure_drop = value
407
        except Exception as ex:
408
            message = f"error occurred({repr(ex)}) in {sys.exc_info()[-1].tb_frame.f_code.co_filename}:" \
409
                      f"{sys.exc_info()[-1].tb_lineno}"
410
            self.addMessage.emit(MessageType.Error, message)
411

    
412
    def clearlogs(self):
413
        """
414
        @brief: clear logs
415
        @return: None
416
        """
417
        try:
418
            self.listWidgetLogs.clear()
419
        except Exception as ex:
420
            message = f'error occurred({ex}) in {sys.exc_info()[-1].tb_frame.f_code.co_filename}:' \
421
                      f'{sys.exc_info()[-1].tb_lineno}'
422
            self.addMessage.emit(MessageType.Error, message)
423
        finally:
424
            logs = self.listWidgetLogs.count()
425
            if logs:
426
                self.tabWidget.setTabText(self.tabWidget.indexOf(self.tabLogs), 'Logs({})'.format(logs))
427
            else:
428
                self.tabWidget.setTabText(self.tabWidget.indexOf(self.tabLogs), 'Logs')
429

    
430
    def on_left_rotation_clicked(self):
431
        from RotateCommand import RotateCommand
432

    
433
        try:
434
            if self.graphicsView.command is not None:
435
                self.graphicsView.command.reset()
436

    
437
            viewer = self.graphicsView
438
            items = viewer.scene.selectedItems()
439
            if items:
440
                viewer.scene.undo_stack.push(RotateCommand(viewer.scene, items, reverse=True))
441
        except Exception as ex:
442
            message = f"error occurred({repr(ex)}) in {sys.exc_info()[-1].tb_frame.f_code.co_filename}:" \
443
                      f"{sys.exc_info()[-1].tb_lineno}"
444

    
445
            self.addMessage.emit(MessageType.Error, message)
446

    
447
    def on_right_rotation_clicked(self):
448
        from RotateCommand import RotateCommand
449

    
450
        try:
451
            if self.graphicsView.command is not None:
452
                self.graphicsView.command.reset()
453

    
454
            viewer = self.graphicsView
455
            items = viewer.scene.selectedItems()
456
            if items:
457
                viewer.scene.undo_stack.push(RotateCommand(viewer.scene, items))
458
        except Exception as ex:
459
            message = f"error occurred({repr(ex)}) in {sys.exc_info()[-1].tb_frame.f_code.co_filename}:" \
460
                      f"{sys.exc_info()[-1].tb_lineno}"
461

    
462
            self.addMessage.emit(MessageType.Error, message)
463

    
464
    def on_horizontal_filp_clicked(self):
465
        from FlipCommand import FlipCommand
466

    
467
        try:
468
            if self.graphicsView.command is not None:
469
                self.graphicsView.command.reset()
470

    
471
            viewer = self.graphicsView
472
            items = viewer.scene.selectedItems()
473
            if items:
474
                viewer.scene.undo_stack.push(FlipCommand(viewer.scene, items, 1))
475
        except Exception as ex:
476
            message = f"error occurred({repr(ex)}) in {sys.exc_info()[-1].tb_frame.f_code.co_filename}:" \
477
                      f"{sys.exc_info()[-1].tb_lineno}"
478

    
479
            self.addMessage.emit(MessageType.Error, message)
480

    
481
    def on_vertical_filp_clicked(self):
482
        from FlipCommand import FlipCommand
483

    
484
        try:
485
            if self.graphicsView.command is not None:
486
                self.graphicsView.command.reset()
487

    
488
            viewer = self.graphicsView
489
            items = viewer.scene.selectedItems()
490
            if items:
491
                viewer.scene.undo_stack.push(FlipCommand(viewer.scene, items, 2))
492
        except Exception as ex:
493
            message = f"error occurred({repr(ex)}) in {sys.exc_info()[-1].tb_frame.f_code.co_filename}:" \
494
                      f"{sys.exc_info()[-1].tb_lineno}"
495

    
496
            self.addMessage.emit(MessageType.Error, message)
497

    
498
    def on_select_polygon_clicked(self):
499
        from SelectByPolygonCommand import SelectByPolygonCommand
500

    
501
        def on_success():
502
            try:
503
                count = len(self.actionSelectByPolygon.tag._polyline._vertices)
504
                if count > 2:
505
                    points = []
506
                    for point in self.actionSelectByPolygon.tag._polyline._vertices:
507
                        points.append(QPointF(point[0],point[1]))
508

    
509
                    polygon = QPolygonF(points)
510
                    path = QPainterPath()
511
                    path.addPolygon(polygon)
512
                    self.graphicsView.scene.setSelectionArea(path)
513

    
514
            finally:
515
                self.graphicsView.scene.removeItem(self.actionSelectByPolygon.tag._polyline)
516
                self.graphicsView.scene.invalidate()
517

    
518
                self.actionSelectByPolygon.tag.reset()
519
                self.actionSelectByPolygon.setChecked(False)
520
                self.graphicsView.useDefaultCommand()
521

    
522
        if self.graphicsView.command is not None:
523
            self.graphicsView.command.reset()
524

    
525
        if self.actionSelectByPolygon.isChecked():
526
            if not hasattr(self.actionSelectByPolygon, 'tag'):
527
                cmd = SelectByPolygonCommand(self.graphicsView)
528
                self.actionSelectByPolygon.tag = cmd
529

    
530
            self.actionSelectByPolygon.tag.onSuccess.connect(on_success)
531
            self.actionSelectByPolygon.tag.onRejected.connect(self.onCommandRejected)
532
            self.graphicsView.command = self.actionSelectByPolygon.tag
533

    
534
        if self.actionSelectByPolygon.isChecked() == False:
535
            self.onCommandRejected()
536

    
537
    def closeEvent(self, event: QCloseEvent) -> None:
538
        """save geometry and state and then ask user to save drawing which is modified"""
539

    
540
        self.settings.setValue('geometry', self.saveGeometry())
541
        self.settings.setValue('windowState', self.saveState())
542

    
543
        self.save_drawing_if_necessary()
544

    
545
        """update view region"""
546
        app_doc_data = AppDocData.instance()
547
        if app_doc_data.activeDrawing:
548
            rect = self.graphicsView.viewport().rect()
549
            app_doc_data.activeDrawing.view_rect = self.graphicsView.mapToScene(rect).boundingRect()
550
            app_doc_data.update_view_region(app_doc_data.activeDrawing)
551
        """up to here"""
552

    
553
        event.accept()
554

    
555
    def open_context_menu(self, position):
556
        indexes = self.treeViewDrawingList.selectedIndexes()
557
        if len(indexes) > 0:
558
            index = indexes[0]
559
            item = index.model().itemFromIndex(index)
560

    
561
            menu = QMenu()
562

    
563
            if not item.parent():
564
                newDrawingAction = menu.addAction(QIcon(':/images/New.svg'), self.tr('New...'))
565
                newDrawingAction.triggered.connect(lambda: self.newDrawingActionClickEvent(item))
566
                menu.addAction(newDrawingAction)
567
            else:
568
                deleteDrawingAction = menu.addAction(QIcon(':/images/Cancel.svg'), self.tr("Delete"))
569
                deleteDrawingAction.triggered.connect(lambda: self.deleteDrawingActionClickEvent(item))
570
                menu.addAction(deleteDrawingAction)
571

    
572
            menu.exec_(self.treeViewDrawingList.viewport().mapToGlobal(position))
573

    
574
    def on_new_drawing(self):
575
        self.new_drawing()
576

    
577
    def newDrawingActionClickEvent(self, item):
578
        self.new_drawing()
579

    
580
    def saveAsDrawingActionClickEvent(self, item):
581
        sourceDb = item.text(2)
582

    
583
        self.saveAs_drawing(sourceDb)
584

    
585
    def deleteDrawingActionClickEvent(self, item):
586
        """ delete selected drawing """
587
        try:
588
            msg = QMessageBox(self)
589
            msg.setIcon(QMessageBox.Question)
590
            msg.setText(self.tr('Do you want to delete drawing on list?\nHowever, Actual drawing is not deleted.'))
591
            msg.setWindowTitle(self.tr("Delete"))
592
            msg.setStandardButtons(QMessageBox.Ok | QMessageBox.Cancel)
593

    
594
            if QMessageBox.Ok == msg.exec_():
595
                model = self.treeViewDrawingList.model()
596
                index = item.index()
597
                drawing_name = model.data(model.index(index.row(), 0, index.parent()))
598
                drawing_path = model.data(model.index(index.row(), 2, index.parent()))
599

    
600
                app_doc_data = AppDocData.instance()
601
                app_doc_data.deleteDrawingByName(drawing_path)
602

    
603
                if app_doc_data.activeDrawing:
604
                    if drawing_name == app_doc_data.activeDrawing.name and drawing_path == app_doc_data.activeDrawing.path:
605
                        app_doc_data.activeDrawing = None
606

    
607
                        if self.graphicsView.hasImage():
608
                            self.graphicsView.clearImage()
609
                            self.graphicsView.scene.clear()
610

    
611
                        self.initTableWidgetHMB()
612

    
613
                self.load_drawing_list()
614
        except Exception as ex:
615
            message = f"error occurred({repr(ex)}) in {sys.exc_info()[-1].tb_frame.f_code.co_filename}:" \
616
                      f"{sys.exc_info()[-1].tb_lineno}"
617
            self.addMessage.emit(MessageType.Error, message)
618

    
619
    def clear_data(self):
620
        self.clear_HMB()
621

    
622
    def eventFilter(self, source, event):
623
        """ display mouse position of graphics view """
624
        if event.type() == QEvent.MouseMove:
625
            pos = self.graphicsView.mapToScene(event.pos())
626
            self._label_mouse.setText('mouse pos : ({},{})'.format(round(pos.x()), round(pos.y())))
627

    
628
        return QWidget.eventFilter(self, source, event)
629

    
630
    def load_stylesheet(self, file):
631
        """load stylesheets"""
632

    
633
        QtWidgets.qApp.loadStyleSheet(os.path.join(os.path.dirname(os.path.realpath(__file__)), file))
634

    
635
        app_doc_data = AppDocData.instance()
636
        configs = [Config('app', 'stylesheet', file)]
637
        app_doc_data.saveAppConfigs(configs)
638

    
639
        for action in self.menuTheme.actions():
640
            if action.text() == file: continue
641
            action.setChecked(False)
642

    
643
    def load_language(self, file):
644
        """ load language file and then apply selected language """
645
        try:
646

    
647
            qm_file = os.path.join(os.path.dirname(os.path.realpath(__file__)), 'translate', '{0}.qm'.format(file))
648
            QtWidgets.qApp.load_language(qm_file)
649

    
650
            app_doc_data = AppDocData.instance()
651
            configs = [Config('app', 'language', file)]
652
            app_doc_data.saveAppConfigs(configs)
653

    
654
            for action in self.menuLanguage.actions():
655
                if action.text().lower() == file.lower(): continue
656
                action.setChecked(False)
657
        finally:
658
            self.retranslateUi(self)
659

    
660
    def clear_output(self):
661
        self.tableWidgetOutput.setColumnCount(0)
662
        self.tableWidgetOutput.setRowCount(0)
663

    
664
        self.tableWidgetDeviation.setColumnCount(0)
665
        self.tableWidgetDeviation.setRowCount(0)
666

    
667
        app_doc_data = AppDocData.instance()
668
        app_doc_data.outputs.clear()
669

    
670
    def clear_loop(self):
671
        self.tableWidgetLoop.setColumnCount(0)
672

    
673
    def initTableWidgetHMB(self):
674
        app_doc_data = AppDocData.instance()
675

    
676
        column_infos = app_doc_data.getHMBDisplayNameAndUnitsExpression()
677
        """ convert unit """
678
        for row in range(column_infos.rowCount()):
679
            item = column_infos.item(row, 1)
680
            unit = self.convertToUnits(item.text())
681
            item.setText(unit)
682

    
683
        self.tableWidgetHMB.setModel(column_infos)
684

    
685
        self.tableWidgetHMB.hideRow(0)  # UID
686
        self.tableWidgetHMB.hideRow(1)  # Components_UID
687
        self.tableWidgetHMB.hideRow(2)  # Stream_No
688
        # self.tableWidgetHMB.hideRow(3)  # Phase_Type
689
        # self.tableWidgetHMB.hideRow(4)  # Flowrate_Mass
690
        # self.tableWidgetHMB.hideRow(5)  # Flowrate_Volume
691
        # self.tableWidgetHMB.hideRow(6)  # Density
692
        # self.tableWidgetHMB.hideRow(7)  # Viscosity
693
        # self.tableWidgetHMB.hideRow(8)  # Temperature
694
        # self.tableWidgetHMB.hideRow(9)  # Molecular_Weight
695
        # self.tableWidgetHMB.hideRow(10)  # Specific_Heat_Ratio
696
        # self.tableWidgetHMB.hideRow(11)  # Compress_Factor
697
        # self.tableWidgetHMB.hideRow(12)  # Nominal_Pipe_Size
698
        # self.tableWidgetHMB.hideRow(13)  # Inside_Pipe_Size
699
        # self.tableWidgetHMB.hideRow(14)  # Schedule_No
700
        # self.tableWidgetHMB.hideRow(15)  # Straight_Length
701
        # self.tableWidgetHMB.hideRow(16)  # Equivalent_Length
702
        self.tableWidgetHMB.hideRow(17)  # Equivalent_Length_Input
703
        self.tableWidgetHMB.hideRow(18)  # Fitting_Length
704
        self.tableWidgetHMB.hideRow(19)  # Fitting_K
705
        self.tableWidgetHMB.hideRow(20)  # Equivalent_Length_Cal
706
        # self.tableWidgetHMB.hideRow(21)  # Roughness
707
        # self.tableWidgetHMB.hideRow(22)  # Limitation_Velocity
708
        # self.tableWidgetHMB.hideRow(23)  # Limitation_Pressure_Drop
709
        # self.tableWidgetHMB.hideRow(24)  # Separator
710
        # self.tableWidgetHMB.hideRow(25)  # Velocity
711
        # self.tableWidgetHMB.hideRow(26)  # Reynolds
712
        # self.tableWidgetHMB.hideRow(27)  # Friction_Factor
713
        # self.tableWidgetHMB.hideRow(28)  # Pressure_Drop
714
        # self.tableWidgetHMB.hideRow(29)  # Pressure_Drop_Friction
715
        # self.tableWidgetHMB.hideRow(30)  # Pressure_Drop_Static
716
        # self.tableWidgetHMB.hideRow(31)  # Pressure_Pipe_End_Point
717
        self.tableWidgetHMB.hideRow(32)  # Power
718

    
719
        # self.tableWidgetHMB.setEditTriggers(QAbstractItemView.NoEditTriggers)
720
        self.tableWidgetHMB.verticalHeader().setVisible(False)
721

    
722
        col_names = ['Stream No.\n', 'Unit\n']
723
        column_infos.setHorizontalHeaderLabels(col_names)
724

    
725
        self.tableWidgetHMB.resizeColumnsToContents()
726
        self.tableWidgetHMB.resizeRowsToContents()
727

    
728
    def copy_selection(self, table_widget):
729
        """copy selected text to clipboard"""
730

    
731
        import io
732
        import csv
733

    
734
        selection = table_widget.selectedIndexes()
735
        if selection:
736
            rows = sorted(index.row() for index in selection)
737
            columns = sorted(index.column() for index in selection)
738
            rowcount = rows[-1] - rows[0] + 1
739
            colcount = columns[-1] - columns[0] + 1
740
            table = [[''] * colcount for _ in range(rowcount)]
741
            for index in selection:
742
                row = index.row() - rows[0]
743
                column = index.column() - columns[0]
744
                table[row][column] = index.data()
745
            stream = io.StringIO()
746
            csv.writer(stream, delimiter='\t').writerows(table)
747
            QApplication.clipboard().setText(stream.getvalue())
748

    
749
    def paste_selection(self, table_widget):
750
        """paste text of clipboard to table widget"""
751

    
752
        import io
753
        import csv
754

    
755
        selection = table_widget.selectedIndexes()
756
        if selection:
757
            model = table_widget.model()
758

    
759
            buffer = QApplication.clipboard().text()
760
            rows = sorted(index.row() for index in selection)
761
            columns = sorted(index.column() for index in selection)
762
            reader = csv.reader(io.StringIO(buffer), delimiter='\t')
763
            if len(rows) == 1 and len(columns) == 1:
764
                for i, line in enumerate(reader):
765
                    for j, cell in enumerate(line):
766
                        index = model.index(rows[0] + i, columns[0] + j)
767
                        item = model.item(index.row(), index.column())
768
                        if item.isEditable():
769
                            data = model.data(index, Qt.UserRole)
770
                            if type(data) is not type(cell) or data != cell:
771
                                item.setBackground(Qt.magenta)
772
                                model.setData(index, cell)
773
            else:
774
                arr = [[cell for cell in row] for row in reader]
775
                for index in selection:
776
                    row = index.row() - rows[0]
777
                    column = index.column() - columns[0]
778
                    index = model.index(index.row(), index.column())
779
                    item = model.item(index.row(), index.column())
780
                    if item.isEditable():
781
                        data = model.data(index, Qt.UserRole)
782
                        if type(data) is not type(arr[row][column]) or data != arr[row][column]:
783
                            item.setBackground(Qt.magenta)
784
                            model.setData(index, arr[row][column])
785

    
786
    '''
787
        @brief      Drawing 속성의 Units 에서 Key값을 이용하여 Value를 찾음
788
        @author     yeonjin
789
        @date       19.08.30
790
    '''
791

    
792
    def findValue(self, key):
793
        value = None
794

    
795
        key = key.replace("{", "").replace("}", "")
796
        for attr in AppDocData.instance().activeDrawing.attrs:
797
            if attr[0] == 'Units':
798
                if key in attr[1]:
799
                    value = attr[1][key]
800
                    break
801

    
802
        return value
803

    
804
    '''
805
        @brief      Convert UnitsExpression To Units Value
806
        @author     yeonjin
807
        @date       19.08.29
808
    '''
809

    
810
    def convertToUnits(self, unitsExpression):
811
        import re
812

    
813
        if unitsExpression is None or AppDocData.instance().activeDrawing is None:
814
            return ''
815

    
816
        found = re.findall('{.*?}', unitsExpression)
817
        for f in found:
818
            key = f
819
            val = self.findValue(key)
820
            if val:
821
                unitsExpression = unitsExpression.replace(key, val)
822

    
823
        return unitsExpression
824

    
825
    def on_left_alignment(self):
826
        """align selected items to left"""
827

    
828
        try:
829
            if self.graphicsView.command is not None:
830
                self.graphicsView.command.reset()
831

    
832
            app_doc_data = AppDocData.instance()
833
            if app_doc_data._activeDrawing is not None:
834
                items = self.graphicsView.scene.selectedItems()
835
                if items:
836
                    self.graphicsView.scene._undo_stack.push(
837
                        LeftAlignmentCommand.LeftAlignmentCommand(self.graphicsView.scene,
838
                                                                  self.graphicsView.scene.selectedItems()))
839
        except Exception as ex:
840
            message = f"error occurred({repr(ex)}) in {sys.exc_info()[-1].tb_frame.f_code.co_filename}:" \
841
                      f"{sys.exc_info()[-1].tb_lineno}"
842
            self.addMessage.emit(MessageType.Error, message)
843

    
844
    def on_right_alignment(self):
845
        """align selected items to right"""
846

    
847
        try:
848
            if self.graphicsView.command is not None:
849
                self.graphicsView.command.reset()
850

    
851
            app_doc_data = AppDocData.instance()
852
            if app_doc_data._activeDrawing is not None:
853
                items = self.graphicsView.scene.selectedItems()
854
                if items:
855
                    self.graphicsView.scene._undo_stack.push(
856
                        RightAlignmentCommand.RightAlignmentCommand(self.graphicsView.scene,
857
                                                                    self.graphicsView.scene.selectedItems()))
858
        except Exception as ex:
859
            message = f"error occurred({repr(ex)}) in {sys.exc_info()[-1].tb_frame.f_code.co_filename}:" \
860
                      f"{sys.exc_info()[-1].tb_lineno}"
861
            self.addMessage.emit(MessageType.Error, message)
862

    
863
    def on_up_alignment(self):
864
        """align selected items to up"""
865

    
866
        try:
867
            if self.graphicsView.command is not None:
868
                self.graphicsView.command.reset()
869

    
870
            app_doc_data = AppDocData.instance()
871
            if app_doc_data._activeDrawing is not None:
872
                items = self.graphicsView.scene.selectedItems()
873
                if items:
874
                    self.graphicsView.scene._undo_stack.push(
875
                        UpAlignmentCommand.UpAlignmentCommand(self.graphicsView.scene,
876
                                                              self.graphicsView.scene.selectedItems()))
877
        except Exception as ex:
878
            message = f"error occurred({repr(ex)}) in {sys.exc_info()[-1].tb_frame.f_code.co_filename}:" \
879
                      f"{sys.exc_info()[-1].tb_lineno}"
880
            self.addMessage.emit(MessageType.Error, message)
881

    
882
    def on_down_alignment(self):
883
        """align selected items to down"""
884

    
885
        try:
886
            if self.graphicsView.command is not None:
887
                self.graphicsView.command.reset()
888

    
889
            app_doc_data = AppDocData.instance()
890
            if app_doc_data._activeDrawing is not None:
891
                items = self.graphicsView.scene.selectedItems()
892
                if items:
893
                    self.graphicsView.scene._undo_stack.push(
894
                        DownAlignmentCommand.DownAlignmentCommand(self.graphicsView.scene,
895
                                                                  self.graphicsView.scene.selectedItems()))
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

    
901
    def load_drawing_list(self):
902
        """load pfd drawing list"""
903

    
904
        try:
905
            app_doc_data = AppDocData.instance()
906
            drawings = app_doc_data.get_drawings()
907

    
908
            if self.treeViewDrawingList.model():
909
                self.treeViewDrawingList.model().clear()
910

    
911
            model = QStandardItemModel()
912
            root = [QStandardItem(self.tr('Drawings')), QStandardItem('')]
913
            model.appendRow(root)
914

    
915
            for drawing in drawings:
916
                items = [QStandardItem(drawing.name), QStandardItem(drawing.date_time), QStandardItem(drawing.org_path)]
917
                items[0].setIcon(QIcon(':images/PFD.png'))
918
                items[0].setData(drawing, Qt.UserRole)
919
                root[0].appendRow(items)
920

    
921
            model.setHorizontalHeaderLabels([self.tr('Name'), self.tr('DateTime'), self.tr('Path')])
922
            self.treeViewDrawingList.setModel(model)
923

    
924
            root[0].setText(self.tr('Drawings') + f"({root[0].rowCount()})")
925
            self.treeViewDrawingList.expandAll()
926
            self.treeViewDrawingList.sortByColumn(1, Qt.DescendingOrder)
927
            self.treeViewDrawingList.resizeColumnToContents(0)
928
            self.treeViewDrawingList.hideColumn(2)
929
        except Exception as ex:
930
            message = f"error occurred({repr(ex)}) in {sys.exc_info()[-1].tb_frame.f_code.co_filename}:" \
931
                      f"{sys.exc_info()[-1].tb_lineno}"
932
            self.addMessage.emit(MessageType.Error, message)
933

    
934
    def save_drawing_if_necessary(self):
935
        """ask user to save drawing or not when drawing is modified"""
936

    
937
        app_doc_data = AppDocData.instance()
938
        if app_doc_data.activeDrawing and app_doc_data.activeDrawing.modified:
939
            if QMessageBox.Yes == QMessageBox.question(self, self.tr("Question"),
940
                                                       self.tr("Do you want to save drawing?"),
941
                                                       QMessageBox.Yes | QMessageBox.No):
942
                self.actionSaveCliked(False)
943

    
944
    def open_selected_drawing(self, index: QModelIndex):
945
        """ open selected drawing """
946
        try:
947
            model = self.treeViewDrawingList.model()
948
            root = index.parent()
949
            if root:
950
                file_path = model.data(model.index(index.row(), 2, root), Qt.DisplayRole)
951
                if os.path.exists(file_path):
952
                    self.save_drawing_if_necessary()
953
                    self.open_drawing(file_path)
954
        except Exception as ex:
955
            message = f"error occurred({repr(ex)}) in {sys.exc_info()[-1].tb_frame.f_code.co_filename}:" \
956
                      f"{sys.exc_info()[-1].tb_lineno}"
957
            self.addMessage.emit(MessageType.Error, message)
958

    
959
    def actionSaveCliked(self, show_message=True):
960
        """action save click event"""
961
        from datetime import datetime
962
        from AppDocData import AppDocData
963
        from EngineeringAbstractItem import QEngineeringAbstractItem
964

    
965
        try:
966
            app_doc_data = AppDocData.instance()
967
            if app_doc_data.activeDrawing is None:
968
                self.showImageSelectionMessageBox()
969
                return
970

    
971
            app_doc_data.activeDrawing.clearItemList()
972

    
973
            items = self.graphicsView.scene.items()
974
            for item in items:
975
                if issubclass(type(item), QEngineeringAbstractItem):
976
                    app_doc_data.activeDrawing.allItems.append(item)
977

    
978
            count = len(app_doc_data.activeDrawing.allItems)
979
            if count > 0:
980
                try:
981
                    self.progress = QProgressDialog(self.tr("Please wait for a while"), self.tr("Cancel"), 0, 100,
982
                                                    self) if not hasattr(self, 'progress') else self.progress
983
                    self.progress.setWindowModality(Qt.WindowModal)
984
                    self.progress.setAutoReset(True)
985
                    self.progress.setAutoClose(True)
986
                    self.progress.setMinimum(0)
987
                    self.progress.resize(600, 100)
988
                    self.progress.setWindowTitle(self.tr("Save"))
989
                    self.progress.show()
990

    
991
                    self.save_drawing_data()
992
                finally:
993
                    self.load_drawing_list()
994
                    self.progress.setValue(self.progress.maximum())
995
                    self.progress.hide()
996
                    if show_message:
997
                        QMessageBox.information(self, self.tr("Information"), self.tr("Save completed successfully."))
998

    
999
        except Exception as ex:
1000
            message = f"error occurred({repr(ex)}) in {sys.exc_info()[-1].tb_frame.f_code.co_filename}:" \
1001
                      f"{sys.exc_info()[-1].tb_lineno}"
1002
            self.addMessage.emit(MessageType.Error, message)
1003

    
1004
    def on_save(self):
1005
        self.actionSaveCliked()
1006

    
1007
    def on_save_as(self):
1008
        """save as drawing file"""
1009
        from shutil import copyfile
1010
        from datetime import datetime
1011
        from Drawing import Drawing
1012

    
1013
        app_doc_data = AppDocData.instance()
1014
        workspace = self.get_work_space()
1015

    
1016
        file_name = os.path.join(workspace, 'copy of ' + app_doc_data.activeDrawing.name + '.hytos')
1017
        options = QFileDialog.Options()
1018
        options |= QFileDialog.DontUseNativeDialog
1019
        name, _ = QFileDialog.getSaveFileName(self, self.tr('Save As'), file_name, 'HYTOS(*.hytos)', options=options)
1020
        if name:
1021
            try:
1022
                if os.path.splitext(name)[1] != '.hytos': name += '.hytos'
1023

    
1024
                self.actionSaveCliked()  # save current drawing
1025

    
1026
                app_doc_data = AppDocData.instance()
1027
                # copy current drawing file to new drawing file
1028
                copyfile(app_doc_data.activeDrawing.path, name)
1029
                app_doc_data.activeDrawing.path = name
1030

    
1031
                matches = [drawing for drawing in app_doc_data.get_drawings()
1032
                           if os.path.exists(drawing.path) and os.path.samefile(drawing.path, name)]
1033
                if not matches:
1034
                    drawing = Drawing(str(uuid.uuid4()), name, str(datetime.now().strftime('%Y-%m-%d %H:%M:%S')))
1035
                    app_doc_data.save_drawing(drawing)
1036
                else:
1037
                    drawing = Drawing(str(matches[0].UID), name, str(datetime.now().strftime('%Y-%m-%d %H:%M:%S')))
1038
                    app_doc_data.update_drawing(drawing)
1039

    
1040
                self.load_drawing_list()
1041
                self.open_border_file()
1042
                self.load_data(drawing)
1043

    
1044
                app_doc_data.activeDrawing.modified = False
1045
                self.setMainWindowTitle(f"{app_doc_data.activeDrawing.path}")
1046
            except Exception as ex:
1047
                message = 'error occurred({}) in {}:{}'.format(ex, sys.exc_info()[-1].tb_frame.f_code.co_filename,
1048
                                                               sys.exc_info()[-1].tb_lineno)
1049
                self.addMessage.emit(MessageType.Error, message)
1050

    
1051
    def on_undo(self):
1052
        """undo"""
1053
        self.graphicsView.scene.undo_stack.undo()
1054

    
1055
    def on_redo(self):
1056
        """redo"""
1057
        self.graphicsView.scene.undo_stack.redo()
1058

    
1059
    def save_drawing_data(self):
1060
        """ save drawing data """
1061

    
1062
        from datetime import datetime
1063
        from AppDocData import AppDocData
1064
        from SymbolSvgItem import SymbolSvgItem
1065
        from EngineeringStreamlineItem import QEngineeringStreamlineItem
1066
        from EngineeringCalloutTextItem import QEngineeringCalloutTextItem
1067
        from EngineeringCloudItem import QEngineeringCloudItem
1068
        from EngineeringDimensionItem import QEngineeringDimensionItem
1069

    
1070
        try:
1071
            app_doc_data = AppDocData.instance()
1072
            items = app_doc_data.activeDrawing.allItems
1073

    
1074
            maxValue = len(items)
1075
            self.progress.setMaximum(maxValue)
1076

    
1077
            app_doc_data.saveToDatabase([item for item in self.graphicsView.scene.items()
1078
                                         if hasattr(item, 'toSql') and (
1079
                                                 type(item) is SymbolSvgItem or
1080
                                                 type(item) is QEngineeringStreamlineItem or
1081
                                                 type(item) is QEngineeringCalloutTextItem or
1082
                                                 type(item) is QEngineeringDimensionItem or
1083
                                                 type(item) is QEngineeringCloudItem)],
1084
                                        self.progress.setValue)
1085

    
1086
            if app_doc_data.activeDrawing:
1087
                app_doc_data.activeDrawing.hmbTable.saveData()
1088
                app_doc_data.save_sheet_history('Save')
1089

    
1090
            """update drawing's modified time"""
1091
            drawings = app_doc_data.get_drawings()
1092
            drawing = [drawing for drawing in drawings if app_doc_data.activeDrawing.UID == drawing.UID]
1093
            if drawing:
1094
                drawing[0].date_time = datetime.now().strftime('%Y-%m-%d %H:%M:%S')
1095
                rect = self.graphicsView.viewport().rect()
1096
                drawing[0].view_rect = self.graphicsView.mapToScene(rect).boundingRect()
1097
                app_doc_data.update_drawing(drawing[0])
1098

    
1099
            app_doc_data.activeDrawing.modified = False
1100
            self.setMainWindowTitle(f"{app_doc_data.activeDrawing.path}")
1101

    
1102
            shutil.copyfile(app_doc_data.activeDrawing.org_path, app_doc_data.activeDrawing.org_path + ".bak")
1103
            shutil.copyfile(app_doc_data.activeDrawing.path, app_doc_data.activeDrawing.org_path)
1104
        except Exception as ex:
1105
            message = f"error occurred({repr(ex)}) in {sys.exc_info()[-1].tb_frame.f_code.co_filename}:" \
1106
                      f"{sys.exc_info()[-1].tb_lineno}"
1107
            self.addMessage.emit(MessageType.Error, message)
1108

    
1109
    '''
1110
        @brief  add message listwidget
1111
        @author humkyung
1112
        @date   2018.07.31
1113
    '''
1114

    
1115
    def onAddMessage(self, messageType, message):
1116
        from AppDocData import MessageType
1117

    
1118
        try:
1119
            current = QDateTime.currentDateTime()
1120

    
1121
            item = QListWidgetItem('{}: {}'.format(current.toString('hh:mm:ss'), message))
1122
            if messageType == MessageType.Error:
1123
                item.setForeground(Qt.red)
1124
            elif messageType == MessageType.Information:
1125
                item.setForeground(Qt.blue)
1126

    
1127
            self.listWidgetLogs.insertItem(0, item)
1128
        except Exception as ex:
1129
            print('error occurred({}) in {}:{}'.format(ex, sys.exc_info()[-1].tb_frame.f_code.co_filename,
1130
                                                       sys.exc_info()[-1].tb_lineno))
1131
        finally:
1132
            logs = self.listWidgetLogs.count()
1133
            if logs:
1134
                self.tabWidget.setTabText(self.tabWidget.indexOf(self.tabLogs), 'Logs({})'.format(logs))
1135
            else:
1136
                self.tabWidget.setTabText(self.tabWidget.indexOf(self.tabLogs), 'Logs')
1137

    
1138
    '''
1139
        @brief      Area Zoom
1140
        @author     Jeongwoo
1141
        @date       2018.06.27
1142
        @history    connect command's rejected signal
1143
    '''
1144

    
1145
    def onAreaZoom(self, action):
1146
        if self.actionZoom.isChecked():
1147
            if self.graphicsView.command is not None:
1148
                self.graphicsView.command.reset()
1149

    
1150
            cmd = AreaZoomCommand.AreaZoomCommand(self.graphicsView)
1151
            cmd.onRejected.connect(self.onCommandRejected)
1152
            self.graphicsView.command = cmd
1153

    
1154
    def fitWindow(self, action):
1155
        """fit window"""
1156
        app_doc_data = AppDocData.instance()
1157
        if app_doc_data.activeDrawing:
1158
            self.graphicsView.useDefaultCommand()
1159
            scene_rect = self.graphicsView.scene.itemsBoundingRect()
1160
            if scene_rect.left() > 0:
1161
                scene_rect.setLeft(0)
1162
            if scene_rect.top() > 0:
1163
                scene_rect.setTop(0)
1164
            if scene_rect.right() < 1189:
1165
                scene_rect.setRight(1189)
1166
            if scene_rect.bottom() < 841:
1167
                scene_rect.setBottom(841)
1168

    
1169
            self.graphicsView.setSceneRect(scene_rect)
1170
            if action is None and app_doc_data.activeDrawing.view_rect.isValid():
1171
                self.graphicsView.zoom_rect(app_doc_data.activeDrawing.view_rect)
1172
            else:
1173
                self.graphicsView.zoomImageInit()
1174
            self.graphicsView.scene.invalidate()
1175

    
1176
    def on_view_connector(self, checked):
1177
        """turn on/off connector"""
1178
        for item in self.graphicsView.scene.items():
1179
            if not hasattr(item, 'connectors'):
1180
                continue
1181
            for connector in item.connectors:
1182
                connector.setVisible(True) if checked else connector.hide()
1183

    
1184
    def scene_changed(self):
1185
        """update modified flag"""
1186

    
1187
        app_doc_data = AppDocData.instance()
1188
        app_doc_data.activeDrawing.modified = True
1189
        self.setMainWindowTitle(f"{app_doc_data.activeDrawing.path}*")
1190

    
1191
    def onSelectionChanged(self):
1192
        """selection changed"""
1193
        from EngineeringStreamlineItem import QEngineeringStreamlineItem
1194

    
1195
        items = [item for item in self.graphicsView.scene.selectedItems() if
1196
                 issubclass(type(item), SymbolSvgItem) or type(item) is QEngineeringStreamlineItem]
1197
        if items:
1198
            item = items[-1]
1199

    
1200
            if type(item) is QEngineeringErrorItem:
1201
                for index in range(self.tableWidgetHMB.rowCount()):
1202

    
1203
                    if self.tableWidgetHMB.item(index, 1).tag is item:
1204
                        self.tableWidgetHMB.selectRow(index)
1205
                        break
1206

    
1207
    '''
1208
        @brief      Initialize scene and itemTreeWidget
1209
        @author     Jeongwoo
1210

1211
        @date       2018.06.14
1212
        @history    humkyung 2018.08.16 ask to delete recognized items before remove
1213
    '''
1214

    
1215
    def onInitializeScene(self, action):
1216
        try:
1217
            msg = QMessageBox(self)
1218
            msg.setIcon(QMessageBox.Question)
1219
            msg.setText(self.tr('Do you want to remove all items?\nThis work cannot be recovered.'))
1220
            msg.setWindowTitle(self.tr("Clear Screen"))
1221
            msg.setStandardButtons(QMessageBox.Ok | QMessageBox.Cancel)
1222
            if QMessageBox.Ok == msg.exec_():
1223

    
1224
                appDocData = AppDocData.instance()
1225
                appDocData.activeDrawing.hmbTable.reset()
1226
                appDocData.clearItemList(True)
1227

    
1228
                items = self.graphicsView.scene.items()
1229
                for item in items:
1230
                    if type(item) is not QGraphicsPixmapItem and item.scene() is not None:
1231
                        self.graphicsView.scene.removeItem(item)
1232

    
1233
                appDocData.initializeDataByDrawingUID(appDocData.activeDrawing.UID)
1234

    
1235
                self.initTableWidgetHMB()
1236

    
1237
        except Exception as ex:
1238
            message = 'error occurred({}) in {}:{}'.format(ex, sys.exc_info()[-1].tb_frame.f_code.co_filename,
1239
                                                           sys.exc_info()[-1].tb_lineno)
1240
            self.addMessage.emit(MessageType.Error, message)
1241

    
1242
    '''
1243
        @brief      Manage Checkable Action statement
1244
        @author     Jeongwoo
1245
        @date       2018.05.10
1246
        @history    2018.06.27  Jeongwoo    Chnage method to initialize command [Set None → DefaultCommand]
1247
    '''
1248

    
1249
    def actionGroupTriggered(self, action):
1250
        if hasattr(self.actionLine, 'tag'):
1251
            self.actionLine.tag.onRejected.emit(None)
1252

    
1253
        if self.graphicsView.command is not None:
1254
            self.graphicsView.useDefaultCommand()
1255

    
1256
        for _action in [x for x in self.actionGroup.actions() if x is not action]:
1257
            _action.setChecked(False)
1258
            if _action is self.actionLine:
1259
                for item in self.graphicsView.scene.items():
1260
                    if not hasattr(item, 'connectors'): continue
1261
                    for connector in item.connectors: connector.hide()
1262

    
1263
        action.setChecked(True)
1264
        if action is self.actionLine:
1265
            for item in self.graphicsView.scene.items():
1266
                if not hasattr(item, 'connectors'): continue
1267
                for connector in item.connectors: connector.setVisible(True)
1268

    
1269
    def showSymbolEditor(self):
1270
        from SymbolEditorDialog import QSymbolEditorDialog
1271

    
1272
        dlg = QSymbolEditorDialog()
1273
        dlg.exec_()
1274

    
1275
    def editor_lost_focus(self, item):
1276
        cursor = item.textCursor()
1277
        cursor.clearSelection()
1278
        item.setTextCursor(cursor)
1279

    
1280
        """
1281
        if item.toPlainText():
1282
            self.removeItem(item)
1283
            item.deleteLater()
1284
        """
1285

    
1286
    def item_selected(self, item):
1287
        pass
1288
        """
1289
        font = item.font()
1290
        color = item.defaultTextColor()
1291
        self.fontCombo.setCurrentFont(font)
1292
        self.fontSizeCombo.setEditText(str(font.pointSize()))
1293
        self.boldAction.setChecked(font.weight() == QFont.Bold)
1294
        self.italicAction.setChecked(font.italic())
1295
        self.underlineAction.setChecked(font.underline())
1296
        """
1297

    
1298
    def on_callout_created(self):
1299
        from CreateCommand import CreateCommand
1300
        try:
1301
            QApplication.restoreOverrideCursor()
1302

    
1303
            callout = self.actionPlaceTextBox.tag.callout
1304
            callout.setTextInteractionFlags(Qt.TextEditorInteraction)
1305
            callout.setFocus()
1306
            callout.lost_focus.connect(self.editor_lost_focus)
1307
            callout.selected_change.connect(self.item_selected)
1308

    
1309
            self.graphicsView.scene.undo_stack.push(CreateCommand(self.graphicsView.scene, [callout, ]))
1310
        finally:
1311
            self.actionPlaceTextBox.tag.reset()
1312

    
1313
    def on_place_callout_textbox(self):
1314
        """place callout textbox"""
1315
        from PlaceCalloutCommand import PlaceCalloutCommand
1316
        if self.graphicsView.command is not None:
1317
            self.graphicsView.command.reset()
1318

    
1319
        if not hasattr(self.actionPlaceTextBox, 'tag'):
1320
            self.actionPlaceTextBox.tag = PlaceCalloutCommand(self.graphicsView)
1321

    
1322
        self.actionPlaceTextBox.tag.onSuccess.connect(self.on_callout_created)
1323
        self.actionPlaceTextBox.tag.onRejected.connect(self.onCommandRejected)
1324

    
1325
        self.graphicsView.command = self.actionPlaceTextBox.tag
1326

    
1327
    def on_dimension_created(self):
1328
        from CreateCommand import CreateCommand
1329
        try:
1330
            QApplication.restoreOverrideCursor()
1331

    
1332
            dimension = self.actionPlaceDimension.tag.dimension
1333
            dimension.transfer.onRemoved.connect(self.on_item_removed)
1334

    
1335
            self.graphicsView.scene.undo_stack.push(CreateCommand(self.graphicsView.scene, [dimension, ]))
1336
        finally:
1337
            self.actionPlaceDimension.tag.reset()
1338

    
1339
    def on_place_dimension(self):
1340
        """place dimension"""
1341
        from PlaceDimensionCommand import PlaceDimensionCommand
1342
        if self.graphicsView.command is not None:
1343
            self.graphicsView.command.reset()
1344

    
1345
        if not hasattr(self.actionPlaceDimension, 'tag'):
1346
            self.actionPlaceDimension.tag = PlaceDimensionCommand(self.graphicsView)
1347

    
1348
        self.actionPlaceDimension.tag.onSuccess.connect(self.on_dimension_created)
1349
        self.actionPlaceDimension.tag.onRejected.connect(self.onCommandRejected)
1350

    
1351
        self.graphicsView.command = self.actionPlaceDimension.tag
1352

    
1353
    def on_place_cloud(self):
1354
        """place a cloud"""
1355
        from PlaceCloudCommand import PlaceCloudCommand
1356
        if self.graphicsView.command is not None:
1357
            self.graphicsView.command.reset()
1358

    
1359
        def on_cloud_created():
1360
            from CreateCommand import CreateCommand
1361
            try:
1362
                QApplication.restoreOverrideCursor()
1363

    
1364
                cloud = self.actionPlaceCloud.tag.cloud
1365
                self.graphicsView.scene.undo_stack.push(CreateCommand(self.graphicsView.scene, [cloud, ]))
1366
            finally:
1367
                self.actionPlaceCloud.tag.reset()
1368

    
1369
        if not hasattr(self.actionPlaceCloud, 'tag'):
1370
            self.actionPlaceCloud.tag = PlaceCloudCommand(self.graphicsView)
1371

    
1372
        self.actionPlaceCloud.tag.onSuccess.connect(on_cloud_created)
1373
        self.actionPlaceCloud.tag.onRejected.connect(self.onCommandRejected)
1374

    
1375
        self.graphicsView.command = self.actionPlaceCloud.tag
1376

    
1377
    def on_help(self):
1378
        """open user manual"""
1379
        import os
1380

    
1381
        try:
1382
            help_file_path = os.path.join(os.path.dirname(os.path.realpath(__file__)), 'HYTOS User Manual.pdf')
1383
            os.startfile(f"\"{help_file_path}\"")
1384
        except Exception as ex:
1385
            message = 'error occurred({}) in {}:{}'.format(ex, sys.exc_info()[-1].tb_frame.f_code.co_filename,
1386
                                                           sys.exc_info()[-1].tb_lineno)
1387
            self.addMessage.emit(MessageType.Error, message)
1388

    
1389
    def on_about(self):
1390
        """show about dialog"""
1391
        from AboutDialog import QAboutDialog
1392

    
1393
        dlg = QAboutDialog()
1394
        dlg.exec_()
1395

    
1396
    def on_readme(self):
1397
        """open readme.html"""
1398

    
1399
        file_path = os.path.join(os.path.dirname(os.path.realpath(__file__)), 'readme.html')
1400
        os.startfile(f"\"{file_path}\"")
1401

    
1402
    def update_label_contents(self):
1403
        from EngineeringCalloutTextItem import QEngineeringCalloutTextItem
1404

    
1405
        items = [item for item in self.graphicsView.scene.items() if issubclass(type(item), SymbolSvgItem) or
1406
                 type(item) is QEngineeringStreamlineItem or type(item) is QEngineeringCalloutTextItem]
1407
        for item in items:
1408
            item.update_label_contents()
1409

    
1410
    def onOptions(self):
1411
        from OptionsDialog import QOptionsDialog
1412
        try:
1413
            app_doc_data = AppDocData.instance()
1414
            configs = app_doc_data.getAppConfigs('option', 'TagFontSize')
1415
            old_tag_font_size = configs[0].value if configs and len(configs) == 1 else 6
1416

    
1417
            configs = app_doc_data.getAppConfigs('option', 'TagFontColor')
1418
            old_tag_font_color = configs[0].value if configs and len(configs) == 1 else '#000000'
1419

    
1420
            configs = app_doc_data.getAppConfigs('option', 'CalloutFontSize')
1421
            old_callout_font_size = configs[0].value if configs and len(configs) == 1 else 6
1422

    
1423
            configs = app_doc_data.getAppConfigs('option', 'CalloutTextColor')
1424
            old_callout_text_color = configs[0].value if configs and len(configs) == 1 else '#000000'
1425

    
1426
            dlg = QOptionsDialog(self)
1427
            dlg.setWindowFlags(dlg.windowFlags() & ~Qt.WindowContextHelpButtonHint)
1428
            if QDialog.Accepted == dlg.exec_():
1429
                if app_doc_data.activeDrawing:
1430
                    if str(old_tag_font_size) != str(dlg.tag_font_size) or \
1431
                            old_tag_font_color != dlg.tag_text_color or \
1432
                            str(old_callout_font_size) != str(dlg.callout_font_size) or \
1433
                            old_callout_text_color != dlg.callout_text_color:
1434
                        self.update_label_contents()
1435

    
1436
        except Exception as ex:
1437
            message = 'error occurred({}) in {}:{}'.format(ex, sys.exc_info()[-1].tb_frame.f_code.co_filename,
1438
                                                           sys.exc_info()[-1].tb_lineno)
1439
            self.addMessage.emit(MessageType.Error, message)
1440

    
1441
    def change_output_font_color(self):
1442
        try:
1443
            row_count = self.tableWidgetDeviation.rowCount()
1444
            col_count = self.tableWidgetDeviation.columnCount()
1445
            for row in range(row_count):
1446
                for col in range(col_count):
1447
                    if row == 0:
1448
                        item = self.tableWidgetDeviation.item(row, col)
1449
                        item.setText('RUN CALCULATION')
1450
                        item.setForeground(Qt.red)
1451
                        self.tableWidgetDeviation.setItem(row, col, item)
1452
                    else:
1453
                        self.tableWidgetDeviation.item(row, col).setForeground(QBrush(QColor(169, 169, 169)))
1454

    
1455
            row_count = self.tableWidgetOutput.rowCount()
1456
            col_count = self.tableWidgetOutput.columnCount()
1457
            for row in range(row_count):
1458
                for col in range(col_count):
1459
                    self.tableWidgetOutput.item(row, col).setForeground(QBrush(QColor(169, 169, 169)))
1460
                    col_span = self.tableWidgetOutput.columnSpan(row, col)
1461
                    if col_span > 1:
1462
                        break
1463
        except Exception as ex:
1464
            message = 'error occurred({}) in {}:{}'.format(ex, sys.exc_info()[-1].tb_frame.f_code.co_filename,
1465
                                                           sys.exc_info()[-1].tb_lineno)
1466
            self.addMessage.emit(MessageType.Error, message)
1467

    
1468
    def calculation(self, saving=False):
1469
        """execute hydro calculation"""
1470
        from AppDocData import AppDocData
1471
        from Calculation import Calculation
1472
        from HydroCalculationCommand import HydroCalculationCommand
1473
        from CalculationValidation import QCalculationValidation
1474
        from ValidationDialog import QValidationDialog
1475

    
1476
        try:
1477
            if self.graphicsView.command is not None:
1478
                self.graphicsView.command.reset()
1479

    
1480
            app_doc_data = AppDocData.instance()
1481
            if app_doc_data.activeDrawing is None:
1482
                self.showImageSelectionMessageBox()
1483
                return
1484

    
1485
            hmbs = app_doc_data.activeDrawing.hmbTable._hmbs
1486
            if hmbs is not None:
1487
                try:
1488
                    errors = []
1489
                    items = [item for item in self.graphicsView.scene.items() if type(item) is SymbolSvgItem or
1490
                             type(item) is QEngineeringStreamlineItem]
1491
                    for item in items:
1492
                        error = item.validate()
1493
                        if error:
1494
                            errors.extend(error)
1495

    
1496
                    HydroCalculationCommand.ERRORS = 0
1497
                    if errors:
1498
                        dlg = QValidationDialog(self, errors)
1499
                        dlg.show()
1500
                        HydroCalculationCommand.ERRORS = len(errors)
1501
                    else:
1502
                        self.progress = QProgressDialog(self.tr("Please wait for a while"), self.tr("Cancel"), 0, 100,
1503
                                                        self) \
1504
                            if not hasattr(self, 'progress') else self.progress
1505
                        self.progress.setWindowModality(Qt.WindowModal)
1506
                        self.progress.setAutoReset(True)
1507
                        self.progress.setAutoClose(True)
1508
                        self.progress.setMinimum(0)
1509
                        self.progress.resize(600, 100)
1510
                        self.progress.setWindowTitle(self.tr("Calculate data..."))
1511
                        self.progress.show()
1512

    
1513
                        maxValue = len(hmbs)
1514
                        self.progress.setMaximum(maxValue)
1515

    
1516
                        for hmb in hmbs:
1517
                            self.progress.setValue(self.progress.value() + 1)
1518

    
1519
                            if hmb.phase_type:
1520
                                Calculation(hmb)
1521

    
1522
                            QApplication.processEvents()
1523

    
1524
                        messages = None
1525
                        """ generate loop """
1526
                        cmd = HydroCalculationCommand(self.graphicsView)
1527
                        messages = cmd.execute(None)
1528
                        cmd.execute_second(None)
1529

    
1530
                        app_doc_data.activeDrawing.loops = cmd.loops
1531

    
1532
                        self.display_loops()
1533
                        self.display_output()
1534

    
1535
                        self.load_HMB()
1536

    
1537
                        """pop up error message dialog if there are some errors"""
1538
                        if messages:
1539
                            dlg = QCalculationValidation()
1540
                            dlg.show_dialog('Calculation will be terminated!', messages)
1541

    
1542
                        if saving:
1543
                            app_doc_data.save_sheet_history('Calculation')
1544
                finally:
1545
                    self.progress.setValue(self.progress.maximum())
1546
                    self.progress.hide()
1547
        except Exception as ex:
1548
            message = f"error occurred({repr(ex)}) in {sys.exc_info()[-1].tb_frame.f_code.co_filename}:" \
1549
                      f"{sys.exc_info()[-1].tb_lineno}"
1550
            self.addMessage.emit(MessageType.Error, message)
1551

    
1552
    def on_generate_report(self) -> None:
1553
        """generate calculation report"""
1554
        from tempfile import NamedTemporaryFile
1555
        import openpyxl
1556
        from DrawImage import DrawImage
1557
        from openpyxl.styles import Font
1558
        from datetime import datetime
1559

    
1560
        try:
1561
            app_doc_data = AppDocData.instance()
1562
            if app_doc_data.activeDrawing is None:
1563
                self.showImageSelectionMessageBox()
1564
                return
1565

    
1566
            report_drawing = MainWindow.USE_IMAGE
1567
            configs = app_doc_data.getAppConfigs('option', 'ReportDrawing')
1568
            if configs and configs[0].value:
1569
                report_drawing = configs[0].value
1570
            report_drawing = MainWindow.USE_IMAGE  #TODO: force to set report drawing to USE_IMAGE
1571

    
1572
            report_drawing_path = None
1573
            with NamedTemporaryFile() as f:
1574
                report_drawing_path = f.name + '.png' if report_drawing == MainWindow.USE_IMAGE else f.name + '.svg'
1575

    
1576
            if report_drawing_path:
1577
                self.on_view_connector(False)  # hide connector
1578
                if report_drawing == MainWindow.USE_IMAGE:
1579
                    self.graphicsView.save_as_image(report_drawing_path)
1580
                else:
1581
                    self.graphicsView.save_as_svg(report_drawing_path)  # try to use save_as_svg when will generate svg file
1582

    
1583
                workspace = self.get_work_space()
1584
                file_name = os.path.join(workspace, app_doc_data.activeDrawing.name + '.xlsx')
1585
                options = QFileDialog.Options()
1586
                options |= QFileDialog.DontUseNativeDialog
1587
                file_name, _ = QFileDialog.getSaveFileName(self, self.tr('Report'), file_name, 'Excel(*.xlsx)',
1588
                                                           options=options)
1589

    
1590
                template = os.path.join(os.getenv('ALLUSERSPROFILE'), App.NAME, 'Report_Template.xlsx')
1591

    
1592
                # get image file path
1593
                company_image_path = os.path.join(os.getenv('ALLUSERSPROFILE'), App.NAME, 'Company.png')
1594
                horizontal_flow_image_path = os.path.join(os.getenv('ALLUSERSPROFILE'), App.NAME, 'Horizontal_Flow.png')
1595
                vertical_upward_flow_image_path = os.path.join(os.getenv('ALLUSERSPROFILE'), App.NAME,
1596
                                                               'Vertical_Upward_Flow.png')
1597
                vertical_downward_flow_image_path = os.path.join(os.getenv('ALLUSERSPROFILE'), App.NAME,
1598
                                                                 'Vertical_Downward_Flow.png')
1599
                # up to here
1600
                if file_name and os.path.exists(template):
1601
                    units = [attr[1] for attr in app_doc_data.activeDrawing.attrs if attr[0] == 'Units'][0]
1602

    
1603
                    wb = openpyxl.load_workbook(template)
1604

    
1605
                    page_no = 1
1606
                    pages = math.ceil(len(list(app_doc_data.activeDrawing.hmbTable.streamNos())) / 20)
1607
                    for page in range(pages):
1608
                        ws = wb.copy_worksheet(wb.get_sheet_by_name('Page'))
1609
                        ws.title = f"Page ({page_no})"
1610

    
1611
                        if report_drawing == MainWindow.USE_IMAGE:
1612
                            cal_image = openpyxl.drawing.image.Image(report_drawing_path)
1613
                            x_scale = MainWindow.PAPER_SIZE.width() / cal_image.width
1614
                            y_scale = MainWindow.PAPER_SIZE.height() / cal_image.height
1615
                            cal_image.width *= x_scale
1616
                            cal_image.height *= y_scale
1617
                            ws.add_image(cal_image, 'A1')
1618

    
1619
                        company_image = openpyxl.drawing.image.Image(company_image_path)
1620
                        company_image.width *= 0.8
1621
                        company_image.height *= 0.7
1622
                        ws.add_image(company_image, 'X54')
1623

    
1624
                        """write sheet information"""
1625
                        configs = app_doc_data.getConfigs('Sheet')
1626
                        for config in configs:
1627
                            if config.key == 'JobNo' and config.value:
1628
                                ws['Z59'].value = config.value
1629
                            elif config.key == 'JobName' and config.value:
1630
                                ws['W60'].value = config.value
1631
                            elif config.key == 'Description' and config.value:
1632
                                ws['W74'].value = config.value
1633
                            elif config.key == 'RevStatus' and config.value:
1634
                                ws['Y69'].value = config.value
1635
                            elif config.key == 'CheckedBy' and config.value:
1636
                                ws['Z79'].value = config.value
1637
                            elif config.key == 'ApprovedBy' and config.value:
1638
                                ws['Z80'].value = config.value
1639

    
1640
                        configs = app_doc_data.getAppConfigs('app', 'SingleID')
1641
                        if configs and configs[0].value:
1642
                            ws['Z78'].value = configs[0].value
1643
                        ws['Z69'].value = str(datetime.now().strftime('%Y-%m-%d %H:%M:%S'))
1644
                        """up to here"""
1645

    
1646
                        # Output [Pump, Compressor, Control Valve]
1647
                        ws['X1'].value = 'Loop_Deviation'
1648
                        ws['X1'].font = Font(bold=True, underline='single', size=11)
1649

    
1650
                        loops = app_doc_data.activeDrawing.loops
1651
                        strmsg = None
1652
                        row_no = 2
1653
                        for loop in loops:
1654
                            deviation = loop.deviation
1655
                            if round(deviation, 9) == 0:
1656
                                continue
1657

    
1658
                            for i in range(1, len(loop.items) - 1, 3):
1659
                                if i == 1:
1660
                                    loop_no = loop.name.replace('Loop', '')
1661
                                    if len(loop_no) > 1:
1662
                                        strmsg = '({}) {}'.format(loop_no, loop.items[i].stream_no)
1663
                                    else:
1664
                                        strmsg = '(0{}) {}'.format(loop_no, loop.items[i].stream_no)
1665
                                else:
1666
                                    if len(str(loop.items[i - 1])) > 13 and str(loop.items[i - 1])[:13] == \
1667
                                            'Line_Splitter':
1668
                                        pre_stream_num = loop.items[i - 3].stream_no
1669
                                        cur_stream_num = loop.items[i].stream_no
1670

    
1671
                                        if '-' in strmsg:
1672
                                            last_stream_num = str(strmsg).rsplit('-', 1)[1]
1673
                                        else:
1674
                                            last_stream_num = str(strmsg).rsplit(' ', 1)[1]
1675

    
1676
                                        if pre_stream_num != int(last_stream_num):
1677
                                            strmsg = f'{strmsg}-{pre_stream_num}-{cur_stream_num}'
1678

    
1679
                            last_stream_num = loop.items[len(loop.items) - 2].stream_no
1680
                            strmsg = f'{strmsg}-{last_stream_num}'
1681

    
1682
                            value = f"{strmsg} = {round(deviation, 3)} {units['Pressure']}"
1683
                            tokens = value.split('-')
1684
                            for at in range(0, len(tokens), 20):
1685
                                cell_value = '-'.join(tokens[at: at + 20 if at + 20 < len(tokens) else len(tokens)])
1686
                                if round(deviation, 3) < 0:
1687
                                    ws.cell(row_no, 24, cell_value).font = Font(underline='single', size=10,
1688
                                                                                color='FF0000')
1689
                                elif round(deviation, 3) > 0:
1690
                                    ws.cell(row_no, 24, cell_value).font = Font(size=10)
1691
                                else:
1692
                                    ws.cell(row_no, 24, cell_value).font = Font(underline='single', size=10)
1693
                                row_no += 1
1694

    
1695
                        start_row_no = row_no + 1
1696
                        start_col_no = 24
1697
                        # Pump
1698
                        pumps = []
1699
                        row_no = start_row_no
1700
                        col_no = start_col_no
1701
                        for loop in loops:
1702
                            for item in loop.items:
1703
                                parent = item.parent
1704
                                if parent:
1705
                                    name = str(item).replace(
1706
                                        '_{}'.format(str(item).split('_')[len(str(item).split('_')) - 1]), '')
1707
                                    if name in pumps:
1708
                                        continue
1709
                                    if name[:3] == 'R_P' or name[:3] == 'L_P' or name[:3] == 'V_P':
1710
                                        pumps.append(name)
1711

    
1712
                                        attr = item.parent.attribute
1713
                                        ws.cell(row_no, col_no, attr['Tag_No']).font = Font(bold=True,
1714
                                                                                            underline='single',
1715
                                                                                            size=11)
1716

    
1717
                                        row_no += 1
1718
                                        ws.cell(row_no, col_no, 'Suct.P :')
1719
                                        col_no += 2
1720
                                        ws.cell(row_no, col_no, round(attr['Suct.P'], 3))
1721
                                        col_no += 1
1722
                                        ws.cell(row_no, col_no, '{}.g'.format(units['Pressure']))
1723

    
1724
                                        row_no += 1
1725
                                        col_no = 24 if col_no == 27 else 28
1726
                                        ws.cell(row_no, col_no, 'Disc.P :')
1727
                                        col_no += 2
1728
                                        ws.cell(row_no, col_no, round(attr['Disc.P'], 3))
1729
                                        col_no += 1
1730
                                        ws.cell(row_no, col_no, '{}.g'.format(units['Pressure']))
1731

    
1732
                                        row_no += 1
1733
                                        col_no = 24 if col_no == 27 else 28
1734
                                        ws.cell(row_no, col_no, 'Diff.P :')
1735
                                        col_no += 2
1736
                                        ws.cell(row_no, col_no, round(attr['Diff.P'], 3))
1737
                                        col_no += 1
1738
                                        ws.cell(row_no, col_no, units['Pressure'])
1739

    
1740
                                        row_no += 1
1741
                                        col_no = 24 if col_no == 27 else 28
1742
                                        ws.cell(row_no, col_no, 'Head :')
1743
                                        col_no += 2
1744
                                        ws.cell(row_no, col_no, round(attr['Head'], 3))
1745
                                        col_no += 1
1746
                                        ws.cell(row_no, col_no, units['Length'])
1747

    
1748
                                        row_no += 1
1749
                                        col_no = 24 if col_no == 27 else 28
1750
                                        ws.cell(row_no, col_no, 'NPSHa :')
1751
                                        col_no += 2
1752
                                        ws.cell(row_no, col_no, round(attr['NPSHa'], 3))
1753
                                        col_no += 1
1754
                                        ws.cell(row_no, col_no, units['Length'])
1755

    
1756
                                        row_no += 1
1757
                                        col_no = 24 if col_no == 27 else 28
1758
                                        ws.cell(row_no, col_no, 'Vap. P :')
1759
                                        col_no += 2
1760
                                        ws.cell(row_no, col_no, attr['Vap. P'])
1761
                                        col_no += 1
1762
                                        ws.cell(row_no, col_no, '{}.a'.format(units['Pressure']))
1763

    
1764
                                        row_no += 1
1765
                                        col_no = 24 if col_no == 27 else 28
1766
                                        ws.cell(row_no, col_no, 'HHP :')
1767
                                        col_no += 2
1768
                                        ws.cell(row_no, col_no, round(attr['HHP'], 3))
1769
                                        col_no += 1
1770
                                        ws.cell(row_no, col_no, units['Power'])
1771

    
1772
                                        col_no = 28 if col_no == 27 else 24
1773
                                        row_no = row_no - 7 if col_no == 28 else row_no + 2
1774

    
1775
                        start_row_no += math.ceil(len(pumps)) * 9
1776

    
1777
                        # Compressor
1778
                        compressors = []
1779
                        row_no = start_row_no
1780
                        col_no = start_col_no
1781
                        for loop in loops:
1782
                            for item in loop.items:
1783
                                parent = item.parent
1784
                                if parent:
1785
                                    name = str(item).replace(
1786
                                        '_{}'.format(str(item).split('_')[len(str(item).split('_')) - 1]), '')
1787
                                    if name in compressors:
1788
                                        continue
1789
                                    if name[:3] == 'R_K' or name[:3] == 'L_K':
1790
                                        compressors.append(name)
1791

    
1792
                                        attr = item.parent.attribute
1793
                                        ws.cell(row_no, col_no, attr['Tag_No']).font = Font(bold=True,
1794
                                                                                            underline='single',
1795
                                                                                            size=11)
1796

    
1797
                                        row_no += 1
1798
                                        ws.cell(row_no, col_no, 'Suct.P :')
1799
                                        col_no += 2
1800
                                        ws.cell(row_no, col_no, round(attr['Suct.P'], 3))
1801
                                        col_no += 1
1802
                                        ws.cell(row_no, col_no, '{}.g'.format(units['Pressure']))
1803

    
1804
                                        row_no += 1
1805
                                        col_no = 24 if col_no == 27 else 28
1806
                                        ws.cell(row_no, col_no, 'Disc.P :')
1807
                                        col_no += 2
1808
                                        ws.cell(row_no, col_no, round(attr['Disc.P'], 3))
1809
                                        col_no += 1
1810
                                        ws.cell(row_no, col_no, '{}.g'.format(units['Pressure']))
1811

    
1812
                                        row_no += 1
1813
                                        col_no = 24 if col_no == 27 else 28
1814
                                        ws.cell(row_no, col_no, 'Diff.P :')
1815
                                        col_no += 2
1816
                                        ws.cell(row_no, col_no, round(attr['Diff.P'], 3))
1817
                                        col_no += 1
1818
                                        ws.cell(row_no, col_no, units['Pressure'])
1819

    
1820
                                        row_no += 1
1821
                                        col_no = 24 if col_no == 27 else 28
1822
                                        ws.cell(row_no, col_no, 'HHP :')
1823
                                        col_no += 2
1824
                                        ws.cell(row_no, col_no, round(attr['HHP'], 3))
1825
                                        col_no += 1
1826
                                        ws.cell(row_no, col_no, units['Power'])
1827

    
1828
                                        col_no = 28 if col_no == 27 else 24
1829
                                        row_no = row_no - 4 if col_no == 28 else row_no + 2
1830

    
1831
                        start_row_no += math.ceil(len(compressors)) * 9
1832

    
1833
                        # Control Valve
1834
                        control_valves = []
1835
                        row_no = start_row_no
1836
                        col_no = start_col_no
1837
                        for loop in loops:
1838
                            for item in loop.items:
1839
                                parent = item.parent
1840
                                if parent:
1841
                                    name = str(item).replace(
1842
                                        '_{}'.format(str(item).split('_')[len(str(item).split('_')) - 1]), '')
1843
                                    if name in control_valves:
1844
                                        continue
1845
                                    if name[:3] == 'CV_':
1846
                                        control_valves.append(name)
1847

    
1848
                                        attr = item.parent.attribute
1849
                                        if 'Tag_No' in attr:
1850
                                            ws.cell(row_no, col_no, attr['Tag_No']).font = Font(bold=True,
1851
                                                                                                underline='single',
1852
                                                                                                size=11)
1853

    
1854
                                        row_no += 1
1855
                                        ws.cell(row_no, col_no, 'Inlet P :')
1856
                                        col_no += 2
1857
                                        if 'Suct.P' in attr:
1858
                                            ws.cell(row_no, col_no, round(attr['Suct.P'], 3))
1859
                                        col_no += 1
1860
                                        ws.cell(row_no, col_no, '{}.g'.format(units['Pressure']))
1861

    
1862
                                        row_no += 1
1863
                                        col_no = 24 if col_no == 27 else 28
1864
                                        ws.cell(row_no, col_no, 'Outlet P :')
1865
                                        col_no += 2
1866
                                        if 'Disc.P' in attr:
1867
                                            ws.cell(row_no, col_no, round(attr['Disc.P'], 3))
1868
                                        col_no += 1
1869
                                        ws.cell(row_no, col_no, '{}.g'.format(units['Pressure']))
1870

    
1871
                                        row_no += 1
1872
                                        col_no = 24 if col_no == 27 else 28
1873
                                        ws.cell(row_no, col_no, 'Diff.P :')
1874
                                        col_no += 2
1875
                                        if 'Diff.P' in attr:
1876
                                            ws.cell(row_no, col_no, round(attr['Diff.P'], 3))
1877
                                        col_no += 1
1878
                                        ws.cell(row_no, col_no, units['Pressure'])
1879

    
1880
                                        row_no += 1
1881
                                        col_no = 24 if col_no == 27 else 28
1882
                                        ws.cell(row_no, col_no, 'dP Ratio :')
1883
                                        col_no += 2
1884
                                        if 'dP Ratio' in attr:
1885
                                            ws.cell(row_no, col_no, round(attr['dP Ratio'] * 100, 2))
1886
                                        col_no += 1
1887
                                        ws.cell(row_no, col_no, '%')
1888

    
1889
                                        col_no = 28 if col_no == 27 else 24
1890
                                        row_no = row_no - 4 if col_no == 28 else row_no + 2
1891

    
1892
                        # write hmb unit
1893
                        ws['B55'].value = '-'
1894
                        ws['B56'].value = units['Pipe_Diameter']
1895
                        ws['B57'].value = units['Flowrate_Mass']
1896
                        ws['B58'].value = units['Flowrate_Volume']
1897
                        ws['B59'].value = units['Density']
1898
                        ws['B60'].value = units['Viscosity']
1899
                        ws['B61'].value = units['Temperature']  # Hidden
1900
                        ws['B62'].value = ''  # Hidden
1901
                        ws['B63'].value = ''  # Hidden
1902
                        ws['B64'].value = ''  # Hidden
1903
                        ws['B65'].value = units['Pipe_Diameter']  # Hidden
1904
                        ws['B66'].value = units['Pipe_Diameter']  # Hidden
1905
                        ws['B67'].value = ''  # Hidden
1906
                        ws['B68'].value = units['Length']
1907
                        ws['B69'].value = units['Length']
1908
                        ws['B70'].value = units['Roughness']
1909
                        ws['B71'].value = units['Velocity']  # Hidden
1910
                        ws['B72'].value = '{}/100{})'.format(units['Pressure'], units['Length'])  # Hidden
1911
                        ws['B74'].value = units['Velocity']
1912
                        ws['B75'].value = ''  # Hidden
1913
                        ws['B76'].value = ''  # Hidden
1914
                        ws['B77'].value = '{}/100{}'.format(units['Pressure'], units['Length'])
1915
                        ws['B78'].value = units['Pressure']
1916
                        ws['B79'].value = units['Pressure']
1917
                        ws['B80'].value = '{}(g)'.format(units['Pressure'])
1918

    
1919
                        page_no += 1
1920

    
1921
                    current_ws = wb.get_sheet_by_name('Page (1)')
1922
                    # write hmb data
1923
                    drawing = app_doc_data.activeDrawing
1924
                    hmbs = drawing.hmbTable._hmbs
1925
                    if hmbs is not None:
1926
                        stream_count = 1
1927
                        col_no = 3
1928
                        _hmbs = sorted(hmbs, key=lambda hmb: hmb.stream_no)
1929
                        for hmb in _hmbs:
1930
                            if hmb.isDeleted == True:
1931
                                continue
1932

    
1933
                            ws = self.get_work_sheet(wb, stream_count)
1934
                            if ws != current_ws:
1935
                                current_ws = ws
1936
                                col_no = 3
1937

    
1938
                            row_no = 54
1939
                            ws.cell(row_no, col_no, hmb.stream_no)
1940
                            row_no += 1
1941
                            ws.cell(row_no, col_no, hmb.phase_type)
1942
                            row_no += 1
1943
                            ws.cell(row_no, col_no, hmb.inside_pipe_size)
1944
                            row_no += 1
1945
                            ws.cell(row_no, col_no, hmb.flowrate_mass)
1946
                            row_no += 1
1947
                            ws.cell(row_no, col_no, hmb.flowrate_volume)
1948
                            row_no += 1
1949
                            ws.cell(row_no, col_no, hmb.density)
1950
                            row_no += 1
1951
                            ws.cell(row_no, col_no, hmb.viscosity)
1952
                            row_no += 1
1953
                            ws.cell(row_no, col_no, hmb.temperature)
1954
                            row_no += 1
1955
                            ws.cell(row_no, col_no, hmb.molecular_weight)
1956
                            row_no += 1
1957
                            ws.cell(row_no, col_no, hmb.specific_heat_ratio)
1958
                            row_no += 1
1959
                            ws.cell(row_no, col_no, hmb.compress_factor)
1960
                            row_no += 1
1961
                            ws.cell(row_no, col_no, hmb.nominal_pipe_size)
1962
                            row_no += 1
1963
                            ws.cell(row_no, col_no, hmb.inside_pipe_size)
1964
                            row_no += 1
1965
                            ws.cell(row_no, col_no, hmb.schedule_no)
1966
                            row_no += 1
1967
                            ws.cell(row_no, col_no, hmb.straight_length)
1968
                            row_no += 1
1969
                            ws.cell(row_no, col_no, hmb.equivalent_length)
1970
                            row_no += 1
1971
                            ws.cell(row_no, col_no, hmb.roughness)
1972
                            row_no += 1
1973
                            ws.cell(row_no, col_no, hmb.limitation_velocity)
1974
                            row_no += 1
1975
                            ws.cell(row_no, col_no, hmb.limitation_pressure_drop)
1976
                            row_no += 2
1977
                            ws.cell(row_no, col_no, hmb.velocity)
1978
                            row_no += 1
1979
                            ws.cell(row_no, col_no, hmb.reynolds)
1980
                            row_no += 1
1981
                            ws.cell(row_no, col_no, hmb.friction_factor)
1982
                            row_no += 1
1983
                            ws.cell(row_no, col_no, hmb.pressure_drop)
1984
                            row_no += 1
1985
                            ws.cell(row_no, col_no, hmb.pressure_drop_friction)
1986
                            row_no += 1
1987
                            ws.cell(row_no, col_no, hmb.pressure_drop_static)
1988
                            row_no += 1
1989
                            ws.cell(row_no, col_no, hmb.pressure_pipe_end_point)
1990

    
1991
                            col_no += 1
1992
                            stream_count += 1
1993

    
1994
                    # two_phase
1995
                    if hmbs is not None:
1996
                        for hmb in hmbs:
1997
                            if hmb.phase_type == 'Mixed':
1998
                                lines = [item for item in self.graphicsView.scene.items() if type(
1999
                                    item) is QEngineeringStreamlineItem and str(item.uid) == str(hmb.components_uid)]
2000
                                if lines:
2001
                                    ws = wb.copy_worksheet(wb.get_sheet_by_name('Two_phase'))
2002
                                    ws.title = 'Two Phase {}'.format(str(lines[0]))
2003

    
2004
                                    # Information
2005
                                    ws['B5'].value = 'File : Two_Phase'
2006
                                    ws['B6'].value = 'Line : {}'.format(lines[0].stream_no)
2007
                                    ws['G6'].value = 'Made by : {}'.format(configs[0].value)
2008

    
2009
                                    # Process Data
2010
                                    ws['C10'].value = units['Flowrate_Mass']
2011
                                    ws['D10'].value = units['Density']
2012
                                    ws['E10'].value = units['Viscosity']
2013
                                    ws['F10'].value = '{}(g)'.format(units['Pressure'])
2014
                                    ws['G10'].value = units['Temperature']
2015

    
2016
                                    ws['C11'].value = lines[0].data.liquid_flowrate_mass
2017
                                    ws['D11'].value = lines[0].data.liquid_density
2018
                                    ws['E11'].value = lines[0].data.liquid_viscosity
2019

    
2020
                                    ws['C12'].value = lines[0].data.vapor_flowrate_mass
2021
                                    ws['D12'].value = lines[0].data.vapor_density
2022
                                    ws['E12'].value = lines[0].data.vapor_viscosity
2023
                                    ws['F12'].value = lines[0].data.vapor_pressure
2024
                                    ws['G12'].value = lines[0].data.vapor_temperature
2025
                                    ws['H12'].value = lines[0].data.vapor_molecular_weight
2026
                                    ws['I12'].value = lines[0].data.vapor_compress_factor
2027

    
2028
                                    # Geometry Data
2029
                                    ws['D16'].value = units['Pipe_Diameter']
2030
                                    ws['E16'].value = units['Roughness']
2031
                                    ws['F16'].value = units['Length']
2032

    
2033
                                    row_no = 17
2034
                                    for geometry in lines[0].mixed_geometry:
2035
                                        col_no = 3
2036
                                        ws.cell(row_no, col_no, str(geometry[0]))  # Element
2037
                                        col_no += 1
2038
                                        ws.cell(row_no, col_no,
2039
                                                float(geometry[3]) if is_float(geometry[3]) else None)  # ID
2040
                                        col_no += 1
2041
                                        ws.cell(row_no, col_no,
2042
                                                float(geometry[4]) if is_float(geometry[4]) else None)  # Roughness
2043
                                        col_no += 1
2044
                                        ws.cell(row_no, col_no,
2045
                                                float(geometry[5]) if is_float(geometry[5]) else None)  # Length
2046
                                        col_no += 1
2047
                                        ws.cell(row_no, col_no,
2048
                                                float(geometry[6]) if is_float(geometry[6]) else None)  # Angle
2049
                                        col_no += 1
2050
                                        ws.cell(row_no, col_no,
2051
                                                float(geometry[7]) if is_float(geometry[7]) else None)  # R/D
2052
                                        col_no += 1
2053
                                        ws.cell(row_no, col_no,
2054
                                                float(geometry[9]) if is_float(geometry[9]) else None)  # K
2055

    
2056
                                        row_no += 1
2057

    
2058
                                    # horizontal_flow_image = openpyxl.drawing.image.Image(horizontal_flow_image_path)
2059
                                    # horizontal_flow_image.width *= 0.6
2060
                                    # horizontal_flow_image.height *= 0.6
2061
                                    # ws.add_image(horizontal_flow_image, 'L3')
2062

    
2063
                                    # vertical_upward_flow_image = openpyxl.drawing.image.Image(
2064
                                    #     vertical_upward_flow_image_path)
2065
                                    # vertical_upward_flow_image.width *= 0.6
2066
                                    # vertical_upward_flow_image.height *= 0.6
2067
                                    # ws.add_image(vertical_upward_flow_image, 'R3')
2068

    
2069
                                    # vertical_downward_flow_image = openpyxl.drawing.image.Image(
2070
                                    #     vertical_downward_flow_image_path)
2071
                                    # vertical_downward_flow_image.width *= 0.6
2072
                                    # vertical_downward_flow_image.height *= 0.6
2073
                                    # ws.add_image(vertical_downward_flow_image, 'Z3')
2074

    
2075
                                    horizontal = DrawImage(horizontal_flow_image_path)
2076
                                    vertical_upward = DrawImage(vertical_upward_flow_image_path)
2077
                                    vertical_downward = DrawImage(vertical_downward_flow_image_path)
2078

    
2079
                                    # Calculation Result
2080
                                    MainWindow.write_calculation_result_units(ws, units)
2081

    
2082
                                    row_no = 37
2083
                                    for row in lines[0].mixed_pressure_variation:
2084
                                        col_no = 12
2085
                                        ws.cell(row_no, col_no, str(row[0]))  # Element
2086
                                        col_no += 1
2087
                                        ws.cell(row_no, col_no, row[1])  # ID
2088
                                        col_no += 1
2089
                                        ws.cell(row_no, col_no, row[2])  # Length
2090
                                        col_no += 1
2091
                                        ws.cell(row_no, col_no, row[3])  # Angle
2092
                                        col_no += 1
2093
                                        ws.cell(row_no, col_no, row[4])  # K
2094
                                        col_no += 1
2095
                                        ws.cell(row_no, col_no, row[5])  # Pressure
2096
                                        col_no += 1
2097
                                        ws.cell(row_no, col_no, row[6])  # Void
2098
                                        col_no += 1
2099
                                        ws.cell(row_no, col_no, row[7])  # Quality
2100
                                        col_no += 1
2101
                                        ws.cell(row_no, col_no, row[8])  # Mean. Density
2102
                                        col_no += 1
2103
                                        ws.cell(row_no, col_no, row[9])  # Homo. Density
2104
                                        col_no += 1
2105
                                        ws.cell(row_no, col_no, row[10])  # V.Density
2106
                                        col_no += 1
2107
                                        ws.cell(row_no, col_no, row[11])  # Mean.Vel
2108
                                        col_no += 1
2109
                                        ws.cell(row_no, col_no, row[12])  # Homo.Vel
2110
                                        col_no += 1
2111
                                        ws.cell(row_no, col_no, row[13])  # Max.Vel
2112
                                        col_no += 1
2113
                                        ws.cell(row_no, col_no, row[14])  # Ero.Vel
2114
                                        col_no += 1
2115
                                        ws.cell(row_no, col_no, row[15])  # Pattern X
2116
                                        col_no += 1
2117
                                        ws.cell(row_no, col_no, row[16])  # Pattern Y
2118
                                        col_no += 1
2119
                                        ws.cell(row_no, col_no, str(row[17]) if row[17] else '')  # Regime
2120
                                        col_no += 1
2121
                                        ws.cell(row_no, col_no, row[18])  # Friction
2122
                                        col_no += 1
2123
                                        ws.cell(row_no, col_no, row[19])  # Gravity
2124
                                        col_no += 1
2125
                                        ws.cell(row_no, col_no, row[20])  # Moment
2126
                                        col_no += 1
2127
                                        ws.cell(row_no, col_no, row[21])  # Total
2128

    
2129
                                        # load_regime
2130
                                        length = row[2]
2131
                                        if length is not None:
2132
                                            x = float(row[15])
2133
                                            y = float(row[16])
2134

    
2135
                                            angle = float(row[3])
2136
                                            if angle == 0:
2137
                                                # Horizontal
2138
                                                origin_x = 57
2139
                                                origin_y = 652
2140

    
2141
                                                image_min_x = 57
2142
                                                image_min_y = 2
2143
                                                image_max_x = 603
2144
                                                image_max_y = 651
2145
                                                left = origin_x + ((image_max_x - image_min_x) / (7 - (-5))) * (
2146
                                                        math.log10(x) - (-5))
2147
                                                top = origin_y - ((image_max_y - image_min_y) / (5 - (-9))) * (
2148
                                                        math.log10(y) - (-9))
2149

    
2150
                                                horizontal.draw_regime(left, top, 8)
2151
                                                # horizontal.draw_regime(origin_x, origin_y, 8) # 0, 0 위치 확인 방법
2152
                                            elif angle > 0:
2153
                                                # Vertical Upward
2154
                                                origin_x = 59
2155
                                                origin_y = 681
2156

    
2157
                                                image_min_x = 60
2158
                                                image_min_y = 29
2159
                                                image_max_x = 596
2160
                                                image_max_y = 681
2161
                                                left = origin_x + ((image_max_x - image_min_x) / (7 - (-2))) * (
2162
                                                        math.log10(x) - (-2))
2163
                                                top = origin_y - ((image_max_y - image_min_y) / (8 - (-5))) * (
2164
                                                        math.log10(y) - (-5))
2165

    
2166
                                                vertical_upward.draw_regime(left, top, 8)
2167
                                                # vertical_upward.draw_regime(origin_x, origin_y, 8) # 0, 0 위치 확인 방법
2168
                                            elif angle < 0:
2169
                                                # Vertical Downward
2170
                                                origin_x = 55
2171
                                                origin_y = 656
2172

    
2173
                                                image_min_x = 55
2174
                                                image_min_y = 21
2175
                                                image_max_x = 572
2176
                                                image_max_y = 656
2177
                                                left = origin_x + ((image_max_x - image_min_x) / (20 - 0)) * (x - 0)
2178
                                                top = origin_y - ((image_max_y - image_min_y) / (24 - 0)) * (y - 0)
2179

    
2180
                                                vertical_downward.draw_regime(left, top, 8)
2181
                                                # vertical_downward.draw_regime(origin_x, origin_y, 8) # 0, 0 위치 확인 방법
2182

    
2183
                                        row_no += 1
2184

    
2185
                                    with NamedTemporaryFile() as f:
2186
                                        horizontal_image_path = f.name + '.png'
2187
                                    horizontal.save_as(horizontal_image_path)
2188

    
2189
                                    horizontal_flow_image = openpyxl.drawing.image.Image(horizontal_image_path)
2190
                                    horizontal_flow_image.width *= 0.6
2191
                                    horizontal_flow_image.height *= 0.6
2192
                                    ws.add_image(horizontal_flow_image, 'L4')
2193

    
2194
                                    with NamedTemporaryFile() as f:
2195
                                        vertical_upward_image_path = f.name + '.png'
2196
                                    vertical_upward.save_as(vertical_upward_image_path)
2197

    
2198
                                    vertical_upward_flow_image = openpyxl.drawing.image.Image(
2199
                                        vertical_upward_image_path)
2200
                                    vertical_upward_flow_image.width *= 0.6
2201
                                    vertical_upward_flow_image.height *= 0.6
2202
                                    ws.add_image(vertical_upward_flow_image, 'S3')
2203

    
2204
                                    with NamedTemporaryFile() as f:
2205
                                        vertical_downward_image_path = f.name + '.png'
2206
                                    vertical_downward.save_as(vertical_downward_image_path)
2207

    
2208
                                    vertical_downward_flow_image = openpyxl.drawing.image.Image(
2209
                                        vertical_downward_image_path)
2210
                                    vertical_downward_flow_image.width *= 0.6
2211
                                    vertical_downward_flow_image.height *= 0.6
2212
                                    ws.add_image(vertical_downward_flow_image, 'AA3')
2213

    
2214
                    active_sheet = wb.get_sheet_by_name('Page (1)')
2215
                    if active_sheet:
2216
                        wb.active = active_sheet
2217

    
2218
                    wb.get_sheet_by_name('Page').sheet_state = 'hidden'
2219
                    wb.get_sheet_by_name('Two_phase').sheet_state = 'hidden'
2220

    
2221
                    name_without_ext, ext = os.path.splitext(file_name)
2222
                    save_file_name = file_name if ext.upper() == '.XLSX' else name_without_ext + '.xlsx'
2223
                    wb.save(filename=save_file_name)
2224

    
2225
                    if report_drawing == 'Use SVG':
2226
                        report_app_path = os.path.join(os.path.dirname(os.path.realpath(__file__)), 'ReportApp',
2227
                                                       'ReportApp.exe')
2228

    
2229
                        arguments = [report_app_path, save_file_name, report_drawing_path]
2230
                        res = subprocess.call(arguments)
2231
                        if res == 0:
2232
                            os.startfile(save_file_name)
2233
                            QMessageBox.information(self, self.tr('Information'), self.tr('Report is done'))
2234
                        else:
2235
                            QMessageBox.information(self, self.tr('Information'),
2236
                                                    self.tr(' Could not find excel file or svg file. '))
2237

    
2238
                            if save_file_name is not None:
2239
                                os.remove(save_file_name)
2240
                    else:
2241
                        os.startfile(save_file_name)
2242

    
2243
                        QMessageBox.information(self, self.tr('Information'), self.tr('Report is done'))
2244
        except Exception as ex:
2245
            message = f"error occurred({repr(ex)}) in {sys.exc_info()[-1].tb_frame.f_code.co_filename}:" \
2246
                      f"{sys.exc_info()[-1].tb_lineno}"
2247
            self.addMessage.emit(MessageType.Error, message)
2248

    
2249
    @staticmethod
2250
    def write_calculation_result_units(ws, units) -> None:
2251
        """write calculation result unit for 2-phase"""
2252

    
2253
        row_no = 36
2254
        ws.cell(row_no, 13, units['Pipe_Diameter'])  # ID
2255
        ws.cell(row_no, 14, units['Length'])  # Length
2256
        ws.cell(row_no, 17, units['Pressure'])  # Pressure
2257
        ws.cell(row_no, 20, units['Density'])  # Mean. Density
2258
        ws.cell(row_no, 21, units['Density'])  # Homo. Density
2259
        ws.cell(row_no, 22, units['Density'])  # V.Density
2260
        ws.cell(row_no, 23, units['Velocity'])  # Mean.Vel
2261
        ws.cell(row_no, 24, units['Velocity'])  # Homo.Vel
2262
        ws.cell(row_no, 25, units['Velocity'])  # Max.Vel
2263
        ws.cell(row_no, 26, units['Velocity'])  # Ero.Vel
2264

    
2265
        ws.cell(35, 30, f"Pressure Drop ({units['Pressure']}/{units['Length']})")  # Pressure Drop
2266
        ws.cell(row_no, 33, units['Pressure'])  # Total
2267

    
2268
    def get_work_sheet(self, work_book, count):
2269
        page_no = math.ceil(count / 20)
2270
        return work_book.get_sheet_by_name('Page ({})'.format(page_no))
2271

    
2272
    def display_output(self):
2273
        from HydroCalculationCommand import HydroCalculationCommand
2274
        from Outputs import Output
2275

    
2276
        try:
2277
            """ display output """
2278
            app_doc_data = AppDocData.instance()
2279
            drawing = app_doc_data.activeDrawing
2280
            if drawing is None:
2281
                return
2282

    
2283
            self.clear_output()
2284
            if not HydroCalculationCommand.ERRORS:
2285
                self.tableWidgetOutput.setColumnCount(3)
2286
                self.tableWidgetOutput.horizontalHeader().setVisible(False)
2287
                self.tableWidgetOutput.verticalHeader().setVisible(False)
2288
                self.tableWidgetOutput.setSelectionMode(QAbstractItemView.SingleSelection)
2289
                self.tableWidgetOutput.setSelectionBehavior(QAbstractItemView.SelectRows)
2290
                self.tableWidgetOutput.setEditTriggers(QAbstractItemView.NoEditTriggers)
2291
                self.tableWidgetOutput.horizontalHeader().setStretchLastSection(True)
2292

    
2293
                self.tableWidgetDeviation.setColumnCount(1)
2294
                self.tableWidgetDeviation.horizontalHeader().setVisible(False)
2295
                self.tableWidgetDeviation.verticalHeader().setVisible(False)
2296
                self.tableWidgetDeviation.setSelectionMode(QAbstractItemView.SingleSelection)
2297
                self.tableWidgetDeviation.setSelectionBehavior(QAbstractItemView.SelectRows)
2298
                self.tableWidgetDeviation.setEditTriggers(QAbstractItemView.NoEditTriggers)
2299
                self.tableWidgetDeviation.horizontalHeader().setStretchLastSection(True)
2300
                self.tableWidgetDeviation.resizeRowsToContents()
2301
                self.tableWidgetDeviation.resizeColumnsToContents()
2302

    
2303
                units = [attr[1] for attr in drawing.attrs if attr[0] == 'Units'][0]
2304

    
2305
                loops = drawing.loops
2306

    
2307
                # Deviation
2308
                self.add_data(self.tableWidgetDeviation, 'Loop_Deviation', None, None, True, None, None)
2309
                strmsg = None
2310
                for loop in loops:
2311
                    deviation = loop.deviation
2312
                    if round(deviation, 9) == 0:
2313
                        continue
2314

    
2315
                    for i in range(1, len(loop.items) - 1, 3):
2316
                        if i == 1:
2317
                            loop_no = loop.name.replace('Loop', '')
2318
                            if len(loop_no) > 1:
2319
                                strmsg = '({}) {}'.format(loop_no, loop.items[i].stream_no)
2320
                            else:
2321
                                strmsg = '(0{}) {}'.format(loop_no, loop.items[i].stream_no)
2322
                        else:
2323
                            if len(str(loop.items[i - 1])) > 13 and str(loop.items[i - 1])[:13] == 'Line_Splitter':
2324
                                pre_stream_num = loop.items[i - 3].stream_no
2325
                                cur_stream_num = loop.items[i].stream_no
2326

    
2327
                                if strmsg.__contains__('-'):
2328
                                    last_stream_num = str(strmsg).rsplit('-', 1)[1]
2329
                                else:
2330
                                    last_stream_num = str(strmsg).rsplit(' ', 1)[1]
2331

    
2332
                                if pre_stream_num != int(last_stream_num):
2333
                                    strmsg = '{}-{}-{}'.format(strmsg, pre_stream_num, cur_stream_num)
2334

    
2335
                    last_stream_num = loop.items[len(loop.items) - 2].stream_no
2336
                    strmsg = '{}-{}'.format(strmsg, last_stream_num)
2337

    
2338
                    if round(deviation, 3) < 0:
2339
                        self.add_data(self.tableWidgetDeviation,
2340
                                      '{} = {} {}'.format(strmsg, round(deviation, 3), units['Pressure']), None, None,
2341
                                      None,
2342
                                      None, QBrush(QColor(255, 0, 0)))
2343
                    else:
2344
                        self.add_data(self.tableWidgetDeviation,
2345
                                      '{} = {} {}'.format(strmsg, round(deviation, 3), units['Pressure']), None, None,
2346
                                      None,
2347
                                      None)
2348

    
2349
                names = []
2350
                # Pump
2351
                for loop in loops:
2352
                    for item in loop.items:
2353
                        parent = item.parent
2354
                        if parent:
2355
                            name = str(item).replace('_{}'.format(str(item).split('_')[len(str(item).split('_')) - 1]),
2356
                                                     '')
2357
                            if name in names:
2358
                                continue
2359
                            if name[:3] == 'R_P' or name[:3] == 'L_P' or name[:3] == 'V_P':
2360
                                names.append(name)
2361
                                attr = item.parent.attribute
2362
                                if len(attr) > 0:
2363
                                    """store calculation output for pump"""
2364
                                    output = Output()
2365
                                    output.components_uid = str(item.parent.uid)
2366
                                    output.suctp = round(attr['Suct.P'], 3)
2367
                                    output.discp = round(attr['Disc.P'], 3)
2368
                                    output.diffp = round(attr['Diff.P'], 3)
2369
                                    output.head = round(attr['Head'], 3)
2370
                                    output.npsha = round(attr['NPSHa'], 3)
2371
                                    output.vapp = attr['Vap. P']
2372
                                    output.hhp = round(attr['HHP'], 3)
2373
                                    app_doc_data.outputs.append(output)
2374
                                    """up to here"""
2375

    
2376
                                    self.add_data(self.tableWidgetOutput, attr['Tag_No'], None, None, True, True)
2377
                                    self.add_data(self.tableWidgetOutput, 'Suct.P :', output.suctp,
2378
                                                  '{}.g'.format(units['Pressure']))
2379
                                    self.add_data(self.tableWidgetOutput, 'Disc.P :', output.discp,
2380
                                                  '{}.g'.format(units['Pressure']))
2381
                                    self.add_data(self.tableWidgetOutput, 'Diff.P :', output.diffp,
2382
                                                  units['Pressure'])
2383
                                    self.add_data(self.tableWidgetOutput, 'Head :', output.head, units['Length'])
2384
                                    self.add_data(self.tableWidgetOutput, 'NPSHa :', output.npsha, units['Length'])
2385
                                    self.add_data(self.tableWidgetOutput, 'Vap. P :', output.vapp,
2386
                                                  '{}.a'.format(units['Pressure']))
2387
                                    self.add_data(self.tableWidgetOutput, 'HHP :', output.hhp, units['Power'])
2388

    
2389
                # Compressor
2390
                for loop in loops:
2391
                    for item in loop.items:
2392
                        parent = item.parent
2393
                        if parent:
2394
                            name = str(item).replace('_{}'.format(str(item).split('_')[len(str(item).split('_')) - 1]),
2395
                                                     '')
2396
                            if name in names:
2397
                                continue
2398
                            if name[:3] == 'R_K' or name[:3] == 'L_K':
2399
                                names.append(name)
2400

    
2401
                                attr = item.parent.attribute
2402
                                if len(attr) > 0:
2403
                                    """store calculation output for compressor"""
2404
                                    output = Output()
2405
                                    output.components_uid = str(item.parent.uid)
2406
                                    output.suctp = round(attr['Suct.P'], 3)
2407
                                    output.discp = round(attr['Disc.P'], 3)
2408
                                    output.diffp = round(attr['Diff.P'], 3)
2409
                                    output.hhp = round(attr['HHP'], 3)
2410
                                    app_doc_data.outputs.append(output)
2411
                                    """up to here"""
2412

    
2413
                                    self.add_data(self.tableWidgetOutput, attr['Tag_No'], None, None, True, True)
2414
                                    self.add_data(self.tableWidgetOutput, 'Suct.P :', output.suctp,
2415
                                                  '{}.g'.format(units['Pressure']))
2416
                                    self.add_data(self.tableWidgetOutput, 'Disc.P :', output.discp,
2417
                                                  '{}.g'.format(units['Pressure']))
2418
                                    self.add_data(self.tableWidgetOutput, 'Diff.P :', output.diffp,
2419
                                                  units['Pressure'])
2420
                                    self.add_data(self.tableWidgetOutput, 'HHP :', output.hhp, units['Power'])
2421

    
2422
                # Control Valve
2423
                for loop in loops:
2424
                    for item in loop.items:
2425
                        parent = item.parent
2426
                        if parent:
2427
                            name = str(item).replace('_{}'.format(str(item).split('_')[len(str(item).split('_')) - 1]),
2428
                                                     '')
2429
                            if name in names:
2430
                                continue
2431
                            if name[:3] == 'CV_':
2432
                                names.append(name)
2433

    
2434
                                attr = item.parent.attribute
2435
                                if len(attr) > 0:
2436
                                    """store calculation output for control valve"""
2437
                                    output = Output()
2438
                                    output.components_uid = str(item.parent.uid)
2439
                                    output.suctp = round(attr['Suct.P'], 3)
2440
                                    output.discp = round(attr['Disc.P'], 3)
2441
                                    output.diffp = round(attr['Diff.P'], 3)
2442
                                    output.dpratio = round(attr['dP Ratio'] * 100, 2)
2443
                                    app_doc_data.outputs.append(output)
2444
                                    """up to here"""
2445

    
2446
                                    self.add_data(self.tableWidgetOutput, attr['Tag_No'], None, None, True, True)
2447
                                    self.add_data(self.tableWidgetOutput, 'Inlet P :', output.suctp,
2448
                                                  '{}.g'.format(units['Pressure']))
2449
                                    self.add_data(self.tableWidgetOutput, 'Outlet P :', output.discp,
2450
                                                  '{}.g'.format(units['Pressure']))
2451
                                    self.add_data(self.tableWidgetOutput, 'Diff.P :', output.diffp,
2452
                                                  units['Pressure'])
2453
                                    self.add_data(self.tableWidgetOutput, 'dP Ratio :', output.dpratio, '%')
2454
        except Exception as ex:
2455
            message = f"error occurred({repr(ex)}) in {sys.exc_info()[-1].tb_frame.f_code.co_filename}:" \
2456
                      f"{sys.exc_info()[-1].tb_lineno}"
2457
            self.addMessage.emit(MessageType.Error, message)
2458

    
2459
    def display_loops(self):
2460
        """ display loops """
2461
        from HydroCalculationCommand import HydroCalculationCommand
2462

    
2463
        try:
2464
            drawing = AppDocData.instance().activeDrawing
2465
            if drawing is None: return
2466

    
2467
            self.tableWidgetLoop.clear()
2468

    
2469
            loops = drawing.loops
2470
            if loops and not HydroCalculationCommand.ERRORS:
2471
                self.tableWidgetLoop.setColumnCount(len(loops) * 5)
2472

    
2473
                _col_names = [[loop.name, 'pressure', 'Static\nLine\ndP_Eq', 'El.\nDensity\nEl.', 'Extra'] for loop in
2474
                              loops]
2475
                col_names = []
2476
                for col_name in _col_names: col_names.extend(col_name)
2477
                self.tableWidgetLoop.setHorizontalHeaderLabels(col_names)
2478
                self.tableWidgetLoop.horizontalHeader().setVisible(True)
2479

    
2480
                max_rows = 0
2481
                for col in range(len(loops)):
2482
                    rows = len(loops[col].items)
2483
                    max_rows = max(max_rows, rows)
2484
                    self.tableWidgetLoop.setRowCount(max_rows)
2485

    
2486
                    for row in range(len(loops[col].items)):
2487
                        item = QTableWidgetItem(str(loops[col].items[row]))
2488
                        item.setTextAlignment(Qt.AlignHCenter | Qt.AlignVCenter)
2489
                        self.tableWidgetLoop.setItem(row, col * 5, item)
2490

    
2491
                    # display calculation values
2492
                    for row in range(len(loops[col].items)):
2493
                        if loops[col].items[row] in loops[col].pressures:
2494
                            pressure = loops[col].pressures[loops[col].items[row]] \
2495
                                if loops[col].pressures[loops[col].items[row]] else 0
2496
                            item = QTableWidgetItem(str(round(pressure, 8)))
2497
                            item.setTextAlignment(Qt.AlignRight | Qt.AlignVCenter)
2498
                            # if not loops[col].pressures[loops[col].items[row]]: item.setBackground(Qt.red)
2499
                            self.tableWidgetLoop.setItem(row, col * 5 + 1, item)
2500

    
2501
                        if loops[col].items[row] in loops[col].pressure_drops:
2502
                            item = QTableWidgetItem(str(round(loops[col].pressure_drops[loops[col].items[row]], 9)))
2503
                            item.setTextAlignment(Qt.AlignRight | Qt.AlignVCenter)
2504
                            # if not loops[col].pressure_drops[loops[col].items[row]]: item.setBackground(Qt.red)
2505
                            self.tableWidgetLoop.setItem(row, col * 5 + 2, item)
2506

    
2507
                        if loops[col].items[row] in loops[col].density_elevations:
2508
                            item = QTableWidgetItem(str(round(loops[col].density_elevations[loops[col].items[row]], 8)))
2509
                            item.setTextAlignment(Qt.AlignRight | Qt.AlignVCenter)
2510
                            # if not loops[col].density_elevations[loops[col].items[row]]: item.setBackground(Qt.red)
2511
                            self.tableWidgetLoop.setItem(row, col * 5 + 3, item)
2512

    
2513
                        if loops[col].items[row] in loops[col].extras:
2514
                            item = QTableWidgetItem(str(loops[col].extras[loops[col].items[row]]))
2515
                            item.setTextAlignment(Qt.AlignRight | Qt.AlignVCenter)
2516
                            # if not loops[col].density_elevations[loops[col].items[row]]: item.setBackground(Qt.red)
2517
                            self.tableWidgetLoop.setItem(row, col * 5 + 4, item)
2518

    
2519
                self.tableWidgetLoop.resizeColumnsToContents()
2520
                self.tableWidgetLoop.resizeRowsToContents()
2521
        except Exception as ex:
2522
            message = f"error occurred({repr(ex)}) in {sys.exc_info()[-1].tb_frame.f_code.co_filename}:" \
2523
                      f"{sys.exc_info()[-1].tb_lineno}"
2524
            self.addMessage.emit(MessageType.Error, message)
2525

    
2526
    def configuration(self):
2527
        """configuration"""
2528
        from ConfigurationDialog import QConfigurationDialog
2529
        from Calculation import Conversion
2530

    
2531
        try:
2532
            appDocData = AppDocData.instance()
2533
            if appDocData.activeDrawing is None:
2534
                self.showImageSelectionMessageBox()
2535
                return
2536

    
2537
            dlg = QConfigurationDialog(self)
2538
            if QDialog.Accepted == dlg.show_dialog():
2539
                if dlg.need_to_convert:
2540
                    Conversion(dlg.decimal_point)
2541
                    self.actionSaveCliked(show_message=False)
2542
                    self.load_HMB()
2543

    
2544
                self.reload_units()
2545
                self.update_label_contents()
2546
                self.change_output_font_color()
2547
        except Exception as ex:
2548
            message = f'error occurred({repr(ex)}) in {sys.exc_info()[-1].tb_frame.f_code.co_filename}:' \
2549
                      f'{sys.exc_info()[-1].tb_lineno}'
2550
            self.addMessage.emit(MessageType.Error, message)
2551

    
2552
    def showImageSelectionMessageBox(self):
2553
        """Show Image Selection Guide MessageBox"""
2554
        QMessageBox.information(self, self.tr("Information"), self.tr("First of all, please open a drawing"))
2555

    
2556
    def display_colors(self, value):
2557
        """ display colors """
2558
        from DisplayColors import DisplayColors
2559
        from DisplayColors import DisplayOptions
2560

    
2561
        DisplayColors.instance().option = DisplayOptions.DisplayByLineNo if value == True else DisplayOptions.DisplayByLineType
2562
        if hasattr(self, 'graphicsView'):
2563
            self.graphicsView.scene.update(self.graphicsView.sceneRect())
2564
            DisplayColors.instance().save_data()
2565

    
2566
    '''
2567
        @brief      Open Border file 
2568
        @author     yeonjin
2569
        @date       2019.07.10
2570
    '''
2571

    
2572
    def open_border_file(self):
2573
        self.fitWindow(None)
2574

    
2575
    def patch_data(self):
2576
        '''apply path data'''
2577
        try:
2578
            app_doc_data = AppDocData.instance()
2579
            file_path = os.path.join(os.path.dirname(os.path.realpath(__file__)), 'Scripts', 'patch.sql')
2580
            if os.path.isfile(file_path):
2581
                with open(file_path, 'rb') as file:
2582
                    scripts = file.read().decode('utf-8')
2583
                    app_doc_data.apply_path_data(scripts)
2584

    
2585
            find_column_names = ['Homo_Den', 'Homo_Vel']
2586
            column_names = app_doc_data.get_column_names('PressureVariation')
2587
            for column_name in find_column_names:
2588
                if column_name not in column_names:
2589
                    app_doc_data.add_column(column_name, 'REAL', 'PressureVariation')
2590

    
2591
            find_column_names = ['Input_Flowrate_Type']
2592
            column_names = app_doc_data.get_column_names('HMB')
2593
            for column_name in find_column_names:
2594
                if column_name not in column_names:
2595
                    app_doc_data.add_column(column_name, 'TEXT', 'HMB')
2596

    
2597
        except Exception as ex:
2598
            message = f"error occurred({repr(ex)}) in {sys.exc_info()[-1].tb_frame.f_code.co_filename}:" \
2599
                      f"{sys.exc_info()[-1].tb_lineno}"
2600
            self.addMessage.emit(MessageType.Error, message)
2601

    
2602
    def setAttributes(self, drawing):
2603
        drawing.setAttributes()
2604

    
2605
    '''
2606
        @brief      Reload HMB Units 
2607
        @author     yeonjin
2608
        @date       2019.07.10
2609
    '''
2610

    
2611
    def reload_units(self):
2612
        from Drawing import Drawing
2613

    
2614
        try:
2615
            app_doc_data = AppDocData.instance()
2616
            drawing = app_doc_data.activeDrawing
2617

    
2618
            self.setAttributes(drawing)
2619
            model = self.tableWidgetHMB.model()
2620

    
2621
            units = app_doc_data.getHMBDisplayNameAndUnitsExpression()  ## load unit information from database
2622
            for row in range(units.rowCount()):
2623
                unit = self.convertToUnits(units.item(row, 1).text())
2624

    
2625
                item = model.item(row, 1)
2626
                item.setText(unit)
2627

    
2628
            self.tableWidgetHMB.resizeColumnsToContents()
2629
            self.tableWidgetHMB.resizeRowsToContents()
2630

    
2631
        except Exception as ex:
2632
            message = f'error occurred({ex}) in {sys.exc_info()[-1].tb_frame.f_code.co_filename}:' \
2633
                      f'{sys.exc_info()[-1].tb_lineno}'
2634
            self.addMessage.emit(MessageType.Error, message)
2635

    
2636
    def load_data(self, drawing):
2637
        """ load data from drawing """
2638
        from AppDocData import AppDocData
2639
        from Calculation import Calculation
2640
        from HydroCalculationCommand import HydroCalculationCommand
2641
        from Drawing import Drawing
2642

    
2643
        try:
2644
            app_doc_data = AppDocData.instance()
2645

    
2646
            self.graphicsView.scene.clear()
2647
            # Set appDocData
2648
            app_doc_data.clear()
2649
            self.onCommandRejected()
2650
            app_doc_data.activeDrawing = drawing
2651

    
2652
            shutil.copyfile(drawing.org_path, drawing.path)
2653
            success = app_doc_data.build_drawing_database(drawing.path)
2654
            if not success:
2655
                QMessageBox.information(self, self.tr('Warning'),
2656
                                        self.tr('The App version is lower than the document version. Please update.'))
2657
                return
2658

    
2659
            self.patch_data()
2660

    
2661
            self.setAttributes(drawing)
2662
            self.setMainWindowTitle(drawing.path)
2663
            self.initTableWidgetHMB()
2664
            self.clear_loop()
2665
            self.clearlogs()
2666
            self.clear_output()
2667
            # Load data on database
2668

    
2669
            self.symbolTreeWidget.initSymbolTreeWidget()
2670

    
2671
            components = app_doc_data.getComponentListByDrawingUID()
2672
            count = len(components)
2673

    
2674
            if count > 0:
2675
                try:
2676
                    self.progress = QProgressDialog(self.tr("Please wait for a while"), self.tr("Cancel"), 0, 100,
2677
                                                    self) if not hasattr(self, 'progress') else self.progress
2678
                    self.progress.setWindowModality(Qt.WindowModal)
2679
                    self.progress.setAutoReset(True)
2680
                    self.progress.setAutoClose(True)
2681
                    self.progress.setMinimum(0)
2682
                    self.progress.resize(600, 100)
2683
                    self.progress.setWindowTitle(self.tr("Load data..."))
2684
                    self.progress.show()
2685

    
2686
                    self.load_components(components)
2687

    
2688
                    self.calculation()
2689
                finally:
2690
                    self.progress.setValue(self.progress.maximum())
2691
                    self.progress.hide()
2692

    
2693
            # self.changeViewCheckedState(False)
2694
            palette = self.graphicsView.palette()
2695
            _pixmap = QPixmap(':/images/error.svg')
2696
            palette.setBrush(QPalette.Background, QBrush(_pixmap))
2697
            self.graphicsView.setPalette(palette)
2698

    
2699
        except Exception as ex:
2700
            message = f'error occurred({repr(ex)}) in {sys.exc_info()[-1].tb_frame.f_code.co_filename}:' \
2701
                      f'{sys.exc_info()[-1].tb_lineno}'
2702
            self.addMessage.emit(MessageType.Error, message)
2703

    
2704
    def saveAs_drawing(self, sourceDb):
2705
        import uuid
2706
        from shutil import copyfile
2707
        from datetime import datetime
2708
        from Drawing import Drawing
2709

    
2710
        workspace = self.get_work_space()
2711

    
2712
        options = QFileDialog.Options()
2713
        options |= QFileDialog.DontUseNativeDialog
2714
        name, _ = QFileDialog.getSaveFileName(self, self.tr('Save As'), workspace, 'HYTOS Files (*.hytos)',
2715
                                              options=options)
2716
        if name:
2717
            if os.path.splitext(name)[1] != '.hytos': name += '.hytos'
2718

    
2719
            app_doc_data = AppDocData.instance()
2720
            # copy template.db to name
2721
            copyfile(sourceDb, name)
2722

    
2723
            matches = [drawing for drawing in app_doc_data.get_drawings() if
2724
                       os.path.exists(drawing.path) and os.path.samefile(drawing.path, name)]
2725
            if not matches:
2726
                drawing = Drawing(str(uuid.uuid4()), name, str(datetime.now().strftime('%Y-%m-%d %H:%M:%S')))
2727
                app_doc_data.save_drawing(drawing)
2728
            else:
2729
                drawing = Drawing(str(matches[0].UID), name, str(datetime.now().strftime('%Y-%m-%d %H:%M:%S')))
2730
                app_doc_data.update_drawing(drawing)
2731

    
2732
            self.load_drawing_list()
2733
            self.load_data(drawing)
2734
            self.open_border_file()
2735

    
2736
    '''
2737
        @brief      create new drawing
2738
        @author     yeonjin
2739
        @date       2019.07.03
2740
    '''
2741

    
2742
    def new_drawing(self):
2743
        import uuid
2744
        from shutil import copyfile
2745
        from datetime import datetime
2746
        from Drawing import Drawing
2747

    
2748
        self.save_drawing_if_necessary()
2749

    
2750
        workspace = self.get_work_space()
2751

    
2752
        options = QFileDialog.Options()
2753
        options |= QFileDialog.DontUseNativeDialog
2754
        name, _ = QFileDialog.getSaveFileName(self, self.tr('New'), workspace, 'HYTOS Files (*.hytos)', options=options)
2755
        if name:
2756
            if os.path.splitext(name)[1] != '.hytos': name += '.hytos'
2757

    
2758
            app_doc_data = AppDocData.instance()
2759
            # copy template.db to name
2760
            copyfile(app_doc_data.getTemplateDbPath(), name)
2761

    
2762
            matches = [drawing for drawing in app_doc_data.get_drawings() if
2763
                       os.path.exists(drawing.path) and os.path.samefile(drawing.path, name)]
2764
            if not matches:
2765
                drawing = Drawing(str(uuid.uuid4()), name, str(datetime.now().strftime('%Y-%m-%d %H:%M:%S')))
2766
                app_doc_data.save_drawing(drawing)
2767
            else:
2768
                drawing = Drawing(str(matches[0].UID), name, str(datetime.now().strftime('%Y-%m-%d %H:%M:%S')))
2769
                app_doc_data.update_drawing(drawing)
2770

    
2771
            self.load_drawing_list()
2772
            self.open_border_file()
2773
            self.load_data(drawing)
2774

    
2775
    def on_open_drawing(self):
2776
        """open selected drawing by user"""
2777

    
2778
        self.save_drawing_if_necessary()
2779

    
2780
        workspace = self.get_work_space()
2781
        options = QFileDialog.Options()
2782
        options |= QFileDialog.DontUseNativeDialog
2783
        name, _ = QFileDialog.getOpenFileName(self, self.tr('Open'), workspace, 'HYTOS File(*.hytos)', options=options)
2784
        if name:
2785
            self.open_drawing(name)
2786

    
2787
    def open_drawing(self, name):
2788
        """open given drawing has name"""
2789
        import uuid
2790
        from Drawing import Drawing
2791
        from datetime import datetime
2792

    
2793
        app_doc_data = AppDocData.instance()
2794
        drawings = app_doc_data.get_drawings()
2795
        matches = [drawing for drawing in drawings if os.path.samefile(drawing.org_path, name)]
2796
        if not matches:
2797
            drawing = Drawing(str(uuid.uuid4()), name, str(datetime.now().strftime('%Y-%m-%d %H:%M:%S')))
2798
            app_doc_data.save_drawing(drawing)
2799

    
2800
            self.load_drawing_list()
2801
        else:
2802
            drawing = matches[0]
2803

    
2804
        # disconnect scene changed if signal is connected
2805
        if self.graphicsView.scene.receivers(self.graphicsView.scene.contents_changed) > 0:
2806
            self.graphicsView.scene.contents_changed.disconnect()
2807

    
2808
        self.load_data(drawing)
2809
        self.open_border_file()
2810

    
2811
        # connect scene changed signal
2812
        self.graphicsView.scene.contents_changed.connect(self.scene_changed)
2813

    
2814
    def get_work_space(self):
2815
        """get work space path"""
2816
        app_doc_data = AppDocData.instance()
2817

    
2818
        configs = app_doc_data.getAppConfigs('option', 'WorkSpace')
2819
        if configs and len(configs) == 1:
2820
            return configs[0].value
2821
        else:
2822
            return os.getcwd()
2823

    
2824
    def changeViewCheckedState(self, checked, clear=True):
2825
        '''change view checked state'''
2826
        if clear:
2827
            self.initTableWidgetHMB()
2828
            # self.clear_data()
2829

    
2830
    '''
2831
        @brief      create a line
2832
        @author     humkyung
2833
        @history    Jeongwoo 2018.05.10 Change method for Checkable action
2834
    '''
2835

    
2836
    def onPlaceLine(self):
2837

    
2838
        if self.graphicsView.command is not None:
2839
            self.graphicsView.command.reset()
2840

    
2841
        #if self.actionLine.isChecked():
2842
        self.actionLine.setChecked(True)
2843
        if not hasattr(self.actionLine, 'tag'):
2844
            self.actionLine.tag = PlaceStreamlineCommand.PlaceStreamlineCommand(self.graphicsView)
2845
            self.actionLine.tag.onSuccess.connect(self.on_stream_line_created)
2846
            self.actionLine.tag.onRejected.connect(self.onCommandRejected)
2847

    
2848
        self.graphicsView.command = self.actionLine.tag
2849

    
2850
    def add_new_stream_line(self, stream_line: QEngineeringStreamlineItem) -> None:
2851
        """add a new stream line"""
2852
        self.add_hmb_data(stream_line)
2853
        stream_line.transfer.onRemoved.connect(self.on_item_removed)
2854
        self.load_HMB()
2855

    
2856
    def on_stream_line_created(self):
2857
        """callback after stream line is created"""
2858
        from CreateCommand import CreateCommand
2859
        try:
2860
            count = len(self.actionLine.tag.streamline._vertices)
2861
            if count > 1:
2862
                stream_line = self.actionLine.tag.streamline
2863
                self.add_new_stream_line(stream_line)
2864
                self.graphicsView.scene.undo_stack.push(CreateCommand(self.graphicsView.scene, [stream_line, ]))
2865
        finally:
2866
            self.actionLine.tag.reset()
2867

    
2868
    def on_stream_line_deleted(self, stream_line):
2869
        """ callback after stream line is deleted """
2870
        app_doc_data = AppDocData.instance()
2871
        activeDrawing = app_doc_data.activeDrawing
2872
        if activeDrawing:
2873
            # activeDrawing.hmbTable.deleteByUID(stream_line.uid)
2874
            activeDrawing.hmbTable.deleteByStreamNo(stream_line.stream_no)
2875

    
2876
        self.load_HMB()
2877

    
2878
    def add_hmb_data(self, stream_line):
2879
        """ add a new hmb data associated with given stream line """
2880
        from HMBTable import HMBTable
2881
        import uuid
2882

    
2883
        try:
2884
            drawing = AppDocData.instance().activeDrawing
2885
            if drawing:
2886
                components_uid = stream_line.uid
2887
                stream_no = self.get_next_stream_no(drawing)
2888
                drawing.hmbTable.add(components_uid, stream_no)
2889
                stream_line.stream_no = stream_no
2890
                stream_line.stream_no_text = str(stream_no)
2891
        except Exception as ex:
2892
            message = 'error occurred({}) in {}:{}'.format(ex, sys.exc_info()[-1].tb_frame.f_code.co_filename,
2893
                                                           sys.exc_info()[-1].tb_lineno)
2894
            self.addMessage.emit(MessageType.Error, message)
2895

    
2896
    def get_next_stream_no(self, drawing):
2897
        if len(list(drawing.hmbTable.streamNos())) == 0:
2898
            return 1
2899
        else:
2900
            if len(list(drawing.hmbTable.deleted_stream_nos())) > 0:
2901
                deleted_stream_nos = sorted(list(drawing.hmbTable.deleted_stream_nos()))
2902
                lastStreamNo = deleted_stream_nos[-1]
2903
                return lastStreamNo
2904
            else:
2905
                streamNos = sorted(list(drawing.hmbTable.streamNos()))
2906
                lastStreamNo = streamNos[-1]
2907
                return lastStreamNo + 1
2908

    
2909
    def clear_HMB(self):
2910
        self.tableWidgetHMB.clearContents()
2911
        self.tableWidgetHMB.setColumnCount(0)
2912

    
2913
    def load_HMB(self) -> None:
2914
        """ display hmb data to table widget """
2915
        from CalculationValidation import QCalculationValidation
2916

    
2917
        drawing = AppDocData.instance().activeDrawing
2918
        if drawing is None: return
2919

    
2920
        try:
2921
            hmbs = drawing.hmbTable._hmbs
2922
            if hmbs is not None:
2923
                model = self.tableWidgetHMB.model()
2924
                model.setColumnCount(2)
2925

    
2926
                col_names = ['Stream No.\n', 'Unit\n']
2927
                _hmbs = sorted(hmbs, key=lambda hmb: hmb.stream_no)
2928
                for hmb in _hmbs:
2929
                    columnCount = model.columnCount()
2930
                    # self.tableWidgetHMB.setColumnCount(columnCount + 1)
2931
                    col_names.append(str(hmb.stream_no) + '\n(' + str(
2932
                        hmb.stream_no_text if hmb.stream_no_text else hmb._stream_no) + ')')
2933

    
2934
                    item = set_item_properties(hmb.uid, Qt.AlignHCenter | Qt.AlignVCenter)
2935
                    model.setItem(0, columnCount, item)
2936
                    item = set_item_properties(hmb.components_uid, Qt.AlignHCenter | Qt.AlignVCenter)
2937
                    model.setItem(1, columnCount, item)
2938
                    item = set_item_properties(hmb.stream_no, Qt.AlignHCenter | Qt.AlignVCenter)
2939
                    model.setItem(2, columnCount, item)
2940
                    item = set_item_properties(hmb.phase_type, Qt.AlignHCenter | Qt.AlignVCenter)
2941
                    item.setData(hmb.phase_type, Qt.UserRole)
2942
                    model.setItem(3, columnCount, item)
2943

    
2944
                    item = set_item_properties(convert_to_fixed_point(hmb.flowrate_mass),
2945
                                               Qt.AlignHCenter | Qt.AlignVCenter)
2946
                    item.setData(hmb.flowrate_mass, Qt.UserRole)
2947
                    model.setItem(4, columnCount, item)
2948

    
2949
                    item = set_item_properties(convert_to_fixed_point(hmb.flowrate_volume),
2950
                                               Qt.AlignHCenter | Qt.AlignVCenter)
2951
                    item.setData(hmb.flowrate_volume, Qt.UserRole)
2952
                    """
2953
                    if hmb.phase_type == 'Vapor':
2954
                        item.setFlags(Qt.ItemIsEnabled | Qt.ItemIsSelectable)
2955
                    """
2956
                    model.setItem(5, columnCount, item)
2957

    
2958
                    item = set_item_properties(convert_to_fixed_point(hmb.density), Qt.AlignHCenter | Qt.AlignVCenter)
2959
                    item.setData(hmb.density, Qt.UserRole)
2960
                    model.setItem(6, columnCount, item)
2961

    
2962
                    item = set_item_properties(convert_to_fixed_point(hmb.viscosity), Qt.AlignHCenter | Qt.AlignVCenter)
2963
                    item.setData(hmb.viscosity, Qt.UserRole)
2964
                    model.setItem(7, columnCount, item)
2965

    
2966
                    item = set_item_properties(convert_to_fixed_point(hmb.temperature),
2967
                                               Qt.AlignHCenter | Qt.AlignVCenter)
2968
                    item.setData(hmb.temperature, Qt.UserRole)
2969
                    model.setItem(8, columnCount, item)
2970

    
2971
                    item = set_item_properties(convert_to_fixed_point(hmb.molecular_weight),
2972
                                               Qt.AlignHCenter | Qt.AlignVCenter)
2973
                    item.setData(hmb.molecular_weight, Qt.UserRole)
2974
                    model.setItem(9, columnCount, item)
2975

    
2976
                    item = set_item_properties(convert_to_fixed_point(hmb.specific_heat_ratio),
2977
                                               Qt.AlignHCenter | Qt.AlignVCenter)
2978
                    item.setData(hmb.specific_heat_ratio, Qt.UserRole)
2979
                    model.setItem(10, columnCount, item)
2980

    
2981
                    item = set_item_properties(convert_to_fixed_point(hmb.compress_factor),
2982
                                               Qt.AlignHCenter | Qt.AlignVCenter)
2983
                    item.setData(hmb.compress_factor, Qt.UserRole)
2984
                    model.setItem(11, columnCount, item)
2985

    
2986
                    item = set_item_properties(convert_to_fixed_point(hmb.nominal_pipe_size),
2987
                                               Qt.AlignHCenter | Qt.AlignVCenter)
2988
                    item.setData(hmb.nominal_pipe_size, Qt.UserRole)
2989
                    model.setItem(12, columnCount, item)
2990

    
2991
                    item = set_item_properties(convert_to_fixed_point(hmb.inside_pipe_size),
2992
                                               Qt.AlignHCenter | Qt.AlignVCenter)
2993
                    item.setData(hmb.inside_pipe_size, Qt.UserRole)
2994
                    model.setItem(13, columnCount, item)
2995

    
2996
                    item = set_item_properties(convert_to_fixed_point(hmb.schedule_no),
2997
                                               Qt.AlignHCenter | Qt.AlignVCenter)
2998
                    item.setData(hmb.schedule_no, Qt.UserRole)
2999
                    model.setItem(14, columnCount, item)
3000

    
3001
                    item = set_item_properties(convert_to_fixed_point(hmb.straight_length),
3002
                                               Qt.AlignHCenter | Qt.AlignVCenter)
3003
                    item.setData(hmb.straight_length, Qt.UserRole)
3004
                    model.setItem(15, columnCount, item)
3005

    
3006
                    item = set_item_properties(convert_to_fixed_point(hmb.equivalent_length),
3007
                                               Qt.AlignHCenter | Qt.AlignVCenter)
3008
                    item.setData(hmb.equivalent_length, Qt.UserRole)
3009
                    model.setItem(16, columnCount, item)
3010

    
3011
                    item = set_item_properties(convert_to_fixed_point(hmb.equivalent_length_input),
3012
                                               Qt.AlignHCenter | Qt.AlignVCenter)
3013
                    item.setData(hmb.equivalent_length_input, Qt.UserRole)
3014
                    model.setItem(17, columnCount, item)
3015

    
3016
                    item = set_item_properties(convert_to_fixed_point(hmb.fitting_length),
3017
                                               Qt.AlignHCenter | Qt.AlignVCenter)
3018
                    item.setData(hmb.fitting_length, Qt.UserRole)
3019
                    model.setItem(18, columnCount, item)
3020

    
3021
                    item = set_item_properties(convert_to_fixed_point(hmb.fitting_K), Qt.AlignHCenter | Qt.AlignVCenter)
3022
                    item.setData(hmb.fitting_K, Qt.UserRole)
3023
                    model.setItem(19, columnCount, item)
3024

    
3025
                    item = set_item_properties(convert_to_fixed_point(hmb.equivalent_length_cal),
3026
                                               Qt.AlignHCenter | Qt.AlignVCenter)
3027
                    item.setData(hmb.equivalent_length_cal, Qt.UserRole)
3028
                    model.setItem(20, columnCount, item)
3029

    
3030
                    item = set_item_properties(convert_to_fixed_point(hmb.roughness), Qt.AlignHCenter | Qt.AlignVCenter)
3031
                    item.setData(hmb.roughness, Qt.UserRole)
3032
                    model.setItem(21, columnCount, item)
3033

    
3034
                    item = set_item_properties(convert_to_fixed_point(hmb.limitation_velocity),
3035
                                               Qt.AlignHCenter | Qt.AlignVCenter)
3036
                    item.setData(hmb.limitation_velocity, Qt.UserRole)
3037
                    model.setItem(22, columnCount, item)
3038

    
3039
                    item = set_item_properties(convert_to_fixed_point(hmb.limitation_pressure_drop),
3040
                                               Qt.AlignHCenter | Qt.AlignVCenter)
3041
                    item.setData(hmb.limitation_pressure_drop, Qt.UserRole)
3042
                    model.setItem(23, columnCount, item)
3043

    
3044
                    item = set_item_properties(None, Qt.AlignHCenter | Qt.AlignVCenter, QColor(153, 204, 255))
3045
                    model.setItem(24, columnCount, item)
3046

    
3047
                    item = set_item_properties(convert_to_fixed_point(hmb.velocity), Qt.AlignHCenter | Qt.AlignVCenter)
3048
                    item.setEditable(False)
3049
                    model.setItem(25, columnCount, item)
3050

    
3051
                    item = set_item_properties(convert_to_fixed_point(hmb.reynolds), Qt.AlignHCenter | Qt.AlignVCenter)
3052
                    item.setEditable(False)
3053
                    model.setItem(26, columnCount, item)
3054

    
3055
                    item = set_item_properties(convert_to_fixed_point(hmb.friction_factor),
3056
                                               Qt.AlignHCenter | Qt.AlignVCenter)
3057
                    item.setEditable(False)
3058
                    model.setItem(27, columnCount, item)
3059

    
3060
                    item = set_item_properties(convert_to_fixed_point(hmb.pressure_drop),
3061
                                               Qt.AlignHCenter | Qt.AlignVCenter)
3062
                    item.setEditable(False)
3063
                    model.setItem(28, columnCount, item)
3064

    
3065
                    item = set_item_properties(convert_to_fixed_point(hmb.pressure_drop_friction),
3066
                                               Qt.AlignHCenter | Qt.AlignVCenter)
3067
                    item.setEditable(False)
3068
                    model.setItem(29, columnCount, item)
3069

    
3070
                    item = set_item_properties(convert_to_fixed_point(hmb.pressure_drop_static),
3071
                                               Qt.AlignHCenter | Qt.AlignVCenter)
3072
                    item.setEditable(False)
3073
                    model.setItem(30, columnCount, item)
3074

    
3075
                    item = set_item_properties(convert_to_fixed_point(hmb.pressure_pipe_end_point),
3076
                                               Qt.AlignHCenter | Qt.AlignVCenter)
3077
                    item.setEditable(False)
3078
                    model.setItem(31, columnCount, item)
3079

    
3080
                    item = set_item_properties(convert_to_fixed_point(hmb.power), Qt.AlignHCenter | Qt.AlignVCenter)
3081
                    item.setEditable(False)
3082
                    model.setItem(32, columnCount, item)
3083

    
3084
                    if hmb.isDeleted:
3085
                        self.tableWidgetHMB.hideColumn(columnCount)
3086

    
3087
                    # mark if velocity or pressure drop is over criteria value
3088
                    if hmb.is_over_criteria:
3089
                        rows = model.rowCount()
3090
                        for row in range(rows):
3091
                            item = model.item(row, columnCount)
3092
                            item.setBackground(Qt.red)
3093
                    # up to here
3094

    
3095
                model.setHorizontalHeaderLabels(col_names)
3096
                self.tableWidgetHMB.setModel(model)
3097

    
3098
                self.tableWidgetHMB.resizeColumnsToContents()
3099
                self.tableWidgetHMB.resizeRowsToContents()
3100
        except Exception as ex:
3101
            message = f"error occurred({repr(ex)}) in {sys.exc_info()[-1].tb_frame.f_code.co_filename}:" \
3102
                      f"{sys.exc_info()[-1].tb_lineno}"
3103
            self.addMessage.emit(MessageType.Error, message)
3104

    
3105
    '''
3106
        @brief      refresh scene
3107
        @author     humkyung
3108
        @date       2018.07.23
3109
    '''
3110

    
3111
    def onCommandRejected(self, cmd=None):
3112
        try:
3113
            if type(cmd) is PlaceStreamlineCommand.PlaceStreamlineCommand:
3114
                if self.actionLine.tag.streamline:
3115
                    self.graphicsView.scene.removeItem(self.actionLine.tag.streamline)
3116
                self.graphicsView.scene.update()
3117
                self.actionLine.tag.reset()
3118
                self.actionLine.setChecked(False)
3119
            elif type(cmd) is AreaZoomCommand.AreaZoomCommand:
3120
                self.actionZoom.setChecked(False)
3121
            else:
3122
                if hasattr(self.actionLine, 'tag') and self.actionLine.tag.streamline:
3123
                    self.graphicsView.scene.removeItem(self.actionLine.tag.streamline)
3124
                    self.graphicsView.scene.update()
3125
                    self.actionLine.tag.reset()
3126

    
3127
                self.actionLine.setChecked(False)
3128
                self.actionZoom.setChecked(False)
3129
                self.actionSelectByPolygon.setChecked(False)
3130
        finally:
3131
            self.graphicsView.useDefaultCommand()
3132

    
3133
    '''
3134
        @brief      restore to default command when user press Escape key
3135
        @author     humkyung 
3136
        @date       2018.08.09
3137

3138
    '''
3139

    
3140
    def keyPressEvent(self, event):
3141
        try:
3142
            if event.key() == Qt.Key_Escape:
3143
                self.onCommandRejected()
3144
                '''self.graphicsView.useDefaultCommand()
3145
                for action in self.toolBar.actions():
3146
                    # if hasattr(action, 'tag') and action.isChecked():
3147
                    if action.isChecked():  # AreaZoom Command's tag is empty
3148
                        action.setChecked(False)'''
3149
            elif (event.key() == Qt.Key_C) and (event.modifiers() & Qt.ControlModifier):
3150
                if self.tableWidgetHMB.hasFocus():
3151
                    self.copy_selection(self.tableWidgetHMB)
3152
            elif (event.key() == Qt.Key_V) and (event.modifiers() & Qt.ControlModifier):
3153
                if self.tableWidgetHMB.hasFocus():
3154
                    self.paste_selection(self.tableWidgetHMB)
3155

    
3156
            QMainWindow.keyPressEvent(self, event)
3157
        except Exception as ex:
3158
            message = f'error occurred({ex}) in {sys.exc_info()[-1].tb_frame.f_code.co_filename}:' \
3159
                      f'{sys.exc_info()[-1].tb_lineno}'
3160
            self.addMessage.emit(MessageType.Error, message)
3161

    
3162
    def on_item_removed(self, item):
3163
        """remove item from tree widget and then remove from scene"""
3164

    
3165
        try:
3166
            matches = [_item for _item in self.graphicsView.scene.items() if hasattr(_item, 'connectors') and \
3167
                       [connector for connector in _item.connectors if
3168
                        connector.connectedItem is not None and connector.connectedItem.parentItem() is item]]
3169
            # disconnect deleted item
3170
            for match in matches:
3171
                for connector in match.connectors:
3172
                    if connector.connectedItem and connector.connectedItem.parentItem() is item:
3173
                        connector.connect(None)
3174

    
3175
            matches = [_item for _item in self.graphicsView.scene.items() if hasattr(_item, 'owner')]
3176
            for match in matches:
3177
                if match.owner is item:
3178
                    match.owner = None
3179

    
3180
            matches = [_item for _item in self.graphicsView.scene.items() if hasattr(_item, 'attrs')]
3181
            done = False
3182
            for match in matches:
3183
                for assoc in match.associations():
3184
                    if item is assoc:
3185
                        match.remove_assoc_item(item)
3186
                        for attr in match.attrs.keys():
3187
                            if str(item.uid) == str(attr.AssocItem.uid):
3188
                                attr.AssocItem = None
3189
                                match.attrs[attr] = ''
3190
                                done = True
3191
                                break
3192
                        break
3193
                if done: break
3194

    
3195
            if type(item) is QEngineeringStreamlineItem:
3196
                self.on_stream_line_deleted(item)
3197

    
3198
            if item.scene() is not None:
3199
                item.scene().removeItem(item)
3200
                del item
3201
        except Exception as ex:
3202
            message = 'error occurred({}) in {}:{}'.format(repr(ex), sys.exc_info()[-1].tb_frame.f_code.co_filename,
3203
                                                           sys.exc_info()[-1].tb_lineno)
3204
            self.addMessage.emit(MessageType.Error, message)
3205

    
3206
    '''
3207
        @brief      load components
3208
        @author     yeonjin
3209
        @date       2019.07.30.
3210
    '''
3211

    
3212
    def load_components(self, componentsUID):
3213
        from EngineeringStreamlineItem import QEngineeringStreamlineItem
3214
        from EngineeringCalloutTextItem import QEngineeringCalloutTextItem
3215
        from EngineeringDimensionItem import QEngineeringDimensionItem
3216
        from EngineeringCloudItem import QEngineeringCloudItem
3217

    
3218
        try:
3219
            app_doc_data = AppDocData.instance()
3220

    
3221
            maxValue = len(componentsUID)
3222
            self.progress.setMaximum(maxValue)
3223

    
3224
            for componentUID in componentsUID:
3225
                componentInfos = app_doc_data.getComponentByComponentUID(componentUID)
3226
                if (len(componentInfos)) > 0:
3227
                    category = componentInfos[0]['Category']  # Category@SymbolType
3228
                    symbol_name = componentInfos[0]['Symbol_Name']  # Name@Symbols
3229

    
3230
                    if category == 'Stream Line':
3231
                        item = QEngineeringStreamlineItem.fromDatabase(componentInfos)
3232
                        if item is not None:
3233
                            item.transfer.onRemoved.connect(self.on_item_removed)
3234
                            self.graphicsView.scene.addItem(item)
3235
                    elif symbol_name == 'Callout':
3236
                        item = QEngineeringCalloutTextItem.fromDatabase(componentInfos)
3237
                        if item:
3238
                            item.transfer.onRemoved.connect(self.on_item_removed)
3239
                            item.lost_focus.connect(self.editor_lost_focus)
3240
                            item.selected_change.connect(self.item_selected)
3241
                            self.graphicsView.scene.addItem(item)
3242
                    elif symbol_name == 'Dimension':
3243
                        item = QEngineeringDimensionItem.fromDatabase(componentInfos)
3244
                        if item:
3245
                            item.transfer.onRemoved.connect(self.on_item_removed)
3246
                            self.graphicsView.scene.addItem(item)
3247
                    elif symbol_name == 'Cloud':
3248
                        item = QEngineeringCloudItem.fromDatabase(componentInfos)
3249
                        if item:
3250
                            self.graphicsView.scene.addItem(item)
3251
                    else:
3252
                        item = SymbolSvgItem.fromDatabase(componentInfos)
3253
                        if item is not None:
3254
                            item.transfer.onRemoved.connect(self.on_item_removed)
3255
                            app_doc_data.symbols.append(item)
3256
                            item.addSvgItemToScene(self.graphicsView.scene)
3257

    
3258
                    self.progress.setValue(self.progress.value() + 1)
3259

    
3260
                QApplication.processEvents()
3261

    
3262
            # self.rebuild_label()
3263

    
3264
            # """ update scene """
3265
            self.graphicsView.scene.update(self.graphicsView.sceneRect())
3266
            for item in self.graphicsView.scene.items():
3267
                # force to connect streamline to symbol
3268
                if type(item) is QEngineeringStreamlineItem:
3269
                    item.on_symbol_pos_changed(None)
3270
                # up to here
3271
                item.setVisible(True)
3272

    
3273
        except Exception as ex:
3274
            message = f'error occurred({repr(ex)}) in {sys.exc_info()[-1].tb_frame.f_code.co_filename}:' \
3275
                      f'{sys.exc_info()[-1].tb_lineno}'
3276
            self.addMessage.emit(MessageType.Error, message)
3277
        finally:
3278
            pass
3279

    
3280
    '''
3281
        @brief      Remove added item on same place and Add GraphicsItem
3282
        @author     Jeongwoo
3283
        @date       2018.05.25
3284
        @history    2018.05.29  Jeongwoo    Moved from QRecognitionDialog
3285
                    2018.06.05  Jeongwoo    Remove Size condition
3286
                    2018.06.18  Jeongwoo    Set Z-index
3287
    '''
3288

    
3289
    def addTextItemToScene(self, textItem):
3290
        textItem.addTextItemToScene(self.graphicsView.scene)
3291

    
3292
    def add_data(self, table_widget, name, value, unit, separation=None, is_cell_merge=None, foregroundcolor=None):
3293
        def make_table_widget_item(name: str, alignment, backgroundcolor=None,
3294
                                   foregroundcolor=None) -> QTableWidgetItem:
3295
            if name is None:
3296
                name = ''
3297

    
3298
            item = QTableWidgetItem(str(name))
3299
            item.setTextAlignment(alignment)
3300
            if backgroundcolor:
3301
                item.setBackground(backgroundcolor)
3302
            if foregroundcolor:
3303
                item.setForeground(foregroundcolor)  # QBrush(QColor(255, 0, 0)))
3304
            return item
3305

    
3306
        row = table_widget.rowCount()
3307
        table_widget.setRowCount(row + 1)
3308

    
3309
        if separation:
3310
            if is_cell_merge:
3311
                table_widget.setSpan(row, 0, 1, 3)
3312
                table_widget.setItem(row, 0, make_table_widget_item(name, Qt.AlignLeft | Qt.AlignVCenter,
3313
                                                                    QColor(153, 204, 255), foregroundcolor))
3314
            else:
3315
                table_widget.setItem(row, 0, make_table_widget_item(name, Qt.AlignLeft | Qt.AlignVCenter,
3316
                                                                    QColor(153, 204, 255), foregroundcolor))
3317
                table_widget.setItem(row, 1, make_table_widget_item(value, Qt.AlignHCenter | Qt.AlignVCenter,
3318
                                                                    QColor(153, 204, 255), foregroundcolor))
3319
                table_widget.setItem(row, 2, make_table_widget_item(unit, Qt.AlignHCenter | Qt.AlignVCenter,
3320
                                                                    QColor(153, 204, 255), foregroundcolor))
3321
        else:
3322
            if is_cell_merge:
3323
                table_widget.setSpan(row, 0, 1, 3)
3324
                table_widget.setItem(row, 0, make_table_widget_item(name, Qt.AlignLeft | Qt.AlignVCenter,
3325
                                                                    None, foregroundcolor))
3326
            else:
3327
                table_widget.setItem(row, 0, make_table_widget_item(name, Qt.AlignLeft | Qt.AlignVCenter,
3328
                                                                    None, foregroundcolor))
3329
                table_widget.setItem(row, 1, make_table_widget_item(value, Qt.AlignRight | Qt.AlignVCenter,
3330
                                                                    None, foregroundcolor))
3331
                table_widget.setItem(row, 2, make_table_widget_item(unit, Qt.AlignLeft | Qt.AlignVCenter,
3332
                                                                    None, foregroundcolor))
3333

    
3334
        table_widget.resizeRowsToContents()
3335
        table_widget.resizeColumnsToContents()
3336

    
3337

    
3338
if __name__ == '__main__':
3339
    pass
클립보드 이미지 추가 (최대 크기: 500 MB)