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_library.h>
33 #include <template_fieldnames.h>
35 #include <sch_edit_frame.h>
36 #include <symbol_lib_table.h>
37 #include <lib_manager.h>
38 #include <symbol_tree_pane.h>
39 #include <widgets/lib_tree.h>
40 #include <sch_legacy_plugin.h>
43 #include <tool/tool_manager.h>
45 #include <dialog_helpers.h>
46 #include <wx/clipbrd.h>
47 
49 {
50  wxString lib = GetCurLib();
51  wxString title = _( "Symbol Editor" );
52 
53  if( GetCurPart() )
54  title += wxT( " \u2014 " ) + GetCurPart()->GetLibId().Format();
55 
56  SetTitle( title );
57 }
58 
59 
60 void LIB_EDIT_FRAME::SelectActiveLibrary( const wxString& aLibrary )
61 {
62  wxString selectedLib = aLibrary;
63 
64  if( selectedLib.empty() )
65  selectedLib = SelectLibraryFromList();
66 
67  if( !selectedLib.empty() )
68  SetCurLib( selectedLib );
69 
70  updateTitle();
71 }
72 
73 
75 {
76  PROJECT& prj = Prj();
77 
78  if( prj.SchSymbolLibTable()->IsEmpty() )
79  {
80  DisplayError( this, _( "No symbol libraries are loaded." ) );
81  return wxEmptyString;
82  }
83 
84  wxArrayString headers;
85 
86  headers.Add( _( "Library" ) );
87 
88  std::vector< wxArrayString > itemsToDisplay;
89  std::vector< wxString > libNicknames = prj.SchSymbolLibTable()->GetLogicalLibs();
90 
91  // Conversion from wxArrayString to vector of ArrayString
92  for( const auto& name : libNicknames )
93  {
94  wxArrayString item;
95 
96  item.Add( name );
97  itemsToDisplay.push_back( item );
98  }
99 
100  wxString old_lib_name = prj.GetRString( PROJECT::SCH_LIB_SELECT );
101 
102  EDA_LIST_DIALOG dlg( this, _( "Select Symbol Library" ), headers, itemsToDisplay,
103  old_lib_name );
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_ALIAS* 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()->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_ALIAS* 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  wxASSERT( lib_part );
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 );
269  m_treePane->Refresh();
271 }
272 
273 
275 {
277  wxString lib = getTargetLib();
278 
279  if( !m_libMgr->LibraryExists( lib ) )
280  {
281  lib = SelectLibraryFromList();
282 
283  if( !m_libMgr->LibraryExists( lib ) )
284  return;
285  }
286 
287  DIALOG_LIB_NEW_COMPONENT dlg( this );
288  dlg.SetMinSize( dlg.GetSize() );
289 
290  if( dlg.ShowModal() == wxID_CANCEL )
291  return;
292 
293  if( dlg.GetName().IsEmpty() )
294  {
295  wxMessageBox( _( "This new symbol has no name and cannot be created." ) );
296  return;
297  }
298 
299  wxString name = dlg.GetName();
300  // Currently, symbol names cannot include a space, that breaks libraries:
301  name.Replace( " ", "_" );
302 
303  // Test if there is a component with this name already.
304  if( !lib.empty() && m_libMgr->PartExists( name, lib ) )
305  {
306  wxString msg = wxString::Format( _( "Symbol \"%s\" already exists in library \"%s\"" ),
307  name, lib );
308  DisplayError( this, msg );
309  return;
310  }
311 
312  LIB_PART new_part( name ); // do not create part on the heap, it will be buffered soon
313  new_part.GetReferenceField().SetText( dlg.GetReference() );
314  new_part.SetUnitCount( dlg.GetUnitCount() );
315 
316  // Initialize new_part.m_TextInside member:
317  // if 0, pin text is outside the body (on the pin)
318  // if > 0, pin text is inside the body
319 
320  if( dlg.GetPinNameInside() )
321  {
322  new_part.SetPinNameOffset( dlg.GetPinTextPosition() );
323 
324  if( new_part.GetPinNameOffset() == 0 )
325  new_part.SetPinNameOffset( 1 );
326  }
327  else
328  {
329  new_part.SetPinNameOffset( 0 );
330  }
331 
332  ( dlg.GetPowerSymbol() ) ? new_part.SetPower() : new_part.SetNormal();
333  new_part.SetShowPinNumbers( dlg.GetShowPinNumber() );
334  new_part.SetShowPinNames( dlg.GetShowPinName() );
335  new_part.LockUnits( dlg.GetLockItems() );
336 
337  if( dlg.GetUnitCount() < 2 )
338  new_part.LockUnits( false );
339 
340  m_libMgr->UpdatePart( &new_part, lib );
341  SyncLibraries( false );
342  LoadPart( name, lib, 1 );
343 
344  new_part.SetConversion( dlg.GetAlternateBodyStyle() );
345  // must be called after loadPart, that calls SetShowDeMorgan, but
346  // because the symbol is empty,it looks like it has no alternate body
348 }
349 
350 
352 {
353  LIB_ID libId = getTargetLibId();
354  const wxString& libName = libId.GetLibNickname();
355  const wxString& partName = libId.GetLibItemName();
356 
357  if( partName.IsEmpty() )
358  {
359  saveLibrary( libName, false );
360  }
361  else
362  {
363  // Save Part
364  if( m_libMgr->FlushPart( partName, libName ) )
365  m_libMgr->ClearPartModified( partName, libName );
366  }
367 
368  m_treePane->Refresh();
370 }
371 
372 
374 {
375  LIB_ID libId = getTargetLibId();
376  const wxString& libName = libId.GetLibNickname();
377  const wxString& partName = libId.GetLibItemName();
378 
379  if( partName.IsEmpty() )
380  saveLibrary( libName, true );
381  else
382  savePartAs();
383 
384  m_treePane->Refresh();
386 }
387 
388 
390 {
391  LIB_ID old_lib_id = getTargetLibId();
392  wxString old_name = old_lib_id.GetLibItemName();
393  wxString old_lib = old_lib_id.GetLibNickname();
394  LIB_PART* part = m_libMgr->GetBufferedPart( old_name, old_lib );
395 
396  if( part )
397  {
398  SYMBOL_LIB_TABLE* tbl = Prj().SchSymbolLibTable();
399  wxArrayString headers;
400  std::vector< wxArrayString > itemsToDisplay;
401  std::vector< wxString > libNicknames = tbl->GetLogicalLibs();
402 
403  headers.Add( _( "Nickname" ) );
404  headers.Add( _( "Description" ) );
405 
406  for( const auto& name : libNicknames )
407  {
408  wxArrayString item;
409  item.Add( name );
410  item.Add( tbl->GetDescription( name ) );
411  itemsToDisplay.push_back( item );
412  }
413 
414  EDA_LIST_DIALOG dlg( this, _( "Save Copy of Symbol" ), headers, itemsToDisplay, old_lib,
415  nullptr, nullptr, /* sort */ false, /* show headers */ false );
416  dlg.SetListLabel( _( "Save in library:" ) );
417  dlg.SetOKLabel( _( "Save" ) );
418 
419  wxBoxSizer* bNameSizer = new wxBoxSizer( wxHORIZONTAL );
420 
421  wxStaticText* label = new wxStaticText( &dlg, wxID_ANY, _( "Name:" ),
422  wxDefaultPosition, wxDefaultSize, 0 );
423  bNameSizer->Add( label, 0, wxALIGN_CENTER_VERTICAL|wxTOP|wxBOTTOM|wxLEFT, 5 );
424 
425  wxTextCtrl* nameTextCtrl = new wxTextCtrl( &dlg, wxID_ANY, old_name,
426  wxDefaultPosition, wxDefaultSize, 0 );
427  bNameSizer->Add( nameTextCtrl, 1, wxALIGN_CENTER_VERTICAL|wxALL, 5 );
428 
429  wxSizer* mainSizer = dlg.GetSizer();
430  mainSizer->Prepend( bNameSizer, 0, wxEXPAND|wxTOP|wxLEFT|wxRIGHT, 5 );
431 
432  // Move nameTextCtrl to the head of the tab-order
433  if( dlg.GetChildren().DeleteObject( nameTextCtrl ) )
434  dlg.GetChildren().Insert( nameTextCtrl );
435 
436  dlg.SetInitialFocus( nameTextCtrl );
437 
438  dlg.Layout();
439  mainSizer->Fit( &dlg );
440 
441  if( dlg.ShowModal() != wxID_OK )
442  return; // canceled by user
443 
444  wxString new_lib = dlg.GetTextSelection();
445 
446  if( new_lib.IsEmpty() )
447  {
448  DisplayError( NULL, _( "No library specified. Symbol could not be saved." ) );
449  return;
450  }
451 
452  wxString new_name = nameTextCtrl->GetValue();
453  new_name.Trim( true );
454  new_name.Trim( false );
455  new_name.Replace( " ", "_" );
456 
457  if( new_name.IsEmpty() )
458  {
459  DisplayError( NULL, _( "No symbol name specified. Symbol could not be saved." ) );
460  return;
461  }
462 
463  // Test if there is a component with this name already.
464  if( m_libMgr->PartExists( new_name, new_lib ) )
465  {
466  wxString msg = wxString::Format( _( "Symbol \"%s\" already exists in library \"%s\"" ),
467  new_name, new_lib );
468  DisplayError( this, msg );
469  return;
470  }
471 
472  LIB_PART new_part( *part );
473  new_part.SetName( new_name );
474 
475  fixDuplicateAliases( &new_part, new_lib );
476  m_libMgr->UpdatePart( &new_part, new_lib );
477  SyncLibraries( false );
478  m_treePane->GetLibTree()->SelectLibId( LIB_ID( new_lib, new_part.GetName() ) );
479 
480  if( isCurrentPart( old_lib_id ) )
481  LoadPart( new_name, new_lib, m_unit );
482  }
483 }
484 
485 
486 void LIB_EDIT_FRAME::UpdateAfterSymbolProperties( wxString* aOldName, wxArrayString* aOldAliases )
487 {
488  wxString msg;
489  wxString lib = GetCurLib();
490  LIB_PART* part = GetCurPart();
491 
492  if( aOldName && *aOldName != part->GetName() )
493  {
494  // Test the current library for name conflicts
495  if( !lib.empty() && m_libMgr->PartExists( part->GetName(), lib ) )
496  {
497  msg.Printf( _( "The name '%s' conflicts with an existing entry in the library '%s'." ),
498  part->GetName(),
499  lib );
500 
501  DisplayErrorMessage( this, msg );
502  part->SetName( *aOldName );
503  }
504  else
505  m_libMgr->UpdatePartAfterRename( part, *aOldName, lib );
506  }
507 
508  if( aOldAliases && *aOldAliases != part->GetAliasNames( false ) )
509  {
510  // If the number of aliases (or their names) have changed, do a full re-sync
511  SyncLibraries( false );
512  }
513  else
514  {
515  // Otherwise just update each alias
516  for( LIB_ALIAS* alias : part->GetAliases() )
517  {
518  wxDataViewItem item = m_libMgr->GetAdapter()->FindItem( alias->GetLibId() );
519  static_cast<LIB_TREE_NODE_LIB_ID*>( item.GetID() )->Update( alias );
520  }
521  }
522 
523  // Reselect the renamed part
524  m_treePane->GetLibTree()->SelectLibId( LIB_ID( lib, part->GetName() ) );
525 
527  SetShowDeMorgan( part->HasConversion() );
528  updateTitle();
529  DisplayCmpDoc();
530 
531  RebuildView();
532  OnModify();
533 }
534 
535 
537 {
538  LIB_ID libId = getTargetLibId();
539 
540  if( m_libMgr->IsPartModified( libId.GetLibItemName(), libId.GetLibNickname() )
541  && !IsOK( this, _( wxString::Format( "Component %s has been modified\n"
542  "Do you want to remove it from the library?",
543  libId.GetUniStringLibItemName() ) ) ) )
544  {
545  return;
546  }
547 
548  if( isCurrentPart( libId ) )
549  emptyScreen();
550 
551  m_libMgr->RemovePart( libId.GetLibItemName(), libId.GetLibNickname() );
552 
554 }
555 
556 
558 {
559  int dummyUnit;
560  LIB_ID libId = m_treePane->GetLibTree()->GetSelectedLibId( &dummyUnit );
561  LIB_PART* part = m_libMgr->GetBufferedPart( libId.GetLibItemName(), libId.GetLibNickname() );
562 
563  if( !part )
564  return;
565 
566  STRING_FORMATTER formatter;
567  SCH_LEGACY_PLUGIN::FormatPart( part, formatter );
568 
569  auto clipboard = wxTheClipboard;
570  wxClipboardLocker clipboardLock( clipboard );
571 
572  if( !clipboardLock || !clipboard->IsOpened() )
573  return;
574 
575  auto data = new wxTextDataObject( wxString( formatter.GetString().c_str(), wxConvUTF8 ) );
576  clipboard->SetData( data );
577 
578  clipboard->Flush();
579 }
580 
581 
582 void LIB_EDIT_FRAME::DuplicatePart( bool aFromClipboard )
583 {
584  int dummyUnit;
585  LIB_ID libId = m_treePane->GetLibTree()->GetSelectedLibId( &dummyUnit );
586  wxString lib = libId.GetLibNickname();
587 
588  if( !m_libMgr->LibraryExists( lib ) )
589  return;
590 
591  LIB_PART* srcPart = nullptr;
592  LIB_PART* newPart = nullptr;
593 
594  if( aFromClipboard )
595  {
596  auto clipboard = wxTheClipboard;
597  wxClipboardLocker clipboardLock( clipboard );
598 
599  if( !clipboardLock || ! clipboard->IsSupported( wxDF_TEXT ) )
600  return;
601 
602  wxTextDataObject data;
603  clipboard->GetData( data );
604  wxString partSource = data.GetText();
605 
606  STRING_LINE_READER reader( TO_UTF8( partSource ), "Clipboard" );
607 
608  try
609  {
610  reader.ReadLine();
611  newPart = SCH_LEGACY_PLUGIN::ParsePart( reader );
612  }
613  catch( IO_ERROR& e )
614  {
615  wxLogMessage( "Can not paste: %s", GetChars( e.Problem() ) );
616  return;
617  }
618  }
619  else
620  {
621  srcPart = m_libMgr->GetBufferedPart( libId.GetLibItemName(), lib );
622  newPart = new LIB_PART( *srcPart );
623  }
624 
625  if( !newPart )
626  return;
627 
628  fixDuplicateAliases( newPart, lib );
629  m_libMgr->UpdatePart( newPart, lib );
630  SyncLibraries( false );
631  m_treePane->GetLibTree()->SelectLibId( LIB_ID( lib, newPart->GetName() ) );
632 
633  delete newPart;
634 }
635 
636 
637 void LIB_EDIT_FRAME::fixDuplicateAliases( LIB_PART* aPart, const wxString& aLibrary )
638 {
639  wxString newName;
640 
641  for( unsigned int i = 0; i < aPart->GetAliasCount(); ++i )
642  {
643  LIB_ALIAS* alias = aPart->GetAlias( i );
644  int sfx = 0;
645  newName = alias->GetName();
646 
647  while( m_libMgr->PartExists( newName, aLibrary ) )
648  {
649  if( sfx == 0 )
650  newName = wxString::Format( "%s_copy", alias->GetName() );
651  else
652  newName = wxString::Format( "%s_copy%d", alias->GetName(), sfx );
653  ++sfx;
654  }
655 
656  if( i == 0 )
657  aPart->SetName( newName );
658  else
659  alias->SetName( newName );
660  }
661 }
662 
663 
664 void LIB_EDIT_FRAME::Revert( bool aConfirm )
665 {
666  LIB_ID libId = getTargetLibId();
667  const wxString& libName = libId.GetLibNickname();
668  const wxString& partName = libId.GetLibItemName(); // Empty if this is the library itself that is selected
669 
670  wxString msg = wxString::Format( _( "Revert \"%s\" to last version saved?" ),
671  partName.IsEmpty() ? libName : partName );
672 
673  if( aConfirm && !ConfirmRevertDialog( this, msg ) )
674  return;
675 
676  bool reload_currentPart = false;
677  wxString curr_partName = partName;
678 
679  if( GetCurPart() )
680  {
681  // the library itself is reverted: the current part will be reloaded only if it is
682  // owned by this library
683  if( partName.IsEmpty() )
684  {
685  LIB_ID curr_libId = GetCurPart()->GetLibId();
686  reload_currentPart = libName == curr_libId.GetLibNickname();
687 
688  if( reload_currentPart )
689  curr_partName = curr_libId.GetLibItemName();
690  }
691  else
692  reload_currentPart = isCurrentPart( libId );
693  }
694 
695  int unit = m_unit;
696 
697  if( reload_currentPart )
698  emptyScreen();
699 
700  if( partName.IsEmpty() )
701  {
702  m_libMgr->RevertLibrary( libName );
703  }
704  else
705  {
706  libId = m_libMgr->RevertPart( libId.GetLibItemName(), libId.GetLibNickname() );
707 
708  m_treePane->GetLibTree()->SelectLibId( libId );
710  }
711 
712  if( reload_currentPart && m_libMgr->PartExists( curr_partName, libName ) )
713  LoadPart( curr_partName, libName, unit );
714 
715  m_treePane->Refresh();
717 }
718 
719 
721 {
722  wxCHECK_RET( m_libMgr, "Library manager object not created." );
723 
724  Revert( false );
725  m_libMgr->RevertAll();
726 }
727 
728 
729 void LIB_EDIT_FRAME::LoadPart( const wxString& aAlias, const wxString& aLibrary, int aUnit )
730 {
731  wxCHECK( m_libMgr->PartExists( aAlias, aLibrary ), /* void */ );
732  LIB_PART* part = m_libMgr->GetBufferedPart( aAlias, aLibrary );
733  LIB_ALIAS* alias = part ? part->GetAlias( aAlias ) : nullptr;
734 
735  if( !alias )
736  {
737  wxString msg = wxString::Format( _( "Symbol name \"%s\" not found in library \"%s\"" ),
738  GetChars( aAlias ),
739  GetChars( aLibrary ) );
740  DisplayError( this, msg );
741  return;
742  }
743 
744  // Optimize default edit options for this symbol
745  // Usually if units are locked, graphic items are specific to each unit
746  // and if units are interchangeable, graphic items are common to units
747  m_DrawSpecificUnit = part->UnitsLocked();
748 
749  LoadOneLibraryPartAux( alias, aLibrary, aUnit, 0 );
750 }
751 
752 
753 bool LIB_EDIT_FRAME::saveLibrary( const wxString& aLibrary, bool aNewFile )
754 {
755  wxFileName fn;
756  wxString msg;
757  PROJECT& prj = Prj();
758 
760 
761  if( !aNewFile && ( aLibrary.empty() || !prj.SchSymbolLibTable()->HasLibrary( aLibrary ) ) )
762  {
763  DisplayError( this, _( "No library specified." ) );
764  return false;
765  }
766 
767  if( aNewFile )
768  {
769  SEARCH_STACK* search = prj.SchSearchS();
770 
771  // Get a new name for the library
772  wxString default_path = prj.GetRString( PROJECT::SCH_LIB_PATH );
773 
774  if( !default_path )
775  default_path = search->LastVisitedPath();
776 
777  fn.SetName( aLibrary );
778  fn.SetExt( SchematicLibraryFileExtension );
779 
780  wxFileDialog dlg( this, wxString::Format( _( "Save Library \"%s\" As..." ), aLibrary ),
781  default_path, fn.GetFullName(), SchematicLibraryFileWildcard(),
782  wxFD_SAVE | wxFD_OVERWRITE_PROMPT );
783 
784  if( dlg.ShowModal() == wxID_CANCEL )
785  return false;
786 
787  fn = dlg.GetPath();
788 
789  // The GTK file chooser doesn't return the file extension added to
790  // file name so add it here.
791  if( fn.GetExt().IsEmpty() )
792  fn.SetExt( SchematicLibraryFileExtension );
793  }
794  else
795  {
796  fn = prj.SchSymbolLibTable()->GetFullURI( aLibrary );
797  }
798 
799  // Verify the user has write privileges before attempting to save the library file.
800  if( !IsWritable( fn ) )
801  return false;
802 
803  ClearMsgPanel();
804 
805  // Copy .lib file to .bak.
806  if( !backupFile( fn, "bak" ) )
807  return false;
808 
809  wxFileName docFileName = fn;
810  docFileName.SetExt( DOC_EXT );
811 
812  // Copy .dcm file to .bck.
813  if( !backupFile( docFileName, "bck" ) )
814  return false;
815 
816  if( !m_libMgr->SaveLibrary( aLibrary, fn.GetFullPath() ) )
817  {
818  msg.Printf( _( "Failed to save changes to symbol library file \"%s\"" ),
819  fn.GetFullPath() );
820  DisplayErrorMessage( this, _( "Error saving library" ), msg );
821  return false;
822  }
823 
824  if( !aNewFile )
825  m_libMgr->ClearLibraryModified( aLibrary );
826 
827  msg.Printf( _( "Symbol library file \"%s\" saved" ), fn.GetFullPath() );
828  wxString msg1;
829  msg1.Printf( _( "Symbol library documentation file \"%s\" saved" ), docFileName.GetFullPath() );
830  AppendMsgPanel( msg, msg1, BLUE );
832 
833  return true;
834 }
835 
836 
837 bool LIB_EDIT_FRAME::saveAllLibraries( bool aRequireConfirmation )
838 {
839  bool doSave = true;
840  int dirtyCount = 0;
841  bool applyToAll = false;
842 
843  for( const auto& libNickname : m_libMgr->GetLibraryNames() )
844  {
845  if( m_libMgr->IsLibraryModified( libNickname ) )
846  dirtyCount++;
847  }
848 
849  for( const auto& libNickname : m_libMgr->GetLibraryNames() )
850  {
851  if( m_libMgr->IsLibraryModified( libNickname ) )
852  {
853  if( aRequireConfirmation && !applyToAll )
854  {
855  wxString msg = wxString::Format( _( "Save changes to \"%s\" before closing?" ),
856  libNickname );
857 
858  switch( UnsavedChangesDialog( this, msg, dirtyCount > 1 ? &applyToAll : nullptr ) )
859  {
860  case wxID_YES: doSave = true; break;
861  case wxID_NO: doSave = false; break;
862  default:
863  case wxID_CANCEL: return false;
864  }
865  }
866 
867  if( doSave )
868  {
869  // If saving under existing name fails then do a Save As..., and if that
870  // fails then cancel close action.
871  if( !saveLibrary( libNickname, false ) && !saveLibrary( libNickname, true ) )
872  return false;
873  }
874  }
875  }
876 
877  return true;
878 }
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.
LIB_PART * GetCurPart() const
Return the current part being edited or NULL if none selected.
void DuplicatePart(bool aFromClipboard)
Inserts a duplicate part.
Definition: libedit.cpp:582
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
Part library alias object definition.
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:156
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
Class PROJECT holds project specific data.
Definition: project.h:58
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
This file is part of the common library.
bool RemovePart(const wxString &aName, const wxString &aLibrary)
Removes the part from the part buffer.
bool HasConversion() const
Test if part has more than one body conversion type (DeMorgan).
void SetOKLabel(const wxString &aLabel)
Definition: displlst.cpp:126
void savePartAs()
Definition: libedit.cpp:389
void LoadPart(const wxString &aLibrary, const wxString &aPart, int Unit)
Definition: libedit.cpp:729
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:60
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:74
static TOOL_ACTION zoomFitScreen
Definition: actions.h:93
wxString SchematicLibraryFileWildcard()
void UpdateAfterSymbolProperties(wxString *aOldName, wxArrayString *aOldAliases)
Definition: libedit.cpp:486
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:557
class EDA_LIST_DIALOG
Class SEARCH_STACK looks for files in a number of places.
Definition: search_stack.h:41
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.
LIB_ALIAS * GetAlias(size_t aIndex) const
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:637
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:118
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:351
#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
wxArrayString GetAliasNames(bool aIncludeRoot=true) const
void SaveAs()
Saves the selected part or library to a new name and/or location.
Definition: libedit.cpp:373
void SetName(const wxString &aName)
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:753
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:536
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.
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
const LIB_ID & GetLibId() const
virtual void ClearUndoRedoList()
Function ClearUndoRedoList clear undo and redo list, using ClearUndoORRedoList() picked items are del...
Define a library symbol object.
Definition of file extensions used in Kicad.
#define DOC_EXT
Definition: class_library.h:50
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
bool LoadOneLibraryPartAux(LIB_ALIAS *aLibEntry, const wxString &aLibrary, int aUnit, int aConvert)
Create a copy of aLibEntry into memory.
Definition: libedit.cpp:216
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.
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:205
void updateTitle()
Updates the main window title bar with the current library name and read only status of the library.
Definition: libedit.cpp:48
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 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
const wxString & GetName() const 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.
Definition: libedit.cpp:122
const char * name
Definition: DXF_plotter.cpp:61
bool saveAllLibraries(bool aRequireConfirmation)
Definition: libedit.cpp:837
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.
const wxString & GetName() const
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:597
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:720
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.
size_t GetAliasCount() const
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
LIB_TREE_MODEL_ADAPTER::PTR & GetAdapter()
Returns the adapter object that provides the stored data.
Definition: lib_manager.h:269
void Revert(bool aConfirm=true)
Reverts unsaved changes in a part, restoring to the last saved state.
Definition: libedit.cpp:664
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:281
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:120
LIB_ALIASES GetAliases() const