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 <symbol_library.h>
33 #include <tools/ee_selection.h>
35 #include <tool/tool_manager.h>
36 #include <dialog_erc.h>
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_SYMBOL* 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_SYMBOL::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_SYMBOL* symbol = static_cast<SCH_SYMBOL*>( 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_SYMBOL_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_SYMBOL_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  wxWindow* erc_dlg = wxWindow::FindWindowByName( DIALOG_ERC_WINDOW_NAME );
118 
119  if( erc_dlg )
120  static_cast<DIALOG_ERC*>( erc_dlg )->UpdateAnnotationWarning();
121 
122  SyncView();
123  GetCanvas()->Refresh();
124  OnModify();
125 
126  // Must go after OnModify() so the connectivity graph has been updated
128 }
129 
130 
132  ANNOTATE_ORDER_T aSortOption,
133  ANNOTATE_ALGO_T aAlgoOption,
134  int aStartNumber,
135  bool aResetAnnotation,
136  bool aRepairTimestamps,
137  REPORTER& aReporter )
138 {
140  EE_SELECTION& selection = selTool->RequestSelection();
141 
142  SCH_REFERENCE_LIST references;
143  SCH_SCREENS screens( Schematic().Root() );
144  SCH_SHEET_LIST sheets = Schematic().GetSheets();
145  SCH_SHEET_PATH currentSheet = GetCurrentSheet();
146  bool appendUndo = false;
147 
148  // Map of locked symbols
149  SCH_MULTI_UNIT_REFERENCE_MAP lockedSymbols;
150 
151  // Map of previous annotation for building info messages
152  std::map<wxString, wxString> previousAnnotation;
153 
154  // Test for and replace duplicate time stamps in symbols and sheets. Duplicate
155  // time stamps can happen with old schematics, schematic conversions, or manual
156  // editing of files.
157  if( aRepairTimestamps )
158  {
159  int count = screens.ReplaceDuplicateTimeStamps();
160 
161  if( count )
162  {
163  wxString msg;
164  msg.Printf( _( "%d duplicate time stamps were found and replaced." ), count );
165  aReporter.ReportTail( msg, RPT_SEVERITY_WARNING );
166  }
167  }
168 
169  // Collect all the sets that must be annotated together.
170  switch( aAnnotateScope )
171  {
172  case ANNOTATE_ALL:
173  sheets.GetMultiUnitSymbols( lockedSymbols );
174  break;
175 
177  currentSheet.GetMultiUnitSymbols( lockedSymbols );
178  break;
179 
180  case ANNOTATE_SELECTION:
181  selection.GetMultiUnitSymbols( lockedSymbols, currentSheet );
182  break;
183  }
184 
185  // Store previous annotations for building info messages
186  mapExistingAnnotation( previousAnnotation );
187 
188  // If it is an annotation for all the symbols, reset previous annotation.
189  if( aResetAnnotation )
190  DeleteAnnotation( aAnnotateScope, &appendUndo );
191 
192  // Set sheet number and number of sheets.
194 
195  // Build symbol list
196  switch( aAnnotateScope )
197  {
198  case ANNOTATE_ALL:
199  sheets.GetSymbols( references );
200  break;
201 
203  GetCurrentSheet().GetSymbols( references );
204  break;
205 
206  case ANNOTATE_SELECTION:
207  selection.GetSymbols( references, currentSheet );
208  break;
209  }
210 
211  // Build additional list of references to be used during reannotation
212  // to avoid duplicate designators (no additional references when annotating
213  // the full schematic)
214  SCH_REFERENCE_LIST additionalRefs;
215 
216  if( aAnnotateScope != ANNOTATE_ALL )
217  {
218  SCH_REFERENCE_LIST allRefs;
219  sheets.GetSymbols( allRefs );
220 
221  for( size_t i = 0; i < allRefs.GetCount(); i++ )
222  {
223  if( !references.Contains( allRefs[i] ) )
224  additionalRefs.AddItem( allRefs[i] );
225  }
226  }
227 
228  // Break full symbol reference into name (prefix) and number:
229  // example: IC1 become IC, and 1
230  references.SplitReferences();
231 
232  switch( aSortOption )
233  {
234  default:
235  case SORT_BY_X_POSITION: references.SortByXCoordinate(); break;
236  case SORT_BY_Y_POSITION: references.SortByYCoordinate(); break;
237  }
238 
239  bool useSheetNum = false;
240  int idStep = 100;
241 
242  switch( aAlgoOption )
243  {
244  default:
245  case INCREMENTAL_BY_REF:
246  break;
247 
248  case SHEET_NUMBER_X_100:
249  useSheetNum = true;
250  break;
251 
252  case SHEET_NUMBER_X_1000:
253  useSheetNum = true;
254  idStep = 1000;
255  break;
256  }
257 
258  // Recalculate and update reference numbers in schematic
259  references.Annotate( useSheetNum, idStep, aStartNumber, lockedSymbols, additionalRefs );
260 
261  for( size_t i = 0; i < references.GetCount(); i++ )
262  {
263  SCH_REFERENCE& ref = references[i];
264  SCH_SYMBOL* symbol = ref.GetSymbol();
265  SCH_SHEET_PATH* sheet = &ref.GetSheetPath();
266 
267  SaveCopyInUndoList( sheet->LastScreen(), symbol, UNDO_REDO::CHANGED, appendUndo );
268  appendUndo = true;
269  ref.Annotate();
270 
271  KIID_PATH full_uuid = sheet->Path();
272  full_uuid.push_back( symbol->m_Uuid );
273 
274  wxString prevRef = previousAnnotation[ full_uuid.AsString() ];
275  wxString newRef = symbol->GetRef( sheet );
276 
277  if( symbol->GetUnitCount() > 1 )
278  newRef << LIB_SYMBOL::SubReference( symbol->GetUnitSelection( sheet ) );
279 
280  wxString msg;
281 
282  if( prevRef.Length() )
283  {
284  if( newRef == prevRef )
285  continue;
286 
287  if( symbol->GetUnitCount() > 1 )
288  {
289  msg.Printf( _( "Updated %s (unit %s) from %s to %s." ),
290  symbol->GetValue( sheet, true ),
291  LIB_SYMBOL::SubReference( symbol->GetUnit(), false ),
292  prevRef,
293  newRef );
294  }
295  else
296  {
297  msg.Printf( _( "Updated %s from %s to %s." ),
298  symbol->GetValue( sheet, true ),
299  prevRef,
300  newRef );
301  }
302  }
303  else
304  {
305  if( symbol->GetUnitCount() > 1 )
306  {
307  msg.Printf( _( "Annotated %s (unit %s) as %s." ),
308  symbol->GetValue( sheet, true ),
309  LIB_SYMBOL::SubReference( symbol->GetUnit(), false ),
310  newRef );
311  }
312  else
313  {
314  msg.Printf( _( "Annotated %s as %s." ),
315  symbol->GetValue( sheet, true ),
316  newRef );
317  }
318  }
319 
320  aReporter.Report( msg, RPT_SEVERITY_ACTION );
321  }
322 
323  // Final control (just in case ... ).
324  if( !CheckAnnotate(
325  [ &aReporter ]( ERCE_T , const wxString& aMsg, SCH_REFERENCE* , SCH_REFERENCE* )
326  {
327  aReporter.Report( aMsg, RPT_SEVERITY_ERROR );
328  },
329  aAnnotateScope ) )
330  {
331  aReporter.ReportTail( _( "Annotation complete." ), RPT_SEVERITY_ACTION );
332  }
333 
334  // Update on screen references, that can be modified by previous calculations:
337 
338  wxWindow* erc_dlg = wxWindow::FindWindowByName( DIALOG_ERC_WINDOW_NAME );
339 
340  if( erc_dlg )
341  static_cast<DIALOG_ERC*>( erc_dlg )->UpdateAnnotationWarning();
342 
343  SyncView();
344  GetCanvas()->Refresh();
345  OnModify();
346 
347  // Must go after OnModify() so the connectivity graph has been updated
349 }
350 
351 
353  ANNOTATE_SCOPE_T aAnnotateScope )
354 {
355  SCH_REFERENCE_LIST referenceList;
356  constexpr bool includePowerSymbols = false;
357 
358  // Build the list of symbols
359  switch( aAnnotateScope )
360  {
361  case ANNOTATE_ALL:
362  Schematic().GetSheets().GetSymbols( referenceList );
363  break;
364 
366  GetCurrentSheet().GetSymbols( referenceList, includePowerSymbols );
367  break;
368 
369  case ANNOTATE_SELECTION:
371  EE_SELECTION& selection = selTool->RequestSelection();
372  selection.GetSymbols( referenceList, GetCurrentSheet(), includePowerSymbols );
373  break;
374  }
375 
376  // Empty schematic does not need annotation
377  if( referenceList.GetCount() == 0 )
378  return 0;
379 
380  return referenceList.CheckAnnotation( aErrorHandler );
381 }
A container for handling SCH_SHEET_PATH objects in a flattened hierarchy.
EE_TYPE OfType(KICAD_T aType) const
Definition: sch_rtree.h:230
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.
int GetUnitCount() const
Return the number of units per package of the symbol.
Definition: sch_symbol.cpp:393
KIID_PATH Path() const
Get the sheet path as an KIID_PATH.
void ClearAnnotation(const SCH_SHEET_PATH *aSheetPath)
Clear exiting symbol annotation.
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:99
void DeleteAnnotation(ANNOTATE_SCOPE_T aAnnotateScope, bool *appendUndo)
Clear the current symbol 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:131
void AddItem(const SCH_REFERENCE &aItem)
static wxString SubReference(int aUnit, bool aAddSeparator=true)
Definition: lib_symbol.cpp:495
SCH_SYMBOL * GetSymbol() const
const wxString GetRef(const SCH_SHEET_PATH *aSheet, bool aIncludeUnit=false) const
Return the reference for the given sheet path.
Definition: sch_symbol.cpp:464
A pure virtual class used to derive REPORTER objects from.
Definition: reporter.h:70
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:352
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 ...
#define DIALOG_ERC_WINDOW_NAME
Definition: dialog_erc.h:37
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.
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.
int GetUnitSelection(const SCH_SHEET_PATH *aSheet) const
Return the instance-specific unit selection for the given sheet path.
Definition: sch_symbol.cpp:554
void Annotate()
Update the annotation of the symbol according the current object state.
Annotate using the first free reference number starting at the sheet number * 100.
SCHEMATIC & Schematic() const
size_t GetCount() const
Definition for symbol library class.
ANNOTATE_SCOPE_T
Schematic annotation scope options.
#define _(s)
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.
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:596
std::map< wxString, SCH_REFERENCE_LIST > SCH_MULTI_UNIT_REFERENCE_MAP
Container to map reference designators for multi-unit parts.
const KIID m_Uuid
Definition: eda_item.h:474
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:540
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:158
Schematic symbol object.
Definition: sch_symbol.h:78
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.
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:316
ANNOTATE_ALGO_T
Schematic annotation type options.
EE_RTREE & Items()
Gets the full RTree, usually for iterating.
Definition: sch_screen.h:110
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.
virtual void Refresh(bool aEraseBackground=true, const wxRect *aRect=nullptr) override
Update the board display after modifying it by a python script (note: it is automatically called by a...
Annotate by X position from left to right.
A base class for most all the KiCad significant classes used in schematics and boards.
Definition: eda_item.h:99
Annotate using the first free reference number starting at the sheet number * 1000.
SCH_SHEET_PATH & GetCurrentSheet() const
int ReplaceDuplicateTimeStamps()
Test all sheet and symbol objects in the schematic for duplicate time stamps and replaces them as nec...
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.
int GetUnit() const
Definition: sch_symbol.h:196
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:182
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:593