KiCad PCB EDA Suite
dialog_edit_one_field.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) 2012 Jean-Pierre Charras, jean-pierre.charras@gipsa-lab.inpg.com
5  * Copyright (C) 2016 Wayne Stambaugh, stambaughw@gmail.com
6  * Copyright (C) 2004-2020 KiCad Developers, see change_log.txt for contributors.
7  *
8  * This program is free software; you can redistribute it and/or
9  * modify it under the terms of the GNU General Public License
10  * as published by the Free Software Foundation; either version 2
11  * of the License, or (at your option) any later version.
12  *
13  * This program is distributed in the hope that it will be useful,
14  * but WITHOUT ANY WARRANTY; without even the implied warranty of
15  * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
16  * GNU General Public License for more details.
17  *
18  * You should have received a copy of the GNU General Public License
19  * along with this program; if not, you may find one here:
20  * http://www.gnu.org/licenses/old-licenses/gpl-2.0.html
21  * or you may search the http://www.gnu.org website for the version 2 license,
22  * or you may write to the Free Software Foundation, Inc.,
23  * 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301, USA
24  */
25 
26 #include <fctsys.h>
27 #include <common.h>
28 #include <kiway.h>
29 #include <confirm.h>
30 #include <kicad_string.h>
31 #include <sch_base_frame.h>
32 #include <sch_edit_frame.h>
33 #include <ee_collectors.h>
34 #include <sch_component.h>
35 #include <class_libentry.h>
36 #include <lib_field.h>
37 #include <template_fieldnames.h>
38 #include <class_library.h>
39 #include <sch_validators.h>
40 #include <schematic.h>
41 #include <dialog_edit_one_field.h>
42 #include <sch_text.h>
43 #include <scintilla_tricks.h>
44 
46  const EDA_TEXT* aTextItem ) :
47  DIALOG_LIB_EDIT_TEXT_BASE( aParent ),
48  m_posX( aParent, m_xPosLabel, m_xPosCtrl, m_xPosUnits, true ),
49  m_posY( aParent, m_yPosLabel, m_yPosCtrl, m_yPosUnits, true ),
50  m_textSize( aParent, m_textSizeLabel, m_textSizeCtrl, m_textSizeUnits, true ),
51  m_scintillaTricks( nullptr )
52 {
53  wxASSERT( aTextItem );
54 
55  SetTitle( aTitle );
56 
57  // The field ID and power status are Initialized in the derived object's ctor.
58  m_fieldId = VALUE;
59  m_isPower = false;
60 
62 
63  m_text = aTextItem->GetText();
64  m_isItalic = aTextItem->IsItalic();
65  m_isBold = aTextItem->IsBold();
66  m_position = aTextItem->GetTextPos();
67  m_size = aTextItem->GetTextWidth();
68  m_isVertical = ( aTextItem->GetTextAngle() == TEXT_ANGLE_VERT );
69  m_verticalJustification = aTextItem->GetVertJustify() + 1;
70  m_horizontalJustification = aTextItem->GetHorizJustify() + 1;
71  m_isVisible = aTextItem->IsVisible();
72 }
73 
74 
76 {
77  delete m_scintillaTricks;
78 }
79 
80 
82 {
83  SCH_BASE_FRAME* parent = GetParent();
84  bool libedit = parent->IsType( FRAME_SCH_LIB_EDITOR );
85 
86  m_TextCtrl->SetValidator( SCH_FIELD_VALIDATOR( libedit, m_fieldId, &m_text ) );
87 
88  // Disable options for graphic text editing which are not needed for fields.
89  m_CommonConvert->Show( false );
90  m_CommonUnit->Show( false );
91 
92  if( !libedit && ( m_fieldId == REFERENCE || m_fieldId == VALUE ) )
93  {
94  m_StyledTextCtrl->Show( false );
96  }
97  else
98  {
99  m_TextCtrl->Show( false );
101  }
102 
103  // Show the footprint selection dialog if this is the footprint field.
106 
107  // Value fields of power components cannot be modified. This will grey out
108  // the text box and display an explanation.
109  if( m_fieldId == VALUE && m_isPower )
110  {
111  m_PowerComponentValues->Show( true );
112  m_TextCtrl->Enable( false );
113  }
114  else
115  {
116  m_PowerComponentValues->Show( false );
117  m_TextCtrl->Enable( true );
118  }
119 
120  m_sdbSizerButtonsOK->SetDefault();
121 
122  GetSizer()->SetSizeHints( this );
123 
124  // Adjust the height of the scintilla text editor after the first layout
125  if( m_StyledTextCtrl->IsShown() )
126  {
127  wxSize maxSize = m_StyledTextCtrl->GetSize();
128  maxSize.y = m_xPosCtrl->GetSize().y;
129  m_StyledTextCtrl->SetMaxSize( maxSize );
130  m_StyledTextCtrl->SetUseVerticalScrollBar( false );
131  m_StyledTextCtrl->SetUseHorizontalScrollBar( false );
132  }
133 
134  // Now all widgets have the size fixed, call FinishDialogSettings
136 }
137 
138 
140 {
141  // pick a footprint using the footprint picker.
142  wxString fpid;
143 
144  if( m_StyledTextCtrl->IsShown() )
145  fpid = m_StyledTextCtrl->GetValue();
146  else
147  fpid = m_TextCtrl->GetValue();
148 
150 
151  if( frame->ShowModal( &fpid, this ) )
152  {
153  if( m_StyledTextCtrl->IsShown() )
154  m_StyledTextCtrl->SetValue( fpid );
155  else
156  m_TextCtrl->SetValue( fpid );
157  }
158 
159  frame->Destroy();
160 }
161 
162 
163 void DIALOG_EDIT_ONE_FIELD::OnSetFocusText( wxFocusEvent& event )
164 {
165 #ifdef __WXGTK__
166  // Force an update of the text control before setting the text selection
167  // This is needed because GTK seems to ignore the selection on first update
168  //
169  // Note that we can't do this on OSX as it tends to provoke Apple's
170  // "[NSAlert runModal] may not be invoked inside of transaction begin/commit pair"
171  // bug. See: https://bugs.launchpad.net/kicad/+bug/1837225
173  m_TextCtrl->Update();
174 #endif
175 
176  if( m_fieldId == REFERENCE )
177  SelectReferenceNumber( static_cast<wxTextEntry*>( m_TextCtrl ) );
178  else if( m_fieldId == VALUE || m_fieldId == SHEETNAME_V )
179  m_TextCtrl->SetSelection( -1, -1 );
180 
181  event.Skip();
182 }
183 
184 
186 {
187  if( m_TextCtrl->IsShown() )
188  m_TextCtrl->SetValue( m_text );
189  else if( m_StyledTextCtrl->IsShown() )
190  m_StyledTextCtrl->SetValue( m_text );
191 
195  m_orientChoice->SetSelection( m_isVertical ? 1 : 0 );
196  m_hAlignChoice->SetSelection( m_horizontalJustification );
197  m_vAlignChoice->SetSelection( m_verticalJustification );
198  m_visible->SetValue( m_isVisible );
199  m_italic->SetValue( m_isItalic );
200  m_bold->SetValue( m_isBold );
201 
202  return true;
203 }
204 
205 
207 {
208  if( m_TextCtrl->IsShown() )
209  m_text = m_TextCtrl->GetValue();
210  else if( m_StyledTextCtrl->IsShown() )
211  m_text = m_StyledTextCtrl->GetValue();
212 
213  if( m_fieldId == REFERENCE )
214  {
215  // Test if the reference string is valid:
217  {
218  DisplayError( this, _( "Illegal reference designator value!" ) );
219  return false;
220  }
221  }
222  else if( m_fieldId == VALUE )
223  {
224  if( m_text.IsEmpty() )
225  {
226  DisplayError( this, _( "Value may not be empty." ) );
227  return false;
228  }
229  }
230 
231  m_isVertical = m_orientChoice->GetSelection() == 1;
234  m_horizontalJustification = m_hAlignChoice->GetSelection();
235  m_verticalJustification = m_vAlignChoice->GetSelection();
236  m_isVisible = m_visible->GetValue();
237  m_isItalic = m_italic->GetValue();
238  m_isBold = m_bold->GetValue();
239 
240  return true;
241 }
242 
243 
245 {
246  aText->SetTextPos( m_position );
247  aText->SetTextSize( wxSize( m_size, m_size ) );
248  aText->SetVisible( m_isVisible );
250  aText->SetItalic( m_isItalic );
251  aText->SetBold( m_isBold );
254 }
255 
256 
258  const wxString& aTitle,
259  const LIB_FIELD* aField ) :
260  DIALOG_EDIT_ONE_FIELD( aParent, aTitle, aField )
261 {
262  m_fieldId = aField->GetId();
263 
264  // When in the library editor, power components can be renamed.
265  m_isPower = false;
266  init();
267 }
268 
269 
271  const wxString& aTitle,
272  const SCH_FIELD* aField ) :
273  DIALOG_EDIT_ONE_FIELD( aParent, aTitle, aField ),
274  m_field( aField )
275 {
276  if( aField->GetParent() && aField->GetParent()->Type() == SCH_COMPONENT_T )
277  {
278  m_fieldId = aField->GetId();
279  }
280  else if( aField->GetParent() && aField->GetParent()->Type() == SCH_SHEET_T )
281  {
282  switch( aField->GetId() )
283  {
284  case SHEETNAME: m_fieldId = SHEETNAME_V; break;
285  case SHEETFILENAME: m_fieldId = SHEETFILENAME_V; break;
286  default: m_fieldId = SHEETUSERFIELD_V; break;
287  }
288  }
289 
290  m_isPower = false;
291 
292  m_textLabel->SetLabel( m_field->GetName() + ":" );
293 
294  // The library symbol may have been removed so using SCH_COMPONENT::GetPartRef() here
295  // could result in a segfault. If the library symbol is no longer available, the
296  // schematic fields can still edit so set the power symbol flag to false. This may not
297  // be entirely accurate if the power library is missing but it's better then a segfault.
298  if( aField->GetParent() && aField->GetParent()->Type() == SCH_COMPONENT_T )
299  {
300  const SCH_COMPONENT* component = (SCH_COMPONENT*) aField->GetParent();
301  const LIB_PART* part = GetParent()->GetLibPart( component->GetLibId(), true );
302 
303  if( part && part->IsPower() )
304  m_isPower = true;
305  }
306 
307  m_StyledTextCtrl->Bind( wxEVT_STC_CHARADDED, &DIALOG_SCH_EDIT_ONE_FIELD::onScintillaCharAdded, this );
308 
309  init();
310 }
311 
312 
313 void DIALOG_SCH_EDIT_ONE_FIELD::onScintillaCharAdded( wxStyledTextEvent &aEvent )
314 {
315  SCH_EDIT_FRAME* editFrame = static_cast<SCH_EDIT_FRAME*>( GetParent() );
316  wxArrayString autocompleteTokens;
317  int pos = m_StyledTextCtrl->GetCurrentPos();
318  int start = m_StyledTextCtrl->WordStartPosition( pos, true );
319  wxString partial;
320 
321  auto textVarRef =
322  [&]( int pt )
323  {
324  return pt >= 2
325  && m_StyledTextCtrl->GetCharAt( pt - 2 ) == '$'
326  && m_StyledTextCtrl->GetCharAt( pt - 1 ) == '{';
327  };
328 
329  // Check for cross-reference
330  if( start > 1 && m_StyledTextCtrl->GetCharAt( start - 1 ) == ':' )
331  {
332  int refStart = m_StyledTextCtrl->WordStartPosition( start - 1, true );
333 
334  if( textVarRef( refStart ) )
335  {
336  partial = m_StyledTextCtrl->GetRange( start, pos );
337 
338  wxString ref = m_StyledTextCtrl->GetRange( refStart, start - 1 );
339  SCH_SHEET_LIST sheets = editFrame->Schematic().GetSheets();
340  SCH_REFERENCE_LIST refs;
341  SCH_COMPONENT* refComponent = nullptr;
342 
343  sheets.GetComponents( refs );
344 
345  for( size_t jj = 0; jj < refs.GetCount(); jj++ )
346  {
347  if( refs[ jj ].GetComp()->GetRef( &refs[ jj ].GetSheetPath(), true ) == ref )
348  {
349  refComponent = refs[ jj ].GetComp();
350  break;
351  }
352  }
353 
354  if( refComponent )
355  refComponent->GetContextualTextVars( &autocompleteTokens );
356  }
357  }
358  else if( textVarRef( start ) )
359  {
360  partial = m_StyledTextCtrl->GetTextRange( start, pos );
361 
362  SCH_COMPONENT* comp = dynamic_cast<SCH_COMPONENT*>( m_field->GetParent() );
363  SCH_SHEET* sheet = dynamic_cast<SCH_SHEET*>( m_field->GetParent() );
364 
365  if( comp )
366  comp->GetContextualTextVars( &autocompleteTokens );
367  else if( sheet )
368  sheet->GetContextualTextVars( &autocompleteTokens );
369 
370  for( std::pair<wxString, wxString> entry : Prj().GetTextVars() )
371  autocompleteTokens.push_back( entry.first );
372  }
373 
374  m_scintillaTricks->DoAutocomplete( partial, autocompleteTokens );
375  m_StyledTextCtrl->SetFocus();
376 }
377 
378 
380 {
381  SCH_EDIT_FRAME* editFrame = dynamic_cast<SCH_EDIT_FRAME*>( GetParent() );
382  SCH_ITEM* parent = dynamic_cast<SCH_ITEM*>( aField->GetParent() );
383  int fieldType = aField->GetId();
384 
385  if( parent && parent->Type() == SCH_COMPONENT_T && fieldType == REFERENCE )
386  {
387  wxASSERT( aSheetPath );
388  static_cast<SCH_COMPONENT*>( parent )->SetRef( aSheetPath, m_text );
389  }
390 
391  bool positioningModified = false;
392 
393  if( aField->GetTextPos() != m_position )
394  positioningModified = true;
395 
396  if( ( aField->GetTextAngle() == TEXT_ANGLE_VERT ) != m_isVertical )
397  positioningModified = true;
398 
400  positioningModified = true;
401 
403  positioningModified = true;
404 
405  aField->SetText( m_text );
406  updateText( aField );
407 
408  // The value, footprint and datasheet fields should be kept in sync in multi-unit
409  // parts.
410  // Of course the component must be annotated to collect other units.
411  if( editFrame && parent && parent->Type() == SCH_COMPONENT_T
412  && ( fieldType == VALUE || fieldType == FOOTPRINT || fieldType == DATASHEET ) )
413  {
414  SCH_COMPONENT* thisUnit = static_cast<SCH_COMPONENT*>( parent );
415  std::vector<SCH_COMPONENT*> otherUnits;
416 
417  CollectOtherUnits( editFrame->GetCurrentSheet(), thisUnit, &otherUnits );
418 
419  for( SCH_COMPONENT* otherUnit : otherUnits )
420  {
421  editFrame->SaveCopyInUndoList( otherUnit, UR_CHANGED, true /* append */);
422  otherUnit->GetField( fieldType )->SetText( m_text );
423  editFrame->RefreshItem( otherUnit );
424  }
425  }
426 
427  if( positioningModified && parent )
428  parent->ClearFieldsAutoplaced();
429 }
#define TEXT_ANGLE_HORIZ
void DisplayError(wxWindow *aParent, const wxString &aText, int aDisplayTime)
Display an error or warning message box with aMessage.
Definition: confirm.cpp:239
SCH_SHEET_LIST.
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
KIWAY_PLAYER is a wxFrame capable of the OpenProjectFiles function, meaning it can load a portion of ...
Definition: kiway_player.h:59
KIWAY & Kiway() const
Function Kiway returns a reference to the KIWAY that this object has an opportunity to participate in...
Definition: kiway_holder.h:56
EDA_TEXT_VJUSTIFY_T GetVertJustify() const
Definition: eda_text.h:199
name of datasheet
SCH_SHEET_LIST GetSheets() const
Builds and returns an updated schematic hierarchy TODO: can this be cached?
Definition: schematic.h:92
#define TEXT_ANGLE_VERT
SCINTILLA_TRICKS * m_scintillaTricks
This file is part of the common library.
void onScintillaCharAdded(wxStyledTextEvent &aEvent)
SCINTILLA_TRICKS is used to add cut/copy/paste, autocomplete and brace highlighting to a wxStyleTextC...
bool IsVisible() const
Definition: eda_text.h:185
void DoAutocomplete(const wxString &aPartial, const wxArrayString &aTokens)
void SetItalic(bool isItalic)
Definition: eda_text.h:178
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
double GetTextAngle() const
Definition: eda_text.h:173
int GetId() const
Definition: sch_field.h:114
void UpdateField(SCH_FIELD *aField, SCH_SHEET_PATH *aSheetPath)
Schematic editor (Eeschema) main window.
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
#define SHEETNAME_V
void SetInitialFocus(wxWindow *aWindow)
Sets the window (usually a wxTextCtrl) that should be focused when the dialog is shown.
Definition: dialog_shim.h:114
Field Name Module PCB, i.e. "16DIP300".
Field Reference of part, i.e. "IC21".
DIALOG_EDIT_ONE_FIELD(SCH_BASE_FRAME *aParent, const wxString &aTitle, const EDA_TEXT *aTextItem)
SCH_REFERENCE_LIST is used to create a flattened list of components because in a complex hierarchy,...
DIALOG_SCH_EDIT_ONE_FIELD(SCH_BASE_FRAME *aParent, const wxString &aTitle, const SCH_FIELD *aField)
bool IsItalic() const
Definition: eda_text.h:179
A mix-in class (via multiple inheritance) that handles texts such as labels, parts,...
Definition: eda_text.h:112
wxBitmap KiBitmap(BITMAP_DEF aBitmap)
Construct a wxBitmap from a memory record, held in a BITMAP_DEF.
Definition: bitmap.cpp:80
DIALOG_LIB_EDIT_ONE_FIELD(SCH_BASE_FRAME *aParent, const wxString &aTitle, const LIB_FIELD *aField)
void SelectReferenceNumber(wxTextEntry *aTextEntry)
Select the number (or "?") in a reference for ease of editing.
Definition: common.cpp:312
DIALOG_EDIT_ONE_FIELD is a base class to edit schematic and component library fields.
#define VALUE
EDA_TEXT_HJUSTIFY_T GetHorizJustify() const
Definition: eda_text.h:198
static EDA_TEXT_HJUSTIFY_T MapHorizJustify(int aHorizJustify)
Definition: eda_text.cpp:58
virtual void SetText(const wxString &aText)
Definition: eda_text.cpp:116
VTBL_ENTRY KIWAY_PLAYER * Player(FRAME_T aFrameType, bool doCreate=true, wxTopLevelWindow *aParent=NULL)
Function Player returns the KIWAY_PLAYER* given a FRAME_T.
Definition: kiway.cpp:342
void GetComponents(SCH_REFERENCE_LIST &aReferences, bool aIncludePowerSymbols=true, bool aForceIncludeOrphanComponents=false) const
Function GetComponents adds a SCH_REFERENCE() object to aReferences for each component in the list of...
PROJECT & Prj() const
Function Prj returns a reference to the PROJECT "associated with" this KIWAY.
Class LIB_PIN definition.
void SetVertJustify(EDA_TEXT_VJUSTIFY_T aType)
Definition: eda_text.h:202
Definitions of control validators for schematic dialogs.
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.
#define SHEETFILENAME_V
SCHEMATIC & Schematic() const
Define a library symbol object.
void ClearFieldsAutoplaced()
Set fields automatically placed flag false.
Definition: sch_item.h:437
EDA_ITEM * GetParent() const
Definition: base_struct.h:195
SCH_SHEET_PATH.
const BITMAP_OPAQUE small_library_xpm[1]
void GetContextualTextVars(wxArrayString *aVars) const
Return the list of system text vars & fields for this symbol.
static EDA_TEXT_VJUSTIFY_T MapVertJustify(int aVertJustify)
Definition: eda_text.cpp:72
bool TransferDataToWindow() override
#define SHEETUSERFIELD_V
void updateText(EDA_TEXT *aText)
Class DIALOG_LIB_EDIT_TEXT_BASE.
Sheet symbol placed in a schematic, and is the entry point for a sub schematic.
Definition: sch_sheet.h:216
unsigned GetCount() const
Function GetCount.
SCH_BASE_FRAME * GetParent()
int GetTextWidth() const
Definition: eda_text.h:241
bool IsPower() const
bool IsType(FRAME_T aType) const
void RefreshItem(EDA_ITEM *aItem, bool isAddOrDelete=false)
Mark an item for refresh.
void SetHorizJustify(EDA_TEXT_HJUSTIFY_T aType)
Definition: eda_text.h:201
#define _(s)
Definition: 3d_actions.cpp:33
void OnTextValueSelectButtonClick(wxCommandEvent &aEvent) override
Function OnTextValueSelectButtonClick Handles the select button next to the text value field.
virtual void SetValue(int aValue)
Function SetValue Sets new value (in Internal Units) for the text field, taking care of units convers...
wxString GetName(bool aUseDefaultName=true) const
Function GetName returns the field name.
Definition: sch_field.cpp:420
Schematic symbol object.
Definition: sch_component.h:88
The common library.
virtual long long int GetValue()
Function GetValue Returns the current value in Internal Units.
bool TransferDataFromWindow() override
bool Destroy() override
Our version of Destroy() which is virtual from wxWidgets.
const wxPoint & GetTextPos() const
Definition: eda_text.h:247
SCH_SHEET_PATH & GetCurrentSheet() const
void CollectOtherUnits(SCH_SHEET_PATH &aSheet, SCH_COMPONENT *aUnit, std::vector< SCH_COMPONENT * > *otherUnits)
virtual void SetTextAngle(double aAngle)
Definition: eda_text.h:166
A text control validator used for validating the text allowed in library and schematic component fiel...
Definition for part library class.
static bool IsReferenceStringValid(const wxString &aReferenceString)
Tests for an acceptable reference string.
const LIB_ID & GetLibId() const
A shim class between EDA_DRAW_FRAME and several derived classes: LIB_EDIT_FRAME, LIB_VIEW_FRAME,...
void SetBold(bool aBold)
Definition: eda_text.h:181
Base class for any item which can be embedded within the SCHEMATIC container class,...
Definition: sch_item.h:186
virtual bool ShowModal(wxString *aResult=NULL, wxWindow *aResultantFocusWindow=NULL)
Function ShowModal puts up this wxFrame as if it were a modal dialog, with all other instantiated wxF...
virtual const wxString & GetText() const
Return the string associated with the text object.
Definition: eda_text.h:126
KICAD_T Type() const
Function Type()
Definition: base_struct.h:193
virtual void OnSetFocusText(wxFocusEvent &event) override
Used to select the variant part of some text fields (for instance, the question mark or number in a r...