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;
139 [package_panel,
this] ()
170 details << wxT(
"<h5>" ) + package.
name + wxT(
"</h5>" );
173 [](
const wxString&
text ) -> wxString
179 for(
unsigned i = 0; i <
text.length(); ++i )
181 wxUniChar c =
text[i];
185 if( c ==
' ' || c ==
'\n')
187 result += wxString::Format( wxT(
"<a href='%s'>%s</a>" ), url, url );
191 result += wxT(
"</p><p>" );
200 else if(
text.Mid( i, 5 ) == wxT(
"http:" )
201 ||
text.Mid( i, 6 ) == wxT(
"https:" ) )
208 result += wxT(
"</p><p>" );
217 result += wxString::Format( wxT(
"<a href='%s'>%s</a>" ), url, url );
222 wxString desc = package.description_full;
223 details << wxT(
"<p>" ) + format_desc( desc ) + wxT(
"</p>" );
225 details << wxT(
"<p><b>" ) +
_(
"Metadata" ) + wxT(
"</b></p>" );
226 details << wxT(
"<ul>" );
227 details << wxT(
"<li>" ) +
_(
"Package identifier: " ) + package.identifier + wxT(
"</li>" );
228 details << wxT(
"<li>" ) +
_(
"License: " ) + package.license + wxT(
"</li>" );
230 if( package.tags.size() > 0 )
234 for(
const std::string& tag : package.tags )
236 if( !tags_str.IsEmpty() )
242 details << wxT(
"<li>" ) +
_(
"Tags: " ) + tags_str + wxT(
"</li>" );
246 [](
const std::pair<const std::string, wxString>& entry ) -> wxString
248 wxString
name = entry.first;
251 if(
name == wxT(
"email" ) )
252 return wxString::Format( wxT(
"<a href='mailto:%s'>%s</a>" ), url, url );
253 else if( url.StartsWith( wxT(
"http:" ) ) || url.StartsWith( wxT(
"https:" ) ) )
254 return wxString::Format( wxT(
"<a href='%s'>%s</a>" ), url, url );
260 [&](
const wxString& type,
const PCM_CONTACT& contact )
262 details << wxT(
"<li>" ) + type + wxT(
": " ) + contact.name + wxT(
"<ul>" );
264 for(
const std::pair<const std::string, wxString>& entry : contact.contact )
266 details << wxT(
"<li>" );
267 details << entry.first + wxT(
": " ) + format_entry( entry );
268 details << wxT(
"</li>" );
271 details << wxT(
"</ul>" );
274 write_contact(
_(
"Author" ), package.author );
276 if( package.maintainer )
277 write_contact(
_(
"Maintainer" ), *package.maintainer );
279 if( package.resources.size() > 0 )
281 details << wxT(
"<li>" ) +
_(
"Resources" ) + wxT(
"<ul>" );
283 for(
const std::pair<const std::string, wxString>& entry : package.resources )
285 details << wxT(
"<li>" );
286 details << entry.first + wxT(
": " );
287 details << format_entry( entry ) + wxT(
"</li>" );
290 details << wxT(
"</ul>" );
293 details << wxT(
"</ul>" );
295 m_infoText->SetPage( details );
298 OnSizeInfoBox(
dummy );
301 m_gridVersions->Freeze();
303 if( m_gridVersions->GetNumberRows() != 0 )
304 m_gridVersions->DeleteRows( 0, m_gridVersions->GetNumberRows() );
307 wxString current_version;
310 current_version = m_pcm->GetInstalledPackageVersion( package.identifier );
312 wxFont bold_font = m_gridVersions->GetDefaultCellFont().Bold();
316 if( !version.
compatible && !m_showAllVersions->IsChecked() )
319 m_gridVersions->InsertRows( row );
321 m_gridVersions->SetCellValue( row, COL_VERSION, version.
version );
322 m_gridVersions->SetCellValue( row, COL_DOWNLOAD_SIZE,
324 m_gridVersions->SetCellValue( row, COL_INSTALL_SIZE,
326 m_gridVersions->SetCellValue( row, COL_COMPATIBILITY,
327 version.
compatible ? wxT(
"\u2714" ) : wxEmptyString );
328 m_gridVersions->SetCellValue( row, COL_STATUS, STATUS_ENUM_TO_STR.at( version.
status ) );
330 m_gridVersions->SetCellAlignment( row, COL_COMPATIBILITY, wxALIGN_CENTER, wxALIGN_CENTER );
332 if( current_version == version.
version )
334 for(
int col = 0; col < m_gridVersions->GetNumberCols(); col++ )
335 m_gridVersions->SetCellFont( row, col, bold_font );
341 for(
int col = 0; col < m_gridVersions->GetNumberCols(); col++ )
344 m_gridVersions->SetColSize( col, m_gridVersions->GetVisibleWidth( col ) );
348 if( m_gridVersions->GetNumberRows() >= 1 )
350 wxString version = m_currentSelected->GetPackageData().current_version;
352 if( version.IsEmpty() )
353 version = m_currentSelected->GetPreferredVersion();
355 if( !version.IsEmpty() )
357 for(
int i = 0; i < m_gridVersions->GetNumberRows(); i++ )
359 if( m_gridVersions->GetCellValue( i, COL_VERSION ) == version )
361 m_gridVersions->SelectRow( i );
362 m_gridVersions->SetGridCursor( i, COL_VERSION );
370 m_gridVersions->SelectRow( 0 );
374 m_gridVersions->Thaw();
376 updateDetailsButtons();
378 m_infoText->Show(
true );
379 m_sizerVersions->Show(
true );
380 m_sizerVersions->Layout();
382 wxSize size = m_infoScrollWindow->GetTargetWindow()->GetBestVirtualSize();
383 m_infoScrollWindow->SetVirtualSize( size );
413 if( b >= 1024 * 1024 )
414 return wxString::Format( wxT(
"%.1f MB" ), b / 1000.0 / 1000.0 );
417 return wxString::Format( wxT(
"%lld kB" ), b / 1000 );
419 return wxString::Format( wxT(
"%lld B" ), b );
439 switch( packageData.
state )
458 it->second->SetState( aState, aPinned );
500 const wxArrayInt selectedRows =
m_gridVersions->GetSelectedRows();
503 const PCM_PACKAGE&
package = m_currentSelected->GetPackageData().package;
505 auto ver_it = std::find_if( package.versions.begin(), package.versions.end(),
508 return ver.version == version;
511 wxASSERT_MSG( ver_it != package.
versions.end(),
"Could not find package version" );
513 if( !ver_it->download_url )
515 wxMessageBox(
_(
"Package download url is not specified" ),
516 _(
"Error downloading package" ), wxICON_INFORMATION | wxOK,
this );
520 const wxString& url = *ver_it->download_url;
526 wxString::Format( wxT(
"%s_v%s.zip" ), package.identifier, version ),
527 wxT(
"ZIP files (*.zip)|*.zip" ), wxFD_SAVE | wxFD_OVERWRITE_PROMPT );
529 if( dialog.ShowModal() == wxID_CANCEL )
532 wxString
path = dialog.GetPath();
535 std::ofstream output(
path.ToUTF8(), std::ios_base::binary );
537 std::unique_ptr<WX_PROGRESS_REPORTER> reporter =
538 std::make_unique<WX_PROGRESS_REPORTER>(
this,
_(
"Downloading package" ), 1 );
540 bool success = m_pcm->DownloadToStream( url, &output, reporter.get(), 0 );
546 if( ver_it->download_sha256 )
548 std::ifstream stream(
path.ToUTF8(), std::ios_base::binary );
550 bool matches = m_pcm->VerifyHash( stream, *ver_it->download_sha256 );
556 _(
"Integrity of the downloaded package could not be verified, hash "
557 "does not match. Are you sure you want to keep this file?" ),
558 _(
"Keep downloaded file" ), wxICON_EXCLAMATION | wxYES_NO,
this )
561 wxRemoveFile(
path );
567 if( wxFileExists(
path ) )
568 wxRemoveFile(
path );
593 const wxArrayInt selectedRows =
m_gridVersions->GetSelectedRows();
596 const PCM_PACKAGE&
package = m_currentSelected->GetPackageData().package;
598 auto ver_it = std::find_if( package.versions.begin(), package.versions.end(),
601 return ver.version == version;
604 wxCHECK_RET( ver_it != package.
versions.end(),
"Could not find package version" );
606 if( !ver_it->compatible
607 && wxMessageBox(
_(
"This package version is incompatible with your kicad version or "
608 "platform. Are you sure you want to install it anyway?" ),
609 _(
"Install package" ), wxICON_EXCLAMATION | wxYES_NO,
this )
615 m_actionCallback( m_currentSelected->GetPackageData(), action, version );
647 std::vector<std::pair<int, int>> package_ranks;
649 const wxString search_term =
m_searchCtrl->GetValue().Trim();
657 if( search_term.size() > 2 )
658 rank =
m_pcm->GetPackageSearchRank( pkg, search_term );
664 package_ranks.emplace_back( rank, index );
667 std::sort( package_ranks.begin(), package_ranks.end(),
668 [](
const std::pair<int, int>& a,
const std::pair<int, int>& b )
670 return a.first > b.first || ( a.first == b.first && a.second < b.second );
675 sizer->Clear(
false );
677 for(
const std::pair<int, int>& pair : package_ranks )
683 sizer->Add( panel, 0, wxEXPAND );
727 wxT(
"getAction() called with ambiguous version selection" ) );
729 int selected_row = 0;
737 switch( package.state )
744 if( version == package.current_version )
763 infoSize.y =
m_infoText->GetInternalRepresentation()->GetHeight() + 12;
775 const wxHtmlLinkInfo&
info = aEvent.GetLinkInfo();
776 ::wxLaunchDefaultBrowser(
info.GetHref() );
808 std::vector<wxString> packages;
811 std::back_inserter( packages ) );
813 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.
T * GetAppSettings()
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...
KIWAY Kiway & Pgm(), KFCTL_STANDALONE
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