From 5678a166eeb6c68644b53247276b40e50e61351d Mon Sep 17 00:00:00 2001 From: Wayne Stambaugh Date: Sat, 19 May 2018 12:10:08 -0400 Subject: [PATCH] Fix template path bugs. Remove KICAD_PTEMPLATE environment variable as it's purpose was not clear and was often poorly defined as the path to the KiCad installed templates. Add a new KICAD_TEMPLATE_DIR environment variable which clearly should be the path of the KiCad installed templates. Make this environment variable available in the user settings in case the default is wrong which has been the case in some instances. Use the standard search stack to set the default system template path which has a much greater chance of being correct. Add a new KICAD_USER_TEMPLATE_DIR environment variable which clearly should be the path of the user defined templates. Users most likely were not even aware of the old default user path unless they read the fine manual. Set template path search stack priority as follows: * KICAD_USER_TEMPLATE_DIR * KICAD_TEMPLATE_DIR * Search stack template paths Reverse template selection dialog and project path dialog for improved user experience. Fixes lp:1543443 https://bugs.launchpad.net/kicad/+bug/1543443 --- common/dialogs/dialog_env_var_config.cpp | 23 ++++-- common/pgm_base.cpp | 70 +++++++++++++++-- kicad/kicad.cpp | 31 ++++++-- kicad/prjconfig.cpp | 97 +++++++----------------- 4 files changed, 132 insertions(+), 89 deletions(-) diff --git a/common/dialogs/dialog_env_var_config.cpp b/common/dialogs/dialog_env_var_config.cpp index ef50409674..017756f1f4 100644 --- a/common/dialogs/dialog_env_var_config.cpp +++ b/common/dialogs/dialog_env_var_config.cpp @@ -2,7 +2,7 @@ * This program source code file is part of KICAD, a free EDA CAD application. * * Copyright (C) 2015 Wayne Stambaugh - * Copyright (C) 2015-2017 KiCad Developers, see AUTHORS.txt for contributors. + * Copyright (C) 2015-2018 KiCad Developers, see AUTHORS.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 @@ -66,7 +66,7 @@ protected: void OnSelectPath( wxCommandEvent& event ) override; void onHelpClick( wxCommandEvent& event ) override; - // Currently, only upper case variable names are acepted. onVarNameChange + // Currently, only upper case variable names are accepted. onVarNameChange // changes on the fly any lower case char by the corresponding upper case void onVarNameChange( wxCommandEvent& event ) override; @@ -285,6 +285,7 @@ void DIALOG_ENV_VAR_CONFIG::EditSelectedEntry() } } + void DIALOG_ENV_VAR_CONFIG::OnHelpButton( wxCommandEvent& event ) { wxString msg = _( "Enter the name and value for each environment variable. Grey entries " @@ -296,10 +297,12 @@ void DIALOG_ENV_VAR_CONFIG::OnHelpButton( wxCommandEvent& event ) msg << _( "To ensure environment variable names are valid on all platforms, the name field " "will only accept upper case letters, digits, and the underscore characters." ); msg << wxT( "

" ); - msg << _( "KICAD_SYMBOL_DIR is the base path of the locally installed symbol libraries." ); + msg << _( "KICAD_SYMBOL_DIR is the base path of the locally installed symbol " + "libraries." ); msg << wxT( "

" ); msg << _( "KIGITHUB is used by KiCad to define the URL of the repository " - "of the official KiCad footprint libraries." ); + "of the official KiCad footprint libraries. This is only required if the " + "Github plugin is used to access footprint libraries" ); msg << wxT( "

" ); msg << _( "KISYS3DMOD is the base path of system footprint 3D " "shapes (.3Dshapes folders)." ); @@ -313,8 +316,11 @@ void DIALOG_ENV_VAR_CONFIG::OnHelpButton( wxCommandEvent& event ) "project. For instance, ${KIPRJMOD}/libs/footprints.pretty can be defined as a " "folder containing a project specific footprint library named footprints.pretty." ); msg << wxT( "

" ); - msg << _( "KICAD_PTEMPLATES is optional and can be defined if you want to " - "create your own project templates folder." ); + msg << _( "KICAD_TEMPLATE_DIR is required and is the path containing the project " + "templates installed with KiCad." ); + msg << wxT( "

" ); + msg << _( "KICAD_USER_TEMPLATE_DIR is required and is the path containing any user " + "specific project templates." ); HTML_MESSAGE_BOX dlg( GetParent(), _( "Environment Variable Help" ) ); dlg.SetDialogSizeInDU( 400, 350 ); @@ -337,8 +343,9 @@ bool DIALOG_ENV_VAR_CONFIG::IsEnvVarImmutable( const wxString aEnvVar ) "KISYS3DMOD", "KISYSMOD", "KIPRJMOD", - "KICAD_PTEMPLATES", - "KICAD_SYMBOL_DIR" + "KICAD_SYMBOL_DIR", + "KICAD_TEMPLATE_DIR", + "KICAD_USER_TEMPLATE_DIR" }; for( unsigned int ii=0; ii<6; ii++ ) diff --git a/common/pgm_base.cpp b/common/pgm_base.cpp index 7d04fce4d0..5aae852310 100644 --- a/common/pgm_base.cpp +++ b/common/pgm_base.cpp @@ -2,8 +2,8 @@ * This program source code file is part of KiCad, a free EDA CAD application. * * Copyright (C) 2004-2015 Jean-Pierre Charras, jp.charras at wanadoo.fr - * Copyright (C) 2008-2015 Wayne Stambaugh - * Copyright (C) 1992-2017 KiCad Developers, see AUTHORS.txt for contributors. + * Copyright (C) 2008 Wayne Stambaugh + * Copyright (C) 1992-2018 KiCad Developers, see AUTHORS.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 @@ -482,6 +482,7 @@ bool PGM_BASE::InitPgm() // KISYSMOD envVarName = wxT( "KISYSMOD" ); + if( wxGetEnv( envVarName, &envValue ) == true && !envValue.IsEmpty() ) { tmpFileName.AssignDir( envValue ); @@ -493,11 +494,13 @@ bool PGM_BASE::InitPgm() tmpFileName.AppendDir( wxT( "modules" ) ); envVarItem.SetDefinedExternally( false ); } + envVarItem.SetValue( tmpFileName.GetPath() ); m_local_env_vars[ envVarName ] = envVarItem; // KISYS3DMOD envVarName = wxT( "KISYS3DMOD" ); + if( wxGetEnv( envVarName, &envValue ) == true && !envValue.IsEmpty() ) { tmpFileName.AssignDir( envValue ); @@ -508,11 +511,13 @@ bool PGM_BASE::InitPgm() tmpFileName.AppendDir( wxT( "packages3d" ) ); envVarItem.SetDefinedExternally( false ); } + envVarItem.SetValue( tmpFileName.GetFullPath() ); m_local_env_vars[ envVarName ] = envVarItem; - // KICAD_PTEMPLATES - envVarName = wxT( "KICAD_PTEMPLATES" ); + // KICAD_TEMPLATE_DIR + envVarName = "KICAD_TEMPLATE_DIR"; + if( wxGetEnv( envVarName, &envValue ) == true && !envValue.IsEmpty() ) { tmpFileName.AssignDir( envValue ); @@ -520,15 +525,67 @@ bool PGM_BASE::InitPgm() } else { - tmpFileName = baseSharePath; - tmpFileName.AppendDir( wxT( "template" ) ); + // Attempt to find the best default template path. + SEARCH_STACK bases; + SEARCH_STACK templatePaths; + + SystemDirsAppend( &bases ); + + for( unsigned i = 0; i < bases.GetCount(); ++i ) + { + wxFileName fn( bases[i], wxEmptyString ); + + // Add KiCad template file path to search path list. + fn.AppendDir( "template" ); + + // Only add path if exists and can be read by the user. + if( fn.DirExists() && fn.IsDirReadable() ) + { + wxLogDebug( "Checking template path '%s' exists", fn.GetPath() ); + templatePaths.AddPaths( fn.GetPath() ); + } + } + + if( templatePaths.IsEmpty() ) + { + tmpFileName = baseSharePath; + tmpFileName.AppendDir( "template" ); + } + else + { + // Take the first one. There may be more but this will likely be the best option. + tmpFileName.AssignDir( templatePaths[0] ); + } + envVarItem.SetDefinedExternally( false ); } + + envVarItem.SetValue( tmpFileName.GetPath() ); + m_local_env_vars[ envVarName ] = envVarItem; + + // KICAD_USER_TEMPLATE_DIR + envVarName = "KICAD_USER_TEMPLATE_DIR"; + + if( wxGetEnv( envVarName, &envValue ) == true && !envValue.IsEmpty() ) + { + tmpFileName.AssignDir( envValue ); + envVarItem.SetDefinedExternally( true ); + } + else + { + // Default user template path. + tmpFileName = wxStandardPaths::Get().GetDocumentsDir(); + tmpFileName.AppendDir( "kicad" ); + tmpFileName.AppendDir( "template" ); + envVarItem.SetDefinedExternally( false ); + } + envVarItem.SetValue( tmpFileName.GetPath() ); m_local_env_vars[ envVarName ] = envVarItem; // KICAD_SYMBOLS envVarName = wxT( "KICAD_SYMBOL_DIR" ); + if( wxGetEnv( envVarName, &envValue ) == true && !envValue.IsEmpty() ) { tmpFileName.AssignDir( envValue ); @@ -540,6 +597,7 @@ bool PGM_BASE::InitPgm() tmpFileName.AppendDir( wxT( "library" ) ); envVarItem.SetDefinedExternally( false ); } + envVarItem.SetValue( tmpFileName.GetPath() ); m_local_env_vars[ envVarName ] = envVarItem; diff --git a/kicad/kicad.cpp b/kicad/kicad.cpp index c919519c5d..91d2e13a34 100644 --- a/kicad/kicad.cpp +++ b/kicad/kicad.cpp @@ -2,7 +2,7 @@ * This program source code file is part of KiCad, a free EDA CAD application. * * Copyright (C) 2004-2015 Jean-Pierre Charras, jp.charras at wanadoo.fr - * Copyright (C) 2004-2017 KiCad Developers, see AUTHORS.txt for contributors. + * Copyright (C) 2004-2018 KiCad Developers, see AUTHORS.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 @@ -59,6 +59,7 @@ KIFACE_I& Kiface() throw std::logic_error( "Unexpected call to Kiface() in kicad/kicad.cpp" ); } + static PGM_KICAD program; @@ -104,8 +105,24 @@ bool PGM_KICAD::OnPgmInit() // Add KiCad template file path to search path list. fn.AppendDir( wxT( "template" ) ); - m_bm.m_search.AddPaths( fn.GetPath() ); + + // Only add path if exists and can be read by the user. + if( fn.DirExists() && fn.IsDirReadable() ) + m_bm.m_search.AddPaths( fn.GetPath() ); } + + // The KICAD_TEMPLATE_DIR takes precedence over the search stack template path. + ENV_VAR_MAP_CITER it = GetLocalEnvVariables().find( "KICAD_TEMPLATE_DIR" ); + + if( it != GetLocalEnvVariables().end() && it->second.GetValue() != wxEmptyString ) + m_bm.m_search.Insert( it->second.GetValue(), 0 ); + + // The KICAD_USER_TEMPLATE_DIR takes precedence over KICAD_TEMPLATE_DIR and the search + // stack template path. + it = GetLocalEnvVariables().find( "KICAD_USER_TEMPLATE_DIR" ); + + if( it != GetLocalEnvVariables().end() && it->second.GetValue() != wxEmptyString ) + m_bm.m_search.Insert( it->second.GetValue(), 0 ); } // Must be called before creating the main frame in order to @@ -203,8 +220,9 @@ struct APP_KICAD : public wxApp #if defined (__LINUX__) APP_KICAD(): wxApp() { - // Disable proxy menu in Unity window manager. Only usual menubar works with wxWidgets (at least <= 3.1) - // When the proxy menu menubar is enable, some important things for us do not work: menuitems UI events and shortcuts. + // Disable proxy menu in Unity window manager. Only usual menubar works with + // wxWidgets (at least <= 3.1). When the proxy menu menubar is enable, some + // important things for us do not work: menuitems UI events and shortcuts. wxString wm; if( wxGetEnv( wxT( "XDG_CURRENT_DESKTOP" ), &wm ) && wm.CmpNoCase( wxT( "Unity" ) ) == 0 ) @@ -251,9 +269,8 @@ struct APP_KICAD : public wxApp } /** - * Function MacOpenFile - * is specific to MacOSX (not used under Linux or Windows). - * MacOSX requires it for file association. + * Set MacOS file associations. + * * @see http://wiki.wxwidgets.org/WxMac-specific_topics */ void MacOpenFile( const wxString& aFileName ) diff --git a/kicad/prjconfig.cpp b/kicad/prjconfig.cpp index 18501d8d51..ffebdc9299 100644 --- a/kicad/prjconfig.cpp +++ b/kicad/prjconfig.cpp @@ -270,82 +270,27 @@ void KICAD_MANAGER_FRAME::OnNewProject( wxCommandEvent& aEvent ) void KICAD_MANAGER_FRAME::OnCreateProjectFromTemplate( wxCommandEvent& event ) { - wxString default_dir = wxFileName( Prj().GetProjectFullName() ).GetPathWithSep(); - wxString title = _( "New Project Folder" ); - wxDirDialog dlg( this, title, default_dir ); - - if( dlg.ShowModal() == wxID_CANCEL ) - return; - - // Builds the project .pro filename, from the new project folder name - wxFileName fn; - fn.AssignDir( dlg.GetPath() ); - fn.SetName( dlg.GetPath().AfterLast( SEP() ) ); - fn.SetExt( wxT( "pro" ) ); - - wxChar sep[2] = { SEP(), 0 }; // nul terminated separator wxChar string. - - ClearMsg(); - DIALOG_TEMPLATE_SELECTOR* ps = new DIALOG_TEMPLATE_SELECTOR( this ); wxFileName templatePath; wxString envStr; -#ifndef __WXMAC__ - wxGetEnv( wxT( "KICAD" ), &envStr ); + // KiCad system template path. + ENV_VAR_MAP_CITER it = Pgm().GetLocalEnvVariables().find( "KICAD_TEMPLATE_DIR" ); - // Add a new tab for system templates - if( !envStr.empty() ) + if( it != Pgm().GetLocalEnvVariables().end() && it->second.GetValue() != wxEmptyString ) { - // user may or may not have including terminating separator. - if( !envStr.EndsWith( sep ) ) - envStr += sep; - - templatePath = envStr + wxT( "template" ) + sep; + templatePath.AssignDir( it->second.GetValue() ); + ps->AddTemplatesPage( _( "System Templates" ), templatePath ); } - else + + // User template path. + it = Pgm().GetLocalEnvVariables().find( "KICAD_USER_TEMPLATE_DIR" ); + + if( it != Pgm().GetLocalEnvVariables().end() && it->second.GetValue() != wxEmptyString ) { - // The standard path should be in the share directory for kicad. As - // it is normal on Windows to only have the share directory and not - // the kicad sub-directory we fall back to that if the directory - // doesn't exist - templatePath = wxPathOnly( wxStandardPaths::Get().GetExecutablePath() ) + - sep + wxT( ".." ) + sep + wxT( "share" ) + sep + wxT( "kicad" ) + - sep + wxT( "template" ) + sep; - - if( !wxDirExists( templatePath.GetFullPath() ) ) - { - templatePath = wxPathOnly( wxStandardPaths::Get().GetExecutablePath() ) + sep + - wxT( ".." ) + sep + wxT( "share" ) + sep + wxT( "template" ) + sep; - } - } -#else - // Use what is provided in the bundle data dir - templatePath = GetOSXKicadDataDir() + sep + wxT( "template" ); -#endif - - ps->AddTemplatesPage( _( "System Templates" ), templatePath ); - - // Add a new tab for user templates - wxFileName userPath = wxStandardPaths::Get().GetDocumentsDir() + sep + wxT( "kicad" ) + - sep + wxT( "template" ) + sep; - - ps->AddTemplatesPage( _( "User Templates" ), userPath ); - - // Check to see if a custom template location is available and setup a - // new selection tab if there is. - envStr.clear(); - wxGetEnv( wxT( "KICAD_PTEMPLATES" ), &envStr ); - - if( !envStr.empty() ) - { - if( !envStr.EndsWith( sep ) ) - envStr += sep; - - wxFileName envPath = envStr; - - ps->AddTemplatesPage( _( "Portable Templates" ), envPath ); + templatePath.AssignDir( it->second.GetValue() ); + ps->AddTemplatesPage( _( "User Templates" ), templatePath ); } // Show the project template selector dialog @@ -362,7 +307,21 @@ void KICAD_MANAGER_FRAME::OnCreateProjectFromTemplate( wxCommandEvent& event ) return; } - // Make sure the user has write permissions to the base path. + // Get project destination folder and project file name. + wxString default_dir = wxFileName( Prj().GetProjectFullName() ).GetPathWithSep(); + wxString title = _( "New Project Folder" ); + wxDirDialog dlg( this, title, default_dir ); + + if( dlg.ShowModal() == wxID_CANCEL ) + return; + + // Builds the project .pro filename, from the new project folder name + wxFileName fn; + fn.AssignDir( dlg.GetPath() ); + fn.SetName( dlg.GetPath().AfterLast( SEP() ) ); + fn.SetExt( "pro" ); + + // Make sure the user has write permissions to the project path. wxFileName prjPath = fn; while( !prjPath.DirExists() ) @@ -380,6 +339,8 @@ void KICAD_MANAGER_FRAME::OnCreateProjectFromTemplate( wxCommandEvent& event ) return; } + ClearMsg(); + // Make sure we are not overwriting anything in the destination folder. std::vector< wxFileName > destFiles;