From a97ccbf7ed6b529a8a9984a3f401c20d7e587309 Mon Sep 17 00:00:00 2001 From: "Marcus A. Romer" <5656753-aimylios@users.noreply.gitlab.com> Date: Mon, 5 Apr 2021 19:03:36 +0200 Subject: [PATCH] Refactor help file search logic Rely on existing code to initialise the list of paths in which the KiCad documentation might be located, thereby making SearchHelpFileFullPath platform-agnostic and easier to read. --- common/searchhelpfilefullpath.cpp | 252 ++++++++++-------------------- common/tool/common_control.cpp | 11 +- include/common.h | 27 ++-- 3 files changed, 96 insertions(+), 194 deletions(-) diff --git a/common/searchhelpfilefullpath.cpp b/common/searchhelpfilefullpath.cpp index 7021b9f2f4..344e0005a3 100644 --- a/common/searchhelpfilefullpath.cpp +++ b/common/searchhelpfilefullpath.cpp @@ -2,197 +2,107 @@ * This program source code file is part of KiCad, a free EDA CAD application. * * Copyright (C) 2014-2015 CERN - * Copyright (C) 2014-2018 KiCad Developers, see CHANGELOG.TXT for contributors. + * Copyright (C) 2014-2021 KiCad Developers, see AUTHORS.txt for contributors. * @author Maciej Suminski * - * 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 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. + * 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 + * You should have received a copy of the GNU General Public License along + * with this program. If not, see . */ -#include #include -#include // to define DEFAULT_INSTALL_PATH -#include -#include +#include +#include #include -#include + +#include +#include -/** - * Function FindFileInSearchPaths - * looks in "this" for \a aFilename, but first modifies every search - * path by appending a list of path fragments from aSubdirs. That modification - * is not relative. - */ -wxString FindFileInSearchPaths( const SEARCH_STACK& aStack, - const wxString& aFilename, const wxArrayString* aSubdirs ) +wxString SearchHelpFileFullPath( const wxString& aBaseName ) { - wxPathList paths; + SEARCH_STACK basePaths; + wxString helpFile; - for( unsigned i = 0; i < aStack.GetCount(); ++i ) + // the documentation is expected to be located in one of the system directories + SystemDirsAppend( &basePaths ); + +#if defined( DEBUG ) + basePaths.Show( wxString( __func__ ) + ": basePaths" ); +#endif + + // By default, the documentation from kicad-doc is installed to a folder called "help" with + // subdirectories for all supported languages. Although this can be changed at build-time by + // overwriting ${KICAD_DOC_PATH}, the best guess KiCad can make is that help files are always + // located in a folder named "help". If no translation matching the current locale settings is + // available, the English version will be returned instead. + + wxLocale* currentLocale = Pgm().GetLocale(); + wxArrayString localeNameDirs; + + // canonical form of the current locale (e.g., "fr_FR") + localeNameDirs.Add( currentLocale->GetCanonicalName() ); + + // short form of the current locale (e.g., "fr") + // wxLocale::GetName() does not always return the short form + localeNameDirs.Add( currentLocale->GetName().BeforeLast( '_' ) ); + + // plain English (in case a localised version of the help file cannot be found) + localeNameDirs.Add( "en" ); + + for( wxString& locale : localeNameDirs ) { - wxFileName fn( aStack[i], wxEmptyString ); + SEARCH_STACK docPaths; - if( aSubdirs ) + for( wxString& base : basePaths ) { - for( unsigned j = 0; j < aSubdirs->GetCount(); j++ ) - fn.AppendDir( (*aSubdirs)[j] ); + wxFileName path( base, wxEmptyString ); + + // add /help// + path.AppendDir( "help" ); + path.AppendDir( locale ); + docPaths.AddPaths( path.GetPath() ); + + // add /doc/help// + path.InsertDir( path.GetDirCount() - 2, "doc" ); + docPaths.AddPaths( path.GetPath() ); + + // add /doc/kicad/help// + path.InsertDir( path.GetDirCount() - 2, "kicad" ); + docPaths.AddPaths( path.GetPath() ); } - wxLogTrace( tracePathsAndFiles, " %s", fn.GetFullPath() ); +#if defined( DEBUG ) + docPaths.Show( wxString( __func__ ) + ": docPaths (" + locale + ")" ); +#endif - if( fn.DirExists() ) + // search HTML first, as it is the preferred format for help files + wxLogTrace( tracePathsAndFiles, "Checking SEARCH_STACK for file %s.html", aBaseName ); + helpFile = docPaths.FindValidPath( aBaseName + ".html" ); + + if( !helpFile.IsEmpty() ) { - paths.Add( fn.GetPath() ); + // prepend URI protocol to open the file in a browser + helpFile = "file://" + helpFile; + break; } + + // search PDF only when no corresponding HTML file was found + wxLogTrace( tracePathsAndFiles, "Checking SEARCH_STACK for file %s.pdf", aBaseName ); + helpFile = docPaths.FindValidPath( aBaseName + ".pdf" ); + + if( !helpFile.IsEmpty() ) + break; } - return paths.FindValidPath( aFilename ); -} - - -// See also FindKicadHelpPath.cpp.notused. -wxString SearchHelpFileFullPath( const SEARCH_STACK& aSStack, const wxString& aBaseName ) -{ - wxArrayString subdirs; - wxArrayString altsubdirs; - SEARCH_STACK ss = aSStack; - - // It might already be in aSStack, but why depend on other code - // far away when it's so easy to add it again (to our copy) as the first place to look. - - // This is CMAKE_INSTALL_PREFIX unless DEFAULT_INSTALL_PATH was defined during - // build configuration: - ss.AddPaths( wxT( DEFAULT_INSTALL_PATH ), 0 ); - -#if defined(__WXMAC__) - ss.AddPaths( PATHS::GetOSXKicadMachineDataDir() ); - ss.AddPaths( Pgm().GetExecutablePath(), 0 ); - - // OS X packages can have the help files in - // /Library/Application\ Support/kicad/help, - // and in Contents/SharedSupport/help inside the - // bundle. - // Below we account for an international subdirectory. - subdirs.Add( "help" ); - altsubdirs.Add( "Contents" ); - altsubdirs.Add( "SharedSupport" ); - altsubdirs.Add( "help" ); -#endif - -#if ! defined(__WXMAC__) // && defined(__linux__) - // This is the executable path minus the trailing bin directory used on Windows and Linux. - wxFileName tmp( Pgm().GetExecutablePath(), wxEmptyString ); - wxArrayString binDirs = tmp.GetDirs(); - - if( !binDirs.IsEmpty() && binDirs[ binDirs.GetCount() - 1 ].CmpNoCase( wxT( "bin" ) ) == 0 ) - tmp.RemoveLastDir(); - - ss.AddPaths( tmp.GetPath(), 0 ); - - // Based on kicad-doc.bzr/CMakeLists.txt, line 20, the help files are - // installed into "/share/doc/kicad/help" for linux. - // This is ${KICAD_HELP} var in that CMakeLists.txt file. - // Below we account for an international subdirectory. - subdirs.Add( "share" ); - subdirs.Add( "doc" ); - subdirs.Add( "kicad" ); - subdirs.Add( "help" ); - - // Based on kicad-doc.bzr/CMakeLists.txt, line 35, the help files are - // installed into "/doc/help" for Windows. - // This is ${KICAD_HELP} var in that CMakeLists.txt file. - // Below we account for an international subdirectory. - altsubdirs.Add( "doc" ); - altsubdirs.Add( "help" ); -#endif - - // If there's a KICAD environment variable set, always use that guy's path first. - if( !Pgm().GetKicadEnvVariable().IsEmpty() ) - ss.AddPaths( Pgm().GetKicadEnvVariable(), 0 ); - - /* Search for a help file. - * we *must* find a help file. - * so help is searched in directories in this order: - * help/ like help/en_GB - * help/ like help/en - * help/en - */ - - wxLocale* i18n = Pgm().GetLocale(); - - // We try to find help file in help/ - // If fails, try to find help file in help/ - // If fails, try to find help file in help/en - wxArrayString locale_name_dirs; - locale_name_dirs.Add( i18n->GetCanonicalName() ); // canonical name like fr_FR - - // wxLocale::GetName() does not return always the short name - locale_name_dirs.Add( i18n->GetName().BeforeLast( '_' ) ); // short canonical name like fr - locale_name_dirs.Add( "en" ); // default (en) - -#if defined(DEBUG) && 1 - ss.Show( wxString( __func__ ) ); - wxLogTrace( tracePathsAndFiles, "%s: m_help_file:'%s'", __func__, aBaseName ); -#endif - - wxLogTrace( tracePathsAndFiles, "Checking SEARCH_STACK for file %s", aBaseName ); - - // Help files can be html (.html ext) or pdf (.pdf ext) files. - // Therefore, .html file is searched and if not found, - // .pdf file is searched in the same paths - wxString fn; - - for( unsigned ii = 0; ii < locale_name_dirs.GetCount(); ii++ ) - { - subdirs.Add( locale_name_dirs[ii] ); - altsubdirs.Add( locale_name_dirs[ii] ); - - fn = FindFileInSearchPaths( ss, aBaseName + wxT( ".html" ), &altsubdirs ); - - if( !fn.IsEmpty() ) - { - // Prepend URI protocol since we will open in a browser - fn = wxT( "file://" ) + fn; - break; - } - - fn = FindFileInSearchPaths( ss, aBaseName + wxT( ".pdf" ), &altsubdirs ); - - if( !fn.IsEmpty() ) - break; - - fn = FindFileInSearchPaths( ss, aBaseName + wxT( ".html" ), &subdirs ); - - if( !fn.IsEmpty() ) - { - // Prepend URI protocol since we will open in a browser - fn = wxT( "file://" ) + fn; - break; - } - - fn = FindFileInSearchPaths( ss, aBaseName + wxT( ".pdf" ), &subdirs ); - - if( !fn.IsEmpty() ) - break; - - subdirs.RemoveAt( subdirs.GetCount() - 1 ); - altsubdirs.RemoveAt( altsubdirs.GetCount() - 1 ); - } - - return fn; + return helpFile; } diff --git a/common/tool/common_control.cpp b/common/tool/common_control.cpp index 6410b66a27..b5bf688feb 100644 --- a/common/tool/common_control.cpp +++ b/common/tool/common_control.cpp @@ -166,9 +166,8 @@ int COMMON_CONTROL::ShowPlayer( const TOOL_EVENT& aEvent ) int COMMON_CONTROL::ShowHelp( const TOOL_EVENT& aEvent ) { - const SEARCH_STACK& search = m_frame->sys_search(); - wxString helpFile; - wxString msg; + wxString helpFile; + wxString msg; /* We have to get document for beginners, * or the full specific doc @@ -188,7 +187,7 @@ int COMMON_CONTROL::ShowHelp( const TOOL_EVENT& aEvent ) // or "Getting_Started_in_KiCad.html" or "Getting_Started_in_KiCad.pdf" for( auto& name : names ) { - helpFile = SearchHelpFileFullPath( search, name ); + helpFile = SearchHelpFileFullPath( name ); if( !helpFile.IsEmpty() ) break; @@ -196,7 +195,7 @@ int COMMON_CONTROL::ShowHelp( const TOOL_EVENT& aEvent ) if( !helpFile ) { - msg = wxString::Format( _( "Html or pdf help file \n%s\nor\n%s could not be found." ), + msg = wxString::Format( _( "Help file \"%s\" or\n\"%s\" could not be found." ), names[0], names[1] ); wxMessageBox( msg ); return -1; @@ -206,7 +205,7 @@ int COMMON_CONTROL::ShowHelp( const TOOL_EVENT& aEvent ) { wxString base_name = m_frame->help_name(); - helpFile = SearchHelpFileFullPath( search, base_name ); + helpFile = SearchHelpFileFullPath( base_name ); if( !helpFile ) { diff --git a/include/common.h b/include/common.h index 76ca05bb26..e59d449caf 100644 --- a/include/common.h +++ b/include/common.h @@ -57,24 +57,17 @@ int ProcessExecute( const wxString& aCommandLine, int aFlags = wxEXEC_ASYNC, /** * Return the help file's full path. - *

- * Return the KiCad help file with path and extension. - * Help files can be html (.html ext) or pdf (.pdf ext) files. - * A \.html file is searched and if not found, - * \.pdf file is searched in the same path. - * If the help file for the current locale is not found, an attempt to find - * the English version of the help file is made. - * Help file is searched in directories in this order: - * help/\ like help/en_GB - * help/\ like help/en - * help/en - *

- * @param aSearchStack contains some possible base dirs that may be above the - * the one actually holding @a aBaseName. These are starting points for nested searches. - * @param aBaseName is the name of the help file to search for,

without extension

. - * @return wxEmptyString is returned if aBaseName is not found, else the full path & filename. + * + * Return the full path and name (including extension) of the given KiCad help file. It is expected + * to be found in a subfolder help/\<_LANG_\>/ in one of the system paths. Supported file types are + * *.html and *.pdf. If no such file is available for the current locale, an attempt to find the + * English version is made. The search order for \<_LANG_\> is: 1) canonical form (e.g., "fr_FR"), + * 2) short form (e.g., "fr"), and 3) "en". + * + * @param aBaseName is the name of the help file to search for (without extension). + * @return the full path and filename if \a aBaseName is found, else wxEmptyString. */ -wxString SearchHelpFileFullPath( const SEARCH_STACK& aSearchStack, const wxString& aBaseName ); +wxString SearchHelpFileFullPath( const wxString& aBaseName ); /** * Make \a aTargetFullFileName absolute and create the path of this file if it doesn't yet exist.