ba593f4111
Three bugs prevented KiCad from picking up symbol and footprint library file changes after a git branch switch without a restart. GetLibraryHash() returned a static value based on the library name and URI for non-buffered libraries. The hash now incorporates the file modification time so the synchronizing adapter re-enumerates the library when content changes on disk. OnSymChange() exited early when the project had no legacy symbol libraries, skipping the reload for modern .kicad_sym libraries. The legacy lib guard is removed from the event handler. FP_TREE_SYNCHRONIZING_ADAPTER::updateLibrary() always read from the startup cache. Added RefreshLibraryIfChanged() to compare the on-disk timestamp and re-enumerate when it has changed. Fixes https://gitlab.com/kicad/code/kicad/-/issues/23245
204 lines
8.8 KiB
C++
204 lines
8.8 KiB
C++
/*
|
|
* This program source code file is part of KiCad, a free EDA CAD application.
|
|
*
|
|
* Copyright The KiCad Developers, see AUTHORS.txt for contributors.
|
|
* @author Jon Evans <jon@craftyjon.com>
|
|
*
|
|
* 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 3 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, see <http://www.gnu.org/licenses/>.
|
|
*/
|
|
|
|
|
|
#ifndef FOOTPRINT_LIBRARY_ADAPTER_H
|
|
#define FOOTPRINT_LIBRARY_ADAPTER_H
|
|
|
|
#include <lib_id.h>
|
|
#include <core/leak_at_exit.h>
|
|
#include <libraries/library_manager.h>
|
|
#include <pcb_io/pcb_io.h>
|
|
#include <project.h>
|
|
|
|
class FOOTPRINT;
|
|
|
|
|
|
/**
|
|
* An interface to the global shared library manager that is schematic-specific
|
|
* and linked to one project in particular. This is what can return actual concrete
|
|
* schematic library content (symbols).
|
|
*/
|
|
class FOOTPRINT_LIBRARY_ADAPTER : public LIBRARY_MANAGER_ADAPTER
|
|
{
|
|
public:
|
|
FOOTPRINT_LIBRARY_ADAPTER( LIBRARY_MANAGER& aManager );
|
|
|
|
LIBRARY_TABLE_TYPE Type() const override { return LIBRARY_TABLE_TYPE::FOOTPRINT; }
|
|
|
|
static wxString GlobalPathEnvVariableName();
|
|
|
|
/// Loads or reloads the given library, if it exists
|
|
std::optional<LIB_STATUS> LoadOne( LIB_DATA* aLib ) override;
|
|
|
|
/// Loads or reloads the given library, if it exists
|
|
std::optional<LIB_STATUS> LoadOne( const wxString& aNickname );
|
|
|
|
/**
|
|
* Retrieves a list of footprints contained in a given loaded library
|
|
* @param aNickname is the library to query
|
|
* @param aBestEfforts if true, don't throw on errors, just return a smaller or empty list.
|
|
* @return a list of footprints contained in the given library
|
|
*/
|
|
std::vector<FOOTPRINT*> GetFootprints( const wxString& aNickname, bool aBestEfforts = false );
|
|
|
|
|
|
/**
|
|
* Retrieves a list of footprint names contained in a given loaded library
|
|
* @param aNickname is the library to query
|
|
* @param aBestEfforts if true, don't throw on errors, just return a smaller or empty list.
|
|
* @return a list of names of footprints contained in the given library
|
|
*/
|
|
std::vector<wxString> GetFootprintNames( const wxString& aNickname, bool aBestEfforts = false );
|
|
|
|
/**
|
|
* Generates a filesystem timestamp / hash value for library(ies)
|
|
* @param aNickname is an optional specific library to timestamp. If nullptr,
|
|
* a timestamp will be calculated for all libraries in the table.
|
|
* @return a value that can be used to determine if libraries have changed on disk
|
|
*/
|
|
long long GenerateTimestamp( const wxString* aNickname );
|
|
|
|
/**
|
|
* Checks whether the library on disk has changed since it was last enumerated into
|
|
* PreloadedFootprints and, if so, clears the stale cache and re-enumerates the library
|
|
* synchronously. This allows external changes such as git branch switches to be picked
|
|
* up without restarting KiCad.
|
|
*
|
|
* @param aNickname is the library to check and potentially refresh.
|
|
*/
|
|
void RefreshLibraryIfChanged( const wxString& aNickname );
|
|
|
|
bool FootprintExists( const wxString& aNickname, const wxString& aName );
|
|
|
|
/**
|
|
* Load a #FOOTPRINT having @a aName from the library given by @a aNickname.
|
|
*
|
|
* @param aNickname is a locator for the "library", it is a "name" in #LIB_TABLE_ROW
|
|
* @param aName is the name of the #FOOTPRINT to load.
|
|
* @param aKeepUUID = true to keep initial items UUID, false to set new UUID
|
|
* normally true if loaded in the footprint editor, false
|
|
* if loaded in the board editor. Make sense only in kicad_plugin
|
|
* @return the footprint if found or NULL if not found.
|
|
* @throw IO_ERROR if the library cannot be found or read. No exception
|
|
* is thrown in the case where \a aNickname cannot be found.
|
|
*/
|
|
FOOTPRINT* LoadFootprint( const wxString& aNickname, const wxString& aName, bool aKeepUUID );
|
|
|
|
FOOTPRINT* LoadFootprint( const LIB_ID& aLibId, bool aKeepUUID )
|
|
{
|
|
return LoadFootprint( aLibId.GetLibNickname(), aLibId.GetLibItemName(), aKeepUUID );
|
|
}
|
|
|
|
/**
|
|
* Load a footprint having @a aFootprintId with possibly an empty nickname.
|
|
*
|
|
* @param aFootprintId the [nickname] and name of the design block to load.
|
|
* @param aKeepUUID = true to keep initial items UUID, false to set new UUID
|
|
* normally true if loaded in the footprint editor, false
|
|
* if loaded in the board editor
|
|
* used only in kicad_plugin
|
|
* @return the #FOOTPRINT if found caller owns it, else NULL if not found.
|
|
*
|
|
* @throw IO_ERROR if the library cannot be found or read. No exception is
|
|
* thrown in the case where \a aFootprintId cannot be found.
|
|
* @throw PARSE_ERROR if @a aFootprintId is not parsed OK.
|
|
*/
|
|
FOOTPRINT* LoadFootprintWithOptionalNickname( const LIB_ID& aFootprintId, bool aKeepUUID );
|
|
|
|
// TODO(JE) library tables - hoist out?
|
|
/**
|
|
* The set of return values from SaveSymbol() below.
|
|
*/
|
|
enum SAVE_T
|
|
{
|
|
SAVE_OK,
|
|
SAVE_SKIPPED,
|
|
};
|
|
|
|
/**
|
|
* Write @a aFootprint to an existing library given by @a aNickname.
|
|
*
|
|
* If a #FOOTPRINT by the same name already exists or there are any conflicting alias
|
|
* names, the new #FOOTPRINT will silently overwrite any existing aliases and/or part
|
|
* because libraries cannot have duplicate alias names. It is the responsibility of
|
|
* the caller to check the library for conflicts before saving.
|
|
*
|
|
* @param aNickname is a locator for the "library", it is a "name" in LIB_TABLE_ROW
|
|
* @param aFootprint is what to store in the library. The library owns the footprint after this
|
|
* call.
|
|
* @param aOverwrite when true means overwrite any existing symbol 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 the footprint.
|
|
*/
|
|
SAVE_T SaveFootprint( const wxString& aNickname, const FOOTPRINT* aFootprint,
|
|
bool aOverwrite = true );
|
|
|
|
/**
|
|
* Deletes the @a aFootprintName from the library given by @a aNickname.
|
|
*
|
|
* @param aNickname is a locator for the "library", it is a "name" in LIB_TABLE_ROW.
|
|
* @param aFootprintName is the name of a footprint to delete from the specified library.
|
|
* @throw IO_ERROR if there is a problem finding the footprint or the library, or deleting it.
|
|
*/
|
|
void DeleteFootprint( const wxString& aNickname, const wxString& aFootprintName );
|
|
|
|
/**
|
|
* Return true if the library given by @a aNickname is writable.
|
|
*
|
|
* It is possible that some footprint libraries are read only because of where they are
|
|
* installed.
|
|
*
|
|
* @param aNickname is the library nickname in the footprint library table.
|
|
* @throw IO_ERROR if no library at @a aNickname exists.
|
|
*/
|
|
bool IsFootprintLibWritable( const wxString& aNickname );
|
|
|
|
protected:
|
|
std::map<wxString, LIB_DATA>& globalLibs() override { return GlobalLibraries.Get(); }
|
|
std::map<wxString, LIB_DATA>& globalLibs() const override { return GlobalLibraries.Get(); }
|
|
std::shared_mutex& globalLibsMutex() override { return GlobalLibraryMutex; }
|
|
std::shared_mutex& globalLibsMutex() const override { return GlobalLibraryMutex; }
|
|
|
|
void enumerateLibrary( LIB_DATA* aLib, const wxString& aUri ) override;
|
|
|
|
LIBRARY_RESULT<IO_BASE*> createPlugin( const LIBRARY_TABLE_ROW* row ) override;
|
|
|
|
IO_BASE* plugin( const LIB_DATA* aRow ) override { return pcbplugin( aRow ); }
|
|
|
|
private:
|
|
static PCB_IO* pcbplugin( const LIB_DATA* aRow );
|
|
|
|
static LEAK_AT_EXIT<std::map<wxString, LIB_DATA>> GlobalLibraries;
|
|
static std::shared_mutex GlobalLibraryMutex;
|
|
|
|
/// Storage for preloaded footprints, indexed by library nickname.
|
|
/// These are cloned during library enumeration so GetFootprints() returns instantly.
|
|
static LEAK_AT_EXIT<std::map<wxString, std::vector<std::unique_ptr<FOOTPRINT>>>> PreloadedFootprints;
|
|
static std::shared_mutex PreloadedFootprintsMutex;
|
|
|
|
/// Per-library filesystem timestamps recorded when PreloadedFootprints was last populated.
|
|
/// Used by RefreshLibraryIfChanged() to detect external modifications.
|
|
std::map<wxString, long long> m_preloadedTimestamps;
|
|
};
|
|
|
|
#endif //FOOTPRINT_LIBRARY_ADAPTER_H
|