KiCad PCB EDA Suite
Loading...
Searching...
No Matches
project_tree_pane.cpp
Go to the documentation of this file.
1/*
2 * This program source code file is part of KiCad, a free EDA CAD application.
3 *
4 * Copyright (C) 2012 SoftPLC Corporation, Dick Hollenbeck <[email protected]>
5 * Copyright (C) 2012 Jean-Pierre Charras, jp.charras at wanadoo.fr
6 * Copyright (C) 1992-2021 KiCad Developers, see AUTHORS.txt for contributors.
7 *
8 * This program is free software; you can redistribute it and/or
9 * modify it under the terms of the GNU General Public License
10 * as published by the Free Software Foundation; either version 2
11 * of the License, or (at your option) any later version.
12 *
13 * This program is distributed in the hope that it will be useful,
14 * but WITHOUT ANY WARRANTY; without even the implied warranty of
15 * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
16 * GNU General Public License for more details.
17 *
18 * You should have received a copy of the GNU General Public License
19 * along with this program; if not, you may find one here:
20 * http://www.gnu.org/licenses/old-licenses/gpl-2.0.html
21 * or you may search the http://www.gnu.org website for the version 2 license,
22 * or you may write to the Free Software Foundation, Inc.,
23 * 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301, USA
24 */
25
26#include <stack>
27
28#include <wx/regex.h>
29#include <wx/stdpaths.h>
30#include <wx/string.h>
31#include <wx/msgdlg.h>
32#include <wx/textdlg.h>
33
34#include <bitmaps.h>
35#include <bitmap_store.h>
36#include <gestfich.h>
37#include <macros.h>
38#include <menus_helpers.h>
39#include <trace_helpers.h>
42#include <core/kicad_algo.h>
43#include <paths.h>
44#include <launch_ext.h>
45#include <wx/dcclient.h>
46#include <wx/settings.h>
47
48#include "project_tree_item.h"
49#include "project_tree.h"
50#include "pgm_kicad.h"
51#include "kicad_id.h"
52#include "kicad_manager_frame.h"
53
54#include "project_tree_pane.h"
55
56
57/* Note about the project tree build process:
58 * Building the project tree can be *very* long if there are a lot of subdirectories in the
59 * working directory. Unfortunately, this happens easily if the project file *.pro is in the
60 * user's home directory.
61 * So the tree project is built "on demand":
62 * First the tree is built from the current directory and shows files and subdirs.
63 * > First level subdirs trees are built (i.e subdirs contents are not read)
64 * > When expanding a subdir, each subdir contains is read, and the corresponding sub tree is
65 * populated on the fly.
66 */
67
68// list of files extensions listed in the tree project window
69// Add extensions in a compatible regex format to see others files types
70static const wxChar* s_allowedExtensionsToList[] = {
71 wxT( "^.*\\.pro$" ),
72 wxT( "^.*\\.kicad_pro$" ),
73 wxT( "^.*\\.pdf$" ),
74 wxT( "^.*\\.sch$" ), // Legacy Eeschema files
75 wxT( "^.*\\.kicad_sch$" ), // S-expr Eeschema files
76 wxT( "^[^$].*\\.brd$" ), // Legacy Pcbnew files
77 wxT( "^[^$].*\\.kicad_pcb$" ), // S format Pcbnew board files
78 wxT( "^[^$].*\\.kicad_dru$" ), // Design rule files
79 wxT( "^[^$].*\\.kicad_wks$" ), // S format kicad drawing sheet files
80 wxT( "^[^$].*\\.kicad_mod$" ), // S format kicad footprint files, currently not listed
81 wxT( "^.*\\.net$" ), // pcbnew netlist file
82 wxT( "^.*\\.cir$" ), // Spice netlist file
83 wxT( "^.*\\.lib$" ), // Legacy schematic library file
84 wxT( "^.*\\.kicad_sym$" ), // S-expr symbol libraries
85 wxT( "^.*\\.txt$" ), // Text files
86 wxT( "^.*\\.md$" ), // Markdown files
87 wxT( "^.*\\.pho$" ), // Gerber file (Old Kicad extension)
88 wxT( "^.*\\.gbr$" ), // Gerber file
89 wxT( "^.*\\.gbrjob$" ), // Gerber job file
90 wxT( "^.*\\.gb[alops]$" ), // Gerber back (or bottom) layer file (deprecated Protel ext)
91 wxT( "^.*\\.gt[alops]$" ), // Gerber front (or top) layer file (deprecated Protel ext)
92 wxT( "^.*\\.g[0-9]{1,2}$" ), // Gerber inner layer file (deprecated Protel ext)
93 wxT( "^.*\\.gm[0-9]{1,2}$" ), // Gerber mechanical layer file (deprecated Protel ext)
94 wxT( "^.*\\.gko$" ), // Gerber keepout layer file (deprecated Protel ext)
95 wxT( "^.*\\.odt$" ),
96 wxT( "^.*\\.htm$" ),
97 wxT( "^.*\\.html$" ),
98 wxT( "^.*\\.rpt$" ), // Report files
99 wxT( "^.*\\.csv$" ), // Report files in comma separated format
100 wxT( "^.*\\.pos$" ), // Footprint position files
101 wxT( "^.*\\.cmp$" ), // CvPcb cmp/footprint link files
102 wxT( "^.*\\.drl$" ), // Excellon drill files
103 wxT( "^.*\\.nc$" ), // Excellon NC drill files (alternate file ext)
104 wxT( "^.*\\.xnc$" ), // Excellon NC drill files (alternate file ext)
105 wxT( "^.*\\.svg$" ), // SVG print/plot files
106 wxT( "^.*\\.ps$" ), // PostScript plot files
107 wxT( "^.*\\.zip$" ), // Zip archive files
108 nullptr // end of list
109};
110
111
119BEGIN_EVENT_TABLE( PROJECT_TREE_PANE, wxSashLayoutWindow )
120 EVT_TREE_ITEM_ACTIVATED( ID_PROJECT_TREE, PROJECT_TREE_PANE::onSelect )
121 EVT_TREE_ITEM_EXPANDED( ID_PROJECT_TREE, PROJECT_TREE_PANE::onExpand )
122 EVT_TREE_ITEM_RIGHT_CLICK( ID_PROJECT_TREE, PROJECT_TREE_PANE::onRight )
129 EVT_IDLE( PROJECT_TREE_PANE::onIdle )
130 EVT_PAINT( PROJECT_TREE_PANE::onPaint )
131END_EVENT_TABLE()
132
133
135 wxSashLayoutWindow( parent, ID_LEFT_FRAME, wxDefaultPosition, wxDefaultSize,
136 wxNO_BORDER | wxTAB_TRAVERSAL )
137{
138 m_Parent = parent;
139 m_TreeProject = nullptr;
140 m_isRenaming = false;
141 m_selectedItem = nullptr;
142 m_watcherNeedReset = false;
143
144 m_watcher = nullptr;
145 Connect( wxEVT_FSWATCHER,
146 wxFileSystemWatcherEventHandler( PROJECT_TREE_PANE::onFileSystemEvent ) );
147
148 Bind( wxEVT_SYS_COLOUR_CHANGED,
149 wxSysColourChangedEventHandler( PROJECT_TREE_PANE::onThemeChanged ), this );
150
151 /*
152 * Filtering is now inverted: the filters are actually used to _enable_ support
153 * for a given file type.
154 */
155 for( int ii = 0; s_allowedExtensionsToList[ii] != nullptr; ii++ )
156 m_filters.emplace_back( s_allowedExtensionsToList[ii] );
157
158 m_filters.emplace_back( wxT( "^no KiCad files found" ) );
159
160 ReCreateTreePrj();
161}
162
163
165{
167}
168
169
171{
172 if( m_watcher )
173 {
174 m_watcher->RemoveAll();
175 m_watcher->SetOwner( nullptr );
176 delete m_watcher;
177 m_watcher = nullptr;
178 }
179}
180
181
183{
184 std::vector<PROJECT_TREE_ITEM*> tree_data = GetSelectedData();
185
186 if( tree_data.size() != 1 )
187 return;
188
189 wxString prj_filename = tree_data[0]->GetFileName();
190
191 m_Parent->LoadProject( prj_filename );
192}
193
194
195void PROJECT_TREE_PANE::onOpenDirectory( wxCommandEvent& event )
196{
197 // Get the root directory name:
198 std::vector<PROJECT_TREE_ITEM*> tree_data = GetSelectedData();
199
200 for( PROJECT_TREE_ITEM* item_data : tree_data )
201 {
202 // Ask for the new sub directory name
203 wxString curr_dir = item_data->GetDir();
204
205 if( curr_dir.IsEmpty() )
206 {
207 // Use project path if the tree view path was empty.
208 curr_dir = wxPathOnly( m_Parent->GetProjectFileName() );
209
210 // As a last resort use the user's documents folder.
211 if( curr_dir.IsEmpty() || !wxFileName::DirExists( curr_dir ) )
213
214 if( !curr_dir.IsEmpty() )
215 curr_dir += wxFileName::GetPathSeparator();
216 }
217
218 LaunchExternal( curr_dir );
219 }
220}
221
222
223void PROJECT_TREE_PANE::onCreateNewDirectory( wxCommandEvent& event )
224{
225 // Get the root directory name:
226 std::vector<PROJECT_TREE_ITEM*> tree_data = GetSelectedData();
227
228 for( PROJECT_TREE_ITEM* item_data : tree_data )
229 {
230 wxString prj_dir = wxPathOnly( m_Parent->GetProjectFileName() );
231
232 // Ask for the new sub directory name
233 wxString curr_dir = item_data->GetDir();
234
235 if( curr_dir.IsEmpty() )
236 curr_dir = prj_dir;
237
238 wxString new_dir = wxGetTextFromUser( _( "Directory name:" ), _( "Create New Directory" ) );
239
240 if( new_dir.IsEmpty() )
241 return;
242
243 wxString full_dirname = curr_dir + wxFileName::GetPathSeparator() + new_dir;
244
245 wxMkdir( full_dirname );
246 addItemToProjectTree( full_dirname, item_data->GetId(), nullptr, false );
247 }
248}
249
250
252{
253 switch( type )
254 {
255 case TREE_FILE_TYPE::LEGACY_PROJECT: return LegacyProjectFileExtension;
256 case TREE_FILE_TYPE::JSON_PROJECT: return ProjectFileExtension;
257 case TREE_FILE_TYPE::LEGACY_SCHEMATIC: return LegacySchematicFileExtension;
258 case TREE_FILE_TYPE::SEXPR_SCHEMATIC: return KiCadSchematicFileExtension;
259 case TREE_FILE_TYPE::LEGACY_PCB: return LegacyPcbFileExtension;
260 case TREE_FILE_TYPE::SEXPR_PCB: return KiCadPcbFileExtension;
261 case TREE_FILE_TYPE::GERBER: return GerberFileExtensionsRegex;
262 case TREE_FILE_TYPE::GERBER_JOB_FILE: return GerberJobFileExtension;
263 case TREE_FILE_TYPE::HTML: return HtmlFileExtension;
264 case TREE_FILE_TYPE::PDF: return PdfFileExtension;
265 case TREE_FILE_TYPE::TXT: return TextFileExtension;
266 case TREE_FILE_TYPE::MD: return MarkdownFileExtension;
267 case TREE_FILE_TYPE::NET: return NetlistFileExtension;
268 case TREE_FILE_TYPE::CMP_LINK: return FootprintAssignmentFileExtension;
269 case TREE_FILE_TYPE::REPORT: return ReportFileExtension;
270 case TREE_FILE_TYPE::FP_PLACE: return FootprintPlaceFileExtension;
271 case TREE_FILE_TYPE::DRILL: return DrillFileExtension;
272 case TREE_FILE_TYPE::DRILL_NC: return "nc";
273 case TREE_FILE_TYPE::DRILL_XNC: return "xnc";
274 case TREE_FILE_TYPE::SVG: return SVGFileExtension;
275 case TREE_FILE_TYPE::DRAWING_SHEET: return DrawingSheetFileExtension;
276 case TREE_FILE_TYPE::FOOTPRINT_FILE: return KiCadFootprintFileExtension;
277 case TREE_FILE_TYPE::SCHEMATIC_LIBFILE: return LegacySymbolLibFileExtension;
278 case TREE_FILE_TYPE::SEXPR_SYMBOL_LIB_FILE: return KiCadSymbolLibFileExtension;
279 case TREE_FILE_TYPE::DESIGN_RULES: return DesignRulesFileExtension;
280 case TREE_FILE_TYPE::ZIP_ARCHIVE: return ArchiveFileExtension;
281 default: return wxEmptyString;
282 }
283}
284
285
286std::vector<wxString> getProjects( const wxDir& dir )
287{
288 std::vector<wxString> projects;
289 wxString dir_filename;
290 bool haveFile = dir.GetFirst( &dir_filename );
291
292 while( haveFile )
293 {
294 wxFileName file( dir_filename );
295
296 if( file.GetExt() == LegacyProjectFileExtension || file.GetExt() == ProjectFileExtension )
297 projects.push_back( file.GetName() );
298
299 haveFile = dir.GetNext( &dir_filename );
300 }
301
302 return projects;
303}
304
305
306wxTreeItemId PROJECT_TREE_PANE::addItemToProjectTree( const wxString& aName,
307 const wxTreeItemId& aParent,
308 std::vector<wxString>* aProjectNames,
309 bool aRecurse )
310{
311 TREE_FILE_TYPE type = TREE_FILE_TYPE::UNKNOWN;
312 wxFileName fn( aName );
313
314 // Files/dirs names starting by "." are not visible files under unices.
315 // Skip them also under Windows
316 if( fn.GetName().StartsWith( wxT( "." ) ) )
317 return wxTreeItemId();
318
319 if( wxDirExists( aName ) )
320 {
321 type = TREE_FILE_TYPE::DIRECTORY;
322 }
323 else
324 {
325 // Filter
326 wxRegEx reg;
327 bool addFile = false;
328
329 for( const wxString& m_filter : m_filters )
330 {
331 wxCHECK2_MSG( reg.Compile( m_filter, wxRE_ICASE ), continue,
332 wxString::Format( "Regex %s failed to compile.", m_filter ) );
333
334 if( reg.Matches( aName ) )
335 {
336 addFile = true;
337 break;
338 }
339 }
340
341 if( !addFile )
342 return wxTreeItemId();
343
344 for( int i = static_cast<int>( TREE_FILE_TYPE::LEGACY_PROJECT );
345 i < static_cast<int>( TREE_FILE_TYPE::MAX ); i++ )
346 {
347 wxString ext = GetFileExt( (TREE_FILE_TYPE) i );
348
349 if( ext == wxT( "" ) )
350 continue;
351
352 reg.Compile( wxString::FromAscii( "^.*\\." ) + ext + wxString::FromAscii( "$" ),
353 wxRE_ICASE );
354
355 if( reg.Matches( aName ) )
356 {
357 type = (TREE_FILE_TYPE) i;
358 break;
359 }
360 }
361 }
362
363 wxString file = wxFileNameFromPath( aName );
364 wxFileName currfile( file );
365 wxFileName project( m_Parent->GetProjectFileName() );
366
367 // Ignore legacy projects with the same name as the current project
368 if( ( type == TREE_FILE_TYPE::LEGACY_PROJECT )
369 && ( currfile.GetName().CmpNoCase( project.GetName() ) == 0 ) )
370 {
371 return wxTreeItemId();
372 }
373
374 if( currfile.GetExt() == GetFileExt( TREE_FILE_TYPE::LEGACY_SCHEMATIC )
375 || currfile.GetExt() == GetFileExt( TREE_FILE_TYPE::SEXPR_SCHEMATIC ) )
376 {
377 if( aProjectNames )
378 {
379 if( !alg::contains( *aProjectNames, currfile.GetName() ) )
380 return wxTreeItemId();
381 }
382 else
383 {
384 PROJECT_TREE_ITEM* parentTreeItem = GetItemIdData( aParent );
385 wxDir parentDir( parentTreeItem->GetDir() );
386 std::vector<wxString> projects = getProjects( parentDir );
387
388 if( !alg::contains( projects, currfile.GetName() ) )
389 return wxTreeItemId();
390 }
391 }
392
393 // also check to see if it is already there.
394 wxTreeItemIdValue cookie;
395 wxTreeItemId kid = m_TreeProject->GetFirstChild( aParent, cookie );
396
397 while( kid.IsOk() )
398 {
399 PROJECT_TREE_ITEM* itemData = GetItemIdData( kid );
400
401 if( itemData && itemData->GetFileName() == aName )
402 return itemData->GetId(); // well, we would have added it, but it is already here!
403
404 kid = m_TreeProject->GetNextChild( aParent, cookie );
405 }
406
407 // Only show current files if both legacy and current files are present
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 )
410 {
411 kid = m_TreeProject->GetFirstChild( aParent, cookie );
412
413 while( kid.IsOk() )
414 {
415 PROJECT_TREE_ITEM* itemData = GetItemIdData( kid );
416
417 if( itemData )
418 {
419 wxFileName fname( itemData->GetFileName() );
420
421 if( fname.GetName().CmpNoCase( currfile.GetName() ) == 0 )
422 {
423 switch( type )
424 {
425 case TREE_FILE_TYPE::LEGACY_PROJECT:
426 if( itemData->GetType() == TREE_FILE_TYPE::JSON_PROJECT )
427 return wxTreeItemId();
428
429 break;
430
431 case TREE_FILE_TYPE::LEGACY_SCHEMATIC:
432 if( itemData->GetType() == TREE_FILE_TYPE::SEXPR_SCHEMATIC )
433 return wxTreeItemId();
434
435 break;
436
437 case TREE_FILE_TYPE::JSON_PROJECT:
438 if( itemData->GetType() == TREE_FILE_TYPE::LEGACY_PROJECT )
439 m_TreeProject->Delete( kid );
440
441 break;
442
443 case TREE_FILE_TYPE::SEXPR_SCHEMATIC:
444 if( itemData->GetType() == TREE_FILE_TYPE::LEGACY_SCHEMATIC )
445 m_TreeProject->Delete( kid );
446
447 break;
448
449 default:
450 break;
451 }
452 }
453 }
454
455 kid = m_TreeProject->GetNextChild( aParent, cookie );
456 }
457 }
458
459 // Append the item (only appending the filename not the full path):
460 wxTreeItemId newItemId = m_TreeProject->AppendItem( aParent, file );
461 PROJECT_TREE_ITEM* data = new PROJECT_TREE_ITEM( type, aName, m_TreeProject );
462
463 m_TreeProject->SetItemData( newItemId, data );
464 data->SetState( 0 );
465
466 // Mark root files (files which have the same aName as the project)
467 wxString fileName = currfile.GetName().Lower();
468 wxString projName = project.GetName().Lower();
469 data->SetRootFile( fileName == projName || fileName.StartsWith( projName + "-" ) );
470
471#ifndef __WINDOWS__
472 bool subdir_populated = false;
473#endif
474
475 // This section adds dirs and files found in the subdirs
476 // in this case AddFile is recursive, but for the first level only.
477 if( TREE_FILE_TYPE::DIRECTORY == type && aRecurse )
478 {
479 wxDir dir( aName );
480
481 if( dir.IsOpened() ) // protected dirs will not open properly.
482 {
483 std::vector<wxString> projects = getProjects( dir );
484 wxString dir_filename;
485 bool haveFile = dir.GetFirst( &dir_filename );
486
487 data->SetPopulated( true );
488
489#ifndef __WINDOWS__
490 subdir_populated = aRecurse;
491#endif
492
493 while( haveFile )
494 {
495 // Add name in tree, but do not recurse
496 wxString path = aName + wxFileName::GetPathSeparator() + dir_filename;
497 addItemToProjectTree( path, newItemId, &projects, false );
498
499 haveFile = dir.GetNext( &dir_filename );
500 }
501 }
502
503 // Sort filenames by alphabetic order
504 m_TreeProject->SortChildren( newItemId );
505 }
506
507#ifndef __WINDOWS__
508 if( subdir_populated )
509 m_watcherNeedReset = true;
510#endif
511
512 return newItemId;
513}
514
515
517{
518 wxString pro_dir = m_Parent->GetProjectFileName();
519
520 if( !m_TreeProject )
521 m_TreeProject = new PROJECT_TREE( this );
522 else
523 m_TreeProject->DeleteAllItems();
524
525 if( !pro_dir ) // This is empty from PROJECT_TREE_PANE constructor
526 return;
527
528 wxFileName fn = pro_dir;
529 bool prjReset = false;
530
531 if( !fn.IsOk() )
532 {
533 fn.Clear();
534 fn.SetPath( PATHS::GetDefaultUserProjectsPath() );
535 fn.SetName( NAMELESS_PROJECT );
536 fn.SetExt( ProjectFileExtension );
537 prjReset = true;
538 }
539
540 bool prjOpened = fn.FileExists();
541
542 // We may have opened a legacy project, in which case GetProjectFileName will return the
543 // name of the migrated (new format) file, which may not have been saved to disk yet.
544 if( !prjOpened && !prjReset )
545 {
546 fn.SetExt( LegacyProjectFileExtension );
547 prjOpened = fn.FileExists();
548
549 // Set the ext back so that in the tree view we see the (not-yet-saved) new file
550 fn.SetExt( ProjectFileExtension );
551 }
552
553 // root tree:
554 m_root = m_TreeProject->AddRoot( fn.GetFullName(), static_cast<int>( TREE_FILE_TYPE::ROOT ),
555 static_cast<int>( TREE_FILE_TYPE::ROOT ) );
556 m_TreeProject->SetItemBold( m_root, true );
557
558 // The main project file is now a JSON file
559 m_TreeProject->SetItemData( m_root, new PROJECT_TREE_ITEM( TREE_FILE_TYPE::JSON_PROJECT,
560 fn.GetFullPath(), m_TreeProject ) );
561
562 // Now adding all current files if available
563 if( prjOpened )
564 {
565 pro_dir = wxPathOnly( m_Parent->GetProjectFileName() );
566 wxDir dir( pro_dir );
567
568 if( dir.IsOpened() ) // protected dirs will not open, see "man opendir()"
569 {
570 std::vector<wxString> projects = getProjects( dir );
571 wxString filename;
572 bool haveFile = dir.GetFirst( &filename );
573
574 while( haveFile )
575 {
576 if( filename != fn.GetFullName() )
577 {
578 wxString name = dir.GetName() + wxFileName::GetPathSeparator() + filename;
579 // Add items living in the project directory, and populate the item
580 // if it is a directory (sub directories will be not populated)
581 addItemToProjectTree( name, m_root, &projects, true );
582 }
583
584 haveFile = dir.GetNext( &filename );
585 }
586 }
587 }
588 else
589 {
590 m_TreeProject->AppendItem( m_root, wxT( "Empty project" ) );
591 }
592
593 m_TreeProject->Expand( m_root );
594
595 // Sort filenames by alphabetic order
596 m_TreeProject->SortChildren( m_root );
597}
598
599
600void PROJECT_TREE_PANE::onRight( wxTreeEvent& Event )
601{
602 wxTreeItemId curr_item = Event.GetItem();
603
604 // Ensure item is selected (Under Windows right click does not select the item)
605 m_TreeProject->SelectItem( curr_item );
606
607 std::vector<PROJECT_TREE_ITEM*> selection = GetSelectedData();
608
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;
615
616 if( selection.size() == 0 )
617 return;
618
619 // Remove things that don't make sense for multiple selections
620 if( selection.size() != 1 )
621 {
622 can_switch_to_project = false;
623 can_create_new_directory = false;
624 can_rename = false;
625 }
626
627 for( PROJECT_TREE_ITEM* item : selection )
628 {
629 // Check for empty project
630 if( !item )
631 {
632 can_switch_to_project = false;
633 can_edit = false;
634 can_rename = false;
635 continue;
636 }
637
638 can_delete = item->CanDelete();
639 can_rename = item->CanRename();
640
641 switch( item->GetType() )
642 {
643 case TREE_FILE_TYPE::LEGACY_PROJECT:
644 case TREE_FILE_TYPE::JSON_PROJECT:
645 can_rename = false;
646
647 if( item->GetId() == m_TreeProject->GetRootItem() )
648 {
649 can_switch_to_project = false;
650 }
651 else
652 {
653 can_create_new_directory = false;
654 can_open_this_directory = false;
655 }
656 break;
657
658 case TREE_FILE_TYPE::DIRECTORY:
659 can_switch_to_project = false;
660 can_edit = false;
661 break;
662
663 default:
664 can_switch_to_project = false;
665 can_create_new_directory = false;
666 can_open_this_directory = false;
667
668 break;
669 }
670 }
671
672 wxMenu popup_menu;
673 wxString text;
674 wxString help_text;
675
676 if( can_switch_to_project )
677 {
679 _( "Switch to this Project" ),
680 _( "Close all editors, and switch to the selected project" ),
681 KiBitmap( BITMAPS::open_project ) );
682 popup_menu.AppendSeparator();
683 }
684
685 if( can_create_new_directory )
686 {
687 AddMenuItem( &popup_menu, ID_PROJECT_NEWDIR, _( "New Directory..." ),
688 _( "Create a New Directory" ), KiBitmap( BITMAPS::directory ) );
689 }
690
691 if( can_open_this_directory )
692 {
693 if( selection.size() == 1 )
694 {
695#ifdef __APPLE__
696 text = _( "Reveal in Finder" );
697 help_text = _( "Reveals the directory in a Finder window" );
698#else
699 text = _( "Open Directory in File Explorer" );
700 help_text = _( "Opens the directory in the default system file manager" );
701#endif
702 }
703 else
704 {
705#ifdef __APPLE__
706 text = _( "Reveal in Finder" );
707 help_text = _( "Reveals the directories in a Finder window" );
708#else
709 text = _( "Open Directories in File Explorer" );
710 help_text = _( "Opens the directories in the default system file manager" );
711#endif
712 }
713
714 AddMenuItem( &popup_menu, ID_PROJECT_OPEN_DIR, text, help_text,
715 KiBitmap( BITMAPS::directory_browser ) );
716 }
717
718 if( can_edit )
719 {
720 if( selection.size() == 1 )
721 help_text = _( "Open the file in a Text Editor" );
722 else
723 help_text = _( "Open files in a Text Editor" );
724
725 AddMenuItem( &popup_menu, ID_PROJECT_TXTEDIT, _( "Edit in a Text Editor" ),
726 help_text, KiBitmap( BITMAPS::editor ) );
727 }
728
729 if( can_rename )
730 {
731 if( selection.size() == 1 )
732 {
733 text = _( "Rename File..." );
734 help_text = _( "Rename file" );
735 }
736 else
737 {
738 text = _( "Rename Files..." );
739 help_text = _( "Rename files" );
740 }
741
742 AddMenuItem( &popup_menu, ID_PROJECT_RENAME, text, help_text, KiBitmap( BITMAPS::right ) );
743 }
744
745 if( can_delete )
746 {
747 if( selection.size() == 1 )
748 help_text = _( "Delete the file and its content" );
749 else
750 help_text = _( "Delete the files and their contents" );
751
752 if( can_switch_to_project
753 || can_create_new_directory
754 || can_open_this_directory
755 || can_edit
756 || can_rename )
757 {
758 popup_menu.AppendSeparator();
759 }
760
761#ifdef __WINDOWS__
762 AddMenuItem( &popup_menu, ID_PROJECT_DELETE, _( "Delete" ), help_text,
763 KiBitmap( BITMAPS::trash ) );
764#else
765 AddMenuItem( &popup_menu, ID_PROJECT_DELETE, _( "Move to Trash" ), help_text,
766 KiBitmap( BITMAPS::trash ) );
767#endif
768 }
769
770 if( popup_menu.GetMenuItemCount() > 0 )
771 PopupMenu( &popup_menu );
772}
773
774
776{
777 wxString editorname = Pgm().GetTextEditor();
778
779 if( editorname.IsEmpty() )
780 {
781 wxMessageBox( _( "No text editor selected in KiCad. Please choose one." ) );
782 return;
783 }
784
785 std::vector<PROJECT_TREE_ITEM*> tree_data = GetSelectedData();
786 wxString files;
787
788 for( PROJECT_TREE_ITEM* item_data : tree_data )
789 {
790 wxString fullFileName = item_data->GetFileName();
791
792 if( !files.IsEmpty() )
793 files += " ";
794
795 files += fullFileName;
796 }
797
798 ExecuteFile( editorname, files );
799}
800
801
802void PROJECT_TREE_PANE::onDeleteFile( wxCommandEvent& event )
803{
804 std::vector<PROJECT_TREE_ITEM*> tree_data = GetSelectedData();
805
806 for( PROJECT_TREE_ITEM* item_data : tree_data )
807 item_data->Delete();
808}
809
810
811void PROJECT_TREE_PANE::onRenameFile( wxCommandEvent& event )
812{
813 wxTreeItemId curr_item = m_TreeProject->GetFocusedItem();
814 std::vector<PROJECT_TREE_ITEM*> tree_data = GetSelectedData();
815
816 // XXX: Unnecessary?
817 if( tree_data.size() != 1 )
818 return;
819
820 wxString buffer = m_TreeProject->GetItemText( curr_item );
821 wxString msg = wxString::Format( _( "Change filename: '%s'" ),
822 tree_data[0]->GetFileName() );
823 wxTextEntryDialog dlg( this, msg, _( "Change filename" ), buffer );
824
825 if( dlg.ShowModal() != wxID_OK )
826 return; // canceled by user
827
828 buffer = dlg.GetValue();
829 buffer.Trim( true );
830 buffer.Trim( false );
831
832 if( buffer.IsEmpty() )
833 return; // empty file name not allowed
834
835 tree_data[0]->Rename( buffer, true );
836 m_isRenaming = true;
837}
838
839
840void PROJECT_TREE_PANE::onSelect( wxTreeEvent& Event )
841{
842 std::vector<PROJECT_TREE_ITEM*> tree_data = GetSelectedData();
843
844 if( tree_data.size() != 1 )
845 return;
846
847 // Bookmark the selected item but don't try and activate it until later. If we do it now,
848 // there will be more events at least on Windows in this frame that will steal focus from
849 // any newly launched windows
850 m_selectedItem = tree_data[0];
851}
852
853
854void PROJECT_TREE_PANE::onIdle( wxIdleEvent& aEvent )
855{
856 // Idle executes once all other events finished processing. This makes it ideal to launch
857 // a new window without starting Focus wars.
859 {
860 m_selectedItem = nullptr;
862 }
863
864 if( m_selectedItem != nullptr )
865 {
866 // Activate launches a window which may run the event loop on top of us and cause OnIdle
867 // to get called again, so be sure to block off the activation condition first.
869 m_selectedItem = nullptr;
870
871 item->Activate( this );
872 }
873}
874
875
876void PROJECT_TREE_PANE::onExpand( wxTreeEvent& Event )
877{
878 wxTreeItemId itemId = Event.GetItem();
879 PROJECT_TREE_ITEM* tree_data = GetItemIdData( itemId );
880
881 if( !tree_data )
882 return;
883
884 if( tree_data->GetType() != TREE_FILE_TYPE::DIRECTORY )
885 return;
886
887 // explore list of non populated subdirs, and populate them
888 wxTreeItemIdValue cookie;
889 wxTreeItemId kid = m_TreeProject->GetFirstChild( itemId, cookie );
890
891#ifndef __WINDOWS__
892 bool subdir_populated = false;
893#endif
894
895 for( ; kid.IsOk(); kid = m_TreeProject->GetNextChild( itemId, cookie ) )
896 {
897 PROJECT_TREE_ITEM* itemData = GetItemIdData( kid );
898
899 if( !itemData || itemData->GetType() != TREE_FILE_TYPE::DIRECTORY )
900 continue;
901
902 if( itemData->IsPopulated() )
903 continue;
904
905 wxString fileName = itemData->GetFileName();
906 wxDir dir( fileName );
907
908 if( dir.IsOpened() )
909 {
910 std::vector<wxString> projects = getProjects( dir );
911 wxString dir_filename;
912 bool haveFile = dir.GetFirst( &dir_filename );
913
914 while( haveFile )
915 {
916 // Add name to tree item, but do not recurse in subdirs:
917 wxString name = fileName + wxFileName::GetPathSeparator() + dir_filename;
918 addItemToProjectTree( name, kid, &projects, false );
919
920 haveFile = dir.GetNext( &dir_filename );
921 }
922
923 itemData->SetPopulated( true ); // set state to populated
924
925#ifndef __WINDOWS__
926 subdir_populated = true;
927#endif
928 }
929
930 // Sort filenames by alphabetic order
931 m_TreeProject->SortChildren( kid );
932 }
933
934#ifndef __WINDOWS__
935 if( subdir_populated )
936 m_watcherNeedReset = true;
937#endif
938}
939
940
941std::vector<PROJECT_TREE_ITEM*> PROJECT_TREE_PANE::GetSelectedData()
942{
943 wxArrayTreeItemIds selection;
944 std::vector<PROJECT_TREE_ITEM*> data;
945
946 m_TreeProject->GetSelections( selection );
947
948 for( auto it = selection.begin(); it != selection.end(); it++ )
949 {
950 PROJECT_TREE_ITEM* item = GetItemIdData( *it );
951 if( !item )
952 {
953 wxLogDebug( "Null tree item returned for selection, dynamic_cast failed?" );
954 continue;
955 }
956
957 data.push_back( item );
958 }
959
960 return data;
961}
962
963
965{
966 return dynamic_cast<PROJECT_TREE_ITEM*>( m_TreeProject->GetItemData( aId ) );
967}
968
969
970wxTreeItemId PROJECT_TREE_PANE::findSubdirTreeItem( const wxString& aSubDir )
971{
972 wxString prj_dir = wxPathOnly( m_Parent->GetProjectFileName() );
973
974 // If the subdir is the current working directory, return m_root
975 // in main list:
976 if( prj_dir == aSubDir )
977 return m_root;
978
979 // The subdir is in the main tree or in a subdir: Locate it
980 wxTreeItemIdValue cookie;
981 wxTreeItemId root_id = m_root;
982 std::stack<wxTreeItemId> subdirs_id;
983
984 wxTreeItemId child = m_TreeProject->GetFirstChild( root_id, cookie );
985
986 while( true )
987 {
988 if( ! child.IsOk() )
989 {
990 if( subdirs_id.empty() ) // all items were explored
991 {
992 root_id = child; // Not found: return an invalid wxTreeItemId
993 break;
994 }
995 else
996 {
997 root_id = subdirs_id.top();
998 subdirs_id.pop();
999 child = m_TreeProject->GetFirstChild( root_id, cookie );
1000
1001 if( !child.IsOk() )
1002 continue;
1003 }
1004 }
1005
1006 PROJECT_TREE_ITEM* itemData = GetItemIdData( child );
1007
1008 if( itemData && ( itemData->GetType() == TREE_FILE_TYPE::DIRECTORY ) )
1009 {
1010 if( itemData->GetFileName() == aSubDir ) // Found!
1011 {
1012 root_id = child;
1013 break;
1014 }
1015
1016 // child is a subdir, push in list to explore it later
1017 if( itemData->IsPopulated() )
1018 subdirs_id.push( child );
1019 }
1020
1021 child = m_TreeProject->GetNextChild( root_id, cookie );
1022 }
1023
1024 return root_id;
1025}
1026
1027
1028void PROJECT_TREE_PANE::onFileSystemEvent( wxFileSystemWatcherEvent& event )
1029{
1030 // No need to process events when we're shutting down
1031 if( !m_watcher )
1032 return;
1033
1034 const wxFileName& pathModified = event.GetPath();
1035 wxString subdir = pathModified.GetPath();
1036 wxString fn = pathModified.GetFullPath();
1037
1038 switch( event.GetChangeType() )
1039 {
1040 case wxFSW_EVENT_DELETE:
1041 case wxFSW_EVENT_CREATE:
1042 case wxFSW_EVENT_RENAME:
1043 break;
1044
1045 case wxFSW_EVENT_MODIFY:
1046 case wxFSW_EVENT_ACCESS:
1047 default:
1048 return;
1049 }
1050
1051 wxTreeItemId root_id = findSubdirTreeItem( subdir );
1052
1053 if( !root_id.IsOk() )
1054 return;
1055
1056 wxTreeItemIdValue cookie; // dummy variable needed by GetFirstChild()
1057 wxTreeItemId kid = m_TreeProject->GetFirstChild( root_id, cookie );
1058
1059 switch( event.GetChangeType() )
1060 {
1061 case wxFSW_EVENT_CREATE:
1062 {
1063 wxTreeItemId newitem =
1064 addItemToProjectTree( pathModified.GetFullPath(), root_id, nullptr, true );
1065
1066 // If we are in the process of renaming a file, select the new one
1067 // This is needed for MSW and OSX, since we don't get RENAME events from them, just a
1068 // pair of DELETE and CREATE events.
1069 if( m_isRenaming && newitem.IsOk() )
1070 {
1071 m_TreeProject->SelectItem( newitem );
1072 m_isRenaming = false;
1073 }
1074 }
1075 break;
1076
1077 case wxFSW_EVENT_DELETE:
1078 while( kid.IsOk() )
1079 {
1080 PROJECT_TREE_ITEM* itemData = GetItemIdData( kid );
1081
1082 if( itemData && itemData->GetFileName() == fn )
1083 {
1084 m_TreeProject->Delete( kid );
1085 return;
1086 }
1087 kid = m_TreeProject->GetNextChild( root_id, cookie );
1088 }
1089 break;
1090
1091 case wxFSW_EVENT_RENAME :
1092 {
1093 const wxFileName& newpath = event.GetNewPath();
1094 wxString newdir = newpath.GetPath();
1095 wxString newfn = newpath.GetFullPath();
1096
1097 while( kid.IsOk() )
1098 {
1099 PROJECT_TREE_ITEM* itemData = GetItemIdData( kid );
1100
1101 if( itemData && itemData->GetFileName() == fn )
1102 {
1103 m_TreeProject->Delete( kid );
1104 break;
1105 }
1106
1107 kid = m_TreeProject->GetNextChild( root_id, cookie );
1108 }
1109
1110 // Add the new item only if it is not the current project file (root item).
1111 // Remember: this code is called by a wxFileSystemWatcherEvent event, and not always
1112 // called after an actual file rename, and the cleanup code does not explore the
1113 // root item, because it cannot be renamed by the user. Also, ensure the new file
1114 // actually exists on the file system before it is readded. On Linux, moving a file
1115 // to the trash can cause the same path to be returned in both the old and new paths
1116 // of the event, even though the file isn't there anymore.
1117 PROJECT_TREE_ITEM* rootData = GetItemIdData( root_id );
1118
1119 if( rootData && newpath.Exists() && ( newfn != rootData->GetFileName() ) )
1120 {
1121 wxTreeItemId newroot_id = findSubdirTreeItem( newdir );
1122 wxTreeItemId newitem = addItemToProjectTree( newfn, newroot_id, nullptr, true );
1123
1124 // If the item exists, select it
1125 if( newitem.IsOk() )
1126 m_TreeProject->SelectItem( newitem );
1127 }
1128
1129 m_isRenaming = false;
1130 }
1131 break;
1132 }
1133
1134 // Sort filenames by alphabetic order
1135 m_TreeProject->SortChildren( root_id );
1136}
1137
1138
1140{
1141 m_watcherNeedReset = false;
1142
1143 wxString prj_dir = wxPathOnly( m_Parent->GetProjectFileName() );
1144
1145#if defined( _WIN32 )
1146 if( KIPLATFORM::ENV::IsNetworkPath( prj_dir ) )
1147 {
1148 // Due to a combination of a bug in SAMBA sending bad change event IDs and wxWidgets
1149 // choosing to fault on an invalid event ID instead of sanely ignoring them we need to
1150 // avoid spawning a filewatcher. Unfortunately this punishes corporate environments with
1151 // Windows Server shares :/
1152 m_Parent->SetStatusText( _( "Network path: not monitoring folder changes" ), 1 );
1153 return;
1154 }
1155 else
1156 {
1157 m_Parent->SetStatusText( _( "Local path: monitoring folder changes" ), 1 );
1158 }
1159#endif
1160
1161 // Prepare file watcher:
1162 if( m_watcher )
1163 {
1164 m_watcher->RemoveAll();
1165 }
1166 else
1167 {
1168 m_watcher = new wxFileSystemWatcher();
1169 m_watcher->SetOwner( this );
1170 }
1171
1172 // We can see wxString under a debugger, not a wxFileName
1173 wxFileName fn;
1174 fn.AssignDir( prj_dir );
1175 fn.DontFollowLink();
1176
1177 // Add directories which should be monitored.
1178 // under windows, we add the curr dir and all subdirs
1179 // under unix, we add only the curr dir and the populated subdirs
1180 // see http://docs.wxwidgets.org/trunk/classwx_file_system_watcher.htm
1181 // under unix, the file watcher needs more work to be efficient
1182 // moreover, under wxWidgets 2.9.4, AddTree does not work properly.
1183#ifdef __WINDOWS__
1184 m_watcher->AddTree( fn );
1185#else
1186 m_watcher->Add( fn );
1187
1188 if( m_TreeProject->IsEmpty() )
1189 return;
1190
1191 // Add subdirs
1192 wxTreeItemIdValue cookie;
1193 wxTreeItemId root_id = m_root;
1194
1195 std::stack < wxTreeItemId > subdirs_id;
1196
1197 wxTreeItemId kid = m_TreeProject->GetFirstChild( root_id, cookie );
1198
1199 while( true )
1200 {
1201 if( !kid.IsOk() )
1202 {
1203 if( subdirs_id.empty() ) // all items were explored
1204 {
1205 break;
1206 }
1207 else
1208 {
1209 root_id = subdirs_id.top();
1210 subdirs_id.pop();
1211 kid = m_TreeProject->GetFirstChild( root_id, cookie );
1212
1213 if( !kid.IsOk() )
1214 continue;
1215 }
1216 }
1217
1218 PROJECT_TREE_ITEM* itemData = GetItemIdData( kid );
1219
1220 if( itemData && itemData->GetType() == TREE_FILE_TYPE::DIRECTORY )
1221 {
1222 // we can see wxString under a debugger, not a wxFileName
1223 const wxString& path = itemData->GetFileName();
1224
1225 wxLogTrace( tracePathsAndFiles, "%s: add '%s'\n", __func__, TO_UTF8( path ) );
1226
1227 if( wxFileName::IsDirReadable( path ) ) // linux whines about watching protected dir
1228 {
1229 fn.AssignDir( path );
1230 m_watcher->Add( fn );
1231
1232 // if kid is a subdir, push in list to explore it later
1233 if( itemData->IsPopulated() && m_TreeProject->GetChildrenCount( kid ) )
1234 subdirs_id.push( kid );
1235 }
1236 }
1237
1238 kid = m_TreeProject->GetNextChild( root_id, cookie );
1239 }
1240#endif
1241
1242#if defined(DEBUG) && 1
1243 wxArrayString paths;
1244 m_watcher->GetWatchedPaths( &paths );
1245 wxLogTrace( tracePathsAndFiles, "%s: watched paths:", __func__ );
1246
1247 for( unsigned ii = 0; ii < paths.GetCount(); ii++ )
1248 wxLogTrace( tracePathsAndFiles, " %s\n", TO_UTF8( paths[ii] ) );
1249#endif
1250}
1251
1252
1254{
1255 // Make sure we don't try to inspect the tree after we've deleted its items.
1257
1258 m_TreeProject->DeleteAllItems();
1259}
1260
1261
1262void PROJECT_TREE_PANE::onThemeChanged( wxSysColourChangedEvent &aEvent )
1263{
1266 m_TreeProject->Refresh();
1267
1268 aEvent.Skip();
1269}
1270
1271
1272void PROJECT_TREE_PANE::onPaint( wxPaintEvent& event )
1273{
1274 wxRect rect( wxPoint( 0, 0 ), GetClientSize() );
1275 wxPaintDC dc( this );
1276
1277 dc.SetBrush( wxSystemSettings::GetColour( wxSYS_COLOUR_FRAMEBK ) );
1278 dc.SetPen( wxPen( wxSystemSettings::GetColour( wxSYS_COLOUR_ACTIVEBORDER ), 1 ) );
1279
1280 dc.DrawLine( rect.GetLeft(), rect.GetTop(), rect.GetLeft(), rect.GetBottom() );
1281 dc.DrawLine( rect.GetRight(), rect.GetTop(), rect.GetRight(), rect.GetBottom() );
1282}
1283
1284
1285void KICAD_MANAGER_FRAME::OnChangeWatchedPaths( wxCommandEvent& aEvent )
1286{
1288}
const char * name
Definition: DXF_plotter.cpp:56
wxBitmap KiBitmap(BITMAPS aBitmap, int aHeightTag)
Construct a wxBitmap from an image identifier Returns the image from the active theme if the image ha...
Definition: bitmap.cpp:106
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.
Definition: bitmap.cpp:266
BITMAP_STORE * GetBitmapStore()
Definition: bitmap.cpp:94
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.
Definition: paths.cpp:139
Handle one item (a file or a directory name) for the tree file.
void SetRootFile(bool aValue)
void SetState(int state)
const wxString & GetFileName() const
bool IsPopulated() 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.
Definition: project_tree.h:39
void LoadIcons()
#define _(s)
int ExecuteFile(const wxString &aEditorName, const wxString &aFileName, wxProcess *aCallback)
Call the executable file aEditorName with the parameter aFileName.
Definition: gestfich.cpp:117
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_OPEN_DIR
Definition: kicad_id.h:62
@ ID_PROJECT_SWITCH_TO_OTHER
Definition: kicad_id.h:60
@ ID_PROJECT_NEWDIR
Definition: kicad_id.h:61
@ ID_PROJECT_RENAME
Definition: kicad_id.h:64
@ ID_PROJECT_TXTEDIT
Definition: kicad_id.h:59
@ ID_PROJECT_TREE
Definition: kicad_id.h:58
@ ID_PROJECT_DELETE
Definition: kicad_id.h:63
@ ID_LEFT_FRAME
Definition: kicad_id.h:57
bool LaunchExternal(const wxString &aPath)
Launches the given file or folder in the host OS.
Definition: launch_ext.cpp:25
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.
Definition: macros.h:96
Macros and inline functions to create menus items in menubars or popup menus.
bool IsNetworkPath(const wxString &aPath)
Determines if a given path is a network shared file apth On Windows for example, any form of path is ...
bool contains(const _Container &__container, _Value __value)
Returns true if the container contains the given value.
Definition: kicad_algo.h:99
#define NAMELESS_PROJECT
default name for nameless projects
Definition: project.h:42
std::vector< wxString > getProjects(const wxDir &dir)
static const wxChar * s_allowedExtensionsToList[]
KIWAY Kiway & Pgm(), KFCTL_STANDALONE
The global Program "get" accessor.
Definition: single_top.cpp:115
wxLogTrace helper definitions.
TREE_FILE_TYPE
Definition of file extensions used in Kicad.