KiCad PCB EDA Suite
annotate.cpp
Go to the documentation of this file.
1 /*
2  * This program source code file is part of KiCad, a free EDA CAD application.
3  *
4  * Copyright (C) 2004-2021 KiCad Developers, see AUTHORS.txt for contributors.
5  *
6  * This program is free software; you can redistribute it and/or
7  * modify it under the terms of the GNU General Public License
8  * as published by the Free Software Foundation; either version 2
9  * of the License, or (at your option) any later version.
10  *
11  * This program is distributed in the hope that it will be useful,
12  * but WITHOUT ANY WARRANTY; without even the implied warranty of
13  * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
14  * GNU General Public License for more details.
15  *
16  * You should have received a copy of the GNU General Public License
17  * along with this program; if not, you may find one here:
18  * http://www.gnu.org/licenses/old-licenses/gpl-2.0.html
19  * or you may search the http://www.gnu.org website for the version 2 license,
20  * or you may write to the Free Software Foundation, Inc.,
21  * 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301, USA
22  */
23 
24 #include <algorithm>
25 
26 #include <confirm.h>
27 #include <reporter.h>
28 #include <sch_edit_frame.h>
29 #include <schematic.h>
30 #include <erc_settings.h>
31 #include <sch_reference_list.h>
32 #include <class_library.h>
33 #include <tools/ee_selection.h>
35 #include <tool/tool_manager.h>
36 
37 
38 void SCH_EDIT_FRAME::mapExistingAnnotation( std::map<wxString, wxString>& aMap )
39 {
40  SCH_REFERENCE_LIST references;
41 
42  Schematic().GetSheets().GetSymbols( references );
43 
44  for( size_t i = 0; i < references.GetCount(); i++ )
45  {
46  SCH_COMPONENT* symbol = references[ i ].GetSymbol();
47  SCH_SHEET_PATH* curr_sheetpath = &references[ i ].GetSheetPath();
48  KIID_PATH curr_full_uuid = curr_sheetpath->Path();
49 
50  curr_full_uuid.push_back( symbol->m_Uuid );
51 
52  wxString ref = symbol->GetRef( curr_sheetpath );
53 
54  if( symbol->GetUnitCount() > 1 )
55  ref << LIB_PART::SubReference( symbol->GetUnitSelection( curr_sheetpath ) );
56 
57  if( symbol->IsAnnotated( curr_sheetpath ) )
58  aMap[ curr_full_uuid.AsString() ] = ref;
59  }
60 }
61 
62 
63 void SCH_EDIT_FRAME::DeleteAnnotation( ANNOTATE_SCOPE_T aAnnotateScope, bool* aAppendUndo )
64 {
65  auto clearSymbolAnnotation =
66  [&]( EDA_ITEM* aItem, SCH_SCREEN* aScreen, SCH_SHEET_PATH* aSheet )
67  {
68  SCH_COMPONENT* symbol = static_cast<SCH_COMPONENT*>( aItem );
69 
70  SaveCopyInUndoList( aScreen, symbol, UNDO_REDO::CHANGED, *aAppendUndo );
71  *aAppendUndo = true;
72  symbol->ClearAnnotation( aSheet );
73  };
74 
75  auto clearSheetAnnotation =
76  [&]( SCH_SCREEN* aScreen, SCH_SHEET_PATH* aSheet )
77  {
78  for( SCH_ITEM* item : aScreen->Items().OfType( SCH_COMPONENT_T ) )
79  clearSymbolAnnotation( item, aScreen, aSheet );
80  };
81 
82  SCH_SCREEN* screen = GetScreen();
83  SCH_SHEET_PATH currentSheet = GetCurrentSheet();
84 
85  switch( aAnnotateScope )
86  {
87  case ANNOTATE_ALL:
88  {
89  for( const SCH_SHEET_PATH& sheet : Schematic().GetSheets() )
90  clearSheetAnnotation( sheet.LastScreen(), nullptr );
91 
92  break;
93  }
95  {
96  clearSheetAnnotation( screen, &currentSheet );
97  break;
98  }
99 
100  case ANNOTATE_SELECTION:
101  {
103  EE_SELECTION& selection = selTool->RequestSelection();
104 
105  for( EDA_ITEM* item : selection.Items() )
106  {
107  if( item->Type() == SCH_COMPONENT_T )
108  clearSymbolAnnotation( item, screen, &currentSheet );
109  }
110  break;
111  }
112  }
113 
114  // Update the references for the sheet that is currently being displayed.
116 
117  SyncView();
118  GetCanvas()->Refresh();
119  OnModify();
120 
121  // Must go after OnModify() so the connectivity graph has been updated
123 }
124 
125 
127  ANNOTATE_ORDER_T aSortOption,
128  ANNOTATE_ALGO_T aAlgoOption,
129  int aStartNumber,
130  bool aResetAnnotation,
131  bool aRepairTimestamps,
132  REPORTER& aReporter )
133 {
135  EE_SELECTION& selection = selTool->RequestSelection();
136 
137  SCH_REFERENCE_LIST references;
138  SCH_SCREENS screens( Schematic().Root() );
139  SCH_SHEET_LIST sheets = Schematic().GetSheets();
140  SCH_SHEET_PATH currentSheet = GetCurrentSheet();
141  bool appendUndo = false;
142 
143  // Map of locked symbols
144  SCH_MULTI_UNIT_REFERENCE_MAP lockedSymbols;
145 
146  // Map of previous annotation for building info messages
147  std::map<wxString, wxString> previousAnnotation;
148 
149  // Test for and replace duplicate time stamps in symbols and sheets. Duplicate
150  // time stamps can happen with old schematics, schematic conversions, or manual
151  // editing of files.
152  if( aRepairTimestamps )
153  {
154  int count = screens.ReplaceDuplicateTimeStamps();
155 
156  if( count )
157  {
158  wxString msg;
159  msg.Printf( _( "%d duplicate time stamps were found and replaced." ), count );
160  aReporter.ReportTail( msg, RPT_SEVERITY_WARNING );
161  }
162  }
163 
164  // Collect all the sets that must be annotated together.
165  switch( aAnnotateScope )
166  {
167  case ANNOTATE_ALL:
168  sheets.GetMultiUnitSymbols( lockedSymbols );
169  break;
170 
172  currentSheet.GetMultiUnitSymbols( lockedSymbols );
173  break;
174 
175  case ANNOTATE_SELECTION:
176  selection.GetMultiUnitSymbols( lockedSymbols, currentSheet );
177  break;
178  }
179 
180  // Store previous annotations for building info messages
181  mapExistingAnnotation( previousAnnotation );
182 
183  // If it is an annotation for all the symbols, reset previous annotation.
184  if( aResetAnnotation )
185  DeleteAnnotation( aAnnotateScope, &appendUndo );
186 
187  // Set sheet number and number of sheets.
189 
190  // Build symbol list
191  switch( aAnnotateScope )
192  {
193  case ANNOTATE_ALL:
194  sheets.GetSymbols( references );
195  break;
196 
198  GetCurrentSheet().GetSymbols( references );
199  break;
200 
201  case ANNOTATE_SELECTION:
202  selection.GetSymbols( references, currentSheet );
203  break;
204  }
205 
206  // Build additional list of references to be used during reannotation
207  // to avoid duplicate designators (no additional references when annotating
208  // the full schematic)
209  SCH_REFERENCE_LIST additionalRefs;
210 
211  if( aAnnotateScope != ANNOTATE_ALL )
212  {
213  SCH_REFERENCE_LIST allRefs;
214  sheets.GetSymbols( allRefs );
215 
216  for( size_t i = 0; i < allRefs.GetCount(); i++ )
217  {
218  if( !references.Contains( allRefs[i] ) )
219  additionalRefs.AddItem( allRefs[i] );
220  }
221  }
222 
223  // Break full symbol reference into name (prefix) and number:
224  // example: IC1 become IC, and 1
225  references.SplitReferences();
226 
227  switch( aSortOption )
228  {
229  default:
230  case SORT_BY_X_POSITION: references.SortByXCoordinate(); break;
231  case SORT_BY_Y_POSITION: references.SortByYCoordinate(); break;
232  }
233 
234  bool useSheetNum = false;
235  int idStep = 100;
236 
237  switch( aAlgoOption )
238  {
239  default:
240  case INCREMENTAL_BY_REF:
241  break;
242 
243  case SHEET_NUMBER_X_100:
244  useSheetNum = true;
245  break;
246 
247  case SHEET_NUMBER_X_1000:
248  useSheetNum = true;
249  idStep = 1000;
250  break;
251  }
252 
253  // Recalculate and update reference numbers in schematic
254  references.Annotate( useSheetNum, idStep, aStartNumber, lockedSymbols, additionalRefs );
255 
256  for( size_t i = 0; i < references.GetCount(); i++ )
257  {
258  SCH_REFERENCE& ref = references[i];
259  SCH_COMPONENT* symbol = ref.GetSymbol();
260  SCH_SHEET_PATH* sheet = &ref.GetSheetPath();
261 
262  SaveCopyInUndoList( sheet->LastScreen(), symbol, UNDO_REDO::CHANGED, appendUndo );
263  appendUndo = true;
264  ref.Annotate();
265 
266  KIID_PATH full_uuid = sheet->Path();
267  full_uuid.push_back( symbol->m_Uuid );
268 
269  wxString prevRef = previousAnnotation[ full_uuid.AsString() ];
270  wxString newRef = symbol->GetRef( sheet );
271 
272  if( symbol->GetUnitCount() > 1 )
273  newRef << LIB_PART::SubReference( symbol->GetUnitSelection( sheet ) );
274 
275  wxString msg;
276 
277  if( prevRef.Length() )
278  {
279  if( newRef == prevRef )
280  continue;
281 
282  if( symbol->GetUnitCount() > 1 )
283  msg.Printf( _( "Updated %s (unit %s) from %s to %s" ),
284  symbol->GetValue( sheet, true ),
285  LIB_PART::SubReference( symbol->GetUnit(), false ),
286  prevRef,
287  newRef );
288  else
289  msg.Printf( _( "Updated %s from %s to %s" ),
290  symbol->GetValue( sheet, true ),
291  prevRef,
292  newRef );
293  }
294  else
295  {
296  if( symbol->GetUnitCount() > 1 )
297  msg.Printf( _( "Annotated %s (unit %s) as %s" ),
298  symbol->GetValue( sheet, true ),
299  LIB_PART::SubReference( symbol->GetUnit(), false ),
300  newRef );
301  else
302  msg.Printf( _( "Annotated %s as %s" ),
303  symbol->GetValue( sheet, true ),
304  newRef );
305  }
306 
307  aReporter.Report( msg, RPT_SEVERITY_ACTION );
308  }
309 
310  // Final control (just in case ... ).
311  if( !CheckAnnotate(
312  [ &aReporter ]( ERCE_T , const wxString& aMsg, SCH_REFERENCE* , SCH_REFERENCE* )
313  {
314  aReporter.Report( aMsg, RPT_SEVERITY_ERROR );
315  },
316  aAnnotateScope ) )
317  {
318  aReporter.ReportTail( _( "Annotation complete." ), RPT_SEVERITY_ACTION );
319  }
320 
321  // Update on screen references, that can be modified by previous calculations:
324 
325  SyncView();
326  GetCanvas()->Refresh();
327  OnModify();
328 
329  // Must go after OnModify() so the connectivity graph has been updated
331 }
332 
333 
335  ANNOTATE_SCOPE_T aAnnotateScope )
336 {
337  SCH_REFERENCE_LIST referenceList;
338  constexpr bool includePowerSymbols = false;
339 
340  // Build the list of symbols
341  switch( aAnnotateScope )
342  {
343  case ANNOTATE_ALL:
344  Schematic().GetSheets().GetSymbols( referenceList );
345  break;
346 
348  GetCurrentSheet().GetSymbols( referenceList, includePowerSymbols );
349  break;
350 
351  case ANNOTATE_SELECTION:
353  EE_SELECTION& selection = selTool->RequestSelection();
354  selection.GetSymbols( referenceList, GetCurrentSheet(), includePowerSymbols );
355  break;
356  }
357 
358  // Empty schematic does not need annotation
359  if( referenceList.GetCount() == 0 )
360  return 0;
361 
362  return referenceList.CheckAnnotation( aErrorHandler );
363 }
A container for handling SCH_SHEET_PATH objects in a flattened hierarchy.
EE_TYPE OfType(KICAD_T aType) const
Definition: sch_rtree.h:216
void GetMultiUnitSymbols(SCH_MULTI_UNIT_REFERENCE_MAP &aRefList, bool aIncludePowerSymbols=true) const
Add a SCH_REFERENCE_LIST object to aRefList for each same-reference set of multi-unit parts in the sh...
void SortByYCoordinate()
Sort the list of references by Y position.
void UpdateNetHighlightStatus()
Annotate the selection.
void mapExistingAnnotation(std::map< wxString, wxString > &aMap)
Fill a map of uuid -> reference from the currently loaded schematic.
Definition: annotate.cpp:38
Annotate the full schematic.
void GetMultiUnitSymbols(SCH_MULTI_UNIT_REFERENCE_MAP &aRefList, bool aIncludePowerSymbols=true) const
Add a SCH_REFERENCE_LIST object to aRefList for each same-reference set of multi-unit parts in the li...
void GetSymbols(SCH_REFERENCE_LIST &aReferences, bool aIncludePowerSymbols=true, bool aForceIncludeOrphanSymbols=false) const
Add a SCH_REFERENCE object to aReferences for each symbol in the list of sheets.
This file is part of the common library.
const SCH_SHEET_PATH & GetSheetPath() const
ANNOTATE_ORDER_T
Schematic annotation order options.
KIID_PATH Path() const
Get the sheet path as an KIID_PATH.
virtual REPORTER & ReportTail(const wxString &aText, SEVERITY aSeverity=RPT_SEVERITY_UNDEFINED)
Places the report at the end of the list, for objects that support report ordering.
Definition: reporter.h:93
int GetUnitCount() const
Return the number of units per package of the symbol.
Definition: sch_symbol.cpp:360
void DeleteAnnotation(ANNOTATE_SCOPE_T aAnnotateScope, bool *appendUndo)
Clear the current component annotation.
Definition: annotate.cpp:63
void AnnotateSymbols(ANNOTATE_SCOPE_T aAnnotateScope, ANNOTATE_ORDER_T aSortOption, ANNOTATE_ALGO_T aAlgoOption, int aStartNumber, bool aResetAnnotation, bool aRepairTimestamps, REPORTER &aReporter)
Annotate the symbols in the schematic that are not currently annotated.
Definition: annotate.cpp:126
void AddItem(const SCH_REFERENCE &aItem)
A pure virtual class used to derive REPORTER objects from.
Definition: reporter.h:64
void UpdateAllScreenReferences()
Update all the symbol references for this sheet path.
int CheckAnnotate(ANNOTATION_ERROR_HANDLER aErrorHandler, ANNOTATE_SCOPE_T aAnnotateScope=ANNOTATE_ALL)
Check for annotation errors.
Definition: annotate.cpp:334
virtual REPORTER & Report(const wxString &aText, SEVERITY aSeverity=RPT_SEVERITY_UNDEFINED)=0
Report a string with a given severity.
Container to create a flattened list of symbols because in a complex hierarchy, a symbol can be used ...
EE_SELECTION & RequestSelection(const KICAD_T *aFilterList=EE_COLLECTOR::AllItems)
Return either an existing selection (filtered), or the selection at the current cursor if the existin...
SCH_SCREEN * GetScreen() const override
Return a pointer to a BASE_SCREEN or one of its derivatives.
int GetUnit() const
Definition: sch_symbol.h:195
const wxString GetValue(const SCH_SHEET_PATH *sheet, bool aResolve) const
Return the instance-specific value for the given sheet path.
Definition: sch_symbol.cpp:563
void SortByXCoordinate()
Sort the list of references by X position.
void SyncView()
Mark all items for refresh.
SCH_DRAW_PANEL * GetCanvas() const override
Return a pointer to GAL-based canvas of given EDA draw frame.
void Annotate()
Update the annotation of the symbol according the the current object state.
Annotate using the first free reference number starting at the sheet number * 100.
SCHEMATIC & Schematic() const
size_t GetCount() const
ANNOTATE_SCOPE_T
Schematic annotation scope options.
bool IsAnnotated(const SCH_SHEET_PATH *aSheet)
Check if the symbol has a valid annotation (reference) for the given sheet path.
Definition: sch_symbol.cpp:507
Handle access to a stack of flattened SCH_SHEET objects by way of a path for creating a flattened sch...
ERCE_T
ERC error codes.
Definition: erc_settings.h:36
bool Contains(const SCH_REFERENCE &aItem)
Return true if aItem exists in this list.
std::map< wxString, SCH_REFERENCE_LIST > SCH_MULTI_UNIT_REFERENCE_MAP
Container to map reference designators for multi-unit parts.
virtual void Refresh(bool aEraseBackground=true, const wxRect *aRect=NULL) override
Update the board display after modifying it by a python script (note: it is automatically called by a...
SCH_COMPONENT * GetSymbol() const
const KIID m_Uuid
Definition: eda_item.h:525
Annotate by Y position from top to bottom.
Annotate incrementally using the first free reference number.
SCH_SHEET_LIST GetSheets() const override
Builds and returns an updated schematic hierarchy TODO: can this be cached?
Definition: schematic.h:87
int CheckAnnotation(ANNOTATION_ERROR_HANDLER aErrorHandler)
Check for annotations errors.
void Annotate(bool aUseSheetNum, int aSheetIntervalId, int aStartNumber, SCH_MULTI_UNIT_REFERENCE_MAP aLockedUnitMap, const SCH_REFERENCE_LIST &aAdditionalRefs, bool aStartAtCurrent=false)
Set the reference designators in the list that have not been annotated.
TOOL_MANAGER * m_toolManager
Definition: tools_holder.h:157
SCH_SCREEN * LastScreen()
void SetSheetNumberAndCount()
Set the m_ScreenNumber and m_NumberOfScreens members for screens.
void SplitReferences()
Attempt to split all reference designators into a name (U) and number (1).
void SaveCopyInUndoList(SCH_SCREEN *aScreen, SCH_ITEM *aItemToCopy, UNDO_REDO aTypeCommand, bool aAppend)
Create a copy of the current schematic item, and put it in the undo list.
#define _(s)
Definition: 3d_actions.cpp:33
std::function< void(ERCE_T aType, const wxString &aMsg, SCH_REFERENCE *aItemA, SCH_REFERENCE *aItemB)> ANNOTATION_ERROR_HANDLER
Define a standard error handler for annotation errors.
wxString AsString() const
Definition: kiid.cpp:277
ANNOTATE_ALGO_T
Schematic annotation type options.
EE_RTREE & Items()
Definition: sch_screen.h:103
void GetSymbols(SCH_REFERENCE_LIST &aReferences, bool aIncludePowerSymbols=true, bool aForceIncludeOrphanSymbols=false) const
Adds SCH_REFERENCE object to aReferences for each symbol in the sheet.
Annotate by X position from left to right.
static wxString SubReference(int aUnit, bool aAddSeparator=true)
Definition: lib_symbol.cpp:447
Schematic symbol object.
Definition: sch_symbol.h:78
A base class for most all the KiCad significant classes used in schematics and boards.
Definition: eda_item.h:150
Annotate using the first free reference number starting at the sheet number * 1000.
SCH_SHEET_PATH & GetCurrentSheet() const
int ReplaceDuplicateTimeStamps()
Test all sheet and component objects in the schematic for duplicate time stamps and replaces them as ...
void OnModify() override
Must be called after a schematic change in order to set the "modify" flag of the current screen and u...
Annotate the current sheet.
Definition for part library class.
void ClearAnnotation(const SCH_SHEET_PATH *aSheetPath)
Clear exiting symbol annotation.
void GetSymbols(SCH_REFERENCE_LIST &aReferences, const SCH_SHEET_PATH &aSelectionPath, bool aIncludePowerSymbols=true, bool aForceIncludeOrphanSymbols=false)
Adds SCH_REFERENCE object to aReferences for each symbol in the selection.
Base class for any item which can be embedded within the SCHEMATIC container class,...
Definition: sch_item.h:197
int GetUnitSelection(const SCH_SHEET_PATH *aSheet) const
Return the instance-specific unit selection for the given sheet path.
Definition: sch_symbol.cpp:521
A helper to define a symbol's reference designator in a schematic.
Container class that holds multiple SCH_SCREEN objects in a hierarchy.
Definition: sch_screen.h:549
const wxString GetRef(const SCH_SHEET_PATH *aSheet, bool aIncludeUnit=false) const
Return the reference for the given sheet path.
Definition: sch_symbol.cpp:431