프로젝트

일반

사용자정보

통계
| 개정판:

hytos / DTI_PID / DTI_PID / QSymbolEditorDialog.py @ d52b3462

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

1
# coding: utf-8
2
from PyQt5 import QtCore, QtGui, QtWidgets
3
from PyQt5.QtWidgets import *
4
from PyQt5.QtGui import *
5
from QtImageViewer import QtImageViewer
6
import os
7
import sqlite3
8
import sys
9
import SG_DbHelper
10
import symbol, SymbolBase
11
import potrace
12

    
13
import UI_SymbolEditor
14
from AppDocData import AppDocData
15

    
16

    
17
sys.path.insert(0, os.path.dirname(os.path.realpath(__file__)) + '\\Commands')
18
import CropCommand, HandCommand, ZoomCommand, PenCommand, EraserCommand, AreaEraserCommand, OriginalPointCommand, ConnectionPointCommand
19

    
20

    
21
class QSymbolEditorDialog(QDialog):
22
    FILE_NUMBER = 0
23

    
24
    def __init__(self, parent, image, project):
25
        QDialog.__init__(self, parent)
26
        self.image = image
27
        self.project = project
28
        self.ui = UI_SymbolEditor.Ui_Dialog()
29
        self.ui.setupUi(self)
30
        self.setupImageViewer()
31
        self.setupTools()
32
        self.initForms()
33
        self.initContents()
34
        self.isAccepted = False
35
        self.dbHelper = SG_DbHelper.SG_DbHelper(self.project.getPath())
36

    
37
    '''
38
        @brief  Set up QtImageViewer and QImage
39
    '''
40
    def setupImageViewer(self):
41
        x = self.ui.imageViewContainer.x()
42
        y = self.ui.imageViewContainer.y()
43
        width = self.ui.imageViewContainer.frameGeometry().width()
44
        height = self.ui.imageViewContainer.frameGeometry().height()
45
        self.ui.imageView = QtImageViewer()
46
        self.ui.imageView.setGeometry(QtCore.QRect(0, y, height, height))
47
        self.ui.imageView.aspectRatioMode = QtCore.Qt.KeepAspectRatio
48
        self.ui.imageView.setHorizontalScrollBarPolicy(QtCore.Qt.ScrollBarAsNeeded)
49
        self.ui.imageView.setVerticalScrollBarPolicy(QtCore.Qt.ScrollBarAsNeeded)
50
        self.ui.imageView.canZoom = True
51
        self.ui.imageView.canPan = True
52
        image = self.image.copy()
53
        self.imgW = image.width()
54
        self.imgH = image.height()
55
        image = image.scaled(self.imgW, self.imgH)
56
        self.ui.imageView.setImage(image)
57
        self.ui.imageViewerContainerLayout.addWidget(self.ui.imageView)
58

    
59
    '''
60
        @brief  Set up Hand, Crop, ETC Tools
61
    '''
62
    def setupTools(self):
63
        self.ui.handButton.clicked.connect(self.handToolClickEvent)
64
        self.ui.penButton.clicked.connect(self.penToolClickEvent)
65
        self.ui.penWidthSpinBox.valueChanged.connect(self.penWidthChangedEvent)
66
        self.ui.eraserButton.clicked.connect(self.eraserToolClickEvent)
67
        self.ui.eraserSpinBox.valueChanged.connect(self.eraserWidthChangedEvent)
68
        self.ui.areaEraserButton.clicked.connect(self.areaEraserToolClickEvent)
69
        self.ui.zoomButton.clicked.connect(self.zoomToolClickEvent)
70
        self.ui.initZoomButton.clicked.connect(self.zoomInitToolClickEvent)
71
        self.ui.guidelineCheckbox.stateChanged.connect(self.guidelineStateChangedEvent)
72
        #self.ui.additionalSymbolListWidget.keyPressEvent.connect(self.additionalSymbolListKeyPressEvent)
73
        #self.ui.connectionPointList.keyPressEvent.connect(self.additionalSymbolListKeyPressEvent)
74

    
75
    '''
76
        @brief  Init Forms with type and default values
77
    '''
78
    def initForms(self):
79
        self.ui.idLineEdit.setValidator(QRegExpValidator(QtCore.QRegExp("^[1-9]\d+$")))
80
        self.ui.thresholdLineEdit.setValidator(QRegExpValidator(QtCore.QRegExp("^[0-9]\d+$"))) # ([0-1]{1}[.])?[0-9]+
81
        self.ui.minMatchPointLineEdit.setValidator(QRegExpValidator(QtCore.QRegExp("^[0-9]\d+$")))
82
        self.initIsOriginDetectComboBoxItems()
83
        self.initOcrOptionComboBoxItems()
84
        self.initDefaultSymbolDirectionComboBoxItems()
85
        self.ui.addAdditionalSymbolButton.clicked.connect(self.addAdditionalSymbol)
86
        self.ui.addOriginalPointButton.clicked.connect(self.addOriginalPoint)
87
        self.ui.addConnectionPointButton.clicked.connect(self.addConnectionPoint)
88
        self.initBaseSymbolComboBoxItems()
89
        self.initAdditionalSymbolComboBoxItems()
90
        
91
    '''
92
        @brief  Set data on forms, For modifying symbol
93
    '''
94
    def initContents(self):
95
        self.ui.targetDBLineEdit.setText(self.project.getPath()+'/db/ITI_PID.db')
96
        #self.ui.isOriginDetectComboBox
97
        #self.ui.ocrOptionComboBox
98
        #self.ui.baseSymbolComboBox
99
        #self.initBaseSymbolComboBoxItems()
100
        #self.ui.defaultSymbolDirectionComboBox
101
        #self.ui.additionalSymbolComboBox
102

    
103
    '''
104
        @brief  Init ComboBox Items For DB Field [IsDetectOrigin]
105
    '''
106
    def initIsOriginDetectComboBoxItems(self):
107
        self.ui.isOriginDetectComboBox.addItem("원본 도면", 0)
108
        self.ui.isOriginDetectComboBox.addItem("텍스트 제거 도면", 1)
109

    
110
    '''
111
        @brief  Init ComboBox Items For DB Field [OcrOption]
112
    '''
113
    def initOcrOptionComboBoxItems(self):
114
        self.ui.ocrOptionComboBox.addItem("OCR 미적용", 0)
115
        self.ui.ocrOptionComboBox.addItem("일반 심볼", 1)
116
        self.ui.ocrOptionComboBox.addItem("Instrument 계통", 2)
117
        
118
    '''
119
        @brief  Init ComboBox Items For Direction of DB Field [additionalSymbol]
120
    '''
121
    def initDefaultSymbolDirectionComboBoxItems(self):
122
        self.ui.defaultSymbolDirectionComboBox.addItem("UP", 0)
123
        self.ui.defaultSymbolDirectionComboBox.addItem("DOWN", 2)
124
        self.ui.defaultSymbolDirectionComboBox.addItem("LEFT", 3)
125
        self.ui.defaultSymbolDirectionComboBox.addItem("RIGHT", 1)
126
        
127
    '''
128
        @brief  Init ComboBox Items For DB Field [baseSymbol]
129
    '''
130
    def initBaseSymbolComboBoxItems(self):
131
        symbolNameList = AppDocData.instance().getSymbolNameList()
132
        symbolNameList.sort()
133
        symbolNameList.insert(0, "None")
134
        for name in symbolNameList:
135
            self.ui.baseSymbolComboBox.addItem(name)
136
            
137
    '''
138
        @brief  Init ComboBox Items For symbolName of DB Field [additionalSymbol]
139
    '''
140
    def initAdditionalSymbolComboBoxItems(self):
141
        symbolNameList = AppDocData.instance().getSymbolNameList()
142
        symbolNameList.sort()
143
        symbolNameList.insert(0, "None")
144
        for name in symbolNameList:
145
            self.ui.additionalSymbolComboBox.addItem(name)
146
    
147
    '''
148
        @brief  remove ConnectionPoint Circles (Using for loop)
149
    '''
150
    def removeConnectionPointCircles(self, circlePointList):
151
        for circlePoint in circlePointList:
152
            self.removeConnectionPointCircle(circlePoint)
153
            
154
    '''
155
        @brief  remove each ConnectionPoint Circle
156
    '''
157
    def removeConnectionPointCircle(self, circlePoint):
158
        self.ui.imageView.scene.removeItem(self.ui.imageView.scene.itemAt(QtCore.QPointF(int(circlePoint.x()), int(circlePoint.y())), QTransform()))
159
        
160
    '''
161
        @brief  Display this QDialog
162
    '''
163
    def showDialog(self):
164
        self.setWindowFlags(self.windowFlags() & ~QtCore.Qt.WindowContextHelpButtonHint)
165
        self.show()
166
        self.exec_()
167
        return self.isAccepted
168
    
169
    '''
170
        @brief  Using input [Name], make file name
171
                If the [Name] exists, add number like [FILE_NAME(1), FILE_NAME(2), ...]
172
                Recursive function
173
    '''
174
    def makeFileName(self, originName, newName):
175
        imageFolderDir = self.project.getPath() + "\\image"
176
        imageDir = imageFolderDir + "\\" + newName + ".png"
177
        svgFolderDir = self.project.getPath() + "\\svg"
178
        svgDir = svgFolderDir + "\\" + newName + ".svg"
179
        if (os.path.exists(imageDir)) or (self.dbHelper.isExistFileName(imageDir) or (os.path.exists(svgDir))):
180
            self.FILE_NUMBER = self.FILE_NUMBER + 1
181
            imgName = originName + "({})".format(self.FILE_NUMBER)
182
            return self.makeFileName(originName, imgName)
183
        else:
184
            return newName
185
        
186
    '''
187
        @brief  Make symbol object for saving on DB
188
    '''
189
    def makeSymbolData(self):
190
        symId = self.ui.idLineEdit.text()
191
        name = self.ui.nameLineEdit.text()
192
        type = '' #Empty
193
        self.FILE_NUMBER = 0
194
        fileName = self.makeFileName(name, name)
195
        path = self.project.getPath() + "\\image\\" + fileName + ".png"
196
        threshold = self.ui.thresholdLineEdit.text()
197
        minMatchPoint = self.ui.minMatchPointLineEdit.text()
198
        isDetectOnOrigin = self.ui.isOriginDetectComboBox.currentData()
199
        rotationCount = self.ui.rotationCountSpinBox.value()
200
        ocrOption = self.ui.ocrOptionComboBox.currentData()
201
        isContainChild = 1 if self.ui.isContainChildCheckBox.isChecked() else 0
202
        originalPoint = self.ui.originalPointLineEdit.text()
203
        connectionPoint = self.makeConnectionPointListString()
204
        baseSymbol = self.ui.baseSymbolComboBox.currentText()
205
        additionalSymbol = self.makeAdditionalSymbolListString()
206

    
207
        convertedThreshold = int(threshold) / 100.0
208

    
209
        newSym = symbol.SymbolBase(int(symId), fileName, type, path, convertedThreshold, int(minMatchPoint), isDetectOnOrigin
210
                                   , rotationCount, ocrOption, isContainChild, originalPoint, connectionPoint, baseSymbol, additionalSymbol)
211

    
212
        return newSym
213
    
214
    '''
215
        @brief  Make AdditionalSymbol String
216
                [AdditionalSymbolString = DIRECTION,SYMBOL_NAME/DIRECTION,SYMBOL_NAME/...]
217
    '''
218
    def makeAdditionalSymbolListString(self):
219
        ret = ""
220
        listItems = []
221
        for index in range(self.ui.additionalSymbolListWidget.count()):
222
            listItems.append(self.ui.additionalSymbolListWidget.item(index))
223
        if listItems is not None:
224
            for index in range(len(listItems)):
225
                item = listItems[index]
226
                text = item.text()
227
                if index != 0:
228
                    ret = ret + "/"
229
                ret = ret + text
230
        return ret
231
    
232
    '''
233
        @brief  Make ConnectionPoint String
234
                [ConnectionPointString = x1,y1/x2,y2/...]
235
    '''
236
    def makeConnectionPointListString(self):
237
        ret = ""
238
        listItems = []
239
        for index in range(self.ui.connectionPointList.count()):
240
            listItems.append(self.ui.connectionPointList.item(index))
241
        if listItems is not None:
242
            for index in range(len(listItems)):
243
                item = listItems[index]
244
                text = item.text()
245
                if index != 0:
246
                    ret = ret + "/"
247
                ret = ret + text
248
        return ret
249
    
250
    '''
251
        @brief  Called when Save Button Clicked
252
                Validation Check → Make Symbol Data → Insert Symbol Data into DB → Save png and svg files
253
    '''
254
    def accept(self):
255
        print("save")
256

    
257
        isValid, exceptionMsg = self.isValidSymbolInfo()
258
        if isValid:
259
            print("valid symbol info")
260
            isAdded, fileName, imagePath = self.dbHelper.insertSymbol(self.makeSymbolData())
261

    
262
            if isAdded:
263
                try:
264
                    image = self.ui.imageView.image()
265
                    if image is not None:
266
                        image.save(imagePath, 'PNG')
267
                        potrace.convertImageToSvg(imagePath, self.project.getPath()+"/svg/" + fileName + ".svg")
268
                        self.isAccepted = True
269
                        QDialog.accept(self)
270
                except:
271
                    self.resetInsertSymbol(imagePath, fileName)
272
                    self.isAccepted = False
273
                    QMessageBox.about(self.ui.buttonBox, "알림", "심볼 저장 과정 중 문제가 발생했습니다.")
274
            else:
275
                QMessageBox.about(self.ui.buttonBox, "알림", "심볼 저장 과정 중 문제가 발생했습니다.")
276
        else:
277
            print("invalid symbol info")
278
            QMessageBox.about(self.ui.buttonBox, "알림", exceptionMsg)
279
            
280
    '''
281
        @brief  Called When Cancel Button Clicked
282
    '''
283
    def cancel(self):
284
        print("cancel")
285
        self.isAccepted = Flase
286
        QDialog.cancel(self)
287
        
288
    '''
289
        @brief  Called When error occured while saving png and svg files
290
                Delete png, svg files and record from DB
291
    '''
292
    def resetInsertSymbol(self, imagePath, fileName):
293
        if os.path.exists(imagePath):
294
            os.remove(imagePath)
295

    
296
        svgPath = self.project.getPath()+"/svg/" + fileName + ".svg"
297
        if os.path.exists(svgPath):
298
            os.remove(svgPath)
299

    
300
        AppDocData.instance().deleteSymbol(imagePath)
301

    
302
    def keyPressEvent(self, event):
303
        if event.key() == QtCore.Qt.Key_Delete:
304
            if self.ui.connectionPointList.hasFocus():
305
                selectedItems = self.ui.connectionPointList.selectedItems()
306
                if selectedItems is not None:
307
                    for item in selectedItems:
308
                        text = item.text()
309
                        x = int(text.split(",")[0])
310
                        y = int(text.split(",")[1])
311
                        self.removeConnectionPointCircle(QtCore.QPointF(x, y))
312
                        self.ui.connectionPointList.takeItem(self.ui.connectionPointList.row(item))
313
            elif self.ui.additionalSymbolListWidget.hasFocus():
314
                selectedItems = self.ui.additionalSymbolListWidget.selectedItems()
315
                if selectedItems is not None:
316
                    for item in selectedItems:
317
                        self.ui.additionalSymbolListWidget.takeItem(self.ui.additionalSymbolListWidget.row(item))
318
                        
319
    '''
320
        @brief  Hand Tool Button Clicked
321
    '''
322
    def handToolClickEvent(self, event):
323
        print("hand tool clicked")
324
        self.ui.imageView.command = HandCommand.HandCommand(self.ui.imageView)
325
                         
326
    '''
327
        @brief  Zoom Init Tool Button Clicked
328
    '''
329
    def zoomInitToolClickEvent(self, event):
330
        print("zoom init tool clicked")
331
        self.ui.imageView.command = None
332
        self.ui.imageView.zoomImageInit()
333
                         
334
    '''
335
        @brief  Zoom Tool Button Clicked
336
    '''
337
    def zoomToolClickEvent(self, event):
338
        print("zoom tool clicked")
339
        self.ui.imageView.command = ZoomCommand.ZoomCommand(self.ui.imageView)
340
                         
341
    '''
342
        @brief  Pen Tool Button Clicked
343
    '''
344
    def penToolClickEvent(self, event):
345
        print("Pen")
346
        width = self.ui.toolWidget.findChild(QSpinBox, 'penWidthSpinBox').value()
347
        self.ui.imageView.command = PenCommand.PenCommand(self.ui.imageView)
348
        self.ui.imageView.command.width = width
349
                         
350
    '''
351
        @brief  Pen Width Value Changed
352
    '''
353
    def penWidthChangedEvent(self, value):
354
        print("Pen Width " + str(value))
355
        if self.ui.imageView.command is not None and type(self.ui.imageView.command) is PenCommand.PenCommand:
356
            self.ui.imageView.command.width = value
357
                 
358
    '''
359
        @brief  Eraser Tool Button Clicked
360
    '''
361
    def eraserToolClickEvent(self, event):
362
        print("eraser")
363
        width = self.ui.toolWidget.findChild(QSpinBox, 'eraserSpinBox').value()
364
        self.ui.imageView.command = EraserCommand.EraserCommand(self.ui.imageView)
365
        self.ui.imageView.command.width = width
366
                         
367
    '''
368
        @brief  Eraser Width Value Changed
369
    '''
370
    def eraserWidthChangedEvent(self, value):
371
        print("eraser " + str(value))
372
        if self.ui.imageView.command is not None and type(self.ui.imageView.command) is EraserCommand.EraserCommand:
373
            self.ui.imageView.command.width = value
374
                             
375
    '''
376
        @brief  Area Eraser Tool Button Clicked
377
    '''
378
    def areaEraserToolClickEvent(self, event):
379
        print("area eraser")
380
        self.ui.imageView.command = AreaEraserCommand.AreaEraserCommand(self.ui.imageView)
381
                         
382
    '''
383
        @brief  Guideline Check State Changed
384
    '''
385
    def guidelineStateChangedEvent(self, value):
386
        if self.ui.guidelineCheckbox.isChecked():
387
            self.ui.imageView.showGuideline(True)
388
        else:
389
            self.ui.imageView.showGuideline(False)
390
                             
391
    '''
392
        @brief  Add AdditionalSymbol String on ListWidget
393
    '''
394
    def addAdditionalSymbol(self, event):
395
        print("addAdditionalSymbol")
396
        additionalSymbolIndex = self.ui.additionalSymbolComboBox.currentIndex()
397
        if additionalSymbolIndex != 0:
398
            print("Symbol Selected")
399
            direction = self.ui.defaultSymbolDirectionComboBox.currentText()
400
            symbolName = self.ui.additionalSymbolComboBox.currentText()
401
            text = "{},{}".format(direction, symbolName)
402

    
403
            if self.isAlreadyAdded(text):
404
                QMessageBox.about(self.ui.buttonBox, "알림", "이미 추가된 아이템입니다.")
405
            else:
406
                self.ui.additionalSymbolListWidget.addItem(text)
407
                                 
408
    '''
409
        @brief  Check the text is already added
410
    '''
411
    def isAlreadyAdded(self, text):
412
        for index in range(self.ui.additionalSymbolListWidget.count()):
413
            item = self.ui.additionalSymbolListWidget.item(index)
414
            if item.text() == text:
415
                return True
416
        return False
417
                     
418
    '''
419
        @brief  Original Point Tool Button Clicked
420
    '''
421
    def addOriginalPoint(self, event):
422
        print("addOriginalPoint")
423
        self.ui.imageView.command = OriginalPointCommand.OriginalPointCommand(self.ui.imageView, self.ui.originalPointLineEdit)
424
                         
425
    '''
426
        @brief  Connection Point Tool Button Clicked
427
    '''
428
    def addConnectionPoint(self, event):
429
        print("addConnectionPoint")
430
        self.ui.imageView.command = ConnectionPointCommand.ConnectionPointCommand(self.ui.imageView, self.ui.connectionPointLineEdit, self.ui.connectionPointList)
431
                         
432
    '''
433
        @brief  Validation Check
434
        @return (isValid, errorMsg)
435
    '''
436
    def isValidSymbolInfo(self):
437
        print("isValid")
438
        EXCEPTION_MSG_FORMAT = "{} 입력을 확인해주세요."
439
        EXCEPTION_MSG_DUPLICATED_FORMAT = "이미 저장된 {} 값입니다."
440
        infoTitle = ""
441

    
442
        idText = self.ui.idLineEdit.text()
443
        id = int(idText) if idText else -1
444
        if (id == -1 or id < 100):
445
            infoTitle = self.ui.idLabel.text()
446
            return (False, EXCEPTION_MSG_FORMAT.format(infoTitle))
447

    
448
        if self.dbHelper.isExistData('symId', id):
449
            infoTitle = self.ui.idLabel.text()
450
            return (False, EXCEPTION_MSG_DUPLICATED_FORMAT.format(infoTitle))
451

    
452
        if not self.ui.nameLineEdit.text():
453
            infoTitle = self.ui.nameLabel.text()
454
            return (False, EXCEPTION_MSG_FORMAT.format(infoTitle))
455

    
456
        thresholdText = self.ui.thresholdLineEdit.text()
457
        threshold = float(thresholdText) if thresholdText else -1
458
        if not(threshold >= 0 and threshold <= 100):
459
            infoTitle = self.ui.thresholdLabel.text()
460
            return (False, EXCEPTION_MSG_FORMAT.format(infoTitle))
461
            
462
        minMatchPointText = self.ui.minMatchPointLineEdit.text()
463
        minMatchPoint = float(minMatchPointText) if minMatchPointText else -1
464
        if not(minMatchPoint >= 0):
465
            infoTitle = self.ui.minMatchPointLabel.text()
466
            return (False, EXCEPTION_MSG_FORMAT.format(infoTitle))
467

    
468
        if self.ui.baseSymbolComboBox.currentIndex() == 0: #default value(None) index
469
            infoTitle = self.ui.baseSymbolLabel.text()
470
            return (False, EXCEPTION_MSG_FORMAT.format(infoTitle))
471

    
472
        #Additional Symbol is Nullable
473

    
474
        if not self.ui.originalPointLineEdit.text() or self.ui.imageView.isOriginalPointSelected == False:
475
            infoTitle = self.ui.originalPointLabel.text()
476
            return (False, EXCEPTION_MSG_FORMAT.format(infoTitle))
477

    
478
        if not (self.ui.connectionPointList.count() > 0):
479
            infoTitle = self.ui.connectionPointLabel.text()
480
            return (False, EXCEPTION_MSG_FORMAT.format(infoTitle))
481
            
482
        return True, None
클립보드 이미지 추가 (최대 크기: 500 MB)