38#include <wx/filedlg.h>
98 virtual wxDirTraverseResult
OnFile(
const wxString& aFileName )
override
100 wxFileName file( aFileName );
104 if( file.GetExt().IsSameAs( ext,
false ) )
108 return wxDIR_CONTINUE;
111 virtual wxDirTraverseResult
OnOpenError(
const wxString& aOpenErrorName )
override
119 virtual wxDirTraverseResult
OnDir(
const wxString& aDirName )
override
122 return wxDIR_CONTINUE;
127 for( std::pair<const wxString, int>& foundDirsPair :
m_foundDirs )
128 aPathArray.Add( foundDirsPair.first );
133 for( std::pair<const wxString, int>& failedDirsPair :
m_failedDirs )
134 aPathArray.Add( failedDirsPair.first );
159 void SetValue(
int aRow,
int aCol,
const wxString& aValue )
override
161 wxCHECK( aRow < (
int)
size(), );
199 if( tbl->GetNumberRows() > aRow )
202 const wxString& options = row.
Options();
203 wxString
result = options;
204 std::map<std::string, UTF8> choices;
208 pi->GetLibraryOptions( &choices );
226 size_t ndx = cb_text.find(
"(design_block_lib_table" );
228 if( ndx != std::string::npos )
235 std::ranges::copy( tempTable.Rows(),
236 std::inserter( tbl->Table().Rows(), tbl->Table().Rows().begin() ) );
240 wxGridTableMessage msg( tbl, wxGRIDTABLE_NOTIFY_ROWS_INSERTED, 0, 0 );
241 tbl->GetView()->ProcessTableMessage( msg );
242 m_grid->AutoSizeColumns(
false );
255 m_grid->AutoSizeColumns(
false );
278 wxArrayString choices;
294 [&](
WX_GRID* aGrid,
int aCol )
296 int prevWidth = aGrid->GetColSize( aCol );
298 aGrid->AutoSizeColumn( aCol,
false );
299 aGrid->SetColSize( aCol, std::max( prevWidth, aGrid->GetColSize( aCol ) ) );
308 aGrid->SetSelectionMode( wxGrid::wxGridSelectRows );
310 wxGridCellAttr* attr =
new wxGridCellAttr;
318 auto* libTable = static_cast<DESIGN_BLOCK_LIB_TABLE_GRID*>( grid->GetTable() );
319 LIBRARY_TABLE_ROW& tableRow = libTable->at( row );
320 DESIGN_BLOCK_IO_MGR::DESIGN_BLOCK_FILE_T fileType =
321 DESIGN_BLOCK_IO_MGR::EnumFromStr( tableRow.Type() );
322 const IO_BASE::IO_FILE_DESC& pluginDesc = m_supportedDesignBlockFiles.at( fileType );
324 if( pluginDesc.m_IsFile )
325 return pluginDesc.FileFilter();
327 return wxEmptyString;
331 aGrid->SetColAttr(
COL_URI, attr );
333 attr =
new wxGridCellAttr;
334 attr->SetEditor(
new wxGridCellChoiceEditor( choices ) );
335 aGrid->SetColAttr(
COL_TYPE, attr );
337 attr =
new wxGridCellAttr;
338 attr->SetRenderer(
new wxGridCellBoolRenderer() );
355 if( aGrid->GetNumberRows() > 0 )
356 aGrid->SelectRow( 0 );
408 [](
const std::vector<std::string>& aExts )
412 for(
const std::string& ext : aExts )
414 if( !joined.empty() )
415 joined << wxS(
", " );
417 joined << wxS(
"*." ) << ext;
427 if( desc.m_IsFile && !desc.m_FileExtensions.empty() )
429 entryStr << wxString::Format( wxS(
" (%s)" ), joinExts( desc.m_FileExtensions ) );
431 else if( !desc.m_IsFile && !desc.m_ExtensionsInDir.empty() )
433 wxString midPart = wxString::Format(
_(
"folder with %s files" ), joinExts( desc.m_ExtensionsInDir ) );
435 entryStr << wxString::Format( wxS(
" (%s)" ), midPart );
438 browseMenu->Append( type, entryStr );
498 for(
int r = 0; r < model->GetNumberRows(); )
500 wxString nick = model->GetValue( r,
COL_NICKNAME ).Trim(
false ).Trim();
501 wxString uri = model->GetValue( r,
COL_URI ).Trim(
false ).Trim();
502 unsigned illegalCh = 0;
507 msg =
_(
"A library table row nickname and path cells are empty." );
509 msg =
_(
"A library table row nickname cell is empty." );
511 msg =
_(
"A library table row path cell is empty." );
513 wxWindow* topLevelParent = wxGetTopLevelParent(
this );
515 wxMessageDialog badCellDlg( topLevelParent, msg,
_(
"Invalid Row Definition" ),
516 wxYES_NO | wxCENTER | wxICON_QUESTION | wxYES_DEFAULT );
517 badCellDlg.SetExtendedMessage(
_(
"Empty cells will result in all rows that are "
518 "invalid to be removed from the table." ) );
519 badCellDlg.SetYesNoLabels( wxMessageDialog::ButtonLabel(
_(
"Remove Invalid Cells" ) ),
520 wxMessageDialog::ButtonLabel(
_(
"Cancel Table Update" ) ) );
522 if( badCellDlg.ShowModal() == wxID_NO )
529 model->GetView()->ClearSelection();
530 model->DeleteRows( r, 1 );
534 msg = wxString::Format(
_(
"Illegal character '%c' in nickname '%s'." ), illegalCh, nick );
540 model->GetView()->MakeCellVisible( r, 0 );
541 model->GetView()->SetGridCursor( r, 1 );
543 wxWindow* topLevelParent = wxGetTopLevelParent(
this );
545 wxMessageDialog errdlg( topLevelParent, msg,
_(
"Library Nickname Error" ) );
553 model->SetValue( r,
COL_URI, uri );
569 for(
int r1 = 0; r1 < model->GetNumberRows() - 1; ++r1 )
573 for(
int r2 = r1 + 1; r2 < model->GetNumberRows(); ++r2 )
579 msg = wxString::Format(
_(
"Multiple libraries cannot share the same nickname ('%s')." ),
590 wxWindow* topLevelParent = wxGetTopLevelParent(
this );
592 wxMessageDialog errdlg( topLevelParent, msg,
_(
"Library Nickname Error" ) );
614 [&]() -> std::pair<int, int>
637 wxArrayInt selectedRows =
m_cur_grid->GetSelectedRows();
638 wxGridCellCoordsArray cells =
m_cur_grid->GetSelectedCells();
639 wxGridCellCoordsArray blockTopLeft =
m_cur_grid->GetSelectionBlockTopLeft();
640 wxGridCellCoordsArray blockBotRight =
m_cur_grid->GetSelectionBlockBottomRight();
643 for(
unsigned ii = 0; ii < cells.GetCount(); ii++ )
644 selectedRows.Add( cells[ii].GetRow() );
647 if( !blockTopLeft.IsEmpty() && !blockBotRight.IsEmpty() )
649 for(
int i = blockTopLeft[0].GetRow(); i <= blockBotRight[0].GetRow(); ++i )
650 selectedRows.Add( i );
654 if( selectedRows.size() == 0 &&
m_cur_grid->GetGridCursorRow() >= 0 )
655 selectedRows.Add(
m_cur_grid->GetGridCursorRow() );
657 if( selectedRows.size() == 0 )
663 std::sort( selectedRows.begin(), selectedRows.end() );
672 for(
int ii = selectedRows.GetCount() - 1; ii >= 0; ii-- )
674 int row = selectedRows[ii];
676 if( row != last_row )
683 if(
m_cur_grid->GetNumberRows() > 0 && curRow >= 0 )
696 std::vector<LIBRARY_TABLE_ROW>& rows = tbl->
Table().
Rows();
698 auto current = rows.begin() + curRow;
699 auto prev = rows.begin() + curRow - 1;
701 std::iter_swap( current, prev );
704 wxGridTableMessage msg( tbl, wxGRIDTABLE_NOTIFY_ROWS_INSERTED, row - 1, 0 );
705 tbl->GetView()->ProcessTableMessage( msg );
717 std::vector<LIBRARY_TABLE_ROW>& rows = tbl->
Table().
Rows();
719 auto current = rows.begin() + curRow;
720 auto next = rows.begin() + curRow + 1;
722 std::iter_swap( current,
next );
725 wxGridTableMessage msg( tbl, wxGRIDTABLE_NOTIFY_ROWS_INSERTED, row, 0 );
726 tbl->GetView()->ProcessTableMessage( msg );
737 wxArrayInt selectedRows =
m_cur_grid->GetSelectedRows();
739 if( selectedRows.empty() &&
m_cur_grid->GetGridCursorRow() >= 0 )
740 selectedRows.push_back(
m_cur_grid->GetGridCursorRow() );
742 wxArrayInt rowsToMigrate;
746 for(
int row : selectedRows )
749 rowsToMigrate.push_back( row );
752 if( rowsToMigrate.size() <= 0 )
754 wxMessageBox( wxString::Format(
_(
"Select one or more rows containing libraries "
755 "to save as current KiCad format." ) ) );
760 if( rowsToMigrate.size() == 1 )
762 msg.Printf(
_(
"Save '%s' as current KiCad format and replace entry in table?" ),
767 msg.Printf(
_(
"Save %d libraries as current KiCad format and replace entries in table?" ),
768 (
int) rowsToMigrate.size() );
775 for(
int row : rowsToMigrate )
780 wxFileName legacyLib( resolvedPath );
782 if( !legacyLib.Exists() )
784 msg.Printf(
_(
"Library '%s' not found." ), relPath );
789 wxFileName newLib( resolvedPath );
791 newLib.SetName(
"" );
794 if( newLib.DirExists() )
796 msg.Printf(
_(
"Folder '%s' already exists. Do you want overwrite any existing design "
798 newLib.GetFullPath() );
800 switch( wxMessageBox( msg,
_(
"Migrate Library" ), wxYES_NO | wxCANCEL | wxICON_QUESTION,
m_parent ) )
804 case wxCANCEL:
return;
812 newLib.GetFullPath() ) )
820 relPath = newLib.GetFullPath();
827 msg.Printf(
_(
"Failed to save design block library file '%s'." ), newLib.GetFullPath() );
843 if( event.GetEventType() == wxEVT_BUTTON )
855 wxLogWarning( wxT(
"File type selection event received but could not find the file type in the table" ) );
872 wxWindow* topLevelParent = wxGetTopLevelParent(
this );
876 wxFileDialog dlg( topLevelParent, title, *lastDir, wxEmptyString, fileDesc.
FileFilter(),
877 wxFD_OPEN | wxFD_FILE_MUST_EXIST | wxFD_MULTIPLE );
879 if( dlg.ShowModal() == wxID_CANCEL )
882 dlg.GetPaths( files );
883 *lastDir = dlg.GetDirectory();
887 wxDirDialog dlg( topLevelParent, title, *lastDir,
888 wxDD_DEFAULT_STYLE | wxDD_DIR_MUST_EXIST | wxDD_MULTIPLE );
890 if( dlg.ShowModal() == wxID_CANCEL )
893 dlg.GetPaths( files );
895 if( !files.IsEmpty() )
897 wxFileName first( files.front() );
898 *lastDir = first.GetPath();
907 bool addDuplicates =
false;
908 bool applyToAll =
false;
909 wxString warning =
_(
"Warning: Duplicate Nicknames" );
910 wxString msg =
_(
"A library nicknamed '%s' already exists." );
911 wxString detailedMsg =
_(
"One of the nicknames will need to be changed after "
912 "adding this library." );
914 for(
const wxString& filePath : files )
916 wxFileName fn( filePath );
923 if(
cur_model()->ContainsNickname( nickname ) )
929 wxString::Format( msg, nickname ), detailedMsg,
930 _(
"Skip" ),
_(
"Add Anyway" ), &applyToAll )
934 doAdd = addDuplicates;
939 int last_row =
m_cur_grid->GetNumberRows() - 1;
951 if(
m_pageNdx == 0 &&
path.Contains( wxT(
"${KIPRJMOD}" ) ) )
952 path = fn.GetFullPath();
958 if( !files.IsEmpty() )
960 int new_row =
m_cur_grid->GetNumberRows() - 1;
994 std::optional<LIBRARY_TABLE*> optTable =
996 wxCHECK( optTable,
false );
1001 m_parent->m_GlobalTableChanged =
true;
1013 m_parent->m_ProjectTableChanged =
true;
1026 wxRegEx re(
".*?(\\$\\{(.+?)\\})|(\\$\\((.+?)\\)).*?", wxRE_ADVANCED );
1027 wxASSERT( re.IsValid() );
1029 std::set<wxString> unique;
1039 for(
int row = 0; row < tbl->GetNumberRows(); ++row )
1041 wxString uri = tbl->GetValue( row,
COL_URI );
1043 while( re.Matches( uri ) )
1045 wxString envvar = re.GetMatch( uri, 2 );
1048 if( envvar.IsEmpty() )
1049 envvar = re.GetMatch( uri, 4 );
1052 unique.insert( envvar );
1055 uri.Replace( re.GetMatch( uri, 0 ), wxEmptyString );
1069 for(
const wxString& evName : unique )
1074 m_path_subs_grid->SetCellValue( row, 0, wxT(
"${" ) + evName + wxT(
"}" ) );
1078 wxGetEnv( evName, &evValue );
1105 std::optional<LIBRARY_TABLE*> optTable =
1107 wxCHECK( optTable, );
1110 globalTable->
Save().map_error(
1113 wxMessageBox( wxString::Format(
_(
"Error saving global library table:\n\n%s" ), aError.
message ),
1114 _(
"File Save Error" ), wxOK | wxICON_ERROR );
1120 std::optional<LIBRARY_TABLE*> projectTable =
1125 ( *projectTable )->Save().map_error(
1128 wxMessageBox( wxString::Format(
_(
"Error saving project-specific library table:\n\n%s" ),
1130 _(
"File Save Error" ), wxOK | wxICON_ERROR );
1140 std::string payload =
"";
wxBitmapBundle KiBitmapBundle(BITMAPS aBitmap, int aMinHeight)
void paste_text(const wxString &cb_text) override
handle specialized clipboard text, with leading "(design_block_lib_table", OR spreadsheet formatted t...
DIALOG_EDIT_LIBRARY_TABLES * m_dialog
void optionsEditor(int aRow) override
DESIGN_BLOCK_GRID_TRICKS(DIALOG_EDIT_LIBRARY_TABLES *aParent, WX_GRID *aGrid)
@ KICAD_SEXP
S-expression KiCad file format.
static const wxString ShowType(DESIGN_BLOCK_FILE_T aFileType)
static DESIGN_BLOCK_FILE_T GuessPluginTypeFromLibPath(const wxString &aLibPath, int aCtl=0)
static DESIGN_BLOCK_FILE_T EnumFromStr(const wxString &aFileType)
static bool ConvertLibrary(std::map< std::string, UTF8 > *aOldFileProps, const wxString &aOldFilePath, const wxString &aNewFilePath)
Convert a design block library to the latest KiCad format.
static DESIGN_BLOCK_IO * FindPlugin(DESIGN_BLOCK_FILE_T aFileType)
static wxString GlobalPathEnvVariableName()
This class builds a wxGridTableBase by wrapping an #DESIGN_BLOCK_LIB_TABLE object.
friend class DESIGN_BLOCK_GRID_TRICKS
DESIGN_BLOCK_LIB_TABLE_GRID(const LIBRARY_TABLE &aTableToEdit)
void SetValue(int aRow, int aCol, const wxString &aValue) override
friend class PANEL_DESIGN_BLOCK_LIB_TABLE
bool m_ProjectTableChanged
void InstallPanel(wxPanel *aPanel)
bool m_GlobalTableChanged
An options editor in the form of a two column name/value spreadsheet like (table) UI.
Editor for wxGrid cells that adds a file/folder browser to the grid input field.
Add mouse and command handling (such as cut, copy, and paste) to a WX_GRID instance.
virtual void paste_text(const wxString &cb_text)
WX_GRID * m_grid
I don't own the grid, but he owns me.
wxString m_lastDesignBlockLibDir
A minimalistic software bus for communications between various DLLs/DSOs (DSOs) within the same KiCad...
virtual void ExpressMail(FRAME_T aDestination, MAIL_T aCommand, std::string &aPayload, wxWindow *aSource=nullptr, bool aFromOtherThread=false)
Send aPayload to aDestination from aSource.
virtual PROJECT & Prj() const
Return the PROJECT associated with this KIWAY.
static wxString ExpandURI(const wxString &aShortURI, const PROJECT &aProject)
std::optional< LIBRARY_TABLE * > Table(LIBRARY_TABLE_TYPE aType, LIBRARY_TABLE_SCOPE aScope)
Retrieves a given table; creating a new empty project table if a valid project is loaded and the give...
void LoadGlobalTables(std::initializer_list< LIBRARY_TABLE_TYPE > aTablesToLoad={})
(Re)loads the global library tables in the given list, or all tables if no list is given
void ProjectChanged()
Notify all adapters that the project has changed.
void SetOptions(const wxString &aOptions)
const wxString & Type() const
const wxString & URI() const
const wxString & Nickname() const
const wxString & Options() const
LIBRARY_RESULT< void > Save()
const std::vector< LIBRARY_TABLE_ROW > & Rows() const
void GetPaths(wxArrayString &aPathArray)
virtual wxDirTraverseResult OnOpenError(const wxString &aOpenErrorName) override
std::unordered_map< wxString, int > m_failedDirs
std::vector< std::string > m_searchExtensions
void GetFailedPaths(wxArrayString &aPathArray)
bool HasDirectoryOpenFailures()
LIBRARY_TRAVERSER(std::vector< std::string > aSearchExtensions, wxString aInitialDir)
std::unordered_map< wxString, int > m_foundDirs
virtual wxDirTraverseResult OnDir(const wxString &aDirName) override
virtual wxDirTraverseResult OnFile(const wxString &aFileName) override
static unsigned FindIllegalLibraryNameChar(const UTF8 &aLibraryName)
Looks for characters that are illegal in library nicknames.
static UTF8 FixIllegalChars(const UTF8 &aLibItemName, bool aLib)
Replace illegal LIB_ID item name characters with underscores '_'.
LIB_TABLE_GRID_TRICKS(WX_GRID *aGrid)
LIB_TABLE_GRID(const LIBRARY_TABLE &aTableToEdit, LIBRARY_MANAGER_ADAPTER *aAdapter=nullptr)
void SetValue(int aRow, int aCol, const wxString &aValue) override
virtual size_t size() const
virtual LIBRARY_TABLE_ROW & at(size_t aIndex)
static std::map< std::string, UTF8 > ParseOptions(const std::string &aOptionsList)
Parses aOptionsList and places the result into a #PROPERTIES object which is returned.
WX_GRID * m_path_subs_grid
STD_BITMAP_BUTTON * m_move_up_button
STD_BITMAP_BUTTON * m_delete_button
wxButton * m_migrate_libs_button
SPLIT_BUTTON * m_browseButton
STD_BITMAP_BUTTON * m_append_button
PANEL_DESIGN_BLOCK_LIB_TABLE_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)
STD_BITMAP_BUTTON * m_move_down_button
Dialog to show and edit symbol library tables.
void moveUpHandler(wxCommandEvent &event) override
void onMigrateLibraries(wxCommandEvent &event) override
void adjustPathSubsGridColumns(int aWidth)
DESIGN_BLOCK_LIB_TABLE_GRID * project_model() const
bool TransferDataFromWindow() override
void browseLibrariesHandler(wxCommandEvent &event)
void populateEnvironReadOnlyTable()
Populate the readonly environment variable table with names and values by examining all the full_uri ...
DESIGN_BLOCK_LIB_TABLE_GRID * cur_model() const
std::map< DESIGN_BLOCK_IO_MGR::DESIGN_BLOCK_FILE_T, IO_BASE::IO_FILE_DESC > m_supportedDesignBlockFiles
void moveDownHandler(wxCommandEvent &event) override
DIALOG_EDIT_LIBRARY_TABLES * m_parent
void OnUpdateUI(wxUpdateUIEvent &event) override
wxString m_lastProjectLibDir
void appendRowHandler(wxCommandEvent &event) override
PANEL_DESIGN_BLOCK_LIB_TABLE(DIALOG_EDIT_LIBRARY_TABLES *aParent, PROJECT *aProject)
DESIGN_BLOCK_LIB_TABLE_GRID * global_model() const
void populatePluginList()
~PANEL_DESIGN_BLOCK_LIB_TABLE() override
void onSizeGrid(wxSizeEvent &event) override
void deleteRowHandler(wxCommandEvent &event) override
bool verifyTables()
Trim important fields, removes blank row entries, and checks for duplicates.
static wxString GetDefaultUserDesignBlocksPath()
Gets the default path we point users to create projects.
void PreloadDesignBlockLibraries(KIWAY *aKiway)
Starts a background job to preload the global and project design block libraries.
virtual ENV_VAR_MAP & GetLocalEnvVariables() const
virtual LIBRARY_MANAGER & GetLibraryManager() const
Container for project specific data.
virtual const wxString DesignBlockLibTblName() const
Return the path and file name of this projects design block library table.
const wxString ExpandEnvVarSubstitutions(const wxString &aString, const PROJECT *aProject)
Replace any environment variable & text variable references with their values.
int OKOrCancelDialog(wxWindow *aParent, const wxString &aWarning, const wxString &aMessage, const wxString &aDetailedMessage, const wxString &aOKLabel, const wxString &aCancelLabel, bool *aApplyToAll)
Display a warning dialog with aMessage and returns the user response.
bool IsOK(wxWindow *aParent, const wxString &aMessage)
Display a yes/no dialog with aMessage and returns the user response.
void DisplayErrorMessage(wxWindow *aParent, const wxString &aText, const wxString &aExtraInfo)
Display an error message with aMessage.
void DisplayError(wxWindow *aParent, const wxString &aText)
Display an error or warning message box with aMessage.
This file is part of the common library.
wxString NormalizePath(const wxFileName &aFilePath, const ENV_VAR_MAP *aEnvVars, const wxString &aProjectPath)
Normalize a file path to an environmental variable, if possible.
Helper functions to substitute paths with environmental variables.
Functions related to environment variables, including help functions.
static const std::string KiCadDesignBlockLibPathExtension
std::map< wxString, ENV_VAR_ITEM > ENV_VAR_MAP
std::unique_ptr< T > IO_RELEASER
Helper to hold and release an IO_BASE object when exceptions are thrown.
This file contains miscellaneous commonly used macros and functions.
KICOMMON_API wxString GetVersionedEnvVarName(const wxString &aBaseName)
Construct a versioned environment variable based on this KiCad major version.
void InvokeEditDesignBlockLibTable(KIWAY *aKiway, wxWindow *aParent)
SETTINGS_MANAGER * GetSettingsManager()
PGM_BASE & Pgm()
The global program "get" accessor.
#define PROJECT_VAR_NAME
A variable name whose value holds the current project directory.
T * GetAppSettings(const char *aFilename)
std::vector< FAB_LAYER_COLOR > dummy
MODEL3D_FORMAT_TYPE fileType(const char *aFileName)
Container that describes file type info.
bool m_IsFile
Whether the library is a folder or a file.
wxString FileFilter() const
Container that describes file type info for the add a library options.
bool m_IsFile
Whether the library is a folder or a file.
wxString m_Description
Description shown in the file picker dialog.
wxString m_FileFilter
Filter used for file pickers if m_IsFile is true.
DESIGN_BLOCK_IO_MGR::DESIGN_BLOCK_FILE_T m_Plugin
wxString m_FolderSearchExtension
In case of folders it stands for extensions of files stored inside.
wxString result
Test unit parsing edge cases and error handling.
Definition of file extensions used in Kicad.