29#include <wx/stdpaths.h>
32#include <wx/textdlg.h>
45#include <wx/dcclient.h>
46#include <wx/settings.h>
72 wxT(
"^.*\\.kicad_pro$" ),
75 wxT(
"^.*\\.kicad_sch$" ),
76 wxT(
"^[^$].*\\.brd$" ),
77 wxT(
"^[^$].*\\.kicad_pcb$" ),
78 wxT(
"^[^$].*\\.kicad_dru$" ),
79 wxT(
"^[^$].*\\.kicad_wks$" ),
80 wxT(
"^[^$].*\\.kicad_mod$" ),
84 wxT(
"^.*\\.kicad_sym$" ),
89 wxT(
"^.*\\.gbrjob$" ),
90 wxT(
"^.*\\.gb[alops]$" ),
91 wxT(
"^.*\\.gt[alops]$" ),
92 wxT(
"^.*\\.g[0-9]{1,2}$" ),
93 wxT(
"^.*\\.gm[0-9]{1,2}$" ),
135 wxSashLayoutWindow( parent,
ID_LEFT_FRAME, wxDefaultPosition, wxDefaultSize,
136 wxNO_BORDER | wxTAB_TRAVERSAL )
139 m_TreeProject =
nullptr;
140 m_isRenaming =
false;
141 m_selectedItem =
nullptr;
142 m_watcherNeedReset =
false;
145 Connect( wxEVT_FSWATCHER,
148 Bind( wxEVT_SYS_COLOUR_CHANGED,
158 m_filters.emplace_back( wxT(
"^no KiCad files found" ) );
186 if( tree_data.size() != 1 )
189 wxString prj_filename = tree_data[0]->GetFileName();
203 wxString curr_dir = item_data->GetDir();
205 if( curr_dir.IsEmpty() )
211 if( curr_dir.IsEmpty() || !wxFileName::DirExists( curr_dir ) )
214 if( !curr_dir.IsEmpty() )
215 curr_dir += wxFileName::GetPathSeparator();
233 wxString curr_dir = item_data->GetDir();
235 if( curr_dir.IsEmpty() )
238 wxString new_dir = wxGetTextFromUser(
_(
"Directory name:" ),
_(
"Create New Directory" ) );
240 if( new_dir.IsEmpty() )
243 wxString full_dirname = curr_dir + wxFileName::GetPathSeparator() + new_dir;
245 wxMkdir( full_dirname );
272 case TREE_FILE_TYPE::DRILL_NC:
return "nc";
273 case TREE_FILE_TYPE::DRILL_XNC:
return "xnc";
281 default:
return wxEmptyString;
288 std::vector<wxString> projects;
289 wxString dir_filename;
290 bool haveFile = dir.GetFirst( &dir_filename );
294 wxFileName file( dir_filename );
297 projects.push_back( file.GetName() );
299 haveFile = dir.GetNext( &dir_filename );
307 const wxTreeItemId& aParent,
308 std::vector<wxString>* aProjectNames,
312 wxFileName fn( aName );
316 if( fn.GetName().StartsWith( wxT(
"." ) ) )
317 return wxTreeItemId();
319 if( wxDirExists( aName ) )
321 type = TREE_FILE_TYPE::DIRECTORY;
327 bool addFile =
false;
329 for(
const wxString& m_filter :
m_filters )
331 wxCHECK2_MSG( reg.Compile( m_filter, wxRE_ICASE ),
continue,
332 wxString::Format(
"Regex %s failed to compile.", m_filter ) );
334 if( reg.Matches( aName ) )
342 return wxTreeItemId();
344 for(
int i =
static_cast<int>( TREE_FILE_TYPE::LEGACY_PROJECT );
345 i < static_cast<int>( TREE_FILE_TYPE::MAX ); i++ )
349 if( ext == wxT(
"" ) )
352 reg.Compile( wxString::FromAscii(
"^.*\\." ) + ext + wxString::FromAscii(
"$" ),
355 if( reg.Matches( aName ) )
363 wxString file = wxFileNameFromPath( aName );
364 wxFileName currfile( file );
368 if( ( type == TREE_FILE_TYPE::LEGACY_PROJECT )
369 && ( currfile.GetName().CmpNoCase(
project.GetName() ) == 0 ) )
371 return wxTreeItemId();
374 if( currfile.GetExt() ==
GetFileExt( TREE_FILE_TYPE::LEGACY_SCHEMATIC )
375 || currfile.GetExt() ==
GetFileExt( TREE_FILE_TYPE::SEXPR_SCHEMATIC ) )
380 return wxTreeItemId();
385 wxDir parentDir( parentTreeItem->
GetDir() );
386 std::vector<wxString> projects =
getProjects( parentDir );
389 return wxTreeItemId();
394 wxTreeItemIdValue cookie;
395 wxTreeItemId kid =
m_TreeProject->GetFirstChild( aParent, cookie );
402 return itemData->GetId();
408 if( type == TREE_FILE_TYPE::LEGACY_PROJECT || type == TREE_FILE_TYPE::JSON_PROJECT
409 || type == TREE_FILE_TYPE::LEGACY_SCHEMATIC || type == TREE_FILE_TYPE::SEXPR_SCHEMATIC )
421 if( fname.GetName().CmpNoCase( currfile.GetName() ) == 0 )
425 case TREE_FILE_TYPE::LEGACY_PROJECT:
426 if( itemData->
GetType() == TREE_FILE_TYPE::JSON_PROJECT )
427 return wxTreeItemId();
431 case TREE_FILE_TYPE::LEGACY_SCHEMATIC:
432 if( itemData->
GetType() == TREE_FILE_TYPE::SEXPR_SCHEMATIC )
433 return wxTreeItemId();
437 case TREE_FILE_TYPE::JSON_PROJECT:
438 if( itemData->
GetType() == TREE_FILE_TYPE::LEGACY_PROJECT )
443 case TREE_FILE_TYPE::SEXPR_SCHEMATIC:
444 if( itemData->
GetType() == TREE_FILE_TYPE::LEGACY_SCHEMATIC )
460 wxTreeItemId newItemId =
m_TreeProject->AppendItem( aParent, file );
467 wxString fileName = currfile.GetName().Lower();
468 wxString projName =
project.GetName().Lower();
469 data->
SetRootFile( fileName == projName || fileName.StartsWith( projName +
"-" ) );
472 bool subdir_populated =
false;
477 if( TREE_FILE_TYPE::DIRECTORY == type && aRecurse )
483 std::vector<wxString> projects =
getProjects( dir );
484 wxString dir_filename;
485 bool haveFile = dir.GetFirst( &dir_filename );
490 subdir_populated = aRecurse;
496 wxString
path = aName + wxFileName::GetPathSeparator() + dir_filename;
499 haveFile = dir.GetNext( &dir_filename );
508 if( subdir_populated )
528 wxFileName fn = pro_dir;
529 bool prjReset =
false;
540 bool prjOpened = fn.FileExists();
544 if( !prjOpened && !prjReset )
547 prjOpened = fn.FileExists();
554 m_root =
m_TreeProject->AddRoot( fn.GetFullName(),
static_cast<int>( TREE_FILE_TYPE::ROOT ),
555 static_cast<int>( TREE_FILE_TYPE::ROOT ) );
566 wxDir dir( pro_dir );
570 std::vector<wxString> projects =
getProjects( dir );
572 bool haveFile = dir.GetFirst( &filename );
576 if( filename != fn.GetFullName() )
578 wxString
name = dir.GetName() + wxFileName::GetPathSeparator() + filename;
584 haveFile = dir.GetNext( &filename );
602 wxTreeItemId curr_item = Event.GetItem();
609 bool can_switch_to_project =
true;
610 bool can_create_new_directory =
true;
611 bool can_open_this_directory =
true;
612 bool can_edit =
true;
613 bool can_rename =
true;
614 bool can_delete =
true;
616 if( selection.size() == 0 )
620 if( selection.size() != 1 )
622 can_switch_to_project =
false;
623 can_create_new_directory =
false;
632 can_switch_to_project =
false;
638 can_delete = item->CanDelete();
639 can_rename = item->CanRename();
641 switch( item->GetType() )
643 case TREE_FILE_TYPE::LEGACY_PROJECT:
644 case TREE_FILE_TYPE::JSON_PROJECT:
649 can_switch_to_project =
false;
653 can_create_new_directory =
false;
654 can_open_this_directory =
false;
658 case TREE_FILE_TYPE::DIRECTORY:
659 can_switch_to_project =
false;
664 can_switch_to_project =
false;
665 can_create_new_directory =
false;
666 can_open_this_directory =
false;
676 if( can_switch_to_project )
679 _(
"Switch to this Project" ),
680 _(
"Close all editors, and switch to the selected project" ),
681 KiBitmap( BITMAPS::open_project ) );
682 popup_menu.AppendSeparator();
685 if( can_create_new_directory )
688 _(
"Create a New Directory" ),
KiBitmap( BITMAPS::directory ) );
691 if( can_open_this_directory )
693 if( selection.size() == 1 )
696 text =
_(
"Reveal in Finder" );
697 help_text =
_(
"Reveals the directory in a Finder window" );
699 text =
_(
"Open Directory in File Explorer" );
700 help_text =
_(
"Opens the directory in the default system file manager" );
706 text =
_(
"Reveal in Finder" );
707 help_text =
_(
"Reveals the directories in a Finder window" );
709 text =
_(
"Open Directories in File Explorer" );
710 help_text =
_(
"Opens the directories in the default system file manager" );
715 KiBitmap( BITMAPS::directory_browser ) );
720 if( selection.size() == 1 )
721 help_text =
_(
"Open the file in a Text Editor" );
723 help_text =
_(
"Open files in a Text Editor" );
726 help_text,
KiBitmap( BITMAPS::editor ) );
731 if( selection.size() == 1 )
733 text =
_(
"Rename File..." );
734 help_text =
_(
"Rename file" );
738 text =
_(
"Rename Files..." );
739 help_text =
_(
"Rename files" );
747 if( selection.size() == 1 )
748 help_text =
_(
"Delete the file and its content" );
750 help_text =
_(
"Delete the files and their contents" );
752 if( can_switch_to_project
753 || can_create_new_directory
754 || can_open_this_directory
758 popup_menu.AppendSeparator();
770 if( popup_menu.GetMenuItemCount() > 0 )
771 PopupMenu( &popup_menu );
777 wxString editorname =
Pgm().GetTextEditor();
779 if( editorname.IsEmpty() )
781 wxMessageBox(
_(
"No text editor selected in KiCad. Please choose one." ) );
790 wxString fullFileName = item_data->GetFileName();
792 if( !files.IsEmpty() )
795 files += fullFileName;
817 if( tree_data.size() != 1 )
821 wxString msg = wxString::Format(
_(
"Change filename: '%s'" ),
822 tree_data[0]->GetFileName() );
823 wxTextEntryDialog dlg(
this, msg,
_(
"Change filename" ), buffer );
825 if( dlg.ShowModal() != wxID_OK )
828 buffer = dlg.GetValue();
830 buffer.Trim(
false );
832 if( buffer.IsEmpty() )
835 tree_data[0]->Rename( buffer,
true );
844 if( tree_data.size() != 1 )
878 wxTreeItemId itemId = Event.GetItem();
884 if( tree_data->
GetType() != TREE_FILE_TYPE::DIRECTORY )
888 wxTreeItemIdValue cookie;
889 wxTreeItemId kid =
m_TreeProject->GetFirstChild( itemId, cookie );
892 bool subdir_populated =
false;
895 for( ; kid.IsOk(); kid =
m_TreeProject->GetNextChild( itemId, cookie ) )
899 if( !itemData || itemData->
GetType() != TREE_FILE_TYPE::DIRECTORY )
906 wxDir dir( fileName );
910 std::vector<wxString> projects =
getProjects( dir );
911 wxString dir_filename;
912 bool haveFile = dir.GetFirst( &dir_filename );
917 wxString
name = fileName + wxFileName::GetPathSeparator() + dir_filename;
920 haveFile = dir.GetNext( &dir_filename );
926 subdir_populated =
true;
935 if( subdir_populated )
943 wxArrayTreeItemIds selection;
944 std::vector<PROJECT_TREE_ITEM*> data;
948 for(
auto it = selection.begin(); it != selection.end(); it++ )
953 wxLogDebug(
"Null tree item returned for selection, dynamic_cast failed?" );
957 data.push_back( item );
976 if( prj_dir == aSubDir )
980 wxTreeItemIdValue cookie;
981 wxTreeItemId root_id =
m_root;
982 std::stack<wxTreeItemId> subdirs_id;
984 wxTreeItemId child =
m_TreeProject->GetFirstChild( root_id, cookie );
990 if( subdirs_id.empty() )
997 root_id = subdirs_id.top();
1008 if( itemData && ( itemData->
GetType() == TREE_FILE_TYPE::DIRECTORY ) )
1018 subdirs_id.push( child );
1034 const wxFileName& pathModified =
event.GetPath();
1035 wxString subdir = pathModified.GetPath();
1036 wxString fn = pathModified.GetFullPath();
1038 switch( event.GetChangeType() )
1040 case wxFSW_EVENT_DELETE:
1041 case wxFSW_EVENT_CREATE:
1042 case wxFSW_EVENT_RENAME:
1045 case wxFSW_EVENT_MODIFY:
1046 case wxFSW_EVENT_ACCESS:
1053 if( !root_id.IsOk() )
1056 wxTreeItemIdValue cookie;
1057 wxTreeItemId kid =
m_TreeProject->GetFirstChild( root_id, cookie );
1059 switch( event.GetChangeType() )
1061 case wxFSW_EVENT_CREATE:
1063 wxTreeItemId newitem =
1077 case wxFSW_EVENT_DELETE:
1091 case wxFSW_EVENT_RENAME :
1093 const wxFileName& newpath =
event.GetNewPath();
1094 wxString newdir = newpath.GetPath();
1095 wxString newfn = newpath.GetFullPath();
1119 if( rootData && newpath.Exists() && ( newfn != rootData->
GetFileName() ) )
1125 if( newitem.IsOk() )
1145#if defined( _WIN32 )
1152 m_Parent->SetStatusText(
_(
"Network path: not monitoring folder changes" ), 1 );
1157 m_Parent->SetStatusText(
_(
"Local path: monitoring folder changes" ), 1 );
1174 fn.AssignDir( prj_dir );
1175 fn.DontFollowLink();
1192 wxTreeItemIdValue cookie;
1193 wxTreeItemId root_id =
m_root;
1195 std::stack < wxTreeItemId > subdirs_id;
1197 wxTreeItemId kid =
m_TreeProject->GetFirstChild( root_id, cookie );
1203 if( subdirs_id.empty() )
1209 root_id = subdirs_id.top();
1220 if( itemData && itemData->
GetType() == TREE_FILE_TYPE::DIRECTORY )
1227 if( wxFileName::IsDirReadable(
path ) )
1229 fn.AssignDir(
path );
1234 subdirs_id.push( kid );
1242#if defined(DEBUG) && 1
1243 wxArrayString paths;
1247 for(
unsigned ii = 0; ii < paths.GetCount(); ii++ )
1274 wxRect rect( wxPoint( 0, 0 ), GetClientSize() );
1275 wxPaintDC dc(
this );
1277 dc.SetBrush( wxSystemSettings::GetColour( wxSYS_COLOUR_FRAMEBK ) );
1278 dc.SetPen( wxPen( wxSystemSettings::GetColour( wxSYS_COLOUR_ACTIVEBORDER ), 1 ) );
1280 dc.DrawLine( rect.GetLeft(), rect.GetTop(), rect.GetLeft(), rect.GetBottom() );
1281 dc.DrawLine( rect.GetRight(), rect.GetTop(), rect.GetRight(), rect.GetBottom() );
wxBitmap KiBitmap(BITMAPS aBitmap, int aHeightTag)
Construct a wxBitmap from an image identifier Returns the image from the active theme if the image ha...
wxMenuItem * AddMenuItem(wxMenu *aMenu, int aId, const wxString &aText, const wxBitmap &aImage, wxItemKind aType=wxITEM_NORMAL)
Create and insert a menu item with an icon into aMenu.
BITMAP_STORE * GetBitmapStore()
void ThemeChanged()
Notifies the store that the icon theme has been changed by the user, so caches must be invalidated.
The main KiCad project manager frame.
PROJECT_TREE_PANE * m_leftWin
const wxString GetProjectFileName() const
void OnChangeWatchedPaths(wxCommandEvent &aEvent)
Called by sending a event with id = ID_INIT_WATCHED_PATHS rebuild the list of watched paths.
void LoadProject(const wxFileName &aProjectFileName)
static wxString GetDefaultUserProjectsPath()
Gets the default path we point users to create projects.
Handle one item (a file or a directory name) for the tree file.
void SetRootFile(bool aValue)
const wxString & GetFileName() const
void SetPopulated(bool aValue)
TREE_FILE_TYPE GetType() const
const wxString GetDir() const
void Activate(PROJECT_TREE_PANE *aTreePrjFrame)
PROJECT_TREE_PANE Window to display the tree files.
PROJECT_TREE_ITEM * m_selectedItem
void onDeleteFile(wxCommandEvent &event)
Function onDeleteFile Delete the selected file or directory in the tree project.
void EmptyTreePrj()
Delete all m_TreeProject entries.
void FileWatcherReset()
Reinit the watched paths Should be called after opening a new project to rebuild the list of watched ...
std::vector< PROJECT_TREE_ITEM * > GetSelectedData()
Function GetSelectedData return the item data from item currently selected (highlighted) Note this is...
void onOpenDirectory(wxCommandEvent &event)
Function onOpenDirectory Handles the right-click menu for opening a directory in the current system f...
void onFileSystemEvent(wxFileSystemWatcherEvent &event)
called when a file or directory is modified/created/deleted The tree project is modified when a file ...
wxFileSystemWatcher * m_watcher
void onRight(wxTreeEvent &Event)
Called on a right click on an item.
void onSelect(wxTreeEvent &Event)
Called on a double click on an item.
PROJECT_TREE * m_TreeProject
KICAD_MANAGER_FRAME * m_Parent
void onExpand(wxTreeEvent &Event)
Called on a click on the + or - button of an item with children.
void onIdle(wxIdleEvent &aEvent)
Idle event handler, used process the selected items at a point in time when all other events have bee...
static wxString GetFileExt(TREE_FILE_TYPE type)
friend class PROJECT_TREE_ITEM
wxTreeItemId findSubdirTreeItem(const wxString &aSubDir)
Function findSubdirTreeItem searches for the item in tree project which is the node of the subdirecto...
void ReCreateTreePrj()
Create or modify the tree showing project file names.
void onThemeChanged(wxSysColourChangedEvent &aEvent)
void shutdownFileWatcher()
Shutdown the file watcher.
wxTreeItemId addItemToProjectTree(const wxString &aName, const wxTreeItemId &aParent, std::vector< wxString > *aProjectNames, bool aRecurse)
Function addItemToProjectTree.
void onOpenSelectedFileWithTextEditor(wxCommandEvent &event)
Function onOpenSelectedFileWithTextEditor Call the text editor to open the selected file in the tree ...
PROJECT_TREE_ITEM * GetItemIdData(wxTreeItemId aId)
Function GetItemIdData return the item data corresponding to a wxTreeItemId identifier.
void onCreateNewDirectory(wxCommandEvent &event)
Function onCreateNewDirectory Creates a new subdirectory inside the current kicad project directory t...
void onSwitchToSelectedProject(wxCommandEvent &event)
Switch to a other project selected from the tree project (by selecting an other .pro file inside the ...
void onPaint(wxPaintEvent &aEvent)
We don't have uniform borders so we have to draw them ourselves.
void onRenameFile(wxCommandEvent &event)
Function onRenameFile Rename the selected file or directory in the tree project.
std::vector< wxString > m_filters
PROJECT_TREE This is the class to show (as a tree) the files in the project directory.
int ExecuteFile(const wxString &aEditorName, const wxString &aFileName, wxProcess *aCallback)
Call the executable file aEditorName with the parameter aFileName.
const std::string LegacyPcbFileExtension
const std::string PdfFileExtension
const std::string KiCadSymbolLibFileExtension
const std::string LegacySchematicFileExtension
const std::string FootprintAssignmentFileExtension
const std::string FootprintPlaceFileExtension
const std::string GerberJobFileExtension
const std::string DrillFileExtension
const wxString GerberFileExtensionsRegex
const std::string KiCadFootprintFileExtension
const std::string LegacyProjectFileExtension
const std::string MarkdownFileExtension
const std::string KiCadPcbFileExtension
const std::string SVGFileExtension
const std::string TextFileExtension
const std::string ProjectFileExtension
const std::string NetlistFileExtension
const std::string DesignRulesFileExtension
const std::string HtmlFileExtension
const std::string KiCadSchematicFileExtension
const std::string ReportFileExtension
const std::string DrawingSheetFileExtension
const std::string ArchiveFileExtension
const std::string LegacySymbolLibFileExtension
const wxChar *const tracePathsAndFiles
Flag to enable path and file name debug output.
IDs used in KiCad main frame foe menuitems and tools.
@ ID_PROJECT_SWITCH_TO_OTHER
bool LaunchExternal(const wxString &aPath)
Launches the given file or folder in the host OS.
This file contains miscellaneous commonly used macros and functions.
#define TO_UTF8(wxstring)
Convert a wxString to a UTF8 encoded C string for all wxWidgets build modes.
bool contains(const _Container &__container, _Value __value)
Returns true if the container contains the given value.
#define NAMELESS_PROJECT
default name for nameless projects
std::vector< wxString > getProjects(const wxDir &dir)
static const wxChar * s_allowedExtensionsToList[]
KIWAY Kiway & Pgm(), KFCTL_STANDALONE
The global Program "get" accessor.
wxLogTrace helper definitions.
Definition of file extensions used in Kicad.