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() );
818 std::vector<wxString> packages;
822 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
Replacement of wxFormBuilder's ill-advised m_splitter1OnIdle.
std::unordered_set< wxString > m_updateablePackages
void OnUpdateAllClicked(wxCommandEvent &event) override
void ClearData()
Selects full row of the clicked cell.
void updateDetailsButtons()
Called when package state changes, currently used to calculate Update All button state.
void OnVersionActionClicked(wxCommandEvent &event) override
Shows all versions including incompatible ones.
void OnSizeInfoBox(wxSizeEvent &aEvent) override
Respond to a URL in the info window.
bool canDownload() const
Returns true if the package action can be performed.
void OnDownloadVersionClicked(wxCommandEvent &event) override
Schedules relevant action for selected package version.
wxString toHumanReadableSize(const std::optional< uint64_t > size) const
Returns true if it the download operation can be performed.
void OnSearchTextChanged(wxCommandEvent &event)
void updateCommonState()
Updates details panel.
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)
Clears details panel.
const PinCallback & m_pinCallback
std::shared_ptr< PLUGIN_CONTENT_MANAGER > m_pcm
PCM_PACKAGE_ACTION getAction() const
bool canRunAction() const
Returns implied action for the action button.
PANEL_PACKAGE * m_currentSelected
void unsetPackageDetails()
Bytes to Kb/Mb/Gb string or "-" if absent.
void SetData(const std::vector< PACKAGE_VIEW_DATA > &aPackageData)
Recreates package panels and displays data.
void OnVersionsCellClicked(wxGridEvent &event) override
Opens file chooser dialog and downloads selected package version archive.
void OnURLClicked(wxHtmlLinkEvent &event) override
Respond to scrolling over the window.
void SetSashOnIdle(wxIdleEvent &)
Enqueues all available package updates.
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
Ranks packages for entered search term and rearranges/hides panels according to their rank.
void OnClick(wxMouseEvent &event) override
const PACKAGE_VIEW_DATA & GetPackageData() const
void SetSelected(bool aSelected)
void SetSelectCallback(const std::function< void()> &aCallback)
Marks panel as selected.
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
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 metadataPackage 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 panelCallback for (un)install button
Repository reference to a resource.
std::vector< PACKAGE_VERSION > versions
wxString result
Test unit parsing edge cases and error handling.