Add pin/unpin context menu to Symbol Chooser and Footprint Chooser.

Also moves some more code down into common so it can be shared.

Fixes https://gitlab.com/kicad/code/kicad/issues/12384
This commit is contained in:
Jeff Young 2022-09-21 14:44:13 +01:00
parent 6154a8d5d5
commit 8eb68ee472
12 changed files with 140 additions and 176 deletions

View File

@ -3,7 +3,7 @@
*
* Copyright (C) 2017 Chris Pavlina <pavlina.chris@gmail.com>
* Copyright (C) 2014 Henner Zeller <h.zeller@acm.org>
* Copyright (C) 2014-2021 KiCad Developers, see AUTHORS.txt for contributors.
* Copyright (C) 2014-2022 KiCad Developers, see AUTHORS.txt for contributors.
*
* This program is free software: you can redistribute it and/or modify it
* under the terms of the GNU General Public License as published by the
@ -22,7 +22,6 @@
#include <eda_base_frame.h>
#include <eda_pattern_match.h>
#include <kiface_base.h>
#include <config_params.h>
#include <lib_tree_model_adapter.h>
#include <project/project_file.h>
#include <settings/app_settings.h>
@ -32,8 +31,6 @@
#include <string_utils.h>
#define PINNED_ITEMS_KEY wxT( "PinnedItems" )
static const int kDataViewIndent = 20;
@ -265,6 +262,38 @@ void LIB_TREE_MODEL_ADAPTER::AttachTo( wxDataViewCtrl* aDataViewCtrl )
}
void LIB_TREE_MODEL_ADAPTER::resortTree()
{
Freeze();
BeforeReset();
m_tree.SortNodes();
AfterReset();
Thaw();
}
void LIB_TREE_MODEL_ADAPTER::PinLibrary( LIB_TREE_NODE* aTreeNode )
{
m_parent->Prj().PinLibrary( aTreeNode->m_LibId.GetLibNickname(), isSymbolModel() );
aTreeNode->m_Pinned = true;
resortTree();
m_widget->EnsureVisible( ToItem( aTreeNode ) );
}
void LIB_TREE_MODEL_ADAPTER::UnpinLibrary( LIB_TREE_NODE* aTreeNode )
{
m_parent->Prj().UnpinLibrary( aTreeNode->m_LibId.GetLibNickname(), isSymbolModel() );
aTreeNode->m_Pinned = false;
resortTree();
// Keep focus at top when unpinning
}
wxDataViewColumn* LIB_TREE_MODEL_ADAPTER::doAddColumn( const wxString& aHeader, bool aTranslate )
{
wxString translatedHeader = aTranslate ? wxGetTranslation( aHeader ) : aHeader;
@ -529,7 +558,11 @@ void LIB_TREE_MODEL_ADAPTER::GetValue( wxVariant& aVariant,
switch( aCol )
{
case NAME_COL:
if( node->m_Pinned )
aVariant = GetPinningSymbol() + UnescapeString( node->m_Name );
else
aVariant = UnescapeString( node->m_Name );
break;
case DESC_COL:
@ -537,18 +570,19 @@ void LIB_TREE_MODEL_ADAPTER::GetValue( wxVariant& aVariant,
break;
default:
if( m_colIdxMap.count( aCol ) )
{
wxCHECK_RET( m_colIdxMap.count( aCol ), wxT( "Invalid column in LIB_TREE_MODEL_ADAPTER" ) );
const wxString& key = m_colIdxMap.at( aCol );
if( node->m_Fields.count( m_colIdxMap.at( aCol ) ) )
aVariant = node->m_Fields[m_colIdxMap.at( aCol )];
if( node->m_Fields.count( key ) )
aVariant = node->m_Fields.at( key );
else
aVariant = wxEmptyString;
}
break;
}
}
}
bool LIB_TREE_MODEL_ADAPTER::GetAttr( const wxDataViewItem& aItem,

View File

@ -24,8 +24,10 @@
#include <wx/log.h>
#include <wx/stdpaths.h>
#include <pgm_base.h>
#include <confirm.h>
#include <core/arraydim.h>
#include <core/kicad_algo.h>
#include <fp_lib_table.h>
#include <string_utils.h>
#include <kiface_ids.h>
@ -35,7 +37,8 @@
#include <project/project_file.h>
#include <trace_helpers.h>
#include <wildcards_and_files_ext.h>
#include <settings/common_settings.h>
#include <settings/settings_manager.h>
PROJECT::PROJECT() :
m_readOnly( false ),
@ -149,6 +152,46 @@ const wxString PROJECT::FootprintLibTblName() const
}
void PROJECT::PinLibrary( const wxString& aLibrary, bool isSymbolLibrary )
{
COMMON_SETTINGS* cfg = Pgm().GetCommonSettings();
PROJECT_FILE& project = GetProjectFile();
std::vector<wxString>& pinnedLibs = isSymbolLibrary ? m_projectFile->m_PinnedSymbolLibs
: m_projectFile->m_PinnedFootprintLibs;
if( !alg::contains( pinnedLibs, aLibrary ) )
pinnedLibs.push_back( aLibrary );
Pgm().GetSettingsManager().SaveProject();
pinnedLibs = isSymbolLibrary ? cfg->m_Session.pinned_symbol_libs
: cfg->m_Session.pinned_fp_libs;
if( !alg::contains( pinnedLibs, aLibrary ) )
pinnedLibs.push_back( aLibrary );
cfg->SaveToFile( Pgm().GetSettingsManager().GetPathForSettingsFile( cfg ) );
}
void PROJECT::UnpinLibrary( const wxString& aLibrary, bool isSymbolLibrary )
{
COMMON_SETTINGS* cfg = Pgm().GetCommonSettings();
PROJECT_FILE& project = GetProjectFile();
std::vector<wxString>& pinnedLibs = isSymbolLibrary ? m_projectFile->m_PinnedSymbolLibs
: m_projectFile->m_PinnedFootprintLibs;
alg::delete_matching( pinnedLibs, aLibrary );
Pgm().GetSettingsManager().SaveProject();
pinnedLibs = isSymbolLibrary ? cfg->m_Session.pinned_symbol_libs
: cfg->m_Session.pinned_fp_libs;
alg::delete_matching( pinnedLibs, aLibrary );
cfg->SaveToFile( Pgm().GetSettingsManager().GetPathForSettingsFile( cfg ) );
}
const wxString PROJECT::libTableName( const wxString& aLibTableName ) const
{
wxFileName fn = GetProjectFullName();

View File

@ -29,11 +29,11 @@
#include <wx/sizer.h>
#include <tool/tool_interactive.h>
#include <tool/tool_manager.h>
#include <tool/actions.h>
#include <wx/srchctrl.h>
#include <wx/settings.h>
#include <wx/timer.h>
constexpr int RECENT_SEARCHES_MAX = 10;
std::map<wxString, std::vector<wxString>> g_recentSearches;
@ -575,9 +575,7 @@ void LIB_TREE::onPreselect( wxCommandEvent& aEvent )
void LIB_TREE::onContextMenu( wxDataViewEvent& aEvent )
{
TOOL_INTERACTIVE* tool = m_adapter->GetContextMenuTool();
if( tool )
if( TOOL_INTERACTIVE* tool = m_adapter->GetContextMenuTool() )
{
tool->Activate();
tool->GetManager()->VetoContextMenuMouseWarp();
@ -586,6 +584,30 @@ void LIB_TREE::onContextMenu( wxDataViewEvent& aEvent )
TOOL_EVENT evt( TC_MOUSE, TA_MOUSE_CLICK, BUT_RIGHT );
tool->GetManager()->DispatchContextMenu( evt );
}
else
{
LIB_TREE_NODE* current = GetCurrentTreeNode();
if( current && current->m_Type == LIB_TREE_NODE::LIB )
{
ACTION_MENU menu( true, nullptr );
if( current->m_Pinned )
{
menu.Add( ACTIONS::unpinLibrary );
if( GetPopupMenuSelectionFromUser( menu ) )
m_adapter->UnpinLibrary( current );
}
else
{
menu.Add( ACTIONS::pinLibrary );
if( GetPopupMenuSelectionFromUser( menu ) )
m_adapter->PinLibrary( current );
}
}
}
}

View File

@ -182,12 +182,11 @@ bool SYMBOL_TREE_MODEL_ADAPTER::AddLibraries( const std::vector<wxString>& aNick
if( progressReporter )
{
// Force immediate deletion of the APP_PROGRESS_DIALOG
// ( do not use Destroy(), or use Destroy() followed by wxSafeYield() )
// because on Windows, APP_PROGRESS_DIALOG has some side effects on the event loop
// manager. A side effect is the call of ShowModal() of a dialog following
// the use of SYMBOL_TREE_MODEL_ADAPTER creating a APP_PROGRESS_DIALOG
// has a broken behavior (incorrect modal behavior).
// Force immediate deletion of the APP_PROGRESS_DIALOG. Do not use Destroy(), or Destroy()
// followed by wxSafeYield() because on Windows, APP_PROGRESS_DIALOG has some side effects
// on the event loop manager.
// One in particular is the call of ShowModal() following SYMBOL_TREE_MODEL_ADAPTER
// creating a APP_PROGRESS_DIALOG (which has incorrect modal behaviour).
progressReporter.reset();
m_show_progress = false;
}
@ -229,47 +228,3 @@ wxString SYMBOL_TREE_MODEL_ADAPTER::GenerateInfo( LIB_ID const& aLibId, int aUni
}
void SYMBOL_TREE_MODEL_ADAPTER::GetValue( wxVariant& aVariant, wxDataViewItem const& aItem,
unsigned int aCol ) const
{
if( IsFrozen() )
{
aVariant = wxEmptyString;
return;
}
LIB_TREE_NODE* node = ToNode( aItem );
wxASSERT( node );
switch( aCol )
{
case NAME_COL:
if( node->m_Pinned )
aVariant = GetPinningSymbol() + UnescapeString( node->m_Name );
else
aVariant = UnescapeString( node->m_Name );
break;
case DESC_COL:
aVariant = node->m_Desc;
break;
default:
{
if( m_colIdxMap.count( aCol ) )
{
const wxString& key = m_colIdxMap.at( aCol );
if( node->m_Fields.count( key ) )
aVariant = node->m_Fields.at( key );
else
aVariant = wxEmptyString;
}
break;
}
}
}

View File

@ -64,16 +64,7 @@ protected:
*/
SYMBOL_TREE_MODEL_ADAPTER( EDA_BASE_FRAME* aParent, LIB_TABLE* aLibs );
/**
* Get the value of an item.
*
* @param aVariant wxVariant to receive the data
* @param aItem item whose data will be placed into aVariant
* @param aCol column number of the data
*/
void GetValue( wxVariant& aVariant,
const wxDataViewItem& aItem,
unsigned int aCol ) const override;
bool isSymbolModel() override { return true; }
private:
friend class SYMBOL_ASYNC_LOADER;

View File

@ -61,6 +61,8 @@ protected:
SYMBOL_TREE_SYNCHRONIZING_ADAPTER( SYMBOL_EDIT_FRAME* aParent,
SYMBOL_LIBRARY_MANAGER* aLibMgr );
bool isSymbolModel() override { return true; }
protected:
SYMBOL_EDIT_FRAME* m_frame;
SYMBOL_LIBRARY_MANAGER* m_libMgr;

View File

@ -24,9 +24,6 @@
#include <kiway.h>
#include <pgm_base.h>
#include <project.h>
#include <project/project_file.h>
#include <settings/settings_manager.h>
#include <sch_painter.h>
#include <tool/tool_manager.h>
#include <tools/ee_actions.h>
@ -36,7 +33,6 @@
#include <symbol_viewer_frame.h>
#include <symbol_tree_model_adapter.h>
#include <wildcards_and_files_ext.h>
#include <wildcards_and_files_ext.h>
#include <bitmaps/bitmap_types.h>
#include <confirm.h>
#include <wx/filedlg.h>
@ -439,19 +435,7 @@ int SYMBOL_EDITOR_CONTROL::PinLibrary( const TOOL_EVENT& aEvent )
if( currentNode && !currentNode->m_Pinned )
{
COMMON_SETTINGS* cfg = Pgm().GetCommonSettings();
PROJECT_FILE& project = m_frame->Prj().GetProjectFile();
wxString nickname = currentNode->m_LibId.GetLibNickname();
if( !alg::contains( project.m_PinnedSymbolLibs, nickname ) )
project.m_PinnedSymbolLibs.push_back( nickname );
Pgm().GetSettingsManager().SaveProject();
if( !alg::contains( cfg->m_Session.pinned_symbol_libs, nickname ) )
cfg->m_Session.pinned_symbol_libs.push_back( nickname );
cfg->SaveToFile( Pgm().GetSettingsManager().GetPathForSettingsFile( cfg ) );
m_frame->Prj().PinLibrary( currentNode->m_LibId.GetLibNickname(), true );
currentNode->m_Pinned = true;
editFrame->RegenerateLibraryTree();
@ -471,15 +455,7 @@ int SYMBOL_EDITOR_CONTROL::UnpinLibrary( const TOOL_EVENT& aEvent )
if( currentNode && currentNode->m_Pinned )
{
COMMON_SETTINGS* cfg = Pgm().GetCommonSettings();
PROJECT_FILE& project = m_frame->Prj().GetProjectFile();
wxString nickname = currentNode->m_LibId.GetLibNickname();
alg::delete_matching( project.m_PinnedSymbolLibs, nickname );
Pgm().GetSettingsManager().SaveProject();
alg::delete_matching( cfg->m_Session.pinned_symbol_libs, nickname );
cfg->SaveToFile( Pgm().GetSettingsManager().GetPathForSettingsFile( cfg ) );
m_frame->Prj().UnpinLibrary( currentNode->m_LibId.GetLibNickname(), true );
currentNode->m_Pinned = false;
editFrame->RegenerateLibraryTree();

View File

@ -290,6 +290,9 @@ public:
// Allows subclasses to nominate a context menu handler.
virtual TOOL_INTERACTIVE* GetContextMenuTool() { return nullptr; }
void PinLibrary( LIB_TREE_NODE* aTreeNode );
void UnpinLibrary( LIB_TREE_NODE* aTreeNode );
protected:
/**
* Convert #SYM_TREE_NODE -> wxDataViewItem.
@ -372,6 +375,10 @@ protected:
unsigned int aCol,
wxDataViewItemAttr& aAttr ) const override;
virtual bool isSymbolModel() = 0;
void resortTree();
private:
/**
* Find any results worth highlighting and expand them, according to given criteria
@ -404,7 +411,7 @@ protected:
std::map<unsigned, wxString> m_colIdxMap;
private:
[[maybe_unused]] EDA_BASE_FRAME* m_parent;
EDA_BASE_FRAME* m_parent;
SYM_FILTER_TYPE m_filter;
bool m_show_units;

View File

@ -142,6 +142,9 @@ public:
*/
virtual const wxString SymbolLibTableName() const;
void PinLibrary( const wxString& aLibrary, bool isSymbolLibrary );
void UnpinLibrary( const wxString& aLibrary, bool isSymbolLibrary );
virtual PROJECT_FILE& GetProjectFile() const
{
wxASSERT( m_projectFile );

View File

@ -92,39 +92,3 @@ wxString FP_TREE_MODEL_ADAPTER::GenerateInfo( LIB_ID const& aLibId, int aUnit )
{
return GenerateFootprintInfo( m_libs, aLibId );
}
void FP_TREE_MODEL_ADAPTER::GetValue( wxVariant& aVariant, wxDataViewItem const& aItem,
unsigned int aCol ) const
{
if( IsFrozen() )
{
aVariant = wxEmptyString;
return;
}
LIB_TREE_NODE* node = ToNode( aItem );
wxASSERT( node );
if( aCol == 0 && node->m_Pinned )
aVariant = GetPinningSymbol() + node->m_Name;
else
aVariant = node->m_Name;
switch( aCol )
{
case NAME_COL:
if( node->m_Pinned )
aVariant = GetPinningSymbol() + UnescapeString( node->m_Name );
else
aVariant = UnescapeString( node->m_Name );
break;
case DESC_COL:
aVariant = node->m_Desc;
break;
}
}

View File

@ -51,16 +51,7 @@ protected:
std::vector<LIB_TREE_ITEM*> getFootprints( const wxString& aLibName );
/**
* Get the value of an item.
*
* @param aVariant wxVariant to receive the data
* @param aItem item whose data will be placed into aVariant
* @param aCol column number of the data
*/
void GetValue( wxVariant& aVariant,
const wxDataViewItem& aItem,
unsigned int aCol ) const override;
bool isSymbolModel() override { return false; }
protected:
FP_LIB_TABLE* m_libs;

View File

@ -29,7 +29,6 @@
#include <pgm_base.h>
#include <tool/tool_manager.h>
#include <tools/pcb_actions.h>
#include <view/view_controls.h>
#include <footprint_edit_frame.h>
#include <pcbnew_id.h>
#include <confirm.h>
@ -38,9 +37,6 @@
#include <pad.h>
#include <pcb_group.h>
#include <zone.h>
#include <project.h>
#include <project/project_file.h>
#include <settings/settings_manager.h>
#include <fp_lib_table.h>
#include <dialogs/dialog_cleanup_graphics.h>
#include <dialogs/dialog_footprint_checker.h>
@ -548,19 +544,7 @@ int FOOTPRINT_EDITOR_CONTROL::PinLibrary( const TOOL_EVENT& aEvent )
if( currentNode && !currentNode->m_Pinned )
{
COMMON_SETTINGS* cfg = Pgm().GetCommonSettings();
PROJECT_FILE& project = m_frame->Prj().GetProjectFile();
wxString nickname = currentNode->m_LibId.GetLibNickname();
if( !alg::contains( project.m_PinnedFootprintLibs, nickname ) )
project.m_PinnedFootprintLibs.push_back( nickname );
Pgm().GetSettingsManager().SaveProject();
if( !alg::contains( cfg->m_Session.pinned_fp_libs, nickname ) )
cfg->m_Session.pinned_fp_libs.push_back( nickname );
cfg->SaveToFile( Pgm().GetSettingsManager().GetPathForSettingsFile( cfg ) );
m_frame->Prj().PinLibrary( currentNode->m_LibId.GetLibNickname(), false );
currentNode->m_Pinned = true;
m_frame->RegenerateLibraryTree();
@ -576,15 +560,7 @@ int FOOTPRINT_EDITOR_CONTROL::UnpinLibrary( const TOOL_EVENT& aEvent )
if( currentNode && currentNode->m_Pinned )
{
COMMON_SETTINGS* cfg = Pgm().GetCommonSettings();
PROJECT_FILE& project = m_frame->Prj().GetProjectFile();
wxString nickname = currentNode->m_LibId.GetLibNickname();
alg::delete_matching( project.m_PinnedFootprintLibs, nickname );
Pgm().GetSettingsManager().SaveProject();
alg::delete_matching( cfg->m_Session.pinned_fp_libs, nickname );
cfg->SaveToFile( Pgm().GetSettingsManager().GetPathForSettingsFile( cfg ) );
m_frame->Prj().UnpinLibrary( currentNode->m_LibId.GetLibNickname(), false );
currentNode->m_Pinned = false;
m_frame->RegenerateLibraryTree();