KiCad PCB EDA Suite
dialog_update_fields.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) 2017 CERN
5  * Copyright (C) 2020 KiCad Developers, see AUTHORS.txt for contributors.
6  *
7  * @author Maciej Suminski <maciej.suminski@cern.ch>
8  *
9  * This program is free software; you can redistribute it and/or
10  * modify it under the terms of the GNU General Public License
11  * as published by the Free Software Foundation; either version 3
12  * of the License, or (at your option) any later version.
13  *
14  * This program is distributed in the hope that it will be useful,
15  * but WITHOUT ANY WARRANTY; without even the implied warranty of
16  * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
17  * GNU General Public License for more details.
18  *
19  * You should have received a copy of the GNU General Public License
20  * along with this program; if not, you may find one here:
21  * https://www.gnu.org/licenses/gpl-3.0.html
22  * or you may search the http://www.gnu.org website for the version 3 license,
23  * or you may write to the Free Software Foundation, Inc.,
24  * 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301, USA
25  */
26 
27 #include "dialog_update_fields.h"
28 
29 #include <sch_edit_frame.h>
30 #include <sch_component.h>
31 #include <schematic.h>
32 #include <class_libentry.h>
33 #include <algorithm>
34 
35 
36 int InvokeDialogUpdateFields( SCH_EDIT_FRAME* aCaller, SCH_COMPONENT* aSpecificComponent,
37  bool aCreateUndoEntry )
38 {
39  DIALOG_UPDATE_FIELDS dlg( aCaller, aSpecificComponent, aCreateUndoEntry );
40  return dlg.ShowQuasiModal();
41 }
42 
43 
45  SCH_COMPONENT* aSpecificComponent,
46  bool aCreateUndoEntry ) :
47  DIALOG_UPDATE_FIELDS_BASE( aParent ),
48  m_frame( aParent ),
49  m_createUndo( aCreateUndoEntry )
50 {
51  if( aSpecificComponent )
52  {
53  m_components.emplace_back( aParent->GetScreen(), aSpecificComponent );
54  }
55  else
56  {
57  for( SCH_SHEET_PATH& path : aParent->Schematic().GetSheets() )
58  {
59  SCH_SCREEN* screen = path.LastScreen();
60 
61  for( SCH_ITEM* item : screen->Items().OfType( SCH_COMPONENT_T ) )
62  m_components.emplace_back( screen, static_cast<SCH_COMPONENT*>( item ) );
63  }
64  }
65 
66  m_sdbSizerOK->SetDefault();
67 }
68 
69 
71 {
72  if( !wxDialog::TransferDataFromWindow() )
73  return false;
74 
75  if( m_components.empty() )
76  return true; // nothing to process
77 
78  // Create the set of fields to be updated
79  m_updateFields.clear();
80 
81  for( unsigned i = 0; i < m_fieldsBox->GetCount(); ++i )
82  {
83  if( m_fieldsBox->IsChecked( i ) )
84  m_updateFields.insert( m_fieldsBox->GetString( i ) );
85  }
86 
87 
88  // Undo buffer entry
89  if( m_createUndo )
90  {
91  PICKED_ITEMS_LIST itemsList;
92 
93  for( std::pair<SCH_SCREEN*, SCH_COMPONENT*>& component : m_components )
94  itemsList.PushItem( ITEM_PICKER( component.first, component.second, UNDO_REDO::CHANGED ) );
95 
96  m_frame->SaveCopyInUndoList( itemsList, UNDO_REDO::CHANGED, true );
97  }
98 
99 
100  // Do it!
101  for( std::pair<SCH_SCREEN*, SCH_COMPONENT*>& component : m_components )
102  updateFields( component.second );
103 
104  m_frame->SyncView();
105  m_frame->GetCanvas()->Refresh();
106  m_frame->OnModify();
107 
108  return true;
109 }
110 
111 
113 {
114  if( !wxDialog::TransferDataToWindow() || !m_components.size() )
115  return false;
116 
117  // Collect all user field names from library parts of components that are going to be updated
118  {
119  for( std::pair<SCH_SCREEN*, SCH_COMPONENT*>& component : m_components )
120  {
121  const std::unique_ptr< LIB_PART >& part = component.second->GetPartRef();
122 
123  if( !part )
124  continue;
125 
126  const auto& drawItems = part->GetDrawItems();
127 
128  for( auto it = drawItems.begin( LIB_FIELD_T ); it != drawItems.end( LIB_FIELD_T ); ++it )
129  {
130  const LIB_FIELD* field = static_cast<const LIB_FIELD*>( &( *it ) );
131 
132  if( field->GetId() >= MANDATORY_FIELDS )
133  m_updateFields.insert( field->GetName() );
134  }
135  }
136  }
137 
138  // Update the listbox widget
139  m_fieldsBox->Clear();
140 
141  for( int i = 0; i < MANDATORY_FIELDS; ++i )
142  {
143  m_fieldsBox->Append( m_components.front().second->GetField( i )->GetName() );
144 
145  if( i != REFERENCE && i != VALUE )
146  m_fieldsBox->Check( i, true );
147  }
148 
149  for( const wxString& fieldName : m_updateFields )
150  {
151  int idx = m_fieldsBox->Append( fieldName );
152  m_fieldsBox->Check( idx, true );
153  }
154 
155  // Now all widgets have the size fixed, call FinishDialogSettings
157 
158  return true;
159 }
160 
161 
163 {
164  SCH_FIELDS newFields;
165 
166  std::unique_ptr< LIB_PART >& libPart = aComponent->GetPartRef();
167 
168  if( !libPart ) // the symbol is not found in lib: cannot update fields
169  return;
170 
171  LIB_PART* alias = m_frame->GetLibPart( aComponent->GetLibId() );
172 
173  for( const SCH_FIELD& existingField : aComponent->GetFields() )
174  {
175  if( existingField.GetId() >= 0 && existingField.GetId() < MANDATORY_FIELDS )
176  {
177  newFields.push_back( existingField );
178  continue;
179  }
180 
181  // If requested, transfer only fields that occur also in the original library part
182  if( m_removeExtraBox->IsChecked() && !libPart->FindField( existingField.GetName() ) )
183  continue;
184 
185  newFields.push_back( existingField );
186  }
187 
188  // Update the requested fields
189  for( const wxString& fieldName : m_updateFields )
190  {
191  LIB_FIELD* libField = libPart->FindField( fieldName );
192 
193  if( !libField )
194  continue;
195 
196  auto it = std::find_if( newFields.begin(), newFields.end(),
197  [&] ( const SCH_FIELD& f )
198  {
199  return f.GetName() == fieldName;
200  } );
201 
202  if( it != newFields.end() )
203  {
204  SCH_FIELD* newField = &*it;
205  wxString fieldValue = libField->GetText();
206 
207  if( alias )
208  {
209  if( fieldName == TEMPLATE_FIELDNAME::GetDefaultFieldName( VALUE ) )
210  fieldValue = alias->GetName();
211  else if( fieldName == TEMPLATE_FIELDNAME::GetDefaultFieldName( DATASHEET ) )
212  fieldValue = alias->GetDatasheetField().GetText();
213  }
214 
215  if( fieldValue.IsEmpty() )
216  {
217  // If the library field is empty an update would clear an existing entry.
218  // Check if this is the desired behavior.
219  if( m_resetEmpty->IsChecked() )
220  newField->SetText( wxEmptyString );
221  }
222  else
223  {
224  newField->SetText( fieldValue );
225  }
226 
227  if( m_resetVisibility->IsChecked() )
228  {
229  newField->SetVisible( libField->IsVisible() );
230  }
231 
232  if( m_resetPosition->IsChecked() )
233  {
234  newField->SetTextAngle( libField->GetTextAngle() );
235 
236  // Schematic fields are schematic-relative; symbol editor fields are component-relative
237  if( m_createUndo )
238  newField->SetTextPos( libField->GetTextPos() + aComponent->GetPosition() );
239  else
240  newField->SetTextPos( libField->GetTextPos() );
241  }
242 
243  if( m_resetSizeAndStyle->IsChecked() )
244  {
245  newField->SetHorizJustify( libField->GetHorizJustify() );
246  newField->SetVertJustify( libField->GetVertJustify() );
247  newField->SetTextSize( libField->GetTextSize() );
248  newField->SetItalic( libField->IsItalic() );
249  newField->SetBold( libField->IsBold() );
250  }
251  }
252  else
253  {
254  // Missing field, it has to be added to the component
255  SCH_FIELD newField( wxPoint( 0, 0 ), newFields.size(), aComponent, fieldName );
256 
257  newField.ImportValues( *libField );
258  newField.SetText( libField->GetText() );
259 
260  // Schematic fields are schematic-relative; symbol editor fields are component-relative
261  if( m_createUndo )
262  newField.SetTextPos( libField->GetTextPos() + aComponent->GetPosition() );
263  else
264  newField.SetTextPos( libField->GetTextPos() );
265 
266  newFields.push_back( newField );
267  }
268  }
269 
270  // Apply changes & clean-up
271  aComponent->SetFields( newFields );
272 }
273 
274 
276 {
277  for( unsigned i = 0; i < m_fieldsBox->GetCount(); ++i )
278  m_fieldsBox->Check( i, aCheck );
279 }
bool IsBold() const
Definition: eda_text.h:183
SCH_FIELD instances are attached to a component and provide a place for the component's value,...
Definition: sch_field.h:52
EDA_TEXT_VJUSTIFY_T GetVertJustify() const
Definition: eda_text.h:200
void checkAll(bool aCheck)
Selects or deselects all fields in the listbox widget
name of datasheet
LIB_FIELD & GetDatasheetField()
Return reference to the datasheet field.
SCH_SHEET_LIST GetSheets() const
Builds and returns an updated schematic hierarchy TODO: can this be cached?
Definition: schematic.h:89
bool TransferDataFromWindow() override
wxString GetName() const override
bool IsVisible() const
Definition: eda_text.h:186
void ImportValues(const LIB_FIELD &aSource)
Function ImportValues copy parameters from a LIB_FIELD source.
Definition: sch_field.cpp:233
void SetItalic(bool isItalic)
Definition: eda_text.h:179
The first 4 are mandatory, and must be instantiated in SCH_COMPONENT and LIB_PART constructors.
Dialog to update component fields (i.e.
Field object used in symbol libraries.
Definition: lib_field.h:59
EE_TYPE OfType(KICAD_T aType)
Definition: sch_rtree.h:219
void FinishDialogSettings()
In all dialogs, we must call the same functions to fix minimal dlg size, the default position and per...
void SetTextPos(const wxPoint &aPoint)
Definition: eda_text.h:247
void SetVisible(bool aVisible)
Definition: eda_text.h:185
double GetTextAngle() const
Definition: eda_text.h:174
void PushItem(const ITEM_PICKER &aItem)
Function PushItem pushes aItem to the top of the list.
static const wxString GetDefaultFieldName(int aFieldNdx)
Function GetDefaultFieldName returns a default symbol field name for field aFieldNdx for all componen...
Schematic editor (Eeschema) main window.
bool TransferDataToWindow() override
LIB_PART * GetLibPart(const LIB_ID &aLibId, bool aUseCacheLib=false, bool aShowErrorMsg=false)
Load symbol from symbol library table.
void SetTextSize(const wxSize &aNewSize)
Definition: eda_text.h:238
int GetId() const
Definition: lib_field.h:138
Field Reference of part, i.e. "IC21".
wxString GetName(bool aUseDefaultName=true) const
Returns the field name.
Definition: lib_field.cpp:366
void GetFields(std::vector< SCH_FIELD * > &aVector, bool aVisibleOnly)
Populates a std::vector with SCH_FIELDs.
bool IsItalic() const
Definition: eda_text.h:180
SCH_SCREEN * GetScreen() const override
Return a pointer to a BASE_SCREEN or one of its derivatives.
std::set< wxString > m_updateFields
Set of field names that should have values updated
EDA_TEXT_HJUSTIFY_T GetHorizJustify() const
Definition: eda_text.h:199
void SetFields(const SCH_FIELDS &aFields)
Set multiple schematic fields.
virtual void SetText(const wxString &aText)
Definition: eda_text.cpp:121
void SyncView()
Mark all items for refresh.
int ShowQuasiModal()
const wxSize & GetTextSize() const
Definition: eda_text.h:239
std::vector< SCH_FIELD > SCH_FIELDS
A container for several SCH_FIELD items.
Definition: sch_component.h:65
void SetVertJustify(EDA_TEXT_VJUSTIFY_T aType)
Definition: eda_text.h:203
SCH_DRAW_PANEL * GetCanvas() const override
Return a pointer to GAL-based canvas of given EDA draw frame.
SCHEMATIC & Schematic() const
Define a library symbol object.
void SaveCopyInUndoList(SCH_SCREEN *aScreen, SCH_ITEM *aItemToCopy, UNDO_REDO aTypeCommand, bool aAppend, const wxPoint &aTransformPoint=wxPoint(0, 0))
Create a copy of the current schematic item, and put it in the undo list.
SCH_SHEET_PATH.
std::unique_ptr< LIB_PART > & GetPartRef()
PICKED_ITEMS_LIST is a holder to handle information on schematic or board items.
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...
std::vector< std::pair< SCH_SCREEN *, SCH_COMPONENT * > > m_components
Components to update
Field Value of part, i.e. "3.3K".
void SetHorizJustify(EDA_TEXT_HJUSTIFY_T aType)
Definition: eda_text.h:202
Class DIALOG_UPDATE_FIELDS_BASE.
DIALOG_UPDATE_FIELDS(SCH_EDIT_FRAME *aParent, SCH_COMPONENT *aComponent, bool aCreateUndoEntry)
EE_RTREE & Items()
Definition: sch_screen.h:158
SCH_EDIT_FRAME * m_frame
Schematic symbol object.
Definition: sch_component.h:80
wxPoint GetPosition() const override
const wxPoint & GetTextPos() const
Definition: eda_text.h:248
void OnModify() override
Must be called after a schematic change in order to set the "modify" flag of the current screen and u...
virtual void SetTextAngle(double aAngle)
Definition: eda_text.h:167
const LIB_ID & GetLibId() const
void updateFields(SCH_COMPONENT *aComponent)
Update fields for a single component
void SetBold(bool aBold)
Definition: eda_text.h:182
Base class for any item which can be embedded within the SCHEMATIC container class,...
Definition: sch_item.h:194
virtual const wxString & GetText() const
Return the string associated with the text object.
Definition: eda_text.h:127
int InvokeDialogUpdateFields(SCH_EDIT_FRAME *aCaller, SCH_COMPONENT *aSpecificComponent, bool aCreateUndoEntry)
Update symbol fields.