KiCad PCB EDA Suite
eeschema/libedit/libedit.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) 2019 Jean-Pierre Charras, jp.charras at wanadoo.fr
5  * Copyright (C) 2008 Wayne Stambaugh <stambaughw@gmail.com>
6  * Copyright (C) 2004-2020 KiCad Developers, see AUTHORS.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 <pgm_base.h>
28 #include <confirm.h>
29 #include <gestfich.h>
30 #include <widgets/infobar.h>
31 #include <tools/ee_actions.h>
33 #include <lib_edit_frame.h>
34 #include <class_libentry.h>
35 #include <class_library.h>
36 #include <template_fieldnames.h>
38 #include <symbol_lib_table.h>
39 #include <lib_manager.h>
40 #include <symbol_tree_pane.h>
41 #include <widgets/lib_tree.h>
42 #include <sch_legacy_plugin.h>
43 #include <sch_sexpr_plugin.h>
45 #include <dialog_helpers.h>
46 #include <wx/clipbrd.h>
47 
48 
50 {
51  wxString lib = GetCurLib();
52  wxString title;
53 
54  if( IsSymbolFromSchematic() )
55  {
56  title += wxString::Format( _( "%s from schematic" ), m_reference );
57  title += wxT( " \u2014 " );
58  }
59  else
60  {
61  if( GetCurPart() )
62  title += GetCurPart()->GetLibId().Format() + wxT( " \u2014 " ) ;
63 
65  title += _( "[Read Only Library]" ) + wxT( " \u2014 " );
66  }
67 
68  title += _( "Symbol Editor" );
69  SetTitle( title );
70 }
71 
72 
73 void LIB_EDIT_FRAME::SelectActiveLibrary( const wxString& aLibrary )
74 {
75  wxString selectedLib = aLibrary;
76 
77  if( selectedLib.empty() )
78  selectedLib = SelectLibraryFromList();
79 
80  if( !selectedLib.empty() )
81  SetCurLib( selectedLib );
82 
83  updateTitle();
84 }
85 
86 
88 {
89  PROJECT& prj = Prj();
90 
91  if( prj.SchSymbolLibTable()->IsEmpty() )
92  {
93  ShowInfoBarError( _( "No symbol libraries are loaded." ) );
94  return wxEmptyString;
95  }
96 
97  wxArrayString headers;
98 
99  headers.Add( _( "Library" ) );
100 
101  std::vector< wxArrayString > itemsToDisplay;
102  std::vector< wxString > libNicknames = prj.SchSymbolLibTable()->GetLogicalLibs();
103 
104  // Conversion from wxArrayString to vector of ArrayString
105  for( const wxString& name : libNicknames )
106  {
107  wxArrayString item;
108 
109  item.Add( name );
110  itemsToDisplay.push_back( item );
111  }
112 
113  wxString oldLibName = prj.GetRString( PROJECT::SCH_LIB_SELECT );
114 
115  EDA_LIST_DIALOG dlg( this, _( "Select Symbol Library" ), headers, itemsToDisplay, oldLibName );
116 
117  if( dlg.ShowModal() != wxID_OK )
118  return wxEmptyString;
119 
120  wxString libName = dlg.GetTextSelection();
121 
122  if( !libName.empty() )
123  {
124  if( prj.SchSymbolLibTable()->HasLibrary( libName ) )
125  prj.SetRString( PROJECT::SCH_LIB_SELECT, libName );
126  else
127  libName = wxEmptyString;
128  }
129 
130  return libName;
131 }
132 
133 
135 {
136  if( GetCurPart() )
137  {
138  LIB_ID libId = GetCurPart()->GetLibId();
139  const wxString& libName = libId.GetLibNickname();
140  const wxString& partName = libId.GetLibItemName();
141 
142  if( m_libMgr->FlushPart( partName, libName ) )
143  {
144  m_libMgr->ClearPartModified( partName, libName );
145  return true;
146  }
147  }
148 
149  return false;
150 }
151 
152 
153 bool LIB_EDIT_FRAME::LoadComponentAndSelectLib( const LIB_ID& aLibId, int aUnit, int aConvert )
154 {
155  if( GetCurPart() && GetCurPart()->GetLibId() == aLibId
156  && GetUnit() == aUnit && GetConvert() == aConvert )
157  {
158  return true;
159  }
160 
161  if( GetScreen()->IsModify() && GetCurPart() )
162  {
163  if( !HandleUnsavedChanges( this, _( "The current symbol has been modified. "
164  "Save changes?" ),
165  [&]()->bool { return saveCurrentPart(); } ) )
166  {
167  return false;
168  }
169  }
170 
172  return LoadComponentFromCurrentLib( aLibId.GetLibItemName(), aUnit, aConvert );
173 }
174 
175 
176 bool LIB_EDIT_FRAME::LoadComponentFromCurrentLib( const wxString& aAliasName, int aUnit,
177  int aConvert )
178 {
179  LIB_PART* alias = nullptr;
180 
181  try
182  {
183  alias = Prj().SchSymbolLibTable()->LoadSymbol( GetCurLib(), aAliasName );
184  }
185  catch( const IO_ERROR& ioe )
186  {
187  wxString msg;
188 
189  msg.Printf( _( "Error occurred loading symbol \"%s\" from library \"%s\"." ),
190  aAliasName, GetCurLib() );
191  DisplayErrorMessage( this, msg, ioe.What() );
192  return false;
193  }
194 
195  if( !alias || !LoadOneLibraryPartAux( alias, GetCurLib(), aUnit, aConvert ) )
196  return false;
197 
198  // Enable synchronized pin edit mode for symbols with interchangeable units
200 
203  SetShowDeMorgan( GetCurPart()->Flatten()->HasConversion() );
204 
205  if( aUnit > 0 )
207 
208  return true;
209 }
210 
211 
212 bool LIB_EDIT_FRAME::LoadOneLibraryPartAux( LIB_PART* aEntry, const wxString& aLibrary,
213  int aUnit, int aConvert )
214 {
215  wxString msg, rootName;
216  bool rebuildMenuAndToolbar = false;
217 
218  if( !aEntry || aLibrary.empty() )
219  return false;
220 
221  if( aEntry->GetName().IsEmpty() )
222  {
223  wxLogWarning( "Symbol in library \"%s\" has empty name field.", aLibrary );
224  return false;
225  }
226 
227  // Symbols from the schematic are edited in place and not managed by the library manager.
228  if( IsSymbolFromSchematic() )
229  {
230  delete m_my_part;
231  m_my_part = nullptr;
232 
233  SCH_SCREEN* screen = GetScreen();
234  delete screen;
236  m_isSymbolFromSchematic = false;
237  rebuildMenuAndToolbar = true;
238  }
239 
240  LIB_PART* lib_part = m_libMgr->GetBufferedPart( aEntry->GetName(), aLibrary );
241  wxCHECK( lib_part, false );
242 
243  m_unit = aUnit > 0 ? aUnit : 1;
244  m_convert = aConvert > 0 ? aConvert : 1;
245 
246  // The buffered screen for the part
247  SCH_SCREEN* part_screen = m_libMgr->GetScreen( lib_part->GetName(), aLibrary );
248 
249  SetScreen( part_screen );
250  SetCurPart( new LIB_PART( *lib_part ) );
251  SetCurLib( aLibrary );
252 
253  if( rebuildMenuAndToolbar )
254  {
255  ReCreateMenuBar();
257  GetInfoBar()->Dismiss();
258  }
259 
261  updateTitle();
263  SetShowDeMorgan( GetCurPart()->HasConversion() );
264 
265  // Display the document information based on the entry selected just in
266  // case the entry is an alias.
267  DisplayCmpDoc();
268  Refresh();
269 
270  return true;
271 }
272 
273 
275 {
276  saveAllLibraries( false );
279 }
280 
281 
283 {
285 
286  wxArrayString rootSymbols;
287  wxString lib = getTargetLib();
288 
289  if( !m_libMgr->LibraryExists( lib ) )
290  {
291  lib = SelectLibraryFromList();
292 
293  if( !m_libMgr->LibraryExists( lib ) )
294  return;
295  }
296 
297  m_libMgr->GetRootSymbolNames( lib, rootSymbols );
298 
299  DIALOG_LIB_NEW_COMPONENT dlg( this, &rootSymbols );
300  dlg.SetMinSize( dlg.GetSize() );
301 
302  if( dlg.ShowModal() == wxID_CANCEL )
303  return;
304 
305  if( dlg.GetName().IsEmpty() )
306  {
307  wxMessageBox( _( "This new symbol has no name and cannot be created." ) );
308  return;
309  }
310 
311  wxString name = dlg.GetName();
312  // Currently, symbol names cannot include a space, that breaks libraries:
313  name.Replace( " ", "_" );
314 
315  // Test if there is a component with this name already.
316  if( !lib.empty() && m_libMgr->PartExists( name, lib ) )
317  {
318  wxString msg = wxString::Format( _( "Symbol \"%s\" already exists in library \"%s\"" ),
319  name, lib );
320  DisplayError( this, msg );
321  return;
322  }
323 
324  LIB_PART new_part( name ); // do not create part on the heap, it will be buffered soon
325 
326  wxString parentSymbolName = dlg.GetParentSymbolName();
327 
328  if( parentSymbolName.IsEmpty() )
329  {
330  new_part.GetReferenceField().SetText( dlg.GetReference() );
331  new_part.SetUnitCount( dlg.GetUnitCount() );
332 
333  // Initialize new_part.m_TextInside member:
334  // if 0, pin text is outside the body (on the pin)
335  // if > 0, pin text is inside the body
336 
337  if( dlg.GetPinNameInside() )
338  {
339  new_part.SetPinNameOffset( dlg.GetPinTextPosition() );
340 
341  if( new_part.GetPinNameOffset() == 0 )
342  new_part.SetPinNameOffset( 1 );
343  }
344  else
345  {
346  new_part.SetPinNameOffset( 0 );
347  }
348 
349  ( dlg.GetPowerSymbol() ) ? new_part.SetPower() : new_part.SetNormal();
350  new_part.SetShowPinNumbers( dlg.GetShowPinNumber() );
351  new_part.SetShowPinNames( dlg.GetShowPinName() );
352  new_part.LockUnits( dlg.GetLockItems() );
353  new_part.SetIncludeInBom( dlg.GetIncludeInBom() );
354  new_part.SetIncludeOnBoard( dlg.GetIncludeOnBoard() );
355 
356  if( dlg.GetUnitCount() < 2 )
357  new_part.LockUnits( false );
358 
359  new_part.SetConversion( dlg.GetAlternateBodyStyle() );
360  // must be called after loadPart, that calls SetShowDeMorgan, but
361  // because the symbol is empty,it looks like it has no alternate body
363  }
364  else
365  {
366  LIB_PART* parent = m_libMgr->GetAlias( parentSymbolName, lib );
367  wxCHECK( parent, /* void */ );
368  new_part.SetParent( parent );
369 
370  // Inherit the parent mandatory field attributes.
371  for( int id=0; id<MANDATORY_FIELDS; ++id )
372  {
373  LIB_FIELD* field = new_part.GetField( id );
374 
375  // the MANDATORY_FIELDS are exactly that in RAM.
376  wxCHECK( field, /* void */ );
377 
378  LIB_FIELD* parentField = parent->GetField( id );
379 
380  wxCHECK( parentField, /* void */ );
381 
382  *field = *parentField;
383 
384  if( id == VALUE )
385  field->SetText( name );
386 
387  field->SetParent( &new_part );
388  }
389  }
390 
391  m_libMgr->UpdatePart( &new_part, lib );
392  SyncLibraries( false );
393  LoadPart( name, lib, 1 );
394 }
395 
396 
398 {
399  LIB_ID libId = getTargetLibId();
400  const wxString& libName = libId.GetLibNickname();
401  const wxString& partName = libId.GetLibItemName();
402 
403  if( partName.IsEmpty() )
404  {
405  saveLibrary( libName, false );
406  }
407  else if( !libName.IsEmpty() && m_libMgr->IsLibraryReadOnly( libName ) )
408  {
409  // Force a "Save As..." if the modified library is read only.
410  saveLibrary( libName, true );
411  }
412  else
413  {
414  // Save a single library.
415  if( m_libMgr->FlushPart( partName, libName ) )
416  m_libMgr->ClearPartModified( partName, libName );
417  }
418 
421 }
422 
423 
425 {
426  LIB_ID libId = getTargetLibId();
427  const wxString& libName = libId.GetLibNickname();
428  const wxString& partName = libId.GetLibItemName();
429 
430  if( partName.IsEmpty() )
431  saveLibrary( libName, true );
432  else
433  savePartAs();
434 
437 }
438 
439 
441 {
442  LIB_ID old_lib_id = getTargetLibId();
443  wxString old_name = old_lib_id.GetLibItemName();
444  wxString old_lib = old_lib_id.GetLibNickname();
445  LIB_PART* part = m_libMgr->GetBufferedPart( old_name, old_lib );
446 
447  if( part )
448  {
449  SYMBOL_LIB_TABLE* tbl = Prj().SchSymbolLibTable();
450  wxArrayString headers;
451  std::vector< wxArrayString > itemsToDisplay;
452  std::vector< wxString > libNicknames = tbl->GetLogicalLibs();
453 
454  headers.Add( _( "Nickname" ) );
455  headers.Add( _( "Description" ) );
456 
457  for( const auto& name : libNicknames )
458  {
459  wxArrayString item;
460  item.Add( name );
461  item.Add( tbl->GetDescription( name ) );
462  itemsToDisplay.push_back( item );
463  }
464 
465  EDA_LIST_DIALOG dlg( this, _( "Save Copy of Symbol" ), headers, itemsToDisplay, old_lib );
466  dlg.SetListLabel( _( "Save in library:" ) );
467  dlg.SetOKLabel( _( "Save" ) );
468 
469  wxBoxSizer* bNameSizer = new wxBoxSizer( wxHORIZONTAL );
470 
471  wxStaticText* label = new wxStaticText( &dlg, wxID_ANY, _( "Name:" ),
472  wxDefaultPosition, wxDefaultSize, 0 );
473  bNameSizer->Add( label, 0, wxALIGN_CENTER_VERTICAL|wxTOP|wxBOTTOM|wxLEFT, 5 );
474 
475  wxTextCtrl* nameTextCtrl = new wxTextCtrl( &dlg, wxID_ANY, old_name,
476  wxDefaultPosition, wxDefaultSize, 0 );
477  bNameSizer->Add( nameTextCtrl, 1, wxALIGN_CENTER_VERTICAL|wxALL, 5 );
478 
479  wxSizer* mainSizer = dlg.GetSizer();
480  mainSizer->Prepend( bNameSizer, 0, wxEXPAND|wxTOP|wxLEFT|wxRIGHT, 5 );
481 
482  // Move nameTextCtrl to the head of the tab-order
483  if( dlg.GetChildren().DeleteObject( nameTextCtrl ) )
484  dlg.GetChildren().Insert( nameTextCtrl );
485 
486  dlg.SetInitialFocus( nameTextCtrl );
487 
488  dlg.Layout();
489  mainSizer->Fit( &dlg );
490 
491  if( dlg.ShowModal() != wxID_OK )
492  return; // canceled by user
493 
494  wxString new_lib = dlg.GetTextSelection();
495 
496  if( new_lib.IsEmpty() )
497  {
498  DisplayError( this, _( "No library specified. Symbol could not be saved." ) );
499  return;
500  }
501 
502  // @todo Either check the selecteced library to see if the parent symbol name is in
503  // the new library and/or copy the parent symbol as well. This is the lazy
504  // solution to ensure derived parts do not get orphaned.
505  if( part->IsAlias() && new_lib != old_lib )
506  {
507  DisplayError( this, _( "Derived symbols must be save in the same library\n"
508  "that the parent symbol exists." ) );
509  return;
510  }
511 
512  wxString new_name = nameTextCtrl->GetValue();
513  new_name.Trim( true );
514  new_name.Trim( false );
515  new_name.Replace( " ", "_" );
516 
517  if( new_name.IsEmpty() )
518  {
519  // This is effectively a cancel. No need to nag the user about it.
520  return;
521  }
522 
523  // Test if there is a component with this name already.
524  if( m_libMgr->PartExists( new_name, new_lib ) )
525  {
526  wxString msg = wxString::Format( _( "Symbol \"%s\" already exists in library \"%s\"" ),
527  new_name, new_lib );
528  DisplayError( this, msg );
529  return;
530  }
531 
532  LIB_PART new_part( *part );
533  new_part.SetName( new_name );
534 
535  m_libMgr->UpdatePart( &new_part, new_lib );
536  SyncLibraries( false );
537  m_treePane->GetLibTree()->SelectLibId( LIB_ID( new_lib, new_part.GetName() ) );
538  LoadPart( new_name, new_lib, m_unit );
539  }
540 }
541 
542 
544 {
545  wxCHECK( m_my_part, /* void */ );
546 
547  wxString msg;
548  wxString lib = GetCurLib();
549 
550  if( aOldName && *aOldName != m_my_part->GetName() )
551  {
552  // Test the current library for name conflicts
553  if( !lib.empty() && m_libMgr->PartExists( m_my_part->GetName(), lib ) )
554  {
555  msg.Printf( _( "The name '%s' conflicts with an existing entry in the library '%s'." ),
556  m_my_part->GetName(),
557  lib );
558 
559  DisplayErrorMessage( this, msg );
560  m_my_part->SetName( *aOldName );
561  }
562  else
563  {
564  m_libMgr->UpdatePartAfterRename( m_my_part, *aOldName, lib );
565  }
566 
567  // Reselect the renamed part
569  }
570 
572  SetShowDeMorgan( GetCurPart()->Flatten()->HasConversion() );
573  updateTitle();
574  DisplayCmpDoc();
575 
576  RebuildView();
577  OnModify();
578 }
579 
580 
582 {
583  LIB_ID libId = getTargetLibId();
584 
585  if( m_libMgr->IsPartModified( libId.GetLibItemName(), libId.GetLibNickname() )
586  && !IsOK( this, _( wxString::Format( "The symbol \"%s\" has been modified\n"
587  "Do you want to remove it from the library?",
588  libId.GetUniStringLibItemName() ) ) ) )
589  {
590  return;
591  }
592 
593  if( m_libMgr->HasDerivedSymbols( libId.GetLibItemName(), libId.GetLibNickname() ) )
594  {
595  wxString msg;
596 
597  msg.Printf( _( "The symbol \"%s\" is used to derive other symbols.\n"
598  "Deleting this symbol will delete all of the symbols derived from it.\n\n"
599  "Do you wish to delete this symbol and all of it's derivatives?" ),
600  libId.GetLibItemName().wx_str() );
601 
602  wxMessageDialog::ButtonLabel yesButtonLabel( _( "Delete Symbol" ) );
603  wxMessageDialog::ButtonLabel noButtonLabel( _( "Keep Symbol" ) );
604 
605  wxMessageDialog dlg( this, msg, _( "Warning" ),
606  wxYES_NO | wxYES_DEFAULT | wxICON_QUESTION | wxCENTER );
607  dlg.SetYesNoLabels( yesButtonLabel, noButtonLabel );
608 
609  if( dlg.ShowModal() == wxID_NO )
610  return;
611  }
612 
613  if( isCurrentPart( libId ) )
614  emptyScreen();
615 
616  m_libMgr->RemovePart( libId.GetLibItemName(), libId.GetLibNickname() );
617 
620 }
621 
622 
624 {
625  int dummyUnit;
626  LIB_ID libId = m_treePane->GetLibTree()->GetSelectedLibId( &dummyUnit );
627  LIB_PART* part = m_libMgr->GetBufferedPart( libId.GetLibItemName(), libId.GetLibNickname() );
628 
629  if( !part )
630  return;
631 
632  std::unique_ptr< LIB_PART> tmp = part->Flatten();
633  STRING_FORMATTER formatter;
634  SCH_SEXPR_PLUGIN::FormatPart( tmp.get(), formatter );
635 
636  auto clipboard = wxTheClipboard;
637  wxClipboardLocker clipboardLock( clipboard );
638 
639  if( !clipboardLock || !clipboard->IsOpened() )
640  return;
641 
642  auto data = new wxTextDataObject( wxString( formatter.GetString().c_str(), wxConvUTF8 ) );
643  clipboard->SetData( data );
644 
645  clipboard->Flush();
646 }
647 
648 
649 void LIB_EDIT_FRAME::DuplicatePart( bool aFromClipboard )
650 {
651  int dummyUnit;
652  LIB_ID libId = m_treePane->GetLibTree()->GetSelectedLibId( &dummyUnit );
653  wxString lib = libId.GetLibNickname();
654 
655  if( !m_libMgr->LibraryExists( lib ) )
656  return;
657 
658  LIB_PART* srcPart = nullptr;
659  LIB_PART* newPart = nullptr;
660 
661  if( aFromClipboard )
662  {
663  auto clipboard = wxTheClipboard;
664  wxClipboardLocker clipboardLock( clipboard );
665 
666  if( !clipboardLock || ! clipboard->IsSupported( wxDF_TEXT ) )
667  return;
668 
669  wxTextDataObject data;
670  clipboard->GetData( data );
671  wxString partSource = data.GetText();
672 
673  STRING_LINE_READER reader( TO_UTF8( partSource ), "Clipboard" );
674 
675  try
676  {
677  newPart = SCH_SEXPR_PLUGIN::ParsePart( reader );
678  }
679  catch( IO_ERROR& e )
680  {
681  wxLogMessage( "Can not paste: %s", GetChars( e.Problem() ) );
682  return;
683  }
684  }
685  else
686  {
687  srcPart = m_libMgr->GetBufferedPart( libId.GetLibItemName(), lib );
688 
689  wxCHECK( srcPart, /* void */ );
690 
691  newPart = new LIB_PART( *srcPart );
692 
693  // Derive from same parent.
694  if( srcPart->IsAlias() )
695  {
696  std::shared_ptr< LIB_PART > srcParent = srcPart->GetParent().lock();
697 
698  wxCHECK( srcParent, /* void */ );
699 
700  newPart->SetParent( srcParent.get() );
701  }
702  }
703 
704  if( !newPart )
705  return;
706 
707  ensureUniqueName( newPart, lib );
708  m_libMgr->UpdatePart( newPart, lib );
709  SyncLibraries( false );
710  m_treePane->GetLibTree()->SelectLibId( LIB_ID( lib, newPart->GetName() ) );
711 
712  delete newPart;
713 }
714 
715 
716 void LIB_EDIT_FRAME::ensureUniqueName( LIB_PART* aPart, const wxString& aLibrary )
717 {
718  wxCHECK( aPart, /* void */ );
719 
720  int i = 1;
721  wxString newName = aPart->GetName();
722 
723  // Append a number to the name until the name is unique in the library.
724  while( m_libMgr->PartExists( newName, aLibrary ) )
725  newName.Printf( "%s_%d", aPart->GetName(), i++ );
726 
727  aPart->SetName( newName );
728 }
729 
730 
731 void LIB_EDIT_FRAME::Revert( bool aConfirm )
732 {
733  LIB_ID libId = getTargetLibId();
734  const wxString& libName = libId.GetLibNickname();
735 
736  // Empty if this is the library itself that is selected.
737  const wxString& partName = libId.GetLibItemName();
738 
739  wxString msg = wxString::Format( _( "Revert \"%s\" to last version saved?" ),
740  partName.IsEmpty() ? libName : partName );
741 
742  if( aConfirm && !ConfirmRevertDialog( this, msg ) )
743  return;
744 
745  bool reload_currentPart = false;
746  wxString curr_partName = partName;
747 
748  if( GetCurPart() )
749  {
750  // the library itself is reverted: the current part will be reloaded only if it is
751  // owned by this library
752  if( partName.IsEmpty() )
753  {
754  LIB_ID curr_libId = GetCurPart()->GetLibId();
755  reload_currentPart = libName == curr_libId.GetLibNickname();
756 
757  if( reload_currentPart )
758  curr_partName = curr_libId.GetLibItemName();
759  }
760  else
761  {
762  reload_currentPart = isCurrentPart( libId );
763  }
764  }
765 
766  int unit = m_unit;
767 
768  if( reload_currentPart )
769  emptyScreen();
770 
771  if( partName.IsEmpty() )
772  {
773  m_libMgr->RevertLibrary( libName );
774  }
775  else
776  {
777  libId = m_libMgr->RevertPart( libId.GetLibItemName(), libId.GetLibNickname() );
778 
779  m_treePane->GetLibTree()->SelectLibId( libId );
781  }
782 
783  if( reload_currentPart && m_libMgr->PartExists( curr_partName, libName ) )
784  LoadPart( curr_partName, libName, unit );
785 
786  m_treePane->Refresh();
788 }
789 
790 
792 {
793  wxCHECK_RET( m_libMgr, "Library manager object not created." );
794 
795  Revert( false );
796  m_libMgr->RevertAll();
797 }
798 
799 
800 void LIB_EDIT_FRAME::LoadPart( const wxString& aAlias, const wxString& aLibrary, int aUnit )
801 {
802  LIB_PART* part = m_libMgr->GetBufferedPart( aAlias, aLibrary );
803 
804  if( !part )
805  {
806  wxString msg;
807 
808  msg.Printf( _( "Symbol name \"%s\" not found in library \"%s\"" ), aAlias, aLibrary );
809  DisplayError( this, msg );
810  return;
811  }
812 
813  // Optimize default edit options for this symbol
814  // Usually if units are locked, graphic items are specific to each unit
815  // and if units are interchangeable, graphic items are common to units
817  tools->SetDrawSpecificUnit( part->UnitsLocked() );
818 
819  LoadOneLibraryPartAux( part, aLibrary, aUnit, 0 );
820 }
821 
822 
823 bool LIB_EDIT_FRAME::saveLibrary( const wxString& aLibrary, bool aNewFile )
824 {
825  wxFileName fn;
826  wxString msg;
827  SCH_IO_MGR::SCH_FILE_T fileType = SCH_IO_MGR::SCH_FILE_T::SCH_KICAD;
828  PROJECT& prj = Prj();
829 
831 
832  if( !aNewFile && ( aLibrary.empty() || !prj.SchSymbolLibTable()->HasLibrary( aLibrary ) ) )
833  {
834  ShowInfoBarError( _( "No library specified." ) );
835  return false;
836  }
837 
838  if( aNewFile )
839  {
840  SEARCH_STACK* search = prj.SchSearchS();
841 
842  // Get a new name for the library
843  wxString default_path = prj.GetRString( PROJECT::SCH_LIB_PATH );
844 
845  if( !default_path )
846  default_path = search->LastVisitedPath();
847 
848  fn.SetName( aLibrary );
849  fn.SetExt( KiCadSymbolLibFileExtension );
850 
851  wxString wildcards = KiCadSymbolLibFileWildcard();
852 
853  wxFileDialog dlg( this, wxString::Format( _( "Save Library \"%s\" As..." ), aLibrary ),
854  default_path, fn.GetFullName(), wildcards,
855  wxFD_SAVE | wxFD_OVERWRITE_PROMPT );
856 
857  if( dlg.ShowModal() == wxID_CANCEL )
858  return false;
859 
860  fn = dlg.GetPath();
861 
862  prj.SetRString( PROJECT::SCH_LIB_PATH, fn.GetPath() );
863 
864  if( fn.GetExt().IsEmpty() )
865  fn.SetExt( KiCadSymbolLibFileExtension );
866  }
867  else
868  {
869  fn = prj.SchSymbolLibTable()->GetFullURI( aLibrary );
870  fileType = SCH_IO_MGR::GuessPluginTypeFromLibPath( fn.GetFullPath() );
871  }
872 
873  // Verify the user has write privileges before attempting to save the library file.
874  if( !aNewFile && m_libMgr->IsLibraryReadOnly( aLibrary ) )
875  return false;
876 
877  ClearMsgPanel();
878 
879  // Copy .kicad_symb file to .bak.
880  if( !backupFile( fn, "bak" ) )
881  return false;
882 
883  if( !m_libMgr->SaveLibrary( aLibrary, fn.GetFullPath(), fileType ) )
884  {
885  msg.Printf( _( "Failed to save changes to symbol library file \"%s\"" ),
886  fn.GetFullPath() );
887  DisplayErrorMessage( this, _( "Error saving library" ), msg );
888  return false;
889  }
890 
891  if( !aNewFile )
892  m_libMgr->ClearLibraryModified( aLibrary );
893 
894  ClearMsgPanel();
895  msg.Printf( _( "Symbol library file \"%s\" saved" ), fn.GetFullPath() );
897 
898  return true;
899 }
900 
901 
902 bool LIB_EDIT_FRAME::saveAllLibraries( bool aRequireConfirmation )
903 {
904  bool doSave = true;
905  int dirtyCount = 0;
906  bool applyToAll = false;
907 
908  for( const auto& libNickname : m_libMgr->GetLibraryNames() )
909  {
910  if( m_libMgr->IsLibraryModified( libNickname ) )
911  dirtyCount++;
912  }
913 
914  for( const auto& libNickname : m_libMgr->GetLibraryNames() )
915  {
916  if( m_libMgr->IsLibraryModified( libNickname ) )
917  {
918  if( aRequireConfirmation && !applyToAll )
919  {
920  wxString msg = wxString::Format( _( "Save changes to \"%s\" before closing?" ),
921  libNickname );
922 
923  switch( UnsavedChangesDialog( this, msg, dirtyCount > 1 ? &applyToAll : nullptr ) )
924  {
925  case wxID_YES: doSave = true; break;
926  case wxID_NO: doSave = false; break;
927  default:
928  case wxID_CANCEL: return false;
929  }
930  }
931 
932  if( doSave )
933  {
934  // If saving under existing name fails then do a Save As..., and if that
935  // fails then cancel close action.
936  if( !m_libMgr->IsLibraryReadOnly( libNickname )
937  && saveLibrary( libNickname, false ) )
938  continue;
939 
940  if( !saveLibrary( libNickname, true ) )
941  return false;
942  }
943  }
944  }
945 
946  return true;
947 }
static SCH_FILE_T GuessPluginTypeFromLibPath(const wxString &aLibPath)
Return a plugin type given a symbol library using the file extension of aLibPath.
Definition: sch_io_mgr.cpp:161
void DisplayError(wxWindow *aParent, const wxString &aText, int aDisplayTime)
Display an error or warning message box with aMessage.
Definition: confirm.cpp:239
void DuplicatePart(bool aFromClipboard)
Inserts a duplicate part.
bool HandleUnsavedChanges(wxWindow *aParent, const wxString &aMessage, const std::function< bool()> &aSaveFunction)
Display a dialog with Save, Cancel and Discard Changes buttons.
Definition: confirm.cpp:201
const UTF8 & GetLibItemName() const
Definition: lib_id.h:114
bool ConfirmRevertDialog(wxWindow *parent, const wxString &aMessage)
Display a confirmation dialog for a revert action.
Definition: confirm.cpp:190
void SetPower()
wxString GetTextSelection(int aColumn=0)
Function GetTextSelection return the selected text from aColumn in the wxListCtrl in the dialog.
bool LoadComponentFromCurrentLib(const wxString &aAliasName, int aUnit=0, int aConvert=0)
Loads a symbol from the current active library, optionally setting the selected unit and convert.
LIB_ID GetLibId() const override
PROJECT holds project specific data.
Definition: project.h:61
bool HasDerivedSymbols(const wxString &aSymbolName, const wxString &aLibraryName)
Check if symbol aSymbolName in library aLibraryName is a root symbol that has derived symbols.
int GetPinNameOffset()
int m_convert
Flag if the symbol being edited was loaded directly from a schematic.
void DisplayErrorMessage(wxWindow *aParent, const wxString &aText, const wxString &aExtraInfo)
Display an error message with aMessage.
Definition: confirm.cpp:252
This file is part of the common library TODO brief description.
int GetConvert() const
wxString GetName() const override
static LIB_PART * ParsePart(LINE_READER &aReader, int aVersion=SEXPR_SCHEMATIC_FILE_VERSION)
This file is part of the common library.
bool RemovePart(const wxString &aName, const wxString &aLibrary)
Removes the part from the part buffer.
void SetOKLabel(const wxString &aLabel)
LIB_DRAWING_TOOLS.
void LoadPart(const wxString &aLibrary, const wxString &aPart, int Unit)
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
void SetUnitCount(int aCount, bool aDuplicateDrawItems=true)
Set the units per part count.
LIB_MANAGER * m_libMgr
static TOOL_ACTION cancelInteractive
Definition: actions.h:65
void SelectActiveLibrary(const wxString &aLibrary=wxEmptyString)
Set the current active library to aLibrary.
SCH_SCREEN * GetScreen() const override
Return a pointer to a BASE_SCREEN or one of its derivatives.
wxString SelectLibraryFromList()
Display a list of loaded libraries in the symbol library and allows the user to select a library.
static TOOL_ACTION zoomFitScreen
Definition: actions.h:94
bool LoadOneLibraryPartAux(LIB_PART *aLibEntry, const wxString &aLibrary, int aUnit, int aConvert)
Create a copy of aLibEntry into memory.
bool RunAction(const std::string &aActionName, bool aNow=false, T aParam=NULL)
Function RunAction() Runs the specified action.
Definition: tool_manager.h:140
EDA_LIST_DIALOG.
SEARCH_STACK looks for files in a number of places.
Definition: search_stack.h:41
LIB_PART * GetCurPart()
Return the current part being edited or NULL if none selected.
bool isCurrentPart(const LIB_ID &aLibId) const
Returns true if aLibId is an alias for the editor screen part.
wxString m_reference
The reference of the symbol.
static void FormatPart(LIB_PART *aPart, OUTPUTFORMATTER &aFormatter)
A logical library item identifier and consists of various portions much like a URI.
Definition: lib_id.h:51
void SetIncludeInBom(bool aIncludeInBom)
Set or clear the include in schematic bill of materials flag.
virtual const wxString Problem() const
what was the problem?
Definition: exceptions.cpp:45
void SetInitialFocus(wxWindow *aWindow)
Sets the window (usually a wxTextCtrl) that should be focused when the dialog is shown.
Definition: dialog_shim.h:114
LIB_PART * m_my_part
virtual void SetParent(EDA_ITEM *aParent)
Definition: base_struct.h:196
wxString GetCurLib() const
The nickname of the current library being edited and empty string if none.
void SetShowDeMorgan(bool show)
void Save()
Saves the selected part or library.
LIB_PART * GetAlias(const wxString &aAlias, const wxString &aLibrary) const
Returns either an alias of a working LIB_PART copy, or alias of the original part if there is no work...
#define TO_UTF8(wxstring)
Macro TO_UTF8 converts a wxString to a UTF8 encoded C string for all wxWidgets build modes.
Definition: macros.h:100
void SaveAs()
Saves the selected part or library to a new name and/or location.
Subclass of DIALOG_LIB_NEW_COMPONENT, which is generated by wxFormBuilder.
void Dismiss() override
Dismisses the infobar and updates the containing layout and AUI manager (if one is provided).
Definition: infobar.cpp:139
void SetConversion(bool aSetConvert, bool aDuplicatePins=true)
Set or clear the alternate body style (DeMorgan) for the part.
LIB_FIELD & GetReferenceField()
Return reference to the reference designator field.
int GetUnit() const
bool saveLibrary(const wxString &aLibrary, bool aNewFile)
Saves the changes to the current library.
virtual void SetText(const wxString &aText)
Definition: eda_text.cpp:121
virtual const wxString What() const
A composite of Problem() and Where()
Definition: exceptions.cpp:29
void Refresh()
Update the board display after modifying it by a python script (note: it is automatically called by a...
void ReCreateMenuBar() override
Recreates the menu bar.
LIB_ID RevertPart(const wxString &aAlias, const wxString &aLibrary)
Reverts unsaved changes for a particular part.
void SaveAll()
Saves all modified parts and libraries.
bool IsPartModified(const wxString &aAlias, const wxString &aLibrary) const
Returns true if part has unsaved modifications.
const wxString GetDescription(const wxString &aNickname)
PROJECT & Prj() const
Function Prj returns a reference to the PROJECT "associated with" this KIWAY.
void SetDrawSpecificUnit(bool aSpecific)
SCH_SCREEN * GetScreen(const wxString &aAlias, const wxString &aLibrary)
Returns the screen used to edit a specific part.
bool IsSymbolFromSchematic() const
LIB_ID GetSelectedLibId(int *aUnit=nullptr) const
For multi-unit components, if the user selects the component itself rather than picking an individual...
Definition: lib_tree.cpp:150
void SetParent(LIB_PART *aParent=nullptr)
PART_REF & GetParent()
Define a library symbol object.
Definition of file extensions used in Kicad.
void UpdateAfterSymbolProperties(wxString *aOldName=nullptr)
Helper dialog and control classes.
wxArrayString GetLibraryNames() const
Returns the array of library names.
const UTF8 & GetLibNickname() const
Return the logical library name portion of a LIB_ID.
Definition: lib_id.h:97
wxString KiCadSymbolLibFileWildcard()
wxString GetName(void) const override
const std::string & GetString()
Definition: richio.h:475
bool FlushPart(const wxString &aAlias, const wxString &aLibrary)
Saves part changes to the library copy used by the schematic editor.
std::unique_ptr< LIB_PART > Flatten() const
Return a flattened symbol inheritance to the caller.
FormatType fileType(const char *aFileName)
Definition: loadmodel.cpp:271
void ShowInfoBarError(const wxString &aErrorMsg)
int UnsavedChangesDialog(wxWindow *parent, wxString aMessage, bool *aApplyToAll)
A specialized version of HandleUnsavedChanges which handles an apply-to-all checkbox.
Definition: confirm.cpp:148
bool PartExists(const wxString &aAlias, const wxString &aLibrary) const
Returns true if part with a specific alias exists in library (either original one or buffered).
bool ClearLibraryModified(const wxString &aLibrary) const
Clears the modified flag for all parts in a library.
void RefreshLibTree()
Refreshes the tree (mainly to update highlighting and asterisking)
Definition: lib_tree.cpp:220
bool LoadComponentAndSelectLib(const LIB_ID &aLibId, int aUnit, int aConvert)
Selects the currently active library and loads the symbol from aLibId.
UTF8 Format() const
Definition: lib_id.cpp:237
void RebuildSymbolUnitsList()
void emptyScreen()
Restores the empty editor screen, without any part or library selected.
bool UpdatePart(LIB_PART *aPart, const wxString &aLibrary)
Updates the part buffer with a new version of the part.
void DisplayCmpDoc()
Display the documentation of the selected component.
Definition: symbedit.cpp:204
void updateTitle()
Updates the main window title bar with the current library name and read only status of the library.
VTBL_ENTRY void SetRString(RSTRING_T aStringId, const wxString &aString)
Function SetRString stores a "retained string", which is any session and project specific string iden...
Definition: project.cpp:214
void ensureUniqueName(LIB_PART *aPart, const wxString &aLibrary)
Renames LIB_PART aliases to avoid conflicts before adding a component to a library
Field Value of part, i.e. "3.3K".
bool backupFile(const wxFileName &aOriginalFile, const wxString &aBackupExt)
Creates a backup copy of a file with requested extension
void GetRootSymbolNames(const wxString &aLibName, wxArrayString &aRootSymbolNames)
void SyncLibraries(bool aShowProgress)
Synchronize the library manager to the symbol library table, and then the symbol tree to the library ...
VTBL_ENTRY const wxString & GetRString(RSTRING_T aStringId)
Function GetRString returns a "retained string", which is any session and project specific string ide...
Definition: project.cpp:229
LIB_PART * GetBufferedPart(const wxString &aAlias, const wxString &aLibrary)
Returns the part copy from the buffer.
TOOL_MANAGER * m_toolManager
Definition: tools_holder.h:50
static const wxChar * GetChars(const wxString &s)
Function GetChars returns a wxChar* to the actual wxChar* data within a wxString, and is helpful for ...
Definition: macros.h:153
see class PGM_BASE
void ReCreateHToolbar() override
bool m_SyncPinEdit
Set to true to synchronize pins at the same position when editing symbols with multiple units or mult...
bool saveCurrentPart()
Saves the current part.
const char * name
Definition: DXF_plotter.cpp:60
bool saveAllLibraries(bool aRequireConfirmation)
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:201
void SetShowPinNumbers(bool aShow)
Set or clear the pin number visibility flag.
void SetCurPart(LIB_PART *aPart)
Take ownership of aPart and notes that it is the one currently being edited.
#define _(s)
Definition: 3d_actions.cpp:33
bool LibraryExists(const wxString &aLibrary, bool aCheckEnabled=false) const
Returns true if library exists.
bool m_isSymbolFromSchematic
const wxString LastVisitedPath(const wxString &aSubPathToSearch=wxEmptyString)
Function LastVisitedPath is a quirky function inherited from old code that seems to serve particular ...
void SetScreen(BASE_SCREEN *aScreen) override
bool IsAlias() const
wxString wx_str() const
Definition: utf8.cpp:51
void CreateNewPart()
Creates a new part in the selected library.
LIB_ID getTargetLibId() const
Returns either the part selected in the component tree, if context menu is active or the currently mo...
void OnModify() override
Must be called after a schematic change in order to set the "modify" flag of the current symbol.
bool IsLibraryModified(const wxString &aLibrary) const
Returns true if library has unsaved modifications.
virtual void SetName(const wxString &aName)
WX_INFOBAR * GetInfoBar()
SCH_SCREEN * m_dummyScreen
Helper screen used when no part is loaded
Implementing DIALOG_LIB_NEW_COMPONENT.
wxString SetCurLib(const wxString &aLibNickname)
Sets the current library nickname and returns the old library nickname.
void SetIncludeOnBoard(bool aIncludeOnBoard)
Set or clear include in board netlist flag.
TOOL_MANAGER * GetToolManager() const
Return the MVC controller.
Definition: tools_holder.h:78
void ClearMsgPanel() override
Clear all messages from the message panel.
Definition for part library class.
LIB_TREE * GetLibTree() const
SYMBOL_TREE_PANE * m_treePane
void SetShowPinNames(bool aShow)
Set or clear the pin name visibility flag.
LIB_FIELD * GetField(int aId) const
Return pointer to the requested field.
void SetPinNameOffset(int aOffset)
Set the offset in mils of the pin name text from the pin symbol.
STRING_LINE_READER is a LINE_READER that reads from a multiline 8 bit wide std::string.
Definition: richio.h:254
STRING_FORMATTER implements OUTPUTFORMATTER to a memory buffer.
Definition: richio.h:445
void Revert(bool aConfirm=true)
Reverts unsaved changes in a part, restoring to the last saved state.
Struct IO_ERROR is a class used to hold an error message and may be used when throwing exceptions con...
Definition: ki_exception.h:76
bool IsOK(wxWindow *aParent, const wxString &aMessage)
Display a yes/no dialog with aMessage and returns the user response.
Definition: confirm.cpp:283
bool RevertAll()
Revert all pending changes.
virtual void ClearUndoRedoList()
Function ClearUndoRedoList clear undo and redo list, using ClearUndoORRedoList() picked items are del...
bool IsLibraryReadOnly(const wxString &aLibrary) const
Returns true if the library is stored in a read-only file.
bool UnitsLocked() const
Check whether part units are interchangeable.
const wxString GetUniStringLibItemName() const
Definition: lib_id.h:121
bool SaveLibrary(const wxString &aLibrary, const wxString &aFileName, SCH_IO_MGR::SCH_FILE_T aFileType=SCH_IO_MGR::SCH_FILE_T::SCH_LEGACY)
Saves library to a file, including unsaved changes.
wxString getTargetLib() const
Returns either the library selected in the component tree, if context menu is active or the library t...
std::vector< wxString > GetLogicalLibs()
Return the logical library names, all of them that are pertinent to a look up done on this LIB_TABLE.
void LockUnits(bool aLockUnits)
Set interchangeable the property for part units.
bool ClearPartModified(const wxString &aAlias, const wxString &aLibrary) const
Clears the modified flag for a part.
void SelectLibId(const LIB_ID &aLibId)
Select an item in the tree widget.
Definition: lib_tree.cpp:179
const std::string KiCadSymbolLibFileExtension
bool RevertLibrary(const wxString &aLibrary)
Reverts unsaved changes for a particular library.
bool UpdatePartAfterRename(LIB_PART *aPart, const wxString &oldAlias, const wxString &aLibrary)
Updates the part buffer with a new version of the part when the name has changed.
void SetNormal()
void SetListLabel(const wxString &aLabel)