KiCad PCB EDA Suite
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-2019 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 <tools/ee_actions.h>
31 #include <lib_edit_frame.h>
32 #include <class_libentry.h>
33 #include <class_library.h>
34 #include <template_fieldnames.h>
36 #include <sch_edit_frame.h>
37 #include <symbol_lib_table.h>
38 #include <lib_manager.h>
39 #include <symbol_tree_pane.h>
40 #include <widgets/lib_tree.h>
41 #include <sch_legacy_plugin.h>
44 #include <tool/tool_manager.h>
46 #include <dialog_helpers.h>
47 #include <wx/clipbrd.h>
48 
50 {
51  wxString lib = GetCurLib();
52  wxString title = _( "Symbol Editor" );
53 
54  if( GetCurPart() )
55  title += wxT( " \u2014 " ) + GetCurPart()->GetLibId().Format();
56 
57  SetTitle( title );
58 }
59 
60 
61 void LIB_EDIT_FRAME::SelectActiveLibrary( const wxString& aLibrary )
62 {
63  wxString selectedLib = aLibrary;
64 
65  if( selectedLib.empty() )
66  selectedLib = SelectLibraryFromList();
67 
68  if( !selectedLib.empty() )
69  SetCurLib( selectedLib );
70 
71  updateTitle();
72 }
73 
74 
76 {
77  PROJECT& prj = Prj();
78 
79  if( prj.SchSymbolLibTable()->IsEmpty() )
80  {
81  DisplayError( this, _( "No symbol libraries are loaded." ) );
82  return wxEmptyString;
83  }
84 
85  wxArrayString headers;
86 
87  headers.Add( _( "Library" ) );
88 
89  std::vector< wxArrayString > itemsToDisplay;
90  std::vector< wxString > libNicknames = prj.SchSymbolLibTable()->GetLogicalLibs();
91 
92  // Conversion from wxArrayString to vector of ArrayString
93  for( const auto& name : libNicknames )
94  {
95  wxArrayString item;
96 
97  item.Add( name );
98  itemsToDisplay.push_back( item );
99  }
100 
101  wxString oldLibName = prj.GetRString( PROJECT::SCH_LIB_SELECT );
102 
103  EDA_LIST_DIALOG dlg( this, _( "Select Symbol Library" ), headers, itemsToDisplay, oldLibName );
104 
105  if( dlg.ShowModal() != wxID_OK )
106  return wxEmptyString;
107 
108  wxString libName = dlg.GetTextSelection();
109 
110  if( !libName.empty() )
111  {
112  if( prj.SchSymbolLibTable()->HasLibrary( libName ) )
113  prj.SetRString( PROJECT::SCH_LIB_SELECT, libName );
114  else
115  libName = wxEmptyString;
116  }
117 
118  return libName;
119 }
120 
121 
123 {
124  if( GetCurPart() )
125  {
126  LIB_ID libId = GetCurPart()->GetLibId();
127  const wxString& libName = libId.GetLibNickname();
128  const wxString& partName = libId.GetLibItemName();
129 
130  if( m_libMgr->FlushPart( partName, libName ) )
131  {
132  m_libMgr->ClearPartModified( partName, libName );
133  return true;
134  }
135  }
136 
137  return false;
138 }
139 
140 
141 bool LIB_EDIT_FRAME::LoadComponentAndSelectLib( const LIB_ID& aLibId, int aUnit, int aConvert )
142 {
143  if( GetCurPart() && GetCurPart()->GetLibId() == aLibId
144  && GetUnit() == aUnit && GetConvert() == aConvert )
145  {
146  return true;
147  }
148 
149  if( GetScreen()->IsModify() && GetCurPart() )
150  {
151  if( !HandleUnsavedChanges( this, _( "The current symbol has been modified. "
152  "Save changes?" ),
153  [&]()->bool { return saveCurrentPart(); } ) )
154  {
155  return false;
156  }
157  }
158 
160  return LoadComponentFromCurrentLib( aLibId.GetLibItemName(), aUnit, aConvert );
161 }
162 
163 
164 bool LIB_EDIT_FRAME::LoadComponentFromCurrentLib( const wxString& aAliasName, int aUnit,
165  int aConvert )
166 {
167  LIB_PART* alias = nullptr;
168 
169  try
170  {
171  alias = Prj().SchSymbolLibTable()->LoadSymbol( GetCurLib(), aAliasName );
172  }
173  catch( const IO_ERROR& ioe )
174  {
175  wxString msg;
176 
177  msg.Printf( _( "Error occurred loading symbol \"%s\" from library \"%s\"." ),
178  aAliasName, GetCurLib() );
179  DisplayErrorMessage( this, msg, ioe.What() );
180  return false;
181  }
182 
183  if( !alias || !LoadOneLibraryPartAux( alias, GetCurLib(), aUnit, aConvert ) )
184  return false;
185 
186  // Enable synchronized pin edit mode for symbols with interchangeable units
188 
191  SetShowDeMorgan( GetCurPart()->Flatten()->HasConversion() );
192 
193  if( aUnit > 0 )
195 
196  return true;
197 }
198 
209 static void synchronizeLibEditScreenSettings( const SCH_SCREEN& aCurrentScreen,
210  SCH_SCREEN& aIncomingScreen )
211 {
212  aIncomingScreen.SetGrid( aCurrentScreen.GetGridSize() );
213 }
214 
215 
216 bool LIB_EDIT_FRAME::LoadOneLibraryPartAux( LIB_PART* aEntry, const wxString& aLibrary,
217  int aUnit, int aConvert )
218 {
219  wxString msg, rootName;
220 
221  if( !aEntry || aLibrary.empty() )
222  return false;
223 
224  if( aEntry->GetName().IsEmpty() )
225  {
226  wxLogWarning( "Symbol in library \"%s\" has empty name field.", aLibrary );
227  return false;
228  }
229 
230  LIB_PART* lib_part = m_libMgr->GetBufferedPart( aEntry->GetName(), aLibrary );
231  wxCHECK( lib_part, false );
232 
233  m_unit = aUnit > 0 ? aUnit : 1;
234  m_convert = aConvert > 0 ? aConvert : 1;
235 
236  // The buffered screen for the part
237  SCH_SCREEN* part_screen = m_libMgr->GetScreen( lib_part->GetName(), aLibrary );
238 
239  const SCH_SCREEN* curr_screen = GetScreen();
240 
241  // Before we set the frame screen, transfer any settings from the current
242  // screen that we want to keep to the incoming (buffered) part's screen
243  // which could be out of date relative to the current screen.
244  if( curr_screen )
245  synchronizeLibEditScreenSettings( *curr_screen, *part_screen );
246 
247  SetScreen( part_screen );
248  SetCurPart( new LIB_PART( *lib_part ) );
249  SetCurLib( aLibrary );
250 
252  updateTitle();
254  SetShowDeMorgan( GetCurPart()->HasConversion() );
255  SyncToolbars();
256 
257  // Display the document information based on the entry selected just in
258  // case the entry is an alias.
259  DisplayCmpDoc();
260  Refresh();
261 
262  return true;
263 }
264 
265 
267 {
268  saveAllLibraries( false );
271 }
272 
273 
275 {
277 
278  wxArrayString rootSymbols;
279  wxString lib = getTargetLib();
280 
281  if( !m_libMgr->LibraryExists( lib ) )
282  {
283  lib = SelectLibraryFromList();
284 
285  if( !m_libMgr->LibraryExists( lib ) )
286  return;
287  }
288 
289  m_libMgr->GetRootSymbolNames( lib, rootSymbols );
290 
291  DIALOG_LIB_NEW_COMPONENT dlg( this, &rootSymbols );
292  dlg.SetMinSize( dlg.GetSize() );
293 
294  if( dlg.ShowModal() == wxID_CANCEL )
295  return;
296 
297  if( dlg.GetName().IsEmpty() )
298  {
299  wxMessageBox( _( "This new symbol has no name and cannot be created." ) );
300  return;
301  }
302 
303  wxString name = dlg.GetName();
304  // Currently, symbol names cannot include a space, that breaks libraries:
305  name.Replace( " ", "_" );
306 
307  // Test if there is a component with this name already.
308  if( !lib.empty() && m_libMgr->PartExists( name, lib ) )
309  {
310  wxString msg = wxString::Format( _( "Symbol \"%s\" already exists in library \"%s\"" ),
311  name, lib );
312  DisplayError( this, msg );
313  return;
314  }
315 
316  LIB_PART new_part( name ); // do not create part on the heap, it will be buffered soon
317 
318  wxString parentSymbolName = dlg.GetParentSymbolName();
319 
320  if( parentSymbolName.IsEmpty() )
321  {
322  new_part.GetReferenceField().SetText( dlg.GetReference() );
323  new_part.SetUnitCount( dlg.GetUnitCount() );
324 
325  // Initialize new_part.m_TextInside member:
326  // if 0, pin text is outside the body (on the pin)
327  // if > 0, pin text is inside the body
328 
329  if( dlg.GetPinNameInside() )
330  {
331  new_part.SetPinNameOffset( dlg.GetPinTextPosition() );
332 
333  if( new_part.GetPinNameOffset() == 0 )
334  new_part.SetPinNameOffset( 1 );
335  }
336  else
337  {
338  new_part.SetPinNameOffset( 0 );
339  }
340 
341  ( dlg.GetPowerSymbol() ) ? new_part.SetPower() : new_part.SetNormal();
342  new_part.SetShowPinNumbers( dlg.GetShowPinNumber() );
343  new_part.SetShowPinNames( dlg.GetShowPinName() );
344  new_part.LockUnits( dlg.GetLockItems() );
345 
346  if( dlg.GetUnitCount() < 2 )
347  new_part.LockUnits( false );
348 
349  new_part.SetConversion( dlg.GetAlternateBodyStyle() );
350  // must be called after loadPart, that calls SetShowDeMorgan, but
351  // because the symbol is empty,it looks like it has no alternate body
353  }
354  else
355  {
356  LIB_PART* parent = m_libMgr->GetAlias( parentSymbolName, lib );
357  wxCHECK( parent, /* void */ );
358  new_part.SetParent( parent );
359  }
360 
361  m_libMgr->UpdatePart( &new_part, lib );
362  SyncLibraries( false );
363  LoadPart( name, lib, 1 );
364 }
365 
366 
368 {
369  LIB_ID libId = getTargetLibId();
370  const wxString& libName = libId.GetLibNickname();
371  const wxString& partName = libId.GetLibItemName();
372 
373  if( partName.IsEmpty() )
374  {
375  saveLibrary( libName, false );
376  }
377  else
378  {
379  // Save Part
380  if( m_libMgr->FlushPart( partName, libName ) )
381  m_libMgr->ClearPartModified( partName, libName );
382  }
383 
386 }
387 
388 
390 {
391  LIB_ID libId = getTargetLibId();
392  const wxString& libName = libId.GetLibNickname();
393  const wxString& partName = libId.GetLibItemName();
394 
395  if( partName.IsEmpty() )
396  saveLibrary( libName, true );
397  else
398  savePartAs();
399 
402 }
403 
404 
406 {
407  LIB_ID old_lib_id = getTargetLibId();
408  wxString old_name = old_lib_id.GetLibItemName();
409  wxString old_lib = old_lib_id.GetLibNickname();
410  LIB_PART* part = m_libMgr->GetBufferedPart( old_name, old_lib );
411 
412  if( part )
413  {
414  SYMBOL_LIB_TABLE* tbl = Prj().SchSymbolLibTable();
415  wxArrayString headers;
416  std::vector< wxArrayString > itemsToDisplay;
417  std::vector< wxString > libNicknames = tbl->GetLogicalLibs();
418 
419  headers.Add( _( "Nickname" ) );
420  headers.Add( _( "Description" ) );
421 
422  for( const auto& name : libNicknames )
423  {
424  wxArrayString item;
425  item.Add( name );
426  item.Add( tbl->GetDescription( name ) );
427  itemsToDisplay.push_back( item );
428  }
429 
430  EDA_LIST_DIALOG dlg( this, _( "Save Copy of Symbol" ), headers, itemsToDisplay, old_lib );
431  dlg.SetListLabel( _( "Save in library:" ) );
432  dlg.SetOKLabel( _( "Save" ) );
433 
434  wxBoxSizer* bNameSizer = new wxBoxSizer( wxHORIZONTAL );
435 
436  wxStaticText* label = new wxStaticText( &dlg, wxID_ANY, _( "Name:" ),
437  wxDefaultPosition, wxDefaultSize, 0 );
438  bNameSizer->Add( label, 0, wxALIGN_CENTER_VERTICAL|wxTOP|wxBOTTOM|wxLEFT, 5 );
439 
440  wxTextCtrl* nameTextCtrl = new wxTextCtrl( &dlg, wxID_ANY, old_name,
441  wxDefaultPosition, wxDefaultSize, 0 );
442  bNameSizer->Add( nameTextCtrl, 1, wxALIGN_CENTER_VERTICAL|wxALL, 5 );
443 
444  wxSizer* mainSizer = dlg.GetSizer();
445  mainSizer->Prepend( bNameSizer, 0, wxEXPAND|wxTOP|wxLEFT|wxRIGHT, 5 );
446 
447  // Move nameTextCtrl to the head of the tab-order
448  if( dlg.GetChildren().DeleteObject( nameTextCtrl ) )
449  dlg.GetChildren().Insert( nameTextCtrl );
450 
451  dlg.SetInitialFocus( nameTextCtrl );
452 
453  dlg.Layout();
454  mainSizer->Fit( &dlg );
455 
456  if( dlg.ShowModal() != wxID_OK )
457  return; // canceled by user
458 
459  wxString new_lib = dlg.GetTextSelection();
460 
461  if( new_lib.IsEmpty() )
462  {
463  DisplayError( this, _( "No library specified. Symbol could not be saved." ) );
464  return;
465  }
466 
467  // @todo Either check the selecteced library to see if the parent symbol name is in
468  // the new library and/or copy the parent symbol as well. This is the lazy
469  // solution to ensure derived parts do not get orphaned.
470  if( part->IsAlias() && new_lib != old_lib )
471  {
472  DisplayError( this, _( "Derived symbols must be save in the same library\n"
473  "that the parent symbol exists." ) );
474  return;
475  }
476 
477  wxString new_name = nameTextCtrl->GetValue();
478  new_name.Trim( true );
479  new_name.Trim( false );
480  new_name.Replace( " ", "_" );
481 
482  if( new_name.IsEmpty() )
483  {
484  DisplayError( this, _( "No symbol name specified. Symbol could not be saved." ) );
485  return;
486  }
487 
488  // Test if there is a component with this name already.
489  if( m_libMgr->PartExists( new_name, new_lib ) )
490  {
491  wxString msg = wxString::Format( _( "Symbol \"%s\" already exists in library \"%s\"" ),
492  new_name, new_lib );
493  DisplayError( this, msg );
494  return;
495  }
496 
497  LIB_PART new_part( *part );
498  new_part.SetName( new_name );
499 
500  m_libMgr->UpdatePart( &new_part, new_lib );
501  SyncLibraries( false );
502  m_treePane->GetLibTree()->SelectLibId( LIB_ID( new_lib, new_part.GetName() ) );
503  LoadPart( new_name, new_lib, m_unit );
504  }
505 }
506 
507 
509 {
510  wxCHECK( m_my_part, /* void */ );
511 
512  wxString msg;
513  wxString lib = GetCurLib();
514 
515  if( aOldName && *aOldName != m_my_part->GetName() )
516  {
517  // Test the current library for name conflicts
518  if( !lib.empty() && m_libMgr->PartExists( m_my_part->GetName(), lib ) )
519  {
520  msg.Printf( _( "The name '%s' conflicts with an existing entry in the library '%s'." ),
521  m_my_part->GetName(),
522  lib );
523 
524  DisplayErrorMessage( this, msg );
525  m_my_part->SetName( *aOldName );
526  }
527  else
528  m_libMgr->UpdatePartAfterRename( m_my_part, *aOldName, lib );
529  }
530 
531  // Reselect the renamed part
533 
535  SetShowDeMorgan( GetCurPart()->Flatten()->HasConversion() );
536  updateTitle();
537  DisplayCmpDoc();
538 
539  RebuildView();
540  OnModify();
541 }
542 
543 
545 {
546  LIB_ID libId = getTargetLibId();
547 
548  if( m_libMgr->IsPartModified( libId.GetLibItemName(), libId.GetLibNickname() )
549  && !IsOK( this, _( wxString::Format( "The symbol \"%s\" has been modified\n"
550  "Do you want to remove it from the library?",
551  libId.GetUniStringLibItemName() ) ) ) )
552  {
553  return;
554  }
555 
556  if( m_libMgr->HasDerivedSymbols( libId.GetLibItemName(), libId.GetLibNickname() ) )
557  {
558  wxString msg;
559 
560  msg.Printf( _( "The symbol \"%s\" is used to derive other symbols.\n"
561  "Deleting this symbol will delete all of the symbols derived from it.\n\n"
562  "Do you wish to delete this symbol and all of it's derivatives?" ),
563  libId.GetLibItemName().wx_str() );
564 
565  wxMessageDialog::ButtonLabel yesButtonLabel( _( "Delete Symbol" ) );
566  wxMessageDialog::ButtonLabel noButtonLabel( _( "Keep Symbol" ) );
567 
568  wxMessageDialog dlg( this, msg, _( "Warning" ),
569  wxYES_NO | wxYES_DEFAULT | wxICON_QUESTION | wxCENTER );
570  dlg.SetYesNoLabels( yesButtonLabel, noButtonLabel );
571 
572  if( dlg.ShowModal() == wxID_NO )
573  return;
574  }
575 
576  if( isCurrentPart( libId ) )
577  emptyScreen();
578 
579  m_libMgr->RemovePart( libId.GetLibItemName(), libId.GetLibNickname() );
580 
583 }
584 
585 
587 {
588  int dummyUnit;
589  LIB_ID libId = m_treePane->GetLibTree()->GetSelectedLibId( &dummyUnit );
590  LIB_PART* part = m_libMgr->GetBufferedPart( libId.GetLibItemName(), libId.GetLibNickname() );
591 
592  if( !part )
593  return;
594 
595  STRING_FORMATTER formatter;
596  SCH_LEGACY_PLUGIN::FormatPart( part, formatter );
597 
598  auto clipboard = wxTheClipboard;
599  wxClipboardLocker clipboardLock( clipboard );
600 
601  if( !clipboardLock || !clipboard->IsOpened() )
602  return;
603 
604  auto data = new wxTextDataObject( wxString( formatter.GetString().c_str(), wxConvUTF8 ) );
605  clipboard->SetData( data );
606 
607  clipboard->Flush();
608 }
609 
610 
611 void LIB_EDIT_FRAME::DuplicatePart( bool aFromClipboard )
612 {
613  int dummyUnit;
614  LIB_ID libId = m_treePane->GetLibTree()->GetSelectedLibId( &dummyUnit );
615  wxString lib = libId.GetLibNickname();
616 
617  if( !m_libMgr->LibraryExists( lib ) )
618  return;
619 
620  LIB_PART* srcPart = nullptr;
621  LIB_PART* newPart = nullptr;
622 
623  if( aFromClipboard )
624  {
625  auto clipboard = wxTheClipboard;
626  wxClipboardLocker clipboardLock( clipboard );
627 
628  if( !clipboardLock || ! clipboard->IsSupported( wxDF_TEXT ) )
629  return;
630 
631  wxTextDataObject data;
632  clipboard->GetData( data );
633  wxString partSource = data.GetText();
634 
635  STRING_LINE_READER reader( TO_UTF8( partSource ), "Clipboard" );
636 
637  try
638  {
639  reader.ReadLine();
640  newPart = SCH_LEGACY_PLUGIN::ParsePart( reader );
641  }
642  catch( IO_ERROR& e )
643  {
644  wxLogMessage( "Can not paste: %s", GetChars( e.Problem() ) );
645  return;
646  }
647  }
648  else
649  {
650  srcPart = m_libMgr->GetBufferedPart( libId.GetLibItemName(), lib );
651 
652  wxCHECK( srcPart, /* void */ );
653 
654  newPart = new LIB_PART( *srcPart );
655 
656  // Derive from same parent.
657  if( srcPart->IsAlias() )
658  {
659  std::shared_ptr< LIB_PART > srcParent = srcPart->GetParent().lock();
660 
661  wxCHECK( srcParent, /* void */ );
662 
663  newPart->SetParent( srcParent.get() );
664  }
665  }
666 
667  if( !newPart )
668  return;
669 
670  fixDuplicateAliases( newPart, lib );
671  m_libMgr->UpdatePart( newPart, lib );
672  SyncLibraries( false );
673  m_treePane->GetLibTree()->SelectLibId( LIB_ID( lib, newPart->GetName() ) );
674 
675  delete newPart;
676 }
677 
678 
679 void LIB_EDIT_FRAME::fixDuplicateAliases( LIB_PART* aPart, const wxString& aLibrary )
680 {
681  wxCHECK( aPart, /* void */ );
682 
683  int i = 1;
684  wxString newName;
685 
686  // Append a number to the name until the name is unique in the library.
687  do
688  {
689  newName.Printf( "%s_%d", aPart->GetName(), i );
690  i++;
691  } while( m_libMgr->PartExists( newName, aLibrary ) );
692 
693  aPart->SetName( newName );
694 }
695 
696 
697 void LIB_EDIT_FRAME::Revert( bool aConfirm )
698 {
699  LIB_ID libId = getTargetLibId();
700  const wxString& libName = libId.GetLibNickname();
701 
702  // Empty if this is the library itself that is selected.
703  const wxString& partName = libId.GetLibItemName();
704 
705  wxString msg = wxString::Format( _( "Revert \"%s\" to last version saved?" ),
706  partName.IsEmpty() ? libName : partName );
707 
708  if( aConfirm && !ConfirmRevertDialog( this, msg ) )
709  return;
710 
711  bool reload_currentPart = false;
712  wxString curr_partName = partName;
713 
714  if( GetCurPart() )
715  {
716  // the library itself is reverted: the current part will be reloaded only if it is
717  // owned by this library
718  if( partName.IsEmpty() )
719  {
720  LIB_ID curr_libId = GetCurPart()->GetLibId();
721  reload_currentPart = libName == curr_libId.GetLibNickname();
722 
723  if( reload_currentPart )
724  curr_partName = curr_libId.GetLibItemName();
725  }
726  else
727  {
728  reload_currentPart = isCurrentPart( libId );
729  }
730  }
731 
732  int unit = m_unit;
733 
734  if( reload_currentPart )
735  emptyScreen();
736 
737  if( partName.IsEmpty() )
738  {
739  m_libMgr->RevertLibrary( libName );
740  }
741  else
742  {
743  libId = m_libMgr->RevertPart( libId.GetLibItemName(), libId.GetLibNickname() );
744 
745  m_treePane->GetLibTree()->SelectLibId( libId );
747  }
748 
749  if( reload_currentPart && m_libMgr->PartExists( curr_partName, libName ) )
750  LoadPart( curr_partName, libName, unit );
751 
752  m_treePane->Refresh();
754 }
755 
756 
758 {
759  wxCHECK_RET( m_libMgr, "Library manager object not created." );
760 
761  Revert( false );
762  m_libMgr->RevertAll();
763 }
764 
765 
766 void LIB_EDIT_FRAME::LoadPart( const wxString& aAlias, const wxString& aLibrary, int aUnit )
767 {
768  LIB_PART* part = m_libMgr->GetBufferedPart( aAlias, aLibrary );
769 
770  if( !part )
771  {
772  wxString msg;
773 
774  msg.Printf( _( "Symbol name \"%s\" not found in library \"%s\"" ), aAlias, aLibrary );
775  DisplayError( this, msg );
776  return;
777  }
778 
779  // Optimize default edit options for this symbol
780  // Usually if units are locked, graphic items are specific to each unit
781  // and if units are interchangeable, graphic items are common to units
783 
784  LoadOneLibraryPartAux( part, aLibrary, aUnit, 0 );
785 }
786 
787 
788 bool LIB_EDIT_FRAME::saveLibrary( const wxString& aLibrary, bool aNewFile )
789 {
790  wxFileName fn;
791  wxString msg;
792  PROJECT& prj = Prj();
793 
795 
796  if( !aNewFile && ( aLibrary.empty() || !prj.SchSymbolLibTable()->HasLibrary( aLibrary ) ) )
797  {
798  DisplayError( this, _( "No library specified." ) );
799  return false;
800  }
801 
802  if( aNewFile )
803  {
804  SEARCH_STACK* search = prj.SchSearchS();
805 
806  // Get a new name for the library
807  wxString default_path = prj.GetRString( PROJECT::SCH_LIB_PATH );
808 
809  if( !default_path )
810  default_path = search->LastVisitedPath();
811 
812  fn.SetName( aLibrary );
813  fn.SetExt( SchematicLibraryFileExtension );
814 
815  wxFileDialog dlg( this, wxString::Format( _( "Save Library \"%s\" As..." ), aLibrary ),
816  default_path, fn.GetFullName(), SchematicLibraryFileWildcard(),
817  wxFD_SAVE | wxFD_OVERWRITE_PROMPT );
818 
819  if( dlg.ShowModal() == wxID_CANCEL )
820  return false;
821 
822  fn = dlg.GetPath();
823 
824  // The GTK file chooser doesn't return the file extension added to
825  // file name so add it here.
826  if( fn.GetExt().IsEmpty() )
827  fn.SetExt( SchematicLibraryFileExtension );
828  }
829  else
830  {
831  fn = prj.SchSymbolLibTable()->GetFullURI( aLibrary );
832  }
833 
834  // Verify the user has write privileges before attempting to save the library file.
835  if( !IsWritable( fn ) )
836  return false;
837 
838  ClearMsgPanel();
839 
840  // Copy .lib file to .bak.
841  if( !backupFile( fn, "bak" ) )
842  return false;
843 
844  wxFileName docFileName = fn;
845  docFileName.SetExt( DOC_EXT );
846 
847  // Copy .dcm file to .bck.
848  if( !backupFile( docFileName, "bck" ) )
849  return false;
850 
851  if( !m_libMgr->SaveLibrary( aLibrary, fn.GetFullPath() ) )
852  {
853  msg.Printf( _( "Failed to save changes to symbol library file \"%s\"" ),
854  fn.GetFullPath() );
855  DisplayErrorMessage( this, _( "Error saving library" ), msg );
856  return false;
857  }
858 
859  if( !aNewFile )
860  m_libMgr->ClearLibraryModified( aLibrary );
861 
862  ClearMsgPanel();
863  msg.Printf( _( "Symbol library file \"%s\" saved" ), fn.GetFullPath() );
864  wxString msg1;
865  msg1.Printf( _( "Symbol library documentation file \"%s\" saved" ), docFileName.GetFullPath() );
866  AppendMsgPanel( msg, msg1, BLUE );
868 
869  return true;
870 }
871 
872 
873 bool LIB_EDIT_FRAME::saveAllLibraries( bool aRequireConfirmation )
874 {
875  bool doSave = true;
876  int dirtyCount = 0;
877  bool applyToAll = false;
878 
879  for( const auto& libNickname : m_libMgr->GetLibraryNames() )
880  {
881  if( m_libMgr->IsLibraryModified( libNickname ) )
882  dirtyCount++;
883  }
884 
885  for( const auto& libNickname : m_libMgr->GetLibraryNames() )
886  {
887  if( m_libMgr->IsLibraryModified( libNickname ) )
888  {
889  if( aRequireConfirmation && !applyToAll )
890  {
891  wxString msg = wxString::Format( _( "Save changes to \"%s\" before closing?" ),
892  libNickname );
893 
894  switch( UnsavedChangesDialog( this, msg, dirtyCount > 1 ? &applyToAll : nullptr ) )
895  {
896  case wxID_YES: doSave = true; break;
897  case wxID_NO: doSave = false; break;
898  default:
899  case wxID_CANCEL: return false;
900  }
901  }
902 
903  if( doSave )
904  {
905  // If saving under existing name fails then do a Save As..., and if that
906  // fails then cancel close action.
907  if( !saveLibrary( libNickname, false ) && !saveLibrary( libNickname, true ) )
908  return false;
909  }
910  }
911  }
912 
913  return true;
914 }
Definition: colors.h:57
void DisplayError(wxWindow *aParent, const wxString &aText, int aDisplayTime)
Display an error or warning message box with aMessage.
Definition: confirm.cpp:236
bool m_DrawSpecificUnit
Specify which component parts the current draw item applies to.
void DuplicatePart(bool aFromClipboard)
Inserts a duplicate part.
Definition: libedit.cpp:611
const wxRealPoint & GetGridSize() const
Return the grid size of the currently selected grid.
Definition: base_screen.h:279
static void synchronizeLibEditScreenSettings(const SCH_SCREEN &aCurrentScreen, SCH_SCREEN &aIncomingScreen)
Synchronize screen settings from a current screen into another screen.
Definition: libedit.cpp:209
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 SetConversion(bool aSetConvert)
Set or clear the alternate body style (DeMorgan) for the part.
void SetPower()
wxString GetTextSelection(int aColumn=0)
Function GetTextSelection return the selected text from aColumn in the wxListCtrl in the dialog.
Definition: displlst.cpp:141
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.
Definition: libedit.cpp:164
LIB_ID GetLibId() const override
Class PROJECT holds project specific data.
Definition: project.h:58
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()
void DisplayErrorMessage(wxWindow *aParent, const wxString &aText, const wxString &aExtraInfo)
Display an error message with aMessage.
Definition: confirm.cpp:249
This file is part of the common library TODO brief description.
int GetConvert() const
wxString GetName() const override
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)
Definition: displlst.cpp:112
void savePartAs()
Definition: libedit.cpp:405
void LoadPart(const wxString &aLibrary, const wxString &aPart, int Unit)
Definition: libedit.cpp:766
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.
Definition: libedit.cpp:61
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.
Definition: libedit.cpp:75
static TOOL_ACTION zoomFitScreen
Definition: actions.h:93
bool LoadOneLibraryPartAux(LIB_PART *aLibEntry, const wxString &aLibrary, int aUnit, int aConvert)
Create a copy of aLibEntry into memory.
Definition: libedit.cpp:216
wxString SchematicLibraryFileWildcard()
bool RunAction(const std::string &aActionName, bool aNow=false, T aParam=NULL)
Function RunAction() Runs the specified action.
Definition: tool_manager.h:109
void CopyPartToClipboard()
Definition: libedit.cpp:586
class EDA_LIST_DIALOG
Class 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.
bool IsWritable(const wxFileName &aFileName)
Checks if aFileName can be written.
A logical library item identifier and consists of various portions much like a URI.
Definition: lib_id.h:51
static LIB_PART * ParsePart(LINE_READER &aReader, int majorVersion=0, int minorVersion=0)
void fixDuplicateAliases(LIB_PART *aPart, const wxString &aLibrary)
Renames LIB_PART aliases to avoid conflicts before adding a component to a library
Definition: libedit.cpp:679
virtual const wxString Problem() const
what was the problem?
Definition: exceptions.cpp:49
void SetInitialFocus(wxWindow *aWindow)
Sets the window (usually a wxTextCtrl) that should be focused when the dialog is shown.
Definition: dialog_shim.h:115
LIB_PART * m_my_part
wxString GetCurLib() const
The nickname of the current library being edited and empty string if none.
void SetShowDeMorgan(bool show)
char * ReadLine() override
Function ReadLine reads a line of text into the buffer and increments the line number counter.
Definition: richio.cpp:251
void Save()
Saves the selected part or library.
Definition: libedit.cpp:367
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:48
void SaveAs()
Saves the selected part or library to a new name and/or location.
Definition: libedit.cpp:389
Subclass of DIALOG_LIB_NEW_COMPONENT, which is generated by wxFormBuilder.
void SyncToolbars() override
Update the toolbars (mostly settings/check buttons/checkboxes) with the current controller state.
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.
Definition: libedit.cpp:788
virtual void SetText(const wxString &aText)
Definition: eda_text.cpp:126
virtual const wxString What() const
A composite of Problem() and Where()
Definition: exceptions.cpp:33
void DeletePartFromLibrary()
Definition: libedit.cpp:544
void Refresh()
Update the board display after modifying it by a python script (note: it is automatically called by a...
LIB_ID RevertPart(const wxString &aAlias, const wxString &aLibrary)
Reverts unsaved changes for a particular part.
void SaveAll()
Saves all modified parts and libraries.
Definition: libedit.cpp:266
void SetUnitCount(int count)
Set the units per part count.
const std::string SchematicLibraryFileExtension
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.
Class LIB_PIN definition.
SCH_SCREEN * GetScreen(const wxString &aAlias, const wxString &aLibrary)
Returns the screen used to edit a specific part.
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:145
virtual void ClearUndoRedoList()
Function ClearUndoRedoList clear undo and redo list, using ClearUndoORRedoList() picked items are del...
void SetParent(LIB_PART *aParent=nullptr)
PART_REF & GetParent()
Define a library symbol object.
Definition of file extensions used in Kicad.
#define DOC_EXT
Definition: class_library.h:51
void UpdateAfterSymbolProperties(wxString *aOldName=nullptr)
Definition: libedit.cpp:508
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 GetName(void) const override
const std::string & GetString()
Definition: richio.h:475
static void FormatPart(LIB_PART *aPart, OUTPUTFORMATTER &aFormatter)
bool FlushPart(const wxString &aAlias, const wxString &aLibrary)
Saves part changes to the library copy used by the schematic editor.
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:204
bool LoadComponentAndSelectLib(const LIB_ID &aLibId, int aUnit, int aConvert)
Selects the currently active library and loads the symbol from aLibId.
Definition: libedit.cpp:141
bool SaveLibrary(const wxString &aLibrary, const wxString &aFileName)
Saves library to a file, including unsaved changes.
#define _(s)
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.
Definition: libedit.cpp:49
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:171
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 AppendMsgPanel(const wxString &textUpper, const wxString &textLower, COLOR4D color, int pad=6)
Append a message to the message panel.
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:186
LIB_PART * GetBufferedPart(const wxString &aAlias, const wxString &aLibrary)
Returns the part copy from the buffer.
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:101
see class PGM_BASE
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.
Definition: libedit.cpp:122
const char * name
Definition: DXF_plotter.cpp:61
bool saveAllLibraries(bool aRequireConfirmation)
Definition: libedit.cpp:873
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.
void SetCurPart(LIB_PART *aPart)
Take ownership of aPart and notes that it is the one currently being edited.
bool LibraryExists(const wxString &aLibrary, bool aCheckEnabled=false) const
Returns true if library exists.
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
size_t i
Definition: json11.cpp:649
bool IsAlias() const
wxString wx_str() const
Definition: utf8.cpp:51
void CreateNewPart()
Creates a new part in the selected library.
Definition: libedit.cpp:274
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.
void RevertAll()
Definition: libedit.cpp:757
bool IsLibraryModified(const wxString &aLibrary) const
Returns true if library has unsaved modifications.
virtual void SetName(const wxString &aName)
Implementing DIALOG_LIB_NEW_COMPONENT.
wxString SetCurLib(const wxString &aLibNickname)
Sets the current library nickname and returns the old library nickname.
TOOL_MANAGER * m_toolManager
void ClearMsgPanel() override
Clear all messages from the message panel.
Definition for part library class.
int SetGrid(const wxRealPoint &size)
set the current grid size m_Grid.
LIB_TREE * GetLibTree() const
SYMBOL_TREE_PANE * m_treePane
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.
Class STRING_LINE_READER is a LINE_READER that reads from a multiline 8 bit wide std::string.
Definition: richio.h:254
Class 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.
Definition: libedit.cpp:697
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:280
bool RevertAll()
Revert all pending changes.
bool UnitsLocked() const
Check whether part units are interchangeable.
const wxString GetUniStringLibItemName() const
Definition: lib_id.h:121
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:163
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)
Definition: displlst.cpp:105