3D file name resolver improvements.

* Paths defined via pcbnew->Preferences->Configure Paths are now included in
  the 3D file browser's drop-down list except for KICAD_PTEMPLATES, KIGITHUB,
  KISYSMOD, any paths resembling a URL, and any non-existent paths. When an
  absolute path is shortened using one of these path aliases, let's say
  'KISYS3DMOD' then the name appears in the pcb file as "${KISYS3DMOD}/blah.wrl".
  If a user defines and actual environment variable with the same name, then
  that user defined variable will have precedence over the internally defined
  variable.

* Paths relative to the current project directory are no longer represented
  as "some/path/to/file.wrl".  For compatibility with previous KiCad versions
  it shall always be stored as ${KIPRJMOD}/some/path/to/file.wrl.

* Various restrictions on alias path values have been removed since the
  imposed restrictions could result in corrupted user data as aliases are
  silently dropped.

* Overall the patch should improve back-compatibility by providing a ${ENV_VAR}
  mechanism for supporting different model root directories and ensuring that
  paths relative to KIPRJMOD are expressed in a way that is compatible with
  earlier KiCad versions. This allows users more flexibility and the ability
  to work in a way that ensures 3D model files can be correctly resolved in
  earlier versions of KiCad. Users who do not care about back-compatibility
  may prefer to use the newer alias system.
This commit is contained in:
Cirilo Bernardo 2016-04-17 18:35:32 -04:00 committed by Wayne Stambaugh
parent 32fc9198c3
commit 6120472d60
9 changed files with 258 additions and 174 deletions

View File

@ -686,6 +686,13 @@ bool S3D_CACHE::SetProjectDir( const wxString& aProjDir )
} }
void S3D_CACHE::SetProgramBase( PGM_BASE* aBase )
{
m_FNResolver->SetProgramBase( aBase );
return;
}
wxString S3D_CACHE::GetProjectDir( void ) wxString S3D_CACHE::GetProjectDir( void )
{ {
return m_FNResolver->GetProjectDir(); return m_FNResolver->GetProjectDir();

View File

@ -38,6 +38,7 @@
#include "plugins/3dapi/c3dmodel.h" #include "plugins/3dapi/c3dmodel.h"
class PGM_BASE;
class S3D_CACHE; class S3D_CACHE;
class S3D_CACHE_ENTRY; class S3D_CACHE_ENTRY;
class SCENEGRAPH; class SCENEGRAPH;
@ -138,6 +139,14 @@ public:
*/ */
bool SetProjectDir( const wxString& aProjDir ); bool SetProjectDir( const wxString& aProjDir );
/**
* Function SetProgramBase
* sets the filename resolver's pointer to the application's
* PGM_BASE instance; the pointer is used to extract the
* local env vars.
*/
void SetProgramBase( PGM_BASE* aBase );
/** /**
* Function GetProjectDir * Function GetProjectDir
* returns the current project's working directory * returns the current project's working directory

View File

@ -24,6 +24,7 @@
#include <common.h> #include <common.h>
#include <wx/thread.h> #include <wx/thread.h>
#include <pgm_base.h>
#include "3d_cache_wrapper.h" #include "3d_cache_wrapper.h"
static wxCriticalSection lock3D_wrapper; static wxCriticalSection lock3D_wrapper;
@ -57,6 +58,7 @@ S3D_CACHE* PROJECT::Get3DCacheManager( bool updateProjDir )
wxFileName cfgpath; wxFileName cfgpath;
cfgpath.AssignDir( GetKicadConfigPath() ); cfgpath.AssignDir( GetKicadConfigPath() );
cfgpath.AppendDir( wxT( "3d" ) ); cfgpath.AppendDir( wxT( "3d" ) );
cache->SetProgramBase( &Pgm() );
cache->Set3DConfigDir( cfgpath.GetFullPath() ); cache->Set3DConfigDir( cfgpath.GetFullPath() );
SetElem( ELEM_3DCACHE, cw ); SetElem( ELEM_3DCACHE, cw );
updateProjDir = true; updateProjDir = true;

View File

@ -32,6 +32,7 @@
#include <wx/thread.h> #include <wx/thread.h>
#include <wx/utils.h> #include <wx/utils.h>
#include <wx/msgdlg.h> #include <wx/msgdlg.h>
#include <pgm_base.h>
#include "3d_filename_resolver.h" #include "3d_filename_resolver.h"
@ -54,6 +55,7 @@ static bool getHollerith( const std::string& aString, size_t& aIndex, wxString&
S3D_FILENAME_RESOLVER::S3D_FILENAME_RESOLVER() S3D_FILENAME_RESOLVER::S3D_FILENAME_RESOLVER()
{ {
m_errflags = 0; m_errflags = 0;
m_pgm = NULL;
} }
@ -86,7 +88,7 @@ bool S3D_FILENAME_RESOLVER::SetProjectDir( const wxString& aProjDir, bool* flgCh
if( false == projdir.DirExists() ) if( false == projdir.DirExists() )
return false; return false;
wxString path = projdir.GetPath(); m_curProjDir = projdir.GetPath();
if( flgChanged ) if( flgChanged )
*flgChanged = false; *flgChanged = false;
@ -96,7 +98,7 @@ bool S3D_FILENAME_RESOLVER::SetProjectDir( const wxString& aProjDir, bool* flgCh
S3D_ALIAS al; S3D_ALIAS al;
al.m_alias = _( "(DEFAULT)" ); al.m_alias = _( "(DEFAULT)" );
al.m_pathvar = _( "${PROJDIR}" ); al.m_pathvar = _( "${PROJDIR}" );
al.m_pathexp = path; al.m_pathexp = m_curProjDir;
al.m_description = _( "Current project directory" ); al.m_description = _( "Current project directory" );
m_Paths.push_back( al ); m_Paths.push_back( al );
m_NameMap.clear(); m_NameMap.clear();
@ -107,9 +109,9 @@ bool S3D_FILENAME_RESOLVER::SetProjectDir( const wxString& aProjDir, bool* flgCh
} }
else else
{ {
if( m_Paths.front().m_pathexp.Cmp( path ) ) if( m_Paths.front().m_pathexp.Cmp( m_curProjDir ) )
{ {
m_Paths.front().m_pathexp = path; m_Paths.front().m_pathexp = m_curProjDir;
m_NameMap.clear(); m_NameMap.clear();
if( flgChanged ) if( flgChanged )
@ -138,10 +140,22 @@ bool S3D_FILENAME_RESOLVER::SetProjectDir( const wxString& aProjDir, bool* flgCh
wxString S3D_FILENAME_RESOLVER::GetProjectDir( void ) wxString S3D_FILENAME_RESOLVER::GetProjectDir( void )
{ {
if( m_Paths.empty() ) return m_curProjDir;
return wxEmptyString; }
return m_Paths.front().m_pathexp;
void S3D_FILENAME_RESOLVER::SetProgramBase( PGM_BASE* aBase )
{
m_pgm = aBase;
if( NULL == m_pgm || m_Paths.empty() )
return;
// recreate the path list
m_Paths.clear();
createPathList();
return;
} }
@ -157,15 +171,61 @@ bool S3D_FILENAME_RESOLVER::createPathList( void )
// the user may change this later with a call to SetProjectDir() // the user may change this later with a call to SetProjectDir()
S3D_ALIAS lpath; S3D_ALIAS lpath;
lpath.m_alias = _( "(DEFAULT)" ); lpath.m_alias = _( "${KIPRJMOD}" );
lpath.m_pathvar = _( "${PROJDIR}" ); lpath.m_pathvar = _( "${KIPRJMOD}" );
lpath.m_description = _( "Current project directory" ); lpath.m_pathexp = m_curProjDir;
m_Paths.push_back( lpath );
wxFileName fndummy;
wxUniChar psep = fndummy.GetPathSeparator();
// iterate over the list of internally defined ENV VARs
// and add existing paths to the resolver
if( m_pgm )
{
ENV_VAR_MAP_CITER mS = m_pgm->GetLocalEnvVariables().begin();
ENV_VAR_MAP_CITER mE = m_pgm->GetLocalEnvVariables().end();
while( mS != mE )
{
// filter out URLs, template directories, and known system paths
if( mS->first == wxString( "KICAD_PTEMPLATES" )
|| mS->first == wxString( "KIGITHUB" )
|| mS->first == wxString( "KISYSMOD" ) )
{
++mS;
continue;
}
if( wxString::npos != mS->second.GetValue().find( wxString( "://" ) ) )
{
++mS;
continue;
}
fndummy.Assign( mS->second.GetValue(), "" );
if( !fndummy.DirExists() )
{
++mS;
continue;
}
wxString tmp( "${" );
tmp.Append( mS->first );
tmp.Append( "}" );
lpath.m_alias = tmp;
lpath.m_pathvar = tmp;
lpath.m_pathexp = mS->second.GetValue();
if( !lpath.m_pathexp.empty() && psep == *lpath.m_pathexp.rbegin() )
lpath.m_pathexp.erase( --lpath.m_pathexp.end() );
m_Paths.push_back( lpath ); m_Paths.push_back( lpath );
lpath.m_alias = wxT( "KISYS3DMOD" ); ++mS;
lpath.m_pathvar = wxT( "${KISYS3DMOD}" ); }
lpath.m_description = _( "Legacy 3D environment path" ); }
addPath( lpath );
if( !m_ConfigDir.empty() ) if( !m_ConfigDir.empty() )
readPathList(); readPathList();
@ -191,7 +251,9 @@ bool S3D_FILENAME_RESOLVER::createPathList( void )
bool S3D_FILENAME_RESOLVER::UpdatePathList( std::vector< S3D_ALIAS >& aPathList ) bool S3D_FILENAME_RESOLVER::UpdatePathList( std::vector< S3D_ALIAS >& aPathList )
{ {
while( m_Paths.size() > 2 ) wxUniChar envMarker( '$' );
while( !m_Paths.empty() && envMarker != *m_Paths.back().m_alias.rbegin() )
m_Paths.pop_back(); m_Paths.pop_back();
size_t nI = aPathList.size(); size_t nI = aPathList.size();
@ -258,6 +320,11 @@ wxString S3D_FILENAME_RESOLVER::ResolvePath( const wxString& aFileName )
return tname; return tname;
} }
else if( resolveVirtualEnv( aFileName, tname ) )
{
m_NameMap.insert( std::pair< wxString, wxString > ( aFileName, tname ) );
return tname;
}
if( !( m_errflags & ERRFLG_ENVPATH ) ) if( !( m_errflags & ERRFLG_ENVPATH ) )
{ {
@ -276,7 +343,8 @@ wxString S3D_FILENAME_RESOLVER::ResolvePath( const wxString& aFileName )
// check the path relative to the current project directory; // check the path relative to the current project directory;
// note: this is not necessarily the same as the current working // note: this is not necessarily the same as the current working
// directory, which has already been checked // directory, which has already been checked. This case accounts
// for partial paths which do not contain ${KIPRJMOD}.
if( !sPL->m_pathexp.empty() ) if( !sPL->m_pathexp.empty() )
{ {
wxFileName fpath( wxFileName::DirName( sPL->m_pathexp ) ); wxFileName fpath( wxFileName::DirName( sPL->m_pathexp ) );
@ -295,11 +363,12 @@ wxString S3D_FILENAME_RESOLVER::ResolvePath( const wxString& aFileName )
} }
} }
++sPL; // skip to item 2: KISYS3DMOD // ${ENV_VAR} paths have already been checked; skip all but
// ${KISYS3DMOD}, since legacy behavior was to check if paths
// check if the path is relative to KISYS3DMOD but lacking // were relative to ${KISYS3DMOD}
// the "KISYS3DMOD:" alias tag while( sPL != ePL && sPL->m_alias.StartsWith( "${" ) )
if( !sPL->m_pathexp.empty() ) {
if( sPL->m_alias == "${KISYS3DMOD}" )
{ {
wxFileName fpath( wxFileName::DirName( sPL->m_pathexp ) ); wxFileName fpath( wxFileName::DirName( sPL->m_pathexp ) );
wxString fullPath = fpath.GetPathWithSep() + tname; wxString fullPath = fpath.GetPathWithSep() + tname;
@ -317,6 +386,10 @@ wxString S3D_FILENAME_RESOLVER::ResolvePath( const wxString& aFileName )
} }
} }
++sPL;
}
// at this point the filename must contain an alias or else it is invalid
wxString alias; // the alias portion of the short filename wxString alias; // the alias portion of the short filename
wxString relpath; // the path relative to the alias wxString relpath; // the path relative to the alias
@ -324,8 +397,10 @@ wxString S3D_FILENAME_RESOLVER::ResolvePath( const wxString& aFileName )
{ {
if( !( m_errflags & ERRFLG_RELPATH ) ) if( !( m_errflags & ERRFLG_RELPATH ) )
{ {
// this can happen if the file was intended to be relative to
// ${KISYS3DMOD} but ${KISYS3DMOD} not set or incorrect.
m_errflags |= ERRFLG_RELPATH; m_errflags |= ERRFLG_RELPATH;
wxString errmsg = _( "[3D File Resolver] No such path; ensure KISYS3DMOD is correctly defined" ); wxString errmsg = _( "[3D File Resolver] No such path" );
errmsg.append( "\n" ); errmsg.append( "\n" );
errmsg.append( tname ); errmsg.append( tname );
wxLogTrace( MASK_3D_RESOLVER, "%s\n", errmsg.ToUTF8() ); wxLogTrace( MASK_3D_RESOLVER, "%s\n", errmsg.ToUTF8() );
@ -378,7 +453,6 @@ bool S3D_FILENAME_RESOLVER::addPath( const S3D_ALIAS& aPath )
wxCriticalSectionLocker lock( lock3D_resolver ); wxCriticalSectionLocker lock( lock3D_resolver );
S3D_ALIAS tpath = aPath; S3D_ALIAS tpath = aPath;
tpath.m_duplicate = false;
#ifdef _WIN32 #ifdef _WIN32
while( tpath.m_pathvar.EndsWith( wxT( "\\" ) ) ) while( tpath.m_pathvar.EndsWith( wxT( "\\" ) ) )
@ -424,83 +498,6 @@ bool S3D_FILENAME_RESOLVER::addPath( const S3D_ALIAS& aPath )
while( sPL != ePL ) while( sPL != ePL )
{ {
// aliases with the same m_pathvar are forbidden and the
// user must be forced to fix the problem in order to
// obtain good filename resolution
if( !sPL->m_pathvar.empty() && !tpath.m_pathvar.empty()
&& !tpath.m_pathvar.Cmp( sPL->m_pathvar ) )
{
wxString msg = _( "This alias: " );
msg.append( tpath.m_alias );
msg.append( wxT( "\n" ) );
msg.append( _( "This path: " ) );
msg.append( tpath.m_pathvar );
msg.append( wxT( "\n" ) );
msg.append( _( "Existing alias: " ) );
msg.append( sPL->m_alias );
msg.append( wxT( "\n" ) );
msg.append( _( "Existing path: " ) );
msg.append( sPL->m_pathvar );
wxMessageBox( msg, _( "Bad alias (duplicate path)" ) );
return false;
}
// aliases with the same m_pathexp are acceptable (one or both
// aliases being tested may be expanded variables) but when shortening
// names the preference is for (a) a fully specified path in m_pathvar
// then (b) the more senior alias in the list
if( !sPL->m_pathexp.empty() && !tpath.m_pathexp.empty() )
{
if( !tpath.m_pathexp.Cmp( sPL->m_pathexp ) )
{
wxString msg = _( "This alias: " );
msg.append( tpath.m_alias );
msg.append( wxT( "\n" ) );
msg.append( _( "Existing alias: " ) );
msg.append( sPL->m_alias );
msg.append( wxT( "\n" ) );
msg.append( _( "This path: " ) );
msg.append( tpath.m_pathexp );
msg.append( wxT( "\n" ) );
msg.append( _( "Existing path: " ) );
msg.append( sPL->m_pathexp );
msg.append( wxT( "\n" ) );
msg.append( _( "This full path: " ) );
msg.append( tpath.m_pathexp );
msg.append( wxT( "\n" ) );
msg.append( _( "Existing full path: " ) );
msg.append( sPL->m_pathexp );
wxMessageBox( msg, _( "Bad alias (duplicate path)" ) );
if( tpath.m_pathvar.StartsWith( wxT( "${" ) ) )
tpath.m_duplicate = true;
else if( sPL->m_pathvar.StartsWith( wxT( "${" ) ) )
sPL->m_duplicate = true;
}
if( ( tpath.m_pathexp.find( sPL->m_pathexp ) != wxString::npos
|| sPL->m_pathexp.find( tpath.m_pathexp ) != wxString::npos )
&& tpath.m_pathexp.Cmp( sPL->m_pathexp ) )
{
wxString msg = _( "This alias: " );
msg.append( tpath.m_alias );
msg.append( wxT( "\n" ) );
msg.append( _( "This path: " ) );
msg.append( tpath.m_pathexp );
msg.append( wxT( "\n" ) );
msg.append( _( "Existing alias: " ) );
msg.append( sPL->m_alias );
msg.append( wxT( "\n" ) );
msg.append( _( "Existing path: " ) );
msg.append( sPL->m_pathexp );
wxMessageBox( msg, _( "Bad alias (common path)" ) );
return false;
}
}
if( !tpath.m_alias.Cmp( sPL->m_alias ) ) if( !tpath.m_alias.Cmp( sPL->m_alias ) )
{ {
wxString msg = _( "Alias: " ); wxString msg = _( "Alias: " );
@ -519,8 +516,6 @@ bool S3D_FILENAME_RESOLVER::addPath( const S3D_ALIAS& aPath )
++sPL; ++sPL;
} }
// Note: at this point we may still have duplicated paths
m_Paths.push_back( tpath ); m_Paths.push_back( tpath );
return true; return true;
} }
@ -572,7 +567,6 @@ bool S3D_FILENAME_RESOLVER::readPathList( void )
int lineno = 0; int lineno = 0;
S3D_ALIAS al; S3D_ALIAS al;
al.m_duplicate = false;
size_t idx; size_t idx;
int vnum = 0; // version number int vnum = 0; // version number
@ -647,11 +641,18 @@ bool S3D_FILENAME_RESOLVER::writePathList( void )
return false; return false;
} }
// skip all ${ENV_VAR} alias names
std::list< S3D_ALIAS >::const_iterator sPL = m_Paths.begin();
std::list< S3D_ALIAS >::const_iterator ePL = m_Paths.end();
while( sPL != ePL && sPL->m_alias.StartsWith( "${" ) )
++sPL;
wxFileName cfgpath( m_ConfigDir, S3D_RESOLVER_CONFIG ); wxFileName cfgpath( m_ConfigDir, S3D_RESOLVER_CONFIG );
wxString cfgname = cfgpath.GetFullPath(); wxString cfgname = cfgpath.GetFullPath();
std::ofstream cfgFile; std::ofstream cfgFile;
if( m_Paths.empty() || 1 == m_Paths.size() ) if( sPL == ePL )
{ {
wxMessageDialog md( NULL, wxMessageDialog md( NULL,
_( "3D search path list is empty;\ncontinue to write empty file?" ), _( "3D search path list is empty;\ncontinue to write empty file?" ),
@ -692,23 +693,10 @@ bool S3D_FILENAME_RESOLVER::writePathList( void )
} }
cfgFile << "#V" << CFGFILE_VERSION << "\n"; cfgFile << "#V" << CFGFILE_VERSION << "\n";
std::list< S3D_ALIAS >::const_iterator sPL = m_Paths.begin();
std::list< S3D_ALIAS >::const_iterator ePL = m_Paths.end();
// the first entry is the current project dir; we never add the implicit
// project dir to the path list in the configuration file
++sPL;
std::string tstr; std::string tstr;
while( sPL != ePL ) while( sPL != ePL )
{ {
// never write the KISYS3DMOD entry
if( !sPL->m_alias.Cmp( wxT( "KISYS3DMOD") ) )
{
++sPL;
continue;
}
tstr = sPL->m_alias.ToUTF8(); tstr = sPL->m_alias.ToUTF8();
cfgFile << "\"" << tstr.size() << ":" << tstr << "\","; cfgFile << "\"" << tstr.size() << ":" << tstr << "\",";
tstr = sPL->m_pathvar.ToUTF8(); tstr = sPL->m_pathvar.ToUTF8();
@ -733,6 +721,50 @@ bool S3D_FILENAME_RESOLVER::writePathList( void )
} }
bool S3D_FILENAME_RESOLVER::resolveVirtualEnv( const wxString& aFileName, wxString& aFullPath )
{
aFullPath.clear();
if( !aFileName.StartsWith( "${" ) )
return false;
size_t eDelim = aFileName.find( '}' );
if( eDelim == wxString::npos || eDelim + 2 >= aFileName.length() )
return false;
wxString tPath = aFileName.substr( 0, eDelim + 1 );
std::list< S3D_ALIAS >::const_iterator sPL = m_Paths.begin();
std::list< S3D_ALIAS >::const_iterator ePL = m_Paths.end();
while( sPL != ePL )
{
if( !sPL->m_alias.StartsWith( "${" ) )
return false;
if( sPL->m_alias == tPath )
{
tPath.Append( aFileName.substr( eDelim + 2 ) );
wxFileName tFile( tPath );
tFile.Normalize();
if( tFile.FileExists() )
{
aFullPath = tFile.GetFullPath();
return true;
}
return false;
}
++sPL;
}
return false;
}
wxString S3D_FILENAME_RESOLVER::ShortenPath( const wxString& aFullPathName ) wxString S3D_FILENAME_RESOLVER::ShortenPath( const wxString& aFullPathName )
{ {
wxString fname = aFullPathName; wxString fname = aFullPathName;
@ -745,32 +777,11 @@ wxString S3D_FILENAME_RESOLVER::ShortenPath( const wxString& aFullPathName )
std::list< S3D_ALIAS >::const_iterator eL = m_Paths.end(); std::list< S3D_ALIAS >::const_iterator eL = m_Paths.end();
size_t idx; size_t idx;
// test for files within the current project directory
// and KISYS3DMOD directory
for( int i = 0; i < 2 && sL != eL; ++i )
{
if( !sL->m_pathexp.empty() )
{
wxFileName fpath( sL->m_pathexp, wxT( "" ) );
wxString fps = fpath.GetPathWithSep();
idx = fname.find( fps );
if( std::string::npos != idx && 0 == idx )
{
fname = fname.substr( fps.size() );
return fname;
}
}
++sL;
}
while( sL != eL ) while( sL != eL )
{ {
// undefined paths and duplicates do not participate // undefined paths do not participate in the
// in the file name shortening procedure // file name shortening procedure
if( sL->m_pathexp.empty() || sL->m_duplicate ) if( sL->m_pathexp.empty() )
{ {
++sL; ++sL;
continue; continue;
@ -791,10 +802,21 @@ wxString S3D_FILENAME_RESOLVER::ShortenPath( const wxString& aFullPathName )
fname.Replace( wxT( "\\" ), wxT( "/" ) ); fname.Replace( wxT( "\\" ), wxT( "/" ) );
#endif #endif
if( sL->m_alias.StartsWith( "${" ) )
{
// old style ENV_VAR
tname = sL->m_alias;
tname.Append( "/" );
tname.append( fname );
}
else
{
// new style alias
tname = ":"; tname = ":";
tname.append( sL->m_alias ); tname.append( sL->m_alias );
tname.append( ":" ); tname.append( ":" );
tname.append( fname ); tname.append( fname );
}
return tname; return tname;
} }

View File

@ -39,9 +39,10 @@
#include <wx/string.h> #include <wx/string.h>
#include "str_rsort.h" #include "str_rsort.h"
class PGM_BASE;
struct S3D_ALIAS struct S3D_ALIAS
{ {
bool m_duplicate;
wxString m_alias; // alias to the base path wxString m_alias; // alias to the base path
wxString m_pathvar; // base path as stored in the config file wxString m_pathvar; // base path as stored in the config file
wxString m_pathexp; // expanded base path wxString m_pathexp; // expanded base path
@ -56,6 +57,8 @@ private:
// mapping of (short) file names to resolved names // mapping of (short) file names to resolved names
std::map< wxString, wxString, S3D::rsort_wxString > m_NameMap; std::map< wxString, wxString, S3D::rsort_wxString > m_NameMap;
int m_errflags; int m_errflags;
PGM_BASE* m_pgm;
wxString m_curProjDir;
/** /**
* Function createPathList * Function createPathList
@ -95,6 +98,14 @@ private:
*/ */
bool writePathList( void ); bool writePathList( void );
/**
* Function resolveVirtualEnv
* extracts the ${ENV_VAR} component of aFileName and puts a
* resolved path in aFullPath if the ${ENV_VAR} exists in the
* alias list and the referenced file exists.
*/
bool resolveVirtualEnv( const wxString& aFileName, wxString& aFullPath );
public: public:
S3D_FILENAME_RESOLVER(); S3D_FILENAME_RESOLVER();
@ -120,6 +131,13 @@ public:
bool SetProjectDir( const wxString& aProjDir, bool* flgChanged = NULL ); bool SetProjectDir( const wxString& aProjDir, bool* flgChanged = NULL );
wxString GetProjectDir( void ); wxString GetProjectDir( void );
/**
* Function SetProgramBase
* sets a pointer to the application's PGM_BASE instance;
* the pointer is used to extract the local env vars.
*/
void SetProgramBase( PGM_BASE* aBase );
/** /**
* Function UpdatePathList * Function UpdatePathList

View File

@ -42,33 +42,35 @@ DLG_3D_PATH_CONFIG::DLG_3D_PATH_CONFIG( wxWindow* aParent, S3D_FILENAME_RESOLVER
m_aliasValidator.SetCharExcludes( wxT( "{}[]()%~<>\"='`;:.,&?/\\|$" ) ); m_aliasValidator.SetCharExcludes( wxT( "{}[]()%~<>\"='`;:.,&?/\\|$" ) );
const std::list< S3D_ALIAS >* rpaths = m_resolver->GetPaths(); const std::list< S3D_ALIAS >* rpaths = m_resolver->GetPaths();
std::list< S3D_ALIAS >::const_iterator rI = rpaths->begin();
std::list< S3D_ALIAS >::const_iterator rE = rpaths->end();
size_t listsize = rpaths->size(); size_t listsize = rpaths->size();
size_t listidx = 0;
if( listsize > 0 ) while( rI != rE && (*rI).m_alias.StartsWith( "${" ) )
m_curdir = rpaths->front().m_pathexp; {
++listidx;
++rI;
}
if( listsize < 3 ) if( listidx < listsize )
m_curdir = (*rI).m_pathexp;
else
return; return;
listsize = listsize - 2 - m_Aliases->GetNumberRows(); listsize = listsize - listidx - m_Aliases->GetNumberRows();
// note: if the list allocation fails we have bigger problems // note: if the list allocation fails we have bigger problems
// and there is no point in trying to notify the user here // and there is no point in trying to notify the user here
if( listsize > 0 && !m_Aliases->InsertRows( 0, listsize ) ) if( listsize > 0 && !m_Aliases->InsertRows( 0, listsize ) )
return; return;
std::list< S3D_ALIAS >::const_iterator sL = rpaths->begin();
std::list< S3D_ALIAS >::const_iterator eL = rpaths->end();
int nitems = 0; int nitems = 0;
// skip the current project dir and KISYS3DMOD
++sL;
++sL;
wxGridCellTextEditor* pEdAlias; wxGridCellTextEditor* pEdAlias;
while( sL != eL ) while( rI != rE )
{ {
m_Aliases->SetCellValue( nitems, 0, sL->m_alias ); m_Aliases->SetCellValue( nitems, 0, rI->m_alias );
if( 0 == nitems ) if( 0 == nitems )
{ {
@ -83,12 +85,12 @@ DLG_3D_PATH_CONFIG::DLG_3D_PATH_CONFIG( wxWindow* aParent, S3D_FILENAME_RESOLVER
m_Aliases->SetCellEditor( nitems, 0, pEdAlias ); m_Aliases->SetCellEditor( nitems, 0, pEdAlias );
} }
m_Aliases->SetCellValue( nitems, 1, sL->m_pathvar ); m_Aliases->SetCellValue( nitems, 1, rI->m_pathvar );
m_Aliases->SetCellValue( nitems++, 2, sL->m_description ); m_Aliases->SetCellValue( nitems++, 2, rI->m_description );
// TODO: implement a wxGridCellEditor which invokes a wxDirDialog // TODO: implement a wxGridCellEditor which invokes a wxDirDialog
++sL; ++rI;
} }
m_Aliases->AutoSize(); m_Aliases->AutoSize();

View File

@ -22,6 +22,7 @@
*/ */
#include <set>
#include "dlg_select_3dmodel.h" #include "dlg_select_3dmodel.h"
#include "project.h" #include "project.h"
#include "3d_cache/3d_info.h" #include "3d_cache/3d_info.h"
@ -240,12 +241,20 @@ void DLG_SELECT_3DMODEL::updateDirChoiceList( void )
std::list< S3D_ALIAS > const* md = m_resolver->GetPaths(); std::list< S3D_ALIAS > const* md = m_resolver->GetPaths();
std::list< S3D_ALIAS >::const_iterator sL = md->begin(); std::list< S3D_ALIAS >::const_iterator sL = md->begin();
std::list< S3D_ALIAS >::const_iterator eL = md->end(); std::list< S3D_ALIAS >::const_iterator eL = md->end();
std::vector< wxString > cl; std::set< wxString > cl;
wxString prjDir;
// extract the current project dir
if( sL != eL )
{
prjDir = sL->m_pathexp;
++sL;
}
while( sL != eL ) while( sL != eL )
{ {
if( !sL->m_pathexp.empty() && !sL->m_duplicate ) if( !sL->m_pathexp.empty() && sL->m_pathexp.compare( prjDir ) )
cl.push_back( sL->m_pathexp ); cl.insert( sL->m_pathexp );
++sL; ++sL;
} }
@ -253,7 +262,19 @@ void DLG_SELECT_3DMODEL::updateDirChoiceList( void )
if( !cl.empty() ) if( !cl.empty() )
{ {
dirChoices->Clear(); dirChoices->Clear();
dirChoices->Append( (int)cl.size(), &cl[0] );
if( !prjDir.empty() )
dirChoices->Append( prjDir );
std::set< wxString >::const_iterator sI = cl.begin();
std::set< wxString >::const_iterator eI = cl.end();
while( sI != eI )
{
dirChoices->Append( *sI );
++sI;
}
dirChoices->Select( 0 ); dirChoices->Select( 0 );
} }

View File

@ -75,6 +75,7 @@ DIALOG_MODULE_BOARD_EDITOR::DIALOG_MODULE_BOARD_EDITOR( PCB_EDIT_FRAME* aParent
m_OrientValueCtrl->SetValidator( m_OrientValidator ); m_OrientValueCtrl->SetValidator( m_OrientValidator );
m_OrientValidator.SetWindow( m_OrientValueCtrl ); m_OrientValidator.SetWindow( m_OrientValueCtrl );
aParent->Prj().Get3DCacheManager()->GetResolver()->SetProgramBase( &Pgm() );
m_PreviewPane = new PANEL_PREV_3D( m_Panel3D, aParent->Prj().Get3DCacheManager() ); m_PreviewPane = new PANEL_PREV_3D( m_Panel3D, aParent->Prj().Get3DCacheManager() );
bLowerSizer3D->Add( m_PreviewPane, 1, wxEXPAND, 5 ); bLowerSizer3D->Add( m_PreviewPane, 1, wxEXPAND, 5 );

View File

@ -50,6 +50,7 @@
#include <module_editor_frame.h> #include <module_editor_frame.h>
#include <dialog_edit_module_for_Modedit.h> #include <dialog_edit_module_for_Modedit.h>
#include <wildcards_and_files_ext.h> #include <wildcards_and_files_ext.h>
#include <pgm_base.h>
#include "3d_cache/dialogs/panel_prev_model.h" #include "3d_cache/dialogs/panel_prev_model.h"
#include "3d_cache/dialogs/3d_cache_dialogs.h" #include "3d_cache/dialogs/3d_cache_dialogs.h"
#include "3d_cache/3d_cache.h" #include "3d_cache/3d_cache.h"
@ -70,6 +71,7 @@ DIALOG_MODULE_MODULE_EDITOR::DIALOG_MODULE_MODULE_EDITOR( FOOTPRINT_EDIT_FRAME*
icon.CopyFromBitmap( KiBitmap( icon_modedit_xpm ) ); icon.CopyFromBitmap( KiBitmap( icon_modedit_xpm ) );
SetIcon( icon ); SetIcon( icon );
aParent->Prj().Get3DCacheManager()->GetResolver()->SetProgramBase( &Pgm() );
m_PreviewPane = new PANEL_PREV_3D( m_Panel3D, aParent->Prj().Get3DCacheManager() ); m_PreviewPane = new PANEL_PREV_3D( m_Panel3D, aParent->Prj().Get3DCacheManager() );
bLowerSizer3D->Add( m_PreviewPane, 1, wxEXPAND, 5 ); bLowerSizer3D->Add( m_PreviewPane, 1, wxEXPAND, 5 );