Commit 7e483f69 authored by Dick Hollenbeck's avatar Dick Hollenbeck

Modular KiCad Blueprint Milestone B), major portions:

  *) When kicad.exe closes a project, close any open KIFACEs so that they cannot
     get disassociated from their true PROJECT.
  *) Allow loading eeschema library editor from kicad.exe
  *) Allow loading pcbnew library editor from kicad.exe
  *) Rename LIB_COMPONENT to LIB_PART.
  *) Add class PART_LIBS, and PART_LIB.
  *) Make PART_LIBS non-global, i.e. PROJECT specific.
  *) Implement "data on demand" for PART_LIBS
  *) Implement "data on demand" for schematic SEARCH_STACK.
  *) Use RSTRINGs to retain eeschema editor's notion of last library and part being edited.
  *) Get rid of library search on every SCH_COMPONENT::Draw() call, instead use
     a weak pointer.
  *) Remove all chdir() calls so projects don't need to be CWD.
  *) Romove APPEND support from OpenProjectFiles().
  *) Make OpenProjectFiles() robust, even for creating new projects.
  *) Load EESCHEMA colors in the KIWAY::OnKiwayStart() rather in window open,
     and save them in the .eeschema config file, not in the project file.
  *) Fix bug with wxDir() while accessing protected dirs in kicad.exe
  *) Consolidate template copying into PROJECT class, not in kicad.exe source.
  *) Generally untangle eeschema, making its libraries not global but rather
     held in the PROJECT.
parent c6345965
......@@ -64,18 +64,13 @@ PCBNew
Dick's Final TODO List:
======================
*) Get licensing cleaned up.
*) DLL-ization of pcbnew & eeschema
http://www.eevblog.com/forum/open-source-kicad-geda/seriously-irritated-with-the-library-editor!/
https://blueprints.launchpad.net/kicad/+spec/modular-kicad
Issues as a result of minimal testing:
* If eeschema launched from C++ project manager and does not find all libraries,
then the dialog showing the names of missing libraries is shown twice.
*) Milestone B of Modular KiCad Blueprint:
* Put SEARCH_STACK::LastVisitedPath() out of its misery.
* Combine CVPCB into PCBNEW.
* Clear all/some? retained strings on project change.
* Clear the FP_LIB_TABLE when the last KIWAY_PLAYER using it is closed.
*) Milestone C of Modular KiCad Blueprint
* SWIG class KIWAY, PROJECT, and KIWAY_MGR and fill out KIWAY_MGR as needed.
* Implement PROJECT::Substitute().
* Other stuff in blueprint milestone.
Fix export gencad
\ No newline at end of file
*) Get licensing cleaned up.
......@@ -40,8 +40,8 @@
#include <boost/foreach.hpp>
void wxConfigSaveParams( wxConfigBase* aCfg,
const PARAM_CFG_ARRAY& aList, const wxString& aGroup )
void wxConfigLoadParams( wxConfigBase* aCfg,
const PARAM_CFG_ARRAY& aList, const wxString& aGroup )
{
wxASSERT( aCfg );
......@@ -55,32 +55,18 @@ void wxConfigSaveParams( wxConfigBase* aCfg,
if( param.m_Setup )
continue;
if( param.m_Type == PARAM_COMMAND_ERASE ) // Erase all data
{
if( !!param.m_Ident )
aCfg->DeleteGroup( param.m_Ident );
}
else
{
param.SaveParam( aCfg );
}
param.ReadParam( aCfg );
}
}
void wxConfigLoadParams( wxConfigBase* aCfg,
const PARAM_CFG_ARRAY& aList, const wxString& aGroup )
void wxConfigLoadSetups( wxConfigBase* aCfg, const PARAM_CFG_ARRAY& aList )
{
wxASSERT( aCfg );
BOOST_FOREACH( const PARAM_CFG_BASE& param, aList )
{
if( !!param.m_Group )
aCfg->SetPath( param.m_Group );
else
aCfg->SetPath( aGroup );
if( param.m_Setup )
if( !param.m_Setup )
continue;
param.ReadParam( aCfg );
......@@ -88,13 +74,19 @@ void wxConfigLoadParams( wxConfigBase* aCfg,
}
void wxConfigSaveSetups( wxConfigBase* aCfg, const PARAM_CFG_ARRAY& aList )
void wxConfigSaveParams( wxConfigBase* aCfg,
const PARAM_CFG_ARRAY& aList, const wxString& aGroup )
{
wxASSERT( aCfg );
BOOST_FOREACH( const PARAM_CFG_BASE& param, aList )
{
if( !param.m_Setup )
if( !!param.m_Group )
aCfg->SetPath( param.m_Group );
else
aCfg->SetPath( aGroup );
if( param.m_Setup )
continue;
if( param.m_Type == PARAM_COMMAND_ERASE ) // Erase all data
......@@ -110,7 +102,7 @@ void wxConfigSaveSetups( wxConfigBase* aCfg, const PARAM_CFG_ARRAY& aList )
}
void wxConfigLoadSetups( wxConfigBase* aCfg, const PARAM_CFG_ARRAY& aList )
void wxConfigSaveSetups( wxConfigBase* aCfg, const PARAM_CFG_ARRAY& aList )
{
wxASSERT( aCfg );
......@@ -119,12 +111,19 @@ void wxConfigLoadSetups( wxConfigBase* aCfg, const PARAM_CFG_ARRAY& aList )
if( !param.m_Setup )
continue;
param.ReadParam( aCfg );
if( param.m_Type == PARAM_COMMAND_ERASE ) // Erase all data
{
if( !!param.m_Ident )
aCfg->DeleteGroup( param.m_Ident );
}
else
{
param.SaveParam( aCfg );
}
}
}
void ConfigBaseWriteDouble( wxConfigBase* aConfig, const wxString& aKey, double aValue )
{
// Use a single strategy, regardless of wx version.
......
......@@ -62,8 +62,7 @@ DIALOG_SHIM::DIALOG_SHIM( wxWindow* aParent, wxWindowID id, const wxString& titl
// pray that aParent is either a KIWAY_PLAYER or DIALOG_SHIM derivation.
KIWAY_HOLDER* h = dynamic_cast<KIWAY_HOLDER*>( aParent );
wxASSERT_MSG( h,
wxT( "DIALOG_SHIM's parent is NULL or not derived from KIWAY_PLAYER nor DIALOG_SHIM" ) );
// wxASSERT_MSG( h, wxT( "DIALOG_SHIM's parent is NULL or not derived from KIWAY_PLAYER nor DIALOG_SHIM" ) );
if( h )
SetKiway( this, &h->Kiway() );
......
......@@ -28,6 +28,7 @@
#include <fctsys.h>
#include <macros.h> // DIM()
#include <common.h>
#include <project.h>
#include <confirm.h>
#include <gr_basic.h>
#include <base_struct.h>
......@@ -781,9 +782,11 @@ void DIALOG_PAGES_SETTINGS::GetCustomSizeMilsFromDialog()
// Called on .kicad_wks file description selection change
void DIALOG_PAGES_SETTINGS::OnWksFileSelection( wxCommandEvent& event )
{
wxString pro_dir = wxPathOnly( Prj().GetProjectFullName() );
// Display a file picker dialog
wxFileDialog fileDialog( this, _( "Select Page Layout Descr File" ),
wxGetCwd(), GetWksFileName(),
pro_dir, GetWksFileName(),
PageLayoutDescrFileWildcard,
wxFD_DEFAULT_STYLE | wxFD_FILE_MUST_EXIST );
......@@ -800,11 +803,14 @@ void DIALOG_PAGES_SETTINGS::OnWksFileSelection( wxCommandEvent& event )
// For Win/Linux/macOS compatibility, a relative path is a good idea
if( fn.IsAbsolute() && fileName != GetWksFileName() )
{
fn.MakeRelativeTo( wxGetCwd() );
wxString msg;
msg.Printf( _( "The page layout descr filename has changed\n"
"Do you want to use the relative path:\n%s"),
fn.GetFullPath().GetData() );
fn.MakeRelativeTo( pro_dir );
wxString msg = wxString::Format( _(
"The page layout descr filename has changed.\n"
"Do you want to use the relative path:\n"
"'%s'" ),
GetChars( fn.GetFullPath() )
);
if( IsOK( this, msg ) )
shortFileName = fn.GetFullPath();
}
......
......@@ -37,12 +37,14 @@ EDA_LIST_DIALOG::EDA_LIST_DIALOG( EDA_DRAW_FRAME* aParent, const wxString& aTitl
const wxArrayString& aItemHeaders,
const std::vector<wxArrayString>& aItemList,
const wxString& aSelection,
void( *aCallBackFunction )( wxString& ),
void( *aCallBackFunction )( wxString&, void* ),
void* aCallBackFunctionData,
bool aSortList ) :
EDA_LIST_DIALOG_BASE( aParent, wxID_ANY, aTitle )
{
m_sortList = aSortList;
m_callBackFct = aCallBackFunction;
m_cb_func = aCallBackFunction;
m_cb_data = aCallBackFunctionData;
m_itemsListCp = &aItemList;
for( unsigned i = 0; i < aItemHeaders.Count(); i++ )
......@@ -57,7 +59,7 @@ EDA_LIST_DIALOG::EDA_LIST_DIALOG( EDA_DRAW_FRAME* aParent, const wxString& aTitl
InsertItems( aItemList, 0 );
if( m_callBackFct == NULL )
if( m_cb_func == NULL )
{
m_messages->Show( false );
m_staticTextMsg->Show( false );
......@@ -231,12 +233,11 @@ void EDA_LIST_DIALOG::onCancelClick( wxCommandEvent& event )
void EDA_LIST_DIALOG::onListItemSelected( wxListEvent& event )
{
if( m_callBackFct )
if( m_cb_func )
{
m_messages->Clear();
wxString text = GetTextSelection();
m_callBackFct( text );
m_cb_func( text, m_cb_data );
m_messages->WriteText( text );
}
}
......
......@@ -659,7 +659,7 @@ void EDA_DRAW_FRAME::AppendMsgPanel( const wxString& textUpper,
}
void EDA_DRAW_FRAME::ClearMsgPanel( void )
void EDA_DRAW_FRAME::ClearMsgPanel()
{
if( m_messagePanel == NULL )
return;
......
......@@ -41,100 +41,6 @@
#include <wx/filename.h>
#include <wx/dir.h>
/* List of default paths used to locate help files and KiCad library files.
*
* Under windows, KiCad search its files from the binary path file (first
* argument when running "main") So for a standard install, default paths
* are not mandatory, but they exist, just in case.
* KiCad is often installed in c:/Program Files/kicad or c:/kicad (or d: or
* e: ... ) and the directory "share" has no meaning under windows.
*
* Under linux, the problem is more complex.
* In fact there are 3 cases:
* 1 - When released in a distribution:
* binaries are in /usr/bin, KiCad libs in /usr/share/kicad/ and doc in
* /usr/share/doc/kicad/
* 2 - When compiled by an user:
* binaries also can be in /usr/local/bin, KiCad libs in
* /usr/local/share/kicad/ and doc in /usr/local/share/doc/kicad/
* 3 - When in an "universal tarball" or build for a server:
* all files are in /usr/local/kicad
* This is mandatory when KiCad is installed on a server (in a school for
* instance) because one can export /usr/local/kicad and obviously the others
* paths cannot be used (cannot be mounted by the client, because they are
* already used).
*
* in cases 1 and 2 KiCad files cannot be found from the binary path.
* in case 3 KiCad files can be found from the binary path only if this is
* a KiCad binary file which is launched.
* But if an user creates a symbolic link to the actual binary file to run
* KiCad, the binary path is not good and the defaults paths must be used
*
* Note:
* KiCad uses first the bin path lo locate KiCad tree.
* if not found KiCad uses the environment variable KICAD to find its files
* and at last KiCad uses the default paths.
* So we can export (linux and windows) the variable KICAD:
* like export KICAD=/my_path/kicad if /my_path/kicad is not a default path
*/
wxString MakeReducedFileName( const wxString& fullfilename,
const wxString& default_path,
const wxString& default_ext )
{
wxString reduced_filename = fullfilename;
wxString Cwd, ext, path;
Cwd = default_path;
ext = default_ext;
path = wxPathOnly( reduced_filename ) + UNIX_STRING_DIR_SEP;
reduced_filename.Replace( WIN_STRING_DIR_SEP, UNIX_STRING_DIR_SEP );
Cwd.Replace( WIN_STRING_DIR_SEP, UNIX_STRING_DIR_SEP );
if( Cwd.Last() != '/' )
Cwd += UNIX_STRING_DIR_SEP;
path.Replace( WIN_STRING_DIR_SEP, UNIX_STRING_DIR_SEP );
#ifdef __WINDOWS__
// names are case insensitive under windows
path.MakeLower();
Cwd.MakeLower();
ext.MakeLower();
#endif
// if the path is "default_path" -> remove it
wxString root_path = path.Left( Cwd.Length() );
if( root_path == Cwd )
{
reduced_filename.Remove( 0, Cwd.Length() );
}
else // if the path is the current path -> change path to ./
{
Cwd = wxGetCwd() + UNIX_STRING_DIR_SEP;
#ifdef __WINDOWS__
Cwd.MakeLower();
#endif
Cwd.Replace( WIN_STRING_DIR_SEP, UNIX_STRING_DIR_SEP );
if( path == Cwd )
{ // the path is the current path -> path = "./"
reduced_filename.Remove( 0, Cwd.Length() );
wxString tmp = wxT( "./" ) + reduced_filename;
reduced_filename = tmp;
}
}
// remove extension if == default_ext:
if( !ext.IsEmpty() && reduced_filename.Contains( ext ) )
reduced_filename.Truncate( reduced_filename.Length() - ext.Length() );
return reduced_filename;
}
void AddDelimiterString( wxString& string )
{
......
......@@ -676,16 +676,17 @@ void ParseHotkeyConfig( const wxString& data,
}
/**
* Function ImportHotkeyConfigFromFile
* Prompt the user for an old hotkey file to read, and read it.
* @param aDescList = current hotkey list descr. to initialize.
*/
void EDA_BASE_FRAME::ImportHotkeyConfigFromFile( struct EDA_HOTKEY_CONFIG* aDescList )
void EDA_BASE_FRAME::ImportHotkeyConfigFromFile( EDA_HOTKEY_CONFIG* aDescList )
{
wxString ext = DEFAULT_HOTKEY_FILENAME_EXT;
wxString mask = wxT( "*." ) + ext;
#if 0 // pass in the project dir as an argument
wxString path = wxPathOnly( Prj().GetProjectFullName() );
#else
wxString path = wxGetCwd();
#endif
wxString filename = Kiface().Name() + wxT( '.' ) + ext;
filename = EDA_FileSelector( _( "Read Hotkey Configuration File:" ),
......@@ -704,16 +705,17 @@ void EDA_BASE_FRAME::ImportHotkeyConfigFromFile( struct EDA_HOTKEY_CONFIG* aDesc
}
/**
* Function ExportHotkeyConfigToFile
* Prompt the user for an old hotkey file to read, and read it.
* @param aDescList = current hotkey list descr. to initialize.
*/
void EDA_BASE_FRAME::ExportHotkeyConfigToFile( struct EDA_HOTKEY_CONFIG* aDescList )
void EDA_BASE_FRAME::ExportHotkeyConfigToFile( EDA_HOTKEY_CONFIG* aDescList )
{
wxString ext = DEFAULT_HOTKEY_FILENAME_EXT;
wxString mask = wxT( "*." ) + ext;
#if 0
wxString path = wxPathOnly( Prj().GetProjectFullName() );
#else
wxString path = wxGetCwd();
#endif
wxString filename = Kiface().Name() + wxT( "." ) + ext;
filename = EDA_FileSelector( _( "Write Hotkey Configuration File:" ),
......
......@@ -364,6 +364,8 @@ bool PGM_BASE::initPgm()
{
wxFileName pgm_name( App().argv[0] );
wxConfigBase::DontCreateOnDemand();
wxInitAllImageHandlers();
m_pgm_checker = new wxSingleInstanceChecker( pgm_name.GetName().Lower() + wxT( "-" ) + wxGetUserId() );
......@@ -536,7 +538,9 @@ void PGM_BASE::saveCommonSettings()
// process startup: initPgm(), so test before using:
if( m_common_settings )
{
m_common_settings->Write( workingDirKey, wxGetCwd() );
wxString cur_dir = wxGetCwd();
m_common_settings->Write( workingDirKey, cur_dir );
}
}
......
This diff is collapsed.
......@@ -11,17 +11,39 @@
#endif
wxString SEARCH_STACK::FilenameWithRelativePathInSearchList( const wxString& aFullFilename )
int SEARCH_STACK::Split( wxArrayString* aResult, const wxString aPathString )
{
wxStringTokenizer tokenizer( aPathString, PATH_SEPS, wxTOKEN_STRTOK );
while( tokenizer.HasMoreTokens() )
{
wxString path = tokenizer.GetNextToken();
aResult->Add( path );
}
return aResult->GetCount();
}
// Convert aRelativePath to an absolute path based on aBaseDir
static wxString base_dir( const wxString& aRelativePath, const wxString& aBaseDir )
{
wxFileName fn = aRelativePath;
if( !fn.IsAbsolute() && !!aBaseDir )
{
wxASSERT_MSG( wxFileName( aBaseDir ).IsAbsolute(), wxT( "Must pass absolute path in aBaseDir" ) );
fn.MakeRelativeTo( aBaseDir );
}
return fn.GetFullPath();
}
wxString SEARCH_STACK::FilenameWithRelativePathInSearchList(
const wxString& aFullFilename, const wxString& aBaseDir )
{
/* If the library path is already in the library search paths
* list, just add the library name to the list. Otherwise, add
* the library name with the full or relative path.
* the relative path, when possible is preferable,
* because it preserve use of default libraries paths, when the path is a sub path of
* these default paths
* Note we accept only sub paths,
* not relative paths starting by ../ that are not subpaths and are outside kicad libs paths
*/
wxFileName fn = aFullFilename;
wxString filename = aFullFilename;
......@@ -33,7 +55,7 @@ wxString SEARCH_STACK::FilenameWithRelativePathInSearchList( const wxString& aFu
fn = aFullFilename;
// Search for the shortest subpath within 'this':
if( fn.MakeRelativeTo( (*this)[kk] ) )
if( fn.MakeRelativeTo( base_dir( (*this)[kk], aBaseDir ) ) )
{
if( fn.GetPathWithSep().StartsWith( wxT("..") ) ) // Path outside kicad libs paths
continue;
......@@ -52,13 +74,16 @@ wxString SEARCH_STACK::FilenameWithRelativePathInSearchList( const wxString& aFu
void SEARCH_STACK::RemovePaths( const wxString& aPaths )
{
wxStringTokenizer tokenizer( aPaths, PATH_SEPS, wxTOKEN_STRTOK );
bool isCS = wxFileName::IsCaseSensitive();
wxArrayString paths;
while( tokenizer.HasMoreTokens() )
Split( &paths, aPaths );
for( unsigned i=0; i<paths.GetCount(); ++i )
{
wxString path = tokenizer.GetNextToken();
wxString path = paths[i];
if( Index( path, wxFileName::IsCaseSensitive() ) != wxNOT_FOUND )
if( Index( path, isCS ) != wxNOT_FOUND )
{
Remove( path );
}
......@@ -68,15 +93,17 @@ void SEARCH_STACK::RemovePaths( const wxString& aPaths )
void SEARCH_STACK::AddPaths( const wxString& aPaths, int aIndex )
{
bool isCS = wxFileName::IsCaseSensitive();
wxStringTokenizer tokenizer( aPaths, PATH_SEPS, wxTOKEN_STRTOK );
bool isCS = wxFileName::IsCaseSensitive();
wxArrayString paths;
Split( &paths, aPaths );
// appending all of them, on large or negative aIndex
if( unsigned( aIndex ) >= GetCount() )
{
while( tokenizer.HasMoreTokens() )
for( unsigned i=0; i<paths.GetCount(); ++i )
{
wxString path = tokenizer.GetNextToken();
wxString path = paths[i];
if( wxFileName::IsDirReadable( path )
&& Index( path, isCS ) == wxNOT_FOUND )
......@@ -89,9 +116,9 @@ void SEARCH_STACK::AddPaths( const wxString& aPaths, int aIndex )
// inserting all of them:
else
{
while( tokenizer.HasMoreTokens() )
for( unsigned i=0; i<paths.GetCount(); ++i )
{
wxString path = tokenizer.GetNextToken();
wxString path = paths[i];
if( wxFileName::IsDirReadable( path )
&& Index( path, isCS ) == wxNOT_FOUND )
......@@ -104,6 +131,8 @@ void SEARCH_STACK::AddPaths( const wxString& aPaths, int aIndex )
}
#if 1 // this function is too convoluted for words.
const wxString SEARCH_STACK::LastVisitedPath( const wxString& aSubPathToSearch )
{
wxString path;
......@@ -142,6 +171,7 @@ const wxString SEARCH_STACK::LastVisitedPath( const wxString& aSubPathToSearch )
return path;
}
#endif
#if defined(DEBUG)
......
......@@ -270,20 +270,6 @@ bool PGM_SINGLE_TOP::OnPgmInit( wxApp* aWxApp )
argv1.MakeAbsolute();
argSet[0] = argv1.GetFullPath();
if( !Pgm().LockFile( argSet[0] ) )
{
wxLogSysError( _( "This file is already open." ) );
return false;
}
}
// @todo: setting CWD is taboo in a multi-project environment, this
// will not be possible soon.
if( argv1.GetPath().size() ) // path only
{
// wxSetWorkingDirectory() does not like empty paths
wxSetWorkingDirectory( argv1.GetPath() );
}
// Use the KIWAY_PLAYER::OpenProjectFiles() API function:
......@@ -298,24 +284,6 @@ bool PGM_SINGLE_TOP::OnPgmInit( wxApp* aWxApp )
return false;
}
}
else
{
/*
The lean single_top program launcher has no access to program
settings, for if it did, it would not be lean. That kind of
functionality is in the KIFACE now, but it cannot assume that it is
the only KIFACE in memory. So this looks like a dead concept here,
or an expensive one in terms of code size.
wxString dir;
if( m_pgmSettings->Read( workingDirKey, &dir ) && wxDirExists( dir ) )
{
wxSetWorkingDirectory( dir );
}
*/
}
frame->Show();
......
......@@ -29,6 +29,7 @@
#include <fctsys.h>
#include <common.h>
#include <kiface_i.h>
#include <project.h>
#include <confirm.h>
#include <gestfich.h>
......@@ -91,7 +92,8 @@ void CVPCB_MAINFRAME::AssocieModule( wxCommandEvent& event )
char Line[1024];
FILE* file;
size_t ii;
SEARCH_STACK& search = Prj().SchSearchS();
SEARCH_STACK& search = Kiface().KifaceSearch();
if( m_netlist.IsEmpty() )
return;
......
......@@ -59,30 +59,25 @@ PARAM_CFG_ARRAY& CVPCB_MAINFRAME::GetProjectFileParameters()
}
void CVPCB_MAINFRAME::LoadProjectFile( const wxString& aFileName )
void CVPCB_MAINFRAME::LoadProjectFile()
{
wxFileName fn( aFileName );
PROJECT& prj = Prj();
PROJECT& prj = Prj();
m_ModuleLibNames.Clear();
m_AliasLibNames.Clear();
fn.SetExt( ProjectFileExtension );
// was: Pgm().ReadProjectConfig( fn.GetFullPath(), GROUP, GetProjectFileParameters(), false );
prj.ConfigLoad( Kiface().KifaceSearch(), fn.GetFullPath(), GROUP_CVP, GetProjectFileParameters(), false );
prj.ConfigLoad( Kiface().KifaceSearch(), GROUP_CVP, GetProjectFileParameters() );
if( m_NetlistFileExtension.IsEmpty() )
m_NetlistFileExtension = wxT( "net" );
// Force FP_LIB_TABLE to be loaded on demand.
prj.ElemClear( PROJECT::ELEM_FPTBL );
}
void CVPCB_MAINFRAME::SaveProjectFile( wxCommandEvent& aEvent )
{
wxFileName fn = m_NetlistFileName;
PROJECT& prj = Prj();
wxFileName fn = prj.AbsolutePath( m_NetlistFileName.GetFullPath() );
fn.SetExt( ProjectFileExtension );
......@@ -103,11 +98,8 @@ void CVPCB_MAINFRAME::SaveProjectFile( wxCommandEvent& aEvent )
if( !IsWritable( fn ) )
return;
// was:
// Pgm().WriteProjectConfig( fn.GetFullPath(), GROUP, GetProjectFileParameters() );
PROJECT& prj = Prj();
wxString pro_name = fn.GetFullPath();
prj.ConfigSave( Kiface().KifaceSearch(), fn.GetFullPath(), GROUP_CVP, GetProjectFileParameters() );
prj.ConfigSave( Kiface().KifaceSearch(), GROUP_CVP, GetProjectFileParameters(), pro_name );
}
......@@ -217,7 +217,7 @@ public:
* Function LoadProjectFile
* reads the configuration parameter from the project (.pro) file \a aFileName
*/
void LoadProjectFile( const wxString& aFileName );
void LoadProjectFile();
void LoadSettings( wxConfigBase* aCfg ); // override virtual
......
......@@ -169,7 +169,7 @@ bool CVPCB_MAINFRAME::ReadNetListAndLinkFiles()
if( m_compListBox == NULL )
return false;
LoadProjectFile( m_NetlistFileName.GetFullPath() );
LoadProjectFile();
LoadFootprintFiles();
BuildFOOTPRINTS_LISTBOX();
......
......@@ -95,18 +95,18 @@ void SCH_EDIT_FRAME::AnnotateComponents( bool aAnnotateSchematic,
// Set sheet number and number of sheets.
SetSheetNumberAndCount();
/* Build component list */
// Build component list
if( aAnnotateSchematic )
{
sheets.GetComponents( references );
sheets.GetComponents( Prj().SchLibs(), references );
}
else
{
m_CurrentSheet->GetComponents( references );
m_CurrentSheet->GetComponents( Prj().SchLibs(), references );
}
/* Break full components reference in name (prefix) and number:
* example: IC1 become IC, and 1 */
// Break full components reference in name (prefix) and number:
// example: IC1 become IC, and 1
references.SplitReferences();
switch( aSortOption )
......@@ -172,15 +172,15 @@ void SCH_EDIT_FRAME::AnnotateComponents( bool aAnnotateSchematic,
int SCH_EDIT_FRAME::CheckAnnotate( wxArrayString* aMessageList, bool aOneSheetOnly )
{
/* build the screen list */
// build the screen list
SCH_SHEET_LIST SheetList;
SCH_REFERENCE_LIST ComponentsList;
/* Build the list of components */
// Build the list of components
if( !aOneSheetOnly )
SheetList.GetComponents( ComponentsList );
SheetList.GetComponents( Prj().SchLibs(), ComponentsList );
else
m_CurrentSheet->GetComponents( ComponentsList );
m_CurrentSheet->GetComponents( Prj().SchLibs(), ComponentsList );
return ComponentsList.CheckAnnotation( aMessageList );
}
......@@ -54,7 +54,7 @@ void SCH_EDIT_FRAME::backAnnotateFootprints( const std::string& aChangedSetOfRef
SCH_SHEET_LIST sheets;
bool isChanged = false;
sheets.GetComponents( refs, false );
sheets.GetComponents( Prj().SchLibs(), refs, false );
DSNLEXER lexer( aChangedSetOfReferences, FROM_UTF8( __func__ ) );
PTREE doc;
......@@ -98,7 +98,7 @@ void SCH_EDIT_FRAME::backAnnotateFootprints( const std::string& aChangedSetOfRef
// We have found a candidate.
// Note: it can be not unique (multiple parts per package)
// So we *do not* stop the search here
SCH_COMPONENT* component = refs[ii].GetComponent();
SCH_COMPONENT* component = refs[ii].GetComp();
SCH_FIELD* fpfield = component->GetField( FOOTPRINT );
const wxString& oldfp = fpfield->GetText();
......@@ -133,9 +133,9 @@ bool SCH_EDIT_FRAME::ProcessCmpToFootprintLinkFile( const wxString& aFullFilenam
{
// Build a flat list of components in schematic:
SCH_REFERENCE_LIST referencesList;
SCH_SHEET_LIST SheetList;
SCH_SHEET_LIST sheetList;
SheetList.GetComponents( referencesList, false );
sheetList.GetComponents( Prj().SchLibs(), referencesList, false );
FILE* cmpFile = wxFopen( aFullFilename, wxT( "rt" ) );
if( cmpFile == NULL )
......@@ -196,9 +196,9 @@ bool SCH_EDIT_FRAME::ProcessCmpToFootprintLinkFile( const wxString& aFullFilenam
if( Cmp_KEEPCASE( reference, referencesList[ii].GetRef() ) == 0 )
{
// We have found a candidate.
// Note: it can be not unique (multiple parts per package)
// Note: it can be not unique (multiple units per part)
// So we *do not* stop the search here
SCH_COMPONENT* component = referencesList[ii].GetComponent();
SCH_COMPONENT* component = referencesList[ii].GetComp();
SCH_FIELD* fpfield = component->GetField( FOOTPRINT );
fpfield->SetText( footprint );
......@@ -218,7 +218,7 @@ bool SCH_EDIT_FRAME::ProcessCmpToFootprintLinkFile( const wxString& aFullFilenam
bool SCH_EDIT_FRAME::LoadCmpToFootprintLinkFile()
{
wxString path = wxGetCwd();
wxString path = wxPathOnly( Prj().GetProjectFullName() );
wxFileDialog dlg( this, _( "Load Component-Footprint Link File" ),
path, wxEmptyString,
......
......@@ -109,12 +109,12 @@ bool LIB_EDIT_FRAME::HandleBlockEnd( wxDC* DC )
DisplayError( this, wxT( "Error in HandleBlockPLace" ) );
break;
case BLOCK_DRAG:
case BLOCK_DRAG: // Drag
case BLOCK_DRAG_ITEM:
case BLOCK_MOVE:
case BLOCK_COPY:
if ( m_component )
ItemCount = m_component->SelectItems( GetScreen()->m_BlockLocate,
case BLOCK_MOVE: // Move
case BLOCK_COPY: // Copy
if( GetCurPart() )
ItemCount = GetCurPart()->SelectItems( GetScreen()->m_BlockLocate,
m_unit, m_convert,
m_editPinsPerPartOrConvert );
if( ItemCount )
......@@ -139,57 +139,56 @@ bool LIB_EDIT_FRAME::HandleBlockEnd( wxDC* DC )
GetScreen()->m_BlockLocate.SetState( STATE_BLOCK_MOVE );
break;
case BLOCK_DELETE: /* Delete */
if ( m_component )
ItemCount = m_component->SelectItems( GetScreen()->m_BlockLocate,
case BLOCK_DELETE: // Delete
if( GetCurPart() )
ItemCount = GetCurPart()->SelectItems( GetScreen()->m_BlockLocate,
m_unit, m_convert,
m_editPinsPerPartOrConvert );
if( ItemCount )
SaveCopyInUndoList( m_component );
SaveCopyInUndoList( GetCurPart() );
if ( m_component )
if( GetCurPart() )
{
m_component->DeleteSelectedItems();
GetCurPart()->DeleteSelectedItems();
OnModify();
}
break;
case BLOCK_SAVE: /* Save */
case BLOCK_SAVE: // Save
case BLOCK_PASTE:
case BLOCK_FLIP:
break;
case BLOCK_ROTATE:
case BLOCK_MIRROR_X:
case BLOCK_MIRROR_Y:
if ( m_component )
ItemCount = m_component->SelectItems( GetScreen()->m_BlockLocate,
if( GetCurPart() )
ItemCount = GetCurPart()->SelectItems( GetScreen()->m_BlockLocate,
m_unit, m_convert,
m_editPinsPerPartOrConvert );
if( ItemCount )
SaveCopyInUndoList( m_component );
SaveCopyInUndoList( GetCurPart() );
pt = GetScreen()->m_BlockLocate.Centre();
pt = GetNearestGridPosition( pt );
NEGATE( pt.y );
if ( m_component )
if( GetCurPart() )
{
OnModify();
int block_cmd = GetScreen()->m_BlockLocate.GetCommand();
if( block_cmd == BLOCK_MIRROR_Y)
m_component->MirrorSelectedItemsH( pt );
GetCurPart()->MirrorSelectedItemsH( pt );
else if( block_cmd == BLOCK_MIRROR_X)
m_component->MirrorSelectedItemsV( pt );
GetCurPart()->MirrorSelectedItemsV( pt );
else if( block_cmd == BLOCK_ROTATE )
m_component->RotateSelectedItems( pt );
GetCurPart()->RotateSelectedItems( pt );
}
break;
case BLOCK_ZOOM: /* Window Zoom */
case BLOCK_ZOOM: // Window Zoom
Window_Zoom( GetScreen()->m_BlockLocate );
break;
......@@ -200,10 +199,10 @@ bool LIB_EDIT_FRAME::HandleBlockEnd( wxDC* DC )
break;
}
if( ! nextCmd )
if( !nextCmd )
{
if( GetScreen()->m_BlockLocate.GetCommand() != BLOCK_SELECT_ITEMS_ONLY && m_component )
m_component->ClearSelectedItems();
if( GetScreen()->m_BlockLocate.GetCommand() != BLOCK_SELECT_ITEMS_ONLY && GetCurPart() )
GetCurPart()->ClearSelectedItems();
GetScreen()->m_BlockLocate.SetState( STATE_NO_BLOCK );
GetScreen()->m_BlockLocate.SetCommand( BLOCK_IDLE );
......@@ -233,62 +232,62 @@ void LIB_EDIT_FRAME::HandleBlockPlace( wxDC* DC )
case BLOCK_IDLE:
break;
case BLOCK_DRAG:
case BLOCK_DRAG: // Drag
case BLOCK_DRAG_ITEM:
case BLOCK_MOVE:
case BLOCK_PRESELECT_MOVE: /* Move with preselection list*/
case BLOCK_MOVE: // Move
case BLOCK_PRESELECT_MOVE: // Move with preselection list
GetScreen()->m_BlockLocate.ClearItemsList();
if ( m_component )
SaveCopyInUndoList( m_component );
if( GetCurPart() )
SaveCopyInUndoList( GetCurPart() );
pt = GetScreen()->m_BlockLocate.GetMoveVector();
pt.y *= -1;
if ( m_component )
m_component->MoveSelectedItems( pt );
if( GetCurPart() )
GetCurPart()->MoveSelectedItems( pt );
m_canvas->Refresh( true );
break;
case BLOCK_COPY: /* Copy */
case BLOCK_COPY: // Copy
GetScreen()->m_BlockLocate.ClearItemsList();
if ( m_component )
SaveCopyInUndoList( m_component );
if( GetCurPart() )
SaveCopyInUndoList( GetCurPart() );
pt = GetScreen()->m_BlockLocate.GetMoveVector();
NEGATE( pt.y );
if ( m_component )
m_component->CopySelectedItems( pt );
if( GetCurPart() )
GetCurPart()->CopySelectedItems( pt );
break;
case BLOCK_PASTE: /* Paste (recopy the last block saved) */
case BLOCK_PASTE: // Paste (recopy the last block saved)
GetScreen()->m_BlockLocate.ClearItemsList();
break;
case BLOCK_ROTATE: // Invert by popup menu, from block move
case BLOCK_MIRROR_X: // Invert by popup menu, from block move
case BLOCK_MIRROR_Y: // Invert by popup menu, from block move
if ( m_component )
SaveCopyInUndoList( m_component );
if( GetCurPart() )
SaveCopyInUndoList( GetCurPart() );
pt = GetScreen()->m_BlockLocate.Centre();
pt = GetNearestGridPosition( pt );
NEGATE( pt.y );
if ( m_component )
if( GetCurPart() )
{
int block_cmd = GetScreen()->m_BlockLocate.GetCommand();
if( block_cmd == BLOCK_MIRROR_Y)
m_component->MirrorSelectedItemsH( pt );
GetCurPart()->MirrorSelectedItemsH( pt );
else if( block_cmd == BLOCK_MIRROR_X)
m_component->MirrorSelectedItemsV( pt );
GetCurPart()->MirrorSelectedItemsV( pt );
else if( block_cmd == BLOCK_ROTATE )
m_component->RotateSelectedItems( pt );
GetCurPart()->RotateSelectedItems( pt );
}
break;
......@@ -326,7 +325,7 @@ void DrawMovingBlockOutlines( EDA_DRAW_PANEL* aPanel, wxDC* aDC, const wxPoint&
LIB_EDIT_FRAME* parent = (LIB_EDIT_FRAME*) aPanel->GetParent();
wxASSERT( parent != NULL );
LIB_COMPONENT* component = parent->GetComponent();
LIB_PART* component = parent->GetCurPart();
if( component == NULL )
return;
......
This diff is collapsed.
This diff is collapsed.
This diff is collapsed.
This diff is collapsed.
......@@ -291,7 +291,7 @@ void SCH_REFERENCE_LIST::Annotate( bool aUseSheetNum, int aSheetIntervalId )
int LastReferenceNumber = 0;
int NumberOfUnits, Unit;
/* Components with an invisible reference (power...) always are re-annotated. */
// Components with an invisible reference (power...) always are re-annotated.
ResetHiddenReferences();
/* calculate index of the first component with the same reference prefix
......@@ -301,7 +301,7 @@ void SCH_REFERENCE_LIST::Annotate( bool aUseSheetNum, int aSheetIntervalId )
*/
unsigned first = 0;
/* calculate the last used number for this reference prefix: */
// calculate the last used number for this reference prefix:
#ifdef USE_OLD_ALGO
int minRefId = 0;
......@@ -330,7 +330,7 @@ void SCH_REFERENCE_LIST::Annotate( bool aUseSheetNum, int aSheetIntervalId )
if( ( componentFlatList[first].CompareRef( componentFlatList[ii] ) != 0 )
|| ( aUseSheetNum && ( componentFlatList[first].m_SheetNum != componentFlatList[ii].m_SheetNum ) ) )
{
/* New reference found: we need a new ref number for this reference */
// New reference found: we need a new ref number for this reference
first = ii;
#ifdef USE_OLD_ALGO
minRefId = 0;
......@@ -352,7 +352,7 @@ void SCH_REFERENCE_LIST::Annotate( bool aUseSheetNum, int aSheetIntervalId )
}
// Annotation of one part per package components (trivial case).
if( componentFlatList[ii].GetLibComponent()->GetPartCount() <= 1 )
if( componentFlatList[ii].GetLibComponent()->GetUnitCount() <= 1 )
{
if( componentFlatList[ii].m_IsNew )
{
......@@ -370,8 +370,8 @@ void SCH_REFERENCE_LIST::Annotate( bool aUseSheetNum, int aSheetIntervalId )
continue;
}
/* Annotation of multi-part components ( n parts per package ) (complex case) */
NumberOfUnits = componentFlatList[ii].GetLibComponent()->GetPartCount();
// Annotation of multi-unit parts ( n units per part ) (complex case)
NumberOfUnits = componentFlatList[ii].GetLibComponent()->GetUnitCount();
if( componentFlatList[ii].m_IsNew )
{
......@@ -382,7 +382,7 @@ void SCH_REFERENCE_LIST::Annotate( bool aUseSheetNum, int aSheetIntervalId )
#endif
componentFlatList[ii].m_NumRef = LastReferenceNumber;
if( !componentFlatList[ii].IsPartsLocked() )
if( !componentFlatList[ii].IsUnitsLocked() )
componentFlatList[ii].m_Unit = 1;
componentFlatList[ii].m_Flag = 1;
......@@ -400,9 +400,9 @@ void SCH_REFERENCE_LIST::Annotate( bool aUseSheetNum, int aSheetIntervalId )
int found = FindUnit( ii, Unit );
if( found >= 0 )
continue; /* this unit exists for this reference (unit already annotated) */
continue; // this unit exists for this reference (unit already annotated)
/* Search a component to annotate ( same prefix, same value, not annotated) */
// Search a component to annotate ( same prefix, same value, not annotated)
for( unsigned jj = ii + 1; jj < componentFlatList.size(); jj++ )
{
if( componentFlatList[jj].m_Flag ) // already tested
......@@ -420,8 +420,8 @@ void SCH_REFERENCE_LIST::Annotate( bool aUseSheetNum, int aSheetIntervalId )
if( !componentFlatList[jj].m_IsNew )
continue;
/* Component without reference number found, annotate it if possible */
if( !componentFlatList[jj].IsPartsLocked()
// Component without reference number found, annotate it if possible
if( !componentFlatList[jj].IsUnitsLocked()
|| ( componentFlatList[jj].m_Unit == Unit ) )
{
componentFlatList[jj].m_NumRef = componentFlatList[ii].m_NumRef;
......@@ -486,7 +486,7 @@ int SCH_REFERENCE_LIST::CheckAnnotation( wxArrayString* aMessageList )
// Error if unit number selected does not exist ( greater than the number of
// parts in the component ). This can happen if a component has changed in a
// library after a previous annotation.
if( std::max( componentFlatList[ii].GetLibComponent()->GetPartCount(), 1 )
if( std::max( componentFlatList[ii].GetLibComponent()->GetUnitCount(), 1 )
< componentFlatList[ii].m_Unit )
{
if( componentFlatList[ii].m_NumRef >= 0 )
......@@ -498,7 +498,7 @@ int SCH_REFERENCE_LIST::CheckAnnotation( wxArrayString* aMessageList )
GetChars( componentFlatList[ii].GetRef() ),
GetChars( tmp ),
componentFlatList[ii].m_Unit,
componentFlatList[ii].GetLibComponent()->GetPartCount() );
componentFlatList[ii].GetLibComponent()->GetUnitCount() );
if( aMessageList )
aMessageList->Add( msg );
......@@ -555,8 +555,8 @@ int SCH_REFERENCE_LIST::CheckAnnotation( wxArrayString* aMessageList )
/* Test error if units are different but number of parts per package
* too high (ex U3 ( 1 part) and we find U3B this is an error) */
if( componentFlatList[ii].GetLibComponent()->GetPartCount()
!= componentFlatList[ii + 1].GetLibComponent()->GetPartCount() )
if( componentFlatList[ii].GetLibComponent()->GetUnitCount()
!= componentFlatList[ii + 1].GetLibComponent()->GetUnitCount() )
{
if( componentFlatList[ii].m_NumRef >= 0 )
tmp << componentFlatList[ii].m_NumRef;
......@@ -584,7 +584,7 @@ int SCH_REFERENCE_LIST::CheckAnnotation( wxArrayString* aMessageList )
error++;
}
/* Error if values are different between units, for the same reference */
// Error if values are different between units, for the same reference
int next = ii + 1;
if( componentFlatList[ii].CompareValue( componentFlatList[next] ) != 0 )
......@@ -592,12 +592,12 @@ int SCH_REFERENCE_LIST::CheckAnnotation( wxArrayString* aMessageList )
msg.Printf( _( "Different values for %s%d%s (%s) and %s%d%s (%s)" ),
GetChars( componentFlatList[ii].GetRef() ),
componentFlatList[ii].m_NumRef,
GetChars( LIB_COMPONENT::SubReference(
GetChars( LIB_PART::SubReference(
componentFlatList[ii].m_Unit ) ),
GetChars( componentFlatList[ii].m_Value->GetText() ),
GetChars( componentFlatList[next].GetRef() ),
componentFlatList[next].m_NumRef,
GetChars( LIB_COMPONENT::SubReference(
GetChars( LIB_PART::SubReference(
componentFlatList[next].m_Unit ) ),
GetChars( componentFlatList[next].m_Value->GetText() ) );
......@@ -617,7 +617,7 @@ int SCH_REFERENCE_LIST::CheckAnnotation( wxArrayString* aMessageList )
|| ( componentFlatList[ii].GetSheetPath() != componentFlatList[ii + 1].GetSheetPath() ) )
continue;
/* Same time stamp found. */
// Same time stamp found.
wxString full_path;
full_path.Printf( wxT( "%s%8.8X" ),
......@@ -640,7 +640,7 @@ int SCH_REFERENCE_LIST::CheckAnnotation( wxArrayString* aMessageList )
}
SCH_REFERENCE::SCH_REFERENCE( SCH_COMPONENT* aComponent, LIB_COMPONENT* aLibComponent,
SCH_REFERENCE::SCH_REFERENCE( SCH_COMPONENT* aComponent, LIB_PART* aLibComponent,
SCH_SHEET_PATH& aSheetPath )
{
wxASSERT( aComponent != NULL && aLibComponent != NULL );
......@@ -694,7 +694,7 @@ void SCH_REFERENCE::Split()
{
m_IsNew = true;
if( !IsPartsLocked() )
if( !IsUnitsLocked() )
m_Unit = 0x7FFFFFFF;
refText.erase( ll ); // delete last char
......@@ -705,7 +705,7 @@ void SCH_REFERENCE::Split()
{
m_IsNew = true;
if( !IsPartsLocked() )
if( !IsUnitsLocked() )
m_Unit = 0x7FFFFFFF;
}
else
......
......@@ -98,8 +98,11 @@ bool COMPONENT_TREE_SEARCH_CONTAINER::scoreComparator( const TREE_NODE* a1, cons
}
COMPONENT_TREE_SEARCH_CONTAINER::COMPONENT_TREE_SEARCH_CONTAINER()
: tree( NULL ), libraries_added( 0 ), preselect_unit_number( -1 )
COMPONENT_TREE_SEARCH_CONTAINER::COMPONENT_TREE_SEARCH_CONTAINER( PART_LIBS* aLibs ) :
tree( NULL ),
libraries_added( 0 ),
preselect_unit_number( -1 ),
m_libs( aLibs )
{
}
......@@ -127,7 +130,7 @@ void COMPONENT_TREE_SEARCH_CONTAINER::SetTree( wxTreeCtrl* aTree )
}
void COMPONENT_TREE_SEARCH_CONTAINER::AddLibrary( CMP_LIBRARY& aLib )
void COMPONENT_TREE_SEARCH_CONTAINER::AddLibrary( PART_LIB& aLib )
{
wxArrayString all_aliases;
......@@ -139,7 +142,7 @@ void COMPONENT_TREE_SEARCH_CONTAINER::AddLibrary( CMP_LIBRARY& aLib )
void COMPONENT_TREE_SEARCH_CONTAINER::AddAliasList( const wxString& aNodeName,
const wxArrayString& aAliasNameList,
CMP_LIBRARY* aOptionalLib )
PART_LIB* aOptionalLib )
{
TREE_NODE* const lib_node = new TREE_NODE( TREE_NODE::TYPE_LIB, NULL, NULL,
aNodeName, wxEmptyString, wxEmptyString );
......@@ -152,7 +155,7 @@ void COMPONENT_TREE_SEARCH_CONTAINER::AddAliasList( const wxString& aNodeName,
if( aOptionalLib )
a = aOptionalLib->FindAlias( aName );
else
a = CMP_LIBRARY::FindLibraryEntry( aName, wxEmptyString );
a = m_libs->FindLibraryEntry( aName, wxEmptyString );
if( a == NULL )
continue;
......@@ -186,12 +189,12 @@ void COMPONENT_TREE_SEARCH_CONTAINER::AddAliasList( const wxString& aNodeName,
a, a->GetName(), display_info, search_text );
nodes.push_back( alias_node );
if( a->GetComponent()->IsMulti() ) // Add all units as sub-nodes.
if( a->GetPart()->IsMulti() ) // Add all units as sub-nodes.
{
for( int u = 1; u <= a->GetComponent()->GetPartCount(); ++u )
for( int u = 1; u <= a->GetPart()->GetUnitCount(); ++u )
{
wxString unitName = _("Unit");
unitName += wxT( " " ) + LIB_COMPONENT::SubReference( u, false );
unitName += wxT( " " ) + LIB_PART::SubReference( u, false );
TREE_NODE* unit_node = new TREE_NODE( TREE_NODE::TYPE_UNIT,
alias_node, a,
unitName,
......
......@@ -28,13 +28,14 @@
#include <wx/string.h>
class LIB_ALIAS;
class CMP_LIBRARY;
class PART_LIB;
class PART_LIBS;
class wxTreeCtrl;
class wxArrayString;
// class COMPONENT_TREE_SEARCH_CONTAINER
// A container for components that allows to search them matching their name, keywords
// and descripotions, updating a wxTreeCtrl with the results (toplevel nodes:
// and descriptions, updating a wxTreeCtrl with the results (toplevel nodes:
// libraries, leafs: components), scored by relevance.
//
// The scored result list is adpated on each update on the search-term: this allows
......@@ -42,7 +43,7 @@ class wxArrayString;
class COMPONENT_TREE_SEARCH_CONTAINER
{
public:
COMPONENT_TREE_SEARCH_CONTAINER();
COMPONENT_TREE_SEARCH_CONTAINER( PART_LIBS* aLibs );
~COMPONENT_TREE_SEARCH_CONTAINER();
/** Function AddLibrary
......@@ -51,7 +52,7 @@ public:
*
* @param aLib containting all the components to be added.
*/
void AddLibrary( CMP_LIBRARY& aLib );
void AddLibrary( PART_LIB& aLib );
/** Function AddComponentList
* Add the given list of components, given by name, to be searched.
......@@ -62,7 +63,7 @@ public:
* @param aOptionalLib Library to look up the component names (if NULL: global lookup)
*/
void AddAliasList( const wxString& aNodeName, const wxArrayString& aAliasNameList,
CMP_LIBRARY* aOptionalLib );
PART_LIB* aOptionalLib );
/** Function SetPreselectNode
* Set the component name to be selected in absence of any search-result.
......@@ -111,6 +112,8 @@ private:
wxString preselect_node_name;
int preselect_unit_number;
PART_LIBS* m_libs; // no ownership
};
#endif /* COMPONENT_TREE_SEARCH_CONTAINER_H */
......@@ -38,25 +38,27 @@
#include <boost/foreach.hpp>
extern void DisplayCmpDocAndKeywords( wxString& Name );
// Used in DataBaseGetName: this is a callback function for EDA_LIST_DIALOG
// to display keywords and description of a component
void DisplayCmpDocAndKeywords( wxString& Name )
void DisplayCmpDocAndKeywords( wxString& aName, void* aData )
{
LIB_ALIAS* CmpEntry = NULL;
PART_LIBS* libs = (PART_LIBS*) aData;
wxASSERT( libs );
CmpEntry = CMP_LIBRARY::FindLibraryEntry( Name );
LIB_ALIAS* part = libs->FindLibraryEntry( aName );
if( CmpEntry == NULL )
if( !part )
return;
Name = wxT( "Description: " ) + CmpEntry->GetDescription();
Name += wxT( "\nKey Words: " ) + CmpEntry->GetKeyWords();
aName = wxT( "Description: " ) + part->GetDescription();
aName += wxT( "\nKey Words: " ) + part->GetKeyWords();
}
#if 0 // not used, should be wxFrame member for KIWAY and PROJECT access.
/*
* Displays a list of filtered components found in libraries for selection,
* Keys is a list of keywords to filter components which do not match these keywords
......@@ -75,7 +77,7 @@ wxString DataBaseGetName( EDA_DRAW_FRAME* frame, wxString& Keys, wxString& BufNa
Keys.MakeUpper();
/* Review the list of libraries for counting. */
BOOST_FOREACH( CMP_LIBRARY& lib, CMP_LIBRARY::GetLibraryList() )
BOOST_FOREACH( PART_LIB& lib, PART_LIB::GetLibraryList() )
{
lib.SearchEntryNames( nameList, BufName, Keys );
}
......@@ -119,6 +121,7 @@ wxString DataBaseGetName( EDA_DRAW_FRAME* frame, wxString& Keys, wxString& BufNa
// Show candidate list:
wxString cmpname;
EDA_LIST_DIALOG dlg( frame, _( "Select Component" ), headers, nameList, cmpname,
DisplayCmpDocAndKeywords, true );
......@@ -128,3 +131,4 @@ wxString DataBaseGetName( EDA_DRAW_FRAME* frame, wxString& Keys, wxString& BufNa
cmpname = dlg.GetTextSelection();
return cmpname;
}
#endif
......@@ -302,7 +302,7 @@ void DIALOG_BOM::OnRunPlugin( wxCommandEvent& event )
fn = g_RootSheet->GetScreen()->GetFileName();
if( fn.GetPath().IsEmpty() )
fn.SetPath( wxGetCwd() );
fn.SetPath( wxPathOnly( Prj().GetProjectFullName() ) );
fn.ClearExt();
wxString fullfilename = fn.GetFullPath();
......
......@@ -251,13 +251,13 @@ void DIALOG_CHOOSE_COMPONENT::OnHandlePreviewRepaint( wxPaintEvent& aRepaintEven
int unit = 0;
LIB_ALIAS* selection = m_search_container->GetSelectedAlias( &unit );
renderPreview( selection ? selection->GetComponent() : NULL, unit );
renderPreview( selection ? selection->GetPart() : NULL, unit );
}
// Render the preview in our m_componentView. If this gets more complicated, we should
// probably have a derived class from wxPanel; but this keeps things local.
void DIALOG_CHOOSE_COMPONENT::renderPreview( LIB_COMPONENT* aComponent, int aUnit )
void DIALOG_CHOOSE_COMPONENT::renderPreview( LIB_PART* aComponent, int aUnit )
{
wxPaintDC dc( m_componentView );
dc.SetBackground( *wxWHITE_BRUSH );
......
......@@ -28,7 +28,7 @@
class COMPONENT_TREE_SEARCH_CONTAINER;
class LIB_ALIAS;
class LIB_COMPONENT;
class LIB_PART;
class wxTreeItemId;
class DIALOG_CHOOSE_COMPONENT : public DIALOG_CHOOSE_COMPONENT_BASE
......@@ -79,7 +79,7 @@ protected:
private:
bool updateSelection();
void selectIfValid( const wxTreeItemId& aTreeId );
void renderPreview( LIB_COMPONENT* aComponent, int aUnit );
void renderPreview( LIB_PART* aComponent, int aUnit );
COMPONENT_TREE_SEARCH_CONTAINER* const m_search_container;
const int m_deMorganConvert;
......
......@@ -64,7 +64,7 @@ void DIALOG_EDIT_COMPONENT_IN_LIBRARY::initDlg()
{
m_AliasLocation = -1;
LIB_COMPONENT* component = m_Parent->GetComponent();
LIB_PART* component = m_Parent->GetCurPart();
if( component == NULL )
{
......@@ -125,7 +125,7 @@ void DIALOG_EDIT_COMPONENT_IN_LIBRARY::OnCancelClick( wxCommandEvent& event )
void DIALOG_EDIT_COMPONENT_IN_LIBRARY::InitPanelDoc()
{
LIB_ALIAS* alias;
LIB_COMPONENT* component = m_Parent->GetComponent();
LIB_PART* component = m_Parent->GetCurPart();
if( component == NULL )
return;
......@@ -151,7 +151,7 @@ void DIALOG_EDIT_COMPONENT_IN_LIBRARY::InitPanelDoc()
*/
void DIALOG_EDIT_COMPONENT_IN_LIBRARY::InitBasicPanel()
{
LIB_COMPONENT* component = m_Parent->GetComponent();
LIB_PART* component = m_Parent->GetCurPart();
if( m_Parent->GetShowDeMorgan() )
m_AsConvertButt->SetValue( true );
......@@ -172,10 +172,10 @@ void DIALOG_EDIT_COMPONENT_IN_LIBRARY::InitBasicPanel()
m_ShowPinNumButt->SetValue( component->ShowPinNumbers() );
m_ShowPinNameButt->SetValue( component->ShowPinNames() );
m_PinsNameInsideButt->SetValue( component->GetPinNameOffset() != 0 );
m_SelNumberOfUnits->SetValue( component->GetPartCount() );
m_SelNumberOfUnits->SetValue( component->GetUnitCount() );
m_SetSkew->SetValue( component->GetPinNameOffset() );
m_OptionPower->SetValue( component->IsPower() );
m_OptionPartsLocked->SetValue( component->UnitsLocked() && component->GetPartCount() > 1 );
m_OptionPartsLocked->SetValue( component->UnitsLocked() && component->GetUnitCount() > 1 );
}
......@@ -184,7 +184,7 @@ void DIALOG_EDIT_COMPONENT_IN_LIBRARY::OnOkClick( wxCommandEvent& event )
/* Update the doc, keyword and doc filename strings */
int index;
LIB_ALIAS* alias;
LIB_COMPONENT* component = m_Parent->GetComponent();
LIB_PART* component = m_Parent->GetCurPart();
if( component == NULL )
{
......@@ -248,7 +248,7 @@ void DIALOG_EDIT_COMPONENT_IN_LIBRARY::OnOkClick( wxCommandEvent& event )
* Obviously, cannot be true if there is only one part */
component->LockUnits( m_OptionPartsLocked->GetValue() );
if( component->GetPartCount() <= 1 )
if( component->GetUnitCount() <= 1 )
component->LockUnits( false );
/* Update the footprint filter list */
......@@ -265,7 +265,7 @@ void DIALOG_EDIT_COMPONENT_IN_LIBRARY::CopyDocFromRootToAlias( wxCommandEvent& e
return;
LIB_ALIAS* parent_alias;
LIB_COMPONENT* component = m_Parent->GetComponent();
LIB_PART* component = m_Parent->GetCurPart();
if( component == NULL )
return;
......@@ -309,8 +309,8 @@ void DIALOG_EDIT_COMPONENT_IN_LIBRARY::DeleteAllAliasOfPart( wxCommandEvent& eve
void DIALOG_EDIT_COMPONENT_IN_LIBRARY::AddAliasOfPart( wxCommandEvent& event )
{
wxString aliasname;
LIB_COMPONENT* component = m_Parent->GetComponent();
CMP_LIBRARY* library = m_Parent->GetLibrary();
LIB_PART* component = m_Parent->GetCurPart();
PART_LIB* library = m_Parent->GetCurLib();
if( component == NULL )
return;
......@@ -371,7 +371,7 @@ void DIALOG_EDIT_COMPONENT_IN_LIBRARY::DeleteAliasOfPart( wxCommandEvent& event
}
m_PartAliasListCtrl->Delete( m_PartAliasListCtrl->GetSelection() );
LIB_COMPONENT* component = m_Parent->GetComponent();
LIB_PART* component = m_Parent->GetCurPart();
if( component )
component->RemoveAlias( aliasname );
......@@ -389,16 +389,16 @@ void DIALOG_EDIT_COMPONENT_IN_LIBRARY::DeleteAliasOfPart( wxCommandEvent& event
*/
bool DIALOG_EDIT_COMPONENT_IN_LIBRARY::ChangeNbUnitsPerPackage( int MaxUnit )
{
LIB_COMPONENT* component = m_Parent->GetComponent();
LIB_PART* part = m_Parent->GetCurPart();
if( component == NULL || component->GetPartCount() == MaxUnit || MaxUnit < 1 )
if( !part || part->GetUnitCount() == MaxUnit || MaxUnit < 1 )
return false;
if( MaxUnit < component->GetPartCount()
if( MaxUnit < part->GetUnitCount()
&& !IsOK( this, _( "Delete extra parts from component?" ) ) )
return false;
component->SetPartCount( MaxUnit );
part->SetUnitCount( MaxUnit );
return true;
}
......@@ -408,7 +408,7 @@ bool DIALOG_EDIT_COMPONENT_IN_LIBRARY::ChangeNbUnitsPerPackage( int MaxUnit )
*/
bool DIALOG_EDIT_COMPONENT_IN_LIBRARY::SetUnsetConvert()
{
LIB_COMPONENT* component = m_Parent->GetComponent();
LIB_PART* component = m_Parent->GetCurPart();
if( component == NULL || ( m_Parent->GetShowDeMorgan() == component->HasConversion() ) )
return false;
......@@ -437,13 +437,13 @@ bool DIALOG_EDIT_COMPONENT_IN_LIBRARY::SetUnsetConvert()
void DIALOG_EDIT_COMPONENT_IN_LIBRARY::BrowseAndSelectDocFile( wxCommandEvent& event )
{
PROJECT& prj = Prj();
SEARCH_STACK& search = prj.SchSearchS();
SEARCH_STACK* search = prj.SchSearchS();
wxString mask = wxT( "*" );
wxString docpath = prj.GetRString( PROJECT::DOC_PATH );
if( !docpath )
docpath = search.LastVisitedPath( wxT( "doc" ) );
docpath = search->LastVisitedPath( wxT( "doc" ) );
wxString fullFileName = EDA_FileSelector( _( "Doc Files" ),
docpath,
......@@ -468,7 +468,8 @@ void DIALOG_EDIT_COMPONENT_IN_LIBRARY::BrowseAndSelectDocFile( wxCommandEvent& e
prj.SetRString( PROJECT::DOC_PATH, fn.GetPath() );
wxString filename = search.FilenameWithRelativePathInSearchList( fullFileName );
wxString filename = search->FilenameWithRelativePathInSearchList(
fullFileName, wxPathOnly( Prj().GetProjectFullName() ) );
// Filenames are always stored in unix like mode, ie separator "\" is stored as "/"
// to ensure files are identical under unices and windows
......@@ -496,7 +497,7 @@ void DIALOG_EDIT_COMPONENT_IN_LIBRARY::DeleteAllFootprintFilter( wxCommandEvent&
void DIALOG_EDIT_COMPONENT_IN_LIBRARY::AddFootprintFilter( wxCommandEvent& event )
{
wxString Line;
LIB_COMPONENT* component = m_Parent->GetComponent();
LIB_PART* component = m_Parent->GetCurPart();
if( component == NULL )
return;
......@@ -531,7 +532,7 @@ void DIALOG_EDIT_COMPONENT_IN_LIBRARY::AddFootprintFilter( wxCommandEvent& event
void DIALOG_EDIT_COMPONENT_IN_LIBRARY::DeleteOneFootprintFilter( wxCommandEvent& event )
{
LIB_COMPONENT* component = m_Parent->GetComponent();
LIB_PART* component = m_Parent->GetCurPart();
int ii = m_FootprintFilterListBox->GetSelection();
m_FootprintFilterListBox->Delete( ii );
......
......@@ -54,7 +54,7 @@ static int s_SelectedRow;
class DIALOG_EDIT_LIBENTRY_FIELDS_IN_LIB : public DIALOG_EDIT_LIBENTRY_FIELDS_IN_LIB_BASE
{
public:
DIALOG_EDIT_LIBENTRY_FIELDS_IN_LIB( LIB_EDIT_FRAME* aParent, LIB_COMPONENT* aLibEntry );
DIALOG_EDIT_LIBENTRY_FIELDS_IN_LIB( LIB_EDIT_FRAME* aParent, LIB_PART* aLibEntry );
//~DIALOG_EDIT_LIBENTRY_FIELDS_IN_LIB() {}
private:
......@@ -125,7 +125,7 @@ private:
}
LIB_EDIT_FRAME* m_parent;
LIB_COMPONENT* m_libEntry;
LIB_PART* m_libEntry;
bool m_skipCopyFromPanel;
/// a copy of the edited component's LIB_FIELDs
......@@ -135,12 +135,12 @@ private:
void LIB_EDIT_FRAME::InstallFieldsEditorDialog( wxCommandEvent& event )
{
if( m_component == NULL )
if( !GetCurLib() )
return;
m_canvas->EndMouseCapture( ID_NO_TOOL_SELECTED, m_canvas->GetDefaultCursor() );
DIALOG_EDIT_LIBENTRY_FIELDS_IN_LIB dlg( this, m_component );
DIALOG_EDIT_LIBENTRY_FIELDS_IN_LIB dlg( this, GetCurPart() );
int abort = dlg.ShowQuasiModal();
......@@ -156,7 +156,7 @@ void LIB_EDIT_FRAME::InstallFieldsEditorDialog( wxCommandEvent& event )
DIALOG_EDIT_LIBENTRY_FIELDS_IN_LIB::DIALOG_EDIT_LIBENTRY_FIELDS_IN_LIB(
LIB_EDIT_FRAME* aParent,
LIB_COMPONENT* aLibEntry ) :
LIB_PART* aLibEntry ) :
DIALOG_EDIT_LIBENTRY_FIELDS_IN_LIB_BASE( aParent )
{
m_parent = aParent;
......
This diff is collapsed.
......@@ -36,6 +36,7 @@
#include <class_sch_screen.h>
#include <wxEeschemaStruct.h>
#include <invoke_sch_dialog.h>
#include <project.h>
#include <netlist.h>
#include <class_netlist_object.h>
......@@ -134,14 +135,12 @@ void DIALOG_ERC::OnCloseErcDialog( wxCloseEvent& event )
}
/* wxEVT_COMMAND_BUTTON_CLICKED event handler for ID_RESET_MATRIX */
void DIALOG_ERC::OnResetMatrixClick( wxCommandEvent& event )
{
ResetDefaultERCDiag( event );
}
/* wxEVT_COMMAND_BUTTON_CLICKED event handler for ID_ERC_CMP */
void DIALOG_ERC::OnErcCmpClick( wxCommandEvent& event )
{
wxBusyCursor();
......@@ -155,7 +154,6 @@ void DIALOG_ERC::OnErcCmpClick( wxCommandEvent& event )
m_MessagesList->AppendText( messageList[ii] );
}
// Single click on a marker info:
void DIALOG_ERC::OnLeftClickMarkersList( wxCommandEvent& event )
{
m_lastMarkerFound = NULL;
......@@ -209,8 +207,7 @@ void DIALOG_ERC::OnLeftClickMarkersList( wxCommandEvent& event )
m_parent->RedrawScreen( marker->m_Pos, false);
}
// Double click on a marker info:
// Close the dialog and jump to the selected marker
void DIALOG_ERC::OnLeftDblClickMarkersList( wxCommandEvent& event )
{
// Remember: OnLeftClickMarkersList was called just berfore
......@@ -231,8 +228,6 @@ void DIALOG_ERC::OnLeftDblClickMarkersList( wxCommandEvent& event )
}
/* Build or rebuild the panel showing the ERC conflict matrix
*/
void DIALOG_ERC::ReBuildMatrixPanel()
{
// Try to know the size of bitmap button used in drc matrix
......@@ -325,10 +320,6 @@ void DIALOG_ERC::ReBuildMatrixPanel()
}
/*
* Function DisplayERC_MarkersList
* read the schematic and display the list of ERC markers
*/
void DIALOG_ERC::DisplayERC_MarkersList()
{
SCH_SHEET_LIST sheetList;
......@@ -358,8 +349,6 @@ void DIALOG_ERC::DisplayERC_MarkersList()
}
/* Resets the default values of the ERC matrix.
*/
void DIALOG_ERC::ResetDefaultERCDiag( wxCommandEvent& event )
{
memcpy( DiagErc, DefaultDiagErc, sizeof(DiagErc) );
......@@ -367,8 +356,6 @@ void DIALOG_ERC::ResetDefaultERCDiag( wxCommandEvent& event )
}
/* Change the error level for the pressed button, on the matrix table
*/
void DIALOG_ERC::ChangeErrorLevel( wxCommandEvent& event )
{
int id, level, ii, x, y;
......@@ -426,9 +413,9 @@ void DIALOG_ERC::TestErc( wxArrayString* aMessagesList )
m_writeErcFile = m_WriteResultOpt->GetValue();
/* Build the whole sheet list in hierarchy (sheet, not screen) */
// Build the whole sheet list in hierarchy (sheet, not screen)
SCH_SHEET_LIST sheets;
sheets.AnnotatePowerSymbols();
sheets.AnnotatePowerSymbols( Prj().SchLibs() );
if( m_parent->CheckAnnotate( aMessagesList, false ) )
{
......
......@@ -48,7 +48,7 @@ void DIALOG_LIB_EDIT_PIN::OnPaintShowPanel( wxPaintEvent& event )
// In fact m_dummyPin should not have a parent, but draw functions need a parent
// to know some options, about pin texts
LIB_EDIT_FRAME* libframe = (LIB_EDIT_FRAME*) GetParent();
m_dummyPin->SetParent( libframe->GetComponent() );
m_dummyPin->SetParent( libframe->GetCurPart() );
// Calculate a suitable scale to fit the available draw area
EDA_RECT bBox = m_dummyPin->GetBoundingBox();
......
......@@ -25,7 +25,7 @@ public:
wxString GetReference( void ) { return m_textReference->GetValue(); }
void SetPartCount( int count ) { m_spinPartCount->SetValue( count ); }
int GetPartCount( void ) { return m_spinPartCount->GetValue(); }
int GetUnitCount( void ) { return m_spinPartCount->GetValue(); }
void SetAlternateBodyStyle( bool enable )
{
......
......@@ -613,7 +613,7 @@ void NETLIST_DIALOG::GenNetlist( wxCommandEvent& event )
fn.SetExt( fileExt );
if( fn.GetPath().IsEmpty() )
fn.SetPath( wxGetCwd() );
fn.SetPath( wxPathOnly( Prj().GetProjectFullName() ) );
wxString fullpath = fn.GetFullPath();
......
......@@ -53,18 +53,20 @@ void SCH_EDIT_FRAME::EditComponentFieldText( SCH_FIELD* aField )
wxCHECK_RET( component != NULL && component->Type() == SCH_COMPONENT_T,
wxT( "Invalid schematic field parent item." ) );
LIB_COMPONENT* entry = CMP_LIBRARY::FindLibraryComponent( component->GetLibName() );
LIB_PART* part = Prj().SchLibs()->FindLibPart( component->GetPartName() );
wxCHECK_RET( entry != NULL, wxT( "Library entry for component <" ) +
component->GetLibName() + wxT( "> could not be found." ) );
wxCHECK_RET( part, wxT( "Library part for component <" ) +
component->GetPartName() + wxT( "> could not be found." ) );
fieldNdx = aField->GetId();
if( fieldNdx == VALUE && entry->IsPower() )
if( fieldNdx == VALUE && part->IsPower() )
{
wxString msg;
msg.Printf( _( "%s is a power component and it's value cannot be modified!\n\nYou must \
create a new power component with the new value." ), GetChars( entry->GetName() ) );
wxString msg = wxString::Format( _(
"%s is a power component and it's value cannot be modified!\n\n"
"You must create a new power component with the new value." ),
GetChars( part->GetName() )
);
DisplayInfoMessage( this, msg );
return;
}
......
This diff is collapsed.
This diff is collapsed.
This diff is collapsed.
This diff is collapsed.
This diff is collapsed.
......@@ -75,6 +75,8 @@ int InvokeDialogCreateBOM( SCH_EDIT_FRAME* aCaller );
#define NET_PLUGIN_CHANGE 1
int InvokeDialogNetList( SCH_EDIT_FRAME* aCaller );
int InvokeEeschemaConfig( SCH_EDIT_FRAME* aEditFrame, wxFrame* aParent );
bool InvokeEeschemaConfig( wxWindow* aParent,
wxString* aCallersProjectSpecificLibPaths, wxArrayString* aCallersLibNames );
#endif // INVOKE_SCH_DIALOG_H_
......@@ -84,7 +84,7 @@ static wxPoint calcCenter( const wxPoint& A, const wxPoint& B, const wxPoint& C
}
LIB_ARC::LIB_ARC( LIB_COMPONENT* aParent ) : LIB_ITEM( LIB_ARC_T, aParent )
LIB_ARC::LIB_ARC( LIB_PART* aParent ) : LIB_ITEM( LIB_ARC_T, aParent )
{
m_Radius = 0;
m_t1 = 0;
......
......@@ -84,7 +84,7 @@ class LIB_ARC : public LIB_ITEM
void calcRadiusAngles();
public:
LIB_ARC( LIB_COMPONENT * aParent );
LIB_ARC( LIB_PART * aParent );
// Do not create a copy constructor. The one generated by the compiler is adequate.
......
This diff is collapsed.
This diff is collapsed.
This diff is collapsed.
This diff is collapsed.
This diff is collapsed.
This diff is collapsed.
This diff is collapsed.
This diff is collapsed.
This diff is collapsed.
This diff is collapsed.
This diff is collapsed.
This diff is collapsed.
This diff is collapsed.
This diff is collapsed.
This diff is collapsed.
This diff is collapsed.
This diff is collapsed.
This diff is collapsed.
This diff is collapsed.
This diff is collapsed.
This diff is collapsed.
This diff is collapsed.
This diff is collapsed.
This diff is collapsed.
This diff is collapsed.
This diff is collapsed.
This diff is collapsed.
This diff is collapsed.
This diff is collapsed.
This diff is collapsed.
This diff is collapsed.
This diff is collapsed.
This diff is collapsed.
This diff is collapsed.
This diff is collapsed.
This diff is collapsed.
This diff is collapsed.
This diff is collapsed.
This diff is collapsed.
This diff is collapsed.
This diff is collapsed.
This diff is collapsed.
This diff is collapsed.
This diff is collapsed.
This diff is collapsed.
This diff is collapsed.
This diff is collapsed.
This diff is collapsed.
This diff is collapsed.
This diff is collapsed.
This diff is collapsed.
This diff is collapsed.
This diff is collapsed.
This diff is collapsed.
This diff is collapsed.
This diff is collapsed.
This diff is collapsed.
This diff is collapsed.
This diff is collapsed.
This diff is collapsed.
This diff is collapsed.
This diff is collapsed.
This diff is collapsed.
This diff is collapsed.
This diff is collapsed.
This diff is collapsed.
This diff is collapsed.
This diff is collapsed.
This diff is collapsed.
This diff is collapsed.
This diff is collapsed.
This diff is collapsed.
This diff is collapsed.
This diff is collapsed.
This diff is collapsed.
This diff is collapsed.
This diff is collapsed.
This diff is collapsed.
This diff is collapsed.
This diff is collapsed.
This diff is collapsed.
This diff is collapsed.
This diff is collapsed.
This diff is collapsed.
This diff is collapsed.
This diff is collapsed.
This diff is collapsed.
This diff is collapsed.
This diff is collapsed.
This diff is collapsed.
This diff is collapsed.
This diff is collapsed.
This diff is collapsed.
This diff is collapsed.
This diff is collapsed.
This diff is collapsed.
This diff is collapsed.
This diff is collapsed.
This diff is collapsed.
This diff is collapsed.
This diff is collapsed.
This diff is collapsed.
This diff is collapsed.
This diff is collapsed.
This diff is collapsed.
This diff is collapsed.
This diff is collapsed.
This diff is collapsed.
This diff is collapsed.
This diff is collapsed.
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