Allow multiple selections in Kicad project manager (starting point)

This commit is contained in:
Mikolaj Wielgus 2019-12-05 20:35:37 +01:00 committed by jean-pierre charras
parent 52db6acb86
commit 350a991f26
3 changed files with 264 additions and 202 deletions

View File

@ -63,13 +63,12 @@
// list of files extensions listed in the tree project window // list of files extensions listed in the tree project window
// *.sch files are always allowed, do not add here // *.sch files are always allowed, do not add here
// Add extensions in a compatible regex format to see others files types // Add extensions in a compatible regex format to see others files types
static const wxChar* s_allowedExtensionsToList[] = static const wxChar* s_allowedExtensionsToList[] = {
{
wxT( "^.*\\.pro$" ), wxT( "^.*\\.pro$" ),
wxT( "^.*\\.pdf$" ), wxT( "^.*\\.pdf$" ),
wxT( "^[^$].*\\.brd$" ), // Legacy Pcbnew files wxT( "^[^$].*\\.brd$" ), // Legacy Pcbnew files
wxT( "^[^$].*\\.kicad_pcb$" ), // S format Pcbnew board files wxT( "^[^$].*\\.kicad_pcb$" ), // S format Pcbnew board files
wxT( "^[^$].*\\.kicad_wks$" ), // S format kicad page layout descr files wxT( "^[^$].*\\.kicad_wks$" ), // S format kicad page layout help_textr files
wxT( "^[^$].*\\.kicad_mod$" ), // S format kicad footprint files, currently not listed wxT( "^[^$].*\\.kicad_mod$" ), // S format kicad footprint files, currently not listed
wxT( "^.*\\.net$" ), // pcbnew netlist file wxT( "^.*\\.net$" ), // pcbnew netlist file
wxT( "^.*\\.cir$" ), // Spice netlist file wxT( "^.*\\.cir$" ), // Spice netlist file
@ -172,12 +171,12 @@ TREE_PROJECT_FRAME::~TREE_PROJECT_FRAME()
void TREE_PROJECT_FRAME::OnSwitchToSelectedProject( wxCommandEvent& event ) void TREE_PROJECT_FRAME::OnSwitchToSelectedProject( wxCommandEvent& event )
{ {
TREEPROJECT_ITEM* tree_data = GetSelectedData(); std::vector<TREEPROJECT_ITEM*> tree_data = GetSelectedData();
if( !tree_data ) if( tree_data.size() != 1 )
return; return;
wxString prj_filename = tree_data->GetFileName(); wxString prj_filename = tree_data[0]->GetFileName();
m_Parent->LoadProject( prj_filename ); m_Parent->LoadProject( prj_filename );
} }
@ -186,13 +185,12 @@ void TREE_PROJECT_FRAME::OnSwitchToSelectedProject( wxCommandEvent& event )
void TREE_PROJECT_FRAME::OnOpenDirectory( wxCommandEvent& event ) void TREE_PROJECT_FRAME::OnOpenDirectory( wxCommandEvent& event )
{ {
// Get the root directory name: // Get the root directory name:
TREEPROJECT_ITEM* treeData = GetSelectedData(); std::vector<TREEPROJECT_ITEM*> tree_data = GetSelectedData();
if( !treeData )
return;
for( TREEPROJECT_ITEM* item_data : tree_data )
{
// Ask for the new sub directory name // Ask for the new sub directory name
wxString curr_dir = treeData->GetDir(); wxString curr_dir = item_data->GetDir();
if( curr_dir.IsEmpty() ) if( curr_dir.IsEmpty() )
{ {
@ -220,21 +218,21 @@ void TREE_PROJECT_FRAME::OnOpenDirectory( wxCommandEvent& event )
wxLaunchDefaultApplication( curr_dir ); wxLaunchDefaultApplication( curr_dir );
#endif #endif
}
} }
void TREE_PROJECT_FRAME::OnCreateNewDirectory( wxCommandEvent& event ) void TREE_PROJECT_FRAME::OnCreateNewDirectory( wxCommandEvent& event )
{ {
// Get the root directory name: // Get the root directory name:
TREEPROJECT_ITEM* treeData = GetSelectedData(); std::vector<TREEPROJECT_ITEM*> tree_data = GetSelectedData();
if( !treeData )
return;
for( TREEPROJECT_ITEM* item_data : tree_data )
{
wxString prj_dir = wxPathOnly( m_Parent->GetProjectFileName() ); wxString prj_dir = wxPathOnly( m_Parent->GetProjectFileName() );
// Ask for the new sub directory name // Ask for the new sub directory name
wxString curr_dir = treeData->GetDir(); wxString curr_dir = item_data->GetDir();
if( !curr_dir.IsEmpty() ) // A subdir is selected if( !curr_dir.IsEmpty() ) // A subdir is selected
{ {
@ -249,7 +247,8 @@ void TREE_PROJECT_FRAME::OnCreateNewDirectory( wxCommandEvent& event )
curr_dir += wxFileName::GetPathSeparator(); curr_dir += wxFileName::GetPathSeparator();
} }
wxString msg = wxString::Format( _( "Current project directory:\n%s" ), GetChars( prj_dir ) ); wxString msg =
wxString::Format( _( "Current project directory:\n%s" ), GetChars( prj_dir ) );
wxString subdir = wxGetTextFromUser( msg, _( "Create New Directory" ), curr_dir ); wxString subdir = wxGetTextFromUser( msg, _( "Create New Directory" ), curr_dir );
if( subdir.IsEmpty() ) if( subdir.IsEmpty() )
@ -259,6 +258,7 @@ void TREE_PROJECT_FRAME::OnCreateNewDirectory( wxCommandEvent& event )
// Make the new item and let the file watcher add it to the tree // Make the new item and let the file watcher add it to the tree
wxMkdir( full_dirname ); wxMkdir( full_dirname );
}
} }
@ -536,155 +536,211 @@ void TREE_PROJECT_FRAME::ReCreateTreePrj()
void TREE_PROJECT_FRAME::OnRight( wxTreeEvent& Event ) void TREE_PROJECT_FRAME::OnRight( wxTreeEvent& Event )
{ {
int tree_id;
TREEPROJECT_ITEM* tree_data;
wxString fullFileName;
wxTreeItemId curr_item = Event.GetItem(); wxTreeItemId curr_item = Event.GetItem();
// Ensure item is selected (Under Windows right click does not select the item) // Ensure item is selected (Under Windows right click does not select the item)
m_TreeProject->SelectItem( curr_item ); m_TreeProject->SelectItem( curr_item );
tree_data = GetSelectedData(); std::vector<TREEPROJECT_ITEM*> tree_data = GetSelectedData();
if( !tree_data ) bool can_switch_to_project = true;
bool can_create_new_directory = true;
bool can_open_this_directory = true;
bool can_edit = true;
bool can_rename = true;
bool can_delete = true;
bool can_print = true;
if( tree_data.size() == 0 )
return; return;
tree_id = tree_data->GetType(); if( tree_data.size() != 1 )
fullFileName = tree_data->GetFileName(); {
can_switch_to_project = false;
can_create_new_directory = false;
can_rename = false;
can_print = false;
}
wxMenu popupMenu; if( curr_item == m_TreeProject->GetRootItem() )
can_switch_to_project = false;
for( TREEPROJECT_ITEM* item_data : tree_data )
{
int tree_id = item_data->GetType();
wxString full_file_name = item_data->GetFileName();
switch( tree_id ) switch( tree_id )
{ {
case TREE_PROJECT: case TREE_PROJECT:
// Add a swith to an other project option only if the selected item can_edit = false;
// is not the root item (current project) can_rename = false;
if( curr_item != m_TreeProject->GetRootItem() ) can_delete = false;
{ can_print = false;
AddMenuItem( &popupMenu, ID_PROJECT_SWITCH_TO_OTHER, break;
_( "&Switch to this Project" ), case TREE_DIRECTORY:
_( "Close all editors, and switch to the selected project" ), can_switch_to_project = false;
KiBitmap( open_project_xpm ) ); can_edit = false;
popupMenu.AppendSeparator(); can_rename = false;
can_print = false;
break;
default:
can_switch_to_project = false;
can_create_new_directory = false;
can_open_this_directory = false;
if( !CanPrintFile( full_file_name ) )
can_print = false;
break;
}
} }
AddMenuItem( &popupMenu, ID_PROJECT_NEWDIR, wxMenu popup_menu;
_( "New D&irectory..." ), wxString text;
_( "Create a New Directory" ), wxString help_text;
KiBitmap( directory_xpm ) );
AddMenuItem( &popupMenu, ID_PROJECT_OPEN_DIR, if( can_switch_to_project )
#ifdef __APPLE__
_( "Reveal in Finder" ),
_( "Reveals the directory in a Finder window" ),
#else
_( "&Open Directory in File Explorer" ),
_( "Opens the directory in the default system file manager" ),
#endif
KiBitmap( directory_browser_xpm ) );
break;
case TREE_DIRECTORY:
AddMenuItem( &popupMenu, ID_PROJECT_NEWDIR,
_( "New D&irectory..." ),
_( "Create a New Directory" ),
KiBitmap( directory_xpm ) );
AddMenuItem( &popupMenu, ID_PROJECT_OPEN_DIR,
#ifdef __APPLE__
_( "Reveal in Finder" ),
_( "Reveals the directory in a Finder window" ),
#else
_( "&Open Directory in File Explorer" ),
_( "Opens the directory in the default system file manager" ),
#endif
KiBitmap( directory_browser_xpm ) );
popupMenu.AppendSeparator();
AddMenuItem( &popupMenu, ID_PROJECT_DELETE,
_( "&Delete Directory" ),
_( "Delete the Directory and its content" ),
KiBitmap( delete_xpm ) );
break;
default:
AddMenuItem( &popupMenu, ID_PROJECT_TXTEDIT,
_( "&Edit in a Text Editor" ),
_( "Open the file in a Text Editor" ),
KiBitmap( editor_xpm ) );
AddMenuItem( &popupMenu, ID_PROJECT_RENAME,
_( "&Rename File..." ),
_( "Rename file" ),
KiBitmap( right_xpm ) );
popupMenu.AppendSeparator();
AddMenuItem( &popupMenu, ID_PROJECT_DELETE,
_( "&Delete File" ),
_( "Delete the file and its content" ),
KiBitmap( delete_xpm ) );
if( CanPrintFile( fullFileName ) )
{ {
popupMenu.AppendSeparator(); AddMenuItem( &popup_menu, ID_PROJECT_SWITCH_TO_OTHER, _( "&Switch to this Project" ),
AddMenuItem( &popupMenu, ID_PROJECT_PRINT, _( "Close all editors, and switch to the selected project" ),
KiBitmap( open_project_xpm ) );
popup_menu.AppendSeparator();
}
if( can_create_new_directory )
{
AddMenuItem( &popup_menu, ID_PROJECT_NEWDIR, _( "New D&irectory..." ),
_( "Create a New Directory" ), KiBitmap( directory_xpm ) );
}
if( can_open_this_directory )
{
if( tree_data.size() == 1 )
{
#ifdef __APPLE__
text = _( "Reveal in Finder" );
help_text = _( "Reveals the directory in a Finder window" );
#else
text = _( "&Open Directory in File Explorer" );
help_text = _( "Opens the directory in the default system file manager" );
#endif
}
else
{
#ifdef __APPLE__
text = _( "Reveal in Finder" );
help_text = _( "Reveals the directories in a Finder window" );
#else
text = _( "&Open Directories in File Explorer" );
help_text = _( "Opens the directories in the default system file manager" );
#endif
}
AddMenuItem( &popup_menu, ID_PROJECT_OPEN_DIR, text, help_text,
KiBitmap( directory_browser_xpm ) );
}
if( can_edit )
{
if( tree_data.size() == 1 )
help_text = _( "Open the file in a Text Editor" );
else
help_text = _( "Open the files in a Text Editor" );
AddMenuItem( &popup_menu, ID_PROJECT_TXTEDIT, _( "&Edit in a Text Editor" ), help_text,
KiBitmap( editor_xpm ) );
}
if( can_rename )
{
if( tree_data.size() == 1 )
{
text = _( "&Rename File..." );
help_text = _( "Rename file" );
}
else
{
text = _( "&Rename Files..." );
help_text = _( "Rename files" );
}
AddMenuItem( &popup_menu, ID_PROJECT_RENAME, text, help_text, KiBitmap( right_xpm ) );
}
if( can_delete )
{
if( tree_data.size() == 1 )
help_text = _( "Delete the file and its content" );
else
help_text = _( "Delete the files and their contents" );
if( can_switch_to_project || can_create_new_directory || can_open_this_directory || can_edit
|| can_rename )
popup_menu.AppendSeparator();
AddMenuItem(
&popup_menu, ID_PROJECT_DELETE, _( "&Delete" ), help_text, KiBitmap( delete_xpm ) );
}
if( can_print )
{
popup_menu.AppendSeparator();
AddMenuItem( &popup_menu, ID_PROJECT_PRINT,
#ifdef __APPLE__ #ifdef __APPLE__
_( "Print..." ), _( "Print..." ),
#else #else
_( "&Print" ), _( "&Print" ),
#endif #endif
_( "Print the contents of the file" ), _( "Print the contents of the file" ), KiBitmap( print_button_xpm ) );
KiBitmap( print_button_xpm ) );
}
break;
} }
PopupMenu( &popupMenu ); PopupMenu( &popup_menu );
} }
void TREE_PROJECT_FRAME::OnOpenSelectedFileWithTextEditor( wxCommandEvent& event ) void TREE_PROJECT_FRAME::OnOpenSelectedFileWithTextEditor( wxCommandEvent& event )
{ {
TREEPROJECT_ITEM* tree_data = GetSelectedData(); std::vector<TREEPROJECT_ITEM*> tree_data = GetSelectedData();
if( !tree_data || tree_data->GetType() == TREE_DIRECTORY ) for( TREEPROJECT_ITEM* item_data : tree_data )
return; {
wxString fullFileName = item_data->GetFileName();
wxString fullFileName = tree_data->GetFileName();
AddDelimiterString( fullFileName ); AddDelimiterString( fullFileName );
wxString editorname = Pgm().GetEditorName(); wxString editorname = Pgm().GetEditorName();
if( !editorname.IsEmpty() ) if( !editorname.IsEmpty() )
ExecuteFile( this, editorname, fullFileName ); ExecuteFile( this, editorname, fullFileName );
}
} }
void TREE_PROJECT_FRAME::OnDeleteFile( wxCommandEvent& ) void TREE_PROJECT_FRAME::OnDeleteFile( wxCommandEvent& )
{ {
TREEPROJECT_ITEM* tree_data = GetSelectedData(); std::vector<TREEPROJECT_ITEM*> tree_data = GetSelectedData();
if( tree_data ) for( TREEPROJECT_ITEM* item_data : tree_data )
tree_data->Delete(); item_data->Delete();
} }
void TREE_PROJECT_FRAME::OnPrintFile( wxCommandEvent& ) void TREE_PROJECT_FRAME::OnPrintFile( wxCommandEvent& )
{ {
TREEPROJECT_ITEM* tree_data = GetSelectedData(); std::vector<TREEPROJECT_ITEM*> tree_data = GetSelectedData();
if( tree_data ) for( TREEPROJECT_ITEM* item_data : tree_data )
tree_data->Print(); item_data->Print();
} }
void TREE_PROJECT_FRAME::OnRenameFile( wxCommandEvent& ) void TREE_PROJECT_FRAME::OnRenameFile( wxCommandEvent& )
{ {
wxTreeItemId curr_item = m_TreeProject->GetSelection(); wxTreeItemId curr_item = m_TreeProject->GetFocusedItem();
TREEPROJECT_ITEM* tree_data = GetSelectedData(); std::vector<TREEPROJECT_ITEM*> tree_data = GetSelectedData();
if( !tree_data ) // XXX: Unnecessary?
if( tree_data.size() != 1 )
return; return;
wxString buffer = m_TreeProject->GetItemText( curr_item ); wxString buffer = m_TreeProject->GetItemText( curr_item );
wxString msg = wxString::Format( _( "Change filename: \"%s\"" ), tree_data->GetFileName() ); wxString msg = wxString::Format( _( "Change filename: \"%s\"" ), tree_data[0]->GetFileName() );
wxTextEntryDialog dlg( this, msg, _( "Change filename" ), buffer ); wxTextEntryDialog dlg( this, msg, _( "Change filename" ), buffer );
if( dlg.ShowModal() != wxID_OK ) if( dlg.ShowModal() != wxID_OK )
@ -697,19 +753,19 @@ void TREE_PROJECT_FRAME::OnRenameFile( wxCommandEvent& )
if( buffer.IsEmpty() ) if( buffer.IsEmpty() )
return; // empty file name not allowed return; // empty file name not allowed
tree_data->Rename( buffer, true ); tree_data[0]->Rename( buffer, true );
m_isRenaming = true; m_isRenaming = true;
} }
void TREE_PROJECT_FRAME::OnSelect( wxTreeEvent& Event ) void TREE_PROJECT_FRAME::OnSelect( wxTreeEvent& Event )
{ {
TREEPROJECT_ITEM* selected_item = GetSelectedData(); std::vector<TREEPROJECT_ITEM*> tree_data = GetSelectedData();
if( !selected_item ) if( tree_data.size() != 1 )
return; return;
selected_item->Activate( this ); tree_data[0]->Activate( this );
} }
@ -775,9 +831,17 @@ void TREE_PROJECT_FRAME::OnExpand( wxTreeEvent& Event )
} }
TREEPROJECT_ITEM* TREE_PROJECT_FRAME::GetSelectedData() std::vector<TREEPROJECT_ITEM*> TREE_PROJECT_FRAME::GetSelectedData()
{ {
return GetItemIdData( m_TreeProject->GetSelection() ); wxArrayTreeItemIds selection;
std::vector<TREEPROJECT_ITEM*> data;
m_TreeProject->GetSelections( selection );
for( auto it = selection.begin(); it != selection.end(); it++ )
data.push_back( GetItemIdData( *it ) );
return data;
} }
@ -818,7 +882,7 @@ wxTreeItemId TREE_PROJECT_FRAME::findSubdirTreeItem( const wxString& aSubDir )
subdirs_id.pop(); subdirs_id.pop();
kid = m_TreeProject->GetFirstChild( root_id, cookie ); kid = m_TreeProject->GetFirstChild( root_id, cookie );
if( !kid.IsOk() ) if( ! kid.IsOk() )
continue; continue;
} }
} }

View File

@ -83,13 +83,13 @@ protected:
* Note this is not necessary the "clicked" item, * Note this is not necessary the "clicked" item,
* because when expanding, collapsing an item this item is not selected * because when expanding, collapsing an item this item is not selected
*/ */
TREEPROJECT_ITEM* GetSelectedData(); std::vector<TREEPROJECT_ITEM*> GetSelectedData();
/** /**
* Function GetItemIdData * Function GetItemIdData
* return the item data corresponding to a wxTreeItemId identifier * return the item data corresponding to a wxTreeItemId identifier
* @param aId = the wxTreeItemId identifier. * @param aId = the wxTreeItemId identifier.
* @return a TREEPROJECT_ITEM pointer correspondinfg to item id aId * @return a TREEPROJECT_ITEM pointer corresponding to item id aId
*/ */
TREEPROJECT_ITEM* GetItemIdData( wxTreeItemId aId ); TREEPROJECT_ITEM* GetItemIdData( wxTreeItemId aId );

View File

@ -39,11 +39,9 @@
IMPLEMENT_ABSTRACT_CLASS( TREEPROJECTFILES, wxTreeCtrl ) IMPLEMENT_ABSTRACT_CLASS( TREEPROJECTFILES, wxTreeCtrl )
TREEPROJECTFILES::TREEPROJECTFILES( TREE_PROJECT_FRAME* parent ) : TREEPROJECTFILES::TREEPROJECTFILES( TREE_PROJECT_FRAME* parent )
wxTreeCtrl( parent, ID_PROJECT_TREE, : wxTreeCtrl( parent, ID_PROJECT_TREE, wxDefaultPosition, wxDefaultSize,
wxDefaultPosition, wxDefaultSize, wxTR_HAS_BUTTONS | wxTR_MULTIPLE, wxDefaultValidator, wxT( "EDATreeCtrl" ) )
wxTR_HAS_BUTTONS, wxDefaultValidator,
wxT( "EDATreeCtrl" ) )
{ {
m_Parent = parent; m_Parent = parent;