diff --git a/common/plotters/PDF_plotter.cpp b/common/plotters/PDF_plotter.cpp index 3e7c19deec..c929d99e4f 100644 --- a/common/plotters/PDF_plotter.cpp +++ b/common/plotters/PDF_plotter.cpp @@ -1340,7 +1340,7 @@ bool PDF_PLOTTER::EndPlot() href = ResolveUriByEnvVars( href, m_project ); js += wxString::Format( wxT( "[\"%s\", \"%s\"],\n" ), - EscapeString( property, CTX_JS_STR ), + EscapeString( href, CTX_JS_STR ), EscapeString( href, CTX_JS_STR ) ); } else if( property.Find( "https:" ) >= 0 ) @@ -1351,7 +1351,7 @@ bool PDF_PLOTTER::EndPlot() href = ResolveUriByEnvVars( href, m_project ); js += wxString::Format( wxT( "[\"%s\", \"%s\"],\n" ), - EscapeString( property, CTX_JS_STR ), + EscapeString( href, CTX_JS_STR ), EscapeString( href, CTX_JS_STR ) ); } else if( property.Find( "file:" ) >= 0 ) @@ -1361,8 +1361,10 @@ bool PDF_PLOTTER::EndPlot() if( m_project ) href = ResolveUriByEnvVars( href, m_project ); + href = NormalizeFileUri( href ); + js += wxString::Format( wxT( "[\"%s\", \"%s\"],\n" ), - EscapeString( property, CTX_JS_STR ), + EscapeString( href, CTX_JS_STR ), EscapeString( href, CTX_JS_STR ) ); } else @@ -1388,13 +1390,22 @@ bool PDF_PLOTTER::EndPlot() } } } - else if( url.StartsWith( "http:" ) || url.StartsWith( "https:" ) ) + else if( url.StartsWith( "http:" ) || url.StartsWith( "https:" ) + || url.StartsWith( "file:" ) ) { - wxString menuText = wxString::Format( _( "Open %s" ), url ); + wxString href = url; + + if( m_project ) + href = ResolveUriByEnvVars( url, m_project ); + + if( url.StartsWith( "file:" ) ) + href = NormalizeFileUri( href ); + + wxString menuText = wxString::Format( _( "Open %s" ), href ); js += wxString::Format( wxT( "[\"%s\", \"%s\"],\n" ), - EscapeString( menuText, CTX_JS_STR ), - EscapeString( url, CTX_JS_STR ) ); + EscapeString( href, CTX_JS_STR ), + EscapeString( href, CTX_JS_STR ) ); } } @@ -1434,6 +1445,7 @@ function ShM(aEntries) { var cChoice = app.popUpMenuEx.apply(app, aParams); if (cChoice != null && cChoice.substring(0, 1) == '#') this.pageNum = parseInt(cChoice.slice(1)); else if (cChoice != null && cChoice.substring(0, 4) == 'http') app.launchURL(cChoice); + else if (cChoice != null && cChoice.substring(0, 4) == 'file') app.openDoc(cChoice.substring(7)); } )JS"; diff --git a/common/string_utils.cpp b/common/string_utils.cpp index 77c2c0881d..7b3bf86d64 100644 --- a/common/string_utils.cpp +++ b/common/string_utils.cpp @@ -34,7 +34,9 @@ #include #include // StrPrintf #include +#include #include +#include #include #include "locale_io.h" @@ -1457,3 +1459,29 @@ wxString From_UTF8( const std::string& aString ) return line; } + + +wxString NormalizeFileUri( const wxString& aFileUri ) +{ + wxString uriPathAndFileName; + + wxCHECK( aFileUri.StartsWith( wxS( "file://" ), &uriPathAndFileName ), aFileUri ); + + wxString tmp; + wxString retv = wxS( "file://" ); + wxFileName fn = uriPathAndFileName; + + tmp = fn.GetPathWithSep( wxPATH_UNIX ); + tmp.Replace( wxS( "\\" ), wxS( "/" ) ); + tmp.Replace( wxS( ":" ), wxS( "" ) ); + + if( !tmp.IsEmpty() && tmp[0] != '/' ) + tmp = wxS( "/" ) + tmp; + + retv += tmp; + retv += fn.GetFullName(); + + wxLogDebug( wxS( "Normalize file: '%s'." ), retv ); + + return retv; +} diff --git a/include/string_utils.h b/include/string_utils.h index 8dac917ecb..2f00f21a1e 100644 --- a/include/string_utils.h +++ b/include/string_utils.h @@ -1,7 +1,7 @@ /* * This program source code file is part of KiCad, a free EDA CAD application. * - * Copyright (C) 2004-2021 KiCad Developers, see change_log.txt for contributors. + * Copyright (C) 2004-2021, 2024 KiCad Developers, see change_log.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 @@ -405,4 +405,21 @@ KICOMMON_API std::string FormatDouble2Str( double aValue ); KICOMMON_API wxString From_UTF8( const std::string& aString ); KICOMMON_API wxString From_UTF8( const char* cstring ); +/** + * Normalize file path \a aFileUri to URI convention. + * + * Unfortunately none of the wxWidgets objects results in acceptable file URIs which breaks + * PDF plotting URI links. This is an attempt to normalize Windows local file paths to a + * URI that PDF readers that can run JavaScript can handle. + * + * @note This does not expand environment or user variables. Variable expansion should be + * performed before calling. If \a aFileUri does not begin with 'file://', \a aFileUri + * returned unchanged. + * + * @param aFileUri is the string to be normalized. + * @return the normalized string. + */ +KICOMMON_API wxString NormalizeFileUri( const wxString& aFileUri ); + + #endif // STRING_UTILS_H