summaryrefslogtreecommitdiff
path: root/eeschema/libedit.cpp
diff options
context:
space:
mode:
Diffstat (limited to 'eeschema/libedit.cpp')
-rw-r--r--eeschema/libedit.cpp742
1 files changed, 742 insertions, 0 deletions
diff --git a/eeschema/libedit.cpp b/eeschema/libedit.cpp
new file mode 100644
index 0000000..fe2f121
--- /dev/null
+++ b/eeschema/libedit.cpp
@@ -0,0 +1,742 @@
+/*
+ * This program source code file is part of KiCad, a free EDA CAD application.
+ *
+ * Copyright (C) 2015 Jean-Pierre Charras, jp.charras at wanadoo.fr
+ * Copyright (C) 2008-2013 Wayne Stambaugh <stambaughw@verizon.net>
+ * Copyright (C) 2004-2015 KiCad Developers, see change_log.txt for contributors.
+ *
+ * This program is free software; you can redistribute it and/or
+ * modify it under the terms of the GNU General Public License
+ * as published by the Free Software Foundation; either version 2
+ * of the License, or (at your option) any later version.
+ *
+ * This program is distributed in the hope that it will be useful,
+ * but WITHOUT ANY WARRANTY; without even the implied warranty of
+ * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
+ * GNU General Public License for more details.
+ *
+ * You should have received a copy of the GNU General Public License
+ * along with this program; if not, you may find one here:
+ * http://www.gnu.org/licenses/old-licenses/gpl-2.0.html
+ * or you may search the http://www.gnu.org website for the version 2 license,
+ * or you may write to the Free Software Foundation, Inc.,
+ * 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301, USA
+ */
+
+/**
+ * @file libedit.cpp
+ * @brief Eeschema component library editor.
+ */
+
+#include <fctsys.h>
+#include <kiway.h>
+#include <gr_basic.h>
+#include <macros.h>
+#include <pgm_base.h>
+#include <class_drawpanel.h>
+#include <confirm.h>
+#include <gestfich.h>
+#include <class_sch_screen.h>
+
+#include <eeschema_id.h>
+#include <general.h>
+#include <libeditframe.h>
+#include <class_library.h>
+#include <template_fieldnames.h>
+#include <wildcards_and_files_ext.h>
+
+#include <dialogs/dialog_lib_new_component.h>
+
+
+void LIB_EDIT_FRAME::DisplayLibInfos()
+{
+ wxString msg = _( "Part Library Editor: " );
+ PART_LIB* lib = GetCurLib();
+
+ if( lib )
+ {
+ msg += lib->GetFullFileName();
+
+ if( lib->IsReadOnly() )
+ msg += _( " [Read Only]" );
+ }
+ else
+ {
+ msg += _( "no library selected" );
+ }
+
+ SetTitle( msg );
+}
+
+
+void LIB_EDIT_FRAME::SelectActiveLibrary( PART_LIB* aLibrary )
+{
+ if( !aLibrary )
+ aLibrary = SelectLibraryFromList();
+
+ if( aLibrary )
+ {
+ SetCurLib( aLibrary );
+ }
+
+ DisplayLibInfos();
+}
+
+
+bool LIB_EDIT_FRAME::LoadComponentAndSelectLib( LIB_ALIAS* aLibEntry, PART_LIB* aLibrary )
+{
+ if( GetScreen()->IsModify()
+ && !IsOK( this, _( "The current component is not saved.\n\nDiscard current changes?" ) ) )
+ return false;
+
+ SelectActiveLibrary( aLibrary );
+ return LoadComponentFromCurrentLib( aLibEntry );
+}
+
+
+bool LIB_EDIT_FRAME::LoadComponentFromCurrentLib( LIB_ALIAS* aLibEntry )
+{
+ if( !LoadOneLibraryPartAux( aLibEntry, GetCurLib() ) )
+ return false;
+
+ m_editPinsPerPartOrConvert = GetCurPart()->UnitsLocked() ? true : false;
+
+ GetScreen()->ClearUndoRedoList();
+ Zoom_Automatique( false );
+ SetShowDeMorgan( GetCurPart()->HasConversion() );
+
+ return true;
+}
+
+
+void LIB_EDIT_FRAME::LoadOneLibraryPart( wxCommandEvent& event )
+{
+ wxString cmp_name;
+ LIB_ALIAS* libEntry = NULL;
+
+ m_canvas->EndMouseCapture( ID_NO_TOOL_SELECTED, m_canvas->GetDefaultCursor() );
+
+ if( GetScreen()->IsModify()
+ && !IsOK( this, _( "The current component is not saved.\n\nDiscard current changes?" ) ) )
+ return;
+
+ PART_LIB* lib = GetCurLib();
+
+ // No current lib, ask user for the library to use.
+ if( !lib )
+ {
+ SelectActiveLibrary();
+ lib = GetCurLib();
+
+ if( !lib )
+ return;
+ }
+
+ wxArrayString dummyHistoryList;
+ int dummyLastUnit;
+ SCHLIB_FILTER filter;
+ filter.LoadFrom( lib->GetName() );
+ cmp_name = SelectComponentFromLibrary( &filter, dummyHistoryList, dummyLastUnit,
+ true, NULL, NULL );
+
+ if( cmp_name.IsEmpty() )
+ return;
+
+ GetScreen()->ClrModify();
+ m_lastDrawItem = m_drawItem = NULL;
+
+ // Delete previous library component, if any
+ SetCurPart( NULL );
+ m_aliasName.Empty();
+
+ // Load the new library component
+ libEntry = lib->FindEntry( cmp_name );
+ PART_LIB* searchLib = lib;
+
+ if( !libEntry )
+ {
+ // Not found in the active library: search inside the full list
+ // (can happen when using Viewlib to load a component)
+ libEntry = Prj().SchLibs()->FindLibraryEntry( cmp_name );
+
+ if( libEntry )
+ {
+ searchLib = libEntry->GetLib();
+
+ // The entry to load is not in the active lib
+ // Ask for a new active lib
+ wxString msg = _( "The selected component is not in the active library." );
+ msg += wxT("\n\n");
+ msg += _( "Do you want to change the active library?" );
+
+ if( IsOK( this, msg ) )
+ SelectActiveLibrary( searchLib );
+ }
+ }
+
+ if( !libEntry )
+ {
+ wxString msg = wxString::Format( _(
+ "Part name '%s' not found in library '%s'" ),
+ GetChars( cmp_name ),
+ GetChars( searchLib->GetName() )
+ );
+ DisplayError( this, msg );
+ return;
+ }
+
+ PART_LIB* old = SetCurLib( searchLib );
+
+ LoadComponentFromCurrentLib( libEntry );
+
+ SetCurLib( old );
+
+ DisplayLibInfos();
+}
+
+
+bool LIB_EDIT_FRAME::LoadOneLibraryPartAux( LIB_ALIAS* aEntry, PART_LIB* aLibrary )
+{
+ wxString msg, rootName;
+
+ if( !aEntry || !aLibrary )
+ return false;
+
+ if( aEntry->GetName().IsEmpty() )
+ {
+ wxLogWarning( wxT( "Entry in library <%s> has empty name field." ),
+ GetChars( aLibrary->GetName() ) );
+ return false;
+ }
+
+ wxString cmpName = m_aliasName = aEntry->GetName();
+
+ LIB_PART* lib_part = aEntry->GetPart();
+
+ wxASSERT( lib_part );
+
+ wxLogDebug( wxT( "\"<%s>\" is alias of \"<%s>\"" ),
+ GetChars( cmpName ),
+ GetChars( lib_part->GetName() ) );
+
+ LIB_PART* part = new LIB_PART( *lib_part ); // clone it and own it.
+ SetCurPart( part );
+ m_aliasName = aEntry->GetName();
+
+ m_unit = 1;
+ m_convert = 1;
+
+ m_showDeMorgan = false;
+
+ if( part->HasConversion() )
+ m_showDeMorgan = true;
+
+ GetScreen()->ClrModify();
+ DisplayLibInfos();
+ UpdateAliasSelectList();
+ UpdatePartSelectList();
+
+ // Display the document information based on the entry selected just in
+ // case the entry is an alias.
+ DisplayCmpDoc();
+
+ return true;
+}
+
+
+void LIB_EDIT_FRAME::RedrawComponent( wxDC* aDC, wxPoint aOffset )
+{
+ LIB_PART* part = GetCurPart();
+
+ if( part )
+ {
+ // display reference like in schematic (a reference U is shown U? or U?A)
+ // although it is stored without ? and part id.
+ // So temporary change the reference by a schematic like reference
+ LIB_FIELD* field = part->GetField( REFERENCE );
+ wxString fieldText = field->GetText();
+ wxString fieldfullText = field->GetFullText( m_unit );
+
+ field->EDA_TEXT::SetText( fieldfullText ); // change the field text string only
+ part->Draw( m_canvas, aDC, aOffset, m_unit, m_convert, GR_DEFAULT_DRAWMODE );
+ field->EDA_TEXT::SetText( fieldText ); // restore the field text string
+ }
+}
+
+void LIB_EDIT_FRAME::RedrawActiveWindow( wxDC* DC, bool EraseBg )
+{
+ if( GetScreen() == NULL )
+ return;
+
+ m_canvas->DrawBackGround( DC );
+
+ RedrawComponent( DC, wxPoint( 0, 0 ) );
+
+#ifdef USE_WX_OVERLAY
+ if( IsShown() )
+ {
+ m_overlay.Reset();
+ wxDCOverlay overlaydc( m_overlay, (wxWindowDC*)DC );
+ overlaydc.Clear();
+ }
+#endif
+
+ if( m_canvas->IsMouseCaptured() )
+ m_canvas->CallMouseCapture( DC, wxDefaultPosition, false );
+
+ m_canvas->DrawCrossHair( DC );
+
+ DisplayLibInfos();
+ UpdateStatusBar();
+}
+
+
+void LIB_EDIT_FRAME::OnSaveActiveLibrary( wxCommandEvent& event )
+{
+ bool newFile = false;
+ if( event.GetId() == ID_LIBEDIT_SAVE_CURRENT_LIB_AS )
+ newFile = true;
+
+ this->SaveActiveLibrary( newFile );
+}
+
+
+bool LIB_EDIT_FRAME::SaveActiveLibrary( bool newFile )
+{
+ wxFileName fn;
+ wxString msg;
+
+ m_canvas->EndMouseCapture( ID_NO_TOOL_SELECTED, m_canvas->GetDefaultCursor() );
+
+ PART_LIB* lib = GetCurLib();
+
+ if( !lib )
+ {
+ DisplayError( this, _( "No library specified." ) );
+ return false;
+ }
+
+ if( GetScreen()->IsModify() )
+ {
+ if( IsOK( this, _( "Include last component changes?" ) ) )
+ SaveOnePart( lib, false );
+ }
+
+ if( newFile )
+ {
+ PROJECT& prj = Prj();
+ SEARCH_STACK* search = prj.SchSearchS();
+
+ // Get a new name for the library
+ wxString default_path = prj.GetRString( PROJECT::SCH_LIB_PATH );
+
+ if( !default_path )
+ default_path = search->LastVisitedPath();
+
+ wxFileDialog dlg( this, _( "Part Library Name:" ), default_path,
+ wxEmptyString, SchematicLibraryFileWildcard,
+ wxFD_SAVE | wxFD_OVERWRITE_PROMPT );
+
+ if( dlg.ShowModal() == wxID_CANCEL )
+ return false;
+
+ fn = dlg.GetPath();
+
+ // The GTK file chooser doesn't return the file extension added to
+ // file name so add it here.
+ if( fn.GetExt().IsEmpty() )
+ fn.SetExt( SchematicLibraryFileExtension );
+
+ prj.SetRString( PROJECT::SCH_LIB_PATH, fn.GetPath() );
+ }
+ else
+ {
+ fn = wxFileName( lib->GetFullFileName() );
+
+ msg.Printf( _( "Modify library file '%s' ?" ),
+ GetChars( fn.GetFullPath() ) );
+
+ if( !IsOK( this, msg ) )
+ return false;
+ }
+
+ // Verify the user has write privileges before attempting to
+ // save the library file.
+ if( !IsWritable( fn ) )
+ return false;
+
+ ClearMsgPanel();
+
+ wxFileName libFileName = fn;
+ wxFileName backupFileName = fn;
+
+ // Rename the old .lib file to .bak.
+ if( libFileName.FileExists() )
+ {
+ backupFileName.SetExt( wxT( "bak" ) );
+
+ if( backupFileName.FileExists() )
+ wxRemoveFile( backupFileName.GetFullPath() );
+
+ if( !wxRenameFile( libFileName.GetFullPath(), backupFileName.GetFullPath() ) )
+ {
+ libFileName.MakeAbsolute();
+ msg = wxT( "Failed to rename old component library file " ) +
+ backupFileName.GetFullPath();
+ DisplayError( this, msg );
+ }
+ }
+
+ try
+ {
+ FILE_OUTPUTFORMATTER libFormatter( libFileName.GetFullPath() );
+
+ if( !lib->Save( libFormatter ) )
+ {
+ msg.Printf( _( "Error occurred while saving library file '%s'" ),
+ GetChars( fn.GetFullPath() ) );
+ AppendMsgPanel( _( "*** ERROR: ***" ), msg, RED );
+ DisplayError( this, msg );
+ return false;
+ }
+ }
+ catch( ... /* IO_ERROR ioe */ )
+ {
+ libFileName.MakeAbsolute();
+ msg.Printf( _( "Failed to create component library file '%s'" ),
+ GetChars( libFileName.GetFullPath() ) );
+ DisplayError( this, msg );
+ return false;
+ }
+
+ wxFileName docFileName = libFileName;
+
+ docFileName.SetExt( DOC_EXT );
+
+ // Rename .doc file to .bck.
+ if( docFileName.FileExists() )
+ {
+ backupFileName.SetExt( wxT( "bck" ) );
+
+ if( backupFileName.FileExists() )
+ wxRemoveFile( backupFileName.GetFullPath() );
+
+ if( !wxRenameFile( docFileName.GetFullPath(), backupFileName.GetFullPath() ) )
+ {
+ msg = wxT( "Failed to save old library document file " ) +
+ backupFileName.GetFullPath();
+ DisplayError( this, msg );
+ }
+ }
+
+ try
+ {
+ FILE_OUTPUTFORMATTER docFormatter( docFileName.GetFullPath() );
+
+ if( !lib->SaveDocs( docFormatter ) )
+ {
+ msg.Printf( _( "Error occurred while saving library documentation file <%s>" ),
+ GetChars( docFileName.GetFullPath() ) );
+ AppendMsgPanel( _( "*** ERROR: ***" ), msg, RED );
+ DisplayError( this, msg );
+ return false;
+ }
+ }
+ catch( ... /* IO_ERROR ioe */ )
+ {
+ docFileName.MakeAbsolute();
+ msg.Printf( _( "Failed to create component document library file <%s>" ),
+ GetChars( docFileName.GetFullPath() ) );
+ DisplayError( this, msg );
+ return false;
+ }
+
+ msg.Printf( _( "Library file '%s' OK" ), GetChars( fn.GetFullName() ) );
+ fn.SetExt( DOC_EXT );
+ wxString msg1;
+ msg1.Printf( _( "Documentation file '%s' OK" ), GetChars( fn.GetFullPath() ) );
+ AppendMsgPanel( msg, msg1, BLUE );
+
+ return true;
+}
+
+
+void LIB_EDIT_FRAME::DisplayCmpDoc()
+{
+ LIB_ALIAS* alias;
+ PART_LIB* lib = GetCurLib();
+ LIB_PART* part = GetCurPart();
+
+ ClearMsgPanel();
+
+ if( !lib || !part )
+ return;
+
+ wxString msg = part->GetName();
+
+ AppendMsgPanel( _( "Name" ), msg, BLUE, 8 );
+
+ if( m_aliasName == part->GetName() )
+ msg = _( "None" );
+ else
+ msg = m_aliasName;
+
+ alias = part->GetAlias( m_aliasName );
+
+ wxCHECK_RET( alias != NULL, wxT( "Alias not found in component." ) );
+
+ AppendMsgPanel( _( "Alias" ), msg, RED, 8 );
+
+ static wxChar UnitLetter[] = wxT( "?ABCDEFGHIJKLMNOPQRSTUVWXYZ" );
+ msg = UnitLetter[m_unit];
+
+ AppendMsgPanel( _( "Unit" ), msg, BROWN, 8 );
+
+ if( m_convert > 1 )
+ msg = _( "Convert" );
+ else
+ msg = _( "Normal" );
+
+ AppendMsgPanel( _( "Body" ), msg, GREEN, 8 );
+
+ if( part->IsPower() )
+ msg = _( "Power Symbol" );
+ else
+ msg = _( "Part" );
+
+ AppendMsgPanel( _( "Type" ), msg, MAGENTA, 8 );
+ AppendMsgPanel( _( "Description" ), alias->GetDescription(), CYAN, 8 );
+ AppendMsgPanel( _( "Key words" ), alias->GetKeyWords(), DARKDARKGRAY );
+ AppendMsgPanel( _( "Datasheet" ), alias->GetDocFileName(), DARKDARKGRAY );
+}
+
+
+void LIB_EDIT_FRAME::DeleteOnePart( wxCommandEvent& event )
+{
+ wxString cmp_name;
+ LIB_ALIAS* libEntry;
+ wxArrayString nameList;
+ wxString msg;
+
+ m_canvas->EndMouseCapture( ID_NO_TOOL_SELECTED, m_canvas->GetDefaultCursor() );
+
+ m_lastDrawItem = NULL;
+ m_drawItem = NULL;
+
+ PART_LIB* lib = GetCurLib();
+
+ if( !lib )
+ {
+ SelectActiveLibrary();
+
+ lib = GetCurLib();
+ if( !lib )
+ {
+ DisplayError( this, _( "Please select a component library." ) );
+ return;
+ }
+ }
+
+ lib->GetEntryNames( nameList );
+
+ if( nameList.IsEmpty() )
+ {
+ msg.Printf( _( "Part library '%s' is empty." ), GetChars( lib->GetName() ) );
+ wxMessageBox( msg, _( "Delete Entry Error" ), wxID_OK | wxICON_EXCLAMATION, this );
+ return;
+ }
+
+ msg.Printf( _( "Select one of %d components to delete\nfrom library '%s'." ),
+ int( nameList.GetCount() ),
+ GetChars( lib->GetName() ) );
+
+ wxSingleChoiceDialog dlg( this, msg, _( "Delete Part" ), nameList );
+
+ if( dlg.ShowModal() == wxID_CANCEL || dlg.GetStringSelection().IsEmpty() )
+ return;
+
+ libEntry = lib->FindEntry( dlg.GetStringSelection() );
+
+ if( !libEntry )
+ {
+ msg.Printf( _( "Entry '%s' not found in library '%s'." ),
+ GetChars( dlg.GetStringSelection() ),
+ GetChars( lib->GetName() ) );
+ DisplayError( this, msg );
+ return;
+ }
+
+ msg.Printf( _( "Delete component '%s' from library '%s' ?" ),
+ GetChars( libEntry->GetName() ),
+ GetChars( lib->GetName() ) );
+
+ if( !IsOK( this, msg ) )
+ return;
+
+ LIB_PART* part = GetCurPart();
+
+ if( !part || !part->HasAlias( libEntry->GetName() ) )
+ {
+ lib->RemoveEntry( libEntry );
+ return;
+ }
+
+ // If deleting the current entry or removing one of the aliases for
+ // the current entry, sync the changes in the current entry as well.
+
+ if( GetScreen()->IsModify() && !IsOK( this, _(
+ "The component being deleted has been modified."
+ " All changes will be lost. Discard changes?" ) ) )
+ {
+ return;
+ }
+
+ LIB_ALIAS* nextEntry = lib->RemoveEntry( libEntry );
+
+ if( nextEntry != NULL )
+ {
+ if( LoadOneLibraryPartAux( nextEntry, lib ) )
+ Zoom_Automatique( false );
+ }
+ else
+ {
+ SetCurPart( NULL ); // delete CurPart
+ m_aliasName.Empty();
+ }
+
+ m_canvas->Refresh();
+}
+
+
+
+void LIB_EDIT_FRAME::CreateNewLibraryPart( wxCommandEvent& event )
+{
+ wxString name;
+
+ if( GetCurPart() && GetScreen()->IsModify() && !IsOK( this, _(
+ "All changes to the current component will be lost!\n\n"
+ "Clear the current component from the screen?" ) ) )
+ {
+ return;
+ }
+
+ m_canvas->EndMouseCapture( ID_NO_TOOL_SELECTED, m_canvas->GetDefaultCursor() );
+
+ m_drawItem = NULL;
+
+ DIALOG_LIB_NEW_COMPONENT dlg( this );
+
+ dlg.SetMinSize( dlg.GetSize() );
+
+ if( dlg.ShowModal() == wxID_CANCEL )
+ return;
+
+ if( dlg.GetName().IsEmpty() )
+ {
+ wxMessageBox( _( "This new component has no name and cannot be created. Aborted" ) );
+ return;
+ }
+
+ name = dlg.GetName();
+ name.Replace( wxT( " " ), wxT( "_" ) );
+
+ PART_LIB* lib = GetCurLib();
+
+ // Test if there a component with this name already.
+ if( lib && lib->FindEntry( name ) )
+ {
+ wxString msg = wxString::Format( _(
+ "Part '%s' already exists in library '%s'" ),
+ GetChars( name ),
+ GetChars( lib->GetName() )
+ );
+ DisplayError( this, msg );
+ return;
+ }
+
+ LIB_PART* new_part = new LIB_PART( name );
+
+ SetCurPart( new_part );
+ m_aliasName = new_part->GetName();
+
+ new_part->GetReferenceField().SetText( dlg.GetReference() );
+ new_part->SetUnitCount( dlg.GetUnitCount() );
+
+ // Initialize new_part->m_TextInside member:
+ // if 0, pin text is outside the body (on the pin)
+ // if > 0, pin text is inside the body
+ new_part->SetConversion( dlg.GetAlternateBodyStyle() );
+ SetShowDeMorgan( dlg.GetAlternateBodyStyle() );
+
+ if( dlg.GetPinNameInside() )
+ {
+ new_part->SetPinNameOffset( dlg.GetPinTextPosition() );
+
+ if( new_part->GetPinNameOffset() == 0 )
+ new_part->SetPinNameOffset( 1 );
+ }
+ else
+ {
+ new_part->SetPinNameOffset( 0 );
+ }
+
+ ( dlg.GetPowerSymbol() ) ? new_part->SetPower() : new_part->SetNormal();
+ new_part->SetShowPinNumbers( dlg.GetShowPinNumber() );
+ new_part->SetShowPinNames( dlg.GetShowPinName() );
+ new_part->LockUnits( dlg.GetLockItems() );
+
+ if( dlg.GetUnitCount() < 2 )
+ new_part->LockUnits( false );
+
+ m_unit = 1;
+ m_convert = 1;
+
+ DisplayLibInfos();
+ DisplayCmpDoc();
+ UpdateAliasSelectList();
+ UpdatePartSelectList();
+
+ m_editPinsPerPartOrConvert = new_part->UnitsLocked() ? true : false;
+ m_lastDrawItem = NULL;
+
+ GetScreen()->ClearUndoRedoList();
+ OnModify();
+
+ m_canvas->Refresh();
+ m_mainToolBar->Refresh();
+}
+
+
+bool LIB_EDIT_FRAME::SaveOnePart( PART_LIB* aLib, bool aPromptUser )
+{
+ wxString msg;
+ LIB_PART* part = GetCurPart();
+
+ GetScreen()->ClrModify();
+
+ LIB_PART* old_part = aLib->FindPart( part->GetName() );
+
+ if( old_part && aPromptUser )
+ {
+ msg.Printf( _( "Part '%s' already exists. Change it?" ),
+ GetChars( part->GetName() ) );
+
+ if( !IsOK( this, msg ) )
+ return false;
+ }
+
+ m_drawItem = m_lastDrawItem = NULL;
+
+ if( old_part )
+ aLib->ReplacePart( old_part, part );
+ else
+ aLib->AddPart( part );
+
+ msg.Printf( _( "Part '%s' saved in library '%s'" ),
+ GetChars( part->GetName() ),
+ GetChars( aLib->GetName() ) );
+
+ SetStatusText( msg );
+
+ return true;
+}