35#include <wx/filedlg.h>
37#include <wx/tokenzr.h>
40#define GRID_CELL_MARGIN 4
53 std::shared_ptr<PLUGIN_CONTENT_MANAGER> aPcm,
57 m_actionCallback( aActionCallback ),
58 m_pinCallback( aPinCallback ),
73 m_searchCtrl->SetMinSize( wxSize( -1, GetTextExtent( wxT(
"qb" ) ).y + 10 ) );
96 wxColor background = wxStaticText::GetClassDefaultAttributes().colBg;
142 [package_panel,
this] ()
173 details << wxT(
"<h5>" ) + package.
name + wxT(
"</h5>" );
176 [](
const wxString&
text ) -> wxString
182 for(
unsigned i = 0; i <
text.length(); ++i )
184 wxUniChar c =
text[i];
188 if( c ==
' ' || c ==
'\n')
190 result += wxString::Format( wxT(
"<a href='%s'>%s</a>" ), url, url );
194 result += wxT(
"</p><p>" );
203 else if(
text.Mid( i, 5 ) == wxT(
"http:" )
204 ||
text.Mid( i, 6 ) == wxT(
"https:" ) )
211 result += wxT(
"</p><p>" );
220 result += wxString::Format( wxT(
"<a href='%s'>%s</a>" ), url, url );
225 wxString desc = package.description_full;
226 details << wxT(
"<p>" ) + format_desc( desc ) + wxT(
"</p>" );
228 details << wxT(
"<p><b>" ) +
_(
"Metadata" ) + wxT(
"</b></p>" );
229 details << wxT(
"<ul>" );
230 details << wxT(
"<li>" ) +
_(
"Package identifier: " ) + package.identifier + wxT(
"</li>" );
231 details << wxT(
"<li>" ) +
_(
"License: " ) + package.license + wxT(
"</li>" );
233 if( package.tags.size() > 0 )
237 for(
const std::string& tag : package.tags )
239 if( !tags_str.IsEmpty() )
245 details << wxT(
"<li>" ) +
_(
"Tags: " ) + tags_str + wxT(
"</li>" );
249 [](
const std::pair<const std::string, wxString>& entry ) -> wxString
251 wxString
name = entry.first;
254 if(
name == wxT(
"email" ) )
255 return wxString::Format( wxT(
"<a href='mailto:%s'>%s</a>" ), url, url );
256 else if( url.StartsWith( wxT(
"http:" ) ) || url.StartsWith( wxT(
"https:" ) ) )
257 return wxString::Format( wxT(
"<a href='%s'>%s</a>" ), url, url );
263 [&](
const wxString& type,
const PCM_CONTACT& contact )
265 details << wxT(
"<li>" ) + type + wxT(
": " ) + contact.name + wxT(
"<ul>" );
267 for(
const std::pair<const std::string, wxString>& entry : contact.contact )
269 details << wxT(
"<li>" );
270 details << entry.first << wxT(
": " ) + format_entry( entry );
271 details << wxT(
"</li>" );
274 details << wxT(
"</ul>" );
277 write_contact(
_(
"Author" ), package.author );
279 if( package.maintainer )
280 write_contact(
_(
"Maintainer" ), *package.maintainer );
282 if( package.resources.size() > 0 )
284 details << wxT(
"<li>" ) +
_(
"Resources" ) + wxT(
"<ul>" );
286 for(
const std::pair<const std::string, wxString>& entry : package.resources )
288 details << wxT(
"<li>" );
289 details << entry.first << wxT(
": " );
290 details << format_entry( entry ) + wxT(
"</li>" );
293 details << wxT(
"</ul>" );
296 details << wxT(
"</ul>" );
298 m_infoText->SetPage( details );
301 OnSizeInfoBox(
dummy );
304 m_gridVersions->Freeze();
306 if( m_gridVersions->GetNumberRows() != 0 )
307 m_gridVersions->DeleteRows( 0, m_gridVersions->GetNumberRows() );
310 wxString current_version;
313 current_version = m_pcm->GetInstalledPackageVersion( package.identifier );
315 wxFont bold_font = m_gridVersions->GetDefaultCellFont().Bold();
319 if( !version.
compatible && !m_showAllVersions->IsChecked() )
322 m_gridVersions->InsertRows( row );
324 m_gridVersions->SetCellValue( row, COL_VERSION, version.
version );
325 m_gridVersions->SetCellValue( row, COL_DOWNLOAD_SIZE,
327 m_gridVersions->SetCellValue( row, COL_INSTALL_SIZE,
329 m_gridVersions->SetCellValue( row, COL_COMPATIBILITY,
330 version.
compatible ? wxT(
"\u2714" ) : wxEmptyString );
331 m_gridVersions->SetCellValue( row, COL_STATUS, STATUS_ENUM_TO_STR.at( version.
status ) );
333 m_gridVersions->SetCellAlignment( row, COL_COMPATIBILITY, wxALIGN_CENTER, wxALIGN_CENTER );
335 if( current_version == version.
version )
337 for(
int col = 0; col < m_gridVersions->GetNumberCols(); col++ )
338 m_gridVersions->SetCellFont( row, col, bold_font );
344 for(
int col = 0; col < m_gridVersions->GetNumberCols(); col++ )
347 m_gridVersions->SetColSize( col, m_gridVersions->GetVisibleWidth( col ) );
351 if( m_gridVersions->GetNumberRows() >= 1 )
353 wxString version = m_currentSelected->GetPackageData().current_version;
355 if( version.IsEmpty() )
356 version = m_currentSelected->GetPreferredVersion();
358 if( !version.IsEmpty() )
360 for(
int i = 0; i < m_gridVersions->GetNumberRows(); i++ )
362 if( m_gridVersions->GetCellValue( i, COL_VERSION ) == version )
364 m_gridVersions->SelectRow( i );
365 m_gridVersions->SetGridCursor( i, COL_VERSION );
373 m_gridVersions->SelectRow( 0 );
377 m_gridVersions->Thaw();
379 updateDetailsButtons();
381 m_infoText->Show(
true );
382 m_sizerVersions->Show(
true );
383 m_sizerVersions->Layout();
385 wxSize size = m_infoScrollWindow->GetTargetWindow()->GetBestVirtualSize();
386 m_infoScrollWindow->SetVirtualSize( size );
416 if( b >= 1024 * 1024 )
417 return wxString::Format( wxT(
"%.1f MB" ), b / 1000.0 / 1000.0 );
420 return wxString::Format( wxT(
"%lld kB" ), b / 1000 );
422 return wxString::Format( wxT(
"%lld B" ), b );
442 switch( packageData.
state )
461 it->second->SetState( aState, aPinned );
503 const wxArrayInt selectedRows =
m_gridVersions->GetSelectedRows();
506 const PCM_PACKAGE&
package = m_currentSelected->GetPackageData().package;
508 auto ver_it = std::find_if( package.versions.begin(), package.versions.end(),
511 return ver.version == version;
514 wxASSERT_MSG( ver_it != package.
versions.end(),
"Could not find package version" );
516 if( !ver_it->download_url )
518 wxMessageBox(
_(
"Package download url is not specified" ),
519 _(
"Error downloading package" ), wxICON_INFORMATION | wxOK,
520 wxGetTopLevelParent(
this ) );
524 const wxString& url = *ver_it->download_url;
529 wxWindow* topLevelParent = wxGetTopLevelParent(
this );
531 wxString::Format( wxT(
"%s_v%s.zip" ), package.identifier, version ),
532 wxT(
"ZIP files (*.zip)|*.zip" ), wxFD_SAVE | wxFD_OVERWRITE_PROMPT );
534 if( dialog.ShowModal() == wxID_CANCEL )
537 wxString
path = dialog.GetPath();
540 std::ofstream output(
path.ToUTF8(), std::ios_base::binary );
542 std::unique_ptr<WX_PROGRESS_REPORTER> reporter =
543 std::make_unique<WX_PROGRESS_REPORTER>(
this,
_(
"Downloading package" ), 1 );
545 bool success = m_pcm->DownloadToStream( url, &output, reporter.get(), 0 );
551 if( ver_it->download_sha256 )
553 std::ifstream stream(
path.ToUTF8(), std::ios_base::binary );
555 bool matches = m_pcm->VerifyHash( stream, *ver_it->download_sha256 );
561 _(
"Integrity of the downloaded package could not be verified, hash "
562 "does not match. Are you sure you want to keep this file?" ),
563 _(
"Keep downloaded file" ), wxICON_EXCLAMATION | wxYES_NO,
564 wxGetTopLevelParent(
this ) )
567 wxRemoveFile(
path );
573 if( wxFileExists(
path ) )
574 wxRemoveFile(
path );
599 const wxArrayInt selectedRows =
m_gridVersions->GetSelectedRows();
602 const PCM_PACKAGE&
package = m_currentSelected->GetPackageData().package;
604 auto ver_it = std::find_if( package.versions.begin(), package.versions.end(),
607 return ver.version == version;
610 wxCHECK_RET( ver_it != package.
versions.end(),
"Could not find package version" );
612 if( !ver_it->compatible
613 && wxMessageBox(
_(
"This package version is incompatible with your KiCad version or "
614 "platform. Are you sure you want to install it anyway?" ),
615 _(
"Install package" ), wxICON_EXCLAMATION | wxYES_NO,
616 wxGetTopLevelParent(
this ) )
622 m_actionCallback( m_currentSelected->GetPackageData(), action, version );
654 std::vector<std::pair<int, int>> package_ranks;
656 const wxString search_term =
m_searchCtrl->GetValue().Trim();
664 if( search_term.size() > 2 )
665 rank =
m_pcm->GetPackageSearchRank( pkg, search_term );
671 package_ranks.emplace_back( rank, index );
674 std::sort( package_ranks.begin(), package_ranks.end(),
675 [](
const std::pair<int, int>& a,
const std::pair<int, int>& b )
677 return a.first > b.first || ( a.first == b.first && a.second < b.second );
682 sizer->Clear(
false );
684 for(
const std::pair<int, int>& pair : package_ranks )
690 sizer->Add( panel, 0, wxEXPAND );
734 wxT(
"getAction() called with ambiguous version selection" ) );
736 int selected_row = 0;
744 switch( package.state )
751 if( version == package.current_version )
770 infoSize.y =
m_infoText->GetInternalRepresentation()->GetHeight() + 12;
782 const wxHtmlLinkInfo&
info = aEvent.GetLinkInfo();
783 ::wxLaunchDefaultBrowser(
info.GetHref() );
815 std::vector<wxString> packages;
818 std::back_inserter( packages ) );
820 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.
bool SetPage(const wxString &aSource) override
wxString m_PcmLastDownloadDir
Class PANEL_PACKAGES_VIEW_BASE.
WX_SPLITTER_WINDOW * m_splitter1
wxScrolledWindow * m_packageListWindow
void m_splitter1OnIdle(wxIdleEvent &)
wxButton * m_buttonAction
wxButton * m_buttonUpdateAll
wxButton * m_buttonDownload
wxBoxSizer * m_sizerVersions
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
virtual SETTINGS_MANAGER & GetSettingsManager() const
T * GetAppSettings(const wxString &aFilename)
Returns a handle to the a given settings by type If the settings have already been loaded,...
int GetVisibleWidth(int aCol, bool aHeader=true, bool aContents=true, bool aKeep=false)
Calculates the specified column based on the actual size of the text on screen.
void SetBorders(bool aLeft, bool aRight, bool aTop, bool aBottom)
void SetPaneMinimums(int aFirst, int aSecond)
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
void Refresh()
Update the board display after modifying it by a python script (note: it is automatically called by a...
PGM_BASE & Pgm()
The global Program "get" accessor.
std::vector< FAB_LAYER_COLOR > dummy
wxString EscapeHTML(const wxString &aString)
Return a new wxString escaped for embedding in HTML.
< Package version metadata Package 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 Callback for (un)install button
Repository reference to a resource.
std::vector< PACKAGE_VERSION > versions