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 <kiway.h>
28 #include <gr_basic.h>
29 #include <macros.h>
30 #include <pgm_base.h>
31 #include <sch_draw_panel.h>
32 #include <confirm.h>
33 #include <gestfich.h>
34 
35 #include <eeschema_id.h>
36 #include <tools/ee_actions.h>
37 #include <general.h>
38 #include <lib_edit_frame.h>
39 #include <class_library.h>
40 #include <template_fieldnames.h>
42 #include <sch_edit_frame.h>
43 #include <symbol_lib_table.h>
44 #include <lib_manager.h>
45 #include <symbol_tree_pane.h>
46 #include <widgets/lib_tree.h>
47 #include <sch_legacy_plugin.h>
50 #include <tool/tool_manager.h>
52 #include <dialog_helpers.h>
53 #include <wx/clipbrd.h>
54 
56 {
57  wxString lib = GetCurLib();
58  wxString title = _( "Symbol Editor" );
59 
60  if( GetCurPart() )
61  title += wxT( " \u2014 " ) + GetCurPart()->GetLibId().Format();
62 
63  SetTitle( title );
64 }
65 
66 
67 void LIB_EDIT_FRAME::SelectActiveLibrary( const wxString& aLibrary )
68 {
69  wxString selectedLib = aLibrary;
70 
71  if( selectedLib.empty() )
72  selectedLib = SelectLibraryFromList();
73 
74  if( !selectedLib.empty() )
75  SetCurLib( selectedLib );
76 
77  updateTitle();
78 }
79 
80 
82 {
83  PROJECT& prj = Prj();
84 
85  if( prj.SchSymbolLibTable()->IsEmpty() )
86  {
87  DisplayError( this, _( "No symbol libraries are loaded." ) );
88  return wxEmptyString;
89  }
90 
91  wxArrayString headers;
92 
93  headers.Add( _( "Library" ) );
94 
95  std::vector< wxArrayString > itemsToDisplay;
96  std::vector< wxString > libNicknames = prj.SchSymbolLibTable()->GetLogicalLibs();
97 
98  // Conversion from wxArrayString to vector of ArrayString
99  for( const auto& name : libNicknames )
100  {
101  wxArrayString item;
102 
103  item.Add( name );
104  itemsToDisplay.push_back( item );
105  }
106 
107  wxString old_lib_name = prj.GetRString( PROJECT::SCH_LIB_SELECT );
108 
109  EDA_LIST_DIALOG dlg( this, _( "Select Symbol Library" ), headers, itemsToDisplay,
110  old_lib_name );
111 
112  if( dlg.ShowModal() != wxID_OK )
113  return wxEmptyString;
114 
115  wxString libname = dlg.GetTextSelection();
116 
117  if( !libname.empty() )
118  {
119  if( prj.SchSymbolLibTable()->HasLibrary( libname ) )
120  prj.SetRString( PROJECT::SCH_LIB_SELECT, libname );
121  else
122  libname = wxEmptyString;
123  }
124 
125  return libname;
126 }
127 
128 
130 {
131  if( GetCurPart() )
132  {
133  LIB_ID libId = GetCurPart()->GetLibId();
134  const wxString& libName = libId.GetLibNickname();
135  const wxString& partName = libId.GetLibItemName();
136 
137  if( m_libMgr->FlushPart( partName, libName ) )
138  {
139  m_libMgr->ClearPartModified( partName, libName );
140  return true;
141  }
142  }
143 
144  return false;
145 }
146 
147 
148 bool LIB_EDIT_FRAME::LoadComponentAndSelectLib( const LIB_ID& aLibId, int aUnit, int aConvert )
149 {
150  if( GetCurPart() && GetCurPart()->GetLibId() == aLibId
151  && GetUnit() == aUnit && GetConvert() == aConvert )
152  {
153  return true;
154  }
155 
156  if( GetScreen()->IsModify() && GetCurPart() )
157  {
158  if( !HandleUnsavedChanges( this, _( "The current symbol has been modified. Save changes?" ),
159  [&]()->bool { return saveCurrentPart(); } ) )
160  {
161  return false;
162  }
163  }
164 
166  return LoadComponentFromCurrentLib( aLibId.GetLibItemName(), aUnit, aConvert );
167 }
168 
169 
170 bool LIB_EDIT_FRAME::LoadComponentFromCurrentLib( const wxString& aAliasName, int aUnit,
171  int aConvert )
172 {
173  LIB_ALIAS* alias = nullptr;
174 
175  try
176  {
177  alias = Prj().SchSymbolLibTable()->LoadSymbol( GetCurLib(), aAliasName );
178  }
179  catch( const IO_ERROR& ioe )
180  {
181  wxString msg;
182 
183  msg.Printf( _( "Error occurred loading symbol \"%s\" from library \"%s\"." ),
184  aAliasName, GetCurLib() );
185  DisplayErrorMessage( this, msg, ioe.What() );
186  return false;
187  }
188 
189  if( !alias || !LoadOneLibraryPartAux( alias, GetCurLib(), aUnit, aConvert ) )
190  return false;
191 
192  // Enable synchronized pin edit mode for symbols with interchangeable units
194 
196  m_toolManager->RunAction( "common.Control.zoomFitScreen", true );
197  SetShowDeMorgan( GetCurPart()->HasConversion() );
198 
199  if( aUnit > 0 )
201 
202  return true;
203 }
204 
216  const SCH_SCREEN& aCurrentScreen, SCH_SCREEN& aIncomingScreen )
217 {
218  aIncomingScreen.SetGrid( aCurrentScreen.GetGridSize() );
219 }
220 
221 
222 bool LIB_EDIT_FRAME::LoadOneLibraryPartAux( LIB_ALIAS* aEntry, const wxString& aLibrary,
223  int aUnit, int aConvert )
224 {
225  wxString msg, rootName;
226 
227  if( !aEntry || aLibrary.empty() )
228  return false;
229 
230  if( aEntry->GetName().IsEmpty() )
231  {
232  wxLogWarning( "Symbol in library \"%s\" has empty name field.", aLibrary );
233  return false;
234  }
235 
236  LIB_PART* lib_part = m_libMgr->GetBufferedPart( aEntry->GetName(), aLibrary );
237  wxASSERT( lib_part );
238 
239  m_unit = aUnit > 0 ? aUnit : 1;
240  m_convert = aConvert > 0 ? aConvert : 1;
241 
242  // The buffered screen for the part
243  SCH_SCREEN* part_screen = m_libMgr->GetScreen( lib_part->GetName(), aLibrary );
244 
245  const SCH_SCREEN* curr_screen = GetScreen();
246 
247  // Before we set the frame screen, transfer any settings from the current
248  // screen that we want to keep to the incoming (buffered) part's screen
249  // which could be out of date relative to the current screen.
250  if( curr_screen )
251  synchronizeLibEditScreenSettings( *curr_screen, *part_screen );
252 
253  SetScreen( part_screen );
254  SetCurPart( new LIB_PART( *lib_part ) );
255  SetCurLib( aLibrary );
256 
257  m_toolManager->RunAction( "common.Control.zoomFitScreen", true );
258  updateTitle();
260 
261  // Display the document information based on the entry selected just in
262  // case the entry is an alias.
263  DisplayCmpDoc();
264  Refresh();
265 
266  return true;
267 }
268 
269 
270 void LIB_EDIT_FRAME::RedrawComponent( wxDC* aDC, wxPoint aOffset )
271 {
272  LIB_PART* part = GetCurPart();
273 
274  if( part )
275  {
276  // display reference like in schematic (a reference U is shown U? or U?A)
277  // although it is stored without ? and part id.
278  // So temporary change the reference by a schematic like reference
279  LIB_FIELD* field = part->GetField( REFERENCE );
280  wxString fieldText = field->GetText();
281  wxString fieldfullText = field->GetFullText( m_unit );
282 
283  field->EDA_TEXT::SetText( fieldfullText ); // change the field text string only
284  auto opts = PART_DRAW_OPTIONS::Default();
285  opts.show_elec_type = GetShowElectricalType();
286  part->Draw( m_canvas, aDC, aOffset, m_unit, m_convert, opts );
287  field->EDA_TEXT::SetText( fieldText ); // restore the field text string
288  }
289 }
290 
291 
292 void LIB_EDIT_FRAME::RedrawActiveWindow( wxDC* DC, bool EraseBg )
293 {
294  if( GetScreen() == NULL )
295  return;
296 
297  m_canvas->DrawBackGround( DC );
298 
299  RedrawComponent( DC, wxPoint( 0, 0 ) );
300 
301 #ifdef USE_WX_OVERLAY
302  if( IsShown() )
303  {
304  m_overlay.Reset();
305  wxDCOverlay overlaydc( m_overlay, (wxWindowDC*)DC );
306  overlaydc.Clear();
307  }
308 #endif
309 
310  if( m_canvas->IsMouseCaptured() )
311  m_canvas->CallMouseCapture( DC, wxDefaultPosition, false );
312 
313  m_canvas->DrawCrossHair( DC );
314 
315  updateTitle();
316  UpdateStatusBar();
317 }
318 
319 
320 void LIB_EDIT_FRAME::OnSaveAll( wxCommandEvent& event )
321 {
322  saveAllLibraries( false );
323  m_treePane->Refresh();
325 }
326 
327 
328 void LIB_EDIT_FRAME::OnCreateNewPart( wxCommandEvent& event )
329 {
331  wxString lib = getTargetLib();
332 
333  if( !m_libMgr->LibraryExists( lib ) )
334  {
335  lib = SelectLibraryFromList();
336 
337  if( !m_libMgr->LibraryExists( lib ) )
338  return;
339  }
340 
341  DIALOG_LIB_NEW_COMPONENT dlg( this );
342  dlg.SetMinSize( dlg.GetSize() );
343 
344  if( dlg.ShowModal() == wxID_CANCEL )
345  return;
346 
347  if( dlg.GetName().IsEmpty() )
348  {
349  wxMessageBox( _( "This new symbol has no name and cannot be created." ) );
350  return;
351  }
352 
353  wxString name = dlg.GetName();
354  // Currently, symbol names cannot include a space, that breaks libraries:
355  name.Replace( " ", "_" );
356 
357  // Test if there is a component with this name already.
358  if( !lib.empty() && m_libMgr->PartExists( name, lib ) )
359  {
360  wxString msg = wxString::Format( _( "Symbol \"%s\" already exists in library \"%s\"" ),
361  name, lib );
362  DisplayError( this, msg );
363  return;
364  }
365 
366  LIB_PART new_part( name ); // do not create part on the heap, it will be buffered soon
367  new_part.GetReferenceField().SetText( dlg.GetReference() );
368  new_part.SetUnitCount( dlg.GetUnitCount() );
369 
370  // Initialize new_part.m_TextInside member:
371  // if 0, pin text is outside the body (on the pin)
372  // if > 0, pin text is inside the body
373 
374  if( dlg.GetPinNameInside() )
375  {
376  new_part.SetPinNameOffset( dlg.GetPinTextPosition() );
377 
378  if( new_part.GetPinNameOffset() == 0 )
379  new_part.SetPinNameOffset( 1 );
380  }
381  else
382  {
383  new_part.SetPinNameOffset( 0 );
384  }
385 
386  ( dlg.GetPowerSymbol() ) ? new_part.SetPower() : new_part.SetNormal();
387  new_part.SetShowPinNumbers( dlg.GetShowPinNumber() );
388  new_part.SetShowPinNames( dlg.GetShowPinName() );
389  new_part.LockUnits( dlg.GetLockItems() );
390 
391  if( dlg.GetUnitCount() < 2 )
392  new_part.LockUnits( false );
393 
394  m_libMgr->UpdatePart( &new_part, lib );
395  SyncLibraries( false );
396  loadPart( name, lib, 1 );
397 
398  new_part.SetConversion( dlg.GetAlternateBodyStyle() );
399  // must be called after loadPart, that calls SetShowDeMorgan, but
400  // because the symbol is empty,it looks like it has no alternate body
402 
403 }
404 
405 
406 void LIB_EDIT_FRAME::OnEditPart( wxCommandEvent& aEvent )
407 {
408  int unit = 0;
409  LIB_ID partId = m_treePane->GetLibTree()->GetSelectedLibId( &unit );
410  loadPart( partId.GetLibItemName(), partId.GetLibNickname(), unit );
411 }
412 
413 
414 void LIB_EDIT_FRAME::OnSave( wxCommandEvent& aEvent )
415 {
416  LIB_ID libId = getTargetLibId();
417  const wxString& libName = libId.GetLibNickname();
418  const wxString& partName = libId.GetLibItemName();
419 
420  if( partName.IsEmpty() )
421  {
422  saveLibrary( libName, false );
423  }
424  else
425  {
426  // Save Part
427  if( m_libMgr->FlushPart( partName, libName ) )
428  m_libMgr->ClearPartModified( partName, libName );
429  }
430 
431  m_treePane->Refresh();
433 }
434 
435 
436 void LIB_EDIT_FRAME::OnSaveAs( wxCommandEvent& aEvent )
437 {
438  LIB_ID libId = getTargetLibId();
439  const wxString& libName = libId.GetLibNickname();
440  const wxString& partName = libId.GetLibItemName();
441 
442  if( partName.IsEmpty() )
443  saveLibrary( libName, true );
444  else
445  savePartAs();
446 
447  m_treePane->Refresh();
449 }
450 
451 
453 {
454  LIB_ID old_lib_id = getTargetLibId();
455  wxString old_name = old_lib_id.GetLibItemName();
456  wxString old_lib = old_lib_id.GetLibNickname();
457  LIB_PART* part = m_libMgr->GetBufferedPart( old_name, old_lib );
458 
459  if( part )
460  {
461  SYMBOL_LIB_TABLE* tbl = Prj().SchSymbolLibTable();
462  wxArrayString headers;
463  std::vector< wxArrayString > itemsToDisplay;
464  std::vector< wxString > libNicknames = tbl->GetLogicalLibs();
465 
466  headers.Add( _( "Nickname" ) );
467  headers.Add( _( "Description" ) );
468 
469  for( const auto& name : libNicknames )
470  {
471  wxArrayString item;
472  item.Add( name );
473  item.Add( tbl->GetDescription( name ) );
474  itemsToDisplay.push_back( item );
475  }
476 
477  EDA_LIST_DIALOG dlg( this, _( "Save Copy of Symbol" ), headers, itemsToDisplay, old_lib,
478  nullptr, nullptr, /* sort */ false, /* show headers */ false );
479  dlg.SetListLabel( _( "Save in library:" ) );
480  dlg.SetOKLabel( _( "Save" ) );
481 
482  wxBoxSizer* bNameSizer = new wxBoxSizer( wxHORIZONTAL );
483 
484  wxStaticText* label = new wxStaticText( &dlg, wxID_ANY, _( "Name:" ),
485  wxDefaultPosition, wxDefaultSize, 0 );
486  bNameSizer->Add( label, 0, wxALIGN_CENTER_VERTICAL|wxTOP|wxBOTTOM|wxLEFT, 5 );
487 
488  wxTextCtrl* nameTextCtrl = new wxTextCtrl( &dlg, wxID_ANY, old_name,
489  wxDefaultPosition, wxDefaultSize, 0 );
490  bNameSizer->Add( nameTextCtrl, 1, wxALIGN_CENTER_VERTICAL|wxALL, 5 );
491 
492  wxSizer* mainSizer = dlg.GetSizer();
493  mainSizer->Prepend( bNameSizer, 0, wxEXPAND|wxTOP|wxLEFT|wxRIGHT, 5 );
494 
495  // Move nameTextCtrl to the head of the tab-order
496  if( dlg.GetChildren().DeleteObject( nameTextCtrl ) )
497  dlg.GetChildren().Insert( nameTextCtrl );
498 
499  dlg.SetInitialFocus( nameTextCtrl );
500 
501  dlg.Layout();
502  mainSizer->Fit( &dlg );
503 
504  if( dlg.ShowModal() != wxID_OK )
505  return; // canceled by user
506 
507  wxString new_lib = dlg.GetTextSelection();
508 
509  if( new_lib.IsEmpty() )
510  {
511  DisplayError( NULL, _( "No library specified. Symbol could not be saved." ) );
512  return;
513  }
514 
515  wxString new_name = nameTextCtrl->GetValue();
516  new_name.Trim( true );
517  new_name.Trim( false );
518  new_name.Replace( " ", "_" );
519 
520  if( new_name.IsEmpty() )
521  {
522  DisplayError( NULL, _( "No symbol name specified. Symbol could not be saved." ) );
523  return;
524  }
525 
526  // Test if there is a component with this name already.
527  if( m_libMgr->PartExists( new_name, new_lib ) )
528  {
529  wxString msg = wxString::Format( _( "Symbol \"%s\" already exists in library \"%s\"" ),
530  new_name, new_lib );
531  DisplayError( this, msg );
532  return;
533  }
534 
535  LIB_PART new_part( *part );
536  new_part.SetName( new_name );
537 
538  fixDuplicateAliases( &new_part, new_lib );
539  m_libMgr->UpdatePart( &new_part, new_lib );
540  SyncLibraries( false );
541  m_treePane->GetLibTree()->SelectLibId( LIB_ID( new_lib, new_part.GetName() ) );
542 
543  if( isCurrentPart( old_lib_id ) )
544  loadPart( new_name, new_lib, m_unit );
545  }
546 }
547 
548 
549 void LIB_EDIT_FRAME::UpdateAfterSymbolProperties( wxString* aOldName, wxArrayString* aOldAliases )
550 {
551  wxString msg;
552  wxString lib = GetCurLib();
553  LIB_PART* part = GetCurPart();
554 
555  if( aOldName && *aOldName != part->GetName() )
556  {
557  // Test the current library for name conflicts
558  if( !lib.empty() && m_libMgr->PartExists( part->GetName(), lib ) )
559  {
560  msg.Printf( _( "The name '%s' conflicts with an existing entry in the library '%s'." ),
561  part->GetName(),
562  lib );
563 
564  DisplayErrorMessage( this, msg );
565  part->SetName( *aOldName );
566  }
567  else
568  m_libMgr->UpdatePartAfterRename( part, *aOldName, lib );
569  }
570 
571  if( aOldAliases && *aOldAliases != part->GetAliasNames( false ) )
572  SyncLibraries( false );
573 
574  // Reselect the renamed part
575  m_treePane->GetLibTree()->SelectLibId( LIB_ID( lib, part->GetName() ) );
576 
578  updateTitle();
579  DisplayCmpDoc();
580 
581  RebuildView();
582  OnModify();
583 }
584 
585 
586 void LIB_EDIT_FRAME::OnRemovePart( wxCommandEvent& aEvent )
587 {
588  LIB_ID libId = getTargetLibId();
589 
590  if( m_libMgr->IsPartModified( libId.GetLibItemName(), libId.GetLibNickname() )
591  && !IsOK( this, _( wxString::Format( "Component %s has been modified\n"
592  "Do you want to remove it from the library?",
593  libId.GetUniStringLibItemName() ) ) ) )
594  {
595  return;
596  }
597 
598  if( isCurrentPart( libId ) )
599  emptyScreen();
600 
601  m_libMgr->RemovePart( libId.GetLibItemName(), libId.GetLibNickname() );
602 
604 }
605 
606 
607 void LIB_EDIT_FRAME::OnCopyCutPart( wxCommandEvent& aEvent )
608 {
609  int dummyUnit;
610  LIB_ID libId = m_treePane->GetLibTree()->GetSelectedLibId( &dummyUnit );
611  LIB_PART* part = m_libMgr->GetBufferedPart( libId.GetLibItemName(), libId.GetLibNickname() );
612 
613  if( !part )
614  return;
615 
616  STRING_FORMATTER formatter;
617  SCH_LEGACY_PLUGIN::FormatPart( part, formatter );
618 
619  auto clipboard = wxTheClipboard;
620  wxClipboardLocker clipboardLock( clipboard );
621 
622  if( !clipboardLock || !clipboard->IsOpened() )
623  return;
624 
625  auto data = new wxTextDataObject( wxString( formatter.GetString().c_str(), wxConvUTF8 ) );
626  clipboard->SetData( data );
627 
628  clipboard->Flush();
629 
630  if( aEvent.GetId() == ID_LIBEDIT_CUT_PART )
631  OnRemovePart( aEvent );
632 }
633 
634 
635 void LIB_EDIT_FRAME::OnPasteDuplicatePart( wxCommandEvent& aEvent )
636 {
637  int dummyUnit;
638  LIB_ID libId = m_treePane->GetLibTree()->GetSelectedLibId( &dummyUnit );
639  wxString lib = libId.GetLibNickname();
640 
641  if( !m_libMgr->LibraryExists( lib ) )
642  return;
643 
644  LIB_PART* srcPart = nullptr;
645  LIB_PART* newPart = nullptr;
646 
647  if( aEvent.GetId() == ID_LIBEDIT_DUPLICATE_PART )
648  {
649  srcPart = m_libMgr->GetBufferedPart( libId.GetLibItemName(), lib );
650  newPart = new LIB_PART( *srcPart );
651  }
652  else if( aEvent.GetId() == ID_LIBEDIT_PASTE_PART )
653  {
654  auto clipboard = wxTheClipboard;
655  wxClipboardLocker clipboardLock( clipboard );
656 
657  if( !clipboardLock || ! clipboard->IsSupported( wxDF_TEXT ) )
658  return;
659 
660  wxTextDataObject data;
661  clipboard->GetData( data );
662  wxString partSource = data.GetText();
663 
664  STRING_LINE_READER reader( TO_UTF8( partSource ), "Clipboard" );
665 
666  try
667  {
668  reader.ReadLine();
669  newPart = SCH_LEGACY_PLUGIN::ParsePart( reader );
670  }
671  catch( IO_ERROR& e )
672  {
673  wxLogError( wxString::Format( "Malformed clipboard: %s" ), GetChars( e.What() ) );
674  return;
675  }
676  }
677  else
678  wxFAIL;
679 
680  if( !newPart )
681  return;
682 
683  fixDuplicateAliases( newPart, lib );
684  m_libMgr->UpdatePart( newPart, lib );
685  SyncLibraries( false );
686  m_treePane->GetLibTree()->SelectLibId( LIB_ID( lib, newPart->GetName() ) );
687 
688  delete newPart;
689 }
690 
691 
692 void LIB_EDIT_FRAME::fixDuplicateAliases( LIB_PART* aPart, const wxString& aLibrary )
693 {
694  wxString newName;
695 
696  for( unsigned int i = 0; i < aPart->GetAliasCount(); ++i )
697  {
698  LIB_ALIAS* alias = aPart->GetAlias( i );
699  int sfx = 0;
700  newName = alias->GetName();
701 
702  while( m_libMgr->PartExists( newName, aLibrary ) )
703  {
704  if( sfx == 0 )
705  newName = wxString::Format( "%s_copy", alias->GetName() );
706  else
707  newName = wxString::Format( "%s_copy%d", alias->GetName(), sfx );
708  ++sfx;
709  }
710 
711  if( i == 0 )
712  aPart->SetName( newName );
713  else
714  alias->SetName( newName );
715  }
716 }
717 
718 
719 void LIB_EDIT_FRAME::OnRevert( wxCommandEvent& aEvent )
720 {
721  LIB_ID libId = getTargetLibId();
722  const wxString& libName = libId.GetLibNickname();
723  const wxString& partName = libId.GetLibItemName(); // Empty if this is the library itself that is selected
724 
725  wxString msg = wxString::Format( _( "Revert \"%s\" to last version saved?" ),
726  partName.IsEmpty() ? libName : partName );
727 
728  if( !ConfirmRevertDialog( this, msg ) )
729  return;
730 
731  bool reload_currentPart = false;
732  wxString curr_partName = partName;
733 
734  if( GetCurPart() )
735  {
736  // the library itself is reverted: the current part will be reloaded only if it is
737  // owned by this library
738  if( partName.IsEmpty() )
739  {
740  LIB_ID curr_libId = GetCurPart()->GetLibId();
741  reload_currentPart = libName == curr_libId.GetLibNickname();
742 
743  if( reload_currentPart )
744  curr_partName = curr_libId.GetLibItemName();
745  }
746  else
747  reload_currentPart = isCurrentPart( libId );
748  }
749 
750  int unit = m_unit;
751 
752  if( reload_currentPart )
753  emptyScreen();
754 
755  if( partName.IsEmpty() )
756  {
757  m_libMgr->RevertLibrary( libName );
758  }
759  else
760  {
761  libId = m_libMgr->RevertPart( libId.GetLibItemName(), libId.GetLibNickname() );
762 
763  m_treePane->GetLibTree()->SelectLibId( libId );
765  }
766 
767  if( reload_currentPart && m_libMgr->PartExists( curr_partName, libName ) )
768  loadPart( curr_partName, libName, unit );
769 
770  m_treePane->Refresh();
772 }
773 
774 
775 void LIB_EDIT_FRAME::loadPart( const wxString& aAlias, const wxString& aLibrary, int aUnit )
776 {
777  wxCHECK( m_libMgr->PartExists( aAlias, aLibrary ), /* void */ );
778  LIB_PART* part = m_libMgr->GetBufferedPart( aAlias, aLibrary );
779  LIB_ALIAS* alias = part ? part->GetAlias( aAlias ) : nullptr;
780 
781  if( !alias )
782  {
783  wxString msg = wxString::Format( _( "Symbol name \"%s\" not found in library \"%s\"" ),
784  GetChars( aAlias ),
785  GetChars( aLibrary ) );
786  DisplayError( this, msg );
787  return;
788  }
789 
790  // Optimize default edit options for this symbol
791  // Usually if units are locked, graphic items are specific to each unit
792  // and if units are interchangeable, graphic items are common to units
793  m_DrawSpecificUnit = part->UnitsLocked() ? true : false;
794 
795  LoadOneLibraryPartAux( alias, aLibrary, aUnit, 0 );
796 }
797 
798 
799 bool LIB_EDIT_FRAME::saveLibrary( const wxString& aLibrary, bool aNewFile )
800 {
801  wxFileName fn;
802  wxString msg;
803  PROJECT& prj = Prj();
804 
806 
807  if( !aNewFile && ( aLibrary.empty() || !prj.SchSymbolLibTable()->HasLibrary( aLibrary ) ) )
808  {
809  DisplayError( this, _( "No library specified." ) );
810  return false;
811  }
812 
813  if( aNewFile )
814  {
815  SEARCH_STACK* search = prj.SchSearchS();
816 
817  // Get a new name for the library
818  wxString default_path = prj.GetRString( PROJECT::SCH_LIB_PATH );
819 
820  if( !default_path )
821  default_path = search->LastVisitedPath();
822 
823  fn.SetName( aLibrary );
824  fn.SetExt( SchematicLibraryFileExtension );
825 
826  wxFileDialog dlg( this, wxString::Format( _( "Save Library \"%s\" As..." ), aLibrary ),
827  default_path, fn.GetFullName(), SchematicLibraryFileWildcard(),
828  wxFD_SAVE | wxFD_OVERWRITE_PROMPT );
829 
830  if( dlg.ShowModal() == wxID_CANCEL )
831  return false;
832 
833  fn = dlg.GetPath();
834 
835  // The GTK file chooser doesn't return the file extension added to
836  // file name so add it here.
837  if( fn.GetExt().IsEmpty() )
838  fn.SetExt( SchematicLibraryFileExtension );
839  }
840  else
841  {
842  fn = prj.SchSymbolLibTable()->GetFullURI( aLibrary );
843  }
844 
845  // Verify the user has write privileges before attempting to save the library file.
846  if( !IsWritable( fn ) )
847  return false;
848 
849  ClearMsgPanel();
850 
851  // Copy .lib file to .bak.
852  if( !backupFile( fn, "bak" ) )
853  return false;
854 
855  wxFileName docFileName = fn;
856  docFileName.SetExt( DOC_EXT );
857 
858  // Copy .dcm file to .bck.
859  if( !backupFile( docFileName, "bck" ) )
860  return false;
861 
862  if( !m_libMgr->SaveLibrary( aLibrary, fn.GetFullPath() ) )
863  {
864  msg.Printf( _( "Failed to save changes to symbol library file \"%s\"" ),
865  fn.GetFullPath() );
866  DisplayErrorMessage( this, _( "Error saving library" ), msg );
867  return false;
868  }
869 
870  if( !aNewFile )
871  m_libMgr->ClearLibraryModified( aLibrary );
872 
873  msg.Printf( _( "Symbol library file \"%s\" saved" ), fn.GetFullPath() );
874  wxString msg1;
875  msg1.Printf( _( "Symbol library documentation file \"%s\" saved" ), docFileName.GetFullPath() );
876  AppendMsgPanel( msg, msg1, BLUE );
878 
879  return true;
880 }
881 
882 
883 bool LIB_EDIT_FRAME::saveAllLibraries( bool aRequireConfirmation )
884 {
885  bool doSave = true;
886  int dirtyCount = 0;
887  bool applyToAll = false;
888 
889  for( const auto& libNickname : m_libMgr->GetLibraryNames() )
890  {
891  if( m_libMgr->IsLibraryModified( libNickname ) )
892  dirtyCount++;
893  }
894 
895  for( const auto& libNickname : m_libMgr->GetLibraryNames() )
896  {
897  if( m_libMgr->IsLibraryModified( libNickname ) )
898  {
899  if( aRequireConfirmation && !applyToAll )
900  {
901  wxString msg = wxString::Format( _( "Save changes to \"%s\" before closing?" ),
902  libNickname );
903 
904  switch( UnsavedChangesDialog( this, msg, dirtyCount > 1 ? &applyToAll : nullptr ) )
905  {
906  case wxID_YES: doSave = true; break;
907  case wxID_NO: doSave = false; break;
908  default:
909  case wxID_CANCEL: return false;
910  }
911  }
912 
913  if( doSave )
914  {
915  // If saving under existing name fails then do a Save As..., and if that
916  // fails then cancel close action.
917  if( !saveLibrary( libNickname, false ) && !saveLibrary( libNickname, true ) )
918  return false;
919  }
920  }
921  }
922 
923  return true;
924 }
925 
926 
928 {
929  LIB_PART* part = GetCurPart();
930 
932 
933  if( !part )
934  return;
935 
936  LIB_ALIAS* alias = part->GetAlias( part->GetName() );
937  wxString msg = part->GetName();
938 
939  AppendMsgPanel( _( "Name" ), msg, BLUE, 8 );
940 
941  static wxChar UnitLetter[] = wxT( "?ABCDEFGHIJKLMNOPQRSTUVWXYZ" );
942  msg = UnitLetter[m_unit];
943 
944  AppendMsgPanel( _( "Unit" ), msg, BROWN, 8 );
945 
946  if( m_convert > 1 )
947  msg = _( "Convert" );
948  else
949  msg = _( "Normal" );
950 
951  AppendMsgPanel( _( "Body" ), msg, GREEN, 8 );
952 
953  if( part->IsPower() )
954  msg = _( "Power Symbol" );
955  else
956  msg = _( "Symbol" );
957 
958  AppendMsgPanel( _( "Type" ), msg, MAGENTA, 8 );
959  AppendMsgPanel( _( "Description" ), alias->GetDescription(), CYAN, 8 );
960  AppendMsgPanel( _( "Key words" ), alias->GetKeyWords(), DARKDARKGRAY );
961  AppendMsgPanel( _( "Datasheet" ), alias->GetDocFileName(), DARKDARKGRAY );
962 }
Definition: colors.h:57
TOOL_MANAGER * m_toolManager
Definition: draw_frame.h:130
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 OnSaveAll(wxCommandEvent &aEvent)
Saves all modified parts and libraries.
Definition: libedit.cpp:320
LIB_FIELD * GetField(int aId)
Return pointer to the requested field.
const wxRealPoint & GetGridSize() const
Return the grid size of the currently selected grid.
Definition: base_screen.h:410
static void synchronizeLibEditScreenSettings(const SCH_SCREEN &aCurrentScreen, SCH_SCREEN &aIncomingScreen)
Synchronise screen settings from a current screen into another screen.
Definition: libedit.cpp:215
bool HandleUnsavedChanges(wxWindow *aParent, const wxString &aMessage, const std::function< bool()> &aSaveFunction)
Function HandleUnsavedChanges displays a dialog with Save, Cancel and Discard Changes buttons.
Definition: confirm.cpp:212
void Draw(EDA_DRAW_PANEL *aPanel, wxDC *aDc, const wxPoint &aOffset, int aMulti, int aConvert, const PART_DRAW_OPTIONS &aOpts)
Draw part.
Part library alias object definition.
const UTF8 & GetLibItemName() const
Definition: lib_id.h:114
bool ConfirmRevertDialog(wxWindow *parent, const wxString &aMessage)
Function ConfirmRevertDialog displays a confirmation for a revert action.
Definition: confirm.cpp:199
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:170
Class PROJECT holds project specific data.
Definition: project.h:57
int GetPinNameOffset()
void DisplayErrorMessage(wxWindow *aParent, const wxString &aText, const wxString &aExtraInfo)
Function DisplayErrorMessage displays an error message with aMessage.
Definition: confirm.cpp:258
This file is part of the common library TODO brief description.
LIB_ALIAS * GetAlias(size_t aIndex)
void OnCreateNewPart(wxCommandEvent &aEvent)
Creates a new part in the selected library.
Definition: libedit.cpp:328
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:126
void savePartAs()
Definition: libedit.cpp:452
Definition: colors.h:61
Field object used in symbol libraries.
Definition: lib_field.h:59
LIB_MANAGER * m_libMgr
manager taking care of temporary modificatoins
static TOOL_ACTION cancelInteractive
Definition: actions.h:45
void SelectActiveLibrary(const wxString &aLibrary=wxEmptyString)
Set the current active library to aLibrary.
Definition: libedit.cpp:67
SCH_SCREEN * GetScreen() const override
Return a pointer to a BASE_SCREEN or one of its derivatives.
wxString SelectLibraryFromList()
Dispaly a list of loaded libraries in the symbol library and allows the user to select a library.
Definition: libedit.cpp:81
wxString SchematicLibraryFileWildcard()
void UpdateAfterSymbolProperties(wxString *aOldName, wxArrayString *aOldAliases)
Definition: libedit.cpp:549
bool RunAction(const std::string &aActionName, bool aNow=false, T aParam=NULL)
Function RunAction() Runs the specified action.
Definition: tool_manager.h:125
class EDA_LIST_DIALOG
virtual const wxString GetText() const
Function GetText returns the string associated with the text object.
Definition: eda_text.h:147
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.
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:692
void SetInitialFocus(wxWindow *aWindow)
Sets the window (usually a wxTextCtrl) that should be focused when the dialog is shown.
Definition: dialog_shim.h:116
Field Reference of part, i.e. "IC21".
const wxString & GetDocFileName() const
wxString GetCurLib() const
The nickname of the current library being edited and empty string if none.
void SetShowDeMorgan(bool show)
This file contains miscellaneous commonly used macros and functions.
char * ReadLine() override
Function ReadLine reads a line of text into the buffer and increments the line number counter.
Definition: richio.cpp:251
void OnSave(wxCommandEvent &aEvent)
Saves the selected part or library.
Definition: libedit.cpp:414
#define TO_UTF8(wxstring)
Macro TO_UTF8 converts a wxString to a UTF8 encoded C string for all wxWidgets build modes.
Definition: macros.h:47
wxArrayString GetAliasNames(bool aIncludeRoot=true) const
void SetName(const wxString &aName)
Subclass of DIALOG_LIB_NEW_COMPONENT, which is generated by wxFormBuilder.
LIB_FIELD & GetReferenceField()
Return reference to the reference designator field.
bool saveLibrary(const wxString &aLibrary, bool aNewFile)
Saves the changes to the current library.
Definition: libedit.cpp:799
virtual const wxString What() const
A composite of Problem() and Where()
Definition: exceptions.cpp:33
void SetText(const wxString &aText) override
Sets the field text to aText.
Definition: lib_field.cpp:453
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 SetUnitCount(int count)
Set the units per part count.
void OnPasteDuplicatePart(wxCommandEvent &aEvent)
Definition: libedit.cpp:635
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.
const wxString & GetKeyWords() const
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:147
const LIB_ID & GetLibId() const
virtual void ClearUndoRedoList()
Function ClearUndoRedoList clear undo and redo list, using ClearUndoORRedoList() picked items are del...
Definition: colors.h:59
int UnsavedChangesDialog(wxWindow *parent, const wxString &aMessage, bool *aApplyToAll)
Function UnsavedChangesDialog a specialized version of HandleUnsavedChanges which handles an apply-to...
Definition: confirm.cpp:181
virtual void CallMouseCapture(wxDC *aDC, const wxPoint &aPosition, bool aErase)
Function CallMouseCapture calls the mouse capture callback.
void OnRemovePart(wxCommandEvent &aEvent)
Removes a part from the working copy of a library.
Definition: libedit.cpp:586
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.
virtual void DrawCrossHair(wxDC *aDC=nullptr, COLOR4D aColor=COLOR4D::WHITE)
Function DrawCrossHair draws the user cross hair.
wxArrayString GetLibraryNames() const
Returns the array of library names.
Definition: lib_manager.cpp:84
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:222
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.
static PART_DRAW_OPTIONS Default()
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.
virtual void ClearMsgPanel()
Clear all messages from the message panel.
bool LoadComponentAndSelectLib(const LIB_ID &aLibId, int aUnit, int aConvert)
Selects the currently active library and loads the symbol from aLibId.
Definition: libedit.cpp:148
bool SaveLibrary(const wxString &aLibrary, const wxString &aFileName)
Saves library to a file, including unsaved changes.
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: libedit.cpp:927
void updateTitle()
Updates the main window title bar with the current library name and read only status of the library.
Definition: libedit.cpp:55
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
const wxString & GetDescription() override
void UpdateStatusBar() override
Update the status bar information.
void OnSaveAs(wxCommandEvent &aEvent)
Saves the selected part or library to a new name and/or location.
Definition: libedit.cpp:436
bool backupFile(const wxFileName &aOriginalFile, const wxString &aBackupExt)
Creates a backup copy of a file with requested extension
EDA_DRAW_PANEL * m_canvas
The area to draw on.
Definition: draw_frame.h:128
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:100
bool IsPower() const
Definition: colors.h:58
see class PGM_BASE
const wxString & GetName() const override
bool m_SyncPinEdit
Set to true to not synchronize pins at the same position when editing symbols with multiple units or ...
bool saveCurrentPart()
Saves the current part.
Definition: libedit.cpp:129
const char * name
Definition: DXF_plotter.cpp:61
bool saveAllLibraries(bool aRequireConfirmation)
Definition: libedit.cpp:883
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 OnRevert(wxCommandEvent &aEvent)
Reverts unsaved changes in a part, restoring to the last saved state.
Definition: libedit.cpp:719
void OnEditPart(wxCommandEvent &aEvent)
Opens the selected part for editing.
Definition: libedit.cpp:406
void OnCopyCutPart(wxCommandEvent &aEvent)
Definition: libedit.cpp:607
void SetCurPart(LIB_PART *aPart)
Take ownership of aPart and notes that it is the one currently being edited.
const wxString & GetName() const
void RedrawComponent(wxDC *aDC, wxPoint aOffset)
Redraw the current component loaded in library editor Display reference like in schematic (a referenc...
Definition: libedit.cpp:270
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 ...
virtual void SetScreen(BASE_SCREEN *aScreen) override
size_t i
Definition: json11.cpp:597
wxString GetFullText(int unit=1) const
Return the text of a field.
Definition: lib_field.cpp:331
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)
Implementing DIALOG_LIB_NEW_COMPONENT.
wxString SetCurLib(const wxString &aLibNickname)
Sets the current library nickname and returns the old library nickname.
virtual void DrawBackGround(wxDC *DC)
Function DrawBackGround.
size_t GetAliasCount() const
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
component search tree widget
void SetShowPinNames(bool aShow)
Set or clear the pin name visibility flag.
void SetPinNameOffset(int aOffset)
Set the offset in mils of the pin name text from the pin symbol.
void RedrawActiveWindow(wxDC *DC, bool EraseBg) override
Redraw the current component loaded in library editor, an axes Display reference like in schematic (a...
Definition: libedit.cpp:292
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 DisplayError(wxWindow *parent, const wxString &text, int displaytime)
Function DisplayError displays an error or warning message box with aMessage.
Definition: confirm.cpp:244
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)
Function IsOK displays a yes/no dialog with aMessage and returns the user response.
Definition: confirm.cpp:294
bool UnitsLocked() const
Check whether part units are interchangeable.
const wxString GetUniStringLibItemName() const
Definition: lib_id.h:121
void loadPart(const wxString &aLibrary, const wxString &aPart, int Unit)
Definition: libedit.cpp:775
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:165
bool GetShowElectricalType()
Allow some frames to show/hide pin electrical type names.
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
Definition: colors.h:62