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) 2021 KiCad Developers, see AUTHORS.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 #include <core/kicad_algo.h>
29 #include <commit.h>
30 #include <eda_item.h>
31 #include <macros.h>
32 
COMMIT()33 COMMIT::COMMIT()
34 {
35 }
36 
37 
~COMMIT()38 COMMIT::~COMMIT()
39 {
40     for( COMMIT_LINE& ent : m_changes )
41     {
42         if( ent.m_copy )
43             delete ent.m_copy;
44     }
45 }
46 
47 
Stage(EDA_ITEM * aItem,CHANGE_TYPE aChangeType)48 COMMIT& COMMIT::Stage( EDA_ITEM* aItem, CHANGE_TYPE aChangeType )
49 {
50     // CHT_MODIFY and CHT_DONE are not compatible
51     assert( ( aChangeType & ( CHT_MODIFY | CHT_DONE ) ) != ( CHT_MODIFY | CHT_DONE ) );
52 
53     int flag = aChangeType & CHT_FLAGS;
54 
55     switch( aChangeType & CHT_TYPE )
56     {
57     case CHT_ADD:
58         assert( m_changedItems.find( aItem ) == m_changedItems.end() );
59         makeEntry( aItem, CHT_ADD | flag );
60         return *this;
61 
62     case CHT_REMOVE:
63         makeEntry( aItem, CHT_REMOVE | flag );
64         return *this;
65 
66     case CHT_MODIFY:
67     {
68         EDA_ITEM* parent = parentObject( aItem );
69         EDA_ITEM* clone = nullptr;
70 
71         assert( parent );
72 
73         if( parent )
74             clone = parent->Clone();
75 
76         assert( clone );
77 
78         if( clone )
79             return createModified( parent, clone, flag );
80 
81         break;
82     }
83 
84     default:
85         assert( false );
86     }
87 
88     return *this;
89 }
90 
91 
Stage(std::vector<EDA_ITEM * > & container,CHANGE_TYPE aChangeType)92 COMMIT& COMMIT::Stage( std::vector<EDA_ITEM*>& container, CHANGE_TYPE aChangeType )
93 {
94     for( EDA_ITEM* item : container )
95     {
96         Stage( item, aChangeType );
97     }
98 
99     return *this;
100 }
101 
102 
Stage(const PICKED_ITEMS_LIST & aItems,UNDO_REDO aModFlag)103 COMMIT& COMMIT::Stage( const PICKED_ITEMS_LIST& aItems, UNDO_REDO aModFlag )
104 {
105     for( unsigned int i = 0; i < aItems.GetCount(); i++ )
106     {
107         UNDO_REDO change_type = aItems.GetPickedItemStatus( i );
108         EDA_ITEM* item = aItems.GetPickedItem( i );
109         EDA_ITEM* copy = nullptr;
110 
111         if( change_type == UNDO_REDO::UNSPECIFIED )
112             change_type = aModFlag;
113 
114         if( ( copy = aItems.GetPickedItemLink( i ) ) )
115         {
116             assert( change_type == UNDO_REDO::CHANGED );
117 
118             // There was already a copy created, so use it
119             Modified( item, copy );
120         }
121         else
122         {
123             Stage( item, convert( change_type ) );
124         }
125     }
126 
127     return *this;
128 }
129 
130 
GetStatus(EDA_ITEM * aItem)131 int COMMIT::GetStatus( EDA_ITEM* aItem )
132 {
133     COMMIT_LINE* entry = findEntry( parentObject( aItem ) );
134 
135     return entry ? entry->m_type : 0;
136 }
137 
138 
createModified(EDA_ITEM * aItem,EDA_ITEM * aCopy,int aExtraFlags)139 COMMIT& COMMIT::createModified( EDA_ITEM* aItem, EDA_ITEM* aCopy, int aExtraFlags )
140 {
141     EDA_ITEM* parent = parentObject( aItem );
142     auto entryIt = m_changedItems.find( parent );
143 
144     if( entryIt != m_changedItems.end() )
145     {
146         delete aCopy;
147         return *this; // item has been already modified once
148     }
149 
150     makeEntry( parent, CHT_MODIFY | aExtraFlags, aCopy );
151 
152     return *this;
153 }
154 
155 
makeEntry(EDA_ITEM * aItem,CHANGE_TYPE aType,EDA_ITEM * aCopy)156 void COMMIT::makeEntry( EDA_ITEM* aItem, CHANGE_TYPE aType, EDA_ITEM* aCopy )
157 {
158     // Expect an item copy if it is going to be modified
159     wxASSERT( !!aCopy == ( ( aType & CHT_TYPE ) == CHT_MODIFY ) );
160 
161     if( m_changedItems.find( aItem ) != m_changedItems.end() )
162     {
163         alg::delete_if( m_changes, [aItem]( const COMMIT_LINE& aEnt )
164                                    {
165                                        return aEnt.m_item == aItem;
166                                    } );
167     }
168 
169     COMMIT_LINE ent;
170 
171     ent.m_item = aItem;
172     ent.m_type = aType;
173     ent.m_copy = aCopy;
174 
175     m_changedItems.insert( aItem );
176     m_changes.push_back( ent );
177 }
178 
179 
findEntry(EDA_ITEM * aItem)180 COMMIT::COMMIT_LINE* COMMIT::findEntry( EDA_ITEM* aItem )
181 {
182     for( COMMIT_LINE& change : m_changes )
183     {
184         if( change.m_item == aItem )
185             return &change;
186     }
187 
188     return nullptr;
189 }
190 
191 
convert(UNDO_REDO aType) const192 CHANGE_TYPE COMMIT::convert( UNDO_REDO aType ) const
193 {
194     switch( aType )
195     {
196     case UNDO_REDO::NEWITEM:
197         return CHT_ADD;
198 
199     case UNDO_REDO::DELETED:
200         return CHT_REMOVE;
201 
202     default:
203         assert( false );
204         KI_FALLTHROUGH;
205 
206     case UNDO_REDO::CHANGED:
207         return CHT_MODIFY;
208     }
209 }
210 
211