35#include <wx/filedlg.h>
37#include <wx/tokenzr.h>
40#define GRID_CELL_MARGIN 4
53 std::shared_ptr<PLUGIN_CONTENT_MANAGER> aPcm,
68 m_splitter1->SetPaneMinimums( FromDIP( 350 ), FromDIP( 450 ) );
73 m_searchCtrl->SetMinSize( wxSize( -1, GetTextExtent( wxT(
"qb" ) ).y + 10 ) );
79 m_panelList->SetBorders(
false,
true,
false,
false );
96 wxColor background = wxStaticText::GetClassDefaultAttributes().colBg;
141 [package_panel,
this] ()
168 bool supportsIpc = std::any_of( package.versions.begin(), package.versions.end(),
171 return aVersion.runtime.value_or( PCM_PACKAGE_RUNTIME::PPR_SWIG )
172 == PCM_PACKAGE_RUNTIME::PPR_IPC;
174 bool legacyRuntimeOnly = ( package.type ==
PT_PLUGIN || package.type ==
PT_FAB ) && !supportsIpc;
179 details << wxT(
"<h5>" ) + package.name + wxT(
"</h5>" );
181 if( legacyRuntimeOnly )
183 details << wxT(
"<p><b>" )
184 +
_(
"Warning: This plugin only supports the legacy Python API "
185 "and will not run in this KiCad version." )
190 [](
const wxString&
text ) -> wxString
196 for(
unsigned i = 0; i <
text.length(); ++i )
198 wxUniChar c =
text[i];
202 if( c ==
' ' || c ==
'\n')
204 result += wxString::Format( wxT(
"<a href='%s'>%s</a>" ), url, url );
208 result += wxT(
"</p><p>" );
217 else if(
text.Mid( i, 5 ) == wxT(
"http:" )
218 ||
text.Mid( i, 6 ) == wxT(
"https:" ) )
225 result += wxT(
"</p><p>" );
234 result += wxString::Format( wxT(
"<a href='%s'>%s</a>" ), url, url );
239 wxString desc = package.description_full;
240 details << wxT(
"<p>" ) + format_desc( desc ) + wxT(
"</p>" );
242 details << wxT(
"<p><b>" ) +
_(
"Metadata" ) + wxT(
"</b></p>" );
243 details << wxT(
"<ul>" );
244 details << wxT(
"<li>" ) +
_(
"Package identifier: " ) + package.identifier + wxT(
"</li>" );
245 details << wxT(
"<li>" ) +
_(
"License: " ) + package.license + wxT(
"</li>" );
247 if( package.tags.size() > 0 )
251 for(
const std::string& tag : package.tags )
253 if( !tags_str.IsEmpty() )
259 details << wxT(
"<li>" ) +
_(
"Tags: " ) + tags_str + wxT(
"</li>" );
263 [](
const std::pair<const std::string, wxString>& entry ) -> wxString
265 wxString
name = entry.first;
268 if(
name == wxT(
"email" ) )
269 return wxString::Format( wxT(
"<a href='mailto:%s'>%s</a>" ), url, url );
270 else if( url.StartsWith( wxT(
"http:" ) ) || url.StartsWith( wxT(
"https:" ) ) )
271 return wxString::Format( wxT(
"<a href='%s'>%s</a>" ), url, url );
277 [&](
const wxString& type,
const PCM_CONTACT& contact )
279 details << wxT(
"<li>" ) + type + wxT(
": " ) + contact.name + wxT(
"<ul>" );
281 for(
const std::pair<const std::string, wxString>& entry : contact.contact )
283 details << wxT(
"<li>" );
284 details << entry.first << wxT(
": " ) + format_entry( entry );
285 details << wxT(
"</li>" );
288 details << wxT(
"</ul>" );
291 write_contact(
_(
"Author" ), package.author );
293 if( package.maintainer )
294 write_contact(
_(
"Maintainer" ), *package.maintainer );
296 if( package.resources.size() > 0 )
298 details << wxT(
"<li>" ) +
_(
"Resources" ) + wxT(
"<ul>" );
300 for(
const std::pair<const std::string, wxString>& entry : package.resources )
302 details << wxT(
"<li>" );
303 details << entry.first << wxT(
": " );
304 details << format_entry( entry ) + wxT(
"</li>" );
307 details << wxT(
"</ul>" );
310 details << wxT(
"</ul>" );
322 wxString current_version;
325 current_version =
m_pcm->GetInstalledPackageVersion( package.identifier );
344 if( current_version == version.
version )
364 if( version.IsEmpty() )
367 if( !version.IsEmpty() )
422 if( b >= 1024 * 1024 )
423 return wxString::Format( wxT(
"%.1f MB" ), b / 1000.0 / 1000.0 );
426 return wxString::Format( wxT(
"%lld kB" ), b / 1000 );
428 return wxString::Format( wxT(
"%lld B" ), b );
448 switch( packageData.
state )
470 it->second->SetState( aState, aPinned );
508 const wxArrayInt selectedRows =
m_gridVersions->GetSelectedRows();
511 const PCM_PACKAGE&
package = m_currentSelected->GetPackageData().package;
513 auto ver_it = std::find_if( package.versions.begin(), package.versions.end(),
516 return ver.version == version;
519 wxASSERT_MSG( ver_it != package.
versions.end(),
"Could not find package version" );
521 if( !ver_it->download_url )
523 wxMessageBox(
_(
"Package download url is not specified" ),
_(
"Error downloading package" ),
524 wxICON_INFORMATION | wxOK, wxGetTopLevelParent(
this ) );
528 const wxString& url = *ver_it->download_url;
531 wxWindow* topLevelParent = wxGetTopLevelParent(
this );
533 wxString::Format( wxT(
"%s_v%s.zip" ), package.identifier, version ),
534 wxT(
"ZIP files (*.zip)|*.zip" ), wxFD_SAVE | wxFD_OVERWRITE_PROMPT );
538 if( dialog.ShowModal() == wxID_CANCEL )
541 wxString
path = dialog.GetPath();
544 std::ofstream output(
path.ToUTF8(), std::ios_base::binary );
548 bool success =
m_pcm->DownloadToStream( url, &output, &
reporter, 0 );
554 if( ver_it->download_sha256 )
556 std::ifstream stream(
path.ToUTF8(), std::ios_base::binary );
558 bool matches =
m_pcm->VerifyHash( stream, *ver_it->download_sha256 );
562 if( !matches && wxMessageBox(
_(
"Integrity of the downloaded package could not be verified, hash "
563 "does not match. Are you sure you want to keep this file?" ),
564 _(
"Keep downloaded file" ), wxICON_EXCLAMATION | wxYES_NO,
565 wxGetTopLevelParent(
this ) )
568 wxRemoveFile(
path );
574 if( wxFileExists(
path ) )
575 wxRemoveFile(
path );
600 const wxArrayInt selectedRows =
m_gridVersions->GetSelectedRows();
603 const PCM_PACKAGE&
package = m_currentSelected->GetPackageData().package;
605 auto ver_it = std::find_if( package.versions.begin(), package.versions.end(),
608 return ver.version == version;
611 wxCHECK_RET( ver_it != package.
versions.end(),
"Could not find package version" );
613 if( ( !ver_it->compatible ||
m_pcm->UsesSWIGRuntime( package, version ) )
614 && wxMessageBox(
_(
"This package version is incompatible with your KiCad version or "
615 "platform. Are you sure you want to install it anyway?" ),
616 _(
"Install package" ), wxICON_EXCLAMATION | wxYES_NO, wxGetTopLevelParent(
this ) )
654 std::vector<std::pair<int, int>> package_ranks;
656 const wxString search_term =
m_searchCtrl->GetValue().Trim();
663 if( search_term.size() > 2 )
664 rank =
m_pcm->GetPackageSearchRank( pkg, search_term );
670 package_ranks.emplace_back( rank,
index );
673 std::sort( package_ranks.begin(), package_ranks.end(),
674 [](
const std::pair<int, int>& a,
const std::pair<int, int>& b )
676 return a.first > b.first || ( a.first == b.first && a.second < b.second );
681 sizer->Clear(
false );
683 for(
const std::pair<int, int>& pair : package_ranks )
689 sizer->Add( panel, 0, wxEXPAND );
738 wxT(
"getAction() called with ambiguous version selection" ) );
740 int selected_row = 0;
748 switch( package.state )
751 case PPS_UNAVAILABLE:
754 case PPS_UPDATE_AVAILABLE:
755 if( version == package.current_version )
756 return PPA_UNINSTALL;
774 infoSize.y =
m_infoText->GetInternalRepresentation()->GetHeight() + 12;
786 const wxHtmlLinkInfo&
info = aEvent.GetLinkInfo();
787 ::wxLaunchDefaultBrowser(
info.GetHref() );
793 if( event.GetWheelAxis() != wxMOUSE_WHEEL_VERTICAL )
807 if( event.IsPageScroll() )
834 std::vector<wxString> packages;
838 for(
const wxString& pkg_id : packages )
PACKAGE_MANAGER m_PackageManager
Add mouse and command handling (such as cut, copy, and paste) to a WX_GRID instance.
wxString m_PcmLastDownloadDir
WX_SPLITTER_WINDOW * m_splitter1
wxScrolledWindow * m_packageListWindow
void m_splitter1OnIdle(wxIdleEvent &)
PANEL_PACKAGES_VIEW_BASE(wxWindow *parent, wxWindowID id=wxID_ANY, const wxPoint &pos=wxDefaultPosition, const wxSize &size=wxSize(-1,-1), long style=wxTAB_TRAVERSAL, const wxString &name=wxEmptyString)
wxButton * m_buttonAction
wxButton * m_buttonUpdateAll
wxButton * m_buttonDownload
wxBoxSizer * m_sizerVersions
wxCheckBox * m_showAllVersions
wxScrolledWindow * m_infoScrollWindow
wxSearchCtrl * m_searchCtrl
void OnInfoMouseWheel(wxMouseEvent &event) override
Respond to scrolling over the window.
std::unordered_set< wxString > m_updateablePackages
void OnUpdateAllClicked(wxCommandEvent &event) override
Enqueues all available package updates.
void ClearData()
Destroys package panels.
void updateDetailsButtons()
Updates buttons below the package details: Download and Install.
void OnVersionActionClicked(wxCommandEvent &event) override
Schedules relevant action for selected package version.
void OnSizeInfoBox(wxSizeEvent &aEvent) override
bool canDownload() const
Returns true if it the download operation can be performed.
void OnDownloadVersionClicked(wxCommandEvent &event) override
Opens file chooser dialog and downloads selected package version archive.
wxString toHumanReadableSize(const std::optional< uint64_t > size) const
Bytes to Kb/Mb/Gb string or "-" if absent.
void OnSearchTextChanged(wxCommandEvent &event)
Ranks packages for entered search term and rearranges/hides panels according to their rank.
void updateCommonState()
Called when package state changes, currently used to calculate Update All button state.
void updatePackageList()
Updates package listing according to search term.
const ActionCallback & m_actionCallback
std::unordered_map< wxString, PANEL_PACKAGE * > m_packagePanels
void setPackageDetails(const PACKAGE_VIEW_DATA &aPackageData)
Updates details panel.
const PinCallback & m_pinCallback
std::shared_ptr< PLUGIN_CONTENT_MANAGER > m_pcm
PCM_PACKAGE_ACTION getAction() const
Returns implied action for the action button.
bool canRunAction() const
Returns true if the package action can be performed.
PANEL_PACKAGE * m_currentSelected
void unsetPackageDetails()
Clears details panel.
void SetData(const std::vector< PACKAGE_VIEW_DATA > &aPackageData)
Recreates package panels and displays data.
void OnVersionsCellClicked(wxGridEvent &event) override
Selects full row of the clicked cell.
void OnURLClicked(wxHtmlLinkEvent &event) override
Respond to a URL in the info window.
void SetSashOnIdle(wxIdleEvent &)
Replacement of wxFormBuilder's ill-advised m_splitter1OnIdle.
static std::unordered_map< PCM_PACKAGE_VERSION_STATUS, wxString > STATUS_ENUM_TO_STR
void SetPackageState(const wxString &aPackageId, const PCM_PACKAGE_STATE aState, const bool aPinned)
Set the state of package.
std::vector< wxString > m_packageInitialOrder
PANEL_PACKAGES_VIEW(wxWindow *parent, std::shared_ptr< PLUGIN_CONTENT_MANAGER > aPcm, const ActionCallback &aCallback, const PinCallback &aPinCallback)
void OnShowAllVersionsClicked(wxCommandEvent &event) override
Shows all versions including incompatible ones.
void OnClick(wxMouseEvent &event) override
Called when anywhere on the panel is clicked (except install button)
const PACKAGE_VIEW_DATA & GetPackageData() const
void SetSelected(bool aSelected)
Marks panel as selected.
void SetSelectCallback(const std::function< void()> &aCallback)
Sets callback for OnClick action.
virtual COMMON_SETTINGS * GetCommonSettings() const
Multi-thread safe progress reporter dialog, intended for use of tasks that parallel reporting back of...
std::function< void(const wxString &aPackageId, const PCM_PACKAGE_STATE aState, const bool aPinned)> PinCallback
std::function< void(const PACKAGE_VIEW_DATA &aData, PCM_PACKAGE_ACTION aAction, const wxString &aVersion)> ActionCallback
Callback for (un)install button.
PCM_PACKAGE_STATE
Package states Package is available if it is not installed and there is a compatible version Package ...
PCM_PACKAGE_ACTION
Package actions.
PGM_BASE & Pgm()
The global program "get" accessor.
T * GetAppSettings(const char *aFilename)
std::vector< FAB_LAYER_COLOR > dummy
wxString EscapeHTML(const wxString &aString)
Return a new wxString escaped for embedding in HTML.
Package version metadata.
std::optional< uint64_t > download_size
std::optional< uint64_t > install_size
PCM_PACKAGE_VERSION_STATUS status
Collection of data relevant to the package display panel.
std::vector< PACKAGE_VERSION > versions
IbisParser parser & reporter
wxString result
Test unit parsing edge cases and error handling.