KiCad PCB EDA Suite
Loading...
Searching...
No Matches
pcbnew/files.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) 2004-2015 Jean-Pierre Charras, jp.charras at wanadoo.fr
5 * Copyright (C) 2011 Wayne Stambaugh <[email protected]>
6 * Copyright (C) 2023 CERN (www.cern.ch)
7 * Copyright (C) 2016-2023 KiCad Developers, see AUTHORS.txt for contributors.
8 *
9 * This program is free software; you can redistribute it and/or
10 * modify it under the terms of the GNU General Public License
11 * as published by the Free Software Foundation; either version 2
12 * of the License, or (at your option) any later version.
13 *
14 * This program is distributed in the hope that it will be useful,
15 * but WITHOUT ANY WARRANTY; without even the implied warranty of
16 * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
17 * GNU General Public License for more details.
18 *
19 * You should have received a copy of the GNU General Public License
20 * along with this program; if not, you may find one here:
21 * http://www.gnu.org/licenses/old-licenses/gpl-2.0.html
22 * or you may search the http://www.gnu.org website for the version 2 license,
23 * or you may write to the Free Software Foundation, Inc.,
24 * 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301, USA
25 */
26
27#include <string>
28
29#include <confirm.h>
30#include <kidialog.h>
31#include <core/arraydim.h>
32#include <core/thread_pool.h>
34#include <gestfich.h>
35#include <pcb_edit_frame.h>
38#include <fp_lib_table.h>
39#include <kiface_base.h>
40#include <macros.h>
41#include <trace_helpers.h>
42#include <lockfile.h>
43#include <wx/snglinst.h>
45#include <pcbnew_id.h>
47#include <tool/tool_manager.h>
48#include <board.h>
49#include <kiplatform/app.h>
51#include <widgets/wx_infobar.h>
54#include <string_utf8_map.h>
55#include <paths.h>
56#include <pgm_base.h>
58#include <project_pcb.h>
62#include <pcb_io/pcb_io_mgr.h>
68#include <tools/pcb_actions.h>
69#include "footprint_info_impl.h"
70#include <board_commit.h>
71#include <zone_filler.h>
74#include <wx_filename.h> // For ::ResolvePossibleSymlinks()
75
76#include <kiplatform/io.h>
77
78#include <wx/stdpaths.h>
79#include <wx/ffile.h>
80#include <wx/filedlg.h>
81#include <wx/txtstrm.h>
82#include <wx/wfstream.h>
83#include <wx/zipstrm.h>
84
85#include "widgets/filedlg_hook_save_project.h"
86
87//#define USE_INSTRUMENTATION 1
88#define USE_INSTRUMENTATION 0
89
90
100bool AskLoadBoardFileName( PCB_EDIT_FRAME* aParent, wxString* aFileName, int aCtl = 0 )
101{
102 std::vector<IO_BASE::IO_FILE_DESC> descriptions;
103
104 for( const auto& plugin : PCB_IO_MGR::PLUGIN_REGISTRY::Instance()->AllPlugins() )
105 {
106 bool isKiCad = plugin.m_type == PCB_IO_MGR::KICAD_SEXP || plugin.m_type == PCB_IO_MGR::LEGACY;
107
108 if( ( aCtl & KICTL_KICAD_ONLY ) && !isKiCad )
109 continue;
110
111 if( ( aCtl & KICTL_NONKICAD_ONLY ) && isKiCad )
112 continue;
113
114 IO_RELEASER<PCB_IO> pi( plugin.m_createFunc() );
115 wxCHECK( pi, false );
116
117 const IO_BASE::IO_FILE_DESC& desc = pi->GetBoardFileDesc();
118
119 if( desc.m_FileExtensions.empty() || !desc.m_CanRead )
120 continue;
121
122 descriptions.emplace_back( desc );
123 }
124
125 wxString fileFiltersStr;
126 std::vector<std::string> allExtensions;
127 std::set<wxString> allWildcardsSet;
128
129 for( const IO_BASE::IO_FILE_DESC& desc : descriptions )
130 {
131 if( !fileFiltersStr.IsEmpty() )
132 fileFiltersStr += wxChar( '|' );
133
134 fileFiltersStr += desc.FileFilter();
135
136 for( const std::string& ext : desc.m_FileExtensions )
137 {
138 allExtensions.emplace_back( ext );
139 allWildcardsSet.insert( wxT( "*." ) + formatWildcardExt( ext ) + wxT( ";" ) );
140 }
141 }
142
143 wxString allWildcardsStr;
144
145 for( const wxString& wildcard : allWildcardsSet )
146 allWildcardsStr << wildcard;
147
148 if( aCtl & KICTL_KICAD_ONLY )
149 {
150 fileFiltersStr = _( "All KiCad Board Files" ) + AddFileExtListToFilter( allExtensions );
151 }
152 else
153 {
154 fileFiltersStr = _( "All supported formats" ) + wxT( "|" ) + allWildcardsStr + wxT( "|" )
155 + fileFiltersStr;
156 }
157
158 wxFileName fileName( *aFileName );
159 wxString path;
160 wxString name;
161
162 if( fileName.FileExists() )
163 {
164 path = fileName.GetPath();
165 name = fileName.GetFullName();
166 }
167 else
168 {
169 path = aParent->GetMruPath();
170
171 if( path.IsEmpty() )
173 // leave name empty
174 }
175
176 bool kicadFormat = ( aCtl & KICTL_KICAD_ONLY );
177
178 wxFileDialog dlg( aParent,
179 kicadFormat ? _( "Open Board File" ) : _( "Import Non KiCad Board File" ),
180 path, name, fileFiltersStr, wxFD_OPEN | wxFD_FILE_MUST_EXIST );
181
182 FILEDLG_IMPORT_NON_KICAD importOptions( aParent->config()->m_System.show_import_issues );
183
184 if( !kicadFormat )
185 dlg.SetCustomizeHook( importOptions );
186
187 if( dlg.ShowModal() == wxID_OK )
188 {
189 *aFileName = dlg.GetPath();
190 aParent->SetMruPath( wxFileName( dlg.GetPath() ).GetPath() );
191
192 if( !kicadFormat )
193 aParent->config()->m_System.show_import_issues = importOptions.GetShowIssues();
194
195 return true;
196 }
197 else
198 {
199 return false;
200 }
201}
202
203
213bool AskSaveBoardFileName( PCB_EDIT_FRAME* aParent, wxString* aFileName, bool* aCreateProject )
214{
215 wxString wildcard = FILEEXT::PcbFileWildcard();
216 wxFileName fn = *aFileName;
217
219
220 wxFileDialog dlg( aParent, _( "Save Board File As" ), fn.GetPath(), fn.GetFullName(), wildcard,
221 wxFD_SAVE | wxFD_OVERWRITE_PROMPT );
222
223// Add a "Create a project" checkbox in standalone mode and one isn't loaded
224 FILEDLG_HOOK_SAVE_PROJECT newProjectHook;
225
226 if( Kiface().IsSingle() && aParent->Prj().IsNullProject() )
227 dlg.SetCustomizeHook( newProjectHook );
228
229 if( dlg.ShowModal() != wxID_OK )
230 return false;
231
232 *aFileName = dlg.GetPath();
233 *aFileName = EnsureFileExtension( *aFileName, FILEEXT::KiCadPcbFileExtension );
234
235 if( newProjectHook.IsAttachedToDialog() )
236 *aCreateProject = newProjectHook.GetCreateNewProject();
237 else if( !aParent->Prj().IsNullProject() )
238 *aCreateProject = true;
239
240 return true;
241}
242
243
244void PCB_EDIT_FRAME::OnFileHistory( wxCommandEvent& event )
245{
246 wxString fn = GetFileFromHistory( event.GetId(), _( "Printed circuit board" ) );
247
248 if( !!fn )
249 {
250 if( !wxFileName::IsFileReadable( fn ) )
251 {
252 if( !AskLoadBoardFileName( this, &fn, KICTL_KICAD_ONLY ) )
253 return;
254 }
255
256 OpenProjectFiles( std::vector<wxString>( 1, fn ), KICTL_KICAD_ONLY );
257 }
258}
259
260
261void PCB_EDIT_FRAME::OnClearFileHistory( wxCommandEvent& aEvent )
262{
264}
265
266
267void PCB_EDIT_FRAME::Files_io( wxCommandEvent& event )
268{
269 int id = event.GetId();
270 Files_io_from_id( id );
271}
272
273
275{
276 wxString msg;
277
278 switch( id )
279 {
280 case ID_LOAD_FILE:
281 {
282 // Only standalone mode can directly load a new document
283 if( !Kiface().IsSingle() )
284 return false;
285
286 int open_ctl = KICTL_KICAD_ONLY;
287 wxString fileName = Prj().AbsolutePath( GetBoard()->GetFileName() );
288
289 return AskLoadBoardFileName( this, &fileName, open_ctl )
290 && OpenProjectFiles( std::vector<wxString>( 1, fileName ), open_ctl );
291 }
292
294 {
295 // Note: we explicitly allow this even if not in standalone mode for now, even though it is dangerous.
296 int open_ctl = KICTL_NONKICAD_ONLY;
297 wxString fileName; // = Prj().AbsolutePath( GetBoard()->GetFileName() );
298
299 return AskLoadBoardFileName( this, &fileName, open_ctl )
300 && OpenProjectFiles( std::vector<wxString>( 1, fileName ), open_ctl );
301 }
302
304 {
305 wxFileName currfn = Prj().AbsolutePath( GetBoard()->GetFileName() );
306 wxFileName fn = currfn;
307
308 wxString rec_name = FILEEXT::AutoSaveFilePrefix + fn.GetName();
309 fn.SetName( rec_name );
310
311 if( !fn.FileExists() )
312 {
313 msg.Printf( _( "Recovery file '%s' not found." ), fn.GetFullPath() );
314 DisplayInfoMessage( this, msg );
315 return false;
316 }
317
318 msg.Printf( _( "OK to load recovery file '%s'?" ), fn.GetFullPath() );
319
320 if( !IsOK( this, msg ) )
321 return false;
322
323 GetScreen()->SetContentModified( false ); // do not prompt the user for changes
324
325 if( OpenProjectFiles( std::vector<wxString>( 1, fn.GetFullPath() ) ) )
326 {
327 // Re-set the name since name or extension was changed
328 GetBoard()->SetFileName( currfn.GetFullPath() );
329 UpdateTitle();
330 return true;
331 }
332
333 return false;
334 }
335
336 case ID_REVERT_BOARD:
337 {
338 wxFileName fn = Prj().AbsolutePath( GetBoard()->GetFileName() );
339
340 msg.Printf( _( "Revert '%s' to last version saved?" ), fn.GetFullPath() );
341
342 if( !IsOK( this, msg ) )
343 return false;
344
345 GetScreen()->SetContentModified( false ); // do not prompt the user for changes
346
347 ReleaseFile();
348
349 return OpenProjectFiles( std::vector<wxString>( 1, fn.GetFullPath() ), KICTL_REVERT );
350 }
351
352 case ID_NEW_BOARD:
353 {
354 // Only standalone mode can directly load a new document
355 if( !Kiface().IsSingle() )
356 return false;
357
358 if( IsContentModified() )
359 {
360 wxFileName fileName = GetBoard()->GetFileName();
361 wxString saveMsg = _( "Current board will be closed, save changes to '%s' before "
362 "continuing?" );
363
364 if( !HandleUnsavedChanges( this, wxString::Format( saveMsg, fileName.GetFullName() ),
365 [&]()->bool
366 {
367 return Files_io_from_id( ID_SAVE_BOARD );
368 } ) )
369 {
370 return false;
371 }
372 }
373 else if( !GetBoard()->IsEmpty() )
374 {
375 if( !IsOK( this, _( "Current Board will be closed. Continue?" ) ) )
376 return false;
377 }
378
380
382
384 mgr->UnloadProject( &mgr->Prj() );
385
386 if( !Clear_Pcb( false ) )
387 return false;
388
391
393
394 OnModify();
395 return true;
396 }
397
398 case ID_SAVE_BOARD:
399 if( !GetBoard()->GetFileName().IsEmpty() )
400 {
401 if( SavePcbFile( Prj().AbsolutePath( GetBoard()->GetFileName() ) ) )
402 {
403 m_autoSaveRequired = false;
404 return true;
405 }
406
407 return false;
408 }
409
411
412 case ID_COPY_BOARD_AS:
413 case ID_SAVE_BOARD_AS:
414 {
415 bool addToHistory = ( id == ID_SAVE_BOARD_AS );
416 wxString orig_name;
417
418 wxFileName::SplitPath( GetBoard()->GetFileName(), nullptr, nullptr, &orig_name, nullptr );
419
420 if( orig_name.IsEmpty() )
421 orig_name = NAMELESS_PROJECT;
422
423 wxFileName savePath( Prj().GetProjectFullName() );
424
425 if( !savePath.IsOk() || !savePath.IsDirWritable() )
426 {
427 savePath = GetMruPath();
428
429 if( !savePath.IsOk() || !savePath.IsDirWritable() )
431 }
432
433 wxFileName fn( savePath.GetPath(), orig_name, FILEEXT::KiCadPcbFileExtension );
434 wxString filename = fn.GetFullPath();
435 bool createProject = false;
436 bool success = false;
437
438 if( AskSaveBoardFileName( this, &filename, &createProject ) )
439 {
440 if( id == ID_COPY_BOARD_AS )
441 {
442 success = SavePcbCopy( filename, createProject );
443 }
444 else
445 {
446 success = SavePcbFile( filename, addToHistory, createProject );
447
448 if( success )
449 m_autoSaveRequired = false;
450 }
451 }
452
453 return success;
454 }
455
456 default:
457 return false;
458 }
459}
460
461
462int PCB_EDIT_FRAME::inferLegacyEdgeClearance( BOARD* aBoard, bool aShowUserMsg )
463{
464 PCB_LAYER_COLLECTOR collector;
465
466 collector.SetLayerId( Edge_Cuts );
467 collector.Collect( aBoard, GENERAL_COLLECTOR::AllBoardItems );
468
469 int edgeWidth = -1;
470 bool mixed = false;
471
472 for( int i = 0; i < collector.GetCount(); i++ )
473 {
474 if( collector[i]->Type() == PCB_SHAPE_T )
475 {
476 int itemWidth = static_cast<PCB_SHAPE*>( collector[i] )->GetWidth();
477
478 if( edgeWidth != -1 && edgeWidth != itemWidth )
479 {
480 mixed = true;
481 edgeWidth = std::max( edgeWidth, itemWidth );
482 }
483 else
484 {
485 edgeWidth = itemWidth;
486 }
487 }
488 }
489
490 if( mixed && aShowUserMsg )
491 {
492 // If they had different widths then we can't ensure that fills will be the same.
493 DisplayInfoMessage( this,
494 _( "If the zones on this board are refilled the Copper Edge "
495 "Clearance setting will be used (see Board Setup > Design "
496 "Rules > Constraints).\n This may result in different fills "
497 "from previous KiCad versions which used the line thicknesses "
498 "of the board boundary on the Edge Cuts layer." ) );
499 }
500
501 return std::max( 0, edgeWidth / 2 );
502}
503
504
505bool PCB_EDIT_FRAME::OpenProjectFiles( const std::vector<wxString>& aFileSet, int aCtl )
506{
507 // This is for python:
508 if( aFileSet.size() != 1 )
509 {
510 UTF8 msg = StrPrintf( "Pcbnew:%s() takes a single filename", __func__ );
511 DisplayError( this, msg );
512 return false;
513 }
514
515 wxString fullFileName( aFileSet[0] );
516 wxFileName wx_filename( fullFileName );
517 wxString msg;
518
519 if( Kiface().IsSingle() )
521
522 // We insist on caller sending us an absolute path, if it does not, we say it's a bug.
523 wxASSERT_MSG( wx_filename.IsAbsolute(), wxT( "Path is not absolute!" ) );
524
525 std::unique_ptr<LOCKFILE> lock = std::make_unique<LOCKFILE>( fullFileName );
526
527 if( !lock->Valid() && lock->IsLockedByMe() )
528 {
529 // If we cannot acquire the lock but we appear to be the one who locked it, check to
530 // see if there is another KiCad instance running. If not, then we can override the
531 // lock. This could happen if KiCad crashed or was interrupted.
532
533 if( !Pgm().SingleInstance()->IsAnotherRunning() )
534 lock->OverrideLock();
535 }
536
537 if( !lock->Valid() )
538 {
539 msg.Printf( _( "PCB '%s' is already open by '%s' at '%s'." ),
540 wx_filename.GetFullName(),
541 lock->GetUsername(),
542 lock->GetHostname() );
543
544 if( !AskOverrideLock( this, msg ) )
545 return false;
546
547 lock->OverrideLock();
548 }
549
550 if( IsContentModified() )
551 {
552 if( !HandleUnsavedChanges( this, _( "The current PCB has been modified. Save changes?" ),
553 [&]() -> bool
554 {
555 return SavePcbFile( GetBoard()->GetFileName() );
556 } ) )
557 {
558 return false;
559 }
560 }
561
562 wxFileName pro = fullFileName;
563 pro.SetExt( FILEEXT::ProjectFileExtension );
564
565 bool is_new = !wxFileName::IsFileReadable( fullFileName );
566
567 // If its a non-existent PCB and caller thinks it exists
568 if( is_new && !( aCtl & KICTL_CREATE ) )
569 {
570 // notify user that fullFileName does not exist, ask if user wants to create it.
571 msg.Printf( _( "PCB '%s' does not exist. Do you wish to create it?" ), fullFileName );
572
573 if( !IsOK( this, msg ) )
574 return false;
575 }
576
577 // Get rid of any existing warnings about the old board
578 GetInfoBar()->Dismiss();
579
580 WX_PROGRESS_REPORTER progressReporter( this, is_new ? _( "Creating PCB" )
581 : _( "Loading PCB" ), 1 );
582
583 // No save prompt (we already prompted above), and only reset to a new blank board if new
584 Clear_Pcb( false, !is_new );
585
587
588 if( !is_new )
589 pluginType = PCB_IO_MGR::FindPluginTypeFromBoardPath( fullFileName, aCtl );
590
591 if( pluginType == PCB_IO_MGR::FILE_TYPE_NONE )
592 return false;
593
594 bool converted = pluginType != PCB_IO_MGR::LEGACY && pluginType != PCB_IO_MGR::KICAD_SEXP;
595
596 // Loading a project should only be done under carefully considered circumstances.
597
598 // The calling code should know not to ask me here to change projects unless
599 // it knows what consequences that will have on other KIFACEs running and using
600 // this same PROJECT. It can be very harmful if that calling code is stupid.
602 bool setProject;
603
604 if( Kiface().IsSingle() || !( aCtl & KICTL_NONKICAD_ONLY ) )
605 setProject = pro.GetFullPath() != mgr->Prj().GetProjectFullName();
606 else
607 setProject = Prj().GetProjectFullName().IsEmpty();
608
609 wxString path = wxPathOnly( Prj().GetProjectFullName() );
610
611 if( setProject )
612 {
613 // calls SaveProject
615
617 mgr->UnloadProject( &mgr->Prj() );
618
619 mgr->LoadProject( pro.GetFullPath() );
620
621 // Do not allow saving a project if one doesn't exist. This normally happens if we are
622 // opening a board that has been moved from its project folder.
623 // For converted projects, we don't want to set the read-only flag because we want a
624 // project to be saved for the new file in case things like netclasses got migrated.
625 Prj().SetReadOnly( !pro.Exists() && !converted );
626 }
627
628 // Clear the cache footprint list which may be project specific
630
631 if( is_new )
632 {
633 // Link the existing blank board to the new project
634 GetBoard()->SetProject( &Prj() );
635
636 GetBoard()->SetFileName( fullFileName );
637
638 OnModify();
639 }
640 else
641 {
642 BOARD* loadedBoard = nullptr; // it will be set to non-NULL if loaded OK
644
645 if( LAYER_MAPPABLE_PLUGIN* mappable_pi = dynamic_cast<LAYER_MAPPABLE_PLUGIN*>( pi.get() ) )
646 {
647 mappable_pi->RegisterCallback( std::bind( DIALOG_MAP_LAYERS::RunModal,
648 this, std::placeholders::_1 ) );
649 }
650
651 if( PROJECT_CHOOSER_PLUGIN* chooser_pi = dynamic_cast<PROJECT_CHOOSER_PLUGIN*>( pi.get() ) )
652 {
653 chooser_pi->RegisterCallback( std::bind( DIALOG_IMPORT_CHOOSE_PROJECT::RunModal,
654 this,
655 std::placeholders::_1 ) );
656 }
657
658 if( ( aCtl & KICTL_REVERT ) )
659 {
660 DeleteAutoSaveFile( fullFileName );
661 }
662 else
663 {
664 // This will rename the file if there is an autosave and the user wants to recover
665 CheckForAutoSaveFile( fullFileName );
666 }
667
668 DIALOG_HTML_REPORTER errorReporter( this );
669 bool failedLoad = false;
670
671 try
672 {
673 if( pi == nullptr )
674 {
675 // There was no plugin found, e.g. due to invalid file extension, file header,...
676 THROW_IO_ERROR( _( "File format is not supported" ) );
677 }
678
679 STRING_UTF8_MAP props;
680
682 props.insert( m_importProperties->begin(), m_importProperties->end() );
683
684 // PCB_IO_EAGLE can use this info to center the BOARD, but it does not yet.
685 props["page_width"] = std::to_string( GetPageSizeIU().x );
686 props["page_height"] = std::to_string( GetPageSizeIU().y );
687
688 pi->SetQueryUserCallback(
689 [&]( wxString aTitle, int aIcon, wxString aMessage, wxString aAction ) -> bool
690 {
691 KIDIALOG dlg( nullptr, aMessage, aTitle, wxOK | wxCANCEL | aIcon );
692
693 if( !aAction.IsEmpty() )
694 dlg.SetOKLabel( aAction );
695
696 dlg.DoNotShowCheckbox( aMessage, 0 );
697
698 return dlg.ShowModal() == wxID_OK;
699 } );
700
701#if USE_INSTRUMENTATION
702 // measure the time to load a BOARD.
703 int64_t startTime = GetRunningMicroSecs();
704#endif
705 if( config()->m_System.show_import_issues )
706 pi->SetReporter( errorReporter.m_Reporter );
707 else
708 pi->SetReporter( &NULL_REPORTER::GetInstance() );
709
710 pi->SetProgressReporter( &progressReporter );
711 loadedBoard = pi->LoadBoard( fullFileName, nullptr, &props, &Prj() );
712
713#if USE_INSTRUMENTATION
714 int64_t stopTime = GetRunningMicroSecs();
715 printf( "PCB_IO::Load(): %u usecs\n", stopTime - startTime );
716#endif
717 }
718 catch( const FUTURE_FORMAT_ERROR& ffe )
719 {
720 msg.Printf( _( "Error loading PCB '%s'." ), fullFileName );
721 progressReporter.Hide();
722 DisplayErrorMessage( this, msg, ffe.Problem() );
723
724 failedLoad = true;
725 }
726 catch( const IO_ERROR& ioe )
727 {
728 if( ioe.Problem() != wxT( "CANCEL" ) )
729 {
730 msg.Printf( _( "Error loading PCB '%s'." ), fullFileName );
731 progressReporter.Hide();
732 DisplayErrorMessage( this, msg, ioe.What() );
733 }
734
735 failedLoad = true;
736 }
737 catch( const std::bad_alloc& )
738 {
739 msg.Printf( _( "Memory exhausted loading PCB '%s'" ), fullFileName );
740 progressReporter.Hide();
741 DisplayErrorMessage( this, msg, wxEmptyString );
742
743 failedLoad = true;
744 }
745
746 if( failedLoad || !loadedBoard )
747 {
748 // We didn't create a new blank board above, so do that now
749 Clear_Pcb( false );
750
751 return false;
752 }
753
754 // This fixes a focus issue after the progress reporter is done on GTK. It shouldn't
755 // cause any issues on macOS and Windows. If it does, it will have to be conditionally
756 // compiled.
757 Raise();
758
759 if( errorReporter.m_Reporter->HasMessage() )
760 {
761 errorReporter.m_Reporter->Flush(); // Build HTML messages
762 errorReporter.ShowModal();
763 }
764
765 // Skip (possibly expensive) connectivity build here; we build it below after load
766 SetBoard( loadedBoard, false, &progressReporter );
767
768 if( GFootprintList.GetCount() == 0 )
769 GFootprintList.ReadCacheFromFile( Prj().GetProjectPath() + wxT( "fp-info-cache" ) );
770
771 if( loadedBoard->m_LegacyDesignSettingsLoaded )
772 {
773 Prj().SetReadOnly( false );
774
775 // Before we had a copper edge clearance setting, the edge line widths could be used
776 // as a kludge to control them. So if there's no setting then infer it from the
777 // edge widths.
778 if( !loadedBoard->m_LegacyCopperEdgeClearanceLoaded )
779 {
780 // Do not show the inferred edge clearance warning dialog when loading third
781 // party boards. For some reason the dialog completely hangs all of KiCad and
782 // the imported board cannot be saved.
783 int edgeClearance = inferLegacyEdgeClearance( loadedBoard, !converted );
784 loadedBoard->GetDesignSettings().m_CopperEdgeClearance = edgeClearance;
785 }
786
787 // On save; design settings will be removed from the board
788 loadedBoard->SetModified();
789 }
790
791 // Move legacy view settings to local project settings
792 if( !loadedBoard->m_LegacyVisibleLayers.test( Rescue ) )
793 {
795 loadedBoard->SetModified();
796 }
797
799 {
801 loadedBoard->SetModified();
802 }
803
804 // we should not ask PCB_IOs to do these items:
805 loadedBoard->BuildListOfNets();
806 ResolveDRCExclusions( true );
808
809 if( loadedBoard->IsModified() )
810 OnModify();
811 else
812 GetScreen()->SetContentModified( false );
813
814 if( ( pluginType == PCB_IO_MGR::LEGACY )
815 || ( pluginType == PCB_IO_MGR::KICAD_SEXP
817 && loadedBoard->GetGenerator().Lower() != wxT( "gerbview" ) ) )
818 {
821 m_infoBar->ShowMessage( _( "This file was created by an older version of KiCad. "
822 "It will be converted to the new format when saved." ),
824 }
825
826 // Import footprints into a project-specific library
827 //==================================================
828 // TODO: This should be refactored out of here into somewhere specific to the Project Import
829 // E.g. KICAD_MANAGER_FRAME::ImportNonKiCadProject
830 if( aCtl & KICTL_IMPORT_LIB )
831 {
832 wxFileName loadedBoardFn( fullFileName );
833 wxString libNickName = loadedBoardFn.GetName();
834
835 // Extract a footprint library from the design and add it to the fp-lib-table
836 // The footprints are saved in a new .pretty library.
837 // If this library already exists, all previous footprints will be deleted
838 std::vector<FOOTPRINT*> loadedFootprints = pi->GetImportedCachedLibraryFootprints();
839 wxString newLibPath = CreateNewProjectLibrary( libNickName );
840
841 // Only create the new library if CreateNewLibrary succeeded (note that this fails if
842 // the library already exists and the user aborts after seeing the warning message
843 // which prompts the user to continue with overwrite or abort)
844 if( newLibPath.Length() > 0 )
845 {
847
848 for( FOOTPRINT* footprint : loadedFootprints )
849 {
850 try
851 {
852 if( !footprint->GetFPID().GetLibItemName().empty() ) // Handle old boards.
853 {
854 footprint->SetReference( "REF**" );
855 piSexpr->FootprintSave( newLibPath, footprint );
856 delete footprint;
857 }
858 }
859 catch( const IO_ERROR& ioe )
860 {
861 wxLogError( _( "Error saving footprint %s to project specific library." )
862 + wxS( "\n%s" ),
863 footprint->GetFPID().GetUniStringLibItemName(),
864 ioe.What() );
865 }
866 }
867
869 const wxString& project_env = PROJECT_VAR_NAME;
870 wxString rel_path, env_path;
871
872 wxASSERT_MSG( wxGetEnv( project_env, &env_path ),
873 wxT( "There is no project variable?" ) );
874
875 wxString result( newLibPath );
876
877 if( result.Replace( env_path, wxT( "$(" ) + project_env + wxT( ")" ) ) )
878 rel_path = result;
879
880 FP_LIB_TABLE_ROW* row = new FP_LIB_TABLE_ROW( libNickName, rel_path,
881 wxT( "KiCad" ), wxEmptyString );
882 prjlibtable->InsertRow( row );
883
884 wxString tblName = Prj().FootprintLibTblName();
885
886 try
887 {
888 PROJECT_PCB::PcbFootprintLibs( &Prj() )->Save( tblName );
889 }
890 catch( const IO_ERROR& ioe )
891 {
892 wxLogError( _( "Error saving project specific footprint library table." )
893 + wxS( "\n%s" ),
894 ioe.What() );
895 }
896
897 // Update footprint LIB_IDs to point to the just imported library
898 for( FOOTPRINT* footprint : GetBoard()->Footprints() )
899 {
900 LIB_ID libId = footprint->GetFPID();
901
902 if( libId.GetLibItemName().empty() )
903 continue;
904
905 libId.SetLibNickname( libNickName );
906 footprint->SetFPID( libId );
907 }
908 }
909 }
910 }
911
912 {
913 wxFileName fn;
914
915 fn.SetPath( Prj().GetProjectPath() );
916 fn.SetName( Prj().GetProjectName() );
918
919 wxString fname = fn.GetFullPath();
920
921 fname.Replace( WIN_STRING_DIR_SEP, UNIX_STRING_DIR_SEP );
922
923 GetBoard()->SetFileName( fname );
924 }
925
926 // Lock the file newly opened:
927 m_file_checker.reset( lock.release() );
928
929 if( !converted )
930 UpdateFileHistory( GetBoard()->GetFileName() );
931
932 std::vector<ZONE*> toFill;
933
934 // Rebuild list of nets (full ratsnest rebuild)
935 GetBoard()->BuildConnectivity( &progressReporter );
936
937 // Load project settings after setting up board; some of them depend on the nets list
940
941 // Syncs the UI (appearance panel, etc) with the loaded board and project
943
944 // Refresh the 3D view, if any
945 EDA_3D_VIEWER_FRAME* draw3DFrame = Get3DViewerFrame();
946
947 if( draw3DFrame )
948 draw3DFrame->NewDisplay();
949#if 0 && defined(DEBUG)
950 // Output the board object tree to stdout, but please run from command prompt:
951 GetBoard()->Show( 0, std::cout );
952#endif
953
954 // from EDA_APPL which was first loaded BOARD only:
955 {
956 /* For an obscure reason the focus is lost after loading a board file
957 * when starting up the process.
958 * (seems due to the recreation of the layer manager after loading the file)
959 * Give focus to main window and Drawpanel
960 * must be done for these 2 windows (for an obscure reason ...)
961 * Linux specific
962 * This is more a workaround than a fix.
963 */
964 SetFocus();
965 GetCanvas()->SetFocus();
966 }
967
968 return true;
969}
970
971
972bool PCB_EDIT_FRAME::SavePcbFile( const wxString& aFileName, bool addToHistory,
973 bool aChangeProject )
974{
975 // please, keep it simple. prompting goes elsewhere.
976 wxFileName pcbFileName = aFileName;
977
978 if( pcbFileName.GetExt() == FILEEXT::LegacyPcbFileExtension )
979 pcbFileName.SetExt( FILEEXT::KiCadPcbFileExtension );
980
981 // Write through symlinks, don't replace them
983
984 if( !IsWritable( pcbFileName ) )
985 {
986 wxString msg = wxString::Format( _( "Insufficient permissions to write file '%s'." ),
987 pcbFileName.GetFullPath() );
988
989 DisplayError( this, msg );
990 return false;
991 }
992
993 // TODO: these will break if we ever go multi-board
994 wxFileName projectFile( pcbFileName );
995 wxFileName rulesFile( pcbFileName );
996 wxString msg;
997
998 projectFile.SetExt( FILEEXT::ProjectFileExtension );
999 rulesFile.SetExt( FILEEXT::DesignRulesFileExtension );
1000
1001 if( projectFile.FileExists() )
1002 {
1004 }
1005 else if( aChangeProject )
1006 {
1007 Prj().SetReadOnly( false );
1008 GetSettingsManager()->SaveProjectAs( projectFile.GetFullPath() );
1009 }
1010
1011 wxFileName currentRules( GetDesignRulesPath() );
1012
1013 if( currentRules.FileExists() && !rulesFile.FileExists() && aChangeProject )
1014 KiCopyFile( currentRules.GetFullPath(), rulesFile.GetFullPath(), msg );
1015
1016 if( !msg.IsEmpty() )
1017 {
1018 DisplayError( this, wxString::Format( _( "Error saving custom rules file '%s'." ),
1019 rulesFile.GetFullPath() ) );
1020 }
1021
1022 if( projectFile.FileExists() )
1023 {
1024 // Save various DRC parameters, such as violation severities (which may have been
1025 // edited via the DRC dialog as well as the Board Setup dialog), DRC exclusions, etc.
1027
1030 }
1031
1032 wxString tempFile = wxFileName::CreateTempFileName( wxS( "pcbnew" ) );
1033 wxString upperTxt;
1034 wxString lowerTxt;
1035
1036 try
1037 {
1039
1040 pi->SaveBoard( tempFile, GetBoard(), nullptr );
1041 }
1042 catch( const IO_ERROR& ioe )
1043 {
1044 DisplayError( this, wxString::Format( _( "Error saving board file '%s'.\n%s" ),
1045 pcbFileName.GetFullPath(),
1046 ioe.What() ) );
1047
1048 lowerTxt.Printf( _( "Failed to create temporary file '%s'." ), tempFile );
1049
1050 SetMsgPanel( upperTxt, lowerTxt );
1051
1052 // In case we started a file but didn't fully write it, clean up
1053 wxRemoveFile( tempFile );
1054
1055 return false;
1056 }
1057
1058 // Preserve the permissions of the current file
1059 KIPLATFORM::IO::DuplicatePermissions( pcbFileName.GetFullPath(), tempFile );
1060
1061 // If save succeeded, replace the original with what we just wrote
1062 if( !wxRenameFile( tempFile, pcbFileName.GetFullPath() ) )
1063 {
1064 DisplayError( this, wxString::Format( _( "Error saving board file '%s'.\n"
1065 "Failed to rename temporary file '%s." ),
1066 pcbFileName.GetFullPath(),
1067 tempFile ) );
1068
1069 lowerTxt.Printf( _( "Failed to rename temporary file '%s'." ),
1070 tempFile );
1071
1072 SetMsgPanel( upperTxt, lowerTxt );
1073
1074 return false;
1075 }
1076
1077 if( !Kiface().IsSingle() )
1078 {
1079 WX_STRING_REPORTER backupReporter( &upperTxt );
1080
1081 if( GetSettingsManager()->TriggerBackupIfNeeded( backupReporter ) )
1082 upperTxt.clear();
1083 }
1084
1085 GetBoard()->SetFileName( pcbFileName.GetFullPath() );
1086
1087 // Update the lock in case it was a Save As
1088 LockFile( pcbFileName.GetFullPath() );
1089
1090 // Put the saved file in File History if requested
1091 if( addToHistory )
1092 UpdateFileHistory( GetBoard()->GetFileName() );
1093
1094 // Delete auto save file on successful save.
1095 wxFileName autoSaveFileName = pcbFileName;
1096
1097 autoSaveFileName.SetName( FILEEXT::AutoSaveFilePrefix + pcbFileName.GetName() );
1098
1099 if( autoSaveFileName.FileExists() )
1100 wxRemoveFile( autoSaveFileName.GetFullPath() );
1101
1102 lowerTxt.Printf( _( "File '%s' saved." ), pcbFileName.GetFullPath() );
1103
1104 SetStatusText( lowerTxt, 0 );
1105
1106 // Get rid of the old version conversion warning, or any other dismissable warning :)
1108 m_infoBar->Dismiss();
1109
1110 if( m_infoBar->IsShownOnScreen() && m_infoBar->HasCloseButton() )
1111 m_infoBar->Dismiss();
1112
1113 GetScreen()->SetContentModified( false );
1114 UpdateTitle();
1115 return true;
1116}
1117
1118
1119bool PCB_EDIT_FRAME::SavePcbCopy( const wxString& aFileName, bool aCreateProject )
1120{
1121 wxFileName pcbFileName( EnsureFileExtension( aFileName, FILEEXT::KiCadPcbFileExtension ) );
1122
1123 if( !IsWritable( pcbFileName ) )
1124 {
1125 DisplayError( this, wxString::Format( _( "Insufficient permissions to write file '%s'." ),
1126 pcbFileName.GetFullPath() ) );
1127 return false;
1128 }
1129
1130 // Save various DRC parameters, such as violation severities (which may have been
1131 // edited via the DRC dialog as well as the Board Setup dialog), DRC exclusions, etc.
1133
1135
1136 try
1137 {
1139
1140 wxASSERT( pcbFileName.IsAbsolute() );
1141
1142 pi->SaveBoard( pcbFileName.GetFullPath(), GetBoard(), nullptr );
1143 }
1144 catch( const IO_ERROR& ioe )
1145 {
1146 DisplayError( this, wxString::Format( _( "Error saving board file '%s'.\n%s" ),
1147 pcbFileName.GetFullPath(),
1148 ioe.What() ) );
1149
1150 return false;
1151 }
1152
1153 wxFileName projectFile( pcbFileName );
1154 wxFileName rulesFile( pcbFileName );
1155 wxString msg;
1156
1157 projectFile.SetExt( FILEEXT::ProjectFileExtension );
1158 rulesFile.SetExt( FILEEXT::DesignRulesFileExtension );
1159
1160 if( aCreateProject && !projectFile.FileExists() )
1161 GetSettingsManager()->SaveProjectCopy( projectFile.GetFullPath() );
1162
1163 wxFileName currentRules( GetDesignRulesPath() );
1164
1165 if( aCreateProject && currentRules.FileExists() && !rulesFile.FileExists() )
1166 KiCopyFile( currentRules.GetFullPath(), rulesFile.GetFullPath(), msg );
1167
1168 if( !msg.IsEmpty() )
1169 {
1170 DisplayError( this, wxString::Format( _( "Error saving custom rules file '%s'." ),
1171 rulesFile.GetFullPath() ) );
1172 }
1173
1174 DisplayInfoMessage( this, wxString::Format( _( "Board copied to:\n%s" ),
1175 pcbFileName.GetFullPath() ) );
1176
1177 return true;
1178}
1179
1180
1182{
1183 wxFileName tmpFileName;
1184
1185 // Don't run autosave if content has not been modified
1186 if( !IsContentModified() )
1187 return true;
1188
1189 wxString title = GetTitle(); // Save frame title, that can be modified by the save process
1190
1191 if( GetBoard()->GetFileName().IsEmpty() )
1192 {
1193 tmpFileName = wxFileName( PATHS::GetDefaultUserProjectsPath(), NAMELESS_PROJECT,
1195 GetBoard()->SetFileName( tmpFileName.GetFullPath() );
1196 }
1197 else
1198 {
1199 tmpFileName = Prj().AbsolutePath( GetBoard()->GetFileName() );
1200 }
1201
1202 wxFileName autoSaveFileName = tmpFileName;
1203
1204 // Auto save file name is the board file name prepended with autosaveFilePrefix string.
1205 autoSaveFileName.SetName( FILEEXT::AutoSaveFilePrefix + autoSaveFileName.GetName() );
1206
1207 if( !autoSaveFileName.IsOk() )
1208 return false;
1209
1210 // If the board file path is not writable, try writing to a platform specific temp file
1211 // path. If that path isn't writable, give up.
1212 if( !autoSaveFileName.IsDirWritable() )
1213 {
1214 autoSaveFileName.SetPath( wxFileName::GetTempDir() );
1215
1216 if( !autoSaveFileName.IsOk() || !autoSaveFileName.IsDirWritable() )
1217 return false;
1218 }
1219
1220 wxLogTrace( traceAutoSave,
1221 wxT( "Creating auto save file <" ) + autoSaveFileName.GetFullPath() + wxT( ">" ) );
1222
1223 if( SavePcbFile( autoSaveFileName.GetFullPath(), false, false ) )
1224 {
1226 GetBoard()->SetFileName( tmpFileName.GetFullPath() );
1227 UpdateTitle();
1228 m_autoSaveRequired = false;
1229 m_autoSavePending = false;
1230
1231 if( !Kiface().IsSingle() &&
1232 GetSettingsManager()->GetCommonSettings()->m_Backup.backup_on_autosave )
1233 {
1235 }
1236
1237 SetTitle( title ); // Restore initial frame title
1238
1239 return true;
1240 }
1241
1242 GetBoard()->SetFileName( tmpFileName.GetFullPath() );
1243
1244 SetTitle( title ); // Restore initial frame title
1245
1246 return false;
1247}
1248
1249
1250bool PCB_EDIT_FRAME::importFile( const wxString& aFileName, int aFileType,
1251 const STRING_UTF8_MAP* aProperties )
1252{
1253 m_importProperties = aProperties;
1254
1255 switch( (PCB_IO_MGR::PCB_FILE_T) aFileType )
1256 {
1258 case PCB_IO_MGR::EAGLE:
1261 return OpenProjectFiles( std::vector<wxString>( 1, aFileName ),
1263
1264 default: break;
1265 }
1266
1267 m_importProperties = nullptr;
1268
1269 return false;
1270}
1271
1272
1273void PCB_EDIT_FRAME::GenIPC2581File( wxCommandEvent& event )
1274{
1275 DIALOG_EXPORT_2581 dlg( this );
1276
1277 if( dlg.ShowModal() != wxID_OK )
1278 return;
1279
1280 wxFileName pcbFileName = dlg.GetOutputPath();
1281
1282 // Write through symlinks, don't replace them
1284
1285 if( pcbFileName.GetName().empty() )
1286 {
1287 DisplayError( this, _( "The board must be saved before generating IPC2581 file." ) );
1288 return;
1289 }
1290
1291 if( !IsWritable( pcbFileName ) )
1292 {
1293 wxString msg = wxString::Format( _( "Insufficient permissions to write file '%s'." ),
1294 pcbFileName.GetFullPath() );
1295
1296 DisplayError( this, msg );
1297 return;
1298 }
1299
1300 wxString tempFile = wxFileName::CreateTempFileName( wxS( "pcbnew_ipc" ) );
1301 wxString upperTxt;
1302 wxString lowerTxt;
1303 WX_PROGRESS_REPORTER reporter( this, _( "Generating IPC2581 file" ), 5 );
1304 STRING_UTF8_MAP props;
1305
1306 props["units"] = dlg.GetUnitsString();
1307 props["sigfig"] = dlg.GetPrecision();
1308 props["version"] = dlg.GetVersion();
1309 props["OEMRef"] = dlg.GetOEM();
1310 props["mpn"] = dlg.GetMPN();
1311 props["mfg"] = dlg.GetMfg();
1312 props["dist"] = dlg.GetDist();
1313 props["distpn"] = dlg.GetDistPN();
1314
1315 auto saveFile =
1316 [&]() -> bool
1317 {
1318 try
1319 {
1321 pi->SetProgressReporter( &reporter );
1322 pi->SaveBoard( tempFile, GetBoard(), &props );
1323 return true;
1324 }
1325 catch( const IO_ERROR& ioe )
1326 {
1327 DisplayError( this, wxString::Format( _( "Error generating IPC2581 file '%s'.\n%s" ),
1328 pcbFileName.GetFullPath(), ioe.What() ) );
1329
1330 lowerTxt.Printf( _( "Failed to create temporary file '%s'." ), tempFile );
1331
1332 SetMsgPanel( upperTxt, lowerTxt );
1333
1334 // In case we started a file but didn't fully write it, clean up
1335 wxRemoveFile( tempFile );
1336
1337 return false;
1338 }
1339 };
1340
1342 auto ret = tp.submit( saveFile );
1343
1344
1345 std::future_status status = ret.wait_for( std::chrono::milliseconds( 250 ) );
1346
1347 while( status != std::future_status::ready )
1348 {
1349 reporter.KeepRefreshing();
1350 status = ret.wait_for( std::chrono::milliseconds( 250 ) );
1351 }
1352
1353 try
1354 {
1355 if( !ret.get() )
1356 return;
1357 }
1358 catch( const std::exception& e )
1359 {
1360 wxLogError( "Exception in IPC2581 generation: %s", e.what() );
1361 GetScreen()->SetContentModified( false );
1362 return;
1363 }
1364
1365 // Preserve the permissions of the current file
1366 KIPLATFORM::IO::DuplicatePermissions( pcbFileName.GetFullPath(), tempFile );
1367
1368 if( dlg.GetCompress() )
1369 {
1370 wxFileName tempfn = pcbFileName;
1371 tempfn.SetExt( FILEEXT::Ipc2581FileExtension );
1372 wxFileName zipfn = tempFile;
1373 zipfn.SetExt( "zip" );
1374
1375 wxFFileOutputStream fnout( zipfn.GetFullPath() );
1376 wxZipOutputStream zip( fnout );
1377 wxFFileInputStream fnin( tempFile );
1378
1379 zip.PutNextEntry( tempfn.GetFullName() );
1380 fnin.Read( zip );
1381 zip.Close();
1382 fnout.Close();
1383
1384 wxRemoveFile( tempFile );
1385 tempFile = zipfn.GetFullPath();
1386 }
1387
1388 // If save succeeded, replace the original with what we just wrote
1389 if( !wxRenameFile( tempFile, pcbFileName.GetFullPath() ) )
1390 {
1391 DisplayError( this, wxString::Format( _( "Error generating IPC2581 file '%s'.\n"
1392 "Failed to rename temporary file '%s." ),
1393 pcbFileName.GetFullPath(),
1394 tempFile ) );
1395
1396 lowerTxt.Printf( _( "Failed to rename temporary file '%s'." ),
1397 tempFile );
1398
1399 SetMsgPanel( upperTxt, lowerTxt );
1400 }
1401
1402 GetScreen()->SetContentModified( false );
1403}
const char * name
Definition: DXF_plotter.cpp:57
KIFACE_BASE & Kiface()
Global KIFACE_BASE "get" accessor.
void SetContentModified(bool aModified=true)
Definition: base_screen.h:59
bool test(size_t pos) const
Definition: base_set.h:47
Information pertinent to a Pcbnew printed circuit board.
Definition: board.h:289
bool m_LegacyDesignSettingsLoaded
True if the legacy board design settings were loaded from a file.
Definition: board.h:372
GAL_SET m_LegacyVisibleItems
Definition: board.h:369
void BuildListOfNets()
Definition: board.h:827
void SetFileName(const wxString &aFileName)
Definition: board.h:324
bool BuildConnectivity(PROGRESS_REPORTER *aReporter=nullptr)
Build or rebuild the board connectivity database for the board, especially the list of connected item...
Definition: board.cpp:186
void SynchronizeNetsAndNetClasses(bool aResetTrackAndViaSizes)
Copy NETCLASS info to each NET, based on NET membership in a NETCLASS.
Definition: board.cpp:2033
LSET m_LegacyVisibleLayers
Visibility settings stored in board prior to 6.0, only used for loading legacy files.
Definition: board.h:368
void SetProject(PROJECT *aProject, bool aReferenceOnly=false)
Link a board to a given project.
Definition: board.cpp:196
const wxString & GetFileName() const
Definition: board.h:326
int GetFileFormatVersionAtLoad() const
Definition: board.h:393
const wxString & GetGenerator() const
Adds an item to the container.
Definition: board.h:396
void ClearProject()
Definition: board.cpp:235
BOARD_DESIGN_SETTINGS & GetDesignSettings() const
Definition: board.cpp:874
void SynchronizeProperties()
Copy the current project's text variables into the boards property cache.
Definition: board.cpp:2024
bool m_LegacyCopperEdgeClearanceLoaded
Definition: board.h:373
int GetCount() const
Return the number of objects in the list.
Definition: collector.h:81
wxString GetOEM() const
wxString GetPrecision() const
bool GetCompress() const
wxString GetMPN() const
wxString GetDistPN() const
wxString GetDist() const
wxString GetMfg() const
wxString GetUnitsString() const
wxString GetOutputPath() const
Class DIALOG_HTML_REPORTER.
WX_HTML_REPORT_BOX * m_Reporter
static std::vector< IMPORT_PROJECT_DESC > RunModal(wxWindow *aParent, const std::vector< IMPORT_PROJECT_DESC > &aProjectDesc)
Create and show a dialog (modal) and returns the data from it after completion.
static std::map< wxString, PCB_LAYER_ID > RunModal(wxWindow *aParent, const std::vector< INPUT_LAYER_DESC > &aLayerDesc)
Create and show a dialog (modal) and returns the data from it after completion.
Create and handle a window for the 3d viewer connected to a Kiway and a pcbboard.
void NewDisplay(bool aForceImmediateRedraw=false)
Reload and refresh (rebuild) the 3D scene.
virtual APP_SETTINGS_BASE * config() const
Returns the settings object used in SaveSettings(), and is overloaded in KICAD_MANAGER_FRAME.
virtual void CheckForAutoSaveFile(const wxFileName &aFileName)
Check if an auto save file exists for aFileName and takes the appropriate action depending on the use...
WX_INFOBAR * m_infoBar
void UpdateFileHistory(const wxString &FullFileName, FILE_HISTORY *aFileHistory=nullptr)
Update the list of recently opened files.
void ClearFileHistory(FILE_HISTORY *aFileHistory=nullptr)
Removes all files from the file history.
wxString GetMruPath() const
virtual void DeleteAutoSaveFile(const wxFileName &aFileName)
bool IsWritable(const wxFileName &aFileName, bool aVerbose=true)
Checks if aFileName can be written.
wxString GetFileFromHistory(int cmdId, const wxString &type, FILE_HISTORY *aFileHistory=nullptr)
Fetches the file name from the file history list.
void SetMruPath(const wxString &aPath)
WX_INFOBAR * GetInfoBar()
void ReleaseFile()
Release the current file marked in use.
std::unique_ptr< LOCKFILE > m_file_checker
void SetMsgPanel(const std::vector< MSG_PANEL_ITEM > &aList)
Clear the message panel and populates it with the contents of aList.
bool LockFile(const wxString &aFileName)
Mark a schematic file as being in use.
void SetFocus() override
void SetModified()
Definition: eda_item.cpp:64
bool IsModified() const
Definition: eda_item.h:106
bool GetCreateNewProject() const
Gets if this hook has attached controls to a dialog box.
void ReadCacheFromFile(const wxString &aFilePath) override
unsigned GetCount() const
Hold a record identifying a library accessed by the appropriate footprint library #PLUGIN object in t...
Definition: fp_lib_table.h:42
static const std::vector< KICAD_T > AllBoardItems
A scan list for all editable board items.
Definition: collectors.h:227
Hold an error message and may be used when throwing exceptions containing meaningful error messages.
Definition: ki_exception.h:77
virtual const wxString What() const
A composite of Problem() and Where()
Definition: exceptions.cpp:30
virtual const wxString Problem() const
what was the problem?
Definition: exceptions.cpp:46
Helper class to create more flexible dialogs, including 'do not show again' checkbox handling.
Definition: kidialog.h:43
void DoNotShowCheckbox(wxString file, int line)
Checks the 'do not show again' setting for the dialog.
Definition: kidialog.cpp:51
int ShowModal() override
Definition: kidialog.cpp:95
PROJECT & Prj() const
Return a reference to the PROJECT associated with this KIWAY.
Plugin class for import plugins that support remappable layers.
A logical library item identifier and consists of various portions much like a URI.
Definition: lib_id.h:49
int SetLibNickname(const UTF8 &aLibNickname)
Override the logical library name portion of the LIB_ID to aLibNickname.
Definition: lib_id.cpp:99
const UTF8 & GetLibItemName() const
Definition: lib_id.h:102
bool InsertRow(LIB_TABLE_ROW *aRow, bool doReplace=false)
Adds aRow if it does not already exist or if doReplace is true.
void Save(const wxString &aFileName) const
Write this library table to aFileName in s-expression form.
static REPORTER & GetInstance()
Definition: reporter.cpp:128
static wxString GetDefaultUserProjectsPath()
Gets the default path we point users to create projects.
Definition: paths.cpp:129
static TOOL_ACTION repairBoard
Definition: pcb_actions.h:537
wxString GetDesignRulesPath()
Return the absolute path to the design rules file for the currently-loaded board.
wxString CreateNewProjectLibrary(const wxString &aLibName=wxEmptyString, const wxString &aProposedName=wxEmptyString)
const VECTOR2I GetPageSizeIU() const override
Works off of GetPageSettings() to return the size of the paper page in the internal units of this par...
PCB_DRAW_PANEL_GAL * GetCanvas() const override
Return a pointer to GAL-based canvas of given EDA draw frame.
PCB_SCREEN * GetScreen() const override
Return a pointer to a BASE_SCREEN or one of its derivatives.
BOARD * GetBoard() const
EDA_3D_VIEWER_FRAME * Get3DViewerFrame()
The main frame for Pcbnew.
void LoadDrawingSheet()
Load the drawing sheet file.
void ResolveDRCExclusions(bool aCreateMarkers)
If aCreateMarkers then create DRC exclusion markers from the serialized data.
void SetBoard(BOARD *aBoard, PROGRESS_REPORTER *aReporter=nullptr) override
Set the #m_Pcb member in such as way as to ensure deleting any previous BOARD.
void GenIPC2581File(wxCommandEvent &event)
Create and IPC2581 output file.
bool doAutoSave() override
Perform auto save when the board has been modified and not saved within the auto save interval.
void OnModify() override
Must be called after a board change to set the modified flag.
void OnClearFileHistory(wxCommandEvent &aEvent)
bool SavePcbCopy(const wxString &aFileName, bool aCreateProject=false)
Write the board data structures to aFileName.
bool OpenProjectFiles(const std::vector< wxString > &aFileSet, int aCtl=0) override
Load a KiCad board (.kicad_pcb) from aFileName.
void onBoardLoaded()
Update the state of the GUI after a new board is loaded or created.
void SaveProjectLocalSettings() override
Save changes to the project local settings.
bool Files_io_from_id(int aId)
Read and write board files according to aId.
bool IsContentModified() const override
Get if the current board has been modified but not saved.
bool LoadProjectSettings()
Load the current project's file configuration settings which are pertinent to this PCB_EDIT_FRAME ins...
bool Clear_Pcb(bool doAskAboutUnsavedChanges, bool aFinal=false)
Delete all and reinitialize the current board.
Definition: initpcb.cpp:42
void Files_io(wxCommandEvent &event)
Call Files_io_from_id with the wxCommandEvent id.
void UpdateTitle()
Set the main window title bar text.
int inferLegacyEdgeClearance(BOARD *aBoard, bool aShowUserMsg=true)
const STRING_UTF8_MAP * m_importProperties
bool SavePcbFile(const wxString &aFileName, bool addToHistory=true, bool aChangeProject=true)
Write the board data structures to a aFileName.
void saveProjectSettings() override
Saves any design-related project settings associated with this frame.
bool importFile(const wxString &aFileName, int aFileType, const STRING_UTF8_MAP *aProperties=nullptr)
Load the given filename but sets the path to the current project path.
void OnFileHistory(wxCommandEvent &event)
static PLUGIN_REGISTRY * Instance()
Definition: pcb_io_mgr.h:93
static PCB_IO * PluginFind(PCB_FILE_T aFileType)
Return a #PLUGIN which the caller can use to import, export, save, or load design documents.
Definition: pcb_io_mgr.cpp:65
PCB_FILE_T
The set of file types that the PCB_IO_MGR knows about, and for which there has been a plugin written,...
Definition: pcb_io_mgr.h:56
@ FILE_TYPE_NONE
Definition: pcb_io_mgr.h:76
@ KICAD_SEXP
S-expression Pcbnew file format.
Definition: pcb_io_mgr.h:58
@ LEGACY
Legacy Pcbnew file formats prior to s-expression.
Definition: pcb_io_mgr.h:59
@ CADSTAR_PCB_ARCHIVE
Definition: pcb_io_mgr.h:63
static PCB_FILE_T FindPluginTypeFromBoardPath(const wxString &aFileName, int aCtl=0)
Return a plugin type given a path for a board file.
Definition: pcb_io_mgr.cpp:108
Collect all BOARD_ITEM objects on a given layer.
Definition: collectors.h:552
void Collect(BOARD_ITEM *aBoard, const std::vector< KICAD_T > &aTypes)
Test a BOARD_ITEM using this class's Inspector method, which does the collection.
Definition: collectors.cpp:536
void SetLayerId(PCB_LAYER_ID aLayerId)
Definition: collectors.h:558
bool KeepRefreshing(bool aWait=false) override
Update the UI dialog.
Plugin class for import plugins that support choosing a project.
LSET m_VisibleLayers
Board settings.
GAL_SET m_VisibleItems
The GAL layers (aka items) that are turned on for viewing (.
static FP_LIB_TABLE * PcbFootprintLibs(PROJECT *aProject)
Return the table of footprint libraries without Kiway.
Definition: project_pcb.cpp:37
virtual void SetReadOnly(bool aReadOnly=true)
Definition: project.h:144
virtual const wxString GetProjectFullName() const
Return the full path and name of the project.
Definition: project.cpp:129
virtual PROJECT_LOCAL_SETTINGS & GetLocalSettings() const
Definition: project.h:172
virtual const wxString FootprintLibTblName() const
Returns the path and filename of this project's footprint library table.
Definition: project.cpp:165
virtual const wxString AbsolutePath(const wxString &aFileName) const
Fix up aFileName if it is relative to the project's directory to be an absolute path and filename.
Definition: project.cpp:320
virtual bool IsNullProject() const
Check if this project is a null project (i.e.
Definition: project.cpp:153
void SaveProjectAs(const wxString &aFullPath, PROJECT *aProject=nullptr)
Sets the currently loaded project path and saves it (pointers remain valid) Note that this will not m...
void SaveProjectCopy(const wxString &aFullPath, PROJECT *aProject=nullptr)
Saves a copy of the current project under the given path.
bool SaveProject(const wxString &aFullPath=wxEmptyString, PROJECT *aProject=nullptr)
Saves a loaded project.
bool LoadProject(const wxString &aFullPath, bool aSetActive=true)
Loads a project or sets up a new project with a specified path.
bool UnloadProject(PROJECT *aProject, bool aSave=true)
Saves, unloads and unregisters the given PROJECT.
bool TriggerBackupIfNeeded(REPORTER &aReporter) const
Calls BackupProject if a new backup is needed according to the current backup policy.
PROJECT & Prj() const
A helper while we are not MDI-capable – return the one and only project.
A name/value tuple with unique names and optional values.
TOOL_MANAGER * m_toolManager
Definition: tools_holder.h:167
bool RunAction(const std::string &aActionName, T aParam)
Run the specified action immediately, pausing the current action to run the new one.
Definition: tool_manager.h:150
An 8 bit string that is assuredly encoded in UTF8, and supplies special conversion support to and fro...
Definition: utf8.h:72
bool empty() const
Definition: utf8.h:104
static void ResolvePossibleSymlinks(wxFileName &aFilename)
Definition: wx_filename.cpp:92
void Flush()
Build the HTML messages page.
bool HasMessage() const override
Returns true if the reporter client is non-empty.
void RemoveAllButtons()
Remove all the buttons that have been added by the user.
Definition: wx_infobar.cpp:304
bool HasCloseButton() const
Definition: wx_infobar.cpp:328
@ OUTDATED_SAVE
OUTDATED_SAVE Messages that should be cleared on save.
void Dismiss() override
Dismisses the infobar and updates the containing layout and AUI manager (if one is provided).
Definition: wx_infobar.cpp:190
void AddCloseButton(const wxString &aTooltip=_("Hide this message."))
Add the default close button to the infobar on the right side.
Definition: wx_infobar.cpp:294
MESSAGE_TYPE GetMessageType() const
Definition: wx_infobar.h:100
void ShowMessage(const wxString &aMessage, int aFlags=wxICON_INFORMATION) override
Show the info bar with the provided message and icon.
Definition: wx_infobar.cpp:154
Multi-thread safe progress reporter dialog, intended for use of tasks that parallel reporting back of...
A wrapper for reporting to a wxString object.
Definition: reporter.h:164
wxString EnsureFileExtension(const wxString &aFilename, const wxString &aExtension)
It's annoying to throw up nag dialogs when the extension isn't right.
Definition: common.cpp:424
bool AskOverrideLock(wxWindow *aParent, const wxString &aMessage)
Display a dialog indicating the file is already open, with an option to reset the lock.
Definition: confirm.cpp:44
bool IsOK(wxWindow *aParent, const wxString &aMessage)
Display a yes/no dialog with aMessage and returns the user response.
Definition: confirm.cpp:250
void DisplayError(wxWindow *aParent, const wxString &aText, int aDisplayTime)
Display an error or warning message box with aMessage.
Definition: confirm.cpp:170
void DisplayInfoMessage(wxWindow *aParent, const wxString &aMessage, const wxString &aExtraInfo)
Display an informational message box with aMessage.
Definition: confirm.cpp:222
bool HandleUnsavedChanges(wxWindow *aParent, const wxString &aMessage, const std::function< bool()> &aSaveFunction)
Display a dialog with Save, Cancel and Discard Changes buttons.
Definition: confirm.cpp:130
void DisplayErrorMessage(wxWindow *aParent, const wxString &aText, const wxString &aExtraInfo)
Display an error message with aMessage.
Definition: confirm.cpp:195
This file is part of the common library.
#define _(s)
Declaration of the eda_3d_viewer class.
FOOTPRINT_LIST_IMPL GFootprintList
The global footprint info table.
Definition: cvpcb.cpp:156
void KiCopyFile(const wxString &aSrcPath, const wxString &aDestPath, wxString &aErrors)
Definition: gestfich.cpp:305
#define WIN_STRING_DIR_SEP
Definition: gestfich.h:37
#define UNIX_STRING_DIR_SEP
Definition: gestfich.h:36
static const std::string ProjectFileExtension
static const std::string LegacyPcbFileExtension
static const std::string Ipc2581FileExtension
static const std::string AutoSaveFilePrefix
static const std::string DesignRulesFileExtension
static const std::string KiCadPcbFileExtension
static wxString PcbFileWildcard()
const wxChar *const traceAutoSave
Flag to enable auto save feature debug tracing.
@ ID_NEW_BOARD
Definition: id.h:76
@ ID_SAVE_BOARD
Definition: id.h:77
@ ID_LOAD_FILE
Definition: id.h:75
@ ID_SAVE_BOARD_AS
Definition: id.h:78
std::unique_ptr< T > IO_RELEASER
Helper to hold and release an IO_BASE object when exceptions are thrown.
Definition: io_mgr.h:33
#define THROW_IO_ERROR(msg)
Definition: ki_exception.h:39
PROJECT & Prj()
Definition: kicad.cpp:595
This file is part of the common library.
#define KICTL_CREATE
caller thinks requested project files may not exist.
Definition: kiway_player.h:76
#define KICTL_REVERT
reverting to a previously-saved (KiCad) file.
Definition: kiway_player.h:78
#define KICTL_IMPORT_LIB
import all footprints into a project library.
Definition: kiway_player.h:77
#define KICTL_KICAD_ONLY
chosen file is from KiCad according to user
Definition: kiway_player.h:75
#define KICTL_NONKICAD_ONLY
chosen file is non-KiCad according to user
Definition: kiway_player.h:74
@ GAL_LAYER_ID_BITMASK_END
This is the end of the layers used for visibility bit masks in legacy board files.
Definition: layer_ids.h:230
@ Edge_Cuts
Definition: layer_ids.h:113
@ Rescue
Definition: layer_ids.h:133
#define GAL_LAYER_INDEX(x)
Use this macro to convert a GAL layer to a 0-indexed offset from LAYER_VIAS.
Definition: layer_ids.h:273
File locking utilities.
This file contains miscellaneous commonly used macros and functions.
#define KI_FALLTHROUGH
The KI_FALLTHROUGH macro is to be used when switch statement cases should purposely fallthrough from ...
Definition: macros.h:83
bool RegisterApplicationRestart(const wxString &aCommandLine)
Registers the application for restart with the OS with the given command line string to pass as args.
Definition: unix/app.cpp:65
bool DuplicatePermissions(const wxString &aSrc, const wxString &aDest)
Duplicates the file security data from one file to another ensuring that they are the same between bo...
Definition: unix/io.cpp:40
#define SEXPR_BOARD_FILE_VERSION
Current s-expression file format version. 2 was the last legacy format version.
bool AskLoadBoardFileName(PCB_EDIT_FRAME *aParent, wxString *aFileName, int aCtl=0)
Show a wxFileDialog asking for a BOARD filename to open.
bool AskSaveBoardFileName(PCB_EDIT_FRAME *aParent, wxString *aFileName, bool *aCreateProject)
Put up a wxFileDialog asking for a BOARD filename to save.
@ ID_IMPORT_NON_KICAD_BOARD
Definition: pcbnew_id.h:19
@ ID_REVERT_BOARD
Definition: pcbnew_id.h:18
@ ID_MENU_RECOVER_BOARD_AUTOSAVE
Definition: pcbnew_id.h:81
@ ID_COPY_BOARD_AS
Definition: pcbnew_id.h:17
SETTINGS_MANAGER * GetSettingsManager()
PGM_BASE & Pgm()
The global Program "get" accessor.
Definition: pgm_base.cpp:1059
see class PGM_BASE
int64_t GetRunningMicroSecs()
An alternate way to calculate an elapsed time (in microsecondes) to class PROF_COUNTER.
#define PROJECT_VAR_NAME
A variable name whose value holds the current project directory.
Definition: project.h:39
#define NAMELESS_PROJECT
default name for nameless projects
Definition: project.h:42
int StrPrintf(std::string *result, const char *format,...)
This is like sprintf() but the output is appended to a std::string instead of to a character array.
Definition: richio.cpp:68
bool show_import_issues
Stored value for "show import issues" when importing non-KiCad designs to this application.
Definition: app_settings.h:146
Variant of PARSE_ERROR indicating that a syntax or related error was likely caused by a file generate...
Definition: ki_exception.h:176
Container that describes file type info.
Definition: io_base.h:40
std::vector< std::string > m_FileExtensions
Filter used for file pickers if m_IsFile is true.
Definition: io_base.h:42
bool m_CanRead
Whether the IO can read this file type.
Definition: io_base.h:45
static thread_pool * tp
Definition: thread_pool.cpp:30
BS::thread_pool thread_pool
Definition: thread_pool.h:30
thread_pool & GetKiCadThreadPool()
Get a reference to the current thread pool.
Definition: thread_pool.cpp:32
wxLogTrace helper definitions.
@ PCB_SHAPE_T
class PCB_SHAPE, a segment not on copper layers
Definition: typeinfo.h:88
wxString AddFileExtListToFilter(const std::vector< std::string > &aExts)
Build the wildcard extension file dialog wildcard filter to add to the base message dialog.
wxString formatWildcardExt(const wxString &aWildcard)
Format wildcard extension to support case sensitive file dialogs.
Definition of file extensions used in Kicad.