Commit b0c739e7 authored by Dick Hollenbeck's avatar Dick Hollenbeck

*) 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.
parent 56615d16
......@@ -62,10 +62,6 @@ PCBNew
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.
*) Get licensing cleaned up.
*) Re-arrange the repo architecture.
......
......@@ -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 );
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 )
{
// use "no exception" form of find row:
......
......@@ -394,6 +394,16 @@ public:
*/
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
* 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
* 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.
*/
void FootprintSave( const wxString& aNickname, const MODULE* aFootprint );
SAVE_T FootprintSave( const wxString& aNickname, const MODULE* aFootprint, bool aOverwrite = true );
/**
* Function FootprintDelete
......@@ -431,6 +446,10 @@ public:
*/
bool IsFootprintLibWritable( const wxString& aNickname );
void FootprintLibDelete( const wxString& aNickname );
void FootprintLibCreate( const wxString& aNickname );
//-----</PLUGIN API SUBSET, REBASED ON aNickname>---------------------------
/**
......
......@@ -295,7 +295,7 @@ public:
* @param aLibName = name of the library to use
* @param aModule = the given footprint
* @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
* footprint name
* @return : true if OK, false if abort
......@@ -305,6 +305,16 @@ public:
bool aOverwrite,
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();
/**
......
......@@ -119,7 +119,7 @@ protected:
void setupTools();
void destroyTools();
void onGenericCommand( wxCommandEvent& aEvent );
void onGenericCommand( wxCommandEvent& aEvent );
// we'll use lower case function names for private member functions.
void createPopUpMenuForZones( ZONE_CONTAINER* edge_zone, wxMenu* aPopMenu );
......@@ -906,12 +906,11 @@ public:
/**
* Function ArchiveModulesOnBoard
* Save modules in a library:
* @param aLibName: the full filename of the library to create or modify
* @param aNewModulesOnly:
* true : save modules not already existing in this lib
* false: save all modules
*/
void ArchiveModulesOnBoard( const wxString& aLibName, bool aNewModulesOnly );
void ArchiveModulesOnBoard( bool aNewModulesOnly );
/**
* Function RecreateBOMFileFromBoard
......
......@@ -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 name;
return wxT( "Eagle" );
}
const wxString& EAGLE_PLUGIN::GetFileExtension() const
const wxString EAGLE_PLUGIN::GetFileExtension() const
{
static const wxString extension = wxT( "brd" );
return extension;
return wxT( "brd" );
}
......
......@@ -80,11 +80,11 @@ class EAGLE_PLUGIN : public PLUGIN
public:
//-----<PUBLIC PLUGIN API>--------------------------------------------------
const wxString& PluginName() const;
const wxString PluginName() const;
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);
......
......@@ -1177,11 +1177,11 @@ void PCB_EDIT_FRAME::Process_Special_Functions( wxCommandEvent& event )
break;
case ID_MENU_ARCHIVE_NEW_MODULES:
ArchiveModulesOnBoard( wxEmptyString, true );
ArchiveModulesOnBoard( true );
break;
case ID_MENU_ARCHIVE_ALL_MODULES:
ArchiveModulesOnBoard( wxEmptyString, false );
ArchiveModulesOnBoard( false );
break;
case ID_GEN_IMPORT_DXF_FILE:
......
This diff is collapsed.
......@@ -25,6 +25,7 @@
#ifndef GITHUB_PLUGIN_H_
#define GITHUB_PLUGIN_H_
#include <kicad_plugin.h>
struct GH_CACHE;
......@@ -32,38 +33,98 @@ struct GH_CACHE;
/**
* Class GITHUB_PLUGIN
* 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
* @date Original date: 10-Sep-2013
*/
class GITHUB_PLUGIN : public PLUGIN
class GITHUB_PLUGIN : public PCB_IO
{
public:
//-----<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 );
wxArrayString FootprintEnumerate( const wxString& aLibraryPath,
const PROPERTIES* aProperties = NULL );
MODULE* FootprintLoad( const wxString& aLibraryPath,
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 );
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>---------------------------------------------------------
GITHUB_PLUGIN(); // constructor, if any, must be zero arg
~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
......@@ -84,7 +145,9 @@ private:
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.
GH_CACHE* m_cache;
GH_CACHE* m_gh_cache;
wxString m_pretty_dir;
};
#endif // GITHUB_PLUGIN_H_
......@@ -52,16 +52,14 @@ public:
//-----<PLUGIN API>---------------------------------------------------------
const wxString& PluginName() const
const wxString PluginName() const
{
static const wxString name = wxT( "Geda PCB" );
return name;
return wxT( "Geda PCB" );
}
const wxString& GetFileExtension() const
const wxString GetFileExtension() const
{
static const wxString extension = wxT( "fp" );
return extension;
return wxT( "fp" );
}
wxArrayString FootprintEnumerate( const wxString& aLibraryPath, const PROPERTIES* aProperties = NULL);
......
......@@ -220,13 +220,13 @@ public:
* Function PluginName
* returns a brief hard coded name for this PLUGIN.
*/
virtual const wxString& PluginName() const = 0;
virtual const wxString PluginName() const = 0;
/**
* Function GetFileExtension
* returns the file extension for the PLUGIN.
*/
virtual const wxString& GetFileExtension() const = 0;
virtual const wxString GetFileExtension() const = 0;
/**
* Function Load
......
......@@ -85,7 +85,10 @@ public:
wxString GetName() const { return m_file_name.GetDirs().Last(); }
wxFileName GetFileName() const { return m_file_name; }
/// Tell if the disk content or the lib_path has changed.
bool IsModified() const;
MODULE* GetModule() const { return m_module.get(); }
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 )
{
wxFileName fn = m_lib_path;
fn.SetName( it->second->GetFileName().GetName() );
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.
init( NULL );
init( aProperties );
cacheLib( aLibraryPath );
......
......@@ -83,20 +83,18 @@ public:
//-----<PLUGIN API>---------------------------------------------------------
const wxString& PluginName() const
const wxString PluginName() const
{
static const wxString name = wxT( "KiCad" );
return name;
return wxT( "KiCad" );
}
const wxString& GetFileExtension() const
const wxString GetFileExtension() const
{
// 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
// with the core of the pcbnew code. (Might someday be a DLL/DSO.) Besides,
// file extension policy should be controlled by the plugin.
static const wxString extension = wxT( "kicad_pcb" );
return extension;
return wxT( "kicad_pcb" );
}
void Save( const wxString& aFileName, BOARD* aBoard,
......@@ -172,6 +170,10 @@ protected:
int m_ctl;
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:
void format( BOARD* aBoard, int aNestLevel = 0 ) const
......@@ -211,11 +213,6 @@ private:
void formatLayers( LAYER_MSK aLayerMask, int aNestLevel = 0 ) const
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_
......@@ -64,16 +64,14 @@ public:
//-----<PLUGIN IMPLEMENTATION>----------------------------------------------
const wxString& PluginName() const
const wxString PluginName() const
{
static const wxString name = wxT( "KiCad-Legacy" );
return name;
return wxT( "KiCad-Legacy" );
}
const wxString& GetFileExtension() const
const wxString GetFileExtension() const
{
static const wxString extension = wxT( "brd" );
return extension;
return wxT( "brd" );
}
BOARD* Load( const wxString& aFileName, BOARD* aAppendToMe, const PROPERTIES* aProperties = NULL );
......
This diff is collapsed.
......@@ -249,7 +249,22 @@ void FOOTPRINT_EDIT_FRAME::Process_Special_Functions( wxCommandEvent& event )
break;
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;
case ID_OPEN_MODULE_VIEWER:
......@@ -349,11 +364,19 @@ void FOOTPRINT_EDIT_FRAME::Process_Special_Functions( wxCommandEvent& event )
break;
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 )
{
Save_Module_In_Library( getLibPath(), GetBoard()->m_Modules, true, true );
GetScreen()->ClrModify();
}
#endif
break;
case ID_MODEDIT_INSERT_MODULE_IN_BOARD:
......
......@@ -401,8 +401,6 @@ public:
*/
bool DeleteModuleFromCurrentLibrary();
void Select_Active_Library();
virtual EDA_COLOR_T GetGridColor( void ) const;
DECLARE_EVENT_TABLE()
......
......@@ -363,9 +363,15 @@ void FOOTPRINT_EDIT_FRAME::OnCloseWindow( wxCloseEvent& Event )
case wxID_YES:
// code from FOOTPRINT_EDIT_FRAME::Process_Special_Functions,
// 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( Save_Module_In_Library( getLibPath(), GetBoard()->m_Modules, true, true ) )
#endif
{
// save was correct
GetScreen()->ClrModify();
......
......@@ -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 name;
return wxT( "P-Cad" );
}
const wxString& PCAD_PLUGIN::GetFileExtension() const
const wxString PCAD_PLUGIN::GetFileExtension() const
{
static const wxString extension = wxT( "pcb" );
return extension;
return wxT( "pcb" );
}
......
......@@ -39,18 +39,19 @@ public:
// -----<PUBLIC PLUGIN API>--------------------------------------------------
const wxString& PluginName() const;
const wxString PluginName() const;
BOARD* Load( const wxString& aFileName,
BOARD* aAppendToMe,
const PROPERTIES* aProperties = NULL );
const wxString& GetFileExtension() const;
const wxString GetFileExtension() const;
// -----</PUBLIC PLUGIN API>-------------------------------------------------
PCAD_PLUGIN();
~PCAD_PLUGIN();
private:
const PROPERTIES* m_props;
BOARD* m_board;
......
Markdown is supported
0% or
You are about to add 0 people to the discussion. Proceed with caution.
Finish editing this message first!
Please register or to comment