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
18 * along with this program. If not, see <https://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 if( event.GetWheelAxis() != wxMOUSE_WHEEL_VERTICAL )
794 return;
795
796 // Accumulate so high-resolution wheels and trackpads aren't truncated.
797 m_infoWheelRotation += event.GetWheelRotation();
798
799 int lines = m_infoWheelRotation / event.GetWheelDelta();
800 m_infoWheelRotation -= lines * event.GetWheelDelta();
801
802 if( lines == 0 )
803 return;
804
805 // GetWheelRotation is OS-direction-corrected; negate only to convert
806 // from wx's wheel convention (positive = up) to ScrollLines (positive = down).
807 if( event.IsPageScroll() )
808 m_infoScrollWindow->ScrollPages( -lines );
809 else
810 m_infoScrollWindow->ScrollLines( -lines * event.GetLinesPerAction() );
811}
812
813
814void PANEL_PACKAGES_VIEW::SetSashOnIdle( wxIdleEvent& aEvent )
815{
817 m_splitter1->SetSashPosition( cfg->m_PackageManager.sash_pos );
818
819 m_packageListWindow->FitInside();
820
821 m_splitter1->Disconnect( wxEVT_IDLE, wxIdleEventHandler( PANEL_PACKAGES_VIEW::SetSashOnIdle ), nullptr, this );
822}
823
824
829
830
831void PANEL_PACKAGES_VIEW::OnUpdateAllClicked( wxCommandEvent& event )
832{
833 // The map will be modified by the callback so we copy the list here
834 std::vector<wxString> packages;
835
836 std::copy( m_updateablePackages.begin(), m_updateablePackages.end(), std::back_inserter( packages ) );
837
838 for( const wxString& pkg_id : packages )
839 {
840 auto it = m_packagePanels.find( pkg_id );
841
842 if( it != m_packagePanels.end() )
843 {
844 const PACKAGE_VIEW_DATA& data = it->second->GetPackageData();
845
847 }
848 }
849}
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:57
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
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
Definition pgm_base.cpp:546
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:367
void AllowNetworkFileSystems(wxDialog *aDialog)
Configure a file dialog to show network and virtual file systems.
Definition wxgtk/ui.cpp:533
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 ...
Definition pcm.h:59
@ PPS_INSTALLED
Definition pcm.h:62
@ PPS_PENDING_UPDATE
Definition pcm.h:66
@ PPS_UPDATE_AVAILABLE
Definition pcm.h:65
@ PPS_PENDING_UNINSTALL
Definition pcm.h:64
@ PPS_PENDING_INSTALL
Definition pcm.h:63
PCM_PACKAGE_ACTION
Package actions.
Definition pcm.h:72
@ PPA_UNINSTALL
Definition pcm.h:74
@ PPA_UPDATE
Definition pcm.h:75
@ PPA_INSTALL
Definition pcm.h:73
@ 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 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 panel.
wxString update_version
PCM_PACKAGE_STATE state
Describes a person's name and contact information.
Definition pcm_data.h:80
Package metadata.
Definition pcm_data.h:114
std::vector< PACKAGE_VERSION > versions
Definition pcm_data.h:127
std::string path
IbisParser parser & reporter
wxString result
Test unit parsing edge cases and error handling.
#define PR_CAN_ABORT