KiCad PCB EDA Suite
Loading...
Searching...
No Matches
panel_packages_view.cpp
Go to the documentation of this file.
1/*
2 * This program source code file is part of KiCad, a free EDA CAD application.
3 *
4 * Copyright (C) 2021 Andrew Lutsenko, anlutsenko at gmail dot com
5 * Copyright The KiCad Developers, see AUTHORS.txt for contributors.
6 *
7 * This program is free software: you can redistribute it and/or modify it
8 * under the terms of the GNU General Public License as published by the
9 * Free Software Foundation, either version 3 of the License, or (at your
10 * option) any later version.
11 *
12 * This program is distributed in the hope that it will be useful, but
13 * WITHOUT ANY WARRANTY; without even the implied warranty of
14 * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU
15 * General Public License for more details.
16 *
17 * You should have received a copy of the GNU General Public License along
18 * with this program. If not, see <http://www.gnu.org/licenses/>.
19 */
20
21#include "panel_packages_view.h"
22#include <grid_tricks.h>
23#include <widgets/html_window.h>
24#include <pgm_base.h>
25#include <kiplatform/ui.h>
29#include <string_utils.h>
30#include <widgets/wx_panel.h>
32
33#include <cmath>
34#include <fstream>
35#include <wx/filedlg.h>
36#include <wx/font.h>
37#include <wx/tokenzr.h>
38
39
40#define GRID_CELL_MARGIN 4
41
42
43std::unordered_map<PCM_PACKAGE_VERSION_STATUS, wxString> PANEL_PACKAGES_VIEW::STATUS_ENUM_TO_STR = {
44 { PVS_INVALID, wxS( "invalid" ) },
45 { PVS_STABLE, wxS( "stable" ) },
46 { PVS_TESTING, wxS( "testing" ) },
47 { PVS_DEVELOPMENT, wxS( "development" ) },
48 { PVS_DEPRECATED, wxS( "deprecated" ) }
49};
50
51
53 std::shared_ptr<PLUGIN_CONTENT_MANAGER> aPcm,
54 const ActionCallback& aActionCallback,
55 const PinCallback& aPinCallback ) :
57 m_actionCallback( aActionCallback ),
58 m_pinCallback( aPinCallback ),
59 m_pcm( aPcm )
60{
61 // Replace wxFormBuilder's sash initializer with one which will respect m_initialSashPos.
62 m_splitter1->Disconnect( wxEVT_IDLE,
64 NULL, this );
65 m_splitter1->Connect( wxEVT_IDLE, wxIdleEventHandler( PANEL_PACKAGES_VIEW::SetSashOnIdle ),
66 NULL, this );
67
68 m_splitter1->SetPaneMinimums( FromDIP( 350 ), FromDIP( 450 ) );
69
70#ifdef __WXGTK__
71 // wxSearchCtrl vertical height is not calculated correctly on some GTK setups
72 // See https://gitlab.com/kicad/code/kicad/-/issues/9019
73 m_searchCtrl->SetMinSize( wxSize( -1, GetTextExtent( wxT( "qb" ) ).y + 10 ) );
74#endif
75
77 m_searchCtrl->SetDescriptiveText( _( "Filter" ) );
78
79 m_panelList->SetBorders( false, true, false, false );
80
81 m_gridVersions->PushEventHandler( new GRID_TRICKS( m_gridVersions ) );
82
83 for( int col = 0; col < m_gridVersions->GetNumberCols(); col++ )
84 {
85 const wxString& heading = m_gridVersions->GetColLabelValue( col );
86 int headingWidth = GetTextExtent( heading ).x + 2 * GRID_CELL_MARGIN;
87
88 // Set the minimal width to the column label size.
89 m_gridVersions->SetColMinimalWidth( col, headingWidth );
90 m_gridVersions->SetColSize( col, m_gridVersions->GetVisibleWidth( col ) );
91 }
92
93 // Most likely should be changed to wxGridSelectNone once WxWidgets>=3.1.5 is mandatory.
94 m_gridVersions->SetSelectionMode( WX_GRID::wxGridSelectRows );
95
96 wxColor background = wxStaticText::GetClassDefaultAttributes().colBg;
97 m_panelList->SetBackgroundColour( background );
98 m_packageListWindow->SetBackgroundColour( background );
99 m_infoScrollWindow->SetBackgroundColour( background );
100 m_infoScrollWindow->EnableScrolling( false, true );
101
102 ClearData();
103}
104
105
107{
108 m_splitter1->Disconnect( wxEVT_IDLE, wxIdleEventHandler( PANEL_PACKAGES_VIEW::SetSashOnIdle ), nullptr, this );
109
111 cfg->m_PackageManager.sash_pos = m_splitter1->GetSashPosition();
112
113 m_gridVersions->PopEventHandler( true );
114}
115
116
118{
120
121 m_currentSelected = nullptr;
122 m_updateablePackages.clear();
123 m_packagePanels.clear();
124 m_packageInitialOrder.clear();
125 m_packageListWindow->GetSizer()->Clear( true ); // Delete panels
126 m_packageListWindow->GetSizer()->FitInside( m_packageListWindow );
127 m_packageListWindow->Layout();
128}
129
130
131void PANEL_PACKAGES_VIEW::SetData( const std::vector<PACKAGE_VIEW_DATA>& aPackageData )
132{
133 ClearData();
134
135 for( const PACKAGE_VIEW_DATA& data : aPackageData )
136 {
138 m_pinCallback, data );
139
140 package_panel->SetSelectCallback(
141 [package_panel, this] ()
142 {
143 if( m_currentSelected && m_currentSelected != package_panel )
144 m_currentSelected->SetSelected( false );
145
146 package_panel->SetSelected( true );
147 m_currentSelected = package_panel;
148 setPackageDetails( package_panel->GetPackageData() );
149
150 Layout();
151 } );
152
153 m_packagePanels.insert( { data.package.identifier, package_panel } );
154 m_packageInitialOrder.push_back( data.package.identifier );
155
156 if( data.state == PPS_UPDATE_AVAILABLE && !data.pinned )
157 m_updateablePackages.insert( data.package.identifier );
158 }
159
162}
163
164
166{
167 const PCM_PACKAGE& package = aPackageData.package;
168 bool supportsIpc = std::any_of( package.versions.begin(), package.versions.end(),
169 []( const PACKAGE_VERSION& aVersion )
170 {
171 return aVersion.runtime.value_or( PCM_PACKAGE_RUNTIME::PPR_SWIG )
172 == PCM_PACKAGE_RUNTIME::PPR_IPC;
173 } );
174 bool legacyRuntimeOnly = ( package.type == PT_PLUGIN || package.type == PT_FAB ) && !supportsIpc;
175
176 // Details
177 wxString details;
178
179 details << wxT( "<h5>" ) + package.name + wxT( "</h5>" );
180
181 if( legacyRuntimeOnly )
182 {
183 details << wxT( "<p><b>" )
184 + _( "Warning: This plugin only supports the legacy Python API "
185 "and will not run in this KiCad version." )
186 + wxT( "</b></p>" );
187 }
188
189 auto format_desc =
190 []( const wxString& text ) -> wxString
191 {
192 wxString result;
193 bool inURL = false;
194 wxString url;
195
196 for( unsigned i = 0; i < text.length(); ++i )
197 {
198 wxUniChar c = text[i];
199
200 if( inURL )
201 {
202 if( c == ' ' || c == '\n')
203 {
204 result += wxString::Format( wxT( "<a href='%s'>%s</a>" ), url, url );
205 inURL = false;
206
207 if( c == '\n' )
208 result += wxT( "</p><p>" );
209 else
210 result += c;
211 }
212 else
213 {
214 url += c;
215 }
216 }
217 else if( text.Mid( i, 5 ) == wxT( "http:" )
218 || text.Mid( i, 6 ) == wxT( "https:" ) )
219 {
220 url = c;
221 inURL = true;
222 }
223 else if( c == '\n' )
224 {
225 result += wxT( "</p><p>" );
226 }
227 else
228 {
229 result += c;
230 }
231 }
232
233 if( inURL )
234 result += wxString::Format( wxT( "<a href='%s'>%s</a>" ), url, url );
235
236 return result;
237 };
238
239 wxString desc = package.description_full;
240 details << wxT( "<p>" ) + format_desc( desc ) + wxT( "</p>" );
241
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>" );
246
247 if( package.tags.size() > 0 )
248 {
249 wxString tags_str;
250
251 for( const std::string& tag : package.tags )
252 {
253 if( !tags_str.IsEmpty() )
254 tags_str += ", ";
255
256 tags_str += tag;
257 }
258
259 details << wxT( "<li>" ) + _( "Tags: " ) + tags_str + wxT( "</li>" );
260 }
261
262 auto format_entry =
263 []( const std::pair<const std::string, wxString>& entry ) -> wxString
264 {
265 wxString name = entry.first;
266 wxString url = EscapeHTML( entry.second );
267
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 );
272 else
273 return entry.second;
274 };
275
276 auto write_contact =
277 [&]( const wxString& type, const PCM_CONTACT& contact )
278 {
279 details << wxT( "<li>" ) + type + wxT( ": " ) + contact.name + wxT( "<ul>" );
280
281 for( const std::pair<const std::string, wxString>& entry : contact.contact )
282 {
283 details << wxT( "<li>" );
284 details << entry.first << wxT( ": " ) + format_entry( entry );
285 details << wxT( "</li>" );
286 }
287
288 details << wxT( "</ul>" );
289 };
290
291 write_contact( _( "Author" ), package.author );
292
293 if( package.maintainer )
294 write_contact( _( "Maintainer" ), *package.maintainer );
295
296 if( package.resources.size() > 0 )
297 {
298 details << wxT( "<li>" ) + _( "Resources" ) + wxT( "<ul>" );
299
300 for( const std::pair<const std::string, wxString>& entry : package.resources )
301 {
302 details << wxT( "<li>" );
303 details << entry.first << wxT( ": " );
304 details << format_entry( entry ) + wxT( "</li>" );
305 }
306
307 details << wxT( "</ul>" );
308 }
309
310 details << wxT( "</ul>" );
311
312 m_infoText->SetPage( details );
313
314 wxSizeEvent dummy;
316
317 // Versions table
318 m_gridVersions->Freeze();
319 m_gridVersions->ClearRows();
320
321 int row = 0;
322 wxString current_version;
323
324 if( aPackageData.state == PPS_INSTALLED || aPackageData.state == PPS_UPDATE_AVAILABLE )
325 current_version = m_pcm->GetInstalledPackageVersion( package.identifier );
326
327 wxFont bold_font = m_gridVersions->GetDefaultCellFont().Bold();
328
329 for( const PACKAGE_VERSION& version : package.versions )
330 {
331 if( !version.compatible && !m_showAllVersions->IsChecked() )
332 continue;
333
334 m_gridVersions->InsertRows( row );
335
336 m_gridVersions->SetCellValue( row, COL_VERSION, version.version );
337 m_gridVersions->SetCellValue( row, COL_DOWNLOAD_SIZE, toHumanReadableSize( version.download_size ) );
338 m_gridVersions->SetCellValue( row, COL_INSTALL_SIZE, toHumanReadableSize( version.install_size ) );
339 m_gridVersions->SetCellValue( row, COL_COMPATIBILITY, version.compatible ? wxT( "\u2714" ) : wxEmptyString );
340 m_gridVersions->SetCellValue( row, COL_STATUS, STATUS_ENUM_TO_STR.at( version.status ) );
341
342 m_gridVersions->SetCellAlignment( row, COL_COMPATIBILITY, wxALIGN_CENTER, wxALIGN_CENTER );
343
344 if( current_version == version.version )
345 {
346 for( int col = 0; col < m_gridVersions->GetNumberCols(); col++ )
347 m_gridVersions->SetCellFont( row, col, bold_font );
348 }
349
350 row++;
351 }
352
353 for( int col = 0; col < m_gridVersions->GetNumberCols(); col++ )
354 {
355 // Set the width to see the full contents
356 m_gridVersions->SetColSize( col, m_gridVersions->GetVisibleWidth( col ) );
357 }
358
359 // Autoselect preferred or installed version
360 if( m_gridVersions->GetNumberRows() >= 1 )
361 {
362 wxString version = m_currentSelected->GetPackageData().current_version;
363
364 if( version.IsEmpty() )
365 version = m_currentSelected->GetPreferredVersion();
366
367 if( !version.IsEmpty() )
368 {
369 for( int i = 0; i < m_gridVersions->GetNumberRows(); i++ )
370 {
371 if( m_gridVersions->GetCellValue( i, COL_VERSION ) == version )
372 {
373 m_gridVersions->SelectRow( i );
374 m_gridVersions->SetGridCursor( i, COL_VERSION );
375 break;
376 }
377 }
378 }
379 else
380 {
381 // Fall back to first row.
382 m_gridVersions->SelectRow( 0 );
383 }
384 }
385
386 m_gridVersions->Thaw();
387
389
390 m_infoText->Show( true );
391 m_sizerVersions->Show( true );
392 m_sizerVersions->Layout();
393
394 wxSize size = m_infoScrollWindow->GetTargetWindow()->GetBestVirtualSize();
395 m_infoScrollWindow->SetVirtualSize( size );
396}
397
398
400{
401 m_infoText->SetPage( wxEmptyString );
402 m_infoText->Show( false );
403 m_sizerVersions->Show( false );
404
405 wxSize size = m_infoScrollWindow->GetTargetWindow()->GetBestVirtualSize();
406 m_infoScrollWindow->SetVirtualSize( size );
407
408 // Clean up grid just so we don't keep stale info around (it's already been hidden).
409 m_gridVersions->Freeze();
410 m_gridVersions->ClearRows();
411 m_gridVersions->Thaw();
412}
413
414
415wxString PANEL_PACKAGES_VIEW::toHumanReadableSize( const std::optional<uint64_t> size ) const
416{
417 if( !size )
418 return wxT( "-" );
419
420 uint64_t b = *size;
421
422 if( b >= 1024 * 1024 )
423 return wxString::Format( wxT( "%.1f MB" ), b / 1000.0 / 1000.0 );
424
425 if( b >= 1024 )
426 return wxString::Format( wxT( "%lld kB" ), b / 1000 );
427
428 return wxString::Format( wxT( "%lld B" ), b );
429}
430
431
433{
434 if( !m_currentSelected )
435 return false;
436
437 return m_gridVersions->GetNumberRows() == 1 || m_gridVersions->GetSelectedRows().size() == 1;
438}
439
440
442{
443 if( !m_currentSelected )
444 return false;
445
446 const PACKAGE_VIEW_DATA& packageData = m_currentSelected->GetPackageData();
447
448 switch( packageData.state )
449 {
453 return false;
454
455 default:
456 break;
457 }
458
459 return m_gridVersions->GetNumberRows() == 1 || m_gridVersions->GetSelectedRows().size() == 1;
460}
461
462
463void PANEL_PACKAGES_VIEW::SetPackageState( const wxString& aPackageId, const PCM_PACKAGE_STATE aState,
464 const bool aPinned )
465{
466 auto it = m_packagePanels.find( aPackageId );
467
468 if( it != m_packagePanels.end() )
469 {
470 it->second->SetState( aState, aPinned );
471
472 if( m_currentSelected && m_currentSelected == it->second )
473 {
474 wxMouseEvent dummy;
475 m_currentSelected->OnClick( dummy );
476 }
477
478 if( aState == PPS_UPDATE_AVAILABLE && !aPinned )
479 m_updateablePackages.insert( aPackageId );
480 else
481 m_updateablePackages.erase( aPackageId );
482
484 }
485}
486
487
489{
490 m_gridVersions->ClearSelection();
491 m_gridVersions->SelectRow( event.GetRow() );
492
494}
495
496
498{
499 if( !canDownload() )
500 {
501 wxBell();
502 return;
503 }
504
505 if( m_gridVersions->GetNumberRows() == 1 )
506 m_gridVersions->SelectRow( 0 );
507
508 const wxArrayInt selectedRows = m_gridVersions->GetSelectedRows();
509
510 wxString version = m_gridVersions->GetCellValue( selectedRows[0], COL_VERSION );
511 const PCM_PACKAGE& package = m_currentSelected->GetPackageData().package;
512
513 auto ver_it = std::find_if( package.versions.begin(), package.versions.end(),
514 [&]( const PACKAGE_VERSION& ver )
515 {
516 return ver.version == version;
517 } );
518
519 wxASSERT_MSG( ver_it != package.versions.end(), "Could not find package version" );
520
521 if( !ver_it->download_url )
522 {
523 wxMessageBox( _( "Package download url is not specified" ), _( "Error downloading package" ),
524 wxICON_INFORMATION | wxOK, wxGetTopLevelParent( this ) );
525 return;
526 }
527
528 const wxString& url = *ver_it->download_url;
530
531 wxWindow* topLevelParent = wxGetTopLevelParent( this );
532 wxFileDialog dialog( topLevelParent, _( "Save Package" ), cfg->m_PcmLastDownloadDir,
533 wxString::Format( wxT( "%s_v%s.zip" ), package.identifier, version ),
534 wxT( "ZIP files (*.zip)|*.zip" ), wxFD_SAVE | wxFD_OVERWRITE_PROMPT );
535
537
538 if( dialog.ShowModal() == wxID_CANCEL )
539 return;
540
541 wxString path = dialog.GetPath();
542 cfg->m_PcmLastDownloadDir = wxPathOnly( path );
543
544 std::ofstream output( path.ToUTF8(), std::ios_base::binary );
545
546 WX_PROGRESS_REPORTER reporter( this, _( "Download Package" ), 1, PR_CAN_ABORT );
547
548 bool success = m_pcm->DownloadToStream( url, &output, &reporter, 0 );
549
550 output.close();
551
552 if( success )
553 {
554 if( ver_it->download_sha256 )
555 {
556 std::ifstream stream( path.ToUTF8(), std::ios_base::binary );
557
558 bool matches = m_pcm->VerifyHash( stream, *ver_it->download_sha256 );
559
560 stream.close();
561
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 ) )
566 == wxNO )
567 {
568 wxRemoveFile( path );
569 }
570 }
571 }
572 else
573 {
574 if( wxFileExists( path ) )
575 wxRemoveFile( path );
576 }
577}
578
579
581{
582 if( !canRunAction() )
583 {
584 wxBell();
585 return;
586 }
587
588 PCM_PACKAGE_ACTION action = getAction();
589
590 if( action == PPA_UNINSTALL )
591 {
593 m_currentSelected->GetPackageData().current_version );
594 return;
595 }
596
597 if( m_gridVersions->GetNumberRows() == 1 )
598 m_gridVersions->SelectRow( 0 );
599
600 const wxArrayInt selectedRows = m_gridVersions->GetSelectedRows();
601
602 wxString version = m_gridVersions->GetCellValue( selectedRows[0], COL_VERSION );
603 const PCM_PACKAGE& package = m_currentSelected->GetPackageData().package;
604
605 auto ver_it = std::find_if( package.versions.begin(), package.versions.end(),
606 [&]( const PACKAGE_VERSION& ver )
607 {
608 return ver.version == version;
609 } );
610
611 wxCHECK_RET( ver_it != package.versions.end(), "Could not find package version" );
612
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 ) )
617 == wxNO )
618 {
619 return;
620 }
621
622 m_actionCallback( m_currentSelected->GetPackageData(), action, version );
623}
624
625
627{
629 {
630 wxMouseEvent dummy;
631 m_currentSelected->OnClick( dummy );
632 }
633
635}
636
637
638void PANEL_PACKAGES_VIEW::OnSearchTextChanged( wxCommandEvent& event )
639{
641
643 m_currentSelected->SetSelected( false );
644
645 m_currentSelected = nullptr;
646
648}
649
650
652{
653 // Sort by descending rank, ascending index
654 std::vector<std::pair<int, int>> package_ranks;
655
656 const wxString search_term = m_searchCtrl->GetValue().Trim();
657
658 for( size_t index = 0; index < m_packageInitialOrder.size(); index++ )
659 {
660 int rank = 1;
661 const PCM_PACKAGE& pkg = m_packagePanels[m_packageInitialOrder[index]]->GetPackageData().package;
662
663 if( search_term.size() > 2 )
664 rank = m_pcm->GetPackageSearchRank( pkg, search_term );
665
666 // Packages with no versions are delisted and should not be shown
667 if( pkg.versions.size() == 0 )
668 rank = 0;
669
670 package_ranks.emplace_back( rank, index );
671 }
672
673 std::sort( package_ranks.begin(), package_ranks.end(),
674 []( const std::pair<int, int>& a, const std::pair<int, int>& b )
675 {
676 return a.first > b.first || ( a.first == b.first && a.second < b.second );
677 } );
678
679 // Rearrange panels, hide ones with 0 rank
680 wxSizer* sizer = m_packageListWindow->GetSizer();
681 sizer->Clear( false ); // Don't delete panels
682
683 for( const std::pair<int, int>& pair : package_ranks )
684 {
686
687 if( pair.first > 0 )
688 {
689 sizer->Add( panel, 0, wxEXPAND );
690 panel->Show();
691
692 if( !m_currentSelected )
693 {
694 wxMouseEvent dummy;
695 panel->OnClick( dummy );
696 }
697 }
698 else
699 {
700 panel->Hide();
701 }
702 }
703
704 m_packageListWindow->FitInside();
705 m_packageListWindow->SetScrollRate( 0, 15 );
706 m_packageListWindow->SendSizeEvent( wxSEND_EVENT_POST );
707}
708
709
711{
712 m_buttonDownload->Enable( canDownload() );
713
714 if( canRunAction() )
715 {
716 m_buttonAction->Enable();
717
718 PCM_PACKAGE_ACTION action = getAction();
719
720 switch( action )
721 {
722 case PPA_INSTALL: m_buttonAction->SetLabel( _( "Install" ) ); break;
723 case PPA_UNINSTALL: m_buttonAction->SetLabel( _( "Uninstall" ) ); break;
724 case PPA_UPDATE: m_buttonAction->SetLabel( _( "Update" ) ); break;
725 }
726 }
727 else
728 {
729 m_buttonAction->Disable();
730 m_buttonAction->SetLabel( _( "Pending" ) );
731 }
732}
733
734
736{
737 wxASSERT_MSG( m_gridVersions->GetNumberRows() == 1 || m_gridVersions->GetSelectedRows().size() == 1,
738 wxT( "getAction() called with ambiguous version selection" ) );
739
740 int selected_row = 0;
741
742 if( m_gridVersions->GetSelectedRows().size() == 1 )
743 selected_row = m_gridVersions->GetSelectedRows()[0];
744
745 wxString version = m_gridVersions->GetCellValue( selected_row, COL_VERSION );
746 const PACKAGE_VIEW_DATA& package = m_currentSelected->GetPackageData();
747
748 switch( package.state )
749 {
750 case PPS_AVAILABLE:
751 case PPS_UNAVAILABLE:
752 return PPA_INSTALL; // Only action for not installed package is to install it
753 case PPS_INSTALLED:
754 case PPS_UPDATE_AVAILABLE:
755 if( version == package.current_version )
756 return PPA_UNINSTALL;
757 else
758 return PPA_UPDATE;
759 default:
760 return PPA_INSTALL; // For pending states return value does not matter as button will be disabled
761 }
762}
763
764
765void PANEL_PACKAGES_VIEW::OnSizeInfoBox( wxSizeEvent& aEvent )
766{
767 wxSize infoSize = KIPLATFORM::UI::GetUnobscuredSize( m_infoText->GetParent() );
768 infoSize.x -= 10;
769 m_infoText->SetMinSize( infoSize );
770 m_infoText->SetMaxSize( infoSize );
771 m_infoText->SetSize( infoSize );
772 m_infoText->Layout();
773
774 infoSize.y = m_infoText->GetInternalRepresentation()->GetHeight() + 12;
775 m_infoText->SetMinSize( infoSize );
776 m_infoText->SetMaxSize( infoSize );
777 m_infoText->SetSize( infoSize );
778 m_infoText->Layout();
779
780 Refresh();
781}
782
783
784void PANEL_PACKAGES_VIEW::OnURLClicked( wxHtmlLinkEvent& aEvent )
785{
786 const wxHtmlLinkInfo& info = aEvent.GetLinkInfo();
787 ::wxLaunchDefaultBrowser( info.GetHref() );
788}
789
790
791void PANEL_PACKAGES_VIEW::OnInfoMouseWheel( wxMouseEvent& event )
792{
793 // Transfer scrolling from the info window to its parent scroll window
794 m_infoScrollWindow->HandleOnMouseWheel( event );
795}
796
797
798void PANEL_PACKAGES_VIEW::SetSashOnIdle( wxIdleEvent& aEvent )
799{
801 m_splitter1->SetSashPosition( cfg->m_PackageManager.sash_pos );
802
803 m_packageListWindow->FitInside();
804
805 m_splitter1->Disconnect( wxEVT_IDLE, wxIdleEventHandler( PANEL_PACKAGES_VIEW::SetSashOnIdle ), nullptr, this );
806}
807
808
813
814
815void PANEL_PACKAGES_VIEW::OnUpdateAllClicked( wxCommandEvent& event )
816{
817 // The map will be modified by the callback so we copy the list here
818 std::vector<wxString> packages;
819
820 std::copy( m_updateablePackages.begin(), m_updateablePackages.end(), std::back_inserter( packages ) );
821
822 for( const wxString& pkg_id : packages )
823 {
824 auto it = m_packagePanels.find( pkg_id );
825
826 if( it != m_packagePanels.end() )
827 {
828 const PACKAGE_VIEW_DATA& data = it->second->GetPackageData();
829
831 }
832 }
833}
int index
const char * name
PACKAGE_MANAGER m_PackageManager
Add mouse and command handling (such as cut, copy, and paste) to a WX_GRID instance.
Definition grid_tricks.h:61
wxString m_PcmLastDownloadDir
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)
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
Definition pgm_base.cpp:541
Multi-thread safe progress reporter dialog, intended for use of tasks that parallel reporting back of...
#define GRID_CELL_MARGIN
#define _(s)
wxSize GetUnobscuredSize(const wxWindow *aWindow)
Tries to determine the size of the viewport of a scrollable widget (wxDataViewCtrl,...
Definition wxgtk/ui.cpp:281
void AllowNetworkFileSystems(wxDialog *aDialog)
Configure a file dialog to show network and virtual file systems.
Definition wxgtk/ui.cpp:435
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
PCM_PACKAGE_STATE
Definition pcm.h:58
@ PPS_INSTALLED
Definition pcm.h:61
@ PPS_PENDING_UPDATE
Definition pcm.h:65
@ PPS_UPDATE_AVAILABLE
Definition pcm.h:64
@ PPS_PENDING_UNINSTALL
Definition pcm.h:63
@ PPS_PENDING_INSTALL
Definition pcm.h:62
PCM_PACKAGE_ACTION
Definition pcm.h:71
@ PPA_UNINSTALL
Definition pcm.h:73
@ PPA_UPDATE
Definition pcm.h:74
@ PPA_INSTALL
Definition pcm.h:72
@ PT_PLUGIN
Definition pcm_data.h:44
@ PT_FAB
Definition pcm_data.h:45
@ PVS_INVALID
Definition pcm_data.h:63
@ PVS_DEVELOPMENT
Definition pcm_data.h:66
@ PVS_STABLE
Definition pcm_data.h:64
@ PVS_TESTING
Definition pcm_data.h:65
@ PVS_DEPRECATED
Definition pcm_data.h:67
PGM_BASE & Pgm()
The global program "get" accessor.
see class PGM_BASE
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
Definition pcm_data.h:92
std::optional< uint64_t > download_size
Definition pcm_data.h:97
std::optional< uint64_t > install_size
Definition pcm_data.h:98
wxString version
Definition pcm_data.h:93
PCM_PACKAGE_VERSION_STATUS status
Definition pcm_data.h:99
< Collection of data relevant to the package display panelCallback for (un)install button
wxString update_version
PCM_PACKAGE_STATE state
Repository reference to a resource.
Definition pcm_data.h:114
std::vector< PACKAGE_VERSION > versions
Definition pcm_data.h:127
std::string path
nlohmann::json output
wxString result
Test unit parsing edge cases and error handling.
#define PR_CAN_ABORT