*) Implement "Copy On Write" (COW) support in GITHUB_PLUGIN. See class header

comment for GITHUB_PLUGIN which should flow into Doxygen output.
*) Rewrote: 
        PCB_BASE_FRAME::Save_Module_In_Library(): now uses fp-lib-table and PROPERTIES.  
        PCB_EDIT_FRAME::ArchiveModulesOnBoard(): now can archive to any writable library type.
        PCB_BASE_FRAME::SelectLibrary(): is now generic for selecting a library, not just the active library.
This commit is contained in:
Dick Hollenbeck 2013-11-27 00:04:04 -06:00
parent 56615d1653
commit b0c739e7ee
21 changed files with 584 additions and 167 deletions

View File

@ -62,10 +62,6 @@ PCBNew
Dick's Final TODO List: Dick's Final TODO List:
====================== ======================
*) Rewrite
PCB_BASE_FRAME::Save_Module_In_Library
PCB_EDIT_FRAME::ArchiveModulesOnBoard
to use FP_LIB_TABLE mechanisms.
*) Apply Fabrizio and Alexander's linux desktop patches after unifying them. *) Apply Fabrizio and Alexander's linux desktop patches after unifying them.
*) Get licensing cleaned up. *) Get licensing cleaned up.
*) Re-arrange the repo architecture. *) Re-arrange the repo architecture.

View File

@ -179,11 +179,27 @@ MODULE* FP_LIB_TABLE::FootprintLoad( const wxString& aNickname, const wxString&
} }
void FP_LIB_TABLE::FootprintSave( const wxString& aNickname, const MODULE* aFootprint ) FP_LIB_TABLE::SAVE_T FP_LIB_TABLE::FootprintSave( const wxString& aNickname, const MODULE* aFootprint, bool aOverwrite )
{ {
const ROW* row = FindRow( aNickname ); const ROW* row = FindRow( aNickname );
wxASSERT( (PLUGIN*) row->plugin ); wxASSERT( (PLUGIN*) row->plugin );
return row->plugin->FootprintSave( row->GetFullURI( true ), aFootprint, row->GetProperties() );
if( !aOverwrite )
{
// Try loading the footprint to see if it already exists, caller wants overwrite
// protection, which is atypical, not the default.
wxString fpname = FROM_UTF8( aFootprint->GetFPID().GetFootprintName().c_str() );
std::auto_ptr<MODULE> m( row->plugin->FootprintLoad( row->GetFullURI( true ), fpname, row->GetProperties() ) );
if( m.get() )
return SAVE_SKIPPED;
}
row->plugin->FootprintSave( row->GetFullURI( true ), aFootprint, row->GetProperties() );
return SAVE_OK;
} }
@ -203,6 +219,22 @@ bool FP_LIB_TABLE::IsFootprintLibWritable( const wxString& aNickname )
} }
void FP_LIB_TABLE::FootprintLibDelete( const wxString& aNickname )
{
const ROW* row = FindRow( aNickname );
wxASSERT( (PLUGIN*) row->plugin );
row->plugin->FootprintLibDelete( row->GetFullURI( true ), row->GetProperties() );
}
void FP_LIB_TABLE::FootprintLibCreate( const wxString& aNickname )
{
const ROW* row = FindRow( aNickname );
wxASSERT( (PLUGIN*) row->plugin );
row->plugin->FootprintLibCreate( row->GetFullURI( true ), row->GetProperties() );
}
const wxString FP_LIB_TABLE::GetDescription( const wxString& aNickname ) const wxString FP_LIB_TABLE::GetDescription( const wxString& aNickname )
{ {
// use "no exception" form of find row: // use "no exception" form of find row:

View File

@ -394,6 +394,16 @@ public:
*/ */
MODULE* FootprintLoad( const wxString& aNickname, const wxString& aFootprintName ); MODULE* FootprintLoad( const wxString& aNickname, const wxString& aFootprintName );
/**
* Enum SAVE_T
* is the set of return values from FootprintSave() below.
*/
enum SAVE_T
{
SAVE_OK,
SAVE_SKIPPED,
};
/** /**
* Function FootprintSave * Function FootprintSave
* will write @a aFootprint to an existing library given by @a aNickname. * will write @a aFootprint to an existing library given by @a aNickname.
@ -405,9 +415,14 @@ public:
* @param aFootprint is what to store in the library. The caller continues * @param aFootprint is what to store in the library. The caller continues
* to own the footprint after this call. * to own the footprint after this call.
* *
* @param aOverwrite when true means overwrite any existing footprint by the
* same name, else if false means skip the write and return SAVE_SKIPPED.
*
* @return SAVE_T - SAVE_OK or SAVE_SKIPPED. If error saving, then IO_ERROR is thrown.
*
* @throw IO_ERROR if there is a problem saving. * @throw IO_ERROR if there is a problem saving.
*/ */
void FootprintSave( const wxString& aNickname, const MODULE* aFootprint ); SAVE_T FootprintSave( const wxString& aNickname, const MODULE* aFootprint, bool aOverwrite = true );
/** /**
* Function FootprintDelete * Function FootprintDelete
@ -431,6 +446,10 @@ public:
*/ */
bool IsFootprintLibWritable( const wxString& aNickname ); bool IsFootprintLibWritable( const wxString& aNickname );
void FootprintLibDelete( const wxString& aNickname );
void FootprintLibCreate( const wxString& aNickname );
//-----</PLUGIN API SUBSET, REBASED ON aNickname>--------------------------- //-----</PLUGIN API SUBSET, REBASED ON aNickname>---------------------------
/** /**

View File

@ -295,7 +295,7 @@ public:
* @param aLibName = name of the library to use * @param aLibName = name of the library to use
* @param aModule = the given footprint * @param aModule = the given footprint
* @param aOverwrite = true to overwrite an existing footprint, false to * @param aOverwrite = true to overwrite an existing footprint, false to
* abort an existing footprint is found * abort if an existing footprint with same name is found
* @param aDisplayDialog = true to display a dialog to enter or confirm the * @param aDisplayDialog = true to display a dialog to enter or confirm the
* footprint name * footprint name
* @return : true if OK, false if abort * @return : true if OK, false if abort
@ -305,6 +305,16 @@ public:
bool aOverwrite, bool aOverwrite,
bool aDisplayDialog ); bool aDisplayDialog );
/**
* Function SelectLibrary
* puts up a dialog and allows the user to pick a library, for unspecified use.
*
* @param aNicknameExisting is the current choice to highlight
*
* @return wxString - the library or wxEmptyString on abort.
*/
wxString SelectLibrary( const wxString& aNicknameExisting );
MODULE* GetModuleByName(); MODULE* GetModuleByName();
/** /**

View File

@ -119,7 +119,7 @@ protected:
void setupTools(); void setupTools();
void destroyTools(); void destroyTools();
void onGenericCommand( wxCommandEvent& aEvent ); void onGenericCommand( wxCommandEvent& aEvent );
// we'll use lower case function names for private member functions. // we'll use lower case function names for private member functions.
void createPopUpMenuForZones( ZONE_CONTAINER* edge_zone, wxMenu* aPopMenu ); void createPopUpMenuForZones( ZONE_CONTAINER* edge_zone, wxMenu* aPopMenu );
@ -906,12 +906,11 @@ public:
/** /**
* Function ArchiveModulesOnBoard * Function ArchiveModulesOnBoard
* Save modules in a library: * Save modules in a library:
* @param aLibName: the full filename of the library to create or modify
* @param aNewModulesOnly: * @param aNewModulesOnly:
* true : save modules not already existing in this lib * true : save modules not already existing in this lib
* false: save all modules * false: save all modules
*/ */
void ArchiveModulesOnBoard( const wxString& aLibName, bool aNewModulesOnly ); void ArchiveModulesOnBoard( bool aNewModulesOnly );
/** /**
* Function RecreateBOMFileFromBoard * Function RecreateBOMFileFromBoard

View File

@ -1106,17 +1106,15 @@ EAGLE_PLUGIN::~EAGLE_PLUGIN()
} }
const wxString& EAGLE_PLUGIN::PluginName() const const wxString EAGLE_PLUGIN::PluginName() const
{ {
static const wxString name = wxT( "Eagle" ); return wxT( "Eagle" );
return name;
} }
const wxString& EAGLE_PLUGIN::GetFileExtension() const const wxString EAGLE_PLUGIN::GetFileExtension() const
{ {
static const wxString extension = wxT( "brd" ); return wxT( "brd" );
return extension;
} }

View File

@ -80,11 +80,11 @@ class EAGLE_PLUGIN : public PLUGIN
public: public:
//-----<PUBLIC PLUGIN API>-------------------------------------------------- //-----<PUBLIC PLUGIN API>--------------------------------------------------
const wxString& PluginName() const; const wxString PluginName() const;
BOARD* Load( const wxString& aFileName, BOARD* aAppendToMe, const PROPERTIES* aProperties = NULL ); BOARD* Load( const wxString& aFileName, BOARD* aAppendToMe, const PROPERTIES* aProperties = NULL );
const wxString& GetFileExtension() const; const wxString GetFileExtension() const;
wxArrayString FootprintEnumerate( const wxString& aLibraryPath, const PROPERTIES* aProperties = NULL); wxArrayString FootprintEnumerate( const wxString& aLibraryPath, const PROPERTIES* aProperties = NULL);

View File

@ -1177,11 +1177,11 @@ void PCB_EDIT_FRAME::Process_Special_Functions( wxCommandEvent& event )
break; break;
case ID_MENU_ARCHIVE_NEW_MODULES: case ID_MENU_ARCHIVE_NEW_MODULES:
ArchiveModulesOnBoard( wxEmptyString, true ); ArchiveModulesOnBoard( true );
break; break;
case ID_MENU_ARCHIVE_ALL_MODULES: case ID_MENU_ARCHIVE_ALL_MODULES:
ArchiveModulesOnBoard( wxEmptyString, false ); ArchiveModulesOnBoard( false );
break; break;
case ID_GEN_IMPORT_DXF_FILE: case ID_GEN_IMPORT_DXF_FILE:

View File

@ -24,22 +24,6 @@
/* /*
This is a pcbnew PLUGIN which supports some of the PLUGIN::Footprint*() functions
in the PLUGIN interface, and could do so by utilizing the version 3 github.com
API documented here:
http://developer.github.com
https://help.github.com/articles/creating-an-access-token-for-command-line-use
but it does not. Rather it simply reads in a zip file of the repo and unzips it
from RAM as needed. Therefore the PLUGIN is read only for accessing
remote pretty libraries. If you want to support writing to the repo, then you
could use the above API.
@todo:
Derive this PLUGIN from KICAD_PLUGIN so we can use its FootprintSave().
Support local footprints if they are present in an optional directory.
Possibly cache the zip file locally. Use HTTP's "have changed" or whatever it is called.
*/ */
@ -76,9 +60,14 @@
#include <github_plugin.h> #include <github_plugin.h>
#include <class_module.h> #include <class_module.h>
#include <macros.h> #include <macros.h>
#include <fp_lib_table.h> // ExpandSubstitutions()
using namespace std; using namespace std;
static const char* PRETTY_DIR = "allow_pretty_writing_to_this_dir";
typedef boost::ptr_map<string, wxZipEntry> MODULE_MAP; typedef boost::ptr_map<string, wxZipEntry> MODULE_MAP;
typedef MODULE_MAP::iterator MODULE_ITER; typedef MODULE_MAP::iterator MODULE_ITER;
typedef MODULE_MAP::const_iterator MODULE_CITER; typedef MODULE_MAP::const_iterator MODULE_CITER;
@ -95,28 +84,27 @@ struct GH_CACHE : public MODULE_MAP
GITHUB_PLUGIN::GITHUB_PLUGIN() : GITHUB_PLUGIN::GITHUB_PLUGIN() :
m_cache( 0 ) PCB_IO(),
m_gh_cache( 0 )
{ {
} }
GITHUB_PLUGIN::~GITHUB_PLUGIN() GITHUB_PLUGIN::~GITHUB_PLUGIN()
{ {
delete m_cache; delete m_gh_cache;
} }
const wxString& GITHUB_PLUGIN::PluginName() const const wxString GITHUB_PLUGIN::PluginName() const
{ {
static wxString name( wxT( "Github" ) ); return wxT( "Github" );
return name;
} }
const wxString& GITHUB_PLUGIN::GetFileExtension() const const wxString GITHUB_PLUGIN::GetFileExtension() const
{ {
static wxString empty_ext; return wxEmptyString;
return empty_ext;
} }
@ -124,12 +112,14 @@ wxArrayString GITHUB_PLUGIN::FootprintEnumerate(
const wxString& aLibraryPath, const PROPERTIES* aProperties ) const wxString& aLibraryPath, const PROPERTIES* aProperties )
{ {
//D(printf("%s: this:%p aLibraryPath:'%s'\n", __func__, this, TO_UTF8(aLibraryPath) );) //D(printf("%s: this:%p aLibraryPath:'%s'\n", __func__, this, TO_UTF8(aLibraryPath) );)
cacheLib( aLibraryPath, aProperties );
cacheLib( aLibraryPath );
wxArrayString ret; wxArrayString ret;
for( MODULE_ITER it = m_cache->begin(); it!=m_cache->end(); ++it ) if( m_pretty_dir.size() )
ret = PCB_IO::FootprintEnumerate( m_pretty_dir );
for( MODULE_ITER it = m_gh_cache->begin(); it!=m_gh_cache->end(); ++it )
{ {
ret.Add( FROM_UTF8( it->first.c_str() ) ); ret.Add( FROM_UTF8( it->first.c_str() ) );
} }
@ -143,13 +133,24 @@ MODULE* GITHUB_PLUGIN::FootprintLoad( const wxString& aLibraryPath,
{ {
// D(printf("%s: this:%p aLibraryPath:'%s'\n", __func__, this, TO_UTF8(aLibraryPath) );) // D(printf("%s: this:%p aLibraryPath:'%s'\n", __func__, this, TO_UTF8(aLibraryPath) );)
cacheLib( aLibraryPath ); // clear or set to valid the variable m_pretty_dir
cacheLib( aLibraryPath, aProperties );
if( m_pretty_dir.size() )
{
// API has FootprintLoad() *not* throwing an exception if footprint not found.
MODULE* local = PCB_IO::FootprintLoad( m_pretty_dir, aFootprintName, aProperties );
if( local )
return local;
}
string fp_name = TO_UTF8( aFootprintName ); string fp_name = TO_UTF8( aFootprintName );
MODULE_CITER it = m_cache->find( fp_name ); MODULE_CITER it = m_gh_cache->find( fp_name );
if( it != m_cache->end() ) // fp_name is present if( it != m_gh_cache->end() ) // fp_name is present
{ {
wxMemoryInputStream mis( &m_zip_image[0], m_zip_image.size() ); wxMemoryInputStream mis( &m_zip_image[0], m_zip_image.size() );
@ -181,7 +182,109 @@ MODULE* GITHUB_PLUGIN::FootprintLoad( const wxString& aLibraryPath,
bool GITHUB_PLUGIN::IsFootprintLibWritable( const wxString& aLibraryPath ) bool GITHUB_PLUGIN::IsFootprintLibWritable( const wxString& aLibraryPath )
{ {
return false; if( m_pretty_dir.size() )
return PCB_IO::IsFootprintLibWritable( m_pretty_dir );
else
return false;
}
void GITHUB_PLUGIN::FootprintSave( const wxString& aLibraryPath,
const MODULE* aFootprint, const PROPERTIES* aProperties )
{
// set m_pretty_dir to either empty or something in aProperties
cacheLib( aLibraryPath, aProperties );
if( GITHUB_PLUGIN::IsFootprintLibWritable( aLibraryPath ) )
{
PCB_IO::FootprintSave( m_pretty_dir, aFootprint, aProperties );
}
else
{
// This typically will not happen if the caller first properly calls
// IsFootprintLibWritable() to determine if calling FootprintSave() is
// even legal, so I spend no time on internationalization here:
string msg = StrPrintf( "Github library\n'%s'\nis only writable if you set option '%s' in Library Tables dialog.",
(const char*) TO_UTF8( aLibraryPath ), PRETTY_DIR );
THROW_IO_ERROR( msg );
}
}
void GITHUB_PLUGIN::FootprintDelete( const wxString& aLibraryPath, const wxString& aFootprintName,
const PROPERTIES* aProperties )
{
// set m_pretty_dir to either empty or something in aProperties
cacheLib( aLibraryPath, aProperties );
if( GITHUB_PLUGIN::IsFootprintLibWritable( aLibraryPath ) )
{
// Does the PCB_IO base class have this footprint?
// We cannot write to github.
wxArrayString pretties = PCB_IO::FootprintEnumerate( m_pretty_dir, aProperties );
if( pretties.Index( aFootprintName ) != wxNOT_FOUND )
{
PCB_IO::FootprintDelete( m_pretty_dir, aFootprintName, aProperties );
}
else
{
wxString msg = wxString::Format(
_( "Footprint\n'%s'\nis not in the writable portion of this Github library\n'%s'" ),
GetChars( aFootprintName ),
GetChars( aLibraryPath )
);
THROW_IO_ERROR( msg );
}
}
else
{
// This typically will not happen if the caller first properly calls
// IsFootprintLibWritable() to determine if calling FootprintSave() is
// even legal, so I spend no time on internationalization here:
string msg = StrPrintf( "Github library\n'%s'\nis only writable if you set option '%s' in Library Tables dialog.",
(const char*) TO_UTF8( aLibraryPath ), PRETTY_DIR );
THROW_IO_ERROR( msg );
}
}
void GITHUB_PLUGIN::FootprintLibCreate( const wxString& aLibraryPath, const PROPERTIES* aProperties )
{
// set m_pretty_dir to either empty or something in aProperties
cacheLib( aLibraryPath, aProperties );
if( m_pretty_dir.size() )
{
PCB_IO::FootprintLibCreate( m_pretty_dir, aProperties );
}
else
{
// THROW_IO_ERROR() @todo
}
}
bool GITHUB_PLUGIN::FootprintLibDelete( const wxString& aLibraryPath, const PROPERTIES* aProperties )
{
// set m_pretty_dir to either empty or something in aProperties
cacheLib( aLibraryPath, aProperties );
if( m_pretty_dir.size() )
{
return PCB_IO::FootprintLibDelete( m_pretty_dir, aProperties );
}
else
{
// THROW_IO_ERROR() @todo
return false;
}
} }
@ -190,32 +293,74 @@ void GITHUB_PLUGIN::FootprintLibOptions( PROPERTIES* aListToAppendTo ) const
// inherit options supported by all PLUGINs. // inherit options supported by all PLUGINs.
PLUGIN::FootprintLibOptions( aListToAppendTo ); PLUGIN::FootprintLibOptions( aListToAppendTo );
(*aListToAppendTo)["allow_pretty_writing_to_this_dir"] = wxString( _( (*aListToAppendTo)[ PRETTY_DIR ] = wxString( _(
"Set this property to a directory where footprints are to be written as pretty " "Set this property to a directory where footprints are to be written as pretty "
"footprints when saving to this library. Anything saved will take precedence over " "footprints when saving to this library. Anything saved will take precedence over "
"footprints by the same name in the github repo. These saved footprints can then " "footprints by the same name in the github repo. These saved footprints can then "
"be sent to the library maintainer as updates. " "be sent to the library maintainer as updates. "
"<p>The directory should have a <b>.pretty</b> file extension because the " "<p>The directory <b>must</b> have a <b>.pretty</b> file extension because the "
"Kicad plugin is used to do the saving.</p>" "format of the save is pretty.</p>"
)).utf8_str(); )).utf8_str();
/*
(*aListToAppendTo)["cache_github_zip_in_this_dir"] = wxString( _( (*aListToAppendTo)["cache_github_zip_in_this_dir"] = wxString( _(
"Set this property to a directory where the github *.zip file will be cached. " "Set this property to a directory where the github *.zip file will be cached. "
"This should speed up subsequent visits to this library." "This should speed up subsequent visits to this library."
)).utf8_str(); )).utf8_str();
*/
} }
void GITHUB_PLUGIN::cacheLib( const wxString& aLibraryPath ) throw( IO_ERROR ) void GITHUB_PLUGIN::cacheLib( const wxString& aLibraryPath, const PROPERTIES* aProperties ) throw( IO_ERROR )
{ {
if( !m_cache || m_lib_path != aLibraryPath ) // This is edge triggered based on a change in 'aLibraryPath',
// usually it does nothing. When the edge fires, m_pretty_dir is set
// to either:
// 1) empty or
// 2) a verified and validated, writable, *.pretty directory.
if( !m_gh_cache || m_lib_path != aLibraryPath )
{ {
delete m_gh_cache;
m_gh_cache = 0;
m_pretty_dir.clear();
if( aProperties )
{
string pretty_dir;
if( aProperties->Value( PRETTY_DIR, &pretty_dir ) )
{
wxString wx_pretty_dir = FROM_UTF8( pretty_dir.c_str() );
wx_pretty_dir = FP_LIB_TABLE::ExpandSubstitutions( wx_pretty_dir );
wxFileName wx_pretty_fn = wx_pretty_dir;
if( !wx_pretty_fn.IsOk() ||
!wx_pretty_fn.IsDirWritable() ||
wx_pretty_fn.GetExt() != wxT( "pretty" )
)
{
wxString msg = wxString::Format(
_( "option '%s' for Github library '%s' must point to a writable directory ending with '.pretty'." ),
GetChars( FROM_UTF8( PRETTY_DIR ) ),
GetChars( aLibraryPath )
);
THROW_IO_ERROR( msg );
}
m_pretty_dir = wx_pretty_dir;
}
}
// operator==( wxString, wxChar* ) does not exist, construct wxString once here. // operator==( wxString, wxChar* ) does not exist, construct wxString once here.
const wxString kicad_mod( wxT( "kicad_mod" ) ); const wxString kicad_mod( wxT( "kicad_mod" ) );
//D(printf("%s: this:%p m_lib_path:'%s' aLibraryPath:'%s'\n", __func__, this, TO_UTF8( m_lib_path), TO_UTF8(aLibraryPath) );) //D(printf("%s: this:%p m_lib_path:'%s' aLibraryPath:'%s'\n", __func__, this, TO_UTF8( m_lib_path), TO_UTF8(aLibraryPath) );)
delete m_cache; m_gh_cache = new GH_CACHE();
m_cache = new GH_CACHE();
// INIT_LOGGER( "/tmp", "test.log" ); // INIT_LOGGER( "/tmp", "test.log" );
remote_get_zip( aLibraryPath ); remote_get_zip( aLibraryPath );
@ -238,7 +383,7 @@ void GITHUB_PLUGIN::cacheLib( const wxString& aLibraryPath ) throw( IO_ERROR )
{ {
string fp_name = TO_UTF8( fn.GetName() ); // omit extension & path string fp_name = TO_UTF8( fn.GetName() ); // omit extension & path
m_cache->insert( fp_name, entry ); m_gh_cache->insert( fp_name, entry );
} }
else else
delete entry; delete entry;

View File

@ -25,6 +25,7 @@
#ifndef GITHUB_PLUGIN_H_ #ifndef GITHUB_PLUGIN_H_
#define GITHUB_PLUGIN_H_ #define GITHUB_PLUGIN_H_
#include <kicad_plugin.h>
struct GH_CACHE; struct GH_CACHE;
@ -32,38 +33,98 @@ struct GH_CACHE;
/** /**
* Class GITHUB_PLUGIN * Class GITHUB_PLUGIN
* implements a portion of pcbnew PLUGIN to provide read only access to a github * implements a portion of pcbnew PLUGIN to provide read only access to a github
* repo consisting of pretty footprints * repo consisting of pretty footprints. It could have used version 3 of the
github.com API documented here:
<code>
http://developer.github.com
https://help.github.com/articles/creating-an-access-token-for-command-line-use
</code>
but it does not. Rather it simply reads in a zip file of the repo and unzips it
from RAM as needed. Therefore the PLUGIN is read only for accessing
remote pretty libraries. The "Library Path" in the fp-lib-table should be set
to the full https:// URL. For example:
<code>
https://github.com/liftoff-sr/pretty_footprints
</code>
This is typically https://github.com/user_name/repo_name
<p>
This PLUGIN also supports "Copy On Write", a.k.a "COW". So a library defined
in the fp-lib-table will take an optional option called
<b>allow_pretty_writing_to_this_dir</b> which is essentially the lib_path for
a local Kicad (pretty) library which is combined to make up the Github library.
If the option is missing, then the Github library is read only. If it is present,
then any writes will go to the local *.pretty directory. Any reads will always
give precedence to the local footprints. So once you have written to the local
directory, no github updates will travel down on any footprints for which you've
written locally. Always keep a separate local *.pretty directory for each Github
library, never combine them you will likely create a mess. You must manually
create the local directory in advance, and the directory name must end with ".pretty".
The option <b>allow_pretty_writing_to_this_dir</b> will be path substituted with
any environment variable strings embedded in the option's value, just like the
"Library Path" is.
<p>
What's the point of COW? It is to turbo charge the sharing of footprints. If you
periodically email your COW pretty footprints to the Github repo maintainer,
you can help update the Github copy. The idea should be to keep the COW file
set as small as possible. After you've received confirmation that your changes
have been committed up at github.com, you can safely delete your COW file(s)
and those from github.com will flow down.
<p>
Note that if you use the module editor to delete a footprint and it is present
in the COW local dir, it will get deleted from there. However, it may not
be deleted from the library as a whole if the footprint of the same name also
existed in the github repo. In this case deleting the local copy will simply
unmask the one at the github repo. Remember, it is masked out if there is
a local COW copy, since the local copy always takes precedence.
* *
* @author Dick Hollenbeck * @author Dick Hollenbeck
* @date Original date: 10-Sep-2013 * @date Original date: 10-Sep-2013
*/ */
class GITHUB_PLUGIN : public PLUGIN class GITHUB_PLUGIN : public PCB_IO
{ {
public: public:
//-----<PLUGIN API>---------------------------------------------------------- //-----<PLUGIN API>----------------------------------------------------------
// ("read-only" subset) const wxString PluginName() const;
const wxString& PluginName() const; const wxString GetFileExtension() const;
const wxString& GetFileExtension() const; wxArrayString FootprintEnumerate( const wxString& aLibraryPath,
const PROPERTIES* aProperties = NULL );
wxArrayString FootprintEnumerate( const wxString& aLibraryPath, const PROPERTIES* aProperties );
MODULE* FootprintLoad( const wxString& aLibraryPath, MODULE* FootprintLoad( const wxString& aLibraryPath,
const wxString& aFootprintName, const PROPERTIES* aProperties ); const wxString& aFootprintName, const PROPERTIES* aProperties );
void FootprintSave( const wxString& aLibraryPath, const MODULE* aFootprint,
const PROPERTIES* aProperties = NULL );
void FootprintDelete( const wxString& aLibraryPath, const wxString& aFootprintName,
const PROPERTIES* aProperties = NULL );
bool IsFootprintLibWritable( const wxString& aLibraryPath ); bool IsFootprintLibWritable( const wxString& aLibraryPath );
void FootprintLibOptions( PROPERTIES* aListToAppendTo ) const; void FootprintLibOptions( PROPERTIES* aListToAppendTo ) const;
// Since I derive from PCB_IO, I have to implement this, else I'd inherit his, which is bad since
// my lib_path is not his. Note: it is impossible to create a Github library, but can the C.O.W. portion.
void FootprintLibCreate( const wxString& aLibraryPath, const PROPERTIES* aProperties );
// Since I derive from PCB_IO, I have to implement this, else I'd inherit his, which is bad since
// my lib_path is not his. Note: it is impossible to delete a Github library, but can the C.O.W portion.
bool FootprintLibDelete( const wxString& aLibraryPath, const PROPERTIES* aProperties );
//-----</PLUGIN API>--------------------------------------------------------- //-----</PLUGIN API>---------------------------------------------------------
GITHUB_PLUGIN(); // constructor, if any, must be zero arg GITHUB_PLUGIN(); // constructor, if any, must be zero arg
~GITHUB_PLUGIN(); ~GITHUB_PLUGIN();
private: protected:
void cacheLib( const wxString& aLibraryPath ) throw( IO_ERROR ); void init( const PROPERTIES* aProperties );
void cacheLib( const wxString& aLibraryPath, const PROPERTIES* aProperties ) throw( IO_ERROR );
/** /**
* Function repoURL_zipURL * Function repoURL_zipURL
@ -84,7 +145,9 @@ private:
wxString m_lib_path; ///< from aLibraryPath, something like https://github.com/liftoff-sr/pretty_footprints wxString m_lib_path; ///< from aLibraryPath, something like https://github.com/liftoff-sr/pretty_footprints
std::string m_zip_image; ///< byte image of the zip file in its entirety. std::string m_zip_image; ///< byte image of the zip file in its entirety.
GH_CACHE* m_cache; GH_CACHE* m_gh_cache;
wxString m_pretty_dir;
}; };
#endif // GITHUB_PLUGIN_H_ #endif // GITHUB_PLUGIN_H_

View File

@ -52,16 +52,14 @@ public:
//-----<PLUGIN API>--------------------------------------------------------- //-----<PLUGIN API>---------------------------------------------------------
const wxString& PluginName() const const wxString PluginName() const
{ {
static const wxString name = wxT( "Geda PCB" ); return wxT( "Geda PCB" );
return name;
} }
const wxString& GetFileExtension() const const wxString GetFileExtension() const
{ {
static const wxString extension = wxT( "fp" ); return wxT( "fp" );
return extension;
} }
wxArrayString FootprintEnumerate( const wxString& aLibraryPath, const PROPERTIES* aProperties = NULL); wxArrayString FootprintEnumerate( const wxString& aLibraryPath, const PROPERTIES* aProperties = NULL);

View File

@ -220,13 +220,13 @@ public:
* Function PluginName * Function PluginName
* returns a brief hard coded name for this PLUGIN. * returns a brief hard coded name for this PLUGIN.
*/ */
virtual const wxString& PluginName() const = 0; virtual const wxString PluginName() const = 0;
/** /**
* Function GetFileExtension * Function GetFileExtension
* returns the file extension for the PLUGIN. * returns the file extension for the PLUGIN.
*/ */
virtual const wxString& GetFileExtension() const = 0; virtual const wxString GetFileExtension() const = 0;
/** /**
* Function Load * Function Load

View File

@ -85,7 +85,10 @@ public:
wxString GetName() const { return m_file_name.GetDirs().Last(); } wxString GetName() const { return m_file_name.GetDirs().Last(); }
wxFileName GetFileName() const { return m_file_name; } wxFileName GetFileName() const { return m_file_name; }
/// Tell if the disk content or the lib_path has changed.
bool IsModified() const; bool IsModified() const;
MODULE* GetModule() const { return m_module.get(); } MODULE* GetModule() const { return m_module.get(); }
void UpdateModificationTime() { m_mod_time = m_file_name.GetModificationTime(); } void UpdateModificationTime() { m_mod_time = m_file_name.GetModificationTime(); }
}; };
@ -339,6 +342,7 @@ bool FP_CACHE::IsModified( const wxString& aLibPath, const wxString& aFootprintN
for( MODULE_CITER it = m_modules.begin(); it != m_modules.end(); ++it ) for( MODULE_CITER it = m_modules.begin(); it != m_modules.end(); ++it )
{ {
wxFileName fn = m_lib_path; wxFileName fn = m_lib_path;
fn.SetName( it->second->GetFileName().GetName() ); fn.SetName( it->second->GetFileName().GetName() );
fn.SetExt( KiCadFootprintFileExtension ); fn.SetExt( KiCadFootprintFileExtension );
@ -1804,7 +1808,7 @@ void PCB_IO::FootprintDelete( const wxString& aLibraryPath, const wxString& aFoo
{ {
LOCALE_IO toggle; // toggles on, then off, the C locale. LOCALE_IO toggle; // toggles on, then off, the C locale.
init( NULL ); init( aProperties );
cacheLib( aLibraryPath ); cacheLib( aLibraryPath );

View File

@ -83,20 +83,18 @@ public:
//-----<PLUGIN API>--------------------------------------------------------- //-----<PLUGIN API>---------------------------------------------------------
const wxString& PluginName() const const wxString PluginName() const
{ {
static const wxString name = wxT( "KiCad" ); return wxT( "KiCad" );
return name;
} }
const wxString& GetFileExtension() const const wxString GetFileExtension() const
{ {
// Would have used wildcards_and_files_ext.cpp's KiCadPcbFileExtension, // Would have used wildcards_and_files_ext.cpp's KiCadPcbFileExtension,
// but to be pure, a plugin should not assume that it will always be linked // but to be pure, a plugin should not assume that it will always be linked
// with the core of the pcbnew code. (Might someday be a DLL/DSO.) Besides, // with the core of the pcbnew code. (Might someday be a DLL/DSO.) Besides,
// file extension policy should be controlled by the plugin. // file extension policy should be controlled by the plugin.
static const wxString extension = wxT( "kicad_pcb" ); return wxT( "kicad_pcb" );
return extension;
} }
void Save( const wxString& aFileName, BOARD* aBoard, void Save( const wxString& aFileName, BOARD* aBoard,
@ -172,6 +170,10 @@ protected:
int m_ctl; int m_ctl;
PCB_PARSER* m_parser; PCB_PARSER* m_parser;
/// we only cache one footprint library, this determines which one.
void cacheLib( const wxString& aLibraryPath, const wxString& aFootprintName = wxEmptyString );
void init( const PROPERTIES* aProperties );
private: private:
void format( BOARD* aBoard, int aNestLevel = 0 ) const void format( BOARD* aBoard, int aNestLevel = 0 ) const
@ -211,11 +213,6 @@ private:
void formatLayers( LAYER_MSK aLayerMask, int aNestLevel = 0 ) const void formatLayers( LAYER_MSK aLayerMask, int aNestLevel = 0 ) const
throw( IO_ERROR ); throw( IO_ERROR );
/// we only cache one footprint library for now, this determines which one.
void cacheLib( const wxString& aLibraryPath, const wxString& aFootprintName = wxEmptyString );
void init( const PROPERTIES* aProperties );
}; };
#endif // KICAD_PLUGIN_H_ #endif // KICAD_PLUGIN_H_

View File

@ -64,16 +64,14 @@ public:
//-----<PLUGIN IMPLEMENTATION>---------------------------------------------- //-----<PLUGIN IMPLEMENTATION>----------------------------------------------
const wxString& PluginName() const const wxString PluginName() const
{ {
static const wxString name = wxT( "KiCad-Legacy" ); return wxT( "KiCad-Legacy" );
return name;
} }
const wxString& GetFileExtension() const const wxString GetFileExtension() const
{ {
static const wxString extension = wxT( "brd" ); return wxT( "brd" );
return extension;
} }
BOARD* Load( const wxString& aFileName, BOARD* aAppendToMe, const PROPERTIES* aProperties = NULL ); BOARD* Load( const wxString& aFileName, BOARD* aAppendToMe, const PROPERTIES* aProperties = NULL );

View File

@ -53,29 +53,29 @@
// unique, "file local" translations: // unique, "file local" translations:
#define FMT_OK_OVERWRITE _( "Library <%s> exists, OK to replace ?" ) #define FMT_OK_OVERWRITE _( "Library '%s' exists, OK to replace ?" )
#define FMT_CREATE_LIB _( "Create New Library" ) #define FMT_CREATE_LIB _( "Create New Library" )
#define FMT_OK_DELETE _( "OK to delete module %s in library <%s>" ) #define FMT_OK_DELETE _( "OK to delete module %s in library '%s'" )
#define FMT_IMPORT_MODULE _( "Import Footprint Module" ) #define FMT_IMPORT_MODULE _( "Import Footprint Module" )
#define FMT_FILE_NOT_FOUND _( "File <%s> not found" ) #define FMT_FILE_NOT_FOUND _( "File '%s' not found" )
#define FMT_NOT_MODULE _( "Not a module file" ) #define FMT_NOT_MODULE _( "Not a module file" )
#define FMT_MOD_NOT_FOUND _( "Unable to find or load footprint %s from lib path <%s>" ) #define FMT_MOD_NOT_FOUND _( "Unable to find or load footprint %s from lib path '%s'" )
#define FMT_BAD_PATH _( "Unable to find or load footprint from path <%s>" ) #define FMT_BAD_PATH _( "Unable to find or load footprint from path '%s'" )
#define FMT_BAD_PATHS _( "The footprint library <%s> could not be found in any of the search paths." ) #define FMT_BAD_PATHS _( "The footprint library '%s' could not be found in any of the search paths." )
#define FMT_LIB_READ_ONLY _( "Library <%s> is read only, not writable" ) #define FMT_LIB_READ_ONLY _( "Library '%s' is read only, not writable" )
#define FMT_EXPORT_MODULE _( "Export Module" ) #define FMT_EXPORT_MODULE _( "Export Module" )
#define FMT_SAVE_MODULE _( "Save Module" ) #define FMT_SAVE_MODULE _( "Save Module" )
#define FMT_MOD_REF _( "Module Reference:" ) #define FMT_MOD_REF _( "Module Reference:" )
#define FMT_EXPORTED _( "Module exported to file <%s>" ) #define FMT_EXPORTED _( "Module exported to file '%s'" )
#define FMT_MOD_DELETED _( "Module %s deleted from library <%s>" ) #define FMT_MOD_DELETED _( "Module %s deleted from library '%s'" )
#define FMT_MOD_CREATE _( "Module Creation" ) #define FMT_MOD_CREATE _( "Module Creation" )
#define FMT_NO_MODULES _( "No modules to archive!" ) #define FMT_NO_MODULES _( "No modules to archive!" )
#define FMT_LIBRARY _( "Library" ) // window title #define FMT_LIBRARY _( "Library" ) // window title
#define FMT_MOD_EXISTS _( "Module %s already exists in library <%s>" ) #define FMT_MOD_EXISTS _( "Module %s already exists in library '%s'" )
#define FMT_NO_REF_ABORTED _( "No reference, aborted" ) #define FMT_NO_REF_ABORTED _( "No reference, aborted" )
#define FMT_SELECT_LIB _( "Select Active Library" ) #define FMT_SELECT_LIB _( "Select Library" )
static const wxString ModExportFileWildcard( _( "KiCad foot print export files (*.emp)|*.emp" ) ); static const wxString ModExportFileWildcard( _( "KiCad foot print export files (*.emp)|*.emp" ) );
@ -463,6 +463,53 @@ wxString FOOTPRINT_EDIT_FRAME::CreateNewLibrary()
bool FOOTPRINT_EDIT_FRAME::DeleteModuleFromCurrentLibrary() bool FOOTPRINT_EDIT_FRAME::DeleteModuleFromCurrentLibrary()
{ {
#if defined(USE_FP_LIB_TABLE)
wxString nickname = getLibNickName();
if( !m_footprintLibTable->IsFootprintLibWritable( nickname ) )
{
wxString msg = wxString::Format(
_( "Library '%s' is read only" ),
GetChars( nickname )
);
DisplayError( this, msg );
return false;
}
wxString fpid_txt = PCB_BASE_FRAME::SelectFootprint( this, nickname,
wxEmptyString, wxEmptyString, m_footprintLibTable );
if( !fpid_txt )
return false;
FPID fpid( fpid_txt );
wxString fpname = FROM_UTF8( fpid.GetFootprintName().c_str() );
// Confirmation
wxString msg = wxString::Format( FMT_OK_DELETE, fpname.GetData(), nickname.GetData() );
if( !IsOK( this, msg ) )
return false;
try
{
m_footprintLibTable->FootprintDelete( nickname, fpname );
}
catch( IO_ERROR ioe )
{
DisplayError( this, ioe.errorText );
return false;
}
msg.Printf( FMT_MOD_DELETED, fpname.GetData(), nickname.GetData() );
SetStatusText( msg );
return true;
#else
PCB_EDIT_FRAME* parent = (PCB_EDIT_FRAME*) GetParent(); PCB_EDIT_FRAME* parent = (PCB_EDIT_FRAME*) GetParent();
wxString libPath = getLibPath(); wxString libPath = getLibPath();
wxString footprintName = PCB_BASE_FRAME::SelectFootprint( this, libPath, wxString footprintName = PCB_BASE_FRAME::SelectFootprint( this, libPath,
@ -497,17 +544,73 @@ bool FOOTPRINT_EDIT_FRAME::DeleteModuleFromCurrentLibrary()
SetStatusText( msg ); SetStatusText( msg );
return true; return true;
#endif
} }
/* Save modules in a library: #if defined(USE_FP_LIB_TABLE)
* param aNewModulesOnly: void PCB_EDIT_FRAME::ArchiveModulesOnBoard( bool aNewModulesOnly )
* true : save modules not already existing in this lib
* false: save all modules
*/
void PCB_EDIT_FRAME::ArchiveModulesOnBoard( const wxString& aLibName, bool aNewModulesOnly )
{ {
wxString fileName = aLibName; if( GetBoard()->m_Modules == NULL )
{
DisplayInfoMessage( this, FMT_NO_MODULES );
return;
}
wxString last_nickname = wxGetApp().ReturnLastVisitedLibraryPath();
wxString nickname = SelectLibrary( last_nickname );
if( !nickname )
return;
wxGetApp().SaveLastVisitedLibraryPath( nickname );
if( !aNewModulesOnly )
{
wxString msg = wxString::Format( FMT_OK_OVERWRITE, GetChars( nickname ) );
if( !IsOK( this, msg ) )
return;
}
m_canvas->SetAbortRequest( false );
try
{
// Delete old library if we're replacing it entirely.
if( !aNewModulesOnly )
{
m_footprintLibTable->FootprintLibDelete( nickname );
m_footprintLibTable->FootprintLibCreate( nickname );
for( MODULE* m = GetBoard()->m_Modules; m; m = m->Next() )
{
m_footprintLibTable->FootprintSave( nickname, m, true );
}
}
else
{
for( MODULE* m = GetBoard()->m_Modules; m; m = m->Next() )
{
m_footprintLibTable->FootprintSave( nickname, m, false );
// Check for request to stop backup (ESCAPE key actuated)
if( m_canvas->GetAbortRequest() )
break;
}
}
}
catch( IO_ERROR ioe )
{
DisplayError( this, ioe.errorText );
}
}
#else
void PCB_EDIT_FRAME::ArchiveModulesOnBoard( bool aNewModulesOnly )
{
wxString fileName;
wxString path; wxString path;
if( GetBoard()->m_Modules == NULL ) if( GetBoard()->m_Modules == NULL )
@ -518,7 +621,6 @@ void PCB_EDIT_FRAME::ArchiveModulesOnBoard( const wxString& aLibName, bool aNewM
path = wxGetApp().ReturnLastVisitedLibraryPath(); path = wxGetApp().ReturnLastVisitedLibraryPath();
if( !aLibName )
{ {
wxFileDialog dlg( this, FMT_LIBRARY, path, wxFileDialog dlg( this, FMT_LIBRARY, path,
wxEmptyString, wxEmptyString,
@ -532,7 +634,9 @@ void PCB_EDIT_FRAME::ArchiveModulesOnBoard( const wxString& aLibName, bool aNewM
} }
wxFileName fn( fileName ); wxFileName fn( fileName );
wxGetApp().SaveLastVisitedLibraryPath( fn.GetPath() ); wxGetApp().SaveLastVisitedLibraryPath( fn.GetPath() );
bool lib_exists = wxFileExists( fileName ); bool lib_exists = wxFileExists( fileName );
if( !aNewModulesOnly && lib_exists ) if( !aNewModulesOnly && lib_exists )
@ -584,12 +688,12 @@ void PCB_EDIT_FRAME::ArchiveModulesOnBoard( const wxString& aLibName, bool aNewM
catch( IO_ERROR ioe ) catch( IO_ERROR ioe )
{ {
DisplayError( this, ioe.errorText ); DisplayError( this, ioe.errorText );
return;
} }
} }
#endif
bool PCB_BASE_FRAME::Save_Module_In_Library( const wxString& aLibPath, bool PCB_BASE_FRAME::Save_Module_In_Library( const wxString& aLibrary,
MODULE* aModule, MODULE* aModule,
bool aOverwrite, bool aOverwrite,
bool aDisplayDialog ) bool aDisplayDialog )
@ -618,10 +722,10 @@ bool PCB_BASE_FRAME::Save_Module_In_Library( const wxString& aLibPath,
if( ! MODULE::IsLibNameValid( footprintName ) ) if( ! MODULE::IsLibNameValid( footprintName ) )
{ {
wxString msg; wxString msg = wxString::Format(
msg.Printf( _("Error:\none of invalid chars '%s' found\nin '%s'" ), _("Error:\none of invalid chars '%s' found\nin '%s'" ),
MODULE::ReturnStringLibNameInvalidChars( true ), MODULE::ReturnStringLibNameInvalidChars( true ),
GetChars( footprintName ) ); GetChars( footprintName ) );
DisplayError( NULL, msg ); DisplayError( NULL, msg );
return false; return false;
@ -637,25 +741,24 @@ bool PCB_BASE_FRAME::Save_Module_In_Library( const wxString& aLibPath,
aModule->SetFPID( footprintName ); aModule->SetFPID( footprintName );
} }
IO_MGR::PCB_FILE_T pluginType = IO_MGR::GuessPluginTypeFromLibPath( aLibPath ); bool module_exists = false;
MODULE* module_exists = NULL;
#if defined(USE_FP_LIB_TABLE)
try try
{ {
PLUGIN::RELEASER pi( IO_MGR::PluginFind( pluginType ) ); MODULE* m = m_footprintLibTable->FootprintLoad( aLibrary, footprintName );
module_exists = pi->FootprintLoad( aLibPath, footprintName ); if( m )
if( module_exists )
{ {
delete module_exists; delete m;
module_exists = true;
// an existing footprint is found in current lib // an existing footprint is found in current lib
if( aDisplayDialog ) if( aDisplayDialog )
{ {
wxString msg = wxString::Format( FMT_MOD_EXISTS, wxString msg = wxString::Format( FMT_MOD_EXISTS,
footprintName.GetData(), aLibPath.GetData() ); footprintName.GetData(), aLibrary.GetData() );
SetStatusText( msg ); SetStatusText( msg );
} }
@ -669,7 +772,46 @@ bool PCB_BASE_FRAME::Save_Module_In_Library( const wxString& aLibPath,
// this always overwrites any existing footprint, but should yell on its // this always overwrites any existing footprint, but should yell on its
// own if the library or footprint is not writable. // own if the library or footprint is not writable.
pi->FootprintSave( aLibPath, aModule ); m_footprintLibTable->FootprintSave( aLibrary, aModule );
#else
IO_MGR::PCB_FILE_T pluginType = IO_MGR::GuessPluginTypeFromLibPath( aLibrary );
try
{
PLUGIN::RELEASER pi( IO_MGR::PluginFind( pluginType ) );
MODULE* m = pi->FootprintLoad( aLibrary, footprintName );
if( m )
{
delete m;
module_exists = true;
// an existing footprint is found in current lib
if( aDisplayDialog )
{
wxString msg = wxString::Format( FMT_MOD_EXISTS,
footprintName.GetData(), aLibrary.GetData() );
SetStatusText( msg );
}
if( !aOverwrite )
{
// Do not save the given footprint: an old one exists
return true;
}
}
// this always overwrites any existing footprint, but should yell on its
// own if the library or footprint is not writable.
pi->FootprintSave( aLibrary, aModule );
#endif
} }
catch( IO_ERROR ioe ) catch( IO_ERROR ioe )
{ {
@ -680,10 +822,10 @@ bool PCB_BASE_FRAME::Save_Module_In_Library( const wxString& aLibPath,
if( aDisplayDialog ) if( aDisplayDialog )
{ {
wxString fmt = module_exists ? wxString fmt = module_exists ?
_( "Component [%s] replaced in <%s>" ) : _( "Component [%s] replaced in '%s'" ) :
_( "Component [%s] added in <%s>" ); _( "Component [%s] added in '%s'" );
wxString msg = wxString::Format( fmt, footprintName.GetData(), aLibPath.GetData() ); wxString msg = wxString::Format( fmt, footprintName.GetData(), aLibrary.GetData() );
SetStatusText( msg ); SetStatusText( msg );
} }
@ -750,10 +892,10 @@ MODULE* PCB_BASE_FRAME::Create_1_Module( const wxString& aModuleName )
#if !defined( USE_FP_LIB_TABLE ) #if !defined( USE_FP_LIB_TABLE )
void FOOTPRINT_EDIT_FRAME::Select_Active_Library() wxString PCB_BASE_FRAME::SelectLibrary( const wxString& aNicknameExisting )
{ {
if( g_LibraryNames.GetCount() == 0 ) if( g_LibraryNames.GetCount() == 0 )
return; return wxEmptyString;
wxArrayString headers; wxArrayString headers;
headers.Add( _( "Library" ) ); headers.Add( _( "Library" ) );
@ -768,37 +910,31 @@ void FOOTPRINT_EDIT_FRAME::Select_Active_Library()
itemsToDisplay.push_back( item ); itemsToDisplay.push_back( item );
} }
EDA_LIST_DIALOG dlg( this, FMT_SELECT_LIB, headers, itemsToDisplay, getLibNickName() ); EDA_LIST_DIALOG dlg( this, FMT_SELECT_LIB, headers, itemsToDisplay, aNicknameExisting );
if( dlg.ShowModal() != wxID_OK ) if( dlg.ShowModal() != wxID_OK )
return; return wxEmptyString;
wxFileName fileName = wxFileName( wxEmptyString, dlg.GetTextSelection(), wxFileName fileName = wxFileName( wxEmptyString, dlg.GetTextSelection(),
LegacyFootprintLibPathExtension ); LegacyFootprintLibPathExtension );
fileName = wxGetApp().FindLibraryPath( fileName ); fileName = wxGetApp().FindLibraryPath( fileName );
if( fileName.IsOk() && fileName.FileExists() ) if( !fileName.IsOk() || !fileName.FileExists() )
{
setLibNickName( fileName.GetName() );
setLibPath( fileName.GetFullPath() );
}
else
{ {
wxString msg = wxString::Format( FMT_BAD_PATHS, GetChars( dlg.GetTextSelection() ) ); wxString msg = wxString::Format( FMT_BAD_PATHS, GetChars( dlg.GetTextSelection() ) );
DisplayError( this, msg ); DisplayError( this, msg );
setLibNickName( wxEmptyString ); return wxEmptyString;
setLibPath( wxEmptyString );
} }
updateTitle(); return fileName.GetFullPath();
} }
#else #else
void FOOTPRINT_EDIT_FRAME::Select_Active_Library() wxString PCB_BASE_FRAME::SelectLibrary( const wxString& aNicknameExisting )
{ {
wxArrayString headers; wxArrayString headers;
@ -818,18 +954,16 @@ void FOOTPRINT_EDIT_FRAME::Select_Active_Library()
itemsToDisplay.push_back( item ); itemsToDisplay.push_back( item );
} }
EDA_LIST_DIALOG dlg( this, FMT_SELECT_LIB, headers, itemsToDisplay, getLibNickName() ); EDA_LIST_DIALOG dlg( this, FMT_SELECT_LIB, headers, itemsToDisplay, aNicknameExisting );
if( dlg.ShowModal() != wxID_OK ) if( dlg.ShowModal() != wxID_OK )
return; return wxEmptyString;
wxString nickname = dlg.GetTextSelection(); wxString nickname = dlg.GetTextSelection();
setLibNickName( nickname ); wxLogDebug( wxT( "Chose footprint library '%s'." ), GetChars( nickname ) );
wxLogDebug( wxT( "Chose footprint library <%s>." ), GetChars( nickname ) ); return nickname;
updateTitle();
} }
#endif #endif

View File

@ -249,7 +249,22 @@ void FOOTPRINT_EDIT_FRAME::Process_Special_Functions( wxCommandEvent& event )
break; break;
case ID_MODEDIT_SELECT_CURRENT_LIB: case ID_MODEDIT_SELECT_CURRENT_LIB:
Select_Active_Library(); {
wxString library = SelectLibrary( getLibNickName() );
if( library.size() )
{
#if defined(USE_FP_LIB_TABLE)
setLibNickName( library );
#else
wxFileName fileName( library );
setLibNickName( fileName.GetName() );
setLibPath( fileName.GetFullPath() );
#endif
updateTitle();
}
}
break; break;
case ID_OPEN_MODULE_VIEWER: case ID_OPEN_MODULE_VIEWER:
@ -349,11 +364,19 @@ void FOOTPRINT_EDIT_FRAME::Process_Special_Functions( wxCommandEvent& event )
break; break;
case ID_MODEDIT_SAVE_LIBMODULE: case ID_MODEDIT_SAVE_LIBMODULE:
#if defined(USE_FP_LIB_TABLE)
if( GetBoard()->m_Modules && getLibNickName().size() )
{
Save_Module_In_Library( getLibNickName(), GetBoard()->m_Modules, true, true );
GetScreen()->ClrModify();
}
#else
if( GetBoard()->m_Modules && getLibPath() != wxEmptyString ) if( GetBoard()->m_Modules && getLibPath() != wxEmptyString )
{ {
Save_Module_In_Library( getLibPath(), GetBoard()->m_Modules, true, true ); Save_Module_In_Library( getLibPath(), GetBoard()->m_Modules, true, true );
GetScreen()->ClrModify(); GetScreen()->ClrModify();
} }
#endif
break; break;
case ID_MODEDIT_INSERT_MODULE_IN_BOARD: case ID_MODEDIT_INSERT_MODULE_IN_BOARD:

View File

@ -401,8 +401,6 @@ public:
*/ */
bool DeleteModuleFromCurrentLibrary(); bool DeleteModuleFromCurrentLibrary();
void Select_Active_Library();
virtual EDA_COLOR_T GetGridColor( void ) const; virtual EDA_COLOR_T GetGridColor( void ) const;
DECLARE_EVENT_TABLE() DECLARE_EVENT_TABLE()

View File

@ -363,9 +363,15 @@ void FOOTPRINT_EDIT_FRAME::OnCloseWindow( wxCloseEvent& Event )
case wxID_YES: case wxID_YES:
// code from FOOTPRINT_EDIT_FRAME::Process_Special_Functions, // code from FOOTPRINT_EDIT_FRAME::Process_Special_Functions,
// at case ID_MODEDIT_SAVE_LIBMODULE // at case ID_MODEDIT_SAVE_LIBMODULE
#if defined(USE_FP_LIB_TABLE)
if( GetBoard()->m_Modules && getLibNickName().size() )
{
if( Save_Module_In_Library( getLibNickName(), GetBoard()->m_Modules, true, true ) )
#else
if( GetBoard()->m_Modules && getLibPath() != wxEmptyString ) if( GetBoard()->m_Modules && getLibPath() != wxEmptyString )
{ {
if( Save_Module_In_Library( getLibPath(), GetBoard()->m_Modules, true, true ) ) if( Save_Module_In_Library( getLibPath(), GetBoard()->m_Modules, true, true ) )
#endif
{ {
// save was correct // save was correct
GetScreen()->ClrModify(); GetScreen()->ClrModify();

View File

@ -55,19 +55,15 @@ PCAD_PLUGIN::~PCAD_PLUGIN()
} }
const wxString& PCAD_PLUGIN::PluginName() const const wxString PCAD_PLUGIN::PluginName() const
{ {
static const wxString name = wxT( "P-Cad" ); return wxT( "P-Cad" );
return name;
} }
const wxString& PCAD_PLUGIN::GetFileExtension() const const wxString PCAD_PLUGIN::GetFileExtension() const
{ {
static const wxString extension = wxT( "pcb" ); return wxT( "pcb" );
return extension;
} }

View File

@ -39,18 +39,19 @@ public:
// -----<PUBLIC PLUGIN API>-------------------------------------------------- // -----<PUBLIC PLUGIN API>--------------------------------------------------
const wxString& PluginName() const; const wxString PluginName() const;
BOARD* Load( const wxString& aFileName, BOARD* Load( const wxString& aFileName,
BOARD* aAppendToMe, BOARD* aAppendToMe,
const PROPERTIES* aProperties = NULL ); const PROPERTIES* aProperties = NULL );
const wxString& GetFileExtension() const; const wxString GetFileExtension() const;
// -----</PUBLIC PLUGIN API>------------------------------------------------- // -----</PUBLIC PLUGIN API>-------------------------------------------------
PCAD_PLUGIN(); PCAD_PLUGIN();
~PCAD_PLUGIN(); ~PCAD_PLUGIN();
private: private:
const PROPERTIES* m_props; const PROPERTIES* m_props;
BOARD* m_board; BOARD* m_board;