프로젝트

일반

사용자정보

통계
| 개정판:

hytos / DTI_PID / DTI_PID / AppDocData.py @ 81d2706d

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

1
# coding: utf-8
2
""" This is document data(SDI) class """
3

    
4
import sys
5
import os
6
import sqlite3
7
from datetime import datetime
8
from enum import Enum
9
from PIL import PngImagePlugin, JpegImagePlugin
10
from PIL import Image
11
from PIL.ImageQt import ImageQt
12

    
13
try:
14
    from PyQt5.QtCore import *
15
    from PyQt5.QtGui import *
16
    from PyQt5 import QtWidgets
17
except ImportError:
18
    from PyQt4.QtCore import *
19
    from PyQt4.QtGui import *
20

    
21
from SingletonInstance import SingletonInstance
22
import symbol
23
from NominalPipeSize import NominalPipeSize
24
from QtImageViewerScene import QtImageViewerScene
25

    
26

    
27
class Config:
28
    def __init__(self, section, key, value):
29
        """constructor"""
30
        self.section = section
31
        self.key = key
32
        self.value = value
33

    
34
    '''
35
        @brief  return size value string
36
        @author humkyung
37
        @date   2018.04.24
38
    '''
39
    def sizeValue(self):
40
        return self.inchStr if 'Inch' == self.sizeUnit else self.metricStr
41

    
42

    
43
'''
44
    @brief  Pipe color class
45
'''
46
class Color:
47
    def __init__(self, index, red, green, blue):
48
        self.index = index
49
        self.red = red
50
        self.green = green
51
        self.blue = blue
52

    
53

    
54
'''
55
    @brief      MessageType
56
    @author     humkyung 
57
    @date       2018.07.31
58
'''
59
class MessageType(Enum):
60
    Normal = 1
61
    Error = 2
62
    Check = 3
63

    
64

    
65
class AppDocData(SingletonInstance):
66
    DATABASE = 'ITI_PID.db'
67

    
68
    def __init__(self):
69
        from DisplayColors import DisplayColors
70

    
71
        self.delimiter = '!-!'
72

    
73
        self._imgFilePath = None
74
        self.imgName = None
75
        self._OCRData = None
76
        self._imgSrc = None
77

    
78
        self._areas = []
79
        self._colors = None
80
        self._lineNoProperties = None
81
        self._lineTypes = None
82
        self._lineTypeConfigs = None
83
        self._activeDrawing = None
84
        #self._hmbTable = None
85
        self._hmbColors = {}
86
        self._hmbData = None
87
        self._arsColors = {}
88
        self._streamLineListModelDatas = []
89
        self._titleBlockProperties = None
90
        self.needReOpening = None
91
        self.SpecBreakUpDownIndicator = []
92
        self.readOnly = False
93

    
94
        # item members are used only recognition except tracerLineNos for trim line no
95
        self.equipments = []
96
        self.lineNos = []
97
        self.lines = []
98
        self.texts = []
99
        self.symbols = []
100
        self.unknowns = []
101
        self.allItems = []
102
        self.tracerLineNos = []
103
        self.lineIndicators = []
104

    
105
        # for cad graphic items to sppid
106
        self.cadGraphics = []
107

    
108
        # caches
109
        self._lineNoPropertiesUID = {}
110
        self._attributeByType = {}
111
        self._connected_items_lists = None
112

    
113
        # caches not need to be clear
114
        self._configs = None
115
        self._symbolType = {}
116
        self._symbolNametList = {}
117
        self._symbolBase = {}
118

    
119
        # for load drawing data from database
120
        self._connecterss = {}
121
        self._associationss = {}
122
        self._attributess = {}
123

    
124
    def clearTempDBData(self):
125
        self._connecterss = {}
126
        self._associationss = {}
127
        self._attributess = {}
128

    
129
    def clearItemList(self, trim):
130
        '''
131
            @brief      clear item list
132
            @author     euisung
133
            @date       2018.11.28
134
        '''
135
        from QEngineeringInstLineNoTextItem import QEngineeringInstLineNoTextItem
136

    
137
        self.equipments.clear()
138
        self.symbols.clear()
139
        self.lineNos.clear()
140
        self.texts.clear()
141
        self.unknowns.clear()
142
        self.allItems.clear()
143
        self.lineIndicators.clear()
144
        if trim:
145
            self.tracerLineNos.clear()
146
            self.lines.clear()
147
            self._connected_items_lists = QEngineeringInstLineNoTextItem()
148

    
149
    def clearData(self):
150
        self._configs = None
151
        self._symbolType = {}
152
        self._symbolNametList = {}
153
        self._symbolBase = {}
154

    
155
        self._lineNoProperties = None
156
        self._lineNoPropertiesUID = {}
157
        self._attributeByType = {}
158

    
159
    '''
160
        @brief      clear
161
        @author     humkyung
162
        @date       2018.09.06
163
    '''
164
    def clear(self, past=None):
165
        from QEngineeringInstLineNoTextItem import QEngineeringInstLineNoTextItem
166

    
167
        if self.activeDrawing and self.activeDrawing.UID and self.activeDrawing.UID != past:
168
            self.clear_occupying_drawing(self.activeDrawing.UID)
169

    
170
        self._imgFilePath = None
171
        self.imgName = None
172
        self._imgSrc = None
173

    
174
        self._areas.clear()
175
        self.equipments.clear()
176
        self.lineNos.clear()
177
        self.lines.clear()
178
        self.texts.clear()
179
        self.symbols.clear()
180
        self.unknowns.clear()
181
        self.allItems.clear()
182
        self.tracerLineNos.clear()
183
        self.cadGraphics.clear()
184
        self.lineIndicators.clear()
185
        self.SpecBreakUpDownIndicator.clear()
186
        #self._colors = None
187
        #self._lineNoProperties = None
188
        self._lineTypeConfigs = None
189
        self._activeDrawing = None
190
        #self._hmbTable = None
191
        self._hmbColors = {}
192
        self._hmbData = None
193
        #self._arsColors = {}
194
        self._streamLineListModelDatas = []
195
        self._titleBlockProperties = None
196

    
197
        #self._configs = None# if not past else self._configs
198
        #self._symbolBase = {}# if not past else self._symbolBase
199
        #self._symbolType = {}# if not past else self._symbolType
200
        #self._lineNoPropertiesUID = {}
201
        self._attributeByType = {}
202
        self._connected_items_lists = QEngineeringInstLineNoTextItem()
203

    
204
        self._connecterss = {}
205
        self._associationss = {}
206
        self._attributess = {}
207

    
208
    def clear_occupying_drawing(self, drawing):
209
        """ clear drawing access """
210
        conn = self.project.database.connect()
211
        with conn:
212
            try:
213
                # Get a cursor object
214
                cursor = conn.cursor()
215
                if drawing:
216
                    sql = "UPDATE Drawings SET [OCCUPIED]=null WHERE [OCCUPIED]='{}' and UID='{}'".format(os.environ['COMPUTERNAME'], drawing)
217
                else:
218
                    sql = "UPDATE Drawings SET [OCCUPIED]=null"
219
                cursor.execute(sql)
220

    
221
                conn.commit()
222
            # Catch the exception
223
            except Exception as ex:
224
                conn.rollback()
225

    
226
                from App import App 
227
                message = 'error occurred({}) in {}:{}'.format(ex, sys.exc_info()[-1].tb_frame.f_code.co_filename, sys.exc_info()[-1].tb_lineno)
228
                App.mainWnd().addMessage.emit(MessageType.Error, message)
229

    
230
    def set_occupying_drawing(self, drawing) -> str:
231
        """ set drawing access return true if success"""
232
        with self.project.database.connect() as conn:
233
            try:
234
                # Get a cursor object
235
                cursor = conn.cursor()
236
                sql = f"select OCCUPIED from Drawings where [UID]='{drawing}'"
237
                cursor.execute(sql)
238

    
239
                rows = cursor.fetchall()
240
                if not rows[0]['OCCUPIED'] or rows[0]['OCCUPIED'] == os.environ['COMPUTERNAME']:
241
                    sql = f"UPDATE Drawings SET [OCCUPIED]='{os.environ['COMPUTERNAME']}' WHERE UID='{drawing}'"
242
                    cursor.execute(sql)
243
                    conn.commit()
244
                    return None
245
                else:
246
                    return rows[0]['OCCUPIED']
247

    
248
            # Catch the exception
249
            except Exception as ex:
250
                conn.rollback()
251

    
252
                from App import App 
253
                message = 'error occurred({}) in {}:{}'.format(ex, sys.exc_info()[-1].tb_frame.f_code.co_filename, sys.exc_info()[-1].tb_lineno)
254
                App.mainWnd().addMessage.emit(MessageType.Error, message)
255

    
256
                return None
257

    
258
    def winsort(self, data):
259
        """ Windows sort """
260

    
261
        from ctypes import wintypes, windll
262
        from functools import cmp_to_key
263

    
264
        _StrCmpLogicalW = windll.Shlwapi.StrCmpLogicalW
265
        _StrCmpLogicalW.argtypes = [wintypes.LPWSTR, wintypes.LPWSTR]
266
        _StrCmpLogicalW.restype  = wintypes.INT
267

    
268
        cmp_fnc = lambda psz1, psz2: _StrCmpLogicalW(psz1, psz2)
269

    
270
        #return sorted(data, key=cmp_to_key(cmp_fnc), reverse=True) #kitech
271
        return sorted(data, key=cmp_to_key(cmp_fnc))
272

    
273
    '''
274
        @brief      Get drawing file list
275
        @author     euisung
276
        @date       2018.09.28
277
    '''
278
    def getDrawingFileList(self):
279
        """ get drawing files which's extension is .png or jpg from drawing folder """
280
        drawingFileList = []
281

    
282
        try:
283
            project = AppDocData.instance().getCurrentProject()
284
            path = project.getDrawingFilePath()
285
            drawingFileList = [f for f in os.listdir(path) if os.path.isfile(os.path.join(path, f)) and
286
                               (os.path.splitext(f)[1].upper() == '.PNG' or os.path.splitext(f)[1].upper() == '.JPG' or
287
                                os.path.splitext(f)[1].upper() == '.JPEG')]
288
            
289
            drawingFileList = self.winsort(drawingFileList)
290
            #drawingFileList.sort()
291
        except Exception as ex:
292
            print('error occurred({}) in {}:{}'.format(ex, sys.exc_info()[-1].tb_frame.f_code.co_filename,
293
                                                      sys.exc_info()[-1].tb_lineno))
294

    
295
        return drawingFileList
296

    
297
    '''
298
        @brief      Get Training file list
299
        @author     euisung
300
        @date       2018.10.16
301
    '''
302
    def getTrainingFileList(self):
303
        try:
304
            project = AppDocData.instance().getCurrentProject()
305
            path = project.getTrainingFilePath()
306
            trainingFileList = os.listdir(path)
307
            trainingFileList.sort()
308
        except Exception as ex:
309
            from App import App
310
            message = 'error occurred({}) in {}:{}'.format(ex, sys.exc_info()[-1].tb_frame.f_code.co_filename,
311
                                                          sys.exc_info()[-1].tb_lineno)
312
            App.mainWnd().addMessage.emit(MessageType.Error, message)
313

    
314
        return trainingFileList
315

    
316
    def getTrainingSymbolFileList(self):
317
        """  Get Symbol Training file list """
318
        try:
319
            project = AppDocData.instance().getCurrentProject()
320
            path = project.getTrainingSymbolFilePath()
321
            symbolTrainingFileList = os.listdir(path)
322
            symbolTrainingFileList.sort()
323
        except Exception as ex:
324
            from App import App
325
            message = 'error occurred({}) in {}:{}'.format(ex, sys.exc_info()[-1].tb_frame.f_code.co_filename,
326
                                                          sys.exc_info()[-1].tb_lineno)
327
            App.mainWnd().addMessage.emit(MessageType.Error, message)
328

    
329
        return symbolTrainingFileList
330

    
331
    '''
332
        @brief      Get DB file path in ProgramData
333
        @author     Jeongwoo
334
        @date       2018.06.27
335
        @history    2018.06.29  Jeongwoo    Change method to get template db path
336
    '''
337
    def getTemplateDbPath(self):
338
        path = os.path.join(os.getenv('ALLUSERSPROFILE'), 'Digital PID')
339
        templateDbPath = os.path.join(path, 'Template.db')
340
        return templateDbPath
341

    
342
    def get_template_symbol_library_path(self):
343
        """return template symbol library path"""
344

    
345
        path = os.path.join(os.getenv('USERPROFILE'), 'Digital PID')
346
        return os.path.join(path, 'SymbolLibrary.syl')
347

    
348
    def getAppDbPath(self):
349
        """
350
        @brief      Get application DB file path in ProgramData
351
        @author     humkyung
352
        @date       2018.10.01
353
        """
354

    
355
        path = os.path.join(os.getenv('USERPROFILE'), 'Digital PID')
356
        app_database = os.path.join(path, 'App.db')
357
        return app_database
358

    
359
    '''
360
        @brief  getter of colors 
361
        @author humkyung
362
        @date   2018.06.18
363
    '''
364
    @property
365
    def colors(self):
366
        import random
367

    
368
        if self._colors is None or self._colors == []:
369
            self._colors = []
370
            with self.project.database.connect() as conn:
371
                try:
372
                    cursor = conn.cursor()
373
                    sql = 'SELECT UID,RED,GREEN,BLUE FROM Colors'
374
                    cursor.execute(sql)
375
                    rows = cursor.fetchall()
376
                    for row in rows:
377
                        self._colors.append(Color(row['UID'], row['RED'], row['GREEN'], row['BLUE']))
378
                # Catch the exception
379
                except Exception as ex:
380
                    from App import App
381
                    message = 'error occurred({}) in {}:{}'.format(ex, sys.exc_info()[-1].tb_frame.f_code.co_filename,
382
                                                                  sys.exc_info()[-1].tb_lineno)
383
                    App.mainWnd().addMessage.emit(MessageType.Error, message)
384

    
385
        return self._colors.pop(random.randrange(0, len(self._colors)))
386

    
387
    '''
388
        @brief  setter of colors
389
        @author humkyung
390
        @date   2018.06.18
391
    '''
392
    @colors.setter
393
    def colors(self, value):
394
        self._colors = value
395

    
396
    '''
397
        @brief      set image file path
398
        @author     humkyung
399
        @date       2018.07.30
400
    '''
401
    def setImgFilePath(self, path):
402
        self._imgFilePath = path
403
        self.imgName = os.path.splitext(os.path.basename(self._imgFilePath))[0]
404

    
405
    @staticmethod
406
    def my_imread(file_path):
407
        """ read a file which's name contains unicode string : ref http://devdoftech.co.kr:82/redmine/issues/631 """
408
        import numpy as np
409
        import cv2
410

    
411
        _bytes = None
412
        with open(file_path.encode('utf-8'), 'rb') as stream:
413
            _bytes = bytearray(stream.read())
414

    
415
        numpyArray = np.asarray(_bytes, dtype=np.uint8)
416
        res = cv2.imdecode(numpyArray, cv2.IMREAD_UNCHANGED)
417
        return res
418

    
419
    @property
420
    def imgSrc(self):
421
        """return the image of active drawing"""
422

    
423
        if self.activeDrawing:
424
            return self.activeDrawing.image
425

    
426
        return None
427

    
428
    @imgSrc.setter
429
    def imgSrc(self, value):
430
        """set the image of active drawing with given value"""
431

    
432
        if self.activeDrawing:
433
            self.activeDrawing.image = value
434

    
435
    '''
436
        @brief  getter of line type configs
437
        @author humkyung
438
        @date   2018.06.28
439
    '''
440
    @property
441
    def lineTypeConfigs(self):
442
        from PyQt5.QtCore import Qt
443

    
444
        if self._lineTypeConfigs is None:
445
            self._lineTypeConfigs = []
446

    
447
            styleMap = [('SolidLine', Qt.SolidLine), ('DashLine', Qt.DashLine), ('DotLine', Qt.DotLine),
448
                        ('DashDotLine', Qt.DashDotLine),
449
                        ('DashDotDotLine', Qt.DashDotDotLine), ('CustomDashLine', Qt.CustomDashLine)]
450

    
451
            configs = self.getConfigs('LineTypes')
452
            for config in configs:
453
                color, width, _style, transparent = config.value.split(',')
454
                matches = [param for param in styleMap if param[0] == _style]
455
                style = matches[0][1] if matches else Qt.SolidLine
456
                self._lineTypeConfigs.append((config.key, color, int(width), style, float(transparent)))
457

    
458
        return self._lineTypeConfigs
459

    
460
    '''
461
        @brief  setter of line type configs
462
        @author humkyung
463
        @date   2018.06.28
464
    '''
465
    @lineTypeConfigs.setter
466
    def lineTypeConfigs(self, value):
467
        self._lineTypeConfigs = value
468

    
469
    @property
470
    def drain_size(self):
471
        """ getter of drain_size """
472
        if not hasattr(self, '_drain_size') or not self._drain_size:
473
            configs = self.getConfigs('Drain Size Rule', 'Size')
474
            self._drain_size = configs[0].value if configs else '1"'
475

    
476
        return self._drain_size
477

    
478
    @drain_size.setter
479
    def drain_size(self, value):
480
        """ setter of drain_size """
481
        self._drain_size = value
482

    
483
    '''
484
        @brief      getter of hmb table
485
        @author     humkyung
486
        @date       2018.07.16
487
    '''
488
    '''
489
    @property
490
    def hmbTable(self):
491
        from HMBTable import HMBTable
492

493
        if self._hmbTable is None:
494
            self._hmbTable = HMBTable()
495
            self._hmbTable.load_data()
496

497
        return self._hmbTable
498
    '''
499

    
500
    '''
501
        @brief      setter of hmb table
502
        @author     humkyung
503
        @date       2018.07.16
504
    '''
505
    '''
506
    @hmbTable.setter
507
    def hmbTable(self, value):
508
        self._hmbTable = value
509
    '''
510

    
511
    '''
512
        @brief  get line type config of given line type
513
        @author humkyung
514
        @date   2018.06.28
515
    '''
516
    def getLineTypeConfig(self, lineType):
517
        from PyQt5.QtCore import Qt
518

    
519
        matches = [config for config in self.lineTypeConfigs if config[0] == lineType]
520
        return matches[0] if matches else (lineType, '#0000FF', 5, Qt.SolidLine, 50)
521

    
522
    def getCurrentPidSource(self):
523
        return self.activeDrawing.currentPidSource
524

    
525
    '''
526
        @brief      Check if exist file name or not
527
        @author     Jeongwoo
528
        @date       2018.05.03
529
    '''
530
    def isExistFileName(self, name):
531
        rows = None
532
        with self.project.database.connect() as conn:
533
            try:
534
                cursor = conn.cursor()
535
                sql = "SELECT * FROM Symbol WHERE name = '" + name + "'"
536
                cursor.execute(sql)
537
                rows = cursor.fetchall()
538
            # Catch the exception
539
            except Exception as ex:
540
                # Roll back any change if something goes wrong
541
                conn.rollback()
542
                print('error occurred({}) in {}:{}'.format(ex, sys.exc_info()[-1].tb_frame.f_code.co_filename,
543
                                                          sys.exc_info()[-1].tb_lineno))
544
            finally:
545
                if rows is not None and len(rows) > 0:
546
                    return True
547
                else:
548
                    return False
549

    
550
    '''
551
        @brief      Insert new symbol into Symbol Table, Moved from SG_DbHelper
552
        @author     Jeongwoo
553
        @date       2018.05.03
554
    '''
555
    def insertSymbol(self, symbol):
556
        isAdded = False
557
        with self.project.database.connect() as conn:
558
            try:
559
                sql = self.project.database.to_sql("""
560
                    INSERT INTO Symbol(name, SymbolType_UID, threshold, minMatchPoint, isDetectOrigin, rotationCount, ocrOption, isContainChild, originalPoint, connectionPoint, baseSymbol, additionalSymbol, isExceptDetect, hasInstrumentLabel, width, height, flip, TextArea, type) 
561
                    VALUES(?, (select UID from SymbolType where Type=?), ?, ?, ?, ?, ?, ?, ?, ?, ?, ?, ?, ?, ?, ?, ?, ?, ?);
562
                """)
563

    
564
                cursor = conn.cursor()
565
                query = (symbol.getName(), symbol.getType(), symbol.getThreshold()
566
                         , symbol.getMinMatchCount(), symbol.getIsDetectOnOrigin(), symbol.getRotationCount()
567
                         , symbol.getOcrOption(), symbol.getIsContainChild()
568
                         , symbol.getOriginalConvertingPoint(), symbol.getConnectionPoint()
569
                         , symbol.getBaseSymbol(), symbol.getAdditionalSymbol(), symbol.getIsExceptDetect(),
570
                         symbol.getHasInstrumentLabel()
571
                         , symbol.width, symbol.height, symbol.detectFlip, symbol.text_area_str, symbol.getDescAndInfo())
572
                cursor.execute(sql, query)
573
                conn.commit()
574
                isAdded = True
575
            # Catch the exception
576
            except Exception as ex:
577
                # Roll back any change if something goes wrong
578
                conn.rollback()
579

    
580
                from App import App
581
                message = 'error occurred({}) in {}:{}'.format(ex, sys.exc_info()[-1].tb_frame.f_code.co_filename,
582
                                                              sys.exc_info()[-1].tb_lineno)
583
                App.mainWnd().addMessage.emit(MessageType.Error, message)
584
            finally:
585
                return (isAdded, symbol.getType(), symbol.getName(), symbol.getPath())
586

    
587
    '''
588
        @brief      Update symbol in Symbol Table, Moved from SG_DbHelper
589
        @author     Jeongwoo
590
        @date       2018.05.03
591
    '''
592
    def updateSymbol(self, symbol):
593
        isUpdated = False
594

    
595
        with self.project.database.connect() as conn:
596
            try:
597
                sql = self.project.database.to_sql("""
598
                    UPDATE Symbol
599
                    SET
600
                        name = ?, SymbolType_UID=(select UID from SymbolType where Type=?), threshold=?, 
601
                        minMatchPoint=?, isDetectOrigin=?, rotationCount=?, ocrOption=?, isContainChild=?, 
602
                        originalPoint=?, connectionPoint=?, baseSymbol=?, additionalSymbol=?, isExceptDetect=?, 
603
                        hasInstrumentLabel=?, width=?, height=?, flip=?, TextArea=?, type=? WHERE uid = ?
604
                """)
605

    
606
                cursor = conn.cursor()
607
                query = (symbol.getName(), symbol.getType(), symbol.getThreshold()
608
                         , symbol.getMinMatchCount(), symbol.getIsDetectOnOrigin(), symbol.getRotationCount()
609
                         , symbol.getOcrOption(), symbol.getIsContainChild()
610
                         , symbol.getOriginalConvertingPoint(), symbol.getConnectionPoint()
611
                         , symbol.getBaseSymbol(), symbol.getAdditionalSymbol(), symbol.getIsExceptDetect(),
612
                         symbol.getHasInstrumentLabel(), symbol.width, symbol.height, symbol.detectFlip, symbol.text_area_str, symbol.getDescAndInfo(), 
613
                         symbol.getUid())
614
                cursor.execute(sql, query)
615
                conn.commit()
616
                isUpdated = True
617
            # Catch the exception
618
            except Exception as ex:
619
                # Roll back any change if something goes wrong
620
                conn.rollback()
621

    
622
                from App import App
623
                message = 'error occurred({}) in {}:{}'.format(ex, sys.exc_info()[-1].tb_frame.f_code.co_filename,
624
                                                              sys.exc_info()[-1].tb_lineno)
625
                App.mainWnd().addMessage.emit(MessageType.Error, message)
626
            finally:
627
                self._symbolBase = {}
628
                return (isUpdated, symbol.getType(), symbol.getName(), symbol.getPath())
629

    
630
    def getSymbolPreset(self):
631
        """ get symbol preset """
632
        presets = []
633
        with self.project.database.connect() as conn:
634
            try:
635
                cursor = conn.cursor()
636
                sql = 'SELECT [UID], [Find], [Target], [Action], [Condition] FROM SymbolPreset'
637
                cursor.execute(sql)
638
                rows = cursor.fetchall()
639
                for row in rows:
640
                    presets.append([row['Find'], row['Target'], row['Action'], row['Condition']])
641
            # Catch the exception
642
            except Exception as ex:
643
                from App import App
644
                message = 'error occurred({}) in {}:{}'.format(ex, sys.exc_info()[-1].tb_frame.f_code.co_filename,
645
                                                                sys.exc_info()[-1].tb_lineno)
646
                App.mainWnd().addMessage.emit(MessageType.Error, message)
647

    
648
                return []
649

    
650
        return presets
651

    
652
    def saveSymbolPreset(self, presets):
653
        """ save symbol preset """
654
        import uuid
655

    
656
        conn = self.project.database.connect()
657
        with conn:
658
            try:
659
                # Get a cursor object
660
                cursor = conn.cursor()
661

    
662
                sql = "delete from SymbolPreset"
663
                cursor.execute(sql)
664

    
665
                for preset in presets:
666
                    sql = self.project.database.to_sql("insert into [SymbolPreset]([UID], [Find], [Target], [Action], [Condition]) values(?,?,?,?,?)")
667
                    param = (str(uuid.uuid4()), preset[0], preset[1], preset[2], preset[3])
668
                    cursor.execute(sql, param)
669
                conn.commit()
670

    
671
            except Exception as ex:
672
                # Roll back any change if something goes wrong
673
                conn.rollback()
674
                from App import App
675
                from AppDocData import MessageType
676
                message = 'error occurred({}) in {}:{}'.format(repr(ex), sys.exc_info()[-1].tb_frame.f_code.co_filename,
677
                                                                sys.exc_info()[-1].tb_lineno)
678
                App.mainWnd().addMessage.emit(MessageType.Error, message)
679
        
680

    
681
    def getTargetSymbolList(self, all=False):
682
        """get symbol list to be detected except isExceptDetect field is unset"""
683
        targetSymbolList = []
684

    
685
        with self.project.database.connect() as conn:
686
            cursor = conn.cursor()
687
            if not all:
688
                sql = """SELECT a.UID,a.Name,b.Type,a.Threshold,a.MinMatchPoint,a.IsDetectOrigin,a.RotationCount,
689
                a.OCROption,a.IsContainChild,a.OriginalPoint,a.ConnectionPoint,a.BaseSymbol,a.AdditionalSymbol,a.Width,a.Height,
690
                a.IsExceptDetect,a.HasInstrumentLabel,a.flip,a.TextArea,b.UID as DB_UID,a.Type as [Desc] FROM Symbol a inner join SymbolType b on 
691
                a.SymbolType_UID=b.UID WHERE a.IsExceptDetect = 0 and a.[SymbolType_UID] != -1 order by width * height desc"""
692
            else:
693
                sql = """SELECT a.UID,a.Name,b.Type,a.Threshold,a.MinMatchPoint,a.IsDetectOrigin,a.RotationCount,
694
                a.OCROption,a.IsContainChild,a.OriginalPoint,a.ConnectionPoint,a.BaseSymbol,a.AdditionalSymbol,a.Width,a.Height,
695
                a.IsExceptDetect,a.HasInstrumentLabel,a.flip,a.TextArea,b.UID as DB_UID,a.Type as [Desc] FROM Symbol a inner join SymbolType b on 
696
                a.SymbolType_UID=b.UID WHERE a.[SymbolType_UID] != -1 order by width * height desc"""
697
            try:
698
                cursor.execute(sql)
699
                rows = cursor.fetchall()
700
                for row in rows:
701
                    sym = symbol.SymbolBase(row['Name'], row['Type'], row['Threshold'],
702
                                                row['MinMatchPoint'], row['IsDetectOrigin'],
703
                                                row['RotationCount'], row['OCROption'],
704
                                                row['IsContainChild'], row['OriginalPoint'],
705
                                                row['ConnectionPoint'], row['BaseSymbol'],
706
                                                row['AdditionalSymbol'], row['IsExceptDetect'],
707
                                                row['HasInstrumentLabel'], row['UID'],
708
                                                iType=row['DB_UID'], width=row['Width'], height=row['Height'],
709
                                                detectFlip=row['flip'], text_area=row['TextArea'], desc=row['Desc'])
710
                    targetSymbolList.append(sym)
711
            except Exception as ex:
712
                print('error occurred({}) in {}:{}'.format(ex, sys.exc_info()[-1].tb_frame.f_code.co_filename,
713
                                                          sys.exc_info()[-1].tb_lineno))
714

    
715
        return targetSymbolList
716

    
717
    def get_favorite_libraries(self):
718
        res = []
719

    
720
        with self.project.database.connect() as conn:
721
            cursor = conn.cursor()
722
            sql = f"select UID,Symbol_UID from Libraries where [User]='{os.environ['COMPUTERNAME'].upper()}'"
723
            try:
724
                cursor.execute(sql)
725
                return cursor.fetchall()
726
            except Exception as ex:
727
                print('error occurred({}) in {}:{}'.format(ex, sys.exc_info()[-1].tb_frame.f_code.co_filename,
728
                                                          sys.exc_info()[-1].tb_lineno))
729

    
730
        return None
731

    
732
    def buildAppDatabase(self):
733
        """build application database"""
734
        path = os.path.join(os.getenv('USERPROFILE'), 'Digital PID')
735
        appDatabaseFilePath = os.path.join(path, 'App.db')
736

    
737
        # Creates or opens a file called mydb with a SQLite3 DB
738
        with sqlite3.connect(appDatabaseFilePath) as conn:
739
            try:
740
                # Get a cursor object
741
                cursor = conn.cursor()
742

    
743
                sqlFiles = ['App.Configuration.sql', 'App.Styles.sql']
744
                for sqlFile in sqlFiles:
745
                    filePath = os.path.join(os.path.dirname(os.path.realpath(__file__)), 'Scripts', sqlFile)
746
                    try:
747
                        file = QFile(filePath)
748
                        file.open(QFile.ReadOnly)
749
                        sql = file.readAll()
750
                        sql = str(sql, encoding='utf8')
751
                        cursor.executescript(sql)
752
                    finally:
753
                        file.close()
754
                conn.commit()
755
            # Catch the exception
756
            except Exception as ex:
757
                # Roll back any change if something goes wrong
758
                conn.rollback()
759
                print('error occurred({}) in {}:{}'.format(ex, sys.exc_info()[-1].tb_frame.f_code.co_filename,
760
                                                          sys.exc_info()[-1].tb_lineno))
761

    
762
        # expiration date is 2019-11-9-23-59-59 : e52SoJJRdZ-apJuhlFWtnFWC
763
        # configs = [Config('app', 'error origin point', '51,72'), Config('app', 'expiration', 'e52SoJJRdZ-apJuhlFWtnFWC')]
764

    
765
        configs = self.getAppConfigs('app', 'license')
766
        if configs and len(configs[0].value.split('.')) == 3:
767
            pass
768
        else:
769
            configs = self.getAppConfigs('app', 'expiration')
770
            if not configs:
771
                configs = self.getAppConfigs('app', 'license')
772
                if configs and 'DOFTECH' in configs[0].value:
773
                    self.deleteAppConfigs('app', 'mode')
774
                    configs = None
775
                else:
776
                    configs = [Config('app', 'mode', 'advanced')]
777
            else:
778
                configs = None
779

    
780
            if configs:
781
                self.saveAppConfigs(configs)
782

    
783
    '''
784
        @brief  load app style
785
        @author humkyung
786
        @date   2018.04.20
787
    '''
788
    def loadAppStyle(self):
789
        style = 'Fusion'
790

    
791
        path = os.path.join(os.getenv('USERPROFILE'), 'Digital PID')
792
        if not os.path.exists(path): os.makedirs(path)
793

    
794
        self.buildAppDatabase()
795
        try:
796
            appDatabaseFilePath = os.path.join(path, 'App.db')
797
            # Creates or opens a file called mydb with a SQLite3 DB
798
            conn = sqlite3.connect(appDatabaseFilePath)
799
            # Get a cursor object
800
            cursor = conn.cursor()
801

    
802
            sql = "select Value from Configuration where Section='App' and Key='Style'"
803
            cursor.execute(sql)
804
            rows = cursor.fetchall()
805
            style = rows[0][0] if 1 == len(rows) else 'Fusion'
806
        # Catch the exception
807
        except Exception as ex:
808
            # Roll back any change if something goes wrong
809
            conn.rollback()
810
            print('error occurred({}) in {}:{}'.format(ex, sys.exc_info()[-1].tb_frame.f_code.co_filename,
811
                                                      sys.exc_info()[-1].tb_lineno))
812
        finally:
813
            # Close the db connection
814
            conn.close()
815

    
816
        return style
817

    
818
    '''
819
        @brief  load app styles and then return a list
820
        @author humkyung
821
        @date   2018.04.20
822
    '''
823
    def loadAppStyles(self):
824
        styles = []
825

    
826
        try:
827
            self.buildAppDatabase()
828

    
829
            path = os.path.join(os.getenv('USERPROFILE'), 'Digital PID')
830
            appDatabaseFilePath = os.path.join(path, 'App.db')
831

    
832
            # Creates or opens a file called mydb with a SQLite3 DB
833
            conn = sqlite3.connect(appDatabaseFilePath)
834
            # Get a cursor object
835
            cursor = conn.cursor()
836

    
837
            sql = 'select UID,Value from Styles'
838
            cursor.execute(sql)
839
            rows = cursor.fetchall()
840
            for row in rows: styles.append(row[1])
841
            if 0 == len(rows): rows.append('fusion')
842
        # Catch the exception
843
        except Exception as ex:
844
            # Roll back any change if something goes wrong
845
            conn.rollback()
846
            print('error occurred({}) in {}:{}'.format(ex, sys.exc_info()[-1].tb_frame.f_code.co_filename,
847
                                                      sys.exc_info()[-1].tb_lineno))
848
        finally:
849
            # Close the db connection
850
            conn.close()
851

    
852
        return styles
853

    
854
    '''
855
        @brief  Set current Project
856
        @history    2018.06.27  Jeongwoo    If DB file is not, copy DB file from ProgramData
857
    '''
858
    def setCurrentProject(self, project):
859
        self.project = project
860
        project.make_sub_directories()
861
        try:
862
            # save size unit
863
            #self.saveConfigs([Config('Project', 'Unit', project.prj_unit)])
864

    
865
            if self.project.database.db_type == 'SQLite':
866
                # Creates or opens a file called mydb with a SQLite3 DB
867
                db_path = self.project.database.file_path
868

    
869
                if not os.path.isfile(db_path):
870
                    templatePath = self.getTemplateDbPath()
871
                    templateFile = QFile(templatePath)
872
                    templateFile.copy(db_path)
873

    
874
                try:
875
                    conn = self.project.database.connect()
876
                    with conn:
877
                        # Get a cursor object
878
                        cursor = conn.cursor()
879

    
880
                        fileNames = os.listdir(os.path.join(os.path.dirname(os.path.realpath(__file__)), 'Scripts'))
881
                        for fileName in fileNames:
882
                            if fileName.endswith(".sql") and ('SQLite_Project' == os.path.splitext(fileName)[0].split('.')[0]):
883
                                try:
884
                                    file = QFile(
885
                                        os.path.join(os.path.dirname(os.path.realpath(__file__)), 'Scripts', fileName))
886
                                    file.open(QFile.ReadOnly)
887
                                    sql = file.readAll()
888
                                    sql = str(sql, encoding='utf8')
889
                                    cursor.executescript(sql)
890
                                finally:
891
                                    file.close()
892
                        conn.commit()
893
                except Exception as ex:
894
                    print('error occurred({}) in {}:{}'.format(ex, sys.exc_info()[-1].tb_frame.f_code.co_filename,
895
                                                              sys.exc_info()[-1].tb_lineno))
896
        # Catch the exception
897
        except Exception as ex:
898
            # Roll back any change if something goes wrong
899
            print('error occurred({}) in {}:{}'.format(ex, sys.exc_info()[-1].tb_frame.f_code.co_filename,
900
                                                      sys.exc_info()[-1].tb_lineno))
901
        finally:
902
            pass
903

    
904
    '''
905
        @brief  Get current Project
906
    '''
907
    def getCurrentProject(self):
908
        return self.project
909

    
910
    '''
911
        @brief      return project database path
912
        @history    humkyung 2018.04.19 return Project.db in Program Data folder instead of PROJECT_DB_PATH variable
913
    '''
914
    def getPrjDatabasePath(self):
915
        path = os.path.join(os.getenv('USERPROFILE'), 'Digital PID')
916
        if not os.path.exists(path): os.makedirs(path)
917

    
918
        prjDatabaseFilePath = os.path.join(path, 'Project.db')
919
        try:
920
            # Creates or opens a file called mydb with a SQLite3 DB
921
            conn = sqlite3.connect(prjDatabaseFilePath)
922
            # Get a cursor object
923
            cursor = conn.cursor()
924

    
925
            filePath = os.path.join(os.path.dirname(os.path.realpath(__file__)), 'Scripts', 'Project.Projects.sql')
926
            try:
927
                file = QFile(filePath)
928
                file.open(QFile.ReadOnly)
929
                sql = file.readAll()
930
                sql = str(sql, encoding='utf8')
931
                cursor.executescript(sql)
932
            finally:
933
                file.close()
934
            conn.commit()
935
        # Catch the exception
936
        except Exception as ex:
937
            # Roll back any change if something goes wrong
938
            conn.rollback()
939
            print('error occurred({}) in {}:{}'.format(ex, sys.exc_info()[-1].tb_frame.f_code.co_filename,
940
                                                      sys.exc_info()[-1].tb_lineno))
941
        finally:
942
            # Close the db connection
943
            conn.close()
944

    
945
        return prjDatabaseFilePath
946

    
947
    def getErrorItemSvgPath(self):
948
        '''
949
            @brief  return error item svg path
950
            @author euisung
951
            @date   2019.04.02
952
        '''
953
        return os.path.join(os.getenv('USERPROFILE'), 'Digital PID', 'Explode.svg')
954

    
955
    def updateTitleBlockProperties(self, titleBlockProps):
956
        '''
957
            @brief  update title block properties
958
            @author euisung
959
            @date   2018.11.09
960
        '''
961
        try:
962
            originTitleBlockProps = self.getTitleBlockProperties()
963
            deletedTitleBlockProps = []
964
            for originTitleBlockProp in originTitleBlockProps:
965
                for titleBlockProp in titleBlockProps:
966
                    # uid compare for determine delete props
967
                    if originTitleBlockProp[0] == titleBlockProp[0]:
968
                        break
969
                deletedTitleBlockProps.append(originTitleBlockProp[0])
970

    
971
            # Creates or opens a file called mydb with a SQLite3 DB
972
            conn = self.project.database.connect()
973
            with conn:
974
                try:
975
                    # Get a cursor object
976
                    cursor = conn.cursor()
977

    
978
                    for deletedTitleBlockProp in deletedTitleBlockProps:
979
                        sql = "delete from TitleBlockValues where TitleBlockProperties_UID='{}'".format(deletedTitleBlockProp)
980
                        cursor.execute(sql)
981
                        sql = "delete from TitleBlockProperties where UID='{}'".format(deletedTitleBlockProp)
982
                        cursor.execute(sql)
983

    
984
                    for titleBlockProp in titleBlockProps:
985
                        sql = self.project.database.to_sql("insert into [TitleBlockProperties]([UID], [NAME], [AREA], [TEXT]) values(?,?,?,?)")
986
                        param = (titleBlockProp[0], titleBlockProp[1], titleBlockProp[2], titleBlockProp[3])  # uid, name, area, text
987
                        cursor.execute(sql, param)
988
                    conn.commit()
989
                    # Catch the exception
990
                except Exception as ex:
991
                    # Roll back any change if something goes wrong
992
                    conn.rollback()
993
                    from App import App
994
                    from AppDocData import MessageType
995
                    message = 'error occurred({}) in {}:{}'.format(repr(ex), sys.exc_info()[-1].tb_frame.f_code.co_filename,
996
                                                                   sys.exc_info()[-1].tb_lineno)
997
                    App.mainWnd().addMessage.emit(MessageType.Error, message)
998
        # Catch the exception
999
        except Exception as ex:
1000
            from App import App
1001
            from AppDocData import MessageType
1002
            message = 'error occurred({}) in {}:{}'.format(repr(ex), sys.exc_info()[-1].tb_frame.f_code.co_filename,
1003
                                                           sys.exc_info()[-1].tb_lineno)
1004
            App.mainWnd().addMessage.emit(MessageType.Error, message)
1005

    
1006
        self._titleBlockProperties = None
1007

    
1008
    def getTitleBlockProperties(self):
1009
        """"return title block properties"""
1010

    
1011
        res = None
1012
        if self._titleBlockProperties is None:
1013
            self._titleBlockProperties = []
1014

    
1015
            with self.project.database.connect() as conn:
1016
                try:
1017
                    # Get a cursor object
1018
                    cursor = conn.cursor()
1019

    
1020
                    sql = "select UID, Name, AREA, [TEXT] from TitleBlockProperties ASC"
1021
                    cursor.execute(sql)
1022
                    rows = cursor.fetchall()
1023
                    for row in rows:
1024
                        attr = []
1025
                        attr.append(row['UID'])  # uid
1026
                        attr.append(row['Name'])  # name
1027
                        attr.append(row['AREA'])  # area
1028
                        attr.append(row['TEXT'])  # text
1029
                        self._titleBlockProperties.append(attr)
1030

    
1031
                    res = self._titleBlockProperties
1032
                # Catch the exception
1033
                except Exception as ex:
1034
                    print('error occurred({}) in {}:{}'.format(ex, sys.exc_info()[-1].tb_frame.f_code.co_filename,
1035
                                                              sys.exc_info()[-1].tb_lineno))
1036
        else:
1037
            res = self._titleBlockProperties
1038

    
1039
        return res
1040

    
1041
    def clearLineNoProperties(self):
1042
        self._lineNoProperties = None
1043
        self._lineNoPropertiesUID = {}
1044

    
1045
    def getLineProperties(self):
1046
        """return line no properties"""
1047
        from SymbolAttr import SymbolAttr
1048

    
1049
        res = None
1050
        if self._lineNoProperties is None:
1051
            self._lineNoProperties = []
1052

    
1053
            with self.project.database.connect() as conn:
1054
                try:
1055
                    # Get a cursor object
1056
                    cursor = conn.cursor()
1057

    
1058
                    sql = "select UID, Name, DisplayName, Type, LimitNumber, [index] from LineProperties " \
1059
                          "order by [index]"
1060
                    cursor.execute(sql)
1061
                    rows = cursor.fetchall()
1062
                    for row in rows:
1063
                        attr = SymbolAttr()
1064
                        attr.UID = row['UID']
1065
                        attr.Attribute = row['Name']
1066
                        attr.DisplayAttribute = row['DisplayName']
1067
                        attr.AttributeType = row['Type']
1068
                        attr.Length = row['LimitNumber']
1069
                        attr.IsProp = 5
1070
                        attr.Index = -1
1071
                        self._lineNoProperties.append(attr)
1072

    
1073
                    res = self._lineNoProperties
1074

    
1075
                    # update cache
1076
                    if res:
1077
                        for _prop in res:
1078
                            if str(_prop.UID) not in self._lineNoPropertiesUID:
1079
                                self._lineNoPropertiesUID[str(_prop.UID)] = [_prop]
1080
                # Catch the exception
1081
                except Exception as ex:
1082
                    print('error occurred({}) in {}:{}'.format(ex, sys.exc_info()[-1].tb_frame.f_code.co_filename,
1083
                                                              sys.exc_info()[-1].tb_lineno))
1084
        else:
1085
            res = self._lineNoProperties
1086

    
1087
        return res
1088

    
1089
    def get_equipment_attributes(self):
1090
        """ return equipment attributes """
1091

    
1092
        from SymbolAttr import SymbolAttr
1093

    
1094
        res = None
1095
        if not hasattr(self, '_equipment_attributes'):
1096
            self._equipment_attributes = []
1097

    
1098
            with self.project.database.connect() as conn:
1099
                try:
1100
                    # Get a cursor object
1101
                    cursor = conn.cursor()
1102

    
1103
                    sql = "select distinct A.Attribute from SymbolAttribute A join SymbolType B on " \
1104
                          "A.SymbolType_UID=B.UID where B.Category in ('Equipment', 'Package')"#,'Equipment Components')"
1105
                    cursor.execute(sql)
1106
                    rows = cursor.fetchall()
1107
                    for row in rows:
1108
                        attr = SymbolAttr()
1109
                        attr.Attribute = row['Attribute']
1110
                        self._equipment_attributes.append(attr)
1111

    
1112
                    res = self._equipment_attributes
1113
                # Catch the exception
1114
                except Exception as ex:
1115
                    print('error occurred({}) in {}:{}'.format(repr(ex), sys.exc_info()[-1].tb_frame.f_code.co_filename,
1116
                                                               sys.exc_info()[-1].tb_lineno))
1117
        else:
1118
            res = self._equipment_attributes
1119

    
1120
        return res
1121

    
1122
    '''
1123
        @brief  return line properties
1124
        @author humkyung
1125
        @date   2018.04.09
1126
    '''
1127
    def getLinePropertiesByUID(self, UID):
1128
        from SymbolAttr import SymbolAttr
1129

    
1130
        res = []
1131
        if UID in self._lineNoPropertiesUID:
1132
            res = self._lineNoPropertiesUID[UID]
1133
            return res
1134

    
1135
        with self.project.database.connect() as conn:
1136
            try:
1137
                # Get a cursor object
1138
                cursor = conn.cursor()
1139

    
1140
                sql = f"select UID, Name, DisplayName, Type, LimitNumber, [index] from LineProperties where " \
1141
                      f"uid = '{UID}'"
1142
                cursor.execute(sql)
1143
                rows = cursor.fetchall()
1144
                for row in rows:
1145
                    attr = SymbolAttr()
1146
                    attr.UID = row['UID']
1147
                    attr.Attribute = row['Name']
1148
                    attr.DisplayAttribute = row['DisplayName']
1149
                    attr.AttributeType = row['Type']
1150
                    attr.Length = row['LimitNumber']
1151
                    attr.IsProp = 5
1152
                    attr.Index = -1
1153
                    res.append(attr)
1154
                self._lineNoPropertiesUID[UID] = res
1155
            # Catch the exception
1156
            except Exception as ex:
1157
                print('error occurred({}) in {}:{}'.format(ex, sys.exc_info()[-1].tb_frame.f_code.co_filename,
1158
                                                          sys.exc_info()[-1].tb_lineno))
1159

    
1160
        return res
1161

    
1162
    '''
1163
        @brief  return line types 
1164
        @author humkyung
1165
        @date   2018.06.27
1166
    '''
1167
    def getLineTypes(self):
1168
        from LineTypeConditions import LineTypeConditions
1169

    
1170
        res = []
1171
        conn = self.project.database.connect()
1172
        with conn:
1173
            try:
1174
                cursor = conn.cursor()
1175
                sql = "select UID,Name,Type1,Conditions1,Type2,Conditions2 from LineTypes order by Name"
1176
                cursor.execute(sql)
1177
                rows = cursor.fetchall()
1178
                for row in rows:
1179
                    line_type = LineTypeConditions(row['UID'], row['Name'])
1180
                    line_type._conditions[0][0] = row['Type1']
1181
                    line_type._conditions[0][1] = row['Conditions1']
1182
                    line_type._conditions[1][0] = row['Type2']
1183
                    line_type._conditions[1][1] = row['Conditions2']
1184
                    res.append(line_type)
1185
            # Catch the exception
1186
            except Exception as ex:
1187
                print('error occurred({}) in {}:{}'.format(ex, sys.exc_info()[-1].tb_frame.f_code.co_filename,
1188
                                                          sys.exc_info()[-1].tb_lineno))
1189

    
1190
        return res
1191

    
1192
    '''
1193
        @brief      Insert New Project Info
1194
        @author     Jeongwoo
1195
        @date       2018.04.06
1196
        @history    humkyung 2018.04.19 use getPrjDatabasePath function instead of PROJECT_DB_PATH variable
1197
    '''
1198
    def insertProjectInfo(self, desc, prj_unit, dir):
1199
        prjDatabaseFilePath = self.getPrjDatabasePath()
1200
        conn = sqlite3.connect(prjDatabaseFilePath)
1201
        with conn:
1202
            try:
1203
                folderName = dir.split('/')[-1]
1204
                if folderName:
1205
                    nowDate = datetime.now().strftime('%Y.%m.%d %H:%M')
1206
                    sql = "insert or replace into Projects(Name, [Desc], [Unit], Path, CreatedDate, UpdatedDate) values(?, ?, ?, ?, ?, ?)"
1207
                    param = (folderName, desc, prj_unit, dir, nowDate, nowDate)
1208

    
1209
                    cursor = conn.cursor()
1210
                    cursor.execute(sql, param)
1211
                    conn.commit()
1212
                else:
1213
                    print("Empty folder name")
1214
            except Exception as ex:
1215
                # Roll back any change if something goes wrong
1216
                conn.rollback()
1217
                print('error occurred({}) in {}:{}'.format(ex, sys.exc_info()[-1].tb_frame.f_code.co_filename,
1218
                                                          sys.exc_info()[-1].tb_lineno))
1219

    
1220
    def removeProjectInfo(self, targetProject):
1221
        '''
1222
        @brief      Remove Project Info
1223
        @author     Euisung
1224
        @date       2019.01.28
1225
        '''
1226
        prjDatabaseFilePath = self.getPrjDatabasePath()
1227
        conn = sqlite3.connect(prjDatabaseFilePath)
1228
        with conn:
1229
            try:
1230
                sql = "delete from Projects where Id = '{}'".format(targetProject.id)
1231
                cur = conn.cursor()
1232
                cur.execute(sql)
1233
                conn.commit()
1234
            except Exception as ex:
1235
                # Roll back any change if something goes wrong
1236
                conn.rollback()
1237
                print('error occurred({}) in {}:{}'.format(ex, sys.exc_info()[-1].tb_frame.f_code.co_filename,
1238
                                                          sys.exc_info()[-1].tb_lineno))
1239

    
1240
    '''
1241
        @brief      update project
1242
        @author     Jeongwoo
1243
        @date       2018.04.06
1244
        @history    humkyung 2018.04.19 use getPrjDatabasePath function instead of PROJECT_DB_PATH variable
1245
    '''
1246
    def updateProjectUpdatedDate(self, project):
1247
        prjDatabaseFilePath = self.getPrjDatabasePath()
1248
        conn = sqlite3.connect(prjDatabaseFilePath)
1249
        with conn:
1250
            try:
1251
                nowDate = datetime.now().strftime('%Y.%m.%d %H:%M')
1252
                sql = '''
1253
                    UPDATE Projects
1254
                    SET UpdatedDate = ?,[Desc]=?,[Unit]=? 
1255
                    WHERE Id = ?
1256
                '''
1257
                cur = conn.cursor()
1258
                cur.execute(sql, (nowDate, project.desc, project.prj_unit, project.getId()))
1259

    
1260
                if project.database.host and project.database.port:
1261
                    _host = project.database.host + ':' + project.database.port
1262
                else:
1263
                    _host = None
1264
                sql = 'insert or replace into DBSettings(Projects_UID, DBTypes_UID, Host, User, Password, FilePath) values(?,(select UID from DBTypes where Name=?),?,?,?,?)'
1265
                cur = conn.cursor()
1266
                cur.execute(sql, (
1267
                    project.getId(), project.database.db_type, _host, project.database.user,
1268
                    project.database.password, project.database.file_path))
1269
                conn.commit()
1270
            except Exception as ex:
1271
                # Roll back any change if something goes wrong
1272
                conn.rollback()
1273
                print('error occurred({}) in {}:{}'.format(ex, sys.exc_info()[-1].tb_frame.f_code.co_filename,
1274
                                                          sys.exc_info()[-1].tb_lineno))
1275

    
1276
    '''
1277
        @brief  get project list from database
1278
        @history    humkyung 2018.04.18 add only project which's project exists
1279
    '''
1280
    def getProjectList(self):
1281
        from Project import Project
1282

    
1283
        projectList = []
1284

    
1285
        conn = sqlite3.connect(self.getPrjDatabasePath())
1286
        with conn:
1287
            conn.row_factory = sqlite3.Row
1288
            cursor = conn.cursor()
1289
            sql = "select a.Id,a.Name,a.[Desc],a.[Unit],a.Path,a.CreatedDate,a.UpdatedDate,\
1290
                (select \
1291
                CASE \
1292
                WHEN b.DBTypes_UID is NULL THEN 'SQLite' \
1293
                ELSE (select Name from DBTypes where UID=b.DBTypes_UID) \
1294
                END \
1295
                ) DBType,b.Host,b.User,b.Password \
1296
                from projects a left join dbsettings b on a.Id=b.Projects_UID order by strftime(a.UpdatedDate) desc"
1297
            try:
1298
                cursor.execute(sql)
1299
                rows = cursor.fetchall()
1300
                for row in rows:
1301
                    if os.path.isdir(row['Path']):  # check if folder exists
1302
                        projectList.append(Project(row))
1303
            except Exception as ex:
1304
                print('error occurred({}) in {}:{}'.format(ex, sys.exc_info()[-1].tb_frame.f_code.co_filename,
1305
                                                          sys.exc_info()[-1].tb_lineno))
1306

    
1307
        return projectList
1308

    
1309
    '''
1310
        @brief  get sliding window size
1311
        @author humkyung
1312
    '''
1313
    def getSlidingWindowSize(self):
1314
        res = [25, 20]
1315
        try:
1316
            configs = self.getConfigs('Sliding Window')
1317
            for config in configs:
1318
                if config.key == 'Width':
1319
                    res[0] = int(config.value)
1320
                elif config.key == 'Height':
1321
                    res[1] = int(config.value)
1322
        # Catch the exception
1323
        except Exception as ex:
1324
            print('error occurred({}) in {}:{}'.format(ex, sys.exc_info()[-1].tb_frame.f_code.co_filename,
1325
                                                      sys.exc_info()[-1].tb_lineno))
1326

    
1327
        return res
1328

    
1329
    '''
1330
        @brief  get line no configuration
1331
        @author humkyung
1332
        @date   2018.04.16
1333
    '''
1334
    def getLineNoConfiguration(self):
1335
        res = None
1336

    
1337
        conn = self.project.database.connect()
1338
        with conn:
1339
            try:
1340
                # Get a cursor object
1341
                cursor = conn.cursor()
1342

    
1343
                delimiter = None
1344
                sql = "select * from configuration where section='Line No' and key='Delimiter"
1345
                cursor.execute(sql)
1346
                rows = cursor.fetchall()
1347
                if len(rows) == 1:
1348
                    delimiter = rows[0][2]
1349

    
1350
                if delimiter is not None:
1351
                    sql = "select * from configuration where section='Line No' and key='Configuration'"
1352
                    cursor.execute(sql)
1353
                    rows = cursor.fetchall()
1354
                    if len(rows) == 1:
1355
                        res = rows[0][2].split(delimiter)
1356
            # Catch the exception
1357
            except Exception as ex:
1358
                print('error occurred({}) in {}:{}'.format(ex, sys.exc_info()[-1].tb_frame.f_code.co_filename,
1359
                                                          sys.exc_info()[-1].tb_lineno))
1360

    
1361
        return res
1362

    
1363
    '''
1364
        @brief  get area list
1365
        @author humkyung
1366
        @history    euisung     2018.11.20 (0,0),(0,0) process add
1367
    '''
1368
    def getAreaList(self, size=False):
1369
        from Area import Area
1370

    
1371
        if len(self._areas) == 0:
1372
            conn = self.project.database.connect()
1373
            with conn:
1374
                try:
1375
                    # Get a cursor object
1376
                    cursor = conn.cursor()
1377

    
1378
                    sql = "select * from configuration where section='Area'"
1379
                    cursor.execute(sql)
1380
                    rows = cursor.fetchall()
1381
                    for row in rows:
1382
                        name = row['Key']
1383
                        area = Area(name)
1384
                        area.parse(row['Value'])
1385
                        self._areas.append(area)
1386
                # Catch the exception
1387
                except Exception as ex:
1388
                    print('error occurred({}) in {}:{}'.format(ex, sys.exc_info()[-1].tb_frame.f_code.co_filename,
1389
                                                              sys.exc_info()[-1].tb_lineno))
1390

    
1391
        return self._areas if size else [area for area in self._areas if area.name != 'Size']
1392

    
1393
    '''
1394
        @brief  get area of given name
1395
        @author humkyung
1396
        @date   2018.04.07
1397
    '''
1398
    def getArea(self, name):
1399
        areas = self.getAreaList(size=True)
1400
        matches = [area for area in areas if area.name == name]
1401
        if 1 == len(matches) and matches[0].height is not 0 and matches[0].width is not 0:
1402
            return matches[0]
1403

    
1404
        return None
1405

    
1406
    def getConfigs(self, section, key=None):
1407
        """ get configurations from database """
1408
        res = []
1409

    
1410
        if self._configs is None:
1411
            self._configs = []
1412
            with self.project.database.connect() as conn:
1413
                try:
1414
                    # Get a cursor object
1415
                    cursor = conn.cursor()
1416

    
1417
                    sql = "select * from configuration"
1418

    
1419
                    cursor.execute(sql)
1420
                    rows = cursor.fetchall()
1421
                    for row in rows:
1422
                        self._configs.append(Config(row['Section'], row['Key'], row['Value']))
1423
                # Catch the exception
1424
                except Exception as ex:
1425
                    print('error occurred({}) in {}:{}'.format(ex, sys.exc_info()[-1].tb_frame.f_code.co_filename,
1426
                                                              sys.exc_info()[-1].tb_lineno))
1427

    
1428
        if key is not None:
1429
            return [con for con in self._configs if con.section == section and con.key == key]
1430
        else:
1431
            return [con for con in self._configs if con.section == section]
1432

    
1433
    def getAppConfigs(self, section, key=None):
1434
        """get application configurations"""
1435

    
1436
        res = []
1437

    
1438
        # Creates or opens a file called mydb with a SQLite3 DB
1439
        dbPath = self.getAppDbPath()
1440
        with sqlite3.connect(dbPath) as conn:
1441
            try:
1442
                # Get a cursor object
1443
                cursor = conn.cursor()
1444

    
1445
                if key is not None:
1446
                    sql = "select * from configuration where section=? and key=?"
1447
                    param = (section, key)
1448
                else:
1449
                    sql = "select * from configuration where section=?"
1450
                    param = (section,)
1451

    
1452
                cursor.execute(sql, param)
1453
                rows = cursor.fetchall()
1454
                for row in rows:
1455
                    res.append(Config(row[0], row[1], row[2]))
1456
            # Catch the exception
1457
            except Exception as ex:
1458
                print('error occurred({}) in {}:{}'.format(ex, sys.exc_info()[-1].tb_frame.f_code.co_filename,
1459
                                                          sys.exc_info()[-1].tb_lineno))
1460

    
1461
        return res
1462

    
1463
    '''
1464
        @brief      save configurations
1465
        @author     humkyung
1466
        @date       2018.04.16
1467
        @history    humkyung 2018.07.03 replace ' with " if value has '
1468
                    kyouho 2018.07.09 change query method
1469
    '''
1470
    def saveConfigs(self, configs):
1471
        from LineTypeConditions import LineTypeConditions
1472

    
1473
        with self.project.database.connect() as conn:
1474
            try:
1475
                # Get a cursor object
1476
                cursor = conn.cursor()
1477
                if self.project.database.db_type == 'SQLite':
1478
                    cursor.execute('begin')
1479

    
1480
                for config in configs:
1481
                    if type(config) is Config:
1482
                        value = config.value
1483
                        #if type(value) is str and "'" in value:
1484
                        #    value = value.replace("'", "''")
1485

    
1486
                        sql = self.project.database.to_sql(
1487
                            "insert into configuration(Section,[Key],Value) select ?,?,? where not exists(select 1 from configuration where Section=? and [Key]=?)")
1488
                        param = (config.section, config.key, str(value), config.section, config.key)
1489
                        cursor.execute(sql, param)
1490
                        sql = self.project.database.to_sql(
1491
                            "update configuration set Value=? where Section=? and [Key]=?")
1492
                        param = (str(value), config.section, config.key)
1493
                        cursor.execute(sql, param)
1494
                    elif hasattr(config, 'toSql'):
1495
                        sql = config.toSql()
1496
                        if type(sql) is list:
1497
                            for item in sql:
1498
                                if item is not None and 2 == len(item):
1499
                                    cursor.execute(self.project.database.to_sql(item[0]), item[1])
1500
                        else:
1501
                            if sql is not None and 2 == len(sql):
1502
                                cursor.execute(self.project.database.to_sql(sql[0]), sql[1])
1503
                self._configs = None  # reset config table
1504
                LineTypeConditions.CONDITIONS = None
1505

    
1506
                if self.project.database.db_type == 'SQLite':
1507
                    cursor.execute('commit')
1508
                else:
1509
                    conn.commit()
1510
            # Catch the exception
1511
            except Exception as ex:
1512
                # Roll back any change if something goes wrong
1513
                conn.rollback()
1514

    
1515
                from App import App
1516
                message = 'error occurred({}) in {}:{}'.format(ex, sys.exc_info()[-1].tb_frame.f_code.co_filename,
1517
                                                              sys.exc_info()[-1].tb_lineno)
1518
                App.mainWnd().addMessage.emit(MessageType.Error, message)
1519

    
1520
    def saveAppConfigs(self, configs):
1521
        """save application configurations"""
1522

    
1523
        # Creates or opens a file called mydb with a SQLite3 DB
1524
        dbPath = self.getAppDbPath()
1525
        with sqlite3.connect(dbPath) as conn:
1526
            try:
1527
                # Get a cursor object
1528
                cursor = conn.cursor()
1529

    
1530
                for config in configs:
1531
                    value = config.value
1532
                    if type(value) is str and "'" in value:
1533
                        value = value.replace("'", "''")
1534

    
1535
                    sql = "insert or replace into configuration values(?,?,?)"
1536
                    param = (config.section, config.key, value)
1537

    
1538
                    cursor.execute(sql, param)
1539
                conn.commit()
1540
            # Catch the exception
1541
            except Exception as ex:
1542
                # Roll back any change if something goes wrong
1543
                conn.rollback()
1544
                print('error occurred({}) in {}:{}'.format(ex, sys.exc_info()[-1].tb_frame.f_code.co_filename,
1545
                                                          sys.exc_info()[-1].tb_lineno))
1546

    
1547
    def updateProjectUnit(self, unit):
1548
        """save project configurations"""
1549

    
1550
        # Creates or opens a file called mydb with a SQLite3 DB
1551
        dbPath = self.getPrjDatabasePath()
1552
        with sqlite3.connect(dbPath) as conn:
1553
            try:
1554
                # Get a cursor object
1555
                cursor = conn.cursor()
1556

    
1557
                sql = "update Projects set [Unit]=? where [Id]=?"
1558
                param = (unit, self.project.getId())
1559

    
1560
                cursor.execute(sql, param)
1561
                conn.commit()
1562
            # Catch the exception
1563
            except Exception as ex:
1564
                # Roll back any change if something goes wrong
1565
                conn.rollback()
1566
                
1567
                from App import App
1568
                message = 'error occurred({}) in {}:{}'.format(ex, sys.exc_info()[-1].tb_frame.f_code.co_filename,
1569
                                                              sys.exc_info()[-1].tb_lineno)
1570
                App.mainWnd().addMessage.emit(MessageType.Error, message)
1571

    
1572
    def deleteConfigs(self, section, key=None):
1573
        """
1574
        delete configurations by using section and key
1575
        :param section:
1576
        :param key:
1577
        :return: None
1578
        """
1579
        with self.project.database.connect() as conn:
1580
            try:
1581
                # Get a cursor object
1582
                cursor = conn.cursor()
1583

    
1584
                if key is not None:
1585
                    sql = "delete from configuration where section='{}' and [key]='{}'".format(section, key)
1586
                else:
1587
                    sql = "delete from configuration where section='{}'".format(section)
1588
                cursor.execute(sql)
1589

    
1590
                conn.commit()
1591
            # Catch the exception
1592
            except Exception as ex:
1593
                # Roll back any change if something goes wrong
1594
                conn.rollback()
1595

    
1596
                message = f'error occurred({ex}) in {sys.exc_info()[-1].tb_frame.f_code.co_filename}:' \
1597
                          f'{sys.exc_info()[-1].tb_lineno}'
1598
                print(message)
1599

    
1600
    def deleteAppConfigs(self, section, key=None):
1601
        """
1602
        @brief  delete application configurations
1603
        @author humkyung
1604
        @date   2018.11.01
1605
        """
1606

    
1607
        # Creates or opens a file called mydb with a SQLite3 DB
1608
        dbPath = self.getAppDbPath()
1609
        conn = sqlite3.connect(dbPath)
1610
        with conn:
1611
            try:
1612
                # Get a cursor object
1613
                cursor = conn.cursor()
1614

    
1615
                if key is not None:
1616
                    sql = "delete from configuration where section='{}' and key='{}'".format(section, key)
1617
                else:
1618
                    sql = "delete from configuration where section='{}'".format(section)
1619
                cursor.execute(sql)
1620

    
1621
                conn.commit()
1622
            # Catch the exception
1623
            except Exception as ex:
1624
                # Roll back any change if something goes wrong
1625
                conn.rollback()
1626
                print('error occurred({}) in {}:{}'.format(ex, sys.exc_info()[-1].tb_frame.f_code.co_filename,
1627
                                                          sys.exc_info()[-1].tb_lineno))
1628

    
1629
    '''
1630
        @brief      set area list
1631
        @history    humkyung 2018.05.18 round area coordinate and dimension before saving
1632
        @history    euisung  2018.11.20 add self._area reset process
1633
    '''
1634
    def setAreaList(self, areas):
1635
        for area in areas:
1636
            matches = [x for x in self._areas if x.name == area.name]
1637
            if 1 == len(matches):
1638
                matches[0].x = area.x
1639
                matches[0].y = area.y
1640
                matches[0].width = area.width
1641
                matches[0].height = area.height
1642
            elif 0 == len(matches):
1643
                self._areas.append(area)
1644

    
1645
        # Creates or opens a file called mydb with a SQLite3 DB
1646
        conn = self.project.database.connect()
1647
        with conn:
1648
            try:
1649
                # Get a cursor object
1650
                cursor = conn.cursor()
1651

    
1652
                for area in self._areas:
1653
                    sql = "insert into configuration select 'Area','{}','({},{}),({},{})' where not exists(select 1 from configuration where Section='Area' and [Key]='{}')".format(
1654
                        area.name, round(area.x), round(area.y), round(area.width), round(area.height), area.name)
1655
                    cursor.execute(sql)
1656
                    sql = "update configuration set Value='({},{}),({},{})' where Section='Area' and [Key]='{}'".format(
1657
                        round(area.x), round(area.y), round(area.width), round(area.height), area.name)
1658
                    cursor.execute(sql)
1659
                conn.commit()
1660
            # Catch the exception
1661
            except Exception as ex:
1662
                # Roll back any change if something goes wrong
1663
                conn.rollback()
1664

    
1665
                from App import App
1666
                message = 'error occurred({}) in {}:{}'.format(ex, sys.exc_info()[-1].tb_frame.f_code.co_filename,
1667
                                                              sys.exc_info()[-1].tb_lineno)
1668
                App.mainWnd().addMessage.emit(MessageType.Error, message)
1669
            finally:
1670
                # Close the db connection
1671
                self._areas = []
1672

    
1673
    def getSymbolNameList(self):
1674
        """ get symbol name list """
1675
        symbolNametList = []
1676

    
1677
        conn = self.project.database.connect()
1678
        with conn:
1679
            cursor = conn.cursor()
1680
            sql = 'SELECT * FROM SymbolName'
1681
            try:
1682
                cursor.execute(sql)
1683
                rows = cursor.fetchall()
1684
                for row in rows:
1685
                    symbolNametList.append(row['Name'])  # Name String
1686
            except Exception as ex:
1687
                print('error occurred({}) in {}:{}'.format(ex, sys.exc_info()[-1].tb_frame.f_code.co_filename,
1688
                                                          sys.exc_info()[-1].tb_lineno))
1689

    
1690
        return symbolNametList
1691
    
1692
    def getSymbolNameListByUnused(self):
1693
        """ get unused symbol name list """
1694
        symbolNametList = []
1695

    
1696
        conn = self.project.database.connect()
1697
        with conn:
1698
            cursor = conn.cursor()
1699
            #sql = 'select s.[Name] from [Symbol] s where [SymbolType_UID] != -1 and s.[Name] not in (select distinct s.[name] from [Symbol] s inner join [Components] c on c.[Symbol_UID] = s.[UID])'
1700
            sql = 'select s.[UID], s.[Name] from [Symbol] s where [SymbolType_UID] != -1 and s.[UID] not in (select distinct c.[Symbol_UID] from [Components] c)'
1701
            try:
1702
                cursor.execute(sql)
1703
                rows = cursor.fetchall()
1704
                for row in rows:
1705
                    symbolNametList.append([row['UID'], row['Name']])  # Name String
1706
            except Exception as ex:
1707
                # Roll back any change if something goes wrong
1708
                conn.rollback()
1709

    
1710
                from App import App
1711
                message = 'error occurred({}) in {}:{}'.format(ex, sys.exc_info()[-1].tb_frame.f_code.co_filename,
1712
                                                              sys.exc_info()[-1].tb_lineno)
1713
                App.mainWnd().addMessage.emit(MessageType.Error, message)
1714

    
1715
        return symbolNametList
1716

    
1717
    '''
1718
        @brief      get symbol name list by symbol Type
1719
        @author     Jeongwoo
1720
        @date       18.04.06
1721
        @history    .
1722
    '''
1723
    def getSymbolNameListByType(self, type):
1724
        symbolNametList = []
1725
        if type in self._symbolNametList:
1726
            return self._symbolNametList[type]
1727

    
1728
        conn = self.project.database.connect()
1729
        with conn:
1730
            cursor = conn.cursor()
1731
            sql = ''
1732
            if type is not None:
1733
                sql = self.project.database.to_sql('SELECT * FROM SymbolName WHERE [Type]=?')
1734
                try:
1735
                    cursor.execute(sql, (type,))
1736
                    rows = cursor.fetchall()
1737
                    for row in rows:
1738
                        symbolNametList.append(row['Name'])  # Name String
1739
                    self._symbolNametList[type] = symbolNametList
1740
                except Exception as ex:
1741
                    print('error occurred({}) in {}:{}'.format(ex, sys.exc_info()[-1].tb_frame.f_code.co_filename,
1742
                                                              sys.exc_info()[-1].tb_lineno))
1743

    
1744
        return symbolNametList
1745

    
1746
    '''
1747
        @brief  delete added symbol data
1748
    '''
1749
    def deleteSymbol(self, fileName):
1750
        ret = False
1751

    
1752
        conn = self.project.database.connect()
1753
        with conn:
1754
            try:
1755
                cursor = conn.cursor()
1756
                sql = self.project.database.to_sql("DELETE FROM Symbol WHERE name = ?")
1757
                try:
1758
                    cursor.execute(sql, (fileName,))
1759
                    conn.commit()
1760
                    ret = True
1761
                except Exception as ex:
1762
                    conn.rollback()
1763
                    from App import App
1764
                    message = 'error occurred({}) in {}:{}'.format(ex, sys.exc_info()[-1].tb_frame.f_code.co_filename,
1765
                                                                sys.exc_info()[-1].tb_lineno)
1766
                    App.mainWnd().addMessage.emit(MessageType.Error, message)
1767
                    ret = False
1768
            finally:
1769
                self._symbolBase = {}
1770
                return (ret, fileName)
1771

    
1772
    def getDuplicatedAttrs(self, param):
1773
        """ get duplicated attributes """
1774

    
1775
        res = []
1776
        
1777
        with self.project.database.connect() as conn:
1778
            cursor = conn.cursor()
1779
            sql = self.project.database.to_sql(f"SELECT t.Value, c.UID, d.Name FROM "
1780
                                               f"(SELECT a.[Value] FROM Attributes a GROUP BY a.[value] HAVING COUNT(a.[value]) > 1) t "
1781
                                               f"INNER JOIN Attributes a ON a.Value=t.value "
1782
                                               f"INNER JOIN SymbolAttribute b ON a.SymbolAttribute_UID=b.UID "
1783
                                               f"INNER JOIN Components c ON a.Components_UID=c.UID "
1784
                                               f"INNER JOIN Drawings d ON c.Drawings_UID=d.UID "
1785
                                               f"WHERE b.Attribute=? AND t.value != '' AND t.value != 'None' AND t.value IS NOT null")
1786
            try:
1787
                cursor.execute(sql, (param,))
1788
                rows = cursor.fetchall()
1789
                for row in rows:
1790
                    res.append([row['Name'], row['UID'], row['Value']])
1791

    
1792
                res = sorted(res, key=lambda pram: param[2])
1793
                return res
1794

    
1795
            except Exception as ex:
1796
                from App import App
1797
                message = 'error occurred({}) in {}:{}'.format(ex, sys.exc_info()[-1].tb_frame.f_code.co_filename,
1798
                                                              sys.exc_info()[-1].tb_lineno)
1799
                App.mainWnd().addMessage.emit(MessageType.Error, message)
1800

    
1801
    '''
1802
        @brief  get symbol name
1803
        @history    18.04.24    Jeongwoo    Add isExceptDetect Field
1804
    '''
1805
    def getSymbolByQuery(self, fieldName, param):
1806
        ret = None
1807

    
1808
        if fieldName in self._symbolBase:
1809
            if param in self._symbolBase[fieldName]:
1810
                ret = self._symbolBase[fieldName][param]
1811
                return ret
1812
        else:
1813
            self._symbolBase[fieldName] = {}
1814

    
1815
        with self.project.database.connect() as conn:
1816
            cursor = conn.cursor()
1817
            sql = self.project.database.to_sql(f"SELECT a.UID as UID,a.Name,b.Type,a.Threshold,a.MinMatchPoint,"
1818
                                               f"a.IsDetectOrigin,a.RotationCount,a.OCROption,a.IsContainChild,"
1819
                                               f"a.OriginalPoint,a.ConnectionPoint,a.BaseSymbol,a.AdditionalSymbol,"
1820
                                               f"a.IsExceptDetect,a.HasInstrumentLabel,a.flip,a.TextArea,b.UID as DB_UID,a.Type as [Desc] FROM "
1821
                                               f"Symbol a inner join SymbolType b on a.SymbolType_UID=b.UID WHERE "
1822
                                               f"a.{fieldName}=?")
1823
            try:
1824
                cursor.execute(sql, (param,))
1825
                rows = cursor.fetchall()
1826
                if rows is not None and len(rows) > 0:
1827
                    symbolTuple = rows[0]
1828
                    ret = symbol.SymbolBase(symbolTuple['Name'], symbolTuple['Type'], symbolTuple['Threshold']
1829
                                            , symbolTuple['MinMatchPoint'], symbolTuple['IsDetectOrigin'],
1830
                                            symbolTuple['RotationCount'], symbolTuple['OCROption'],
1831
                                            symbolTuple['IsContainChild'], symbolTuple['OriginalPoint'],
1832
                                            symbolTuple['ConnectionPoint'], symbolTuple['BaseSymbol'],
1833
                                            symbolTuple['AdditionalSymbol'], symbolTuple['IsExceptDetect'],
1834
                                            symbolTuple['HasInstrumentLabel'], symbolTuple['UID'],
1835
                                            iType=symbolTuple['DB_UID'], detectFlip=symbolTuple['flip'],
1836
                                            text_area=symbolTuple['TextArea'], desc=symbolTuple['Desc'])
1837
                    self._symbolBase[fieldName][param] = ret
1838
            except Exception as ex:
1839
                from App import App
1840
                message = 'error occurred({}) in {}:{}'.format(ex, sys.exc_info()[-1].tb_frame.f_code.co_filename,
1841
                                                              sys.exc_info()[-1].tb_lineno)
1842
                App.mainWnd().addMessage.emit(MessageType.Error, message)
1843

    
1844
        return ret
1845

    
1846
    '''
1847
        @brief  get symbol name list
1848
        @history    18.04.24    Jeongwoo    Add isExceptDetect Field
1849
    '''
1850
    def getSymbolListByType(self, field_name=None, param=None):
1851
        ret = []
1852

    
1853
        with self.project.database.connect() as conn:
1854
            cursor = conn.cursor()
1855
            if field_name is not None and param is not None:
1856
                sql = """SELECT a.UID,a.Name,b.Type,a.Threshold,a.MinMatchPoint,a.IsDetectOrigin,a.RotationCount,
1857
                a.OCROption,a.IsContainChild,a.OriginalPoint,a.ConnectionPoint,a.BaseSymbol,a.AdditionalSymbol,a.Width,a.Height,
1858
                a.IsExceptDetect,a.HasInstrumentLabel,a.flip,a.TextArea,b.UID as DB_UID,a.Type as [Desc] FROM Symbol a 
1859
                inner join SymbolType b on a.SymbolType_UID=b.UID WHERE 
1860
                SymbolType_UID = (select UID from SymbolType where {}={})""".format(
1861
                    field_name, self.project.database.place_holder)
1862
            else:
1863
                sql = """SELECT a.UID,a.Name,b.Type,a.Threshold,a.MinMatchPoint,a.IsDetectOrigin,a.RotationCount, 
1864
                a.OCROption,a.IsContainChild,a.OriginalPoint,a.ConnectionPoint,a.BaseSymbol,a.AdditionalSymbol,a.Width,a.Height,
1865
                a.IsExceptDetect,a.HasInstrumentLabel,a.flip,a.TextArea,b.UID as DB_UID,a.Type as [Desc] FROM Symbol a 
1866
                inner join SymbolType b on a.SymbolType_UID=b.UID"""
1867
            try:
1868
                cursor.execute(sql, (param,)) if param is not None else cursor.execute(sql)
1869
                rows = cursor.fetchall()
1870
                if rows is not None and len(rows) > 0:
1871
                    for symbolTuple in rows:
1872
                        sym = symbol.SymbolBase(symbolTuple['Name'], symbolTuple['Type'], symbolTuple['Threshold'],
1873
                                                symbolTuple['MinMatchPoint'], symbolTuple['IsDetectOrigin'],
1874
                                                symbolTuple['RotationCount'], symbolTuple['OCROption'],
1875
                                                symbolTuple['IsContainChild'], symbolTuple['OriginalPoint'],
1876
                                                symbolTuple['ConnectionPoint'], symbolTuple['BaseSymbol'],
1877
                                                symbolTuple['AdditionalSymbol'], symbolTuple['IsExceptDetect'],
1878
                                                symbolTuple['HasInstrumentLabel'], symbolTuple['UID'],
1879
                                                iType=symbolTuple['DB_UID'],width=symbolTuple['Width'], height=symbolTuple['Height'],
1880
                                                detectFlip=symbolTuple['flip'], text_area=symbolTuple['TextArea'], desc=symbolTuple['Desc'])
1881
                        ret.append(sym)
1882

    
1883
                # update cache
1884
                if ret:
1885
                    if 'UID' not in self._symbolBase:
1886
                        self._symbolBase['UID'] = {}
1887
                    if 'name' not in self._symbolBase:
1888
                        self._symbolBase['name'] = {}
1889

    
1890
                    for _symbol in ret:
1891
                        if _symbol.uid not in self._symbolBase['UID']:
1892
                            self._symbolBase['UID'][_symbol.uid] = _symbol
1893
                        if _symbol.sName not in self._symbolBase['name']:
1894
                            self._symbolBase['name'][_symbol.sName] = _symbol
1895
            except Exception as ex:
1896
                from App import App
1897
                message = 'error occurred({}) in {}:{}'.format(ex, sys.exc_info()[-1].tb_frame.f_code.co_filename,
1898
                                                              sys.exc_info()[-1].tb_lineno)
1899
                App.mainWnd().addMessage.emit(MessageType.Error, message)
1900

    
1901
        return ret
1902

    
1903
    '''
1904
        @brief      get NominalDiameter
1905
        @author     humkyung
1906
        @date       2018.04.20
1907
        @history    humkyung 2018.04.24 read MetricStr column and set size unit
1908
                    kyouho 2018.07.04 forCheckLineNumber get only inch or metric
1909
                    kyouho 2018.07.16 edit query order by code
1910
    '''
1911
    def getNomialPipeSizeData(self, forCheckLineNumber=False, orderStr="MetricStr"):
1912
        res = []
1913
        configs = self.getConfigs('Line No', 'Size Unit')
1914
        sizeUnit = configs[0].value if 1 == len(configs) else 'Metric'
1915

    
1916
        conn = self.project.database.connect()
1917
        with conn:
1918
            try:
1919
                # Get a cursor object
1920
                cursor = conn.cursor()
1921

    
1922
                sql = f"select UID,Code,Metric,Inch,InchStr,AllowableInchStr,MetricStr,AllowableMetricStr from " \
1923
                      f"NominalDiameter ORDER BY {orderStr} DESC"
1924
                cursor.execute(sql)
1925
                rows = cursor.fetchall()
1926
                for row in rows:
1927
                    pipeSize = NominalPipeSize(row['UID'], row['Code'], float(row['Metric']) if row['Metric'] else None,
1928
                                               float(row['Inch']) if row['Inch'] else None, row['InchStr'],
1929
                                               row['AllowableInchStr'], row['MetricStr'], row['AllowableMetricStr'])
1930
                    pipeSize.sizeUnit = sizeUnit
1931
                    if forCheckLineNumber:
1932
                        if sizeUnit == 'Inch' and pipeSize.inchStr:
1933
                            res.append(pipeSize.inchStr)
1934
                        elif sizeUnit == 'Metric' and pipeSize.metricStr:
1935
                            res.append(pipeSize.metricStr)
1936
                    else:
1937
                        res.append(pipeSize)
1938

    
1939
                if 'Inch' in sizeUnit:
1940
                    res = sorted(res, key=lambda param:len(param.inchStr), reverse=True)
1941
                else:
1942
                    res = sorted(res, key=lambda param:len(param.metricStr), reverse=True)
1943
            # Catch the exception
1944
            except Exception as ex:
1945
                from App import App
1946
                message = 'error occurred({}) in {}:{}'.format(ex, sys.exc_info()[-1].tb_frame.f_code.co_filename,
1947
                                                              sys.exc_info()[-1].tb_lineno)
1948
                App.mainWnd().addMessage.emit(MessageType.Error, message)
1949

    
1950
        return res
1951

    
1952
    '''
1953
        @brief      insert NominalDiameter table
1954
        @author     kyouho
1955
        @date       2018.07.16
1956
    '''
1957
    def insertNomialPipeSize(self, pipeSizes):
1958
        conn = self.project.database.connect()
1959
        with conn:
1960
            try:
1961
                # Get a cursor object
1962
                cursor = conn.cursor()
1963
                for pipeSize in pipeSizes:
1964
                    sql = pipeSize.toSql()
1965
                    if type(sql) is list and len(sql) == 1:
1966
                        cursor.execute(self.project.database.to_sql(sql[0][0]), sql[0][1])
1967

    
1968
                conn.commit()
1969
            # Catch the exception
1970
            except Exception as ex:
1971
                # Roll back any change if something goes wrong
1972
                conn.rollback()
1973

    
1974
                from App import App
1975
                message = 'error occurred({}) in {}:{}'.format(ex, sys.exc_info()[-1].tb_frame.f_code.co_filename,
1976
                                                              sys.exc_info()[-1].tb_lineno)
1977
                App.mainWnd().addMessage.emit(MessageType.Error, message)
1978

    
1979
    '''
1980
        @brief      delete NominalDiameter table
1981
        @author     kyouho
1982
        @date       2018.07.16
1983
    '''
1984
    def deleteNomialPipeSize(self):
1985
        conn = self.project.database.connect()
1986
        with conn:
1987
            cursor = conn.cursor()
1988
            sql = "DELETE FROM NominalDiameter"
1989
            try:
1990
                cursor.execute(sql)
1991
                conn.commit()
1992
            except Exception as ex:
1993
                conn.rollback()
1994
                print('error occurred({}) in {}:{}'.format(ex, sys.exc_info()[-1].tb_frame.f_code.co_filename,
1995
                                                          sys.exc_info()[-1].tb_lineno))
1996

    
1997
    '''
1998
        @brief      convert inch to metric
1999
        @author     kyouho
2000
        @date       2018.07.09
2001
    '''
2002
    def convertInchToMetric(self, inch):
2003
        result = ''
2004
        conn = self.project.database.connect()
2005
        with conn:
2006
            try:
2007
                # Get a cursor object
2008
                cursor = conn.cursor()
2009

    
2010
                sql = "select MetricStr from NominalDiameter WHERE InchStr = ?"
2011
                param = (inch,)
2012
                cursor.execute(sql, param)
2013
                rows = cursor.fetchall()
2014

    
2015
                if rows:
2016
                    result = rows[0][0]
2017
                # Catch the exception
2018
            except Exception as ex:
2019
                print('error occurred({}) in {}:{}'.format(ex, sys.exc_info()[-1].tb_frame.f_code.co_filename,
2020
                                                          sys.exc_info()[-1].tb_lineno))
2021

    
2022
        return result
2023

    
2024
    '''
2025
        @brief      get Color MaxUID
2026
        @author     kyouho
2027
        @date       2018.07.03
2028
    '''
2029
    def getMaxColorUID(self):
2030
        result = 0
2031

    
2032
        conn = self.project.database.connect()
2033
        with conn:
2034
            try:
2035
                # Get a cursor object
2036
                cursor = conn.cursor()
2037

    
2038
                sql = "select MAX(UID) from Colors"
2039
                cursor.execute(sql)
2040
                rows = cursor.fetchall()
2041

    
2042
                result = rows[0][0]
2043
                # Catch the exception
2044
            except Exception as ex:
2045
                print('error occurred({}) in {}:{}'.format(ex, sys.exc_info()[-1].tb_frame.f_code.co_filename,
2046
                                                          sys.exc_info()[-1].tb_lineno))
2047

    
2048
        return result
2049

    
2050
    '''
2051
        @brief      insert Color property
2052
        @author     kyouho
2053
        @date       2018.07.09
2054
    '''
2055
    def setPropertyColor(self, _color):
2056
        conn = self.project.database.connect()
2057
        with conn:
2058
            try:
2059
                # Get a cursor object
2060
                cursor = conn.cursor()
2061
                sql = "INSERT INTO Colors(UID, RED, GREEN, BLUE, PROPERTY, VALUE) VALUES(?,?,?,?,?,?)"
2062
                param = (_color.index, _color.red, _color.green, _color.blue, _color._property, _color.value)
2063
                cursor.execute(sql, param)
2064
                conn.commit()
2065
            # Catch the exception
2066
            except Exception as ex:
2067
                # Roll back any change if something goes wrong
2068
                conn.rollback()
2069
                print('error occurred({}) in {}:{}'.format(ex, sys.exc_info()[-1].tb_frame.f_code.co_filename,
2070
                                                          sys.exc_info()[-1].tb_lineno))
2071

    
2072
    '''
2073
        @brief      delete Color property
2074
        @author     kyouho
2075
        @date       2018.07.09
2076
    '''
2077
    def deletePropertyColor(self, property):
2078
        conn = self.project.database.connect()
2079
        with conn:
2080
            try:
2081
                # Get a cursor object
2082
                cursor = conn.cursor()
2083

    
2084
                sql = "DELETE FROM Colors WHERE PROPERTY = '{}'".format(property)
2085
                cursor.execute(sql)
2086
                conn.commit()
2087
                # Catch the exception
2088
            except Exception as ex:
2089
                # Roll back any change if something goes wrong
2090
                conn.rollback()
2091
                print('error occurred({}) in {}:{}'.format(ex, sys.exc_info()[-1].tb_frame.f_code.co_filename,
2092
                                                          sys.exc_info()[-1].tb_lineno))
2093

    
2094
    '''
2095
        @brief      get Fluid Code
2096
        @author     kyouho
2097
        @date       2018.07.03
2098
        @history    kyouho 2018.07.04 kyouho 2018.07.04 forCheckLineNumber get only code
2099
    '''
2100
    def getFluidCodeData(self, forCheckLineNumber=False):
2101
        from FluidCodeData import FluidCodeData
2102
        result = []
2103

    
2104
        conn = self.project.database.connect()
2105
        with conn:
2106
            try:
2107
                # Get a cursor object
2108
                cursor = conn.cursor()
2109

    
2110
                sql = 'select uid, code, description from FluidCode order by length(code) DESC'
2111
                cursor.execute(sql)
2112
                rows = cursor.fetchall()
2113
                for row in rows:
2114
                    data = FluidCodeData(row[0], row[1], row[2])
2115
                    if forCheckLineNumber:
2116
                        result.append(data.code)
2117
                    else:
2118
                        result.append(data)
2119
                # Catch the exception
2120
            except Exception as ex:
2121
                print('error occurred({}) in {}:{}'.format(ex, sys.exc_info()[-1].tb_frame.f_code.co_filename,
2122
                                                          sys.exc_info()[-1].tb_lineno))
2123

    
2124
        return result
2125

    
2126
    '''
2127
        @brief      get Symbol Attribute
2128
        @author     kyouho
2129
        @date       2018.07.18
2130
        @ no more used
2131
    '''
2132
    def checkAttribute(self, attr):
2133
        conn = self.project.database.connect()
2134
        with conn:
2135
            try:
2136
                # Get a cursor object
2137
                cursor = conn.cursor()
2138

    
2139
                sql = 'select UID from SymbolAttribute where UID = ?'
2140
                param = (attr,)
2141
                cursor.execute(sql, param)
2142
                rows = cursor.fetchall()
2143
                if len(rows):
2144
                    return True
2145
                else:
2146
                    return False
2147
                # Catch the exception
2148
            except Exception as ex:
2149
                print('error occurred({}) in {}:{}'.format(ex, sys.exc_info()[-1].tb_frame.f_code.co_filename,
2150
                                                          sys.exc_info()[-1].tb_lineno))
2151

    
2152
        return False
2153

    
2154
    def read_drawing_shape(self, drawing):
2155
        """read drawing shape"""
2156

    
2157
        res = None
2158

    
2159
        with self.project.database.connect() as conn:
2160
            try:
2161
                # Get a cursor object
2162
                cursor = conn.cursor()
2163

    
2164
                sql = f"select Image from Drawings where UID='{drawing}'"
2165
                cursor.execute(sql)
2166
                records = cursor.fetchall()
2167
                for record in records:
2168
                    res = record[0]
2169
                    break
2170

    
2171
            # Catch the exception
2172
            except Exception as ex:
2173
                from App import App
2174
                # Roll back any change if something goes wrong
2175
                conn.rollback()
2176

    
2177
                message = 'error occurred({}) in {}:{}'.format(repr(ex), sys.exc_info()[-1].tb_frame.f_code.co_filename,
2178
                                                               sys.exc_info()[-1].tb_lineno)
2179
                App.mainWnd().addMessage.emit(MessageType.Error, message)
2180

    
2181
        return res
2182

    
2183
    def read_symbol_shape(self, symbol_name):
2184
        """read symbol shape(image and svg)"""
2185
        
2186
        res = (None, None)
2187

    
2188
        # need to test on mssql
2189
        return res
2190

    
2191
        with self.project.database.connect() as conn:
2192
            try:
2193
                # Get a cursor object
2194
                cursor = conn.cursor()
2195

    
2196
                sql = f"select Image, Svg from Symbol where Name='{symbol_name}'"
2197
                cursor.execute(sql)
2198
                records = cursor.fetchall()
2199
                for record in records:
2200
                    res = (record[0], record[1])
2201
                    break
2202

    
2203
            # Catch the exception
2204
            except Exception as ex:
2205
                from App import App
2206
                # Roll back any change if something goes wrong
2207
                conn.rollback()
2208

    
2209
                message = 'error occurred({}) in {}:{}'.format(repr(ex), sys.exc_info()[-1].tb_frame.f_code.co_filename,
2210
                                                               sys.exc_info()[-1].tb_lineno)
2211
                App.mainWnd().addMessage.emit(MessageType.Error, message)
2212

    
2213
        return res
2214

    
2215

    
2216
    def update_symbol_shape(self, symbol_name, image_file, svg_file, image_display_file):
2217
        """update symbol shape"""
2218

    
2219
        # need to test on mssql
2220
        return
2221

    
2222
        with self.project.database.connect() as conn:
2223
            try:
2224
                # Get a cursor object
2225
                cursor = conn.cursor()
2226

    
2227
                cols = []
2228
                params = []
2229

    
2230
                image_blob_data = None
2231
                if image_file and os.path.isfile(image_file):
2232
                    with open(image_file, 'rb') as file:
2233
                        image_blob_data = file.read()
2234
                    cols.append('Image=?')
2235
                    params.append(image_blob_data)
2236

    
2237
                svg_blob_data = None
2238
                if svg_file and os.path.isfile(svg_file):
2239
                    with open(svg_file, 'rb') as file:
2240
                        svg_blob_data = file.read()
2241
                    cols.append('Svg=?')
2242
                    params.append(svg_blob_data)
2243

    
2244
                image_display_blob_data = None
2245
                if image_file and image_display_file and os.path.isfile(image_display_file):
2246
                    with open(image_file, 'rb') as file:
2247
                        image_display_blob_data = file.read()
2248
                    cols.append('Image_display=?')
2249
                    params.append(image_display_blob_data)
2250

    
2251
                sql = f"update Symbol set {','.join(cols)} where Name='{symbol_name}'"
2252
                # Convert data into tuple format
2253
                cursor.execute(self.project.database.to_sql(sql), tuple(params))
2254
                conn.commit()
2255

    
2256
            # Catch the exception
2257
            except Exception as ex:
2258
                from App import App
2259
                # Roll back any change if something goes wrong
2260
                conn.rollback()
2261

    
2262
                message = 'error occurred({}) in {}:{}'.format(repr(ex), sys.exc_info()[-1].tb_frame.f_code.co_filename,
2263
                                                               sys.exc_info()[-1].tb_lineno)
2264
                App.mainWnd().addMessage.emit(MessageType.Error, message)
2265

    
2266
    def getReplaceTables(self):
2267
        ''' get replace(inst) code tables '''
2268

    
2269
        import uuid
2270
        from CodeTables import CodeTable
2271

    
2272
        with self.project.database.connect() as conn:
2273
            try:
2274
                result = []
2275

    
2276
                # Get a cursor object
2277
                cursor = conn.cursor()
2278

    
2279
                sql = self.project.database.to_sql('select UID, Name, Description from InstTables')
2280
                cursor.execute(sql)
2281
                rows = cursor.fetchall()
2282
                for row in rows:
2283
                    table = []
2284
                    table.append(uuid.UUID(row['UID']))
2285
                    table.append(row['Name'])
2286
                    table.append(row['Description'])
2287
                    table.append(CodeTable.instance('InstCodes', inst_table_uid=row['UID']))
2288
                    result.append(table)
2289
            # Catch the exception
2290
            except Exception as ex:
2291
                from App import App
2292
                message = 'error occurred({}) in {}:{}'.format(ex, sys.exc_info()[-1].tb_frame.f_code.co_filename,
2293
                                                              sys.exc_info()[-1].tb_lineno)
2294
                App.mainWnd().addMessage.emit(MessageType.Error, message)
2295

    
2296
        return result
2297

    
2298
    def getCustomTables(self):
2299
        ''' get custom code tables '''
2300

    
2301
        import uuid
2302
        from CodeTables import CodeTable
2303

    
2304
        with self.project.database.connect() as conn:
2305
            try:
2306
                result = []
2307

    
2308
                # Get a cursor object
2309
                cursor = conn.cursor()
2310

    
2311
                sql = self.project.database.to_sql('select UID, Name, Description from CustomTables')
2312
                cursor.execute(sql)
2313
                rows = cursor.fetchall()
2314
                for row in rows:
2315
                    table = []
2316
                    table.append(uuid.UUID(row['UID']))
2317
                    table.append(row['Name'])
2318
                    table.append(row['Description'])
2319
                    table.append(CodeTable.instance('CustomCodes', custom_table_uid=row['UID']))
2320
                    result.append(table)
2321
            # Catch the exception
2322
            except Exception as ex:
2323
                from App import App
2324
                message = 'error occurred({}) in {}:{}'.format(ex, sys.exc_info()[-1].tb_frame.f_code.co_filename,
2325
                                                              sys.exc_info()[-1].tb_lineno)
2326
                App.mainWnd().addMessage.emit(MessageType.Error, message)
2327

    
2328
        return result
2329

    
2330
    def loadSymbolAttributeCodeTables(self):
2331
        ''' load symbol attribute code tables '''
2332

    
2333
        try:
2334
            types = self.getSymbolTypeList()
2335

    
2336
            for _type in types:
2337
                self.getSymbolAttribute(_type[2])
2338

    
2339
        except Exception as ex:
2340
            from App import App
2341
            message = 'error occurred({}) in {}:{}'.format(ex, sys.exc_info()[-1].tb_frame.f_code.co_filename,
2342
                                                            sys.exc_info()[-1].tb_lineno)
2343
            App.mainWnd().addMessage.emit(MessageType.Error, message)
2344

    
2345
    '''
2346
        @brief      get Symbol Attribute
2347
        @author     kyouho
2348
        @date       2018.07.18
2349
        @history    humkyung 2018.10.13 load expression
2350
    '''
2351
    def getSymbolAttribute(self, _type):
2352
        import uuid
2353
        from SymbolAttr import SymbolAttr
2354
        from CodeTables import CodeTable
2355

    
2356
        result = []
2357

    
2358
        if self._attributeByType and _type in self._attributeByType:
2359
            new_attr_without_any_binding_data = []
2360
            for attr_old in self._attributeByType[_type]:
2361
                attr = SymbolAttr()
2362
                attr.UID = attr_old.UID
2363
                attr.Attribute = attr_old.Attribute
2364
                attr.DisplayAttribute = attr_old.DisplayAttribute
2365
                attr.AttributeType = attr_old.AttributeType
2366
                attr.AttrAt = attr_old.AttrAt
2367
                attr.Expression = attr_old.Expression
2368
                attr.Target = attr_old.Target
2369
                attr.IsProp = attr_old.IsProp
2370
                attr.Codes = attr_old.Codes
2371
                attr.Index = attr_old.Index
2372
                attr.Desc = attr_old.Desc
2373
                new_attr_without_any_binding_data.append(attr)
2374
            self._attributeByType[_type] = new_attr_without_any_binding_data
2375

    
2376
            return self._attributeByType[_type]
2377

    
2378
        with self.project.database.connect() as conn:
2379
            try:
2380
                # Get a cursor object
2381
                cursor = conn.cursor()
2382

    
2383
                sql = self.project.database.to_sql(
2384
                    'select a.UID, a.Attribute, a.DisplayAttribute, a.AttributeType, a.[AttrAt], a.[Expression], '
2385
                    'a.[index], a.[Target], a.[Property], a.[index] from SymbolAttribute a inner join SymbolType t '
2386
                    'on a.SymbolType_UID = t.UID and t.type = ? order by a.[index]')
2387
                param = (_type,)
2388
                cursor.execute(sql, param)
2389
                rows = cursor.fetchall()
2390
                for row in rows:
2391
                    attr = SymbolAttr()
2392
                    attr.UID = uuid.UUID(row['UID'].replace('\n', ""))
2393
                    attr.Attribute = row['Attribute']
2394
                    attr.DisplayAttribute = row['DisplayAttribute'] if self.delimiter not in row['DisplayAttribute'] else row['DisplayAttribute'].split(self.delimiter)[0]
2395
                    attr.AttributeType = row['AttributeType']
2396
                    attr.AttrAt = row['AttrAt']
2397
                    attr.Expression = row['Expression']
2398
                    attr.Target = row['Target']
2399
                    attr.IsProp = row['Property']
2400
                    attr.Index = row['index']
2401
                    attr.Codes = CodeTable.instance('SymbolAttributeCodeTable', symbol_attribute_uid=row['UID'])
2402
                    attr.Desc = '' if self.delimiter not in row['DisplayAttribute'] else row['DisplayAttribute'].split(self.delimiter)[1]
2403
                    result.append(attr)
2404
            # Catch the exception
2405
            except Exception as ex:
2406
                from App import App
2407
                message = 'error occurred({}) in {}:{}'.format(ex, sys.exc_info()[-1].tb_frame.f_code.co_filename,
2408
                                                              sys.exc_info()[-1].tb_lineno)
2409
                App.mainWnd().addMessage.emit(MessageType.Error, message)
2410

    
2411
        self._attributeByType[_type] = result
2412
        return result
2413

    
2414
    '''
2415
        @brief      get Symbol Attribute by UID
2416
        @author     kyouho
2417
        @date       2018.08.17
2418
        @history    humkyung 2018.10.13 load expression
2419
        @ no more used
2420
    '''
2421
    def getSymbolAttributeByUID(self, UID):
2422
        from SymbolAttr import SymbolAttr
2423

    
2424
        res = None
2425

    
2426
        with self.project.database.connect() as conn:
2427
            try:
2428
                # Get a cursor object
2429
                cursor = conn.cursor()
2430

    
2431
                sql = f"select Attribute, DisplayAttribute, AttributeType, AttrAt, Expression, Target, Property, [index] from " \
2432
                      f"SymbolAttribute where uid = '{UID}'"
2433
                cursor.execute(sql)
2434
                rows = cursor.fetchall()
2435
                if len(rows):
2436
                    res = SymbolAttr()
2437
                    res.UID = UID
2438
                    res.Attribute = rows[0]['Attribute']
2439
                    res.DisplayAttribute = rows[0]['DisplayAttribute']
2440
                    res.AttributeType = rows[0]['AttributeType']
2441
                    res.AttrAt = rows[0]['AttrAt']
2442
                    res.Expression = rows[0]['Expression']
2443
                    res.Target = rows[0]['Target']
2444
                    res.IsProp = rows[0]['Property']
2445
                    res.Index = rows[0]['index']
2446
                # Catch the exception
2447
            except Exception as ex:
2448
                from App import App
2449
                message = 'error occurred({}) in {}:{}'.format(ex, sys.exc_info()[-1].tb_frame.f_code.co_filename,
2450
                                                              sys.exc_info()[-1].tb_lineno)
2451
                App.mainWnd().addMessage.emit(MessageType.Error, message)
2452

    
2453
        return res
2454

    
2455
    '''
2456
        @brief      save symbol attributes
2457
        @author     humkyung
2458
        @date       2018.08.14
2459
        @history    humkyung 2018.10.13 save expression
2460
    '''
2461
    def saveSymbolAttributes(self, type, attrs, type_str):
2462
        from CodeTables import CodeTable
2463

    
2464
        with self.project.database.connect() as conn:
2465
            try:
2466
                # Get a cursor object
2467
                cursor = conn.cursor()
2468

    
2469
                # delete symbol attribute code table data
2470
                origin_attrs = self.getSymbolAttribute(type_str)
2471
                for origin_attr in origin_attrs:
2472
                    '''
2473
                    # delete symbol attribute code table data for deleted symbol attribute, and backup not edited attribute code table data
2474
                    remain = False
2475
                    for attr in attrs:
2476
                        if str(origin_attr.UID) == attr[0]:
2477
                            remain = True
2478
                            break
2479
                    if remain and attr[-1] and type(attr[-1][0][3]) is list: # this means not edited and need backup
2480
                        attr[-1] = self.getCodeTable('SymbolAttributeCodeTable', forCheckLineNumber=False, symbol_attribute_uid=origin_attr.UID)
2481
                    '''
2482
                    
2483
                    sql = "delete from SymbolAttributeCodeTable where SymbolAttribute_UID = '{}'".format(origin_attr.UID)
2484
                    cursor.execute(sql)
2485
                # up to here
2486

    
2487
                # update symbol attribute
2488
                sql = self.project.database.to_sql('delete from SymbolAttribute where SymbolType_UID = ?')
2489
                param = (type,)
2490
                cursor.execute(sql, param)
2491

    
2492
                for attr in attrs:
2493
                    sql = self.project.database.to_sql(
2494
                        'insert into SymbolAttribute(UID, SymbolType_UID, Attribute, DisplayAttribute, AttributeType, '
2495
                        'AttrAt, Expression, Target, [index], [Property]) values(?, ?, ?, ?, ?, ?, ?, ?, ?, ?)')
2496
                    attr.insert(1, type)
2497
                    cursor.execute(sql, tuple(attr[:-1]))
2498
                # up to here
2499

    
2500
                # update symbol attribute code table data
2501
                for attr in attrs:
2502
                    if attr[-1]:
2503
                        for code in attr[-1]:
2504
                            sql = self.project.database.to_sql( \
2505
                                "insert into SymbolAttributeCodeTable(UID, Code, Description, Allowables, "
2506
                                "SymbolAttribute_UID) VALUES(?,?,?,?,?)")
2507
                            param = (code[0], code[1], code[2], ','.join(code[3]), attr[0])
2508
                            cursor.execute(sql, param)
2509
                # up to here
2510

    
2511
                conn.commit()
2512

    
2513
                if hasattr(self, '_equipment_attributes'):
2514
                    del self._equipment_attributes
2515

    
2516
                if hasattr(self, '_valve_attributes'):
2517
                    del self._valve_attributes
2518

    
2519
                if hasattr(self, '_inst_attributes'):
2520
                    del self._inst_attributes
2521

    
2522
                if hasattr(self, '_note_attributes'):
2523
                    del self._note_attributes
2524
            # Catch the exception
2525
            except Exception as ex:
2526
                # Roll back any change if something goes wrong
2527
                conn.rollback()
2528

    
2529
                from App import App
2530
                message = 'error occurred({}) in {}:{}'.format(ex, sys.exc_info()[-1].tb_frame.f_code.co_filename,
2531
                                                              sys.exc_info()[-1].tb_lineno)
2532
                App.mainWnd().addMessage.emit(MessageType.Error, message)
2533

    
2534
            self._attributeByType = {}
2535
            CodeTable.clearTables()
2536

    
2537
    def save_hmb_data(self, hmb_list: list):
2538
        import uuid
2539

    
2540
        app_doc_data = AppDocData.instance()
2541
        with app_doc_data.project.database.connect() as conn:
2542
            try:
2543
                cursor = conn.cursor()
2544
                sql = 'delete from HMB_VALUE'
2545
                cursor.execute(sql)
2546
                sql = 'delete from HMB_LIST'
2547
                cursor.execute(sql)
2548
                sql = 'delete from Stream_No'
2549
                cursor.execute(sql)
2550

    
2551
                list_uids = []
2552
                if hmb_list and hmb_list[0].datas:
2553
                    """save hmb data catalog""" 
2554
                    for data in hmb_list[0].datas[0]:
2555
                        sql = f"insert into HMB_LIST(UID, Name, Unit, [index], [Type]) values(?,?,?,?,?)"
2556
                        sql = self.project.database.to_sql(sql)
2557
                        list_uid = str(uuid.uuid4())
2558
                        params = (list_uid, data.name, data.unit, data.index, data.phase)
2559
                        list_uids.append(list_uid)
2560
                        cursor.execute(sql, params)
2561

    
2562
                for hmb in hmb_list:
2563
                    """stream no save"""
2564
                    sql = f'insert into Stream_No(UID, Stream_No, [From], [To]) values(?,?,?,?)'
2565
                    sql = self.project.database.to_sql(sql)
2566
                    hmb.uid = hmb.uid if hmb.uid else str(uuid.uuid4())
2567
                    params = (str(hmb.uid), hmb.stream_no, hmb.hfrom, hmb.hto)
2568
                    cursor.execute(sql, params)
2569

    
2570
                    """save hmb data value"""
2571
                    params = []
2572
                    sql = f"insert into HMB_Value(UID, HMB_LIST_UID, Stream_No_UID, Value, [Case]) values(?,?,?,?,?)"
2573
                    sql = self.project.database.to_sql(sql)
2574
                    for data_case in hmb.datas:
2575
                        index = 0
2576
                        for data in data_case:
2577
                            params.append((str(uuid.uuid4()), list_uids[index], hmb.uid, data.value, data.case))
2578
                            index = index + 1
2579
                    cursor.executemany(sql, tuple(params))
2580

    
2581
                conn.commit()
2582
                self._hmbData = None
2583
                        
2584
            except Exception as ex:
2585
                # Roll back any change if something goes wrong
2586
                conn.rollback()
2587

    
2588
                from App import App
2589
                message = f"error occurred({repr(ex)}) in {sys.exc_info()[-1].tb_frame.f_code.co_filename}:" \
2590
                          f"{sys.exc_info()[-1].tb_lineno}"
2591
                App.mainWnd().addMessage.emit(MessageType.Error, message)
2592

    
2593
    def get_hmb_data(self, file_path: str):
2594
        """get hmb data from pap database if file_path is given otherwise get hmb data from id2 database"""
2595

    
2596
        from HMBTable import HMBData
2597

    
2598
        if not file_path:
2599
            if self._hmbData is None:
2600
                app_doc_data = AppDocData.instance()
2601
                with app_doc_data.project.database.connect() as conn:
2602
                    try:
2603
                        cursor = conn.cursor()
2604
                        sql = f"SELECT v.Value, v.[Case], r.Name, r.Unit, r.[index], r.[Type], s.Stream_No, s.[From], s.[To], s.UID FROM " \
2605
                                f"HMB_VALUE v " \
2606
                                f"INNER JOIN HMB_LIST r ON v.HMB_LIST_UID=r.UID " \
2607
                                f"INNER JOIN Stream_No s ON v.Stream_No_UID=s.UID " \
2608
                                f"ORDER BY s.stream_no"
2609
                        cursor.execute(sql)
2610
                        rows = cursor.fetchall()
2611

    
2612
                        hmbs = HMBData.from_row(rows)
2613
                        self._hmbData = hmbs
2614
                        return self._hmbData
2615
                    except Exception as ex:
2616
                        # Roll back any change if something goes wrong
2617
                        conn.rollback()
2618

    
2619
                        from App import App
2620
                        message = f"error occurred({repr(ex)}) in {sys.exc_info()[-1].tb_frame.f_code.co_filename}:" \
2621
                                f"{sys.exc_info()[-1].tb_lineno}"
2622
                        App.mainWnd().addMessage.emit(MessageType.Error, message)
2623
            else:
2624
                return self._hmbData
2625
        else:
2626
            with sqlite3.connect(file_path) as conn:
2627
                try:
2628
                    conn.row_factory = sqlite3.Row
2629
                    cursor = conn.cursor()
2630
                    sql = 'select * from HMB_condition'
2631
                    cursor.execute(sql)
2632
                    rows = cursor.fetchall()
2633
                    return rows
2634
                except Exception as ex:
2635
                    # Roll back any change if something goes wrong
2636
                    conn.rollback()
2637

    
2638
                    from App import App
2639
                    message = f"error occurred({repr(ex)}) in {sys.exc_info()[-1].tb_frame.f_code.co_filename}:" \
2640
                              f"{sys.exc_info()[-1].tb_lineno}"
2641
                    App.mainWnd().addMessage.emit(MessageType.Error, message)
2642

    
2643
        return None
2644

    
2645
    def get_hmb_attributes(self):
2646
        """get hmb attributes"""
2647
        """no more used"""
2648
        from SymbolAttr import SymbolAttr
2649

    
2650
        attrs = []
2651
        with self.project.database.connect() as conn:
2652
            try:
2653
                # Get a cursor object
2654
                cursor = conn.cursor()
2655

    
2656
                sql = f"select * from SymbolAttribute where SymbolType_UID = " \
2657
                      f"(select UID from SymbolType where Type='HMB') order by [index]"
2658
                sql = self.project.database.to_sql(sql)
2659
                cursor.execute(sql)
2660
                rows = cursor.fetchall()
2661
                for row in rows:
2662
                    attr = SymbolAttr(row['UID'])
2663
                    attr.Attribute = row['Attribute']
2664
                    attr.DisplayAttribute = row['DisplayAttribute']
2665
                    attr.AttributeType = row['AttributeType']
2666
                    attr.AttrAt = row['AttrAt']
2667
                    attr.Expression = row['Expression']
2668
                    attr.Target = row['Target']
2669
                    attr.IsProp = row['Property']
2670
                    attr.Index = row['index']
2671

    
2672
                    attrs.append(attr)
2673

    
2674
            # Catch the exception
2675
            except Exception as ex:
2676
                # Roll back any change if something goes wrong
2677
                conn.rollback()
2678

    
2679
                from App import App
2680
                message = 'error occurred({}) in {}:{}'.format(ex, sys.exc_info()[-1].tb_frame.f_code.co_filename,
2681
                                                               sys.exc_info()[-1].tb_lineno)
2682
                App.mainWnd().addMessage.emit(MessageType.Error, message)
2683

    
2684
        return attrs
2685

    
2686
    def save_hmb_model(self, model: QStandardItemModel):
2687
        """ no more used """
2688
        """save hmb model to database"""
2689

    
2690
        with self.project.database.connect() as conn:
2691
            try:
2692
                # get a cursor object
2693
                cursor = conn.cursor()
2694

    
2695
                # delete hmb table
2696
                sql = 'delete from HMB'
2697
                sql = self.project.database.to_sql(sql)
2698
                cursor.execute(sql)
2699
                # up to here
2700

    
2701
                for row in range(model.rowCount()):
2702
                    params = []
2703
                    for col in range(model.columnCount()):
2704
                        data = model.data(model.index(row, col))
2705
                        params.append(data)
2706

    
2707
                    values = ['?' for col in range(model.columnCount())]
2708
                    sql = f"insert into HMB values({','.join(values)})"
2709
                    cursor.execute(sql, params)
2710

    
2711
                conn.commit()
2712
            except Exception as ex:
2713
                # Roll back any change if something goes wrong
2714
                conn.rollback()
2715

    
2716
                from App import App
2717
                message = f"error occurred({repr(ex)}) in {sys.exc_info()[-1].tb_frame.f_code.co_filename}:" \
2718
                          f"{sys.exc_info()[-1].tb_lineno}"
2719
                App.mainWnd().addMessage.emit(MessageType.Error, message)
2720

    
2721
    def save_hmb_attributes(self, attrs):
2722
        """save hmb attributes"""
2723
        """no more used"""
2724
        from CodeTables import CodeTable
2725

    
2726
        with self.project.database.connect() as conn:
2727
            try:
2728
                # Get a cursor object
2729
                cursor = conn.cursor()
2730

    
2731
                # delete hmb attributes
2732
                sql = f"delete from SymbolAttribute where SymbolType_UID = (select UID from SymbolType where Type='HMB')"
2733
                sql = self.project.database.to_sql(sql)
2734
                cursor.execute(sql)
2735
                # up to here
2736

    
2737
                for idx, attr in enumerate(attrs):
2738
                    sql = self.project.database.to_sql(
2739
                        'insert into SymbolAttribute(UID, SymbolType_UID, Attribute, DisplayAttribute, AttributeType, '
2740
                        'AttrAt, Expression, Target, [index], [Property]) values(?, '
2741
                        '(select uid from SymbolType where Type=\'HMB\'), ?, ?, ?, ?, ?, ?, ?, ?)')
2742
                    params = (str(attr.UID), attr.Attribute, attr.Attribute, 'String', attr.AttrAt,
2743
                              attr.Expression if attr.Expression else None, attr.Target, idx, attr.IsProp)
2744

    
2745
                    cursor.execute(sql, params)
2746
                # up to here
2747

    
2748
                conn.commit()
2749

    
2750
            # Catch the exception
2751
            except Exception as ex:
2752
                # Roll back any change if something goes wrong
2753
                conn.rollback()
2754

    
2755
                from App import App
2756
                message = 'error occurred({}) in {}:{}'.format(ex, sys.exc_info()[-1].tb_frame.f_code.co_filename,
2757
                                                               sys.exc_info()[-1].tb_lineno)
2758
                App.mainWnd().addMessage.emit(MessageType.Error, message)
2759

    
2760
    @staticmethod
2761
    def save_stream_line_data(stream_line_list: list):
2762
        """ save stream line from to """
2763
        import uuid
2764

    
2765
        app_doc_data = AppDocData.instance()
2766
        with app_doc_data.project.database.connect() as conn:
2767
            try:
2768
                cursor = conn.cursor()
2769
                """delete stream line which has stream number is given data"""
2770
                sql = "delete from HMB_From_To where Stream_No=?"
2771
                sql = app_doc_data.project.database.to_sql(sql)
2772
                params = (stream_line_list[0],)
2773
                cursor.execute(sql, params)
2774
                """up to here"""
2775

    
2776
                for stream_line in stream_line_list[1]:
2777
                    sql = f"insert into HMB_From_To(UID,[Drawing_UID],[From_Component_UID],[To_Component_UID],[Stream_No],[Case]) values" \
2778
                          f"(?,?,?,?,?,?)"
2779
                    sql = app_doc_data.project.database.to_sql(sql)
2780
                    params = (str(uuid.uuid4()), stream_line[0], stream_line[1], stream_line[2], stream_line[3], stream_line[4])
2781
                    cursor.execute(sql, params)
2782

    
2783
                conn.commit()
2784
            except Exception as ex:
2785
                # Roll back any change if something goes wrong
2786
                conn.rollback()
2787

    
2788
                from App import App
2789
                message = f"error occurred({repr(ex)}) in {sys.exc_info()[-1].tb_frame.f_code.co_filename}:" \
2790
                          f"{sys.exc_info()[-1].tb_lineno}"
2791
                App.mainWnd().addMessage.emit(MessageType.Error, message)
2792

    
2793
    def get_stream_line_list_data(self, drawing_names=None):
2794
        """ get stream line list data from """
2795
        with self.project.database.connect() as conn:
2796
            try:
2797
                # Get a cursor object
2798
                cursor = conn.cursor()
2799

    
2800
                if drawing_names is None:
2801
                    doc_names = self.activeDrawing.name
2802
                else:
2803
                    doc_names = "','".join(drawing_names)
2804

    
2805
                sql = f"select S.PnIDNumber, S.Tag_Seq_No, S.PipingMaterialsClass, S.InsulationPurpose, S.FluidCode, " \
2806
                      f"S.UnitNumber, S.NominalDiameter, S.[From], S.[To], S.Stream_No, S.[Case], S.[Index], D.Name from Stream_Line_List S " \
2807
                      f"join Drawings D on S.Drawing_UID=D.UID " \
2808
                      f"where S.Drawing_UID in (select UID from Drawings where Name in ('{doc_names}'))"
2809
                sql = self.project.database.to_sql(sql)
2810
                cursor.execute(sql)
2811
                rows = cursor.fetchall()
2812

    
2813
                datas = []
2814
                for row in rows:
2815
                    data = {}
2816
                    data['PnIDNumber'] = row['PnIDNumber']
2817
                    data['Tag Seq No'] = row['Tag_Seq_No']
2818
                    data['PipingMaterialsClass'] = row['PipingMaterialsClass']
2819
                    data['InsulationPurpose'] = row['InsulationPurpose']
2820
                    data['FluidCode'] = row['FluidCode']
2821
                    data['UnitNumber'] = row['UnitNumber']
2822
                    data['NominalDiameter'] = row['NominalDiameter']
2823
                    data['FROM'] = row['From']
2824
                    data['TO'] = row['To']
2825
                    data['Stream No'] = row['Stream_No']
2826
                    data['Case'] = row['Case'] if row['Case'] else ''
2827
                    data['index'] = row['Index']
2828
                    data['Drawing Name'] = row['Name']
2829
                    
2830
                    datas.append(data)
2831

    
2832
                return datas
2833

    
2834
            # Catch the exception
2835
            except Exception as ex:
2836
                # Roll back any change if something goes wrong
2837
                conn.rollback()
2838

    
2839
                from App import App
2840
                message = f"error occurred({repr(ex)}) in {sys.exc_info()[-1].tb_frame.f_code.co_filename}:" \
2841
                          f"{sys.exc_info()[-1].tb_lineno}"
2842
                App.mainWnd().addMessage.emit(MessageType.Error, message)
2843

    
2844
    def get_stream_from_to(self, stream_no: str = None, drawing_uid: str = None) -> list:
2845
        """ get stream lines related to hmb """
2846

    
2847
        with self.project.database.connect() as conn:
2848
            try:
2849
                # Get a cursor object
2850
                cursor = conn.cursor()
2851

    
2852
                if stream_no:
2853
                    sql = f"select h.Drawing_UID, h.From_Component_UID, h.To_Component_UID, d.Name, h.[Case] from HMB_From_To h " \
2854
                          f"inner join Drawings d on d.UID=h.Drawing_UID " \
2855
                          f"where Stream_No = ?"
2856
                    params = (stream_no,)
2857
                else:
2858
                    sql = f"select h.From_Component_UID, h.To_Component_UID, s.Stream_No, h.[Case] from HMB_From_To h " \
2859
                          f"inner join Stream_No s on s.Stream_No=h.Stream_No " \
2860
                          f"where Drawing_UID = ?"
2861
                    params = (drawing_uid,)
2862
                sql = self.project.database.to_sql(sql)
2863
                cursor.execute(sql, params)
2864
                return cursor.fetchall()
2865
            # Catch the exception
2866
            except Exception as ex:
2867
                # Roll back any change if something goes wrong
2868
                conn.rollback()
2869

    
2870
                from App import App
2871
                message = f"error occurred({repr(ex)}) in {sys.exc_info()[-1].tb_frame.f_code.co_filename}:" \
2872
                          f"{sys.exc_info()[-1].tb_lineno}"
2873
                App.mainWnd().addMessage.emit(MessageType.Error, message)
2874

    
2875

    
2876
    def saveCustomCodes(self, tables):
2877
        ''' save custom code tables and codes '''
2878

    
2879
        from CodeTables import CodeTable
2880

    
2881
        conn = self.project.database.connect()
2882
        with conn:
2883
            try:
2884
                # Get a cursor object
2885
                cursor = conn.cursor()
2886

    
2887
                # delete custom codes and tables
2888
                sql = "delete from CustomCodes"
2889
                cursor.execute(sql)
2890

    
2891
                sql = "delete from CustomTables"
2892
                cursor.execute(sql)
2893
                # up to here
2894

    
2895
                # update symbol attribute code table data
2896
                for table in tables:
2897
                    sql = self.project.database.to_sql("insert into CustomTables (UID, Name, Description) VALUES(?,?,?)")
2898
                    param = (table[0], table[1], table[2])
2899
                    cursor.execute(sql, param)
2900

    
2901
                    for code in table[3]:
2902
                        sql = self.project.database.to_sql( \
2903
                            "insert into CustomCodes(UID, Code, Description, Allowables, Table_UID) VALUES(?,?,?,?,?)")
2904
                        param = (code[0], code[1], code[2], ','.join(code[3]), table[0])
2905
                        cursor.execute(sql, param)
2906
                # up to here
2907

    
2908
                conn.commit()
2909

    
2910
            # Catch the exception
2911
            except Exception as ex:
2912
                # Roll back any change if something goes wrong
2913
                conn.rollback()
2914

    
2915
                from App import App
2916
                message = 'error occurred({}) in {}:{}'.format(ex, sys.exc_info()[-1].tb_frame.f_code.co_filename,
2917
                                                              sys.exc_info()[-1].tb_lineno)
2918
                App.mainWnd().addMessage.emit(MessageType.Error, message)
2919

    
2920
            CodeTable.clearTables()
2921

    
2922
    def saveReplaceCodes(self, tables):
2923
        ''' save repalce(inst) code tables and codes '''
2924

    
2925
        from CodeTables import CodeTable
2926

    
2927
        conn = self.project.database.connect()
2928
        with conn:
2929
            try:
2930
                # Get a cursor object
2931
                cursor = conn.cursor()
2932

    
2933
                # delete custom codes and tables
2934
                sql = "delete from InstCodes"
2935
                cursor.execute(sql)
2936

    
2937
                sql = "delete from InstTables"
2938
                cursor.execute(sql)
2939
                # up to here
2940

    
2941
                # update symbol attribute code table data
2942
                for table in tables:
2943
                    sql = self.project.database.to_sql("insert into InstTables (UID, Name, Description) VALUES(?,?,?)")
2944
                    param = (table[0], table[1], table[2])
2945
                    cursor.execute(sql, param)
2946

    
2947
                    for code in table[3]:
2948
                        sql = self.project.database.to_sql( \
2949
                            "insert into InstCodes(UID, Code, Symbols, Attribute, NewCode, Expression, Priority, Table_UID) VALUES(?,?,?,?,?,?,?,?)")
2950
                        param = (code[0], ','.join(code[1]), ','.join(code[2]), ','.join(code[3]), code[4], code[5], code[6], table[0])
2951
                        cursor.execute(sql, param)
2952
                # up to here
2953

    
2954
                conn.commit()
2955

    
2956
            # Catch the exception
2957
            except Exception as ex:
2958
                # Roll back any change if something goes wrong
2959
                conn.rollback()
2960

    
2961
                from App import App
2962
                message = 'error occurred({}) in {}:{}'.format(ex, sys.exc_info()[-1].tb_frame.f_code.co_filename,
2963
                                                              sys.exc_info()[-1].tb_lineno)
2964
                App.mainWnd().addMessage.emit(MessageType.Error, message)
2965

    
2966
            CodeTable.clearTables()
2967

    
2968
    '''
2969
        @brief      save symbol attributes
2970
        @author     humkyung
2971
        @date       2018.08.14
2972
    '''
2973
    def saveLineAttributes(self, attrs):
2974
        with self.project.database.connect() as conn:
2975
            try:
2976
                # Get a cursor object
2977
                cursor = conn.cursor()
2978

    
2979
                sql = 'delete from LineProperties'
2980
                cursor.execute(sql)
2981

    
2982
                for attr in attrs:
2983
                    sql = self.project.database.to_sql(
2984
                        'insert into LineProperties(UID, Name, DisplayName, Type, LimitNumber, [index]) values(?, ?, ?, ?, ?, ?)')
2985
                    cursor.execute(sql, tuple(attr))
2986

    
2987
                conn.commit()
2988

    
2989
                self._lineNoProperties = None
2990
                self._lineNoPropertiesUID = {}
2991
            # Catch the exception
2992
            except Exception as ex:
2993
                # Roll back any change if something goes wrong
2994
                conn.rollback()
2995

    
2996
                from App import App
2997
                message = 'error occurred({}) in {}:{}'.format(ex, sys.exc_info()[-1].tb_frame.f_code.co_filename,
2998
                                                              sys.exc_info()[-1].tb_lineno)
2999
                App.mainWnd().addMessage.emit(MessageType.Error, message)
3000

    
3001
    '''
3002
        @brief      get symbol type id
3003
        @author     kyouho
3004
        @date       2018.08.17
3005
    '''
3006
    def getSymbolTypeId(self, symbolType):
3007
        result = []
3008

    
3009
        with self.project.database.connect() as conn:
3010
            try:
3011
                # Get a cursor object
3012
                cursor = conn.cursor()
3013

    
3014
                sql = self.project.database.to_sql('select UID from SymbolType where Type = ?')
3015
                param = (symbolType,)
3016
                cursor.execute(sql, param)
3017
                rows = cursor.fetchall()
3018

    
3019
                if len(rows):
3020
                    result = rows[0]['UID']
3021
                else:
3022
                    result = -1
3023
                # Catch the exception
3024
            except Exception as ex:
3025
                print('error occurred({}) in {}:{}'.format(ex, sys.exc_info()[-1].tb_frame.f_code.co_filename,
3026
                                                          sys.exc_info()[-1].tb_lineno))
3027

    
3028
        return result
3029

    
3030
    '''
3031
        @brief      get Code Table Data
3032
        @author     kyouho
3033
        @date       2018.07.10
3034
    '''
3035
    def getCodeTable(self, property, forCheckLineNumber=False, symbol_attribute_uid=None, custom_table_uid=None, custom=False, \
3036
                                                    inst_table_uid=None, inst=False):
3037
        result = []
3038
        with self.project.database.connect() as conn:
3039
            try:
3040
                # Get a cursor object
3041
                cursor = conn.cursor()
3042

    
3043
                if property.upper().replace(' ', '') == "NOMINALDIAMETER" and forCheckLineNumber:
3044
                    cols = ['InchStr', 'MetricStr']
3045
                    sql = f"select {cols[0]}, {cols[1]} from [{property}] order by Metric ASC"
3046
                    cursor.execute(sql)
3047
                    rows = cursor.fetchall()
3048
                    for index in range(2):
3049
                        for row in rows:
3050
                            if row[cols[index]] != '' and result.count(row[cols[index]].replace("'", '"')) == 0:
3051
                                result.append(row[cols[index]].replace("'", '"'))
3052
                else:
3053
                    """
3054
                    sql = "select name from sqlite_master where type='table'"# AND name={}".format(property)
3055
                    cursor.execute(sql)
3056
                    rows = cursor.fetchall()
3057
                    if property.upper() in [name[0].upper() for name in rows]:
3058
                    """
3059
                    if not symbol_attribute_uid and not custom_table_uid and not custom and not inst_table_uid and not inst:
3060
                        sql = 'select uid, code, description, Allowables from [{}] order by code DESC'.format(property)
3061
                    elif symbol_attribute_uid and not custom_table_uid and not inst_table_uid and not inst:
3062
                        sql = "select uid, code, description, Allowables from [{}] where SymbolAttribute_UID='{}' " \
3063
                              "order by code DESC".format(property, symbol_attribute_uid)
3064
                    elif not symbol_attribute_uid and custom_table_uid and not inst_table_uid:
3065
                        sql = "select uid, code, description, Allowables from [{}] where Table_UID='{}' " \
3066
                              "order by code DESC".format(property, custom_table_uid)
3067
                    elif not symbol_attribute_uid and not custom_table_uid and inst_table_uid:
3068
                        sql = "select uid, code, symbols, attribute, newcode, expression, priority from [{}] where Table_UID='{}' " \
3069
                              "order by code DESC".format(property, inst_table_uid)
3070
                    elif custom:
3071
                        sql = "select uid, code, description, Allowables from CustomCodes \
3072
                                    where table_uid = (select uid from CustomTables where upper(name) like upper('{}'))".format(property)
3073
                    elif inst:
3074
                        sql = "select uid, code, symbols, attribute, newcode, expression, priority from InstCodes \
3075
                                    where table_uid = (select uid from InstTables where upper(name) like upper('{}'))".format(property)
3076
                    cursor.execute(sql)
3077
                    rows = cursor.fetchall()
3078
                    if not inst:
3079
                        for row in rows:
3080
                            if forCheckLineNumber:
3081
                                data = row['code']
3082
                            else:
3083
                                data = (row['uid'], row['code'], row['description'], row['Allowables'])
3084
                            result.append(data)
3085
                        # else:
3086
                        #    result = None
3087
                    else:
3088
                        for row in rows:
3089
                            data = (row['uid'], row['code'], row['symbols'], row['attribute'], row['newcode'], row['expression'], row['priority'])
3090
                            result.append(data)
3091
            # Catch the exception
3092
            except Exception as ex:
3093
                from App import App
3094
                message = 'error occurred({}) in {}:{}'.format(ex, sys.exc_info()[-1].tb_frame.f_code.co_filename,
3095
                                                              sys.exc_info()[-1].tb_lineno)
3096
                App.mainWnd().addMessage.emit(MessageType.Error, message)
3097

    
3098
        return result
3099

    
3100
    def get_components(self, drawing):
3101
        """ get components in given drawing """
3102

    
3103
        with self.project.database.connect() as conn:
3104
            try:
3105
                # Get a cursor object
3106
                cursor = conn.cursor()
3107

    
3108
                sql = "select a.*,b.Name,b.SymbolType_UID,b.[Type],b.OriginalPoint,b.ConnectionPoint,b.BaseSymbol," \
3109
                      "b.AdditionalSymbol,b.HasInstrumentLabel,b.Flip as DetectFlip from Components a " \
3110
                      "join Symbol b on a.Symbol_UID=b.UID where a.Drawings_UID='{}'".format(drawing)
3111
                cursor.execute(sql)
3112
                return cursor.fetchall()
3113
                # Catch the exception
3114
            except Exception as ex:
3115
                from App import App
3116
                message = 'error occurred({}) in {}:{}'.format(ex, sys.exc_info()[-1].tb_frame.f_code.co_filename,
3117
                                                              sys.exc_info()[-1].tb_lineno)
3118
                App.mainWnd().addMessage.emit(MessageType.Error, message)
3119

    
3120
    def check_runs(self):
3121
        """ check run item duplication """
3122

    
3123
        with self.project.database.connect() as conn:
3124
            try:
3125
                # Get a cursor object
3126
                cursor = conn.cursor()
3127

    
3128
                sql = "select [Components_UID], count([Components_UID]) as count from [PipeRunItems] " \
3129
                      "group by [Components_UID] having count([Components_UID]) > 1"
3130

    
3131
                cursor.execute(sql)
3132

    
3133
                rows = cursor.fetchall()
3134

    
3135
                items = []
3136
                if rows:
3137
                    for row in rows:
3138
                        sql = "select c.[UID], d.[Name] from [Components] c inner join [Drawings] d on c.Drawings_UID=d.[UID]" \
3139
                              "where c.[UID]='" + row["Components_UID"] + "'"
3140
                        cursor.execute(sql)
3141

    
3142
                        _rows = cursor.fetchall()
3143
                        if _rows:
3144
                            items = items + _rows
3145

    
3146
                return items
3147
                # Catch the exception
3148
            except Exception as ex:
3149
                from App import App
3150
                message = 'error occurred({}) in {}:{}'.format(ex, sys.exc_info()[-1].tb_frame.f_code.co_filename,
3151
                                                              sys.exc_info()[-1].tb_lineno)
3152
                App.mainWnd().addMessage.emit(MessageType.Error, message)
3153

    
3154
    def get_opcs(self):
3155
        """ get opc in project """
3156
        configs = self.getConfigs('PSN', 'Symbols')
3157
        target = configs[0].value if configs else 'ALL'
3158

    
3159
        with self.project.database.connect() as conn:
3160
            try:
3161
                # Get a cursor object
3162
                cursor = conn.cursor()
3163

    
3164
                '''
3165
                if target == "ALL" or target == '':
3166
                    sql = "select (select Name from Drawings where UID=a.Drawings_UID) as Drawing," \
3167
                        "(select Value from Components where UID=a.Owner) as [Line No]," \
3168
                        "(select Name from Symbol where a.Symbol_UID=UID) as Symbol," \
3169
                        "(select stuff((select ',' + convert(NVARCHAR(10),[index]) from [Points] where Connected = a.UID for XML PAth('')),1,1,'')) as [Count]," \
3170
                        "UID as OPC from Components a " \
3171
                        "where Symbol_UID in (select UID from Symbol where SymbolType_UID in " \
3172
                        "(select UID from SymbolType where Type='Instrument OPC''s' or Type='Piping OPC''s'))"
3173
                else:
3174
                    sql = "select (select Name from Drawings where UID=a.Drawings_UID) as Drawing," \
3175
                        "(select Value from Components where UID=a.Owner) as [Line No]," \
3176
                        "(select Name from Symbol where a.Symbol_UID=UID) as Symbol," \
3177
                        "(select stuff((select ',' + convert(NVARCHAR(10),[index]) from [Points] where Connected = a.UID for XML PAth('')),1,1,'')) as [Count]," \
3178
                        "UID as OPC from Components a " \
3179
                        "where Symbol_UID in (" + target + ")"
3180
                '''
3181
                if target == "ALL" or target == '':
3182
                    sql = "select (select Name from Drawings where UID=a.Drawings_UID) as Drawing," \
3183
                        "(select Value from Components where UID=a.Owner) as [Line No]," \
3184
                        "(select Name from Symbol where a.Symbol_UID=UID) as Symbol," \
3185
                        "(select Count(1) from [Points] where Connected = a.UID) as [Count]," \
3186
                        "(select [Index] from [PipeRunItems] where Components_UID = a.UID) as [Index]," \
3187
                        "UID as OPC from Components a " \
3188
                        "where Symbol_UID in (select UID from Symbol where SymbolType_UID in " \
3189
                        "(select UID from SymbolType where Type='Instrument OPC''s' or Type='Piping OPC''s'))"
3190
                else:
3191
                    sql = "select (select Name from Drawings where UID=a.Drawings_UID) as Drawing," \
3192
                        "(select Value from Components where UID=a.Owner) as [Line No]," \
3193
                        "(select Name from Symbol where a.Symbol_UID=UID) as Symbol," \
3194
                        "(select Count(1) from [Points] where Connected = a.UID) as [Count]," \
3195
                        "(select [Index] from [PipeRunItems] where Components_UID = a.UID) as [Index]," \
3196
                        "UID as OPC from Components a " \
3197
                        "where Symbol_UID in (" + target + ")"
3198

    
3199
                cursor.execute(sql)
3200

    
3201
                rows = cursor.fetchall()
3202

    
3203
                opcs = []
3204
                if self.project.database.db_type == 'SQLite':
3205
                    for row in rows:
3206
                        #count = str(len(row["Count"].split(',')))
3207
                        opcs.append({ "Drawing":row["Drawing"], "Line No":row["Line No"].replace('\n', ''), "Symbol":row["Symbol"], "Count":row["Count"], "OPC":row["OPC"], "Index": row["Index"]})
3208
                else:
3209
                    opcs = rows
3210

    
3211
                for opc in opcs:
3212
                    opc['Index'] = 0 if opc['Index'] == 1 else 1 # 0 : start with opc, 1 : end with opc
3213

    
3214
                return opcs
3215
                # Catch the exception
3216
            except Exception as ex:
3217
                from App import App
3218
                message = 'error occurred({}) in {}:{}'.format(ex, sys.exc_info()[-1].tb_frame.f_code.co_filename,
3219
                                                              sys.exc_info()[-1].tb_lineno)
3220
                App.mainWnd().addMessage.emit(MessageType.Error, message)
3221

    
3222
    def get_opc_relations(self):
3223
        """ get opc relations """
3224
        conn = self.project.database.connect()
3225
        with conn:
3226
            try:
3227
                # Get a cursor object
3228
                cursor = conn.cursor()
3229

    
3230
                sql = "select (select Name from Drawings where UID=a.From_Drawings_UID) as From_Drawing,\
3231
                a.From_LineNo_UID as From_LineNo,\
3232
                a.From_OPC_UID,\
3233
                (select Name from Drawings where UID=a.To_Drawings_UID) as To_Drawing,\
3234
                a.To_LineNo_UID as To_LineNo,\
3235
                a.To_OPC_UID \
3236
                from OPCRelations a"
3237
                cursor.execute(sql)
3238
                return cursor.fetchall()
3239
                # Catch the exception
3240
            except Exception as ex:
3241
                from App import App
3242
                message = 'error occurred({}) in {}:{}'.format(ex, sys.exc_info()[-1].tb_frame.f_code.co_filename,
3243
                                                              sys.exc_info()[-1].tb_lineno)
3244
                App.mainWnd().addMessage.emit(MessageType.Error, message)
3245

    
3246
    def save_opc_relations(self, opcs):
3247
        """ save opc relations """
3248
        conn = self.project.database.connect()
3249
        with conn:
3250
            try:
3251
                # Get a cursor object
3252
                cursor = conn.cursor()
3253
                sql = 'delete from OPCRelations'
3254
                cursor.execute(sql)
3255

    
3256
                for opc in opcs:
3257
                    sql = 'insert into OPCRelations(From_Drawings_UID,From_LineNo_UID,From_OPC_UID,To_Drawings_UID,To_LineNo_UID,To_OPC_UID) \
3258
                        values({},{},{},{},{},{})'.format(
3259
                        "(select UID from Drawings where Name='{}')".format(opc[0]),
3260
                        "'{}'".format(opc[1]) if opc[1] else 'null',
3261
                        "'{}'".format(opc[2]) if opc[2] else 'null',
3262
                        "(select UID from Drawings where Name='{}')".format(opc[3]) if opc[3] else 'null',
3263
                        "'{}'".format(opc[4]) if opc[4] else 'null',
3264
                        "'{}'".format(opc[5]) if opc[5] else 'null')
3265
                    cursor.execute(sql)
3266

    
3267
                conn.commit()
3268
            # Catch the exception
3269
            except Exception as ex:
3270
                conn.rollback()
3271

    
3272
                from App import App
3273
                message = 'error occurred({}) in {}:{}'.format(ex, sys.exc_info()[-1].tb_frame.f_code.co_filename,
3274
                                                              sys.exc_info()[-1].tb_lineno)
3275
                App.mainWnd().addMessage.emit(MessageType.Error, message)
3276

    
3277
    def get_component_connectors(self, component):
3278
        """ get connectors of given component """
3279
        if self._connecterss and component in self._connecterss:
3280
            return self._connecterss[component]
3281

    
3282
        conn = self.project.database.connect()
3283
        with conn:
3284
            try:
3285
                # Get a cursor object
3286
                cursor = conn.cursor()
3287

    
3288
                sql = f"select a.* from Points a join Components b on a.Components_UID=b.[UID] where Drawings_UID=" \
3289
                      f"'{self.activeDrawing.UID}' order by Components_UID, [Index]"
3290
                cursor.execute(sql)
3291

    
3292
                pre = ''
3293
                rows = cursor.fetchall()
3294
                for row in rows:
3295
                    if pre != row['Components_UID']:
3296
                        if pre != '':
3297
                            self._connecterss[pre] = compo
3298
                        pre = row['Components_UID']
3299
                        compo = []
3300
                        compo.append(row)
3301
                        if row is rows[-1]:
3302
                            self._connecterss[row['Components_UID']] = compo
3303
                    else:
3304
                        compo.append(row)
3305
                        if row is rows[-1]:
3306
                            self._connecterss[row['Components_UID']] = compo
3307

    
3308
                return self._connecterss[component] if component in self._connecterss else []
3309
                # Catch the exception
3310
            except Exception as ex:
3311
                from App import App
3312
                message = 'error occurred({}) in {}:{}'.format(ex, sys.exc_info()[-1].tb_frame.f_code.co_filename,
3313
                                                              sys.exc_info()[-1].tb_lineno)
3314
                App.mainWnd().addMessage.emit(MessageType.Error, message)
3315

    
3316
    def get_component_associations(self, component):
3317
        """ get associations of given component """
3318
        if self._associationss and component in self._associationss:
3319
            return self._associationss[component]
3320
        elif self._associationss:
3321
            return []
3322

    
3323
        conn = self.project.database.connect()
3324
        with conn:
3325
            try:
3326
                # Get a cursor object
3327
                cursor = conn.cursor()
3328

    
3329
                # sql = "select * from Associations where Components_UID='{}'".format(component)
3330
                sql = "select a.* from Associations a \
3331
                            join Components b on a.Components_UID=b.[UID] where Drawings_UID='{}' order by Components_UID".format(
3332
                    self.activeDrawing.UID)
3333
                cursor.execute(sql)
3334

    
3335
                pre = ''
3336
                rows = cursor.fetchall()
3337
                for row in rows:
3338
                    if pre != row['Components_UID']:
3339
                        if pre != '':
3340
                            self._associationss[pre] = compo
3341
                        pre = row['Components_UID']
3342
                        compo = []
3343
                        compo.append(row)
3344
                        if row is rows[-1]:
3345
                            self._associationss[row['Components_UID']] = compo
3346
                    else:
3347
                        compo.append(row)
3348
                        if row is rows[-1]:
3349
                            self._associationss[row['Components_UID']] = compo
3350

    
3351
                return self._associationss[component] if component in self._associationss else []
3352
                # Catch the exception
3353
            except Exception as ex:
3354
                from App import App
3355
                message = 'error occurred({}) in {}:{}'.format(ex, sys.exc_info()[-1].tb_frame.f_code.co_filename,
3356
                                                              sys.exc_info()[-1].tb_lineno)
3357
                App.mainWnd().addMessage.emit(MessageType.Error, message)
3358

    
3359
    def get_component_attributes(self, component):
3360
        """ get attributes of given component """
3361
        if self._attributess and component in self._attributess:
3362
            return self._attributess[component]
3363
        elif self._attributess:
3364
            return []
3365

    
3366
        conn = self.project.database.connect()
3367
        with conn:
3368
            try:
3369
                # Get a cursor object
3370
                cursor = conn.cursor()
3371

    
3372
                sql = "select a.*, b.* from Attributes a \
3373
                            join SymbolAttribute b on a.SymbolAttribute_UID=b.UID \
3374
                            join Components c on a.Components_UID=c.UID \
3375
                        where Drawings_UID='{}' order by a.Components_UID, b.[index]".format(self.activeDrawing.UID)
3376
                cursor.execute(sql)
3377

    
3378
                pre = ''
3379
                rows = cursor.fetchall()
3380
                for row in rows:
3381
                    if pre != row['Components_UID']:
3382
                        if pre != '':
3383
                            self._attributess[pre] = compo
3384
                        pre = row['Components_UID']
3385
                        compo = []
3386
                        compo.append(row)
3387
                        if row is rows[-1]:
3388
                            self._attributess[row['Components_UID']] = compo
3389
                    else:
3390
                        compo.append(row)
3391
                        if row is rows[-1]:
3392
                            self._attributess[row['Components_UID']] = compo
3393

    
3394
                return self._attributess[component] if component in self._attributess else []
3395
                # Catch the exception
3396
            except Exception as ex:
3397
                from App import App
3398
                message = 'error occurred({}) in {}:{}'.format(ex, sys.exc_info()[-1].tb_frame.f_code.co_filename,
3399
                                                              sys.exc_info()[-1].tb_lineno)
3400
                App.mainWnd().addMessage.emit(MessageType.Error, message)
3401

    
3402
    def get_pipe_runs(self, component):
3403
        """ get line runs of given component """
3404
        conn = self.project.database.connect()
3405
        with conn:
3406
            try:
3407
                # Get a cursor object
3408
                cursor = conn.cursor()
3409

    
3410
                sql = "select * from PipeRuns where Owner='{}' order by [Index]".format(component)
3411
                cursor.execute(sql)
3412
                return cursor.fetchall()
3413
                # Catch the exception
3414
            except Exception as ex:
3415
                from App import App
3416
                message = 'error occurred({}) in {}:{}'.format(ex, sys.exc_info()[-1].tb_frame.f_code.co_filename,
3417
                                                              sys.exc_info()[-1].tb_lineno)
3418
                App.mainWnd().addMessage.emit(MessageType.Error, message)
3419

    
3420
    def get_pipe_run_items(self, pipe_run):
3421
        """ get line run items of given pipe run """
3422
        conn = self.project.database.connect()
3423
        with conn:
3424
            try:
3425
                # Get a cursor object
3426
                cursor = conn.cursor()
3427

    
3428
                sql = "select * from PipeRunItems where PipeRuns_UID='{}' order by [Index]".format(pipe_run)
3429
                cursor.execute(sql)
3430
                return cursor.fetchall()
3431
                # Catch the exception
3432
            except Exception as ex:
3433
                from App import App
3434
                message = 'error occurred({}) in {}:{}'.format(ex, sys.exc_info()[-1].tb_frame.f_code.co_filename,
3435
                                                              sys.exc_info()[-1].tb_lineno)
3436
                App.mainWnd().addMessage.emit(MessageType.Error, message)
3437

    
3438
    '''
3439
        @brief      get special item types from database
3440
        @author     humkyung
3441
        @date       2019.08.10
3442
    '''
3443
    def get_special_item_types(self):
3444
        conn = self.project.database.connect()
3445
        with conn:
3446
            try:
3447
                # Get a cursor object
3448
                cursor = conn.cursor()
3449

    
3450
                sql = 'select UID, Code, Type, Allowables from SpecialItemTypes order by Code DESC'
3451
                cursor.execute(sql)
3452
                return cursor.fetchall()
3453
                # Catch the exception
3454
            except Exception as ex:
3455
                from App import App
3456
                message = 'error occurred({}) in {}:{}'.format(ex, sys.exc_info()[-1].tb_frame.f_code.co_filename,
3457
                                                              sys.exc_info()[-1].tb_lineno)
3458
                App.mainWnd().addMessage.emit(MessageType.Error, message)
3459

    
3460
    '''
3461
        @brief      save special item types
3462
        @author     humkyung
3463
        @date       2019.08.10
3464
    '''
3465
    def save_special_item_types(self, datas):
3466
        import uuid
3467

    
3468
        conn = self.project.database.connect()
3469
        with conn:
3470
            try:
3471
                # Get a cursor object
3472
                cursor = conn.cursor()
3473

    
3474
                for data in datas:
3475
                    uid, code, _type, allowables = data[0], data[1], data[2], data[3]
3476
                    if not uid:
3477
                        sql = self.project.database.to_sql(
3478
                            'insert into SpecialItemTypes(UID, Code, Type, Allowables) values(?, ?, ?, ?)')
3479
                        param = (str(uuid.uuid4()), data[1], data[2], data[3])
3480
                    elif uid == '-1':
3481
                        sql = self.project.database.to_sql('delete from SpecialItemTypes where uid=?')
3482
                        param = (data[-1],)
3483
                    else:
3484
                        sql = self.project.database.to_sql(
3485
                            'update SpecialItemTypes SET Code=?, Type=?, Allowables=? WHERE UID = ?')
3486
                        param = (data[1], data[2], data[3], data[0])
3487
                    cursor.execute(sql, param)
3488

    
3489
                conn.commit()
3490
            # Catch the exception
3491
            except Exception as ex:
3492
                # Roll back any change if something goes wrong
3493
                conn.rollback()
3494

    
3495
                from App import App
3496
                message = 'error occurred({}) in {}:{}'.format(ex, sys.exc_info()[-1].tb_frame.f_code.co_filename,
3497
                                                              sys.exc_info()[-1].tb_lineno)
3498
                App.mainWnd().addMessage.emit(MessageType.Error, message)
3499

    
3500
    def get_special_items(self, drawings=None):
3501
        """ get special items from database """
3502
        result = []
3503

    
3504
        conn = self.project.database.connect()
3505
        with conn:
3506
            try:
3507
                # get a cursor object
3508
                cursor = conn.cursor()
3509

    
3510
                sql = 'select distinct (select Value from Components where UID=D.Owner) as "Line No",C.Code from Components A \
3511
                    left join Drawings B on A.Drawings_UID=B.UID \
3512
                    left join SpecialItemTypes C on A.SpecialItemTypes_UID=C.UID \
3513
                    left join Components D on A.Connected=D.UID \
3514
                    where A.SpecialItemTypes_UID is not null'
3515
                if drawings is not None:
3516
                    doc_names = "','".join(drawings)
3517
                    sql += f" and A.Drawings_UID in (select UID from Drawings where Name in ('{doc_names}'))"
3518
                sql += ' order by "Line No"'
3519
                cursor.execute(sql)
3520

    
3521
                return cursor.fetchall()
3522
            # catch the exception
3523
            except Exception as ex:
3524
                from App import App
3525
                message = 'error occurred({}) in {}:{}'.format(ex, sys.exc_info()[-1].tb_frame.f_code.co_filename,
3526
                                                              sys.exc_info()[-1].tb_lineno)
3527
                App.mainWnd().addMessage.emit(MessageType.Error, message)
3528

    
3529
        return None
3530

    
3531
    '''
3532
        @brief      Set Common Code Data
3533
        @author     kyouho
3534
        @date       2018.07.12
3535
    '''
3536
    def saveCommonCodeData(self, tableName, datas):
3537
        import uuid
3538

    
3539
        conn = self.project.database.connect()
3540
        with conn:
3541
            try:
3542
                # Get a cursor object
3543
                cursor = conn.cursor()
3544

    
3545
                sql = self.project.database.to_sql('delete from {}'.format(tableName))
3546
                cursor.execute(sql)
3547

    
3548
                for data in datas:
3549
                    '''
3550
                    uid, code, description, allowables = data[0], data[1], data[2], data[3]
3551
                    if not uid:
3552
                        sql = self.project.database.to_sql(
3553
                            "insert into {}(UID, CODE, DESCRIPTION, ALLOWABLES) values(?, ?, ?, ?)".format(tableName))
3554
                        param = (str(uuid.uuid4()), data[1], data[2], data[3])
3555
                    elif uid == '-1':
3556
                        sql = self.project.database.to_sql('delete from {} where uid=?'.format(tableName))
3557
                        param = (data[-1],)
3558
                    else:
3559
                        sql = self.project.database.to_sql(
3560
                            "update {} SET CODE=?, DESCRIPTION=?, ALLOWABLES=? WHERE UID = ?".format(tableName))
3561
                        param = (data[1], data[2], data[3], data[0])
3562
                    cursor.execute(sql, param)
3563
                    '''
3564
                    if data[0]:
3565
                        uid = data[0]
3566
                    else:
3567
                        uid = str(uuid.uuid4())
3568
                    sql = self.project.database.to_sql(
3569
                        "insert into {}(UID, CODE, DESCRIPTION, ALLOWABLES) values(?, ?, ?, ?)".format(tableName))
3570
                    param = (uid, data[1], data[2], data[3])
3571
                    cursor.execute(sql, param)
3572

    
3573
                conn.commit()
3574
            # Catch the exception
3575
            except Exception as ex:
3576
                # Roll back any change if something goes wrong
3577
                conn.rollback()
3578

    
3579
                from App import App
3580
                message = 'error occurred({}) in {}:{}'.format(ex, sys.exc_info()[-1].tb_frame.f_code.co_filename,
3581
                                                              sys.exc_info()[-1].tb_lineno)
3582
                App.mainWnd().addMessage.emit(MessageType.Error, message)
3583

    
3584
    def selectView(self):
3585
        """ get document name list """
3586
        result = []
3587

    
3588
        with self.project.database.connect() as conn:
3589
            try:
3590
                # Get a cursor object
3591
                cursor = conn.cursor()
3592

    
3593
                sql = "select * from T_PSN_VIEW"
3594
                cursor.execute(sql)
3595

    
3596
                rows = cursor.fetchall()
3597
                for row in rows:
3598
                    result.append(row['OID'])
3599

    
3600
                result.sort()
3601
            # Catch the exception
3602
            except Exception as ex:
3603
                print('error occurred({}) in {}:{}'.format(ex, sys.exc_info()[-1].tb_frame.f_code.co_filename,
3604
                                                          sys.exc_info()[-1].tb_lineno))
3605

    
3606
        return result
3607

    
3608
    '''
3609
        @brief      Set Common Code Data
3610
        @author     kyouho
3611
        @date       2018.07.12
3612
    '''
3613
    def deleteCommonCodeData(self, datas):
3614
        try:
3615
            conn = self.project.database.connect()
3616
            with conn:
3617
                # Get a cursor object
3618
                cursor = conn.cursor()
3619

    
3620
                for data in datas:
3621
                    uid = data[0]
3622
                    tableName = data[1]
3623

    
3624
                    if uid:
3625
                        sql = "delete from {} where UID = ?".format(tableName)
3626
                        param = (uid,)
3627
                        cursor.execute(sql, param)
3628

    
3629
                    cursor.execute(sql, param)
3630

    
3631
                conn.commit()
3632

    
3633
        # Catch the exception
3634
        except Exception as ex:
3635
            # Roll back any change if something goes wrong
3636
            conn.rollback()
3637

    
3638
            from App import App
3639
            message = f"error occurred({repr(ex)}) in {sys.exc_info()[-1].tb_frame.f_code.co_filename}:" \
3640
                        f"{sys.exc_info()[-1].tb_lineno}"
3641
            App.mainWnd().addMessage.emit(MessageType.Error, message)
3642

    
3643
    '''
3644
        @brief      delete data list
3645
        @author     kyouho
3646
        @date       2018.08.16
3647
    '''
3648
    def deleteDataList(self, tableName, UID):
3649
        conn = self.project.database.connect()
3650
        with conn:
3651
            try:
3652
                # Get a cursor object
3653
                cursor = conn.cursor()
3654
                sql = 'delete from {} where UID = {}'.format(tableName, UID)
3655
                cursor.execute(sql)
3656
                conn.commit()
3657

    
3658
            # Catch the exception
3659
            except Exception as ex:
3660
                # Roll back any change if something goes wrong
3661
                conn.rollback()
3662

    
3663
                from App import App
3664
                message = f"error occurred({repr(ex)}) in {sys.exc_info()[-1].tb_frame.f_code.co_filename}:" \
3665
                          f"{sys.exc_info()[-1].tb_lineno}"
3666
                App.mainWnd().addMessage.emit(MessageType.Error, message)
3667

    
3668
    def get_document_name_list(self):
3669
        """ get document name list """
3670
        result = []
3671

    
3672
        with self.project.database.connect() as conn:
3673
            try:
3674
                # Get a cursor object
3675
                cursor = conn.cursor()
3676

    
3677
                sql = "select distinct B.Name as 'Drawing_Name' from Components A join Drawings B on " \
3678
                      "A.Drawings_UID=B.UID"
3679
                cursor.execute(sql)
3680

    
3681
                rows = cursor.fetchall()
3682
                for row in rows:
3683
                    result.append(row['Drawing_Name'])
3684

    
3685
                result.sort()
3686
            # Catch the exception
3687
            except Exception as ex:
3688
                print('error occurred({}) in {}:{}'.format(ex, sys.exc_info()[-1].tb_frame.f_code.co_filename,
3689
                                                          sys.exc_info()[-1].tb_lineno))
3690

    
3691
        return result
3692

    
3693
    '''
3694
        @brief      get line documentName list
3695
        @author     kyouho
3696
        @date       2018.08.13
3697
    '''
3698
    def getLineDocumentNameList(self):
3699
        result = []
3700

    
3701
        conn = self.project.database.connect()
3702
        with conn:
3703
            try:
3704
                # Get a cursor object
3705
                cursor = conn.cursor()
3706

    
3707
                sql = 'select DISTINCT(PNID_NO) from LINE_DATA_LIST'
3708

    
3709
                cursor.execute(sql)
3710
                rows = cursor.fetchall()
3711
                for row in rows:
3712
                    result.append(row[0])
3713
            # Catch the exception
3714
            except Exception as ex:
3715
                print('error occurred({}) in {}:{}'.format(ex, sys.exc_info()[-1].tb_frame.f_code.co_filename,
3716
                                                          sys.exc_info()[-1].tb_lineno))
3717

    
3718
        return result
3719

    
3720
    '''
3721
        @brief      get line data list
3722
        @author     kyouho
3723
        @date       2018.08.13
3724
    '''
3725
    def get_line_data_list(self, drawings=None):
3726
        result = []
3727

    
3728
        with self.project.database.connect() as conn:
3729
            try:
3730
                # Get a cursor object
3731
                cursor = conn.cursor()
3732

    
3733
                '''
3734
                sql = 'select A.UID,B.Name,A.Value as [Line No] from Components A left join Drawings B on A.Drawings_UID=B.UID'
3735
                if drawings is not None:
3736
                    doc_names = "','".join(drawings)
3737
                    sql += f" where A.Symbol_UID=1 and Drawings_UID in (select UID from Drawings where Name in ('{doc_names}'))"
3738
                cursor.execute(sql)
3739
                comps = [(row['UID'], row['Name'], row['Line No']) for row in cursor.fetchall()]
3740
                for comp in comps:
3741
                    sql = f"select b.Name,a.Value from LineNoAttributes a left join LineProperties b " \
3742
                          f"on a.LineProperties_UID=b.UID where a.Components_UID='{comp[0]}'"
3743
                    cursor.execute(sql)
3744
                    attrs = cursor.fetchall()
3745
                    data = []
3746
                    for attr in attrs:
3747
                        data.append([attr['Name'], attr['Value']])
3748
                    if data:
3749
                        data.insert(0, ['Drawing Name', comp[1]])
3750
                        data.insert(0, ['UID', comp[0]])
3751
                        data.insert(0, ['Line No', comp[2]])
3752
                        result.append(data)
3753
                '''
3754

    
3755
                sql = 'select A.UID,A.[X],A.[Y],B.Name,A.Value as [Line No],D.[Name] as AttrN,C.[Value] as [AttrV] from Components A left join Drawings B on A.Drawings_UID=B.UID \
3756
                        left join LineNoAttributes C on A.[UID]=C.Components_UID left join LineProperties D on C.LineProperties_UID=D.UID'
3757
                if drawings is not None:
3758
                    doc_names = "','".join(drawings)
3759
                    sql += f" where A.Symbol_UID=1 and Drawings_UID in (select UID from Drawings where Name in ('{doc_names}'))"
3760
                cursor.execute(sql)
3761

    
3762
                comps = [[row['UID'], row['Name'], row['Line No'], row['AttrN'], row['AttrV'], row['X'], row['Y']] for row in cursor.fetchall()]
3763
                lineNos = {}
3764

    
3765
                for comp in comps:
3766
                    if comp[0] not in lineNos:
3767
                        lineNos[comp[0]] = [['Line No', comp[2]], ['UID', comp[0]], ['Drawing Name', comp[1]], ['X', str(comp[5])], ['Y', str(comp[6])]]
3768
                    lineNos[comp[0]].append([comp[3], comp[4]])
3769

    
3770
                result = list(lineNos.values())
3771

    
3772
            # catch the exception
3773
            except Exception as ex:
3774
                print('error occurred({}) in {}:{}'.format(ex, sys.exc_info()[-1].tb_frame.f_code.co_filename,
3775
                                                          sys.exc_info()[-1].tb_lineno))
3776

    
3777
        return result
3778

    
3779
    def get_equipment_data_list(self, drawings=None):
3780
        """ get equipment data list """
3781

    
3782
        result = []
3783

    
3784
        with self.project.database.connect() as conn:
3785
            try:
3786
                # Get a cursor object
3787
                cursor = conn.cursor()
3788

    
3789
                sql = "select A.UID,A.[X],A.[Y],B.NAME,C.SymbolType_UID,D.Type,C.NAME as symbol from Components A join Drawings B on A.Drawings_UID=B.UID\
3790
                        join Symbol C on A.Symbol_UID=C.UID\
3791
                        join SymbolType D on C.SymbolType_UID=D.UID\
3792
                        where (D.Category in ('Equipment') or A.Symbol_UID=7)"#,'Equipment Components')"
3793

    
3794
                if drawings is not None:
3795
                    doc_names = "','".join(drawings)
3796
                    sql += f" and A.Drawings_UID in (select UID from Drawings where Name in ('{doc_names}'))"
3797

    
3798
                cursor.execute(sql)
3799
                comps = [(row['UID'], row['NAME'], row['SymbolType_UID'], row['Type'], row['symbol'], row['X'], row['Y']) for row in cursor.fetchall()]
3800
                for comp in comps:
3801
                    sql = f"select distinct B.Attribute,A.Value from Attributes A left join SymbolAttribute B on " \
3802
                          f"A.SymbolAttribute_UID=B.UID where A.Components_UID='{comp[0]}'"
3803
                    cursor.execute(sql)
3804
                    attrs = cursor.fetchall()
3805
                    data = []
3806
                    for attr in attrs:
3807
                        data.append([attr['Attribute'], attr['Value']])
3808
                    if data:
3809
                        data.insert(0, ['Type', comp[3]])
3810
                        data.insert(0, ['Drawing Name', comp[1]])
3811
                        data.insert(0, ['ITEM_NO', comp[4]])
3812
                        data.insert(0, ['UID', comp[0]])
3813
                        data.insert(0, ['X', str(comp[5])])
3814
                        data.insert(0, ['Y', str(comp[6])])
3815
                        result.append(data)
3816

    
3817
            # catch the exception
3818
            except Exception as ex:
3819
                print('error occurred({}) in {}:{}'.format(ex, sys.exc_info()[-1].tb_frame.f_code.co_filename,
3820
                                                           sys.exc_info()[-1].tb_lineno))
3821

    
3822
        return result
3823

    
3824
    '''
3825
        @brief      set line data list
3826
        @author     kyouho
3827
        @date       2018.08.13
3828
    '''
3829
    def setLineDataList(self, dataLists):
3830
        conn = self.project.database.connect()
3831
        with conn:
3832
            try:
3833
                # Get a cursor object
3834
                cursor = conn.cursor()
3835

    
3836
                for data in dataLists:
3837
                    sql = "insert into LINE_DATA_LIST(UID, LINE_SIZE, LINE_SYMBOL, LINE_NO, LINE_CLASS, LINE_ROUTING_FROM, LINE_ROUTING_TO, SERVICE_FLUID, SERVICE_DENSITY, SERVICE_STATE, OPERATION_CONDITION_TEMP, OPERATION_CONDITION_PRESS, DESIGN_CONDITION_TEMP, DESIGN_CONDITION_PRESS, TEST_CONDITION_TEMP, TEST_CONDITION_PRESS, INSUL_CODE, PAINT_CODE, NDE_CODE, PWHT, PNID_NO) values(?, ?, ?, ?, ?, ?, ?, ?, ?, ?, ?, ?, ?, ?, ?, ?, ?, ?, ?, ?, ?)"
3838
                    param = tuple(data)
3839
                    cursor.execute(sql, param)
3840

    
3841
                conn.commit()
3842

    
3843
            # Catch the exception
3844
            except Exception as ex:
3845
                # Roll back any change if something goes wrong
3846
                conn.rollback()
3847

    
3848
                from App import App
3849
                message = f"error occurred({repr(ex)}) in {sys.exc_info()[-1].tb_frame.f_code.co_filename}:" \
3850
                          f"{sys.exc_info()[-1].tb_lineno}"
3851
                App.mainWnd().addMessage.emit(MessageType.Error, message)
3852

    
3853
    '''
3854
        @brief      delete line data list
3855
        @author     kyouho
3856
        @date       2018.08.13
3857
    '''
3858
    def deleteLineDataList(self, removeUID):
3859
        conn = self.project.database.connect()
3860
        with conn:
3861
            try:
3862
                # Get a cursor object
3863
                cursor = conn.cursor()
3864

    
3865
                for uid in removeUID:
3866
                    sql = "delete from LINE_DATA_LIST where uid = '{}'".format(uid)
3867
                    cursor.execute(sql)
3868

    
3869
                conn.commit()
3870

    
3871
            # Catch the exception
3872
            except Exception as ex:
3873
                # Roll back any change if something goes wrong
3874
                conn.rollback()
3875

    
3876
                from App import App
3877
                message = f"error occurred({repr(ex)}) in {sys.exc_info()[-1].tb_frame.f_code.co_filename}:" \
3878
                          f"{sys.exc_info()[-1].tb_lineno}"
3879
                App.mainWnd().addMessage.emit(MessageType.Error, message)
3880

    
3881
    '''
3882
        @brief      delete line data list
3883
        @author     kyouho
3884
        @date       2018.08.13
3885
    '''
3886
    def deleteLineDataList_LineNo(self, removeUID):
3887
        conn = self.project.database.connect()
3888
        with conn:
3889
            try:
3890
                # Get a cursor object
3891
                cursor = conn.cursor()
3892

    
3893
                for uid in removeUID:
3894
                    sql = "delete from LINE_DATA_LIST where LINE_NO = ?"
3895
                    param = (uid,)
3896
                    cursor.execute(sql, param)
3897

    
3898
                conn.commit()
3899

    
3900
            # Catch the exception
3901
            except Exception as ex:
3902
                # Roll back any change if something goes wrong
3903
                conn.rollback()
3904

    
3905
                from App import App
3906
                message = f"error occurred({repr(ex)}) in {sys.exc_info()[-1].tb_frame.f_code.co_filename}:" \
3907
                          f"{sys.exc_info()[-1].tb_lineno}"
3908
                App.mainWnd().addMessage.emit(MessageType.Error, message)
3909

    
3910
    '''
3911
        @brief      delete equip data list
3912
        @author     kyouho
3913
        @date       2018.08.14
3914
    '''
3915
    def deleteEquipDataList(self, removeUID):
3916
        conn = self.project.database.connect()
3917
        with conn:
3918
            try:
3919
                # Get a cursor object
3920
                cursor = conn.cursor()
3921

    
3922
                for uid in removeUID:
3923
                    sql = "delete from EQUIPMENT_DATA_LIST where uid = '{}'".format(uid)
3924
                    cursor.execute(sql)
3925

    
3926
                conn.commit()
3927

    
3928
            # Catch the exception
3929
            except Exception as ex:
3930
                # Roll back any change if something goes wrong
3931
                conn.rollback()
3932

    
3933
                from App import App
3934
                message = f"error occurred({repr(ex)}) in {sys.exc_info()[-1].tb_frame.f_code.co_filename}:" \
3935
                          f"{sys.exc_info()[-1].tb_lineno}"
3936
                App.mainWnd().addMessage.emit(MessageType.Error, message)
3937

    
3938
    '''
3939
        @brief      delete inst data list
3940
        @author     kyouho
3941
        @date       2018.08.14
3942
    '''
3943
    def deleteInstDataList(self, removeUID):
3944
        conn = self.project.database.connect()
3945
        with conn:
3946
            try:
3947
                # Get a cursor object
3948
                cursor = conn.cursor()
3949

    
3950
                for uid in removeUID:
3951
                    sql = "delete from INSTRUMENT_DATA_LIST where uid = '{}'".format(uid)
3952
                    cursor.execute(sql)
3953

    
3954
                conn.commit()
3955

    
3956
            # Catch the exception
3957
            except Exception as ex:
3958
                # Roll back any change if something goes wrong
3959
                conn.rollback()
3960

    
3961
                from App import App
3962
                message = f"error occurred({repr(ex)}) in {sys.exc_info()[-1].tb_frame.f_code.co_filename}:" \
3963
                          f"{sys.exc_info()[-1].tb_lineno}"
3964
                App.mainWnd().addMessage.emit(MessageType.Error, message)
3965

    
3966
    '''
3967
        @brief      delete note data list
3968
        @author     kyouho
3969
        @date       2018.10.10
3970
    '''
3971
    def deleteNoteDataList(self, removeUID):
3972
        conn = self.project.database.connect()
3973
        with conn:
3974
            try:
3975
                # Get a cursor object
3976
                cursor = conn.cursor()
3977

    
3978
                for uid in removeUID:
3979
                    sql = "delete from NOTE_DATA_LIST where uid = '{}'".format(uid)
3980
                    cursor.execute(sql)
3981

    
3982
                conn.commit()
3983

    
3984
            # Catch the exception
3985
            except Exception as ex:
3986
                # Roll back any change if something goes wrong
3987
                conn.rollback()
3988

    
3989
                from App import App
3990
                message = f"error occurred({repr(ex)}) in {sys.exc_info()[-1].tb_frame.f_code.co_filename}:" \
3991
                          f"{sys.exc_info()[-1].tb_lineno}"
3992
                App.mainWnd().addMessage.emit(MessageType.Error, message)
3993

    
3994
    def get_valve_attributes(self):
3995
        """ return valve attributes """
3996

    
3997
        from SymbolAttr import SymbolAttr
3998

    
3999
        res = None
4000
        if not hasattr(self, '_valve_attributes'):
4001
            self._valve_attributes = []
4002

    
4003
            with self.project.database.connect() as conn:
4004
                try:
4005
                    # Get a cursor object
4006
                    cursor = conn.cursor()
4007

    
4008
                    sql = "select distinct A.Attribute from SymbolAttribute A join SymbolType B on " \
4009
                          "A.SymbolType_UID=B.UID where B.Category = 'Piping'"
4010
                    cursor.execute(sql)
4011
                    rows = cursor.fetchall()
4012
                    for row in rows:
4013
                        attr = SymbolAttr()
4014
                        attr.Attribute = row['Attribute']
4015
                        self._valve_attributes.append(attr)
4016

    
4017
                    res = self._valve_attributes
4018
                # Catch the exception
4019
                except Exception as ex:
4020
                    from App import App
4021
                    message = 'error occurred({}) in {}:{}'.format(ex, sys.exc_info()[-1].tb_frame.f_code.co_filename,
4022
                                                                sys.exc_info()[-1].tb_lineno)
4023
                    App.mainWnd().addMessage.emit(MessageType.Error, message)
4024
        else:
4025
            res = self._valve_attributes
4026

    
4027
        return res
4028

    
4029
    def get_valve_data_list(self, drawings=None):
4030
        """get valve data list"""
4031

    
4032
        result = []
4033
        conn = self.project.database.connect()
4034
        with conn:
4035
            try:
4036
                # Get a cursor object
4037
                cursor = conn.cursor()
4038

    
4039
                sql = "select a.[UID],a.[X],a.[Y],D.Name,E.Name as 'Drawing Name',C.Attribute,B.Value,a.[Owner] from Components a " \
4040
                      "join Attributes B on a.UID=B.Components_UID " \
4041
                      "join SymbolAttribute C on B.SymbolAttribute_UID=C.UID " \
4042
                      "join Symbol D on a.Symbol_UID=D.UID " \
4043
                      "join Drawings E on a.Drawings_UID=E.UID " \
4044
                      "where a.Symbol_UID in (select UID from Symbol where SymbolType_UID in " \
4045
                      "(select UID from SymbolType where Category in ('Piping')))"
4046
                if drawings is not None:
4047
                    doc_names = "','".join(drawings)
4048
                    sql += f" and A.Drawings_UID in (select UID from Drawings where Name in ('{doc_names}'))"
4049

    
4050
                cursor.execute(sql)
4051
                rows = cursor.fetchall()
4052
                '''
4053
                for row in rows:
4054
                    matches = [res for res in result if res['UID'] == row['UID']]
4055
                    if matches:
4056
                        matches[0][row['Attribute']] = row['Value']
4057
                    else:
4058
                        data = {'UID': row['UID'], 'ITEM_NO': row['Name'], 'Drawing Name': row['Drawing Name'],
4059
                                'Owner': row['Owner'], row['Attribute']: row['Value']}
4060
                        result.append(data)
4061

4062
                '''
4063
                valves = {}
4064

    
4065
                for row in rows:
4066
                    if row['UID'] not in valves:
4067
                        valves[row['UID']] = {'UID': row['UID'], 'ITEM_NO': row['Name'], 'Drawing Name': row['Drawing Name'],
4068
                                'Owner': row['Owner'], 'X': str(row['X']), 'Y': str(row['Y'])}
4069
                    valves[row['UID']][row['Attribute']] = row['Value']
4070

    
4071
                result = list(valves.values())
4072

    
4073
            # Catch the exception
4074
            except Exception as ex:
4075
                from App import App
4076
                message = 'error occurred({}) in {}:{}'.format(ex, sys.exc_info()[-1].tb_frame.f_code.co_filename,
4077
                                                              sys.exc_info()[-1].tb_lineno)
4078
                App.mainWnd().addMessage.emit(MessageType.Error, message)
4079

    
4080
        return result
4081

    
4082
    def get_instrument_attributes(self):
4083
        """ return valve attributes """
4084

    
4085
        from SymbolAttr import SymbolAttr
4086

    
4087
        res = None
4088
        if not hasattr(self, '_inst_attributes'):
4089
            self._inst_attributes = []
4090

    
4091
            with self.project.database.connect() as conn:
4092
                try:
4093
                    # Get a cursor object
4094
                    cursor = conn.cursor()
4095

    
4096
                    sql = "select distinct A.Attribute from SymbolAttribute A join SymbolType B on " \
4097
                          "A.SymbolType_UID=B.UID where B.Category = 'Instrumentation'"
4098
                    cursor.execute(sql)
4099
                    rows = cursor.fetchall()
4100
                    for row in rows:
4101
                        attr = SymbolAttr()
4102
                        attr.Attribute = row['Attribute']
4103
                        self._inst_attributes.append(attr)
4104

    
4105
                    res = self._inst_attributes
4106
                # Catch the exception
4107
                except Exception as ex:
4108
                    from App import App
4109
                    message = 'error occurred({}) in {}:{}'.format(ex, sys.exc_info()[-1].tb_frame.f_code.co_filename,
4110
                                                                sys.exc_info()[-1].tb_lineno)
4111
                    App.mainWnd().addMessage.emit(MessageType.Error, message)
4112
        else:
4113
            res = self._inst_attributes
4114

    
4115
        return res
4116

    
4117
    '''
4118
        @brief      get instrument data list
4119
        @author     kyouho
4120
        @date       2018.08.14
4121
    '''
4122
    def get_instrument_data_list(self, drawings=None):
4123
        result = []
4124
        conn = self.project.database.connect()
4125
        with conn:
4126
            try:
4127
                # Get a cursor object
4128
                cursor = conn.cursor()
4129

    
4130
                sql = "select a.[UID],a.[X],a.[Y],D.Name,E.Name as 'Drawing Name',C.Attribute,B.Value,a.Symbol_UID,a.[Owner] from Components a " \
4131
                      "join Attributes B on a.UID=B.Components_UID " \
4132
                      "join SymbolAttribute C on B.SymbolAttribute_UID=C.UID " \
4133
                      "join Symbol D on a.Symbol_UID=D.UID " \
4134
                      "join Drawings E on a.Drawings_UID=E.UID " \
4135
                      "where a.Symbol_UID in (select UID from Symbol where SymbolType_UID in " \
4136
                      "(select UID from SymbolType where Category in ('Instrumentation')))"
4137
                if drawings is not None:
4138
                    doc_names = "','".join(drawings)
4139
                    sql += f" and A.Drawings_UID in (select UID from Drawings where Name in ('{doc_names}'))"
4140

    
4141
                cursor.execute(sql)
4142
                rows = cursor.fetchall()
4143
                '''
4144
                for row in rows:
4145
                    matches = [res for res in result if res['UID'] == row['UID']]
4146
                    if matches:
4147
                        matches[0][row['Attribute']] = row['Value']
4148
                    else:
4149
                        data = {'UID': row['UID'], 'ITEM_NO': row['Name'], 'Drawing Name': row['Drawing Name'], 'Owner': row['Owner'], 
4150
                                'Symbol_UID': int(row['Symbol_UID']), row['Attribute']: row['Value']}
4151
                        result.append(data)
4152
                '''
4153
                insts = {}
4154

    
4155
                for row in rows:
4156
                    if row['UID'] not in insts:
4157
                        insts[row['UID']] = {'UID': row['UID'], 'ITEM_NO': row['Name'], 'Drawing Name': row['Drawing Name'], 'Owner': row['Owner'], 
4158
                                'Symbol_UID': int(row['Symbol_UID']), 'X': str(row['X']), 'Y': str(row['Y'])}
4159
                    insts[row['UID']][row['Attribute']] = row['Value']
4160

    
4161
                result = list(insts.values())
4162
            # Catch the exception
4163
            except Exception as ex:
4164
                from App import App
4165
                message = 'error occurred({}) in {}:{}'.format(ex, sys.exc_info()[-1].tb_frame.f_code.co_filename,
4166
                                                              sys.exc_info()[-1].tb_lineno)
4167
                App.mainWnd().addMessage.emit(MessageType.Error, message)
4168

    
4169
        return result
4170

    
4171
    def get_note_attributes(self):
4172
        """ return note attributes """
4173

    
4174
        from SymbolAttr import SymbolAttr
4175

    
4176
        res = None
4177
        if not hasattr(self, '_note_attributes'):
4178
            self._note_attributes = []
4179

    
4180
            with self.project.database.connect() as conn:
4181
                try:
4182
                    # Get a cursor object
4183
                    cursor = conn.cursor()
4184

    
4185
                    sql = "select distinct A.Attribute from SymbolAttribute A join SymbolType B on " \
4186
                          "A.SymbolType_UID=B.UID where B.Category='General' and B.Type='Notes'"
4187
                    cursor.execute(sql)
4188
                    rows = cursor.fetchall()
4189
                    for row in rows:
4190
                        attr = SymbolAttr()
4191
                        attr.Attribute = row['Attribute']
4192
                        self._note_attributes.append(attr)
4193

    
4194
                    res = self._note_attributes
4195
                # Catch the exception
4196
                except Exception as ex:
4197
                    from App import App
4198
                    message = 'error occurred({}) in {}:{}'.format(ex, sys.exc_info()[-1].tb_frame.f_code.co_filename,
4199
                                                                sys.exc_info()[-1].tb_lineno)
4200
                    App.mainWnd().addMessage.emit(MessageType.Error, message)
4201
        else:
4202
            res = self._note_attributes
4203

    
4204
        return res
4205

    
4206
    def get_note_data_list(self, drawings=None):
4207
        """ get note data list """
4208
        result = []
4209

    
4210
        conn = self.project.database.connect()
4211
        with conn:
4212
            try:
4213
                # Get a cursor object
4214
                cursor = conn.cursor()
4215

    
4216
                sql = "select a.UID,D.Name,E.Name as 'Drawing Name',C.Attribute,B.Value from Components a " \
4217
                      "join Attributes B on a.UID=B.Components_UID " \
4218
                      "join SymbolAttribute C on B.SymbolAttribute_UID=C.UID " \
4219
                      "join Symbol D on a.Symbol_UID=D.UID " \
4220
                      "join Drawings E on a.Drawings_UID=E.UID " \
4221
                      "where a.Symbol_UID in (select UID from Symbol where SymbolType_UID in " \
4222
                      "(select UID from SymbolType where Category='General' and Type='Notes'))"
4223
                if drawings is not None:
4224
                    doc_names = "','".join(drawings)
4225
                    sql += f" and A.Drawings_UID in (select UID from Drawings where Name in ('{doc_names}'))"
4226

    
4227
                cursor.execute(sql)
4228
                rows = cursor.fetchall()
4229
                for row in rows:
4230
                    matches = [res for res in result if res['UID'] == row['UID']]
4231
                    if matches:
4232
                        matches[0][row['Attribute']] = row['Value']
4233
                    else:
4234
                        data = {'UID': row['UID'], 'ITEM_NO': row['Name'], 'Drawing Name': row['Drawing Name'],
4235
                                row['Attribute']: row['Value']}
4236
                        result.append(data)
4237
            # Catch the exception
4238
            except Exception as ex:
4239
                from App import App
4240
                message = 'error occurred({}) in {}:{}'.format(ex, sys.exc_info()[-1].tb_frame.f_code.co_filename,
4241
                                                              sys.exc_info()[-1].tb_lineno)
4242
                App.mainWnd().addMessage.emit(MessageType.Error, message)
4243

    
4244
        return result
4245

    
4246
    def clearAllDrawingDataFromDatabase(self):
4247
        """ clear all drawing data from database """
4248

    
4249
        sql = ''
4250

    
4251
        with self.project.database.connect() as conn:
4252
            try:
4253
                # Get a cursor object
4254
                cursor = conn.cursor()
4255

    
4256
                sql = "delete from LINE_DATA_LIST"
4257
                cursor.execute(sql)
4258
                sql = "delete from TitleBlockValues"
4259
                cursor.execute(sql)
4260
                sql = "delete from LineNoAttributes"
4261
                cursor.execute(sql)
4262
                sql = "delete from Attributes"
4263
                cursor.execute(sql)
4264
                sql = "delete from Associations"
4265
                cursor.execute(sql)
4266
                sql = "delete from Points"
4267
                cursor.execute(sql)
4268
                sql = "delete from PipeRunItems"
4269
                cursor.execute(sql)
4270
                sql = "delete from PipeRuns"
4271
                cursor.execute(sql)
4272
                sql = "delete from Components"
4273
                cursor.execute(sql)
4274
                sql = "delete from Stream_Line_List"
4275
                cursor.execute(sql)
4276
                sql = "delete from [Views]"
4277
                cursor.execute(sql)
4278
                sql = "delete from Drawings"
4279
                cursor.execute(sql)
4280
                sql = "delete from Libraries"
4281
                cursor.execute(sql)
4282

    
4283
                """
4284
                for drawing in drawings:
4285
                    sql = "delete from LINE_DATA_LIST where PNID_NO = '{}'".format(drawing.UID)
4286
                    cursor.execute(sql)
4287
                    sql = "delete from TitleBlockValues where Drawings_UID = '{}'".format(drawing.UID)
4288
                    cursor.execute(sql)
4289
                    sql = f"delete from LineNoAttributes where Components_UID in " \
4290
                                f"(select UID from Components where Drawings_UID='{drawing.UID}')"
4291
                    cursor.execute(sql)
4292
                    sql = f"delete from Attributes where Components_UID in " \
4293
                                f"(select UID from Components where Drawings_UID='{drawing.UID}')"
4294
                    cursor.execute(sql)
4295
                    sql = f"delete from Associations where Components_UID in " \
4296
                                f"(select UID from Components where Drawings_UID='{drawing.UID}')"
4297
                    cursor.execute(sql)
4298
                    sql = f"delete from Points where Components_UID in " \
4299
                                f"(select UID from Components where Drawings_UID='{drawing.UID}')"
4300
                    cursor.execute(sql)
4301
                    sql = f"delete from PipeRunItems where PipeRuns_UID in " \
4302
                                f"(select UID from PipeRuns where Drawings_UID='{drawing.UID}')"
4303
                    cursor.execute(sql)
4304
                    sql = f"delete from PipeRuns where Drawings_UID='{drawing.UID}'"
4305
                    cursor.execute(sql)
4306
                    sql = "delete from Components where Drawings_UID='{}'".format(drawing.UID)
4307
                    cursor.execute(sql)
4308
                    sql = "delete from Stream_Line_List where Drawing_UID='{}'".format(drawing.UID)
4309
                    cursor.execute(sql)
4310
                    sql = "delete from [Views] where Drawings_UID='{}'".format(drawing.UID)
4311
                    cursor.execute(sql)
4312
                    sql = "delete from Drawings where [UID]='{}'".format(drawing.UID)
4313
                    cursor.execute(sql)
4314

4315
                    # multi table delete not support in mssql
4316
                    ''' 
4317
                    sql = f"delete LINE_DATA_LIST, TitleBlockValues, LineNoAttributes, Attributes, Associations, Points, PipeRunItems, PipeRuns, Components, Stream_Line_List, [Views], Drawings " \
4318
                            f"from LINE_DATA_LIST a " \
4319
                            f"join TitleBlockValues b on a.PNID_NO = b.Drawings_UID " \
4320
                            f"join LineNoAttributes c on b.Drawings_UID = c.Drawings_UID " \
4321
                            f"join Attributes d on c.Drawings_UID = d.Drawings_UID " \
4322
                            f"join Associations e on d.Drawings_UID = e.Drawings_UID " \
4323
                            f"join Points f on e.Drawings_UID = f.Drawings_UID " \
4324
                            f"join PipeRunItems g on f.Drawings_UID = g.Drawings_UID " \
4325
                            f"join PipeRuns h on g.Drawings_UID = h.Drawings_UID " \
4326
                            f"join Components i on h.Drawings_UID = i.Drawings_UID " \
4327
                            f"join Stream_Line_List j on i.Drawings_UID = j.Drawing_UID " \
4328
                            f"join [Views] k on j.Drawing_UID = k.Drawings_UID " \
4329
                            f"join Drawings l on k.Drawings_UID = l.[UID] " \
4330
                            f"where l.[uid] = '{drawing.UID}'"
4331
                    cursor.execute(sql)
4332
                    '''
4333
                """
4334

    
4335
                if self.project.database.db_type == 'SQLite':
4336
                    cursor.execute('commit')
4337
                else:
4338
                    conn.commit()
4339

    
4340
                # Catch the exception
4341
            except Exception as ex:
4342
                # Roll back any change if something goes wrong
4343
                conn.rollback()
4344

    
4345
                from App import App
4346
                message = 'error occurred({}\\n{}) in {}:{}'.format(repr(ex), sql,
4347
                                                                    sys.exc_info()[-1].tb_frame.f_code.co_filename,
4348
                                                                    sys.exc_info()[-1].tb_lineno)
4349
                App.mainWnd().addMessage.emit(MessageType.Error, message)
4350

    
4351
    def checkDatabaseCascade(self):
4352
        if self.project.database.db_type == 'SQLite':
4353
            return True
4354
        
4355
        #configs = self.getConfigs('Database', 'Cascade')
4356
        #if 1 == len(configs):
4357
        #    return True
4358
        
4359
        with self.project.database.connect() as conn:
4360
            try:
4361
                # Get a cursor object
4362
                cursor = conn.cursor()
4363
                sql = "select * from INFORMATION_SCHEMA.REFERENTIAL_CONSTRAINTS where DELETE_RULE ='CASCADE'"
4364
                cursor.execute(sql)
4365
                rows = cursor.fetchall()
4366
                if rows:
4367
                    return True
4368
                else:
4369
                    return False
4370

    
4371
            # Catch the exception
4372
            except Exception as ex:
4373
                from App import App
4374
                message = f"error occurred({repr(ex)}) in {sys.exc_info()[-1].tb_frame.f_code.co_filename}:" \
4375
                          f"{sys.exc_info()[-1].tb_lineno}"
4376
                App.mainWnd().addMessage.emit(MessageType.Error, message)
4377
        
4378
        return False
4379

    
4380
    def setDatabaseCascade(self):
4381
        # temp not finished
4382
        with self.project.database.connect() as conn:
4383
            try:
4384
                # Get a cursor object
4385
                cursor = conn.cursor()
4386
                sql = "select * from INFORMATION_SCHEMA.REFERENTIAL_CONSTRAINTS "
4387
                cursor.execute(sql)
4388
                rows = cursor.fetchall()
4389
                if rows:
4390
                    return True
4391
                else:
4392
                    return False
4393

    
4394
            # Catch the exception
4395
            except Exception as ex:
4396
                # Roll back any change if something goes wrong
4397
                conn.rollback()
4398

    
4399
                from App import App
4400
                message = 'error occurred({}\\n{}) in {}:{}'.format(repr(ex), sql,
4401
                                                                    sys.exc_info()[-1].tb_frame.f_code.co_filename,
4402
                                                                    sys.exc_info()[-1].tb_lineno)
4403
                App.mainWnd().addMessage.emit(MessageType.Error, message)
4404

    
4405

    
4406
    def saveToDatabase(self, items, rect: QRectF, show_progress=None):
4407
        """ save given items to database """
4408
        import uuid
4409

    
4410
        # delete all datas of current drawing
4411
        drawing_name = self.activeDrawing.name
4412
        drawing_uid = self.activeDrawing.UID
4413
        sql = ''
4414

    
4415
        isCascade = self.checkDatabaseCascade()
4416

    
4417
        queries = {'first': [], 'second': []}
4418
        for item in items:
4419
            if hasattr(item, 'toSql_return_separately'):
4420
                sql, sqlLater = item.toSql_return_separately()
4421
                queries['first'].append(sql)
4422
                queries['second'].append(sqlLater)
4423
            else:
4424
                queries['first'].append(item.toSql())
4425

    
4426
        """
4427
        # Drawing Cascade test
4428
        if self.project.database.db_type != 'SQLite':
4429
            ''' update drawing's modified time for MSSQL '''
4430
            drawings = self.getDrawings()
4431
            drawing = [drawing for drawing in drawings if self.imgName == os.path.splitext(drawing.name)[0]]
4432
            if drawing[0]:
4433
                drawing[0].datetime = datetime.now().strftime('%Y-%m-%d %H:%M:%S')
4434

4435
            ''' hmb backup '''
4436
            #from_to = self.get_stream_from_to(drawing_uid = self.activeDrawing.UID)
4437
        """
4438

    
4439
        with self.project.database.connect() as conn:
4440
            try:
4441
                # Get a cursor object
4442
                cursor = conn.cursor()
4443
                if self.project.database.db_type == 'SQLite':
4444
                    #import timeit
4445
                    #_start = timeit.default_timer()
4446
                    cursor.execute('begin')
4447

    
4448
                    sql = "delete from LINE_DATA_LIST where PNID_NO = '{}'".format(drawing_name)
4449
                    cursor.execute(sql)
4450

    
4451
                    sql = "delete from TitleBlockValues where Drawings_UID = '{}'".format(drawing_uid)
4452
                    cursor.execute(sql)
4453

    
4454
                    # delete LineNoAttributes
4455
                    sql = f"delete from LineNoAttributes where Components_UID in " \
4456
                        f"(select UID from Components where Drawings_UID='{drawing_uid}')"
4457
                    cursor.execute(sql)
4458

    
4459
                    # delete Attributes
4460
                    sql = f"delete from Attributes where Components_UID in " \
4461
                        f"(select UID from Components where Drawings_UID='{drawing_uid}')"
4462
                    cursor.execute(sql)
4463

    
4464
                    # delete Associations
4465
                    sql = f"delete from Associations where Components_UID in " \
4466
                        f"(select UID from Components where Drawings_UID='{drawing_uid}')"
4467
                    cursor.execute(sql)
4468

    
4469
                    # delete Points
4470
                    sql = f"delete from Points where Components_UID in " \
4471
                        f"(select UID from Components where Drawings_UID='{drawing_uid}')"
4472
                    cursor.execute(sql)
4473

    
4474
                    # delete PipeRunItems
4475
                    sql = f"delete from PipeRunItems where PipeRuns_UID in " \
4476
                        f"(select UID from PipeRuns where Drawings_UID='{drawing_uid}')"
4477
                    cursor.execute(sql)
4478

    
4479
                    # delete PipeRuns
4480
                    sql = f"delete from PipeRuns where Drawings_UID='{drawing_uid}'"
4481
                    cursor.execute(sql)
4482

    
4483
                    # delete Components 
4484
                    sql = "delete from Components where Drawings_UID='{}'".format(drawing_uid)
4485
                    cursor.execute(sql)
4486

    
4487
                    # delete Stream Line List
4488
                    sql = "delete from Stream_Line_List where Drawing_UID='{}'".format(drawing_uid)
4489
                    cursor.execute(sql)
4490
                    #_stop = timeit.default_timer()
4491
                    #seconds = _stop - _start
4492
                    #print(seconds)
4493
                else:
4494
                    #import timeit
4495
                    #_start = timeit.default_timer()
4496
                    if not isCascade:
4497
                        sql = f"delete from LINE_DATA_LIST where PNID_NO = '{drawing_name}'" \
4498
                            f"delete from TitleBlockValues where Drawings_UID = '{drawing_uid}'" \
4499
                            f"delete from LineNoAttributes where Components_UID in " \
4500
                            f"(select UID from Components where Drawings_UID='{drawing_uid}')" \
4501
                            f"delete from Attributes where Components_UID in " \
4502
                            f"(select UID from Components where Drawings_UID='{drawing_uid}')" \
4503
                            f"delete from Associations where Components_UID in " \
4504
                            f"(select UID from Components where Drawings_UID='{drawing_uid}')" \
4505
                            f"delete from Points where Components_UID in " \
4506
                            f"(select UID from Components where Drawings_UID='{drawing_uid}')" \
4507
                            f"delete from PipeRunItems where PipeRuns_UID in " \
4508
                            f"(select UID from PipeRuns where Drawings_UID='{drawing_uid}')" \
4509
                            f"delete from PipeRuns where Drawings_UID='{drawing_uid}'" \
4510
                            f"delete from Components where Drawings_UID='{drawing_uid}'" \
4511
                            f"delete from Stream_Line_List where Drawing_UID='{drawing_uid}'"
4512
                        cursor.execute(sql)
4513
                        #_stop = timeit.default_timer()
4514
                        #seconds = _stop - _start
4515
                        #print(seconds)
4516
                    else:
4517
                        sql = f"delete from LINE_DATA_LIST where PNID_NO = '{drawing_name}'" \
4518
                            f"delete from TitleBlockValues where Drawings_UID = '{drawing_uid}'" \
4519
                            f"delete from Components where Drawings_UID='{drawing_uid}'" \
4520
                            f"delete from Stream_Line_List where Drawing_UID='{drawing_uid}'"
4521
                        cursor.execute(sql)
4522

    
4523
                        '''
4524
                        sql = f"delete from Drawings where [UID] = '{drawing_uid}'"
4525
                        cursor.execute(sql)
4526

4527
                        sql = self.project.database.to_sql(
4528
                            'insert into Drawings(UID, [NAME], [DATETIME], [OCCUPIED], [Image]) values(?, ?, ?, ?, ?)')
4529
                        param = tuple([str(drawing[0].UID), drawing[0].name, drawing[0].datetime, os.environ['COMPUTERNAME'], None])
4530
                        cursor.execute(sql, param)
4531
                        _stop = timeit.default_timer()
4532
                        seconds = _stop - _start
4533
                        print(seconds)
4534
                        '''
4535
                
4536
                progress = 0
4537
                length = len(queries['first']) + len(queries['second'])
4538
                for sql in queries['first']:
4539
                    if type(sql) is list:
4540
                        for item in sql:
4541
                            if item is not None and 2 == len(item):
4542
                                cursor.executemany(self.project.database.to_sql(item[0]), item[1])
4543
                    else:
4544
                        if sql is not None and 2 == len(sql):
4545
                            cursor.executemany(self.project.database.to_sql(sql[0]), sql[1])
4546

    
4547
                    if show_progress:
4548
                        show_progress.emit(int((progress / length)*100))
4549
                    progress += 1
4550

    
4551
                for sql in queries['second']:
4552
                    if type(sql) is list:
4553
                        for item in sql:
4554
                            if item is not None and 2 == len(item):
4555
                                cursor.executemany(self.project.database.to_sql(item[0]), item[1])
4556
                    else:
4557
                        if sql is not None and 2 == len(sql):
4558
                            cursor.executemany(self.project.database.to_sql(sql[0]), sql[1])
4559

    
4560
                    if show_progress:
4561
                        show_progress.emit(int((progress / length)*100))
4562
                    progress += 1
4563

    
4564
                # save Stream No Line List
4565
                index = 1
4566
                for model_data in self._streamLineListModelDatas:
4567
                    sql = f"insert into Stream_Line_List (UID, Drawing_UID, PnIDNumber, Tag_Seq_No, PipingMaterialsClass, InsulationPurpose, FluidCode, " \
4568
                          f"UnitNumber, NominalDiameter, [From], [To], Stream_No, [Case], [Index]) values(?,?,?,?,?,?,?,?,?,?,?,?,?,?)"
4569
                    sql = self.project.database.to_sql(sql)
4570
                    params = (str(uuid.uuid4()), drawing_uid, model_data['PnIDNumber'], model_data['Tag Seq No'], model_data['PipingMaterialsClass'], model_data['InsulationPurpose'], \
4571
                              model_data['FluidCode'], model_data['UnitNumber'], model_data['NominalDiameter'], model_data['FROM'], model_data['TO'], model_data['Stream No'], model_data['Case'], index)
4572
                    cursor.execute(sql, params)
4573
                    index += 1
4574

    
4575
                if show_progress:
4576
                    show_progress.emit(99)
4577

    
4578
                if self.project.database.db_type == 'SQLite':
4579
                    cursor.execute('commit')
4580
                else:
4581
                    conn.commit()
4582
            # Catch the exception
4583
            except Exception as ex:
4584
                # Roll back any change if something goes wrong
4585
                conn.rollback()
4586

    
4587
                from App import App
4588
                message = 'error occurred({}\\n{}) in {}:{}'.format(repr(ex), sql,
4589
                                                                    sys.exc_info()[-1].tb_frame.f_code.co_filename,
4590
                                                                    sys.exc_info()[-1].tb_lineno)
4591
                App.mainWnd().addMessage.emit(MessageType.Error, message)
4592

    
4593
        if rect:
4594
            self.activeDrawing.view_rect = rect
4595
            self.update_view_region(self.activeDrawing)
4596

    
4597
    def update_view_region(self, drawing):
4598
        """update view region"""
4599
        with self.project.database.connect() as conn:
4600
            try:
4601
                # Get a cursor object
4602
                cursor = conn.cursor()
4603

    
4604
                # check if there is view region
4605
                sql = f"select Drawings_UID from Views where Drawings_UID=?"
4606
                params = (drawing.UID,)
4607
                cursor.execute(self.project.database.to_sql(sql), params)
4608
                rows = cursor.fetchall()
4609
                if rows:
4610
                    sql = f"update Views set X=?,Y=?,Width=?,Height=? where Drawings_UID=?"
4611
                    params = (drawing.view_rect.x(), drawing.view_rect.y(),
4612
                              drawing.view_rect.width(), drawing.view_rect.height(), drawing.UID)
4613
                else:
4614
                    sql = f"insert into Views(Drawings_UID,X,Y,Width,Height) values(?,?,?,?,?)"
4615
                    params = (drawing.UID, drawing.view_rect.x(), drawing.view_rect.y(),
4616
                              drawing.view_rect.width(), drawing.view_rect.height())
4617

    
4618
                sql = self.project.database.to_sql(sql)
4619
                cursor.execute(sql, params)
4620
                conn.commit()
4621
            # Catch the exception
4622
            except Exception as ex:
4623

    
4624
                from App import App
4625
                message = 'error occurred({}\\n{}) in {}:{}'.format(repr(ex), sql,
4626
                                                                    sys.exc_info()[-1].tb_frame.f_code.co_filename,
4627
                                                                    sys.exc_info()[-1].tb_lineno)
4628
                App.mainWnd().addMessage.emit(MessageType.Error, message)
4629

    
4630
    '''
4631
        @brief      set equipment data list
4632
        @author     humkyung
4633
        @date       2018.05.03
4634
    '''
4635
    def setEquipmentDataList(self, dataList):
4636
        conn = self.project.database.connect()
4637
        with conn:
4638
            try:
4639
                # Get a cursor object
4640
                cursor = conn.cursor()
4641

    
4642
                for data in dataList:
4643
                    sql = "insert into EQUIPMENT_DATA_LIST(UID, ITEM_NO, SERVICE, NO_REQ, FLUID, DESC_OF_PART, OPERATION_CONDITION_TEMP, OPERATION_CONDITION_PRESS, DESIGN_CONDITION_TEMP, DESIGN_CONDITION_PRESS, MATERIAL, WEIGHT, POWER, INSULATION, PNID_NO, REV) values(?, ?, ?, ?, ?, ?, ?, ?, ?, ?, ?, ?, ?, ?, ?, ?)"
4644
                    param = tuple(data)
4645
                    cursor.execute(self.project.database.to_sql(sql), param)
4646
                conn.commit()
4647
            # Catch the exception
4648
            except Exception as ex:
4649
                # Roll back any change if something goes wrong
4650
                conn.rollback()
4651

    
4652
                from App import App
4653
                message = 'error occurred({}) in {}:{}'.format(ex, sys.exc_info()[-1].tb_frame.f_code.co_filename,
4654
                                                              sys.exc_info()[-1].tb_lineno)
4655
                App.mainWnd().addMessage.emit(MessageType.Error, message)
4656

    
4657
    '''
4658
        @brief      set instrumnet data list
4659
        @author     kyoyho
4660
        @date       2018.08.14
4661
    '''
4662
    def setInstrumentDataList(self, dataList):
4663
        conn = self.project.database.connect()
4664
        with conn:
4665
            try:
4666
                # Get a cursor object
4667
                cursor = conn.cursor()
4668

    
4669
                for data in dataList:
4670
                    sql = "insert into INSTRUMENT_DATA_LIST(UID, ITEM_NO, SERVICE, FLOW_RATE, PRESSURE, TEMPERATURE, TPYE, RANGE, NOR_LEVEL_MM, NOR_LEVEL_PERCENT, DEL_PRESS, SHUT_OFF, LOCATION, PNID_NO, REV) values(?, ?, ?, ?, ?, ?, ?, ?, ?, ?, ?, ?, ?, ?, ?)"
4671
                    param = tuple(data)
4672
                    cursor.execute(sql, param)
4673
                conn.commit()
4674

    
4675
            # Catch the exception
4676
            except Exception as ex:
4677
                # Roll back any change if something goes wrong
4678
                conn.rollback()
4679

    
4680
                from App import App
4681
                message = 'error occurred({}) in {}:{}'.format(ex, sys.exc_info()[-1].tb_frame.f_code.co_filename,
4682
                                                              sys.exc_info()[-1].tb_lineno)
4683
                App.mainWnd().addMessage.emit(MessageType.Error, message)
4684

    
4685
    def getDrawings(self):
4686
        """ get drawings """
4687
        from Drawing import Drawing
4688

    
4689
        res = []
4690

    
4691
        with self.project.database.connect() as conn:
4692
            try:
4693
                cursor = conn.cursor()
4694
                if self.project.database.db_type == 'SQLite':
4695
                    sql = 'select UID, [NAME], [DATETIME], IFNULL(B.[X], 0) as X, IFNULL(B.[Y], 0) as Y, ' \
4696
                          'IFNULL(B.[Width], 0) as Width, IFNULL(B.[Height], 0) as Height from Drawings A ' \
4697
                          'left join Views B on A.UID = B.Drawings_UID'
4698
                else:
4699
                    sql = 'select UID, [NAME], [DATETIME], ISNULL(B.[X], 0) as X, ISNULL(B.[Y], 0) as Y, ' \
4700
                          'ISNULL(B.[Width], 0) as Width, ISNULL(B.[Height], 0) as Height from Drawings A ' \
4701
                          'left join Views B on A.UID = B.Drawings_UID'
4702

    
4703
                cursor.execute(self.project.database.to_sql(sql))
4704
                for row in cursor.fetchall():
4705
                    rect = QRectF(float(row['X']), float(row['Y']), float(row['Width']), float(row['Height']))
4706
                    res.append(Drawing(row['UID'], row['NAME'], row['DATETIME'], rect))
4707
            # Catch the exception
4708
            except Exception as ex:
4709
                from App import App
4710
                message = 'error occurred({}) in {}:{}'.format(repr(ex), sys.exc_info()[-1].tb_frame.f_code.co_filename,
4711
                                                              sys.exc_info()[-1].tb_lineno)
4712
                App.mainWnd().addMessage.emit(MessageType.Error, message)
4713

    
4714
        return res
4715

    
4716
    def saveDrawings(self, drawings):
4717
        """save given drawings"""
4718

    
4719
        import uuid
4720

    
4721
        if not drawings:
4722
            return
4723

    
4724
        with self.project.database.connect() as conn:
4725
            try:
4726
                # Get a cursor object
4727
                cursor = conn.cursor()
4728
                if self.project.database.db_type == 'SQLite':
4729
                    cursor.execute('begin')
4730

    
4731
                for drawing in drawings:
4732
                    if drawing.UID is None:
4733
                        # get image data
4734
                        image_blob_data = None
4735
                        #file_path = os.path.join(self.project.getDrawingFilePath(), drawing.name)
4736
                        #if drawing.name and os.path.isfile(file_path):
4737
                        #    with open(file_path.encode('utf-8'), 'rb') as file:
4738
                        #        image_blob_data = file.read()
4739
                        # up to here
4740

    
4741
                        sql = self.project.database.to_sql(
4742
                            'insert into Drawings(UID, [NAME], [DATETIME], [Image]) values(?, ?, ?, ?)')
4743
                        param = tuple([str(uuid.uuid4()), drawing.name, '', image_blob_data])
4744
                        drawing.UID = param[0]
4745
                    else:
4746
                        sql = self.project.database.to_sql("update Drawings set [NAME]=?,[DATETIME]=? where UID=?")
4747
                        param = (drawing.name, drawing.datetime, str(drawing.UID))
4748
                        #param = (drawing.name, drawing.datetime, image_blob_data, str(drawing.UID))
4749

    
4750
                    cursor.execute(sql, param)
4751

    
4752
                if self.project.database.db_type == 'SQLite':
4753
                    cursor.execute('commit')
4754
                else:
4755
                    conn.commit()
4756
            # Catch the exception
4757
            except Exception as ex:
4758
                # Roll back any change if something goes wrong
4759
                conn.rollback()
4760

    
4761
                from App import App
4762
                message = 'error occurred({}) in {}:{}'.format(repr(ex), sys.exc_info()[-1].tb_frame.f_code.co_filename,
4763
                                                              sys.exc_info()[-1].tb_lineno)
4764
                App.mainWnd().addMessage.emit(MessageType.Error, message)
4765

    
4766
    '''
4767
        @brief  get IsOriginDetect ComboBox Items
4768
    '''
4769
    def getIsOriginDetectComboBoxItems(self):
4770
        return [("원본 도면", 0), ("텍스트 제거 도면", 1)]
4771

    
4772
    '''
4773
        @brief  get IsOriginDetect ComboBox Items
4774
    '''
4775
    def getOcrOptionComboBoxItems(self):
4776
        return [("OCR 미적용", 0), ("일반 심볼", 1), ("Instrument 계통", 2)]
4777

    
4778
    '''
4779
        @brief      Return Symbol Type Items
4780
        @author     Jeongwoo
4781
        @date       18.04.20
4782
        @history    18.05.08    Jeongwoo type index changed
4783
    '''
4784
    def getSymbolTypeList(self):
4785
        symbolTypeList = []
4786

    
4787
        with self.project.database.connect() as conn:
4788
            cursor = conn.cursor()
4789
            sql = 'SELECT * FROM SymbolType ORDER BY Type ASC'
4790
            try:
4791
                cursor.execute(sql)
4792
                rows = cursor.fetchall()
4793
                for row in rows:
4794
                    symbolTypeList.append((row['UID'], row['Category'], row['Type']))  # UID, category, type
4795
            except Exception as ex:
4796
                from App import App
4797
                message = 'error occurred({}) in {}:{}'.format(ex, sys.exc_info()[-1].tb_frame.f_code.co_filename,
4798
                                                              sys.exc_info()[-1].tb_lineno)
4799
                App.mainWnd().addMessage.emit(MessageType.Error, message)
4800

    
4801
        return symbolTypeList
4802

    
4803
    def getSymbolCategoryByType(self, type: str):
4804
        """get symbol category by using symbol type"""
4805
        category = None
4806
        if type in self._symbolType:
4807
            return self._symbolType[type]
4808

    
4809
        with self.project.database.connect() as conn:
4810
            try:
4811
                cursor = conn.cursor()
4812
                sql = self.project.database.to_sql('SELECT Category FROM SymbolType WHERE [Type] = ?')
4813
                cursor.execute(sql, (type,))
4814
                rows = cursor.fetchall()
4815
                if rows is not None and len(rows) > 0:
4816
                    category = rows[0]['Category']
4817
                    self._symbolType[type] = category
4818
            except Exception as ex:
4819
                print('error occurred({}) in {}:{}'.format(ex, sys.exc_info()[-1].tb_frame.f_code.co_filename,
4820
                                                          sys.exc_info()[-1].tb_lineno))
4821

    
4822
        return category
4823

    
4824
    '''
4825
        @brief      Check Symbol Type is included in 'Equipment' Category
4826
        @author     Jeongwoo
4827
        @date       2018.05.09
4828
    '''
4829
    def isEquipmentType(self, type):
4830
        category = self.getSymbolCategoryByType(type)
4831
        return category is not None and category == 'Equipment'
4832

    
4833
    '''
4834
        @brief      Return Symbol Type Items with "None"
4835
        @author     Jeongwoo
4836
        @date       18.04.06
4837
        @history    Seperate SymbolTypeList and "None"
4838
    '''
4839
    def getSymbolTypeComboBoxItems(self):
4840
        symbolTypeList = [symbol_type for symbol_type in self.getSymbolTypeList() if symbol_type[1]]
4841
        symbolTypeList.insert(0, ('None', 'None', 'None'))
4842

    
4843
        return symbolTypeList
4844

    
4845
    '''
4846
        @brief  get Base Symbol ComboBox Items
4847
    '''
4848
    def getBaseSymbolComboBoxItems(self, type=None):
4849
        bsymbolNameList = self.getSymbolNameListByType(type)
4850
        bsymbolNameList = bsymbolNameList.copy()
4851
        bsymbolNameList.sort()
4852
        bsymbolNameList.insert(0, "None")
4853
        return bsymbolNameList
4854

    
4855
    '''
4856
        @brief  get Additional Symbol ComboBox Items
4857
    '''
4858
    def getAdditionalSymbolComboBoxItems(self):
4859
        asymbolNameList = self.getSymbolNameList()
4860
        asymbolNameList.sort()
4861
        asymbolNameList.insert(0, "None")
4862
        return asymbolNameList
4863

    
4864
    '''
4865
        @brief  get Additional Symbol's default direction ComboBox Items
4866
    '''
4867
    def getDefaultSymbolDirectionComboBoxItems(self):
4868
        return [("UP", 0), ("DOWN", 2), ("LEFT", 3), ("RIGHT", 1)]
4869

    
4870
    '''
4871
        @brief  getter of activeDrawing
4872
        @author humkyung
4873
        @date   2018.07.07
4874
    '''
4875
    @property
4876
    def activeDrawing(self):
4877
        return self._activeDrawing
4878

    
4879
    '''
4880
        @brief  setter of activeDrawing
4881
        @author humkyung
4882
        @date   2018.07.07
4883
    '''
4884
    @activeDrawing.setter
4885
    def activeDrawing(self, value):
4886
        if self._activeDrawing:
4887
            del self._activeDrawing
4888

    
4889
        self._activeDrawing = value
4890

    
4891
    def getColNames(self, table):
4892
        """ return column names of given table and attribute names if tabe is VALVE_DATA_LIST or EQUIPMET_DATA_LIST """
4893
        res = None
4894

    
4895
        conn = self.project.database.connect()
4896
        with conn:
4897
            try:
4898
                cursor = conn.cursor()
4899
                cursor.execute('select * from {}'.format(table))
4900
                res = [col_name[0] for col_name in cursor.description]
4901

    
4902
                if table == 'EQUIPMET_DATA_LIST' or table == 'VALVE_DATA_LIST':
4903
                    sql = 'select distinct c.Attribute from {} a left join Attributes b on a.uid=b.Components_UID ' \
4904
                          'left join SymbolAttribute c on b.SymbolAttribute_UID=c.UID where c.Attribute is not NULL'.format(
4905
                        table)
4906
                    cursor.execute(sql)
4907
                    rows = cursor.fetchall()
4908
                    for row in rows:
4909
                        res.append(row['Attribute'])
4910
            # Catch the exception
4911
            except Exception as ex:
4912
                print('error occurred({}) in {}:{}'.format(ex, sys.exc_info()[-1].tb_frame.f_code.co_filename,
4913
                                                          sys.exc_info()[-1].tb_lineno))
4914

    
4915
        return res
4916

    
4917

    
4918
    def get_ext_apps(self):
4919
        """get external application information from App.db"""
4920

    
4921
        path = os.path.join(os.getenv('USERPROFILE'), 'Digital PID')
4922
        app_database_path = os.path.join(path, 'App.db')
4923
        with sqlite3.connect(app_database_path) as conn:
4924
            try:
4925
                conn.row_factory = sqlite3.Row
4926
                cursor = conn.cursor()
4927
                sql = 'select * from ExtApps'
4928
                cursor.execute(sql)
4929
                rows = cursor.fetchall()
4930
                return rows
4931
            except Exception as ex:
4932
                # Roll back any change if something goes wrong
4933
                conn.rollback()
4934

    
4935
                from App import App
4936
                message = f"error occurred({repr(ex)}) in {sys.exc_info()[-1].tb_frame.f_code.co_filename}:" \
4937
                          f"{sys.exc_info()[-1].tb_lineno}"
4938
                App.mainWnd().addMessage.emit(MessageType.Error, message)
4939

    
4940
        return None
4941

    
4942
    def set_ext_apps(self, model:QStandardItemModel) -> None:
4943
        """ save ext apps to database """
4944

    
4945
        path = os.path.join(os.getenv('USERPROFILE'), 'Digital PID')
4946
        app_database_path = os.path.join(path, 'App.db')
4947
        with sqlite3.connect(app_database_path) as conn:
4948
            try:
4949
                # Get a cursor object
4950
                cursor = conn.cursor()
4951

    
4952
                names = ','.join([f"'{model.item(row, 0).text()}'" for row in range(model.rowCount())])
4953
                sql = f"delete from ExtApps where [Name] not in (?)"
4954
                cursor.execute(sql, (names, ))
4955

    
4956
                for row in range(model.rowCount()):
4957
                    param = (model.item(row, 0).text(), model.item(row, 1).text(), model.item(row, 2).text())
4958

    
4959
                    sql = "insert into ExtApps([Name], Executable, Argument) select ?,?,? where not exists" \
4960
                          "(select [Name] from ExtApps where [Name]=?)"
4961
                    cursor.execute(sql, (param[0], param[1], param[2], param[0]))
4962

    
4963
                    sql = f"update ExtApps set Executable=?, Argument=? where [Name]=?"
4964
                    cursor.execute(sql, (param[1], param[2], param[0]))
4965

    
4966
                conn.commit()
4967
            # Catch the exception
4968
            except Exception as ex:
4969
                conn.rollback()
4970

    
4971
                from App import App
4972
                message = f'error occurred({ex}) in {sys.exc_info()[-1].tb_frame.f_code.co_filename}:' \
4973
                          f'{sys.exc_info()[-1].tb_lineno}'
4974
                App.mainWnd().addMessage.emit(MessageType.Error, message)
4975

    
4976
        return None
4977

    
4978
    '''
4979
        @brief  getter of OCRData
4980
        @author humkyung
4981
        @date   2018.11.19
4982
    '''
4983
    @property
4984
    def OCRData(self):
4985
        if self._OCRData is None:
4986
            configs = self.getConfigs('Text Recognition', 'OCR Data')
4987
            self._OCRData = configs[0].value if 1 == len(configs) else 'eng'
4988

    
4989
        return self._OCRData
4990

    
4991
    '''
4992
        @brief  setter of OCRData
4993
        @author humkyung
4994
        @date   2018.11.19
4995
    '''
4996
    @OCRData.setter
4997
    def OCRData(self, value):
4998
        self._OCRData = value
4999

    
5000

    
5001
if __name__ == '__main__':
5002
    from AppDocData import AppDocData
5003

    
5004
    instance = AppDocData.instance()
클립보드 이미지 추가 (최대 크기: 500 MB)