KiCad PCB EDA Suite
dialog_edit_component_in_lib.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) 1992-2019 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 <fctsys.h>
25 #include <kiway.h>
26 #include <common.h>
27 #include <confirm.h>
28 #include <pgm_base.h>
29 #include <kiface_i.h>
30 #include <dialog_text_entry.h>
31 
32 #include <general.h>
33 #include <widgets/wx_grid.h>
35 #include <lib_edit_frame.h>
36 #include <class_library.h>
37 #include <symbol_lib_table.h>
38 #include <sch_item.h>
39 #include <sch_component.h>
40 #include <dialog_helpers.h>
41 #include <bitmaps.h>
42 
43 #ifdef KICAD_SPICE
44 #include <dialog_spice_model.h>
46 #endif /* KICAD_SPICE */
47 
49 
50 
51 #define LibEditFieldsShownColumnsKey wxT( "LibEditFieldsShownColumns" )
52 
54 
55 
57  LIB_PART* aLibEntry ) :
59  m_Parent( aParent ),
60  m_libEntry( aLibEntry ),
61  m_currentAlias( wxNOT_FOUND ),
62  m_pinNameOffset( aParent, m_nameOffsetLabel, m_nameOffsetCtrl, m_nameOffsetUnits, true ),
63  m_delayedFocusCtrl( nullptr ),
64  m_delayedFocusGrid( nullptr ),
65  m_delayedFocusRow( -1 ),
66  m_delayedFocusColumn( -1 ),
67  m_delayedFocusPage( -1 ),
68  m_width( 0 )
69 {
71 
72  // Give a bit more room for combobox editors
73  m_grid->SetDefaultRowSize( m_grid->GetDefaultRowSize() + 4 );
74  m_aliasGrid->SetDefaultRowSize( m_aliasGrid->GetDefaultRowSize() + 4 );
75 
76  // Work around a bug in wxWidgets where it fails to recalculate the grid height
77  // after changing the default row size
78  m_aliasGrid->AppendRows( 1 );
79  m_aliasGrid->DeleteRows( m_grid->GetNumberRows() - 1, 1 );
80 
81  m_fields = new FIELDS_GRID_TABLE<LIB_FIELD>( this, aParent, m_libEntry );
83 
84  m_grid->PushEventHandler( new FIELDS_GRID_TRICKS( m_grid, this ) );
85  m_aliasGrid->PushEventHandler( new FIELDS_GRID_TRICKS( m_grid, this ) );
86 
87  // Show/hide columns according to the user's preference
88  m_config->Read( LibEditFieldsShownColumnsKey, &m_shownColumns, wxT( "0 1 2 3 4 5 6 7" ) );
90 
91  // Hide non-overridden rows in aliases grid
92  m_aliasGrid->HideRow( REFERENCE );
93  m_aliasGrid->HideRow( FOOTPRINT );
94 
95  wxGridCellAttr* attr = new wxGridCellAttr;
96  attr->SetReadOnly();
97  m_aliasGrid->SetColAttr( FDC_NAME, attr );
99  m_aliasGrid->SetCellValue( DATASHEET, FDC_NAME,
101 
102  attr = new wxGridCellAttr;
103  attr->SetEditor( new GRID_CELL_URL_EDITOR( this ) );
104  m_aliasGrid->SetAttr( DATASHEET, FDC_VALUE, attr );
105 
106  m_SymbolNameCtrl->SetValidator( SCH_FIELD_VALIDATOR( true, VALUE ) );
107 
108  // Configure button logos
109  m_bpAdd->SetBitmap( KiBitmap( small_plus_xpm ) );
110  m_bpDelete->SetBitmap( KiBitmap( trash_xpm ) );
111  m_bpMoveUp->SetBitmap( KiBitmap( small_up_xpm ) );
112  m_bpMoveDown->SetBitmap( KiBitmap( small_down_xpm ) );
113  m_addAliasButton->SetBitmap( KiBitmap( small_plus_xpm ) );
114  m_deleteAliasButton->SetBitmap( KiBitmap( trash_xpm ) );
115  m_addFilterButton->SetBitmap( KiBitmap( small_plus_xpm ) );
116  m_deleteFilterButton->SetBitmap( KiBitmap( trash_xpm ) );
117  m_editFilterButton->SetBitmap( KiBitmap( small_edit_xpm ) );
118 
119  m_stdSizerButtonOK->SetDefault();
120 
121 #ifndef KICAD_SPICE
122  m_spiceFieldsButton->Hide();
123 #endif
124 
125  // wxFormBuilder doesn't include this event...
126  m_grid->Connect( wxEVT_GRID_CELL_CHANGING,
128  NULL, this );
129  m_aliasGrid->Connect( wxEVT_GRID_CELL_CHANGING,
131  NULL, this );
132 
133  m_grid->GetParent()->Layout();
134  m_aliasGrid->GetParent()->Layout();
135  Layout();
136 
138 }
139 
140 
142 {
143  m_lastOpenedPage = m_NoteBook->GetSelection( );
144 
146 
147  // Prevents crash bug in wxGrid's d'tor
149 
150  m_grid->Disconnect( wxEVT_GRID_CELL_CHANGING,
152  NULL, this );
153  m_aliasGrid->Disconnect( wxEVT_GRID_CELL_CHANGING,
155  NULL, this );
156 
157  // Delete the GRID_TRICKS.
158  m_grid->PopEventHandler( true );
159  m_aliasGrid->PopEventHandler( true );
160 
161  // An OK will have transferred these and cleared the buffer, but we have to delete them
162  // on a Cancel.
163  for( LIB_ALIAS* alias : m_aliasesBuffer )
164  delete alias;
165 }
166 
167 
169 {
170  if( !wxDialog::TransferDataToWindow() )
171  return false;
172 
173  LIB_ALIAS* rootAlias = m_libEntry->GetAlias( m_libEntry->GetName() );
174 
175  // Push a copy of each field into m_fields
177 
178  // The datasheet field is special. Grab its value from the LIB_ALIAS document file
179  // member except for old libraries that saved the root alias document file in the
180  // datasheet field in the LIB_PART object.
181  if( rootAlias->GetDocFileName().IsEmpty() )
182  {
183  m_fields->at( DATASHEET ).SetText( m_libEntry->GetField( DATASHEET )->GetText() );
184  rootAlias->SetDocFileName( m_libEntry->GetField( DATASHEET )->GetText() );
185  }
186  else
187  {
188  m_fields->at( DATASHEET ).SetText( rootAlias->GetDocFileName() );
189  }
190 
191  // The Y axis for components in lib is from bottom to top while the screen axis is top
192  // to bottom: we must change the y coord sign for editing
193  for( size_t i = 0; i < m_fields->size(); ++i )
194  {
195  wxPoint pos = m_fields->at( i ).GetPosition();
196  pos.y = -pos.y;
197  m_fields->at( i ).SetPosition( pos );
198  }
199 
200  // notify the grid
201  wxGridTableMessage msg( m_fields, wxGRIDTABLE_NOTIFY_ROWS_APPENDED, m_fields->GetNumberRows() );
202  m_grid->ProcessTableMessage( msg );
203  adjustGridColumns( m_grid->GetRect().GetWidth());
204 
205  m_SymbolNameCtrl->SetValue( m_libEntry->GetName() );
206 
207  m_DescCtrl->SetValue( rootAlias->GetDescription() );
208  m_KeywordCtrl->SetValue( rootAlias->GetKeyWords() );
209 
212  m_AsConvertButt->SetValue( m_libEntry->HasConversion() );
213  m_OptionPower->SetValue( m_libEntry->IsPower() );
214 
216  m_ShowPinNameButt->SetValue( m_libEntry->ShowPinNames() );
217  m_PinsNameInsideButt->SetValue( m_libEntry->GetPinNameOffset() != 0 );
219 
220  const LIB_ALIASES aliases = m_libEntry->GetAliases();
221 
222  for( LIB_ALIAS* alias : aliases )
223  {
224  if( alias->IsRoot() )
225  continue;
226 
227  m_aliasesBuffer.push_back( new LIB_ALIAS( *alias, m_libEntry ) );
228  m_aliasListBox->Append( alias->GetName() );
229  }
230 
231  if( m_aliasListBox->GetCount() )
232  m_aliasListBox->SetSelection( 0 );
233 
234  wxCommandEvent dummy;
235  OnSelectAlias( dummy );
236 
237  adjustAliasGridColumns( m_aliasGrid->GetClientRect().GetWidth() - 4 );
238 
240 
241  m_NoteBook->SetSelection( (unsigned) m_lastOpenedPage );
242 
243  return true;
244 }
245 
246 
248 {
250  return false;
251 
252  if( !SCH_COMPONENT::IsReferenceStringValid( m_fields->at( REFERENCE ).GetText() ) )
253  {
254  if( m_NoteBook->GetSelection() != 0 )
255  m_NoteBook->SetSelection( 0 );
256 
257  m_delayedErrorMessage = _( "References must start with a letter." );
261  m_delayedFocusPage = 0;
262 
263  return false;
264  }
265 
266  // Check for missing field names.
267  for( size_t i = MANDATORY_FIELDS; i < m_fields->size(); ++i )
268  {
269  LIB_FIELD& field = m_fields->at( i );
270  wxString fieldName = field.GetName( false );
271 
272  if( fieldName.IsEmpty() )
273  {
274  if( m_NoteBook->GetSelection() != 0 )
275  m_NoteBook->SetSelection( 0 );
276 
277  m_delayedErrorMessage = _( "Fields must have a name." );
281  m_delayedFocusPage = 0;
282 
283  return false;
284  }
285  }
286 
287  if( m_SelNumberOfUnits->GetValue() < m_libEntry->GetUnitCount() )
288  {
289  if( !IsOK( this, _( "Delete extra units from symbol?" ) ) )
290  return false;
291  }
292 
293  if( m_AsConvertButt->GetValue() && !m_libEntry->HasConversion() )
294  {
295  if( !IsOK( this, _( "Add new pins for alternate body style (DeMorgan) to symbol?" ) ) )
296  return false;
297  }
298  else if( !m_AsConvertButt->GetValue() && m_libEntry->HasConversion() )
299  {
300  if( !IsOK( this, _( "Delete alternate body style (DeMorgan) draw items from symbol?" ) ) )
301  return false;
302  }
303 
304  return true;
305 }
306 
307 
309 {
310  if( !wxDialog::TransferDataFromWindow() )
311  return false;
312 
313  LIB_ALIAS* rootAlias = m_libEntry->GetAlias( m_libEntry->GetName() );
314  // We need to keep the name and the value the same at the moment!
315  wxString newName = m_fields->at( VALUE ).GetText();
316 
317  if( m_libEntry->GetName() != newName )
319  else
321 
322  // The Y axis for components in lib is from bottom to top while the screen axis is top
323  // to bottom: we must change the y coord sign when writing back to the library
324  for( size_t i = 0; i < m_fields->size(); ++i )
325  {
326  wxPoint pos = m_fields->at( i ).GetPosition();
327  pos.y = -pos.y;
328  m_fields->at( i ).SetPosition( pos );
329  }
330 
331  // Datasheet field is special; copy it to the root alias docfilename
332  rootAlias->SetDocFileName( m_fields->at( DATASHEET ).GetText() );
333  m_fields->at( DATASHEET ).SetText( wxEmptyString );
334 
336 
337  // We need to keep the name and the value the same at the moment!
338  m_libEntry->SetName( newName );
339 
340  rootAlias->SetDescription( m_DescCtrl->GetValue() );
341  rootAlias->SetKeyWords( m_KeywordCtrl->GetValue() );
342 
345 
346  m_libEntry->SetConversion( m_AsConvertButt->GetValue() );
347 
348  if( m_OptionPower->GetValue() )
349  m_libEntry->SetPower();
350  else
352 
355 
356  if( m_PinsNameInsideButt->GetValue() )
357  {
358  int offset = KiROUND( (double) m_pinNameOffset.GetValue() / IU_PER_MILS );
359 
360  // We interpret an offset of 0 as "outside", so make sure it's non-zero
361  m_libEntry->SetPinNameOffset( offset == 0 ? 20 : offset );
362  }
363  else
364  {
365  m_libEntry->SetPinNameOffset( 0 ); // pin text outside the body (name is on the pin)
366  }
367 
370 
371  for( LIB_ALIAS* alias : m_aliasesBuffer )
372  m_libEntry->AddAlias( alias ); // Transfers ownership; no need to delete
373 
374  m_aliasesBuffer.clear();
375 
376  m_libEntry->GetFootprints().Clear();
378 
379  return true;
380 }
381 
382 
384 {
385  wxGridCellEditor* editor = m_grid->GetCellEditor( event.GetRow(), event.GetCol() );
386  wxControl* control = editor->GetControl();
387 
388  if( control && control->GetValidator() && !control->GetValidator()->Validate( control ) )
389  {
390  event.Veto();
391 
393  m_delayedFocusRow = event.GetRow();
394  m_delayedFocusColumn = event.GetCol();
395  m_delayedFocusPage = 0;
396  }
397  else if( event.GetRow() == VALUE && event.GetCol() == FDC_VALUE )
398  m_SymbolNameCtrl->ChangeValue( event.GetString() );
399 
400  editor->DecRef();
401 }
402 
403 
405 {
406  m_grid->SetCellValue( VALUE, FDC_VALUE, m_SymbolNameCtrl->GetValue() );
407 }
408 
409 
411 {
412  if( !m_delayedFocusCtrl && !m_SymbolNameCtrl->GetValidator()->Validate( m_SymbolNameCtrl ) )
413  {
415  m_delayedFocusPage = 0;
416  }
417 
418  event.Skip();
419 }
420 
421 
422 void DIALOG_EDIT_COMPONENT_IN_LIBRARY::OnAddField( wxCommandEvent& event )
423 {
424  if( !m_grid->CommitPendingChanges() )
425  return;
426 
427  int fieldID = m_fields->size();
428  LIB_FIELD newField( m_libEntry, fieldID );
429 
430  m_fields->push_back( newField );
431 
432  // notify the grid
433  wxGridTableMessage msg( m_fields, wxGRIDTABLE_NOTIFY_ROWS_APPENDED, 1 );
434  m_grid->ProcessTableMessage( msg );
435 
436  m_grid->MakeCellVisible( m_fields->size() - 1, 0 );
437  m_grid->SetGridCursor( m_fields->size() - 1, 0 );
438 
439  m_grid->EnableCellEditControl();
440  m_grid->ShowCellEditControl();
441 }
442 
443 
445 {
446  int curRow = m_grid->GetGridCursorRow();
447 
448  if( curRow < 0 )
449  return;
450  else if( curRow < MANDATORY_FIELDS )
451  {
452  DisplayError( this, wxString::Format( _( "The first %d fields are mandatory." ),
453  MANDATORY_FIELDS ) );
454  return;
455  }
456 
457  m_grid->CommitPendingChanges( true /* quiet mode */ );
458 
459  m_fields->erase( m_fields->begin() + curRow );
460 
461  // notify the grid
462  wxGridTableMessage msg( m_fields, wxGRIDTABLE_NOTIFY_ROWS_DELETED, curRow, 1 );
463  m_grid->ProcessTableMessage( msg );
464 
465  if( m_grid->GetNumberRows() > 0 )
466  {
467  m_grid->MakeCellVisible( std::max( 0, curRow-1 ), m_grid->GetGridCursorCol() );
468  m_grid->SetGridCursor( std::max( 0, curRow-1 ), m_grid->GetGridCursorCol() );
469  }
470 }
471 
472 
473 void DIALOG_EDIT_COMPONENT_IN_LIBRARY::OnMoveUp( wxCommandEvent& event )
474 {
475  if( !m_grid->CommitPendingChanges() )
476  return;
477 
478  int i = m_grid->GetGridCursorRow();
479 
480  if( i > MANDATORY_FIELDS )
481  {
482  LIB_FIELD tmp = m_fields->at( (unsigned) i );
483  m_fields->erase( m_fields->begin() + i, m_fields->begin() + i + 1 );
484  m_fields->insert( m_fields->begin() + i - 1, tmp );
485  m_grid->ForceRefresh();
486 
487  m_grid->SetGridCursor( i - 1, m_grid->GetGridCursorCol() );
488  m_grid->MakeCellVisible( m_grid->GetGridCursorRow(), m_grid->GetGridCursorCol() );
489  }
490  else
491  wxBell();
492 }
493 
494 
495 void DIALOG_EDIT_COMPONENT_IN_LIBRARY::OnMoveDown( wxCommandEvent& event )
496 {
497  if( !m_grid->CommitPendingChanges() )
498  return;
499 
500  int i = m_grid->GetGridCursorRow();
501 
502  if( i >= MANDATORY_FIELDS && i + 1 < m_fields->GetNumberRows() )
503  {
504  LIB_FIELD tmp = m_fields->at( (unsigned) i );
505  m_fields->erase( m_fields->begin() + i, m_fields->begin() + i + 1 );
506  m_fields->insert( m_fields->begin() + i + 1, tmp );
507  m_grid->ForceRefresh();
508 
509  m_grid->SetGridCursor( i + 1, m_grid->GetGridCursorCol() );
510  m_grid->MakeCellVisible( m_grid->GetGridCursorRow(), m_grid->GetGridCursorCol() );
511  }
512  else
513  wxBell();
514 }
515 
516 
517 void DIALOG_EDIT_COMPONENT_IN_LIBRARY::updateAliasName( bool aFromGrid, const wxString& aName )
518 {
519  int idx = m_aliasListBox->GetSelection();
520 
521  if( idx >= 0 )
522  {
523  m_aliasListBox->SetString( (unsigned) idx, aName );
524  m_aliasesBuffer[ idx ]->SetName( aName );
525 
526  if( aFromGrid )
527  m_AliasNameCtrl->ChangeValue( aName );
528  else
529  m_aliasGrid->SetCellValue( VALUE, FDC_VALUE, aName );
530  }
531 }
532 
533 
535 {
536  if( event.GetRow() == VALUE )
537  {
538  int idx = m_aliasListBox->GetSelection();
539  wxString newName = event.GetString();
540 
541  if( idx < 0 || !checkAliasName( newName ) )
542  {
543  event.Veto();
544 
546  m_delayedFocusRow = event.GetRow();
547  m_delayedFocusColumn = event.GetCol();
548  m_delayedFocusPage = 1;
549  }
550  else
551  updateAliasName( true, newName );
552  }
553 }
554 
555 
557 {
558  updateAliasName( false, m_AliasNameCtrl->GetValue() );
559 }
560 
561 
563 {
564  if( !m_delayedFocusCtrl && !checkAliasName( m_AliasNameCtrl->GetValue() ) )
565  {
567  m_delayedFocusPage = 1;
568  }
569 
570  event.Skip();
571 }
572 
573 
575 {
576  if( m_currentAlias >= 0 )
577  {
579 
580  alias->SetName( m_aliasGrid->GetCellValue( VALUE, FDC_VALUE ) );
581  alias->SetDocFileName( m_aliasGrid->GetCellValue( DATASHEET, FDC_VALUE ) );
582  alias->SetDescription( m_AliasDescCtrl->GetValue() );
583  alias->SetKeyWords( m_AliasKeywordsCtrl->GetValue() );
584  }
585 }
586 
587 
589 {
590 #ifdef KICAD_SPICE
591  int diff = m_fields->size();
592  auto cmp = SCH_COMPONENT( *m_libEntry, m_libEntry->GetLibId(), nullptr );
593 
594  DIALOG_SPICE_MODEL dialog( this, cmp, m_fields );
595 
596  if( dialog.ShowModal() != wxID_OK )
597  return;
598 
599  diff = m_fields->size() - diff;
600 
601  if( diff > 0 )
602  {
603  wxGridTableMessage msg( m_fields, wxGRIDTABLE_NOTIFY_ROWS_APPENDED, diff );
604  m_grid->ProcessTableMessage( msg );
605  }
606  else if( diff < 0 )
607  {
608  wxGridTableMessage msg( m_fields, wxGRIDTABLE_NOTIFY_ROWS_DELETED, 0, diff );
609  m_grid->ProcessTableMessage( msg );
610  }
611 
612  m_grid->ForceRefresh();
613 #endif /* KICAD_SPICE */
614 }
615 
616 
618 {
620  {
621  m_aliasListBox->SetSelection( m_currentAlias ); // veto selection change
622  return;
623  }
624 
625  // Copy any pending changes back into the buffer
627 
628  LIB_ALIAS* alias = nullptr;
629  int newIdx = m_aliasListBox->GetSelection();
630 
631  if( newIdx >= 0 )
632  {
633  alias = m_aliasesBuffer[ newIdx ];
634 
635  m_aliasGrid->SetCellValue( VALUE, FDC_VALUE, alias->GetName() );
636  m_aliasGrid->SetCellValue( DATASHEET, FDC_VALUE, alias->GetDocFileName() );
637  m_aliasGrid->Enable( true );
638 
639  // Use ChangeValue() so we don't generate events
640  m_AliasNameCtrl->ChangeValue( alias->GetName() );
641  m_AliasNameCtrl->Enable( true );
642  m_AliasDescCtrl->ChangeValue( alias->GetDescription() );
643  m_AliasDescCtrl->Enable( true );
644  m_AliasKeywordsCtrl->ChangeValue( alias->GetKeyWords() );
645  m_AliasKeywordsCtrl->Enable( true );
646  }
647  else
648  {
649  m_aliasGrid->SetCellValue( VALUE, FDC_VALUE, wxEmptyString );
650  m_aliasGrid->SetCellValue( DATASHEET, FDC_VALUE, wxEmptyString );
651  m_aliasGrid->Enable( false );
652 
653  // Use ChangeValue() so we don't generate events
654  m_AliasNameCtrl->ChangeValue( wxEmptyString );
655  m_AliasNameCtrl->Enable( false );
656  m_AliasDescCtrl->ChangeValue( wxEmptyString );
657  m_AliasDescCtrl->Enable( false );
658  m_AliasKeywordsCtrl->ChangeValue( wxEmptyString );
659  m_AliasKeywordsCtrl->Enable( false );
660  }
661 
662  m_currentAlias = newIdx;
663 }
664 
665 
667 {
668  if( aName.IsEmpty() )
669  return false;
670 
671  if( m_SymbolNameCtrl->GetValue().CmpNoCase( aName ) == 0 )
672  {
673  wxString msg;
674  msg.Printf( _( "Alias can not have same name as symbol." ) );
675  DisplayInfoMessage( this, msg );
676  return false;
677  }
678 
679  for( int i = 0; i < (int)m_aliasListBox->GetCount(); ++i )
680  {
681  if( i == m_aliasListBox->GetSelection() )
682  continue;
683 
684  if( m_aliasListBox->GetString( i ).CmpNoCase( aName ) == 0 )
685  {
686  wxString msg;
687  msg.Printf( _( "Alias \"%s\" already exists." ), aName );
688  DisplayInfoMessage( this, msg );
689  return false;
690  }
691  }
692 
693  wxString library = m_Parent->GetCurLib();
694 
695  if( !library.empty() )
696  {
697  LIB_ALIAS* existing = Prj().SchSymbolLibTable()->LoadSymbol( library, aName );
698 
699  if( existing && existing->GetPart()->GetName() != m_libEntry->GetName() )
700  {
701  wxString msg;
702  msg.Printf( _( "Symbol name \"%s\" already exists in library \"%s\"." ),
703  aName, library );
704  DisplayErrorMessage( this, msg );
705  return false;
706  }
707  }
708 
709  return true;
710 }
711 
712 
713 void DIALOG_EDIT_COMPONENT_IN_LIBRARY::OnAddAlias( wxCommandEvent& event )
714 {
716  return;
717 
718  wxCommandEvent dummy;
719  wxString aliasname = _( "untitled" );
720  int suffix = 1;
721 
722  while( m_aliasListBox->FindString( aliasname ) != wxNOT_FOUND )
723  aliasname = wxString::Format( _( "untitled%i" ), suffix++ );
724 
725  LIB_ALIAS* alias = new LIB_ALIAS( aliasname, m_libEntry );
726 
727  // Initialize with parent's data
728  alias->SetDescription( m_DescCtrl->GetValue() );
729  alias->SetKeyWords( m_KeywordCtrl->GetValue() );
730  alias->SetDocFileName( m_grid->GetCellValue( DATASHEET, FDC_VALUE ) );
731 
732  m_aliasesBuffer.push_back( alias ); // transfers ownership of alias to aliasesBuffer
733 
734  m_aliasListBox->Append( aliasname );
735  m_aliasListBox->SetSelection( m_aliasListBox->GetCount() - 1 );
736  OnSelectAlias( dummy );
737 }
738 
739 
741 {
743  return;
744 
745  int sel = m_aliasListBox->GetSelection();
746 
747  if( sel == wxNOT_FOUND )
748  return;
749 
750  m_aliasListBox->Delete( (unsigned) sel );
751  m_aliasesBuffer.erase( m_aliasesBuffer.begin() + sel );
752  m_currentAlias = wxNOT_FOUND;
753 
754  if( m_aliasListBox->GetCount() == 0 )
755  m_aliasListBox->SetSelection( wxNOT_FOUND );
756  else
757  m_aliasListBox->SetSelection( std::max( 0, sel - 1 ) );
758 
759  wxCommandEvent dummy;
760  OnSelectAlias( dummy );
761 }
762 
763 
765 {
766  int idx = m_FootprintFilterListBox->HitTest( event.GetPosition() );
767  wxCommandEvent dummy;
768 
769  if( idx >= 0 )
771  else
773 }
774 
775 
777 {
778  // Running the Footprint Browser gums up the works and causes the automatic cancel
779  // stuff to no longer work. So we do it here ourselves.
780  EndQuasiModal( wxID_CANCEL );
781 }
782 
783 
785 {
786  wxString filterLine;
787  LIB_PART* component = m_Parent->GetCurPart();
788 
789  if( component == NULL )
790  return;
791 
792  WX_TEXT_ENTRY_DIALOG dlg( this, _( "Filter:" ), _( "Add Footprint Filter" ), filterLine );
793 
794  if( dlg.ShowModal() == wxID_CANCEL || dlg.GetValue().IsEmpty() )
795  return;
796 
797  filterLine = dlg.GetValue();
798  filterLine.Replace( wxT( " " ), wxT( "_" ) );
799 
800  // duplicate filters do no harm, so don't be a nanny.
801 
802  m_FootprintFilterListBox->Append( filterLine );
803  m_FootprintFilterListBox->SetSelection( m_FootprintFilterListBox->GetCount() - 1 );
804 }
805 
806 
808 {
809  int ii = m_FootprintFilterListBox->GetSelection();
810 
811  if( ii >= 0 )
812  {
813  m_FootprintFilterListBox->Delete( (unsigned) ii );
814 
815  if( m_FootprintFilterListBox->GetCount() == 0 )
816  m_FootprintFilterListBox->SetSelection( wxNOT_FOUND );
817  else
818  m_FootprintFilterListBox->SetSelection( std::max( 0, ii - 1 ) );
819  }
820 }
821 
822 
824 {
825  int idx = m_FootprintFilterListBox->GetSelection();
826 
827  if( idx >= 0 )
828  {
829  wxString filter = m_FootprintFilterListBox->GetStringSelection();
830 
831  WX_TEXT_ENTRY_DIALOG dlg( this, _( "Filter:" ), _( "Edit Footprint Filter" ), filter );
832 
833  if( dlg.ShowModal() == wxID_OK && !dlg.GetValue().IsEmpty() )
834  m_FootprintFilterListBox->SetString( (unsigned) idx, dlg.GetValue() );
835  }
836 }
837 
838 
840 {
841  m_width = aWidth;
842 
843  // Account for scroll bars
844  aWidth -= ( m_grid->GetSize().x - m_grid->GetClientSize().x );
845 
846  m_grid->AutoSizeColumn( FDC_NAME );
847 
848  int fixedColsWidth = m_grid->GetColSize( FDC_NAME );
849 
850  for( int i = 2; i < m_grid->GetNumberCols(); i++ )
851  fixedColsWidth += m_grid->GetColSize( i );
852 
853  m_grid->SetColSize( FDC_VALUE, aWidth - fixedColsWidth );
854 }
855 
856 
858 {
859  m_aliasGrid->AutoSizeColumn( FDC_NAME );
860  m_aliasGrid->SetColSize( FDC_VALUE, aWidth - m_aliasGrid->GetColSize( FDC_NAME ) - 2 );
861 }
862 
863 
864 void DIALOG_EDIT_COMPONENT_IN_LIBRARY::OnUpdateUI( wxUpdateUIEvent& event )
865 {
866  m_OptionPartsLocked->Enable( m_SelNumberOfUnits->GetValue() > 1 );
868 
869  if( m_grid->IsCellEditControlShown() )
870  {
871  int row = m_grid->GetGridCursorRow();
872  int col = m_grid->GetGridCursorCol();
873 
874  if( row == VALUE && col == FDC_VALUE )
875  {
876  wxGridCellEditor* editor = m_grid->GetCellEditor( row, col );
877  m_SymbolNameCtrl->ChangeValue( editor->GetValue() );
878  editor->DecRef();
879  }
880  }
881 
882  // Synthesize a Select event when the selection is cleared
883  if( m_aliasListBox->GetSelection() == wxNOT_FOUND && m_currentAlias != wxNOT_FOUND )
884  {
885  wxCommandEvent dummy;
886  OnSelectAlias( dummy );
887  }
888 
889  // Handle shown columns changes
890  wxString shownColumns = m_grid->GetShownColumns();
891 
892  if( shownColumns != m_shownColumns )
893  {
894  m_shownColumns = shownColumns;
895 
896  if( !m_grid->IsCellEditControlShown() )
897  adjustGridColumns( m_grid->GetRect().GetWidth() );
898  }
899 
900  // Handle a delayed focus. The delay allows us to:
901  // a) change focus when the error was triggered from within a killFocus handler
902  // b) show the correct notebook page in the background before the error dialog comes up
903  // when triggered from an OK or a notebook page change
904 
905  if( m_delayedFocusPage >= 0 && m_NoteBook->GetSelection() != m_delayedFocusPage )
906  {
907  m_NoteBook->SetSelection( (unsigned) m_delayedFocusPage );
908  m_delayedFocusPage = -1;
909  }
910 
911  if( !m_delayedErrorMessage.IsEmpty() )
912  {
913  // We will re-enter this routine when the error dialog is displayed, so make
914  // sure we don't keep putting up more dialogs.
915  wxString msg = m_delayedErrorMessage;
916  m_delayedErrorMessage = wxEmptyString;
917 
918  // Do not use DisplayErrorMessage(); it screws up window order on Mac
919  DisplayError( nullptr, msg );
920  }
921 
922  if( m_delayedFocusCtrl )
923  {
924  m_delayedFocusCtrl->SetFocus();
925 
926  if( dynamic_cast<wxTextEntry*>( m_delayedFocusCtrl ) )
927  dynamic_cast<wxTextEntry*>( m_delayedFocusCtrl )->SelectAll();
928 
929  m_delayedFocusCtrl = nullptr;
930  }
931  else if( m_delayedFocusGrid )
932  {
933  m_delayedFocusGrid->SetFocus();
936 
937  m_delayedFocusGrid->EnableCellEditControl( true );
938  m_delayedFocusGrid->ShowCellEditControl();
939 
940  m_delayedFocusGrid = nullptr;
941  m_delayedFocusRow = -1;
943  }
944 }
945 
946 
948 {
949  auto new_size = event.GetSize().GetX();
950 
951  if( new_size != m_width )
952  {
953  adjustGridColumns( event.GetSize().GetX() );
954  }
955 
956  // Always propagate a wxSizeEvent:
957  event.Skip();
958 }
959 
960 
962 {
963  adjustAliasGridColumns( event.GetSize().GetX() );
964 
965  event.Skip();
966 }
wxString GetName(bool aTranslate=true) const
Returns the field name.
Definition: lib_field.cpp:367
LIB_PART * GetCurPart() const
Return the current part being edited or NULL if none selected.
void OnAddFootprintFilter(wxCommandEvent &event) override
int GetUnitCount() const
LIB_FIELD * GetField(int aId)
Return pointer to the requested field.
Part library alias object definition.
void SetConversion(bool aSetConvert)
Set or clear the alternate body style (DeMorgan) for the part.
void SetPower()
name of datasheet
void OnUpdateUI(wxUpdateUIEvent &event) override
int GetPinNameOffset()
void DisplayErrorMessage(wxWindow *aParent, const wxString &aText, const wxString &aExtraInfo)
Display an error message with aMessage.
Definition: confirm.cpp:258
static int KiROUND(double v)
Round a floating point number to an integer using "round halfway cases away from zero".
Definition: common.h:115
void OnAliasNameText(wxCommandEvent &event) override
int GetNumberRows() override
LIB_ALIAS * GetAlias(size_t aIndex)
void OnEditFootprintFilter(wxCommandEvent &event) override
void OnSizeGrid(wxSizeEvent &event) override
This file is part of the common library.
void updateAliasName(bool aFromGrid, const wxString &aName)
bool HasConversion() const
Test if part has more than one body conversion type (DeMorgan).
void ShowHideColumns(const wxString &shownColumns)
Show/hide the grid columns based on a tokenized string of shown column indexes.
Definition: wx_grid.cpp:119
The first 4 are mandatory, and must be instantiated in SCH_COMPONENT and LIB_PART constructors.
Field object used in symbol libraries.
Definition: lib_field.h:59
wxConfigBase * KifaceSettings() const
Definition: kiface_i.h:103
void FinishDialogSettings()
In all dialogs, we must call the same functions to fix minimal dlg size, the default position and per...
static const wxString GetDefaultFieldName(int aFieldNdx)
Function GetDefaultFieldName returns a default symbol field name for field aFieldNdx for all componen...
void SetTable(wxGridTableBase *table, bool aTakeOwnership=false)
Hide wxGrid's SetTable() method with one which doesn't mess up the grid column widths when setting th...
Definition: wx_grid.cpp:57
void OnSymbolNameText(wxCommandEvent &event) override
std::vector< LIB_ALIAS * > LIB_ALIASES
void AddAlias(const wxString &aName)
Add an alias aName to the part.
void OnCancelButtonClick(wxCommandEvent &event) override
void SetDocFileName(const wxString &aDocFileName)
void OnDeleteFootprintFilter(wxCommandEvent &event) override
Field Name Module PCB, i.e. "16DIP300".
Field Reference of part, i.e. "IC21".
KIFACE_I & Kiface()
Global KIFACE_I "get" accessor.
Definition: kicad.cpp:51
void OnAliasNameKillFocus(wxFocusEvent &event) override
const wxString & GetDocFileName() const
void OnMoveUp(wxCommandEvent &event) override
wxString GetCurLib() const
The nickname of the current library being edited and empty string if none.
virtual int GetValue()
Function GetValue Returns the current value in Internal Units.
DIALOG_EDIT_COMPONENT_IN_LIBRARY(LIB_EDIT_FRAME *parent, LIB_PART *aLibEntry)
Constructors.
void DestroyTable(wxGridTableBase *aTable)
Work-around for a bug in wxGrid which crashes when deleting the table if the cell edit control was no...
Definition: wx_grid.cpp:88
bool ShowPinNames()
wxBitmap KiBitmap(BITMAP_DEF aBitmap)
Construct a wxBitmap from a memory record, held in a BITMAP_DEF.
Definition: bitmap.cpp:79
void SetName(const wxString &aName)
#define VALUE
bool ShowPinNumbers()
void SetUnitCount(int count)
Set the units per part count.
PROJECT & Prj() const
Function Prj returns a reference to the PROJECT "associated with" this KIWAY.
void OnFilterDClick(wxMouseEvent &event) override
void OnDeleteField(wxCommandEvent &event) override
const wxString & GetKeyWords() const
const LIB_ID & GetLibId() const
Define a library symbol object.
Helper dialog and control classes.
void OnSelectAlias(wxCommandEvent &event) override
void OnSizeAliasGrid(wxSizeEvent &event) override
void OnSymbolNameKillFocus(wxFocusEvent &event) override
LIB_PART * GetPart() const
Get the shared LIB_PART.
bool CommitPendingChanges(bool aQuietMode=false)
Close any open cell edit controls.
Definition: wx_grid.cpp:167
#define _(s)
void SetDescription(const wxString &aDescription)
void OnMoveDown(wxCommandEvent &event) override
wxArrayString & GetFootprints()
void OnDeleteAlias(wxCommandEvent &event) override
const wxString & GetDescription() override
#define LibEditFieldsShownColumnsKey
wxString GetShownColumns()
Get a tokenized string containing the shown column indexes.
Definition: wx_grid.cpp:101
void EndQuasiModal(int retCode)
wxString GetValue()
The symbol library editor main window.
bool IsPower() const
see class PGM_BASE
const wxString & GetName() const override
void RemoveAllAliases()
void Format(OUTPUTFORMATTER *out, int aNestLevel, int aCtl, CPTREE &aTree)
Function Format outputs a PTREE into s-expression format via an OUTPUTFORMATTER derivative.
Definition: ptree.cpp:205
void SetShowPinNumbers(bool aShow)
Set or clear the pin number visibility flag.
static LIB_PART * dummy()
Used to draw a dummy shape when a LIB_PART is not found in library.
#define max(a, b)
Definition: auxiliary.h:86
const wxString & GetName() const
void SetKeyWords(const wxString &aKeyWords)
virtual void SetValue(int aValue)
Function SetValue Sets new value (in Internal Units) for the text field, taking care of units convers...
size_t i
Definition: json11.cpp:597
Class SCH_COMPONENT describes a real schematic component.
Definition: sch_component.h:73
#define IU_PER_MILS
Definition: plotter.cpp:134
The common library.
Class DIALOG_EDIT_COMPONENT_IN_LIBRARY_BASE.
virtual void SetName(const wxString &aName)
void OnAddAlias(wxCommandEvent &event) override
void OnEditSpiceModel(wxCommandEvent &event) override
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.
void SetShowPinNames(bool aShow)
Set or clear the pin name visibility flag.
void SetPinNameOffset(int aOffset)
Set the offset in mils of the pin name text from the pin symbol.
void DisplayInfoMessage(wxWindow *aParent, const wxString &aMessage, const wxString &aExtraInfo)
Display an informational message box with aMessage.
Definition: confirm.cpp:276
void SetFields(const std::vector< LIB_FIELD > &aFieldsList)
Overwrite all the existing fields in this symbol with fields supplied in aFieldsList.
void OnAddField(wxCommandEvent &event) override
FIELDS_GRID_TABLE< LIB_FIELD > * m_fields
void DisplayError(wxWindow *parent, const wxString &text, int displaytime)
Display an error or warning message box with aMessage.
Definition: confirm.cpp:243
bool IsOK(wxWindow *aParent, const wxString &aMessage)
Display a yes/no dialog with aMessage and returns the user response.
Definition: confirm.cpp:294
virtual const wxString & GetText() const
Function GetText returns the string associated with the text object.
Definition: eda_text.h:124
bool UnitsLocked() const
Check whether part units are interchangeable.
void SaveCopyInUndoList(EDA_ITEM *ItemToCopy, UNDO_REDO_T undoType=UR_LIBEDIT, bool aAppend=false)
Create a copy of the current component, and save it in the undo list.
void Enable(bool aEnable)
Function Enable Enables/diasables the label, widget and units label.
void GetFields(LIB_FIELDS &aList)
Return a list of fields within this part.
void LockUnits(bool aLockUnits)
Set interchangeable the property for part units.
void SetNormal()
LIB_ALIASES GetAliases() const