1 /*
2  * This program source code file is part of KiCad, a free EDA CAD application.
3  *
4  * Copyright 2016-2017 CERN
5  * Copyright (C) 2020-2021 KiCad Developers, see change_log.txt for contributors.
6  *
7  * @author Tomasz Wlostowski <tomasz.wlostowski@cern.ch>
8  * @author Maciej Suminski <maciej.suminski@cern.ch>
9  *
10  * This program is free software; you can redistribute it and/or
11  * modify it under the terms of the GNU General Public License
12  * as published by the Free Software Foundation; either version 2
13  * of the License, or (at your option) any later version.
14  *
15  * This program is distributed in the hope that it will be useful,
16  * but WITHOUT ANY WARRANTY; without even the implied warranty of
17  * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
18  * GNU General Public License for more details.
19  *
20  * You should have received a copy of the GNU General Public License
21  * along with this program; if not, you may find one here:
22  * http://www.gnu.org/licenses/old-licenses/gpl-2.0.html
23  * or you may search the http://www.gnu.org website for the version 2 license,
24  * or you may write to the Free Software Foundation, Inc.,
25  * 51 Franklin Street, Fifth Floor, Boston, MA  02110-1301, USA
26  */
27 
28 #ifndef __COMMIT_H
29 #define __COMMIT_H
30 
31 #include <set>
32 #include <vector>
33 #include <wx/string.h>
34 #include <undo_redo_container.h>
35 
36 class EDA_ITEM;
37 
38 ///< Types of changes
39 enum CHANGE_TYPE {
40     CHT_ADD     = 1,
41     CHT_REMOVE  = 2,
42     CHT_MODIFY  = 4,
43     CHT_TYPE    = CHT_ADD | CHT_REMOVE | CHT_MODIFY,
44 
45     ///< Flag to indicate the change is already applied,
46     ///< just notify observers (not compatible with CHT_MODIFY)
47     CHT_DONE    = 8,
48     CHT_FLAGS   = CHT_DONE
49 };
50 
51 template<typename T>
52 CHANGE_TYPE operator|( CHANGE_TYPE aTypeA, T aTypeB )
53 {
54     return CHANGE_TYPE( (int) aTypeA | (int) aTypeB );
55 }
56 
57 template<typename T>
58 CHANGE_TYPE operator&( CHANGE_TYPE aTypeA, T aTypeB )
59 {
60     return CHANGE_TYPE( (int) aTypeA & (int) aTypeB );
61 }
62 
63 
64 /**
65  * Represent a set of changes (additions, deletions or modifications) of a data model
66  * (e.g. the BOARD) class.
67  *
68  * The class can be used to propagate changes to subscribed objects (e.g. views, ratsnest),
69  * and automatically create undo/redo points.
70  */
71 class COMMIT
72 {
73 public:
74     COMMIT();
75     virtual ~COMMIT();
76 
77     ///< Add a new item to the model
Add(EDA_ITEM * aItem)78     COMMIT& Add( EDA_ITEM* aItem )
79     {
80         return Stage( aItem, CHT_ADD );
81     }
82 
83     ///< Notify observers that aItem has been added
Added(EDA_ITEM * aItem)84     COMMIT& Added( EDA_ITEM* aItem )
85     {
86         return Stage( aItem, CHT_ADD | CHT_DONE );
87     }
88 
89     ///< Remove a new item from the model
Remove(EDA_ITEM * aItem)90     COMMIT& Remove( EDA_ITEM* aItem )
91     {
92         return Stage( aItem, CHT_REMOVE );
93     }
94 
95     ///< Notify observers that aItem has been removed
Removed(EDA_ITEM * aItem)96     COMMIT& Removed( EDA_ITEM* aItem )
97     {
98         return Stage( aItem, CHT_REMOVE | CHT_DONE );
99     }
100 
101     ///< Modify a given item in the model.
102     ///< Must be called before modification is performed.
Modify(EDA_ITEM * aItem)103     COMMIT& Modify( EDA_ITEM* aItem )
104     {
105         return Stage( aItem, CHT_MODIFY );
106     }
107 
108     ///< Create an undo entry for an item that has been already modified. Requires a copy done
109     ///< before the modification.
Modified(EDA_ITEM * aItem,EDA_ITEM * aCopy)110     COMMIT& Modified( EDA_ITEM* aItem, EDA_ITEM* aCopy )
111     {
112         return createModified( aItem, aCopy );
113     }
114 
115     template<class Range>
116 
StageItems(const Range & aRange,CHANGE_TYPE aChangeType)117     COMMIT& StageItems( const Range& aRange, CHANGE_TYPE aChangeType )
118     {
119         for( const auto& item : aRange )
120             Stage( item, aChangeType );
121 
122         return *this;
123     }
124 
125     ///< Add a change of the item aItem of type aChangeType to the change list.
126     virtual COMMIT& Stage( EDA_ITEM* aItem, CHANGE_TYPE aChangeType );
127 
128     virtual COMMIT& Stage( std::vector<EDA_ITEM*>& container, CHANGE_TYPE aChangeType );
129 
130     virtual COMMIT& Stage( const PICKED_ITEMS_LIST& aItems,
131                            UNDO_REDO aModFlag = UNDO_REDO::UNSPECIFIED );
132 
133     ///< Execute the changes.
134     virtual void Push( const wxString& aMessage = wxT( "A commit" ),
135                        bool aCreateUndoEntry = true, bool aSetDirtyBit = true ) = 0;
136 
137     ///< Revert the commit by restoring the modified items state.
138     virtual void Revert() = 0;
139 
Empty()140     bool Empty() const
141     {
142         return m_changes.empty();
143     }
144 
145     ///< Returns status of an item.
146     int GetStatus( EDA_ITEM* aItem );
147 
148 protected:
149     struct COMMIT_LINE
150     {
151         EDA_ITEM*   m_item;       ///< Main item that is added/deleted/modified
152         EDA_ITEM*   m_copy;       ///< Optional copy of the item
153         CHANGE_TYPE m_type;       ///< Modification type
154     };
155 
156     // Should be called in Push() & Revert() methods
clear()157     void clear()
158     {
159         m_changedItems.clear();
160         m_changes.clear();
161     }
162 
163     COMMIT& createModified( EDA_ITEM* aItem, EDA_ITEM* aCopy, int aExtraFlags = 0 );
164 
165     virtual void makeEntry( EDA_ITEM* aItem, CHANGE_TYPE aType, EDA_ITEM* aCopy = nullptr );
166 
167     /**
168      * Search for an entry describing change for a particular item.
169      *
170      * @return null if there is no related entry.
171      */
172     COMMIT_LINE* findEntry( EDA_ITEM* aItem );
173 
174     virtual EDA_ITEM* parentObject( EDA_ITEM* aItem ) const = 0;
175 
176     CHANGE_TYPE convert( UNDO_REDO aType ) const;
177 
178     std::set<EDA_ITEM*> m_changedItems;
179     std::vector<COMMIT_LINE> m_changes;
180 };
181 
182 #endif
183