PCM: add ability to pin packages

Pinned packages don't affect available update notification and will not
be updated with "Update All" button. Manual update is still possible but
will trigger a confirmation dialog.
This commit is contained in:
qu1ck 2022-08-28 04:40:06 -07:00 committed by Seth Hillbrand
parent f6b1ff821b
commit 977b6cd8f3
12 changed files with 226 additions and 66 deletions

View File

@ -88,6 +88,13 @@ void SPLIT_BUTTON::SetBitmap( const wxBitmap& aBmp )
} }
void SPLIT_BUTTON::SetLabel( const wxString& aLabel )
{
m_label = aLabel;
Refresh();
}
wxMenu* SPLIT_BUTTON::GetSplitButtonMenu() wxMenu* SPLIT_BUTTON::GetSplitButtonMenu()
{ {
return m_pMenu; return m_pMenu;

View File

@ -43,6 +43,7 @@ public:
void SetBitmap( const wxBitmap& aBmp ); void SetBitmap( const wxBitmap& aBmp );
void SetMinSize( const wxSize& aSize ) override; void SetMinSize( const wxSize& aSize ) override;
void SetWidthPadding( int aPadding ); void SetWidthPadding( int aPadding );
void SetLabel( const wxString& aLabel ) override;
protected: protected:
void OnKillFocus( wxFocusEvent& aEvent ); void OnKillFocus( wxFocusEvent& aEvent );

View File

@ -66,23 +66,19 @@ DIALOG_PCM::DIALOG_PCM( wxWindow* parent, std::shared_ptr<PLUGIN_CONTENT_MANAGER
m_discardActionButton->SetBitmap( KiBitmap( BITMAPS::small_trash ) ); m_discardActionButton->SetBitmap( KiBitmap( BITMAPS::small_trash ) );
m_panelPending->Layout(); m_panelPending->Layout();
m_installedPanel = new PANEL_PACKAGES_VIEW( m_panelInstalledHolder, m_pcm ); m_actionCallback = [this]( const PACKAGE_VIEW_DATA& aData, PCM_PACKAGE_ACTION aAction,
m_panelInstalledHolder->GetSizer()->Add( m_installedPanel, 1, wxEXPAND ); const wxString& aVersion )
m_panelInstalledHolder->Layout();
for( const std::pair<PCM_PACKAGE_TYPE, wxString>& entry : PACKAGE_TYPE_LIST )
{ {
PANEL_PACKAGES_VIEW* panel = new PANEL_PACKAGES_VIEW( m_contentNotebook, m_pcm ); if( aAction == PPA_UPDATE && m_pcm->IsPackagePinned( aData.package.identifier ) )
wxString label = wxGetTranslation( entry.second ); {
m_contentNotebook->AddPage( panel, wxString::Format( label, 0 ) ); if( wxMessageBox( wxString::Format( _( "Are you sure you want to update pinned package "
m_repositoryContentPanels.insert( { entry.first, panel } ); "from version %s to %s?" ),
} aData.current_version, aVersion ),
_( "Confirm update" ), wxICON_QUESTION | wxYES_NO, this )
== wxNO )
return;
}
m_dialogNotebook->SetPageText( 0, wxString::Format( _( "Repository (%d)" ), 0 ) );
m_callback = [this]( const PACKAGE_VIEW_DATA& aData, PCM_PACKAGE_ACTION aAction,
const wxString& aVersion )
{
m_gridPendingActions->Freeze(); m_gridPendingActions->Freeze();
PCM_PACKAGE_STATE new_state; PCM_PACKAGE_STATE new_state;
@ -125,12 +121,33 @@ DIALOG_PCM::DIALOG_PCM( wxWindow* parent, std::shared_ptr<PLUGIN_CONTENT_MANAGER
updatePendingActionsTab(); updatePendingActionsTab();
m_installedPanel->SetPackageState( aData.package.identifier, new_state ); updatePackageState( aData.package.identifier, new_state );
for( const auto& entry : m_repositoryContentPanels )
entry.second->SetPackageState( aData.package.identifier, new_state );
}; };
m_pinCallback =
[this]( const wxString& aPackageId, const PCM_PACKAGE_STATE aState, const bool aPinned )
{
m_pcm->SetPinned( aPackageId, aPinned );
updatePackageState( aPackageId, aState );
};
m_installedPanel = new PANEL_PACKAGES_VIEW( m_panelInstalledHolder, m_pcm, m_actionCallback,
m_pinCallback );
m_panelInstalledHolder->GetSizer()->Add( m_installedPanel, 1, wxEXPAND );
m_panelInstalledHolder->Layout();
for( const std::pair<PCM_PACKAGE_TYPE, wxString>& entry : PACKAGE_TYPE_LIST )
{
PANEL_PACKAGES_VIEW* panel = new PANEL_PACKAGES_VIEW( m_contentNotebook, m_pcm,
m_actionCallback, m_pinCallback );
wxString label = wxGetTranslation( entry.second );
m_contentNotebook->AddPage( panel, wxString::Format( label, 0 ) );
m_repositoryContentPanels.insert( { entry.first, panel } );
}
m_dialogNotebook->SetPageText( 0, wxString::Format( _( "Repository (%d)" ), 0 ) );
setInstalledPackages(); setInstalledPackages();
updatePendingActionsTab(); updatePendingActionsTab();
@ -312,7 +329,10 @@ void DIALOG_PCM::setRepositoryData( const wxString& aRepositoryId )
package_data.state = m_pcm->GetPackageState( aRepositoryId, pkg.identifier ); package_data.state = m_pcm->GetPackageState( aRepositoryId, pkg.identifier );
if( package_data.state == PPS_INSTALLED || package_data.state == PPS_UPDATE_AVAILABLE ) if( package_data.state == PPS_INSTALLED || package_data.state == PPS_UPDATE_AVAILABLE )
{
package_data.current_version = m_pcm->GetInstalledPackageVersion( pkg.identifier ); package_data.current_version = m_pcm->GetInstalledPackageVersion( pkg.identifier );
package_data.pinned = m_pcm->IsPackagePinned( pkg.identifier );
}
if( package_data.state == PPS_UPDATE_AVAILABLE ) if( package_data.state == PPS_UPDATE_AVAILABLE )
package_data.update_version = m_pcm->GetPackageUpdateVersion( pkg ); package_data.update_version = m_pcm->GetPackageUpdateVersion( pkg );
@ -343,7 +363,7 @@ void DIALOG_PCM::setRepositoryData( const wxString& aRepositoryId )
{ {
PCM_PACKAGE_TYPE type = PACKAGE_TYPE_LIST[i].first; PCM_PACKAGE_TYPE type = PACKAGE_TYPE_LIST[i].first;
const wxString& label = PACKAGE_TYPE_LIST[i].second; const wxString& label = PACKAGE_TYPE_LIST[i].second;
m_repositoryContentPanels[type]->SetData( data[type], m_callback ); m_repositoryContentPanels[type]->SetData( data[type] );
m_contentNotebook->SetPageText( m_contentNotebook->SetPageText(
i, wxString::Format( wxGetTranslation( label ), (int) data[type].size() ) ); i, wxString::Format( wxGetTranslation( label ), (int) data[type].size() ) );
} }
@ -401,7 +421,7 @@ void DIALOG_PCM::setInstalledPackages()
package_list.emplace_back( package_data ); package_list.emplace_back( package_data );
} }
m_installedPanel->SetData( package_list, m_callback ); m_installedPanel->SetData( package_list );
m_dialogNotebook->SetPageText( m_dialogNotebook->SetPageText(
1, wxString::Format( _( "Installed (%d)" ), (int) package_list.size() ) ); 1, wxString::Format( _( "Installed (%d)" ), (int) package_list.size() ) );
@ -489,15 +509,23 @@ void DIALOG_PCM::discardAction( int aIndex )
PCM_PACKAGE_STATE state = PCM_PACKAGE_STATE state =
m_pcm->GetPackageState( action.repository_id, action.package.identifier ); m_pcm->GetPackageState( action.repository_id, action.package.identifier );
m_installedPanel->SetPackageState( action.package.identifier, state ); updatePackageState( action.package.identifier, state );
for( const auto& entry : m_repositoryContentPanels )
entry.second->SetPackageState( action.package.identifier, state );
m_pendingActions.erase( m_pendingActions.begin() + aIndex ); m_pendingActions.erase( m_pendingActions.begin() + aIndex );
} }
void DIALOG_PCM::updatePackageState( const wxString& aPackageId, const PCM_PACKAGE_STATE aState )
{
bool pinned = m_pcm->IsPackagePinned( aPackageId );
m_installedPanel->SetPackageState( aPackageId, aState, pinned );
for( const auto& entry : m_repositoryContentPanels )
entry.second->SetPackageState( aPackageId, aState, pinned );
}
void DIALOG_PCM::OnOpenPackageDirClicked( wxCommandEvent& event ) void DIALOG_PCM::OnOpenPackageDirClicked( wxCommandEvent& event )
{ {
LaunchExternal( m_pcm->Get3rdPartyPath() ); LaunchExternal( m_pcm->Get3rdPartyPath() );

View File

@ -90,11 +90,15 @@ private:
///< Gets installed packages list from PCM and displays it on installed tab ///< Gets installed packages list from PCM and displays it on installed tab
void setInstalledPackages(); void setInstalledPackages();
///< Reflects new state of the package in all panels where it is displayed
void updatePackageState( const wxString& aPackageId, const PCM_PACKAGE_STATE aState );
///< Discards specified pending action ///< Discards specified pending action
void discardAction( int aIndex ); void discardAction( int aIndex );
std::shared_ptr<PLUGIN_CONTENT_MANAGER> m_pcm; std::shared_ptr<PLUGIN_CONTENT_MANAGER> m_pcm;
ActionCallback m_callback; ActionCallback m_actionCallback;
PinCallback m_pinCallback;
PANEL_PACKAGES_VIEW* m_installedPanel; PANEL_PACKAGES_VIEW* m_installedPanel;
std::unordered_map<PCM_PACKAGE_TYPE, PANEL_PACKAGES_VIEW*> m_repositoryContentPanels; std::unordered_map<PCM_PACKAGE_TYPE, PANEL_PACKAGES_VIEW*> m_repositoryContentPanels;
wxString m_selectedRepositoryId; wxString m_selectedRepositoryId;

View File

@ -24,9 +24,9 @@
#include "panel_package.h" #include "panel_package.h"
PANEL_PACKAGE::PANEL_PACKAGE( wxWindow* parent, const ActionCallback& aCallback, PANEL_PACKAGE::PANEL_PACKAGE( wxWindow* parent, const ActionCallback& aCallback,
const PACKAGE_VIEW_DATA& aData ) : const PinCallback& aPinCallback, const PACKAGE_VIEW_DATA& aData ) :
PANEL_PACKAGE_BASE( parent ), PANEL_PACKAGE_BASE( parent ),
m_actionCallback( aCallback ), m_data( aData ) m_actionCallback( aCallback ), m_pinCallback( aPinCallback ), m_data( aData )
{ {
// Propagate clicks on static elements to the panel handler. // Propagate clicks on static elements to the panel handler.
m_name->Connect( wxEVT_LEFT_DOWN, wxMouseEventHandler( PANEL_PACKAGE::OnClick ), NULL, this ); m_name->Connect( wxEVT_LEFT_DOWN, wxMouseEventHandler( PANEL_PACKAGE::OnClick ), NULL, this );
@ -60,13 +60,18 @@ PANEL_PACKAGE::PANEL_PACKAGE( wxWindow* parent, const ActionCallback& aCallback,
m_splitButton->SetLabel( _( "Update" ) ); m_splitButton->SetLabel( _( "Update" ) );
m_splitButton->Bind( wxEVT_BUTTON, &PANEL_PACKAGE::OnButtonClicked, this ); m_splitButton->Bind( wxEVT_BUTTON, &PANEL_PACKAGE::OnButtonClicked, this );
wxMenu* splitMenu = m_splitButton->GetSplitButtonMenu(); wxMenu* splitMenu = m_splitButton->GetSplitButtonMenu();
wxMenuItem* menuItem = splitMenu->Append( wxID_ANY, _( "Uninstall" ) ); m_pinVersionMenuItem =
splitMenu->Append( wxID_ANY, _( "Pin package" ),
_( "Pinned packages don't affect available update notification and "
"will not be updated with \"Update All\" button." ),
wxITEM_CHECK );
splitMenu->Bind( wxEVT_COMMAND_MENU_SELECTED, &PANEL_PACKAGE::OnPinVersionClick, this,
m_pinVersionMenuItem->GetId() );
splitMenu->Bind( wxEVT_COMMAND_MENU_SELECTED, &PANEL_PACKAGE::OnUninstallClick, this, m_actionMenuItem = splitMenu->Append( wxID_ANY, _( "Uninstall" ) );
menuItem->GetId() );
SetState( m_data.state ); SetState( m_data.state, m_data.pinned );
} }
@ -76,9 +81,11 @@ void PANEL_PACKAGE::OnSize( wxSizeEvent& event )
} }
void PANEL_PACKAGE::SetState( PCM_PACKAGE_STATE aState ) void PANEL_PACKAGE::SetState( PCM_PACKAGE_STATE aState, bool aPinned )
{ {
m_data.state = aState; m_data.state = aState;
m_data.pinned = aPinned;
m_splitButton->GetSplitButtonMenu()->Check( m_pinVersionMenuItem->GetId(), aPinned );
switch( aState ) switch( aState )
{ {
@ -95,10 +102,15 @@ void PANEL_PACKAGE::SetState( PCM_PACKAGE_STATE aState )
m_button->Disable(); m_button->Disable();
break; break;
case PCM_PACKAGE_STATE::PPS_INSTALLED: case PCM_PACKAGE_STATE::PPS_INSTALLED:
m_splitButton->Hide(); m_button->Hide();
m_button->Show(); m_splitButton->Show();
m_button->SetLabel( _( "Uninstall" ) );
m_button->Enable(); m_splitButton->SetLabel( _( "Uninstall" ) );
m_splitButton->Bind( wxEVT_BUTTON, &PANEL_PACKAGE::OnButtonClicked, this );
m_actionMenuItem->SetItemLabel( _( "Update" ) );
m_splitButton->GetSplitButtonMenu()->Enable( m_actionMenuItem->GetId(), false );
break; break;
case PCM_PACKAGE_STATE::PPS_PENDING_INSTALL: case PCM_PACKAGE_STATE::PPS_PENDING_INSTALL:
m_splitButton->Hide(); m_splitButton->Hide();
@ -113,9 +125,31 @@ void PANEL_PACKAGE::SetState( PCM_PACKAGE_STATE aState )
m_button->Disable(); m_button->Disable();
break; break;
case PCM_PACKAGE_STATE::PPS_UPDATE_AVAILABLE: case PCM_PACKAGE_STATE::PPS_UPDATE_AVAILABLE:
// The only state where the split button is shown instead of the normal one
m_button->Hide(); m_button->Hide();
m_splitButton->Show(); m_splitButton->Show();
if( aPinned )
{
m_splitButton->SetLabel( _( "Uninstall" ) );
m_splitButton->Bind( wxEVT_BUTTON, &PANEL_PACKAGE::OnUninstallClick, this );
m_actionMenuItem->SetItemLabel( _( "Update" ) );
m_splitButton->GetSplitButtonMenu()->Enable( m_actionMenuItem->GetId(), true );
m_splitButton->GetSplitButtonMenu()->Bind( wxEVT_COMMAND_MENU_SELECTED,
&PANEL_PACKAGE::OnButtonClicked, this,
m_actionMenuItem->GetId() );
}
else
{
m_splitButton->SetLabel( _( "Update" ) );
m_splitButton->Bind( wxEVT_BUTTON, &PANEL_PACKAGE::OnButtonClicked, this );
m_actionMenuItem->SetItemLabel( _( "Uninstall" ) );
m_splitButton->GetSplitButtonMenu()->Enable( m_actionMenuItem->GetId(), true );
m_splitButton->GetSplitButtonMenu()->Bind( wxEVT_COMMAND_MENU_SELECTED,
&PANEL_PACKAGE::OnUninstallClick, this,
m_actionMenuItem->GetId() );
}
break; break;
case PCM_PACKAGE_STATE::PPS_PENDING_UPDATE: case PCM_PACKAGE_STATE::PPS_PENDING_UPDATE:
m_splitButton->Hide(); m_splitButton->Hide();
@ -152,6 +186,14 @@ void PANEL_PACKAGE::OnButtonClicked( wxCommandEvent& event )
} }
void PANEL_PACKAGE::OnPinVersionClick( wxCommandEvent& event )
{
m_data.pinned = event.IsChecked();
m_pinCallback( m_data.package.identifier, m_data.state, m_data.pinned );
}
void PANEL_PACKAGE::OnUninstallClick( wxCommandEvent& event ) void PANEL_PACKAGE::OnUninstallClick( wxCommandEvent& event )
{ {
if( m_data.state == PPS_UPDATE_AVAILABLE ) if( m_data.state == PPS_UPDATE_AVAILABLE )

View File

@ -32,12 +32,14 @@ struct PACKAGE_VIEW_DATA
const PCM_PACKAGE package; const PCM_PACKAGE package;
wxBitmap* bitmap; wxBitmap* bitmap;
PCM_PACKAGE_STATE state; PCM_PACKAGE_STATE state;
bool pinned;
wxString repository_id; wxString repository_id;
wxString repository_name; wxString repository_name;
wxString current_version; wxString current_version;
wxString update_version; wxString update_version;
PACKAGE_VIEW_DATA( const PCM_PACKAGE aPackage ) : PACKAGE_VIEW_DATA( const PCM_PACKAGE aPackage ) :
package( std::move( aPackage ) ), bitmap( nullptr ), state( PPS_INSTALLED ){}; package( std::move( aPackage ) ), bitmap( nullptr ), state( PPS_INSTALLED ),
pinned( false ){};
PACKAGE_VIEW_DATA( const PCM_INSTALLATION_ENTRY& aEntry ) : PACKAGE_VIEW_DATA( const PCM_INSTALLATION_ENTRY& aEntry ) :
package( std::move( aEntry.package ) ), bitmap( nullptr ) package( std::move( aEntry.package ) ), bitmap( nullptr )
{ {
@ -45,6 +47,7 @@ struct PACKAGE_VIEW_DATA
repository_id = aEntry.repository_id; repository_id = aEntry.repository_id;
repository_name = aEntry.repository_name; repository_name = aEntry.repository_name;
current_version = aEntry.current_version; current_version = aEntry.current_version;
pinned = aEntry.pinned;
} }
}; };
@ -53,12 +56,15 @@ struct PACKAGE_VIEW_DATA
using ActionCallback = std::function<void( const PACKAGE_VIEW_DATA& aData, using ActionCallback = std::function<void( const PACKAGE_VIEW_DATA& aData,
PCM_PACKAGE_ACTION aAction, const wxString& aVersion )>; PCM_PACKAGE_ACTION aAction, const wxString& aVersion )>;
using PinCallback = std::function<void( const wxString& aPackageId, const PCM_PACKAGE_STATE aState,
const bool aPinned )>;
class PANEL_PACKAGE : public PANEL_PACKAGE_BASE class PANEL_PACKAGE : public PANEL_PACKAGE_BASE
{ {
public: public:
PANEL_PACKAGE( wxWindow* parent, const ActionCallback& aCallback, PANEL_PACKAGE( wxWindow* parent, const ActionCallback& aCallback,
const PACKAGE_VIEW_DATA& aData ); const PinCallback& aPinCallback, const PACKAGE_VIEW_DATA& aData );
///< Sets callback for OnClick action ///< Sets callback for OnClick action
void SetSelectCallback( const std::function<void()>& aCallback ); void SetSelectCallback( const std::function<void()>& aCallback );
@ -69,13 +75,15 @@ public:
void OnButtonClicked( wxCommandEvent& event ) override; void OnButtonClicked( wxCommandEvent& event ) override;
///< Changes state of the (un)install button ///< Changes state of the (un)install button
void SetState( PCM_PACKAGE_STATE aState ); void SetState( PCM_PACKAGE_STATE aState, bool aPinned );
///< Called when anywhere on the panel is clicked (except install button) ///< Called when anywhere on the panel is clicked (except install button)
void OnClick( wxMouseEvent& event ) override; void OnClick( wxMouseEvent& event ) override;
void OnUninstallClick( wxCommandEvent& event ); void OnUninstallClick( wxCommandEvent& event );
void OnPinVersionClick( wxCommandEvent& event );
void OnSize( wxSizeEvent& event ) override; void OnSize( wxSizeEvent& event ) override;
///< Get preferred version. If criteria are not met, return wxEmptyString ///< Get preferred version. If criteria are not met, return wxEmptyString
@ -87,9 +95,12 @@ private:
void OnPaint( wxPaintEvent& event ) override; void OnPaint( wxPaintEvent& event ) override;
private: private:
wxMenuItem* m_pinVersionMenuItem;
wxMenuItem* m_actionMenuItem;
std::function<void()> m_selectCallback; std::function<void()> m_selectCallback;
bool m_selected = false; bool m_selected = false;
const ActionCallback& m_actionCallback; const ActionCallback& m_actionCallback;
const PinCallback& m_pinCallback;
PACKAGE_VIEW_DATA m_data; PACKAGE_VIEW_DATA m_data;
int m_minHeight; int m_minHeight;
}; };

View File

@ -23,8 +23,8 @@
#include <html_window.h> #include <html_window.h>
#include <pgm_base.h> #include <pgm_base.h>
#include <settings/common_settings.h> #include <settings/common_settings.h>
#include <settings/settings_manager.h>
#include <settings/kicad_settings.h> #include <settings/kicad_settings.h>
#include <settings/settings_manager.h>
#include <string_utils.h> #include <string_utils.h>
#include <widgets/wx_panel.h> #include <widgets/wx_panel.h>
#include <widgets/wx_splitter_window.h> #include <widgets/wx_splitter_window.h>
@ -49,9 +49,11 @@ std::unordered_map<PCM_PACKAGE_VERSION_STATUS, wxString> PANEL_PACKAGES_VIEW::ST
PANEL_PACKAGES_VIEW::PANEL_PACKAGES_VIEW( wxWindow* parent, PANEL_PACKAGES_VIEW::PANEL_PACKAGES_VIEW( wxWindow* parent,
std::shared_ptr<PLUGIN_CONTENT_MANAGER> aPcm ) : std::shared_ptr<PLUGIN_CONTENT_MANAGER> aPcm,
const ActionCallback& aActionCallback,
const PinCallback& aPinCallback ) :
PANEL_PACKAGES_VIEW_BASE( parent ), PANEL_PACKAGES_VIEW_BASE( parent ),
m_pcm( aPcm ) m_pcm( aPcm ), m_actionCallback( aActionCallback ), m_pinCallback( aPinCallback )
{ {
// Replace wxFormBuilder's sash initializer with one which will respect m_initialSashPos. // Replace wxFormBuilder's sash initializer with one which will respect m_initialSashPos.
m_splitter1->Disconnect( wxEVT_IDLE, m_splitter1->Disconnect( wxEVT_IDLE,
@ -121,17 +123,14 @@ void PANEL_PACKAGES_VIEW::ClearData()
} }
void PANEL_PACKAGES_VIEW::SetData( const std::vector<PACKAGE_VIEW_DATA>& aPackageData, void PANEL_PACKAGES_VIEW::SetData( const std::vector<PACKAGE_VIEW_DATA>& aPackageData )
ActionCallback aCallback )
{ {
m_actionCallback = aCallback;
ClearData(); ClearData();
for( const PACKAGE_VIEW_DATA& data : aPackageData ) for( const PACKAGE_VIEW_DATA& data : aPackageData )
{ {
PANEL_PACKAGE* package_panel = PANEL_PACKAGE* package_panel =
new PANEL_PACKAGE( m_packageListWindow, m_actionCallback, data ); new PANEL_PACKAGE( m_packageListWindow, m_actionCallback, m_pinCallback, data );
package_panel->SetSelectCallback( package_panel->SetSelectCallback(
[package_panel, this]() [package_panel, this]()
@ -149,7 +148,7 @@ void PANEL_PACKAGES_VIEW::SetData( const std::vector<PACKAGE_VIEW_DATA>& aPackag
m_packagePanels.insert( { data.package.identifier, package_panel } ); m_packagePanels.insert( { data.package.identifier, package_panel } );
m_packageInitialOrder.push_back( data.package.identifier ); m_packageInitialOrder.push_back( data.package.identifier );
if( data.state == PPS_UPDATE_AVAILABLE ) if( data.state == PPS_UPDATE_AVAILABLE && !data.pinned )
m_updateablePackages.insert( data.package.identifier ); m_updateablePackages.insert( data.package.identifier );
} }
@ -429,13 +428,13 @@ bool PANEL_PACKAGES_VIEW::canRunAction() const
void PANEL_PACKAGES_VIEW::SetPackageState( const wxString& aPackageId, void PANEL_PACKAGES_VIEW::SetPackageState( const wxString& aPackageId,
const PCM_PACKAGE_STATE aState ) const PCM_PACKAGE_STATE aState, const bool aPinned )
{ {
auto it = m_packagePanels.find( aPackageId ); auto it = m_packagePanels.find( aPackageId );
if( it != m_packagePanels.end() ) if( it != m_packagePanels.end() )
{ {
it->second->SetState( aState ); it->second->SetState( aState, aPinned );
if( m_currentSelected && m_currentSelected == it->second ) if( m_currentSelected && m_currentSelected == it->second )
{ {
@ -443,7 +442,7 @@ void PANEL_PACKAGES_VIEW::SetPackageState( const wxString& aPackageId,
m_currentSelected->OnClick( dummy ); m_currentSelected->OnClick( dummy );
} }
if( aState == PPS_UPDATE_AVAILABLE ) if( aState == PPS_UPDATE_AVAILABLE && !aPinned )
{ {
m_updateablePackages.insert( aPackageId ); m_updateablePackages.insert( aPackageId );
} }

View File

@ -35,24 +35,26 @@
class PANEL_PACKAGES_VIEW : public PANEL_PACKAGES_VIEW_BASE class PANEL_PACKAGES_VIEW : public PANEL_PACKAGES_VIEW_BASE
{ {
public: public:
PANEL_PACKAGES_VIEW( wxWindow* parent, std::shared_ptr<PLUGIN_CONTENT_MANAGER> aPcm ); PANEL_PACKAGES_VIEW( wxWindow* parent, std::shared_ptr<PLUGIN_CONTENT_MANAGER> aPcm,
const ActionCallback& aCallback, const PinCallback& aPinCallback );
~PANEL_PACKAGES_VIEW(); ~PANEL_PACKAGES_VIEW();
/** /**
* @brief Recreates package panels and displays data * @brief Recreates package panels and displays data
* *
* @param aPackageData list of package view data * @param aPackageData list of package view data
* @param aCallback (un)install button callback
*/ */
void SetData( const std::vector<PACKAGE_VIEW_DATA>& aPackageData, ActionCallback aCallback ); void SetData( const std::vector<PACKAGE_VIEW_DATA>& aPackageData );
/** /**
* @brief Set the state of package * @brief Set the state of package
* *
* @param aPackageId id of the package * @param aPackageId id of the package
* @param aState new state * @param aState new state
* @param aPinned indicates pinned version
*/ */
void SetPackageState( const wxString& aPackageId, const PCM_PACKAGE_STATE aState ); void SetPackageState( const wxString& aPackageId, const PCM_PACKAGE_STATE aState,
const bool aPinned );
///< Destroys package panels ///< Destroys package panels
void ClearData(); void ClearData();
@ -115,7 +117,8 @@ private:
PCM_PACKAGE_ACTION getAction() const; PCM_PACKAGE_ACTION getAction() const;
private: private:
ActionCallback m_actionCallback; const ActionCallback& m_actionCallback;
const PinCallback& m_pinCallback;
std::unordered_map<wxString, PANEL_PACKAGE*> m_packagePanels; std::unordered_map<wxString, PANEL_PACKAGE*> m_packagePanels;
std::vector<wxString> m_packageInitialOrder; std::vector<wxString> m_packageInitialOrder;
PANEL_PACKAGE* m_currentSelected; PANEL_PACKAGE* m_currentSelected;

View File

@ -813,7 +813,6 @@ PCM_PACKAGE_STATE PLUGIN_CONTENT_MANAGER::GetPackageState( const wxString& aRepo
try try
{ {
repo = &getCachedRepository( aRepositoryId ); repo = &getCachedRepository( aRepositoryId );
} }
catch( ... ) catch( ... )
{ {
@ -938,6 +937,24 @@ PLUGIN_CONTENT_MANAGER::GetInstalledPackageVersion( const wxString& aPackageId )
} }
bool PLUGIN_CONTENT_MANAGER::IsPackagePinned( const wxString& aPackageId ) const
{
if( m_installed.find( aPackageId ) == m_installed.end() )
return false;
return m_installed.at( aPackageId ).pinned;
}
void PLUGIN_CONTENT_MANAGER::SetPinned( const wxString& aPackageId, const bool aPinned )
{
if( m_installed.find( aPackageId ) == m_installed.end() )
return;
m_installed.at( aPackageId ).pinned = aPinned;
}
int PLUGIN_CONTENT_MANAGER::GetPackageSearchRank( const PCM_PACKAGE& aPackage, int PLUGIN_CONTENT_MANAGER::GetPackageSearchRank( const PCM_PACKAGE& aPackage,
const wxString& aSearchTerm ) const wxString& aSearchTerm )
{ {
@ -1096,11 +1113,14 @@ void PLUGIN_CONTENT_MANAGER::RunBackgroundUpdate()
if( m_installed.size() == 0 ) if( m_installed.size() == 0 )
return; return;
// Only fetch repositories that have installed packages // Only fetch repositories that have installed not pinned packages
std::unordered_set<wxString> repo_ids; std::unordered_set<wxString> repo_ids;
for( auto& entry : m_installed ) for( auto& entry : m_installed )
repo_ids.insert( entry.second.repository_id ); {
if( !entry.second.pinned )
repo_ids.insert( entry.second.repository_id );
}
for( const auto& entry : m_repository_list ) for( const auto& entry : m_repository_list )
{ {
@ -1132,7 +1152,7 @@ void PLUGIN_CONTENT_MANAGER::RunBackgroundUpdate()
GetPackageState( installed_package.repository_id, GetPackageState( installed_package.repository_id,
installed_package.package.identifier ); installed_package.package.identifier );
if( state == PPS_UPDATE_AVAILABLE ) if( state == PPS_UPDATE_AVAILABLE && !installed_package.pinned )
availableUpdateCount++; availableUpdateCount++;
} }

View File

@ -240,6 +240,25 @@ public:
*/ */
PCM_PACKAGE_STATE GetPackageState( const wxString& aRepositoryId, const wxString& aPackageId ); PCM_PACKAGE_STATE GetPackageState( const wxString& aRepositoryId, const wxString& aPackageId );
/**
* @brief Returns pinned status of a package
*
* @param aPackageId package id
* @return true if package is installed and is pinned
* @return false if package is not installed or not pinned
*/
bool IsPackagePinned( const wxString& aPackageId ) const;
/**
* @brief Set the pinned status of a package
*
* no-op for not installed packages
*
* @param aPackageId package id
* @param aPinned pinned status
*/
void SetPinned( const wxString& aPackageId, const bool aPinned );
/** /**
* @brief Get the preferred package update version or empty string if there is none * @brief Get the preferred package update version or empty string if there is none
* *

View File

@ -173,3 +173,28 @@ void from_json( const json& j, PCM_REPOSITORY& r )
to_optional( j, "manifests", r.manifests ); to_optional( j, "manifests", r.manifests );
to_optional( j, "maintainer", r.maintainer ); to_optional( j, "maintainer", r.maintainer );
} }
void to_json( json& j, const PCM_INSTALLATION_ENTRY& e )
{
j = json{ { "package", e.package },
{ "current_version", e.current_version },
{ "repository_id", e.repository_id },
{ "repository_name", e.repository_name },
{ "install_timestamp", e.install_timestamp },
{ "pinned", e.pinned } };
}
void from_json( const json& j, PCM_INSTALLATION_ENTRY& e )
{
j.at( "package" ).get_to( e.package );
j.at( "current_version" ).get_to( e.current_version );
j.at( "repository_id" ).get_to( e.repository_id );
j.at( "repository_name" ).get_to( e.repository_name );
j.at( "install_timestamp" ).get_to( e.install_timestamp );
e.pinned = false;
if( j.contains( "pinned" ) )
j.at( "pinned" ).get_to( e.pinned );
}

View File

@ -23,9 +23,9 @@
#include "core/wx_stl_compat.h" #include "core/wx_stl_compat.h"
#include <optional>
#include <map> #include <map>
#include <nlohmann/json.hpp> #include <nlohmann/json.hpp>
#include <optional>
#include <string> #include <string>
#include <tuple> #include <tuple>
#include <vector> #include <vector>
@ -141,6 +141,7 @@ struct PCM_INSTALLATION_ENTRY
wxString repository_id; wxString repository_id;
wxString repository_name; wxString repository_name;
uint64_t install_timestamp; uint64_t install_timestamp;
bool pinned;
// Not serialized fields // Not serialized fields
bool update_available; bool update_available;
@ -203,8 +204,8 @@ void to_json( json& j, const PCM_REPOSITORY& r );
void from_json( const json& j, PCM_REPOSITORY& r ); void from_json( const json& j, PCM_REPOSITORY& r );
NLOHMANN_DEFINE_TYPE_NON_INTRUSIVE( PCM_INSTALLATION_ENTRY, package, current_version, repository_id, void to_json( json& j, const PCM_INSTALLATION_ENTRY& e );
repository_name, install_timestamp ); void from_json( const json& j, PCM_INSTALLATION_ENTRY& e );
#endif // PCM_DATA_H_ #endif // PCM_DATA_H_