프로젝트

일반

사용자정보

개정판 5c058438

ID5c058438859d165191ab7bced9775f714e1e9068
상위 69222bff
하위 3bfd7094, 7036b370, b13fd95b, b4415fb6

백흠경이(가) 약 5년 전에 추가함

issue #366: Undo/Redo for creating

Change-Id: I56deb68073c4a4da2951ce6536ea5f086aee6bbf

차이점 보기:

DTI_PID/DTI_PID/Commands/CreateCommand.py
1
# coding: utf-8
2
""" This is create command module """
1 3
import copy
2
import AbstractCommand
3
from PyQt5.QtCore import pyqtSignal, QObject
4
from PyQt5.QtWidgets import QGraphicsView, QGraphicsScene, QFileDialog, QGraphicsItem, QAbstractGraphicsShapeItem
4
from PyQt5.QtCore import *
5
from PyQt5.QtGui import *
6
from PyQt5.QtWidgets import *
5 7

  
6
class CreateCommand(AbstractCommand.AbstractCommand):
7
    templateCreated = pyqtSignal(QAbstractGraphicsShapeItem)
8 8

  
9
    def __init__(self, imageViewer, shape):
10
        AbstractCommand.AbstractCommand.__init__(self, imageViewer)
11
        self.name = 'Create'
12
        self.template = shape
9
class CreateCommand(QUndoCommand):
10
    def __init__(self, scene, items, parent=None):
11
        super(CreateCommand, self).__init__(parent)
12
        self._scene = scene
13
        self._items = items
14
        self._created = True
13 15

  
14
    '''
15
        @brief  create a shape by using template
16
    '''
17
    def execute(self, param):
18
        if self.template in self.imageViewer.scene().items():
19
            pass
20
        else:
21
            self.imageViewer.scene().addItem(self.template)
22

  
23
        self.template.process(param)
24

  
25
        if self.template.isCreated == True:
26
            instance = self.template.clone()
27
            self.imageViewer.scene().removeItem(self.template)
28
            self.template.init()
29
            self.imageViewer.scene().update()
30

  
31
            self.templateCreated.emit(instance)
32

  
33
            return instance
34
        else:
35
            self.imageViewer.scene().update()
36

  
37
        self.isTreated = False
38
        
39
        return None
40
    
41
    '''
42
        @brief  undo
43
    '''
44 16
    def undo(self):
45
        pass
17
        """undo"""
18
        for item in self._items:
19
            item.transfer.onRemoved.emit(item)
20
        self._created = False
46 21

  
47
    '''
48
        @brief  redo
49
    '''
50 22
    def redo(self):
51
        pass
52
        
23
        """redo"""
24

  
25
        if not self._created:
26
            for item in self._items:
27
                self._scene.addItem(item)
28
        self._created = True
29

  
DTI_PID/DTI_PID/Commands/PlaceLineCommand.py
31 31
        self.imageViewer.setCursor(QCursor(Qt.CrossCursor))
32 32

  
33 33
        self._polyline = None
34
        self._line_type = None
34 35

  
35
    '''
36
        @brief      reset command status
37
        @author     humkyung
38
        @date       2018.07.23
39
    '''
36
    @property
37
    def line_type(self):
38
        return self._line_type
40 39

  
41 40
    def reset(self):
41
        """reset command status"""
42 42
        self._polyline = None
43
        self._line_type = None
43 44

  
44 45
    '''
45 46
        @brief      place a line
......
65 66
                    if selected is not None and type(selected) is QEngineeringConnectorItem:
66 67
                        self._polyline = QEngineeringPolylineItem()
67 68
                        self._polyline._vertices.append(selected.center())
69

  
70
                        # get line type
71
                        if type(selected.parentItem()) is QEngineeringLineItem:
72
                            self._line_type = selected.parentItem().lineType
73
                        elif issubclass(type(selected.parentItem()), SymbolSvgItem):
74
                            for idx, conn in enumerate(selected.parentItem().connectors):
75
                                if selected is conn:
76
                                    self._line_type = selected.parentItem().conn_type[idx]
77
                                    break
78
                        # up to here
79

  
68 80
                        self.imageViewer.scene().addItem(self._polyline)
69 81
                        self.imageViewer.scene().setFocusItem(self._polyline)
70 82
                    elif selected is not None and type(selected) is QEngineeringLineItem:
......
76 88
                        if (pt is not None) and (type(pt) == shapely.geometry.point.Point):
77 89
                            self._polyline = QEngineeringPolylineItem()
78 90
                            self._polyline._vertices.append([pt.x, pt.y])
91
                            self._line_type = selected.lineType
79 92
                            self.imageViewer.scene().addItem(self._polyline)
80 93
                            self.imageViewer.scene().setFocusItem(self._polyline)
81 94
                else:
DTI_PID/DTI_PID/Commands/ReplaceCommand.py
1
# coding: utf-8
2
""" This is replace command module """
3
import os.path
4
import sys
5
from SymbolSvgItem import SymbolSvgItem
6
from EngineeringErrorItem import QEngineeringErrorItem
7
from PyQt5.QtCore import *
8
from PyQt5.QtGui import *
9
from PyQt5.QtWidgets import *
10

  
11

  
12
class ReplaceCommand(QUndoCommand):
13
    def __init__(self, scene, source, target, parent=None):
14
        from SymbolSvgItem import SymbolSvgItem
15

  
16
        super(ReplaceCommand, self).__init__(parent)
17
        self._scene = scene
18
        self._source = source
19
        self._target = target
20
        self._replaced = True
21

  
22
    def undo(self):
23
        """undo"""
24

  
25
        self._scene.addItem(self._source)
26
        self._target.transfer.onRemoved.emit(self._target)
27
        self._scene.update()
28

  
29
        self._replaced = False
30

  
31
    def redo(self):
32
        """redo"""
33

  
34
        if not self._replaced:
35
            self._scene.addItem(self._target)
36
            self._source.transfer.onRemoved.emit(self._source)
37
            self._scene.update()
DTI_PID/DTI_PID/Commands/RotateCommand.py
10 10

  
11 11

  
12 12
class RotateCommand(QUndoCommand):
13
    def __init__(self, scene, items, angle = None, parent=None):
13
    def __init__(self, scene, items, angle=None, parent=None):
14 14
        from SymbolSvgItem import SymbolSvgItem
15 15

  
16 16
        super(RotateCommand, self).__init__(parent)
17 17
        self._scene = scene
18 18
        self._items = [item for item in items if issubclass(type(item), SymbolSvgItem) and
19 19
                       type(self) is not QEngineeringErrorItem]
20
        self._params = [angle]*len(items) if angle else None
21
        self._rotated = True if angle else False
20
        self._params = [angle]*len(items) if angle is not None else None
21
        self._rotated = True if angle is not None else False
22 22

  
23 23
    def undo(self):
24 24
        """undo"""
......
38 38
        if not self._rotated:
39 39
            _params = []
40 40
            for idx, item in enumerate(self._items):
41
                _params.append(item.rotation())
42
                item.rotate(math.radians((_params[idx] + 90) % 360))
41
                angle = item.rotation()
42
                _params.append(angle)
43
                item.rotate(math.radians((angle + 90) % 360 if angle in [0, 90, 180, 270, 360] else 0))
43 44

  
44 45
            self._params = _params
45 46
            self._scene.update()
DTI_PID/DTI_PID/MainWindow.py
9 9

  
10 10
sys.path.insert(0, os.path.dirname(os.path.realpath(__file__)))
11 11
sys.path.insert(0, os.path.join(os.path.dirname(os.path.realpath(__file__)), 'Commands'))
12
import CreateCommand
12
from CreateCommand import CreateCommand
13 13
import CropCommand
14 14
import AreaOcrCommand
15 15
import CreateSymbolCommand
......
1686 1686

  
1687 1687
                detector = LineDetector(None)
1688 1688

  
1689
                lineType = self.lineComboBox.currentText()
1689
                line_type = self.actionLine.tag.line_type if self.actionLine.tag.line_type else \
1690
                    self.lineComboBox.currentText()
1690 1691
                for index in range(count - 1):
1691 1692
                    start = self.actionLine.tag._polyline._vertices[index]
1692 1693
                    end = self.actionLine.tag._polyline._vertices[index + 1]
1693 1694

  
1694 1695
                    lineItem = QEngineeringLineItem(vertices=[start, end])
1695 1696
                    lineItem.transfer.onRemoved.connect(self.itemRemoved)
1696
                    lineItem.lineType = lineType
1697
                    lineItem.lineType = line_type
1697 1698
                    if items:
1698 1699
                        lineItem.connect_if_possible(items[-1], 5)
1699 1700
                    else:
......
1720 1721
                    else:
1721 1722
                        detector.connectLineToLine(selected[0], items[-1], 5)
1722 1723

  
1724
                app_doc_data.scene.undo_stack.push(CreateCommand(app_doc_data.scene, items))
1723 1725
        finally:
1724 1726
            self.graphicsView.scene().removeItem(self.actionLine.tag._polyline)
1725 1727
            self.actionLine.tag.reset()
......
1919 1921
                svg = self.graphicsView.createSymbolObject(symName)
1920 1922
                self.graphicsView.matchSymbolToLine(svg, scenePos)
1921 1923

  
1922
                if old_symbol:
1924
                if old_symbol and svg:
1925
                    from ReplaceCommand import ReplaceCommand
1926

  
1927
                    app_doc_data = AppDocData.instance()
1928

  
1929
                    cmd = ReplaceCommand(app_doc_data.scene, old_symbol, svg)
1930
                    app_doc_data.scene.undo_stack.push(cmd)
1923 1931
                    return
1924 1932
            elif event.key() == Qt.Key_J:
1925 1933
                # insert and connect symbol item that is selected symbol in tree to selected symbol
DTI_PID/DTI_PID/QtImageViewer.py
683 683
                    svg.angle = angle
684 684
            '''
685 685

  
686
            x, y = connectors[0].sceneBoundingRect().center().x() + dx, connectors[
687
                0].sceneBoundingRect().center().y() + dy
686
            x, y = connectors[0].sceneBoundingRect().center().x() + dx, \
687
                   connectors[0].sceneBoundingRect().center().y() + dy
688 688
            svg.loc = [x - svg.symbolOrigin[0], y - svg.symbolOrigin[1]]
689 689
            svg.origin = [x, y]
690
            svg.addSvgItemToScene(self.scene())
690
            svg.addSvgItemToScene(self.scene(), True)
691 691

  
692 692
            items = [item for item in self.scene().items(scenePos) if
693 693
                     type(item) is not QGraphicsPixmapItem and type(item) is not QGraphicsTextItem]
......
738 738
                    connectors[0].connect(svg)
739 739
                    #items[0].highlight(False)
740 740

  
741
            svg.addSvgItemToScene(self.scene())
741
            svg.addSvgItemToScene(self.scene(), True)
742 742

  
743 743
        # svg.reSettingConnetors()
744 744

  
DTI_PID/DTI_PID/RotateSymbol_UI.py
1 1
# -*- coding: utf-8 -*-
2 2

  
3
# Form implementation generated from reading ui file './UI/RotateSymbol.ui'
3
# Form implementation generated from reading ui file '.\UI\RotateSymbol.ui'
4 4
#
5
# Created by: PyQt5 UI code generator 5.11.3
5
# Created by: PyQt5 UI code generator 5.13.0
6 6
#
7 7
# WARNING! All changes made in this file will be lost!
8 8

  
9

  
9 10
from PyQt5 import QtCore, QtGui, QtWidgets
10 11

  
12

  
11 13
class Ui_RotateSymbolDialog(object):
12 14
    def setupUi(self, RotateSymbolDialog):
13 15
        RotateSymbolDialog.setObjectName("RotateSymbolDialog")
......
48 50
        self.label_2.setObjectName("label_2")
49 51
        self.formLayout.setWidget(2, QtWidgets.QFormLayout.LabelRole, self.label_2)
50 52
        self.doubleSpinBoxX = QtWidgets.QDoubleSpinBox(RotateSymbolDialog)
53
        self.doubleSpinBoxX.setEnabled(False)
51 54
        self.doubleSpinBoxX.setDecimals(1)
52 55
        self.doubleSpinBoxX.setMaximum(99999999.0)
53 56
        self.doubleSpinBoxX.setObjectName("doubleSpinBoxX")
54 57
        self.formLayout.setWidget(1, QtWidgets.QFormLayout.FieldRole, self.doubleSpinBoxX)
55 58
        self.doubleSpinBoxY = QtWidgets.QDoubleSpinBox(RotateSymbolDialog)
59
        self.doubleSpinBoxY.setEnabled(False)
56 60
        self.doubleSpinBoxY.setDecimals(1)
57 61
        self.doubleSpinBoxY.setMaximum(99999999.0)
58 62
        self.doubleSpinBoxY.setObjectName("doubleSpinBoxY")
......
61 65
        self.label_3.setObjectName("label_3")
62 66
        self.formLayout.setWidget(3, QtWidgets.QFormLayout.LabelRole, self.label_3)
63 67
        self.spinBoxZValue = QtWidgets.QSpinBox(RotateSymbolDialog)
68
        self.spinBoxZValue.setEnabled(False)
64 69
        self.spinBoxZValue.setMinimum(1)
65 70
        self.spinBoxZValue.setMaximum(250)
66 71
        self.spinBoxZValue.setObjectName("spinBoxZValue")
......
76 81
        self.horizontalLayout_2 = QtWidgets.QHBoxLayout()
77 82
        self.horizontalLayout_2.setObjectName("horizontalLayout_2")
78 83
        self.checkBoxOffset = QtWidgets.QCheckBox(RotateSymbolDialog)
84
        self.checkBoxOffset.setEnabled(False)
79 85
        self.checkBoxOffset.setObjectName("checkBoxOffset")
80 86
        self.horizontalLayout_2.addWidget(self.checkBoxOffset)
81 87
        self.buttonBox = QtWidgets.QDialogButtonBox(RotateSymbolDialog)
......
102 108
        self.label_2.setText(_translate("RotateSymbolDialog", "Origin_Y"))
103 109
        self.label_3.setText(_translate("RotateSymbolDialog", "Z_Value"))
104 110
        self.checkBoxOffset.setText(_translate("RotateSymbolDialog", "Offset"))
105

  
106

  
107
if __name__ == "__main__":
108
    import sys
109
    app = QtWidgets.QApplication(sys.argv)
110
    RotateSymbolDialog = QtWidgets.QDialog()
111
    ui = Ui_RotateSymbolDialog()
112
    ui.setupUi(RotateSymbolDialog)
113
    RotateSymbolDialog.show()
114
    sys.exit(app.exec_())
115

  
DTI_PID/DTI_PID/Shapes/EngineeringLineItem.py
1073 1073
        symbol.size = [symbol.boundingRect().width(), symbol.boundingRect().height()]
1074 1074
        self.scene().addItem(symbol)
1075 1075

  
1076
    '''
1077
        @brief  redraw symbol
1078
        @author kyouho
1079
        @date   2018.07.25
1080
    '''
1081

  
1082
    def reDrawLine(self, symbol, point):
1076
    def update_shape(self, symbol, point):
1077
        """update line shape"""
1083 1078
        for index in range(len(self.connectors)):
1084 1079
            if self.connectors[index].connectedItem == symbol:
1085 1080
                # startPoint
DTI_PID/DTI_PID/Shapes/SymbolSvgItem.py
517 517
        """ call signals when item's position or rotation is changed """
518 518
        if not self.scene(): return super().itemChange(change, value)
519 519

  
520
        if change == QGraphicsItem.ItemPositionHasChanged or change == QGraphicsItem.ItemRotationChange:
520
        if change == QGraphicsItem.ItemPositionHasChanged or change == QGraphicsItem.ItemRotationHasChanged:
521 521
            from EngineeringLineItem import QEngineeringLineItem
522 522
            for connector in self.connectors:
523
                if connector.connectedItem is not None and type(connector.connectedItem) == QEngineeringLineItem:
523
                if connector.connectedItem is not None and type(connector.connectedItem) is QEngineeringLineItem:
524 524
                    line = connector.connectedItem
525
                    line.reDrawLine(self, connector.center())
525
                    line.update_shape(self, connector.center())
526 526
                    line.update_arrow()
527 527

  
528
            self.size[0], self.size[1] = round(self.sceneBoundingRect().width()), round(
529
                self.sceneBoundingRect().height())
528
            self.size[0], self.size[1] = round(self.sceneBoundingRect().width()), \
529
                                         round(self.sceneBoundingRect().height())
530 530

  
531 531
            self.scene().contents_changed.emit()
532 532

  
......
540 540

  
541 541
        cols = ['UID', 'Drawings_UID', 'Symbol_UID', 'X', 'Y', 'Width', 'Height', 'Rotation', 'Area', 'Owner',
542 542
                'Connected', '[Supplied By]', \
543
                'SpecialItemTypes_UID', 'OriginIndex', '[From]', '[To]', '[Freeze]', '[Connected Item]', '[Flip]', 'SceneOriginPoint']
543
                'SpecialItemTypes_UID', 'OriginIndex', '[From]', '[To]', '[Freeze]', '[Connected Item]', '[Flip]',
544
                'SceneOriginPoint']
544 545
        values = ['?', '?', '?', '?', '?', '?', '?', '?', '?', '?', '?', '?', '?', '?', '?', '?', '?', '?', '?', '?']
545 546
        param = [(str(self.uid), str(AppDocData.instance().activeDrawing.UID), self.dbUid, self.loc[0], self.loc[1],
546
                  self.size[0], self.size[1], self.angle,
547
                  self.size[0], self.size[1], math.radians(self.rotation()),
547 548
                  self.area, str(self.owner) if self.owner else None, \
548 549
                  str(self.conns[0]) if self.conns else None, \
549 550
                  self.prop('Supplied By'), \
......
940 941
        if event.buttons() == Qt.LeftButton:
941 942
            self.clicked.emit(self)
942 943

  
943
    '''
944
        @brief      Mouse Release Event
945
        @author     kyouho
946
        @date       18.07.17
947
    '''
948

  
949 944
    def mouseReleaseEvent(self, event):
945
        """Mouse Release Event"""
950 946
        if hasattr(self, '_rotating') and event.button() == Qt.RightButton:
951 947
            from RotateCommand import RotateCommand
952 948

  
953
            self.angle = -self._angle if self._angle > -math.pi and self._angle < 0 else 2 * math.pi - self._angle
949
            self.angle = -self._angle if -math.pi < self._angle < 0 else 2 * math.pi - self._angle
954 950

  
955 951
            self.scene().undo_stack.push(RotateCommand(self.scene(), [self,], self._rotating))
956 952

  
......
1033 1029
    def keyPressEvent(self, event):
1034 1030
        from EngineeringErrorItem import QEngineeringErrorItem
1035 1031
        from RotateSymbolDialog import QRotateSymbolDialog
1032
        from RotateCommand import RotateCommand
1036 1033

  
1037 1034
        if not self.isSelected():
1038 1035
            return
......
1043 1040
        elif event.key() == Qt.Key_C and type(self) is not QEngineeringErrorItem:
1044 1041
            self.changeConnPoint()
1045 1042
        elif event.key() == Qt.Key_Return:
1046
            return
1047 1043
            # disable
1048 1044
            dialog = QRotateSymbolDialog(None, self.angle, self.origin, self.zValue())
1049 1045
            (isAccept, angle, x, y, z) = dialog.showDialog()
1050 1046

  
1051 1047
            if isAccept:
1048
                self.rotate(math.radians(angle))
1049
                self.scene().undo_stack.push(RotateCommand(self.scene(), [self, ], self.angle))
1052 1050
                self.angle = angle
1051
                """
1053 1052
                self.loc = [x - self.symbolOrigin[0], y - self.symbolOrigin[1]]
1054 1053
                self.origin = [x, y]
1055 1054
                self.rotate(self.angle)
1056 1055
                self.setZValue(z)
1056
                """
1057 1057
        elif event.key() == Qt.Key_Escape:
1058 1058
            if hasattr(self, '_rotating'):
1059 1059
                self.ungrabMouse()
......
1269 1269
            node.append(sizeNode)
1270 1270

  
1271 1271
            angleNode = Element('ANGLE')
1272
            angleNode.text = str(self.angle)
1272
            angleNode.text = str(math.radians(self.rotation()))
1273 1273
            node.append(angleNode)
1274 1274

  
1275 1275
            parentSymbolNode = Element('PARENT')
......
1894 1894
        if self.isSelected():
1895 1895
            self.drawFocusRect(painter)
1896 1896

  
1897
    '''
1898
        @brief      Add Svg Item into ImageViewer's Scene
1899
        @author     Jeongwoo
1900
        @date       2018.05.03
1901
        @history    add connectors which's parent is symbol
1902
                    kyouho  2018.07.30  remove connectors logic
1903
    '''
1904

  
1905
    def addSvgItemToScene(self, scene):
1897
    def addSvgItemToScene(self, scene, undoable: bool = False) -> None:
1898
        """Add Svg Item into ImageViewer's Scene"""
1906 1899
        self.setTransformOriginPoint(QPointF(self.symbolOrigin[0], self.symbolOrigin[1]))
1907 1900

  
1908 1901
        if self.flip:
......
1912 1905
        self.setRotation(math.degrees(-self.angle))
1913 1906
        self.moveBy(self.loc[0] + self.symbolOrigin[0], self.loc[1] + self.symbolOrigin[1])
1914 1907

  
1915
        # self.rotate_symbol(self.angle, self.getCurrentPoint())
1916 1908
        scene.addItem(self)
1917 1909
        self.size[0], self.size[1] = round(self.sceneBoundingRect().width()), round(self.sceneBoundingRect().height())
1918
        trans = self.transform()
1910

  
1911
        if undoable:
1912
            from CreateCommand import CreateCommand
1913
            self.scene().undo_stack.push(CreateCommand(self.scene(), [self,]))
1919 1914

  
1920 1915
    '''
1921 1916
        @brief      
DTI_PID/DTI_PID/UI/RotateSymbol.ui
83 83
     </item>
84 84
     <item row="1" column="1">
85 85
      <widget class="QDoubleSpinBox" name="doubleSpinBoxX">
86
       <property name="enabled">
87
        <bool>false</bool>
88
       </property>
86 89
       <property name="decimals">
87 90
        <number>1</number>
88 91
       </property>
......
93 96
     </item>
94 97
     <item row="2" column="1">
95 98
      <widget class="QDoubleSpinBox" name="doubleSpinBoxY">
99
       <property name="enabled">
100
        <bool>false</bool>
101
       </property>
96 102
       <property name="decimals">
97 103
        <number>1</number>
98 104
       </property>
......
110 116
     </item>
111 117
     <item row="3" column="1">
112 118
      <widget class="QSpinBox" name="spinBoxZValue">
119
       <property name="enabled">
120
        <bool>false</bool>
121
       </property>
113 122
       <property name="minimum">
114 123
        <number>1</number>
115 124
       </property>
......
143 152
    <layout class="QHBoxLayout" name="horizontalLayout_2">
144 153
     <item>
145 154
      <widget class="QCheckBox" name="checkBoxOffset">
155
       <property name="enabled">
156
        <bool>false</bool>
157
       </property>
146 158
       <property name="text">
147 159
        <string>Offset</string>
148 160
       </property>

내보내기 Unified diff

클립보드 이미지 추가 (최대 크기: 500 MB)