KiCad PCB EDA Suite
Loading...
Searching...
No Matches
sch_tool_utils.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 The 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 "sch_tool_utils.h"
25
26#include <sch_text.h>
27#include <sch_field.h>
28#include <sch_pin.h>
29#include <sch_reference_list.h>
30#include <sch_symbol.h>
31#include <sch_table.h>
32#include <sch_tablecell.h>
33#include <sch_textbox.h>
34#include <schematic.h>
35#include <sch_sheet_path.h>
36#include <sch_sheet.h>
37#include <kiid.h>
38
39#include <wx/arrstr.h>
40
41wxString GetSchItemAsText( const SCH_ITEM& aItem )
42{
43 switch( aItem.Type() )
44 {
45 case SCH_TEXT_T:
46 case SCH_LABEL_T:
50 case SCH_SHEET_PIN_T:
51 {
52 const SCH_TEXT& text = static_cast<const SCH_TEXT&>( aItem );
53 return text.GetShownText( true );
54 }
55 case SCH_FIELD_T:
56 {
57 // Goes via EDA_TEXT
58 const SCH_FIELD& field = static_cast<const SCH_FIELD&>( aItem );
59 return field.GetShownText( true );
60 }
61 case SCH_TEXTBOX_T:
62 case SCH_TABLECELL_T:
63 {
64 // Also EDA_TEXT
65 const SCH_TEXTBOX& textbox = static_cast<const SCH_TEXTBOX&>( aItem );
66 return textbox.GetShownText( true );
67 }
68 case SCH_PIN_T:
69 {
70 // This is a choice - probably the name makes more sense than the number
71 // (or should it be name/number?)
72 const SCH_PIN& pin = static_cast<const SCH_PIN&>( aItem );
73 return pin.GetShownName();
74 }
75 case SCH_TABLE_T:
76 {
77 // A simple tabbed list of the cells seems like a place to start here
78 const SCH_TABLE& table = static_cast<const SCH_TABLE&>( aItem );
79 wxString s;
80
81 for( int row = 0; row < table.GetRowCount(); ++row )
82 {
83 for( int col = 0; col < table.GetColCount(); ++col )
84 {
85 const SCH_TABLECELL* cell = table.GetCell( row, col );
86 s << cell->GetShownText( true );
87
88 if( col < table.GetColCount() - 1 )
89 {
90 s << '\t';
91 }
92 }
93
94 if( row < table.GetRowCount() - 1 )
95 {
96 s << '\n';
97 }
98 }
99 return s;
100 }
101 default:
102 {
103 break;
104 }
105 }
106
107 return wxEmptyString;
108};
109
110
111wxString GetSelectedItemsAsText( const SELECTION& aSel )
112{
113 wxArrayString itemTexts;
114
115 for( EDA_ITEM* item : aSel )
116 {
117 if( item->IsSCH_ITEM() )
118 {
119 const SCH_ITEM& schItem = static_cast<const SCH_ITEM&>( *item );
120 wxString itemText = GetSchItemAsText( schItem );
121
122 itemText.Trim( false ).Trim( true );
123
124 if( !itemText.IsEmpty() )
125 {
126 itemTexts.Add( std::move( itemText ) );
127 }
128 }
129 }
130
131 return wxJoin( itemTexts, '\n', '\0' );
132}
133
134
135std::set<int> GetUnplacedUnitsForSymbol( const SCH_SYMBOL& aSym )
136{
137 SCHEMATIC const* schematic = aSym.Schematic();
138
139 if( !schematic )
140 return {};
141
142 const wxString symRefDes = aSym.GetRef( &schematic->CurrentSheet(), false );
143
144 // Get a list of all references in the schematic
145 SCH_SHEET_LIST hierarchy = schematic->Hierarchy();
146 SCH_REFERENCE_LIST existingRefs;
147 hierarchy.GetSymbols( existingRefs );
148
149 std::set<int> missingUnits;
150
151 for( int unit = 1; unit <= aSym.GetUnitCount(); ++unit )
152 missingUnits.insert( unit );
153
154 for( const SCH_REFERENCE& ref : existingRefs )
155 {
156 if( symRefDes == ref.GetRef() )
157 missingUnits.erase( ref.GetUnit() );
158 }
159
160 return missingUnits;
161}
162
163
164std::optional<SCH_REFERENCE> FindSymbolByRefAndUnit( const SCHEMATIC& aSchematic,
165 const wxString& aRef, int aUnit )
166{
168 aSchematic.Hierarchy().GetSymbols( refs );
169
170 for( const SCH_REFERENCE& ref : refs )
171 {
172 if( ref.GetRef() == aRef && ref.GetUnit() == aUnit )
173 {
174 return ref;
175 }
176 }
177
178 return std::nullopt;
179}
180
181
182std::vector<SCH_SYMBOL*> GetSameSymbolMultiUnitSelection( const SELECTION& aSel )
183{
184 std::vector<SCH_SYMBOL*> result;
185
186 if( aSel.GetSize() < 2 || !aSel.OnlyContains( { SCH_SYMBOL_T } ) )
187 return result;
188
189 wxString rootRef;
190 LIB_ID rootLibId;
191 bool haveRootLibId = false;
192 size_t rootPinCount = 0;
193 bool haveRootPinCount = false;
194
195 // Preserve selection order for cyclical swaps A->B->C
196 std::vector<EDA_ITEM*> itemsInOrder = aSel.GetItemsSortedBySelectionOrder();
197
198 for( EDA_ITEM* it : itemsInOrder )
199 {
200 SCH_SYMBOL* sym = dynamic_cast<SCH_SYMBOL*>( it );
201
202 if( !sym || !sym->GetLibSymbolRef() || sym->GetLibSymbolRef()->GetUnitCount() < 2 )
203 return {};
204
205 const SCH_SHEET_PATH& sheet = sym->Schematic()->CurrentSheet();
206
207 // Get unit-less reference
208 wxString ref = sym->GetRef( &sheet, false );
209
210 if( rootRef.IsEmpty() )
211 rootRef = ref;
212
213 if( ref != rootRef )
214 return {};
215
216 // Make sure the user isn't selecting units that are misreferenced such that
217 // they have U1A and U1B that are actually from different library symbols.
218 const LIB_ID& libId = sym->GetLibId();
219
220 if( !haveRootLibId )
221 {
222 rootLibId = libId;
223 haveRootLibId = true;
224 }
225
226 if( libId != rootLibId )
227 return {};
228
229 // Ensure same pin count across selected units
230 size_t pinCount = sym->GetPins( &sheet ).size();
231
232 if( !haveRootPinCount )
233 {
234 rootPinCount = pinCount;
235 haveRootPinCount = true;
236 }
237
238 if( pinCount != rootPinCount )
239 return {};
240
241 result.push_back( sym );
242 }
243
244 if( result.size() < 2 )
245 return {};
246
247 return result;
248}
249
250
251bool SwapPinGeometry( SCH_PIN* aFirst, SCH_PIN* aSecond )
252{
253 wxCHECK_MSG( aFirst && aSecond, false, "Invalid pins supplied to SwapPinGeometry" );
254
255 // If the schematic pin is still backed by a library definition, swap that library pin; once the
256 // caller sees the true return value it can decide to clone the updated library data into the
257 // schematic cache. Otherwise the schematic already owns a local copy, so swap in place.
258 SCH_PIN* firstPin = aFirst->GetLibPin() ? aFirst->GetLibPin() : aFirst;
259 SCH_PIN* secondPin = aSecond->GetLibPin() ? aSecond->GetLibPin() : aSecond;
260
261 VECTOR2I firstLocal = firstPin->GetLocalPosition();
262 VECTOR2I secondLocal = secondPin->GetLocalPosition();
263 firstPin->SetPosition( secondLocal );
264 secondPin->SetPosition( firstLocal );
265
266 PIN_ORIENTATION firstOrientation = firstPin->GetOrientation();
267 PIN_ORIENTATION secondOrientation = secondPin->GetOrientation();
268 firstPin->SetOrientation( secondOrientation );
269 secondPin->SetOrientation( firstOrientation );
270
271 int firstLength = firstPin->GetLength();
272 int secondLength = secondPin->GetLength();
273 firstPin->SetLength( secondLength );
274 secondPin->SetLength( firstLength );
275
276 const wxString& firstOp = firstPin->GetOperatingPoint();
277 const wxString& secondOp = secondPin->GetOperatingPoint();
278 firstPin->SetOperatingPoint( secondOp );
279 secondPin->SetOperatingPoint( firstOp );
280
281 // Return true if we touched the library-backed copy so callers can refresh the schematic symbol
282 // cache once the swap completes.
283 return ( firstPin != aFirst ) || ( secondPin != aSecond );
284}
285
286
287bool SymbolHasSheetInstances( const SCH_SYMBOL& aSymbol, const wxString& aCurrentProject,
288 std::set<wxString>* aSheetPaths, std::set<wxString>* aProjectNames )
289{
290 std::set<KIID_PATH> uniquePaths;
291 std::set<wxString> sheetPaths;
292 std::set<wxString> otherProjects;
293
294 for( const SCH_SYMBOL_INSTANCE& instance : aSymbol.GetInstances() )
295 {
296 uniquePaths.insert( instance.m_Path );
297
298 if( !instance.m_Path.empty() )
299 sheetPaths.insert( instance.m_Path.AsString() );
300
301 if( !instance.m_ProjectName.IsEmpty() )
302 {
303 if( aCurrentProject.IsEmpty() || !instance.m_ProjectName.IsSameAs( aCurrentProject ) )
304 otherProjects.insert( instance.m_ProjectName );
305 }
306 }
307
308 bool sharedWithinProject = uniquePaths.size() > 1;
309 bool sharedWithOtherProjects = !otherProjects.empty();
310
311 if( aSheetPaths )
312 {
313 if( sharedWithinProject )
314 *aSheetPaths = sheetPaths;
315 else
316 aSheetPaths->clear();
317 }
318
319 if( aProjectNames )
320 {
321 if( sharedWithOtherProjects )
322 *aProjectNames = otherProjects;
323 else
324 aProjectNames->clear();
325 }
326
327 return sharedWithinProject || sharedWithOtherProjects;
328}
329
330
331std::set<wxString> GetSheetNamesFromPaths( const std::set<wxString>& aSheetPaths, const SCHEMATIC& aSchematic )
332{
333 std::set<wxString> friendlyNames;
334
335 if( aSheetPaths.empty() )
336 return friendlyNames;
337
338 SCH_SHEET_LIST hierarchy = aSchematic.Hierarchy();
339
340 for( const wxString& pathStr : aSheetPaths )
341 {
342 wxString display = pathStr;
343
344 try
345 {
346 KIID_PATH kiidPath( pathStr );
347
348 for( const SCH_SHEET_PATH& sheetPath : hierarchy )
349 {
350 if( sheetPath.Path() == kiidPath )
351 {
352 wxString sheetNames;
353
354 for( size_t ii = 0; ii < sheetPath.size(); ++ii )
355 {
356 SCH_SHEET* sheet = sheetPath.at( ii );
357
358 if( !sheet )
359 continue;
360
361 const SCH_FIELD* nameField = sheet->GetField( FIELD_T::SHEET_NAME );
362
363 if( !nameField )
364 continue;
365
366 wxString name = nameField->GetShownText( false );
367
368 if( name.IsEmpty() )
369 continue;
370
371 if( !sheetNames.IsEmpty() )
372 sheetNames << wxS( "/" );
373
374 sheetNames << name;
375 }
376
377 if( sheetNames.IsEmpty() )
378 display = sheetPath.PathHumanReadable( false, true );
379 else
380 display = sheetNames;
381
382 break;
383 }
384 }
385 }
386 catch( ... )
387 {
388 // If the path cannot be parsed, fall back to the raw string.
389 }
390
391 friendlyNames.insert( display );
392 }
393
394 return friendlyNames;
395}
const char * name
A base class for most all the KiCad significant classes used in schematics and boards.
Definition eda_item.h:98
KICAD_T Type() const
Returns the type of object.
Definition eda_item.h:110
A logical library item identifier and consists of various portions much like a URI.
Definition lib_id.h:49
int GetUnitCount() const override
Holds all the data relating to one schematic.
Definition schematic.h:88
SCH_SHEET_LIST Hierarchy() const
Return the full schematic flattened hierarchical sheet list.
SCH_SHEET_PATH & CurrentSheet() const
Definition schematic.h:171
wxString GetShownText(const SCH_SHEET_PATH *aPath, bool aAllowExtraText, int aDepth=0) const
Base class for any item which can be embedded within the SCHEMATIC container class,...
Definition sch_item.h:167
SCHEMATIC * Schematic() const
Search the item hierarchy to find a SCHEMATIC.
Definition sch_item.cpp:244
VECTOR2I GetLocalPosition() const
Definition sch_pin.h:237
int GetLength() const
Definition sch_pin.cpp:298
const wxString & GetOperatingPoint() const
Definition sch_pin.h:324
void SetOrientation(PIN_ORIENTATION aOrientation)
Definition sch_pin.h:93
SCH_PIN * GetLibPin() const
Definition sch_pin.h:89
void SetPosition(const VECTOR2I &aPos) override
Definition sch_pin.h:238
void SetLength(int aLength)
Definition sch_pin.h:99
PIN_ORIENTATION GetOrientation() const
Definition sch_pin.cpp:263
void SetOperatingPoint(const wxString &aText)
Definition sch_pin.h:325
Container to create a flattened list of symbols because in a complex hierarchy, a symbol can be used ...
A helper to define a symbol's reference designator in a schematic.
A container for handling SCH_SHEET_PATH objects in a flattened hierarchy.
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.
Handle access to a stack of flattened SCH_SHEET objects by way of a path for creating a flattened sch...
Sheet symbol placed in a schematic, and is the entry point for a sub schematic.
Definition sch_sheet.h:47
SCH_FIELD * GetField(FIELD_T aFieldType)
Return a mandatory field in this sheet.
Schematic symbol object.
Definition sch_symbol.h:75
const std::vector< SCH_SYMBOL_INSTANCE > & GetInstances() const
Definition sch_symbol.h:134
std::vector< SCH_PIN * > GetPins(const SCH_SHEET_PATH *aSheet) const
Retrieve a list of the SCH_PINs for the given sheet path.
const LIB_ID & GetLibId() const override
Definition sch_symbol.h:164
int GetUnitCount() const override
Return the number of units per package of the symbol.
std::unique_ptr< LIB_SYMBOL > & GetLibSymbolRef()
Definition sch_symbol.h:183
const wxString GetRef(const SCH_SHEET_PATH *aSheet, bool aIncludeUnit=false) const override
virtual wxString GetShownText(const RENDER_SETTINGS *aSettings, const SCH_SHEET_PATH *aPath, bool aAllowExtraText, int aDepth=0) const
virtual unsigned int GetSize() const override
Return the number of stored items.
Definition selection.h:105
std::vector< EDA_ITEM * > GetItemsSortedBySelectionOrder() const
bool OnlyContains(std::vector< KICAD_T > aList) const
Checks if all items in the selection have a type in aList.
PIN_ORIENTATION
The symbol library pin object orientations.
Definition pin_type.h:105
Definition of the SCH_SHEET_PATH and SCH_SHEET_LIST classes for Eeschema.
std::set< wxString > GetSheetNamesFromPaths(const std::set< wxString > &aSheetPaths, const SCHEMATIC &aSchematic)
Get human-readable sheet names from a set of sheet paths, e.g.
bool SwapPinGeometry(SCH_PIN *aFirst, SCH_PIN *aSecond)
Swap the positions/lengths/etc.
std::set< int > GetUnplacedUnitsForSymbol(const SCH_SYMBOL &aSym)
Get a list of unplaced (i.e.
wxString GetSelectedItemsAsText(const SELECTION &aSel)
bool SymbolHasSheetInstances(const SCH_SYMBOL &aSymbol, const wxString &aCurrentProject, std::set< wxString > *aSheetPaths, std::set< wxString > *aProjectNames)
Returns true when the given symbol has instances, e.g.
std::optional< SCH_REFERENCE > FindSymbolByRefAndUnit(const SCHEMATIC &aSchematic, const wxString &aRef, int aUnit)
Find a symbol by reference and unit.
std::vector< SCH_SYMBOL * > GetSameSymbolMultiUnitSelection(const SELECTION &aSel)
Validates and gathers a selection containing multiple symbol units that all belong to the same refere...
wxString GetSchItemAsText(const SCH_ITEM &aItem)
A simple container for schematic symbol instance information.
wxString result
Test unit parsing edge cases and error handling.
@ SCH_TABLE_T
Definition typeinfo.h:169
@ SCH_TABLECELL_T
Definition typeinfo.h:170
@ SCH_FIELD_T
Definition typeinfo.h:154
@ SCH_DIRECTIVE_LABEL_T
Definition typeinfo.h:175
@ SCH_LABEL_T
Definition typeinfo.h:171
@ SCH_HIER_LABEL_T
Definition typeinfo.h:173
@ SCH_SHEET_PIN_T
Definition typeinfo.h:178
@ SCH_TEXT_T
Definition typeinfo.h:155
@ SCH_TEXTBOX_T
Definition typeinfo.h:156
@ SCH_GLOBAL_LABEL_T
Definition typeinfo.h:172
@ SCH_PIN_T
Definition typeinfo.h:157
VECTOR2< int32_t > VECTOR2I
Definition vector2d.h:695