diff options
Diffstat (limited to 'common/project.cpp')
-rw-r--r-- | common/project.cpp | 381 |
1 files changed, 381 insertions, 0 deletions
diff --git a/common/project.cpp b/common/project.cpp new file mode 100644 index 0000000..a6b7546 --- /dev/null +++ b/common/project.cpp @@ -0,0 +1,381 @@ + +/* + * This program source code file is part of KiCad, a free EDA CAD application. + * + * Copyright (C) 2014 KiCad Developers, see CHANGELOG.TXT for contributors. + * + * This program is free software; you can redistribute it and/or + * modify it under the terms of the GNU General Public License + * as published by the Free Software Foundation; either version 2 + * of the License, or (at your option) any later version. + * + * This program is distributed in the hope that it will be useful, + * but WITHOUT ANY WARRANTY; without even the implied warranty of + * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the + * GNU General Public License for more details. + * + * You should have received a copy of the GNU General Public License + * along with this program; if not, you may find one here: + * http://www.gnu.org/licenses/old-licenses/gpl-2.0.html + * or you may search the http://www.gnu.org website for the version 2 license, + * or you may write to the Free Software Foundation, Inc., + * 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301, USA + */ + + +#include <wx/stdpaths.h> + +#include <fctsys.h> +#include <macros.h> +#include <pgm_base.h> +#include <project.h> +#include <common.h> // NAMELESS_PROJECT +#include <confirm.h> +#include <kicad_string.h> +#include <config_params.h> +#include <wildcards_and_files_ext.h> + + +PROJECT::PROJECT() +{ + memset( m_elems, 0, sizeof(m_elems) ); +} + + +void PROJECT::ElemsClear() +{ + DBG( printf( "%s: clearing all _ELEMS for project %s\n", __func__, TO_UTF8( GetProjectFullName() ) );) + + // careful here, this should work, but the virtual destructor may not + // be in the same link image as PROJECT. + for( unsigned i = 0; i < DIM( m_elems ); ++i ) + { + SetElem( ELEM_T( i ), NULL ); + } +} + + +PROJECT::~PROJECT() +{ + ElemsClear(); +} + + +void PROJECT::SetProjectFullName( const wxString& aFullPathAndName ) +{ + // Compare paths, rather than inodes, to be less surprising to the user. + // Create a temporary wxFileName to normalize the path + wxFileName candidate_path( aFullPathAndName ); + + // Edge transitions only. This is what clears the project + // data using the Clear() function. + if( m_project_name.GetFullPath() != candidate_path.GetFullPath() ) + { + Clear(); // clear the data when the project changes. + + DBG(printf( "%s: old:'%s' new:'%s'\n", __func__, TO_UTF8( GetProjectFullName() ), TO_UTF8( aFullPathAndName ) );) + + m_project_name = aFullPathAndName; + + wxASSERT( m_project_name.IsAbsolute() ); + + wxASSERT( m_project_name.GetExt() == ProjectFileExtension ); + + // until multiple projects are in play, set an environment variable for the + // the project pointer. + { + wxString path = m_project_name.GetPath(); + + wxSetEnv( PROJECT_VAR_NAME, path ); + } + } +} + + +const wxString PROJECT::GetProjectFullName() const +{ + return m_project_name.GetFullPath(); +} + + +const wxString PROJECT::GetProjectPath() const +{ + return m_project_name.GetPathWithSep(); +} + + +const wxString PROJECT::GetProjectName() const +{ + return m_project_name.GetName(); +} + + +const wxString PROJECT::FootprintLibTblName() const +{ + wxFileName fn = GetProjectFullName(); + wxString path = fn.GetPath(); + + // DBG(printf( "path:'%s' fn:'%s'\n", TO_UTF8(path), TO_UTF8(fn.GetFullPath()) );) + + // if there's no path to the project name, or the name as a whole is bogus or its not + // write-able then use a template file. + if( !fn.GetDirCount() || !fn.IsOk() || !wxFileName::IsDirWritable( path ) ) + { + // return a template filename now. + + // this next line is likely a problem now, since it relies on an + // application title which is no longer constant or known. This next line needs + // to be re-thought out. + +#ifndef __WXMAC__ + fn.AssignDir( wxStandardPaths::Get().GetUserConfigDir() ); +#else + // don't pollute home folder, temp folder seems to be more appropriate + fn.AssignDir( wxStandardPaths::Get().GetTempDir() ); +#endif + +#if defined( __WINDOWS__ ) + fn.AppendDir( wxT( "kicad" ) ); +#endif + + /* + The footprint library table name used when no project file is passed + to Pcbnew or CvPcb. This is used temporarily to store the project + specific library table until the project file being edited is saved. + It is then moved to the file fp-lib-table in the folder where the + project file is saved. + */ + fn.SetName( wxT( "prj-fp-lib-table" ) ); + } + else // normal path. + { + fn.SetName( wxT( "fp-lib-table" ) ); + } + + fn.ClearExt(); + + return fn.GetFullPath(); +} + + +void PROJECT::SetRString( RSTRING_T aIndex, const wxString& aString ) +{ + unsigned ndx = unsigned( aIndex ); + + if( ndx < DIM( m_rstrings ) ) + { + m_rstrings[ndx] = aString; + } + else + { + wxASSERT( 0 ); // bad index + } +} + + +const wxString& PROJECT::GetRString( RSTRING_T aIndex ) +{ + unsigned ndx = unsigned( aIndex ); + + if( ndx < DIM( m_rstrings ) ) + { + return m_rstrings[ndx]; + } + else + { + static wxString no_cookie_for_you; + + wxASSERT( 0 ); // bad index + + return no_cookie_for_you; + } +} + + +PROJECT::_ELEM* PROJECT::GetElem( ELEM_T aIndex ) +{ + // This is virtual, so implement it out of line + + if( unsigned( aIndex ) < DIM( m_elems ) ) + { + return m_elems[aIndex]; + } + return NULL; +} + + +void PROJECT::SetElem( ELEM_T aIndex, _ELEM* aElem ) +{ + // This is virtual, so implement it out of line + + if( unsigned( aIndex ) < DIM( m_elems ) ) + { +#if defined(DEBUG) && 0 + if( aIndex == ELEM_SCH_PART_LIBS ) + { + printf( "%s: &m_elems[%i]:%p aElem:%p\n", __func__, aIndex, &m_elems[aIndex], aElem ); + } +#endif + delete m_elems[aIndex]; + m_elems[aIndex] = aElem; + } +} + + +static bool copy_pro_file_template( const SEARCH_STACK& aSearchS, const wxString& aDestination ) +{ + if( aDestination.IsEmpty() ) + { + DBG( printf( "%s: destination is empty.\n", __func__ );) + return false; + } + + wxString templateFile = wxT( "kicad." ) + ProjectFileExtension; + + wxString kicad_pro_template = aSearchS.FindValidPath( templateFile ); + + if( !kicad_pro_template ) + { + DBG( printf( "%s: template file '%s' not found using search paths.\n", __func__, TO_UTF8( templateFile ) );) + + wxFileName templ( wxStandardPaths::Get().GetDocumentsDir(), + wxT( "kicad" ), ProjectFileExtension ); + + if( !templ.IsFileReadable() ) + { + wxString msg = wxString::Format( _( + "Unable to find '%s' template config file." ), + GetChars( templateFile ) ); + + DisplayError( NULL, msg ); + + return false; + } + + kicad_pro_template = templ.GetFullPath(); + } + + DBG( printf( "%s: using template file '%s' as project file.\n", __func__, TO_UTF8( kicad_pro_template ) );) + + // Verify aDestination can be created. if this is not the case, wxCopyFile + // will generate a crappy log error message, and we *do not want* this kind + // of stupid message + wxFileName fn( aDestination ); + bool success = true; + + if( fn.IsOk() && fn.IsDirWritable() ) + success = wxCopyFile( kicad_pro_template, aDestination ); + else + { + wxLogMessage( _( "Cannot create prj file '%s' (Directory not writable)" ), + GetChars( aDestination) ); + success = false; + } + + return success; +} + + +wxConfigBase* PROJECT::configCreate( const SEARCH_STACK& aSList, + const wxString& aGroupName, const wxString& aProjectFileName ) +{ + wxConfigBase* cfg = 0; + wxString cur_pro_fn = !aProjectFileName ? GetProjectFullName() : aProjectFileName; + + if( wxFileName( cur_pro_fn ).IsFileReadable() ) + { + // Note: currently, aGroupName is not used. + // Previoulsy, the version of aGroupName was tested, but it + // was useless, and if the version is important, + // this is not the right place here, because configCreate does know anything + // about info stored in this config file. + cfg = new wxFileConfig( wxEmptyString, wxEmptyString, cur_pro_fn, wxEmptyString ); + return cfg; + } + + // No suitable pro file was found, either does not exist, or not readable. + // Use the template kicad.pro file. Find it by using caller's SEARCH_STACK. + copy_pro_file_template( aSList, cur_pro_fn ); + + cfg = new wxFileConfig( wxEmptyString, wxEmptyString, cur_pro_fn, wxEmptyString ); + + return cfg; +} + + +void PROJECT::ConfigSave( const SEARCH_STACK& aSList, const wxString& aGroupName, + const PARAM_CFG_ARRAY& aParams, const wxString& aFileName ) +{ + std::auto_ptr<wxConfigBase> cfg( configCreate( aSList, aGroupName, aFileName ) ); + + if( !cfg.get() ) + { + // could not find template + return; + } + + cfg->SetPath( wxT( "/" ) ); + + cfg->Write( wxT( "update" ), DateAndTime() ); + + // @todo: pass in aLastClient wxString: + cfg->Write( wxT( "last_client" ), Pgm().App().GetAppName() ); + + // Save parameters + cfg->DeleteGroup( aGroupName ); // Erase all data + cfg->Flush(); + + cfg->SetPath( aGroupName ); + cfg->Write( wxT( "version" ), CONFIG_VERSION ); + + cfg->SetPath( wxT( "/" ) ); + + wxConfigSaveParams( cfg.get(), aParams, aGroupName ); + + cfg->SetPath( wxT( "/" ) ); + + // cfg is deleted here by std::auto_ptr, that saves the *.pro file to disk +} + + +bool PROJECT::ConfigLoad( const SEARCH_STACK& aSList, const wxString& aGroupName, + const PARAM_CFG_ARRAY& aParams, const wxString& aForeignProjectFileName ) +{ + std::auto_ptr<wxConfigBase> cfg( configCreate( aSList, aGroupName, aForeignProjectFileName ) ); + + if( !cfg.get() ) + { + // could not find template + return false; + } + + cfg->SetPath( wxCONFIG_PATH_SEPARATOR ); + + wxString timestamp = cfg->Read( wxT( "update" ) ); + + m_pro_date_and_time = timestamp; + + // We do not want expansion of env var values when reading our project config file + bool state = cfg.get()->IsExpandingEnvVars(); + cfg.get()->SetExpandEnvVars( false ); + + wxConfigLoadParams( cfg.get(), aParams, aGroupName ); + + cfg.get()->SetExpandEnvVars( state ); + + return true; +} + + +const wxString PROJECT::AbsolutePath( const wxString& aFileName ) const +{ + wxFileName fn = aFileName; + + if( !fn.IsAbsolute() ) + { + wxString pro_dir = wxPathOnly( GetProjectFullName() ); + fn.Normalize( wxPATH_NORM_ALL, pro_dir ); + } + + return fn.GetFullPath(); +} |