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 <class_libentry.h>
32 #include <algorithm>
33 
34 
36  const list<SCH_COMPONENT*> aComponents, bool aCreateUndoEntry )
37 {
38  DIALOG_UPDATE_FIELDS dlg( aCaller, aComponents, aCreateUndoEntry );
39  return dlg.ShowQuasiModal();
40 }
41 
42 
44  const list<SCH_COMPONENT*>& aComponents, bool aCreateUndoEntry )
45  : DIALOG_UPDATE_FIELDS_BASE( aParent ), m_frame( aParent ),
46  m_components( aComponents ), m_createUndo( aCreateUndoEntry )
47 {
48  m_sdbSizerOK->SetDefault();
49 }
50 
51 
53 {
54  if( !wxDialog::TransferDataFromWindow() )
55  return false;
56 
57  if( m_components.empty() )
58  return true; // nothing to process
59 
60 
61  // Create the set of fields to be updated
62  m_updateFields.clear();
63 
64  for( unsigned i = 0; i < m_fieldsBox->GetCount(); ++i )
65  {
66  if( m_fieldsBox->IsChecked( i ) )
67  m_updateFields.insert( m_fieldsBox->GetString( i ) );
68  }
69 
70 
71  // Undo buffer entry
72  if( m_createUndo )
73  {
74  PICKED_ITEMS_LIST itemsList;
75 
76  for( auto component : m_components )
77  itemsList.PushItem( ITEM_PICKER( component, UR_CHANGED ) );
78 
79  m_frame->SaveCopyInUndoList( itemsList, UR_CHANGED );
80  }
81 
82 
83  // Do it!
84  for( auto component : m_components )
85  updateFields( component );
86 
87  m_frame->SyncView();
89  m_frame->OnModify();
90 
91  return true;
92 }
93 
94 
96 {
97  if( !wxDialog::TransferDataToWindow() || !m_components.size() )
98  return false;
99 
100  // Collect all user field names from library parts of components that are going to be updated
101  {
102  for( auto component : m_components )
103  {
104  const std::unique_ptr< LIB_PART >& part = component->GetPartRef();
105 
106  if( !part )
107  continue;
108 
109  const auto& drawItems = part->GetDrawItems();
110 
111  for( auto it = drawItems.begin( LIB_FIELD_T ); it != drawItems.end( LIB_FIELD_T ); ++it )
112  {
113  const LIB_FIELD* field = static_cast<const LIB_FIELD*>( &( *it ) );
114 
115  if( field->GetId() >= MANDATORY_FIELDS )
116  m_updateFields.insert( field->GetName() );
117  }
118  }
119  }
120 
121  // Update the listbox widget
122  m_fieldsBox->Clear();
123 
124  for( int i = 0; i < MANDATORY_FIELDS; ++i )
125  {
126  m_fieldsBox->Append( m_components.front()->GetField( i )->GetName() );
127 
128  if( i != REFERENCE && i != VALUE )
129  m_fieldsBox->Check( i, true );
130  }
131 
132  for( const wxString& fieldName : m_updateFields )
133  {
134  int idx = m_fieldsBox->Append( fieldName );
135  m_fieldsBox->Check( idx, true );
136  }
137 
138  // Now all widgets have the size fixed, call FinishDialogSettings
140 
141  return true;
142 }
143 
144 
146 {
147  SCH_FIELDS newFields;
148 
149  std::unique_ptr< LIB_PART >& libPart = aComponent->GetPartRef();
150 
151  if( !libPart ) // the symbol is not found in lib: cannot update fields
152  return;
153 
154  LIB_PART* alias = m_frame->GetLibPart( aComponent->GetLibId() );
155 
156  for( const SCH_FIELD& existingField : aComponent->GetFields() )
157  {
158  if( existingField.GetId() >= 0 && existingField.GetId() < MANDATORY_FIELDS )
159  {
160  newFields.push_back( existingField );
161  continue;
162  }
163 
164  // If requested, transfer only fields that occur also in the original library part
165  if( m_removeExtraBox->IsChecked() && !libPart->FindField( existingField.GetName() ) )
166  continue;
167 
168  newFields.push_back( existingField );
169  }
170 
171  // Update the requested fields
172  for( const wxString& fieldName : m_updateFields )
173  {
174  LIB_FIELD* libField = libPart->FindField( fieldName );
175 
176  if( !libField )
177  continue;
178 
179  auto it = std::find_if( newFields.begin(), newFields.end(),
180  [&] ( const SCH_FIELD& f )
181  {
182  return f.GetName() == fieldName;
183  } );
184 
185  if( it != newFields.end() )
186  {
187  SCH_FIELD* newField = &*it;
188  wxString fieldValue = libField->GetText();
189 
190  if( alias )
191  {
192  if( fieldName == TEMPLATE_FIELDNAME::GetDefaultFieldName( VALUE ) )
193  fieldValue = alias->GetName();
194  else if( fieldName == TEMPLATE_FIELDNAME::GetDefaultFieldName( DATASHEET ) )
195  fieldValue = alias->GetDatasheetField().GetText();
196  }
197 
198  if( fieldValue.IsEmpty() )
199  {
200  // If the library field is empty an update would clear an existing entry.
201  // Check if this is the desired behavior.
202  if( m_resetEmpty->IsChecked() )
203  newField->SetText( wxEmptyString );
204  }
205  else
206  {
207  newField->SetText( fieldValue );
208  }
209 
210  if( m_resetVisibility->IsChecked() )
211  {
212  newField->SetVisible( libField->IsVisible() );
213  }
214 
215  if( m_resetPosition->IsChecked() )
216  {
217  newField->SetTextAngle( libField->GetTextAngle() );
218 
219  // Schematic fields are schematic-relative; symbol editor fields are component-relative
220  if( m_createUndo )
221  newField->SetTextPos( libField->GetTextPos() + aComponent->GetPosition() );
222  else
223  newField->SetTextPos( libField->GetTextPos() );
224  }
225 
226  if( m_resetSizeAndStyle->IsChecked() )
227  {
228  newField->SetHorizJustify( libField->GetHorizJustify() );
229  newField->SetVertJustify( libField->GetVertJustify() );
230  newField->SetTextSize( libField->GetTextSize() );
231  newField->SetItalic( libField->IsItalic() );
232  newField->SetBold( libField->IsBold() );
233  }
234  }
235  else
236  {
237  // Missing field, it has to be added to the component
238  SCH_FIELD newField( wxPoint( 0, 0 ), newFields.size(), aComponent, fieldName );
239 
240  newField.ImportValues( *libField );
241  newField.SetText( libField->GetText() );
242 
243  // Schematic fields are schematic-relative; symbol editor fields are component-relative
244  if( m_createUndo )
245  newField.SetTextPos( libField->GetTextPos() + aComponent->GetPosition() );
246  else
247  newField.SetTextPos( libField->GetTextPos() );
248 
249  newFields.push_back( newField );
250  }
251  }
252 
253  // Apply changes & clean-up
254  aComponent->SetFields( newFields );
255 }
256 
257 
259 {
260  for( unsigned i = 0; i < m_fieldsBox->GetCount(); ++i )
261  m_fieldsBox->Check( i, aCheck );
262 }
bool IsBold() const
Definition: eda_text.h:182
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:199
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.
bool TransferDataFromWindow() override
wxString GetName() const override
bool IsVisible() const
Definition: eda_text.h:185
void ImportValues(const LIB_FIELD &aSource)
Function ImportValues copy parameters from a LIB_FIELD source.
Definition: sch_field.cpp:215
void SetItalic(bool isItalic)
Definition: eda_text.h:178
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
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:246
void SetVisible(bool aVisible)
Definition: eda_text.h:184
set< wxString > m_updateFields
Set of field names that should have values updated
double GetTextAngle() const
Definition: eda_text.h:173
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:237
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:179
list< SCH_COMPONENT * > m_components
Components to update
#define VALUE
EDA_TEXT_HJUSTIFY_T GetHorizJustify() const
Definition: eda_text.h:198
void SetFields(const SCH_FIELDS &aFields)
Set multiple schematic fields.
virtual void SetText(const wxString &aText)
Definition: eda_text.cpp:116
void SyncView()
Mark all items for refresh.
int ShowQuasiModal()
Class LIB_PIN definition.
const wxSize & GetTextSize() const
Definition: eda_text.h:238
std::vector< SCH_FIELD > SCH_FIELDS
A container for several SCH_FIELD items.
Definition: sch_component.h:77
void SetVertJustify(EDA_TEXT_VJUSTIFY_T aType)
Definition: eda_text.h:202
const wxPoint GetPosition() const override
SCH_DRAW_PANEL * GetCanvas() const override
Return a pointer to GAL-based canvas of given EDA draw frame.
bool m_createUndo
Flag indicating whether an undo buffer entry should be created
void SaveCopyInUndoList(SCH_ITEM *aItemToCopy, UNDO_REDO_T aTypeCommand, bool aAppend=false, const wxPoint &aTransformPoint=wxPoint(0, 0))
Create a copy of the current schematic item, and put it in the undo list.
DIALOG_UPDATE_FIELDS(SCH_EDIT_FRAME *aParent, const list< SCH_COMPONENT * > &aComponents, bool aCreateUndoEntry=true)
Define a library symbol object.
std::unique_ptr< LIB_PART > & GetPartRef()
PICKED_ITEMS_LIST is a holder to handle information on schematic or board items.
int InvokeDialogUpdateFields(SCH_EDIT_FRAME *aCaller, const list< SCH_COMPONENT * > aComponents, bool aCreateUndoEntry)
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...
void SetHorizJustify(EDA_TEXT_HJUSTIFY_T aType)
Definition: eda_text.h:201
Class DIALOG_UPDATE_FIELDS_BASE.
Schematic symbol object.
Definition: sch_component.h:88
SCH_EDIT_FRAME * m_frame
Parent frame
const wxPoint & GetTextPos() const
Definition: eda_text.h:247
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:166
const LIB_ID & GetLibId() const
void updateFields(SCH_COMPONENT *aComponent)
Update fields for a single component
void SetBold(bool aBold)
Definition: eda_text.h:181
virtual const wxString & GetText() const
Return the string associated with the text object.
Definition: eda_text.h:126