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
390
392
393 OnModify();
394 return true;
395 }
396
397 case ID_SAVE_BOARD:
398 if( !GetBoard()->GetFileName().IsEmpty() )
399 {
400 if( SavePcbFile( Prj().AbsolutePath( GetBoard()->GetFileName() ) ) )
401 {
402 m_autoSaveRequired = false;
403 return true;
404 }
405
406 return false;
407 }
408
410
411 case ID_COPY_BOARD_AS:
412 case ID_SAVE_BOARD_AS:
413 {
414 bool addToHistory = ( id == ID_SAVE_BOARD_AS );
415 wxString orig_name;
416
417 wxFileName::SplitPath( GetBoard()->GetFileName(), nullptr, nullptr, &orig_name, nullptr );
418
419 if( orig_name.IsEmpty() )
420 orig_name = NAMELESS_PROJECT;
421
422 wxFileName savePath( Prj().GetProjectFullName() );
423
424 if( !savePath.IsOk() || !savePath.IsDirWritable() )
425 {
426 savePath = GetMruPath();
427
428 if( !savePath.IsOk() || !savePath.IsDirWritable() )
430 }
431
432 wxFileName fn( savePath.GetPath(), orig_name, FILEEXT::KiCadPcbFileExtension );
433 wxString filename = fn.GetFullPath();
434 bool createProject = false;
435 bool success = false;
436
437 if( AskSaveBoardFileName( this, &filename, &createProject ) )
438 {
439 if( id == ID_COPY_BOARD_AS )
440 {
441 success = SavePcbCopy( filename, createProject );
442 }
443 else
444 {
445 success = SavePcbFile( filename, addToHistory, createProject );
446
447 if( success )
448 m_autoSaveRequired = false;
449 }
450 }
451
452 return success;
453 }
454
455 default:
456 return false;
457 }
458}
459
460
461int PCB_EDIT_FRAME::inferLegacyEdgeClearance( BOARD* aBoard, bool aShowUserMsg )
462{
463 PCB_LAYER_COLLECTOR collector;
464
465 collector.SetLayerId( Edge_Cuts );
466 collector.Collect( aBoard, GENERAL_COLLECTOR::AllBoardItems );
467
468 int edgeWidth = -1;
469 bool mixed = false;
470
471 for( int i = 0; i < collector.GetCount(); i++ )
472 {
473 if( collector[i]->Type() == PCB_SHAPE_T )
474 {
475 int itemWidth = static_cast<PCB_SHAPE*>( collector[i] )->GetWidth();
476
477 if( edgeWidth != -1 && edgeWidth != itemWidth )
478 {
479 mixed = true;
480 edgeWidth = std::max( edgeWidth, itemWidth );
481 }
482 else
483 {
484 edgeWidth = itemWidth;
485 }
486 }
487 }
488
489 if( mixed && aShowUserMsg )
490 {
491 // If they had different widths then we can't ensure that fills will be the same.
492 DisplayInfoMessage( this,
493 _( "If the zones on this board are refilled the Copper Edge "
494 "Clearance setting will be used (see Board Setup > Design "
495 "Rules > Constraints).\n This may result in different fills "
496 "from previous KiCad versions which used the line thicknesses "
497 "of the board boundary on the Edge Cuts layer." ) );
498 }
499
500 return std::max( 0, edgeWidth / 2 );
501}
502
503
504bool PCB_EDIT_FRAME::OpenProjectFiles( const std::vector<wxString>& aFileSet, int aCtl )
505{
506 // This is for python:
507 if( aFileSet.size() != 1 )
508 {
509 UTF8 msg = StrPrintf( "Pcbnew:%s() takes a single filename", __func__ );
510 DisplayError( this, msg );
511 return false;
512 }
513
514 wxString fullFileName( aFileSet[0] );
515 wxFileName wx_filename( fullFileName );
516 wxString msg;
517
518 if( Kiface().IsSingle() )
520
521 // We insist on caller sending us an absolute path, if it does not, we say it's a bug.
522 wxASSERT_MSG( wx_filename.IsAbsolute(), wxT( "Path is not absolute!" ) );
523
524 std::unique_ptr<LOCKFILE> lock = std::make_unique<LOCKFILE>( fullFileName );
525
526 if( !lock->Valid() && lock->IsLockedByMe() )
527 {
528 // If we cannot acquire the lock but we appear to be the one who
529 // locked it, check to see if there is another KiCad instance running.
530 // If there is not, then we can override the lock. This could happen if
531 // 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'." ), wx_filename.GetFullName(),
540 lock->GetUsername(), lock->GetHostname() );
541
542 if( !AskOverrideLock( this, msg ) )
543 return false;
544
545 lock->OverrideLock();
546 }
547
548 if( IsContentModified() )
549 {
550 if( !HandleUnsavedChanges( this, _( "The current PCB has been modified. Save changes?" ),
551 [&]() -> bool
552 {
553 return SavePcbFile( GetBoard()->GetFileName() );
554 } ) )
555 {
556 return false;
557 }
558 }
559
560 wxFileName pro = fullFileName;
561 pro.SetExt( FILEEXT::ProjectFileExtension );
562
563 bool is_new = !wxFileName::IsFileReadable( fullFileName );
564
565 // If its a non-existent schematic and caller thinks it exists
566 if( is_new && !( aCtl & KICTL_CREATE ) )
567 {
568 // notify user that fullFileName does not exist, ask if user wants to create it.
569 msg.Printf( _( "PCB '%s' does not exist. Do you wish to create it?" ), fullFileName );
570
571 if( !IsOK( this, msg ) )
572 return false;
573 }
574
575 // Get rid of any existing warnings about the old board
576 GetInfoBar()->Dismiss();
577
578 WX_PROGRESS_REPORTER progressReporter( this, is_new ? _( "Creating PCB" )
579 : _( "Loading PCB" ), 1 );
580
581 // No save prompt (we already prompted above), and only reset to a new blank board if new
582 Clear_Pcb( false, !is_new );
583
585
586 if( !is_new )
587 pluginType = PCB_IO_MGR::FindPluginTypeFromBoardPath( fullFileName, aCtl );
588
589 if( pluginType == PCB_IO_MGR::FILE_TYPE_NONE )
590 return false;
591
592 bool converted = pluginType != PCB_IO_MGR::LEGACY && pluginType != PCB_IO_MGR::KICAD_SEXP;
593
594 // Loading a project should only be done under carefully considered circumstances.
595
596 // The calling code should know not to ask me here to change projects unless
597 // it knows what consequences that will have on other KIFACEs running and using
598 // this same PROJECT. It can be very harmful if that calling code is stupid.
600
601 if( pro.GetFullPath() != mgr->Prj().GetProjectFullName() )
602 {
603 // calls SaveProject
605
607 mgr->UnloadProject( &mgr->Prj() );
608
609 mgr->LoadProject( pro.GetFullPath() );
610
611 // Do not allow saving a project if one doesn't exist. This normally happens if we are
612 // standalone and opening a board that has been moved from its project folder.
613 // For converted projects, we don't want to set the read-only flag because we want a project
614 // to be saved for the new file in case things like netclasses got migrated.
615 Prj().SetReadOnly( !pro.Exists() && !converted );
616 }
617
618 // Clear the cache footprint list which may be project specific
620
621 if( is_new )
622 {
623 // Link the existing blank board to the new project
624 GetBoard()->SetProject( &Prj() );
625
626 GetBoard()->SetFileName( fullFileName );
627
628 OnModify();
629 }
630 else
631 {
632 BOARD* loadedBoard = nullptr; // it will be set to non-NULL if loaded OK
634
635 LAYER_REMAPPABLE_PLUGIN* layerRemappableIO = dynamic_cast<LAYER_REMAPPABLE_PLUGIN*>( pi.get() );
636
637 if( layerRemappableIO )
638 {
639 layerRemappableIO->RegisterLayerMappingCallback(
640 std::bind( DIALOG_IMPORTED_LAYERS::GetMapModal, this, std::placeholders::_1 ) );
641 }
642
643 PROJECT_CHOOSER_PLUGIN* projectChooserIO = dynamic_cast<PROJECT_CHOOSER_PLUGIN*>( pi.get() );
644
645 if( projectChooserIO )
646 {
647 projectChooserIO->RegisterChooseProjectCallback(
649 std::placeholders::_1 ) );
650 }
651
652 if( ( aCtl & KICTL_REVERT ) )
653 {
654 DeleteAutoSaveFile( fullFileName );
655 }
656 else
657 {
658 // This will rename the file if there is an autosave and the user wants to recover
659 CheckForAutoSaveFile( fullFileName );
660 }
661
662 DIALOG_HTML_REPORTER errorReporter( this );
663 bool failedLoad = false;
664
665 try
666 {
667 if( pi == nullptr )
668 {
669 // There was no plugin found, e.g. due to invalid file extension, file header,...
670 THROW_IO_ERROR( _( "File format is not supported" ) );
671 }
672
673 STRING_UTF8_MAP props;
674
676 props.insert( m_importProperties->begin(), m_importProperties->end() );
677
678 // PCB_IO_EAGLE can use this info to center the BOARD, but it does not yet.
679 props["page_width"] = std::to_string( GetPageSizeIU().x );
680 props["page_height"] = std::to_string( GetPageSizeIU().y );
681
682 pi->SetQueryUserCallback(
683 [&]( wxString aTitle, int aIcon, wxString aMessage, wxString aAction ) -> bool
684 {
685 KIDIALOG dlg( nullptr, aMessage, aTitle, wxOK | wxCANCEL | aIcon );
686
687 if( !aAction.IsEmpty() )
688 dlg.SetOKLabel( aAction );
689
690 dlg.DoNotShowCheckbox( aMessage, 0 );
691
692 return dlg.ShowModal() == wxID_OK;
693 } );
694
695#if USE_INSTRUMENTATION
696 // measure the time to load a BOARD.
697 int64_t startTime = GetRunningMicroSecs();
698#endif
699 if( config()->m_System.show_import_issues )
700 pi->SetReporter( errorReporter.m_Reporter );
701 else
702 pi->SetReporter( &NULL_REPORTER::GetInstance() );
703
704 pi->SetProgressReporter( &progressReporter );
705 loadedBoard = pi->LoadBoard( fullFileName, nullptr, &props, &Prj() );
706
707#if USE_INSTRUMENTATION
708 int64_t stopTime = GetRunningMicroSecs();
709 printf( "PCB_IO::Load(): %u usecs\n", stopTime - startTime );
710#endif
711 }
712 catch( const FUTURE_FORMAT_ERROR& ffe )
713 {
714 msg.Printf( _( "Error loading PCB '%s'." ), fullFileName );
715 progressReporter.Hide();
716 DisplayErrorMessage( this, msg, ffe.Problem() );
717
718 failedLoad = true;
719 }
720 catch( const IO_ERROR& ioe )
721 {
722 if( ioe.Problem() != wxT( "CANCEL" ) )
723 {
724 msg.Printf( _( "Error loading PCB '%s'." ), fullFileName );
725 progressReporter.Hide();
726 DisplayErrorMessage( this, msg, ioe.What() );
727 }
728
729 failedLoad = true;
730 }
731 catch( const std::bad_alloc& )
732 {
733 msg.Printf( _( "Memory exhausted loading PCB '%s'" ), fullFileName );
734 progressReporter.Hide();
735 DisplayErrorMessage( this, msg, wxEmptyString );
736
737 failedLoad = true;
738 }
739
740 if( failedLoad || !loadedBoard )
741 {
742 // We didn't create a new blank board above, so do that now
743 Clear_Pcb( false );
744
745 return false;
746 }
747
748 // This fixes a focus issue after the progress reporter is done on GTK. It shouldn't
749 // cause any issues on macOS and Windows. If it does, it will have to be conditionally
750 // compiled.
751 Raise();
752
753 if( errorReporter.m_Reporter->HasMessage() )
754 {
755 errorReporter.m_Reporter->Flush(); // Build HTML messages
756 errorReporter.ShowModal();
757 }
758
759 // Skip (possibly expensive) connectivity build here; we build it below after load
760 SetBoard( loadedBoard, false, &progressReporter );
761
762 if( GFootprintList.GetCount() == 0 )
763 GFootprintList.ReadCacheFromFile( Prj().GetProjectPath() + wxT( "fp-info-cache" ) );
764
765 if( loadedBoard->m_LegacyDesignSettingsLoaded )
766 {
767 Prj().SetReadOnly( false );
768
769 // Before we had a copper edge clearance setting, the edge line widths could be used
770 // as a kludge to control them. So if there's no setting then infer it from the
771 // edge widths.
772 if( !loadedBoard->m_LegacyCopperEdgeClearanceLoaded )
773 {
774 // Do not show the inferred edge clearance warning dialog when loading third
775 // party boards. For some reason the dialog completely hangs all of KiCad and
776 // the imported board cannot be saved.
777 int edgeClearance = inferLegacyEdgeClearance( loadedBoard, !converted );
778 loadedBoard->GetDesignSettings().m_CopperEdgeClearance = edgeClearance;
779 }
780
781 // On save; design settings will be removed from the board
782 loadedBoard->SetModified();
783 }
784
785 // Move legacy view settings to local project settings
786 if( !loadedBoard->m_LegacyVisibleLayers.test( Rescue ) )
787 {
789 loadedBoard->SetModified();
790 }
791
793 {
795 loadedBoard->SetModified();
796 }
797
798 // we should not ask PCB_IOs to do these items:
799 loadedBoard->BuildListOfNets();
800 ResolveDRCExclusions( true );
802
803 if( loadedBoard->IsModified() )
804 OnModify();
805 else
806 GetScreen()->SetContentModified( false );
807
808 if( ( pluginType == PCB_IO_MGR::LEGACY )
809 || ( pluginType == PCB_IO_MGR::KICAD_SEXP
811 && loadedBoard->GetGenerator().Lower() != wxT( "gerbview" ) ) )
812 {
815 m_infoBar->ShowMessage( _( "This file was created by an older version of KiCad. "
816 "It will be converted to the new format when saved." ),
818 }
819
820 // Import footprints into a project-specific library
821 //==================================================
822 // TODO: This should be refactored out of here into somewhere specific to the Project Import
823 // E.g. KICAD_MANAGER_FRAME::ImportNonKiCadProject
824 if( aCtl & KICTL_IMPORT_LIB )
825 {
826 wxFileName loadedBoardFn( fullFileName );
827 wxString libNickName = loadedBoardFn.GetName();
828
829 // Extract a footprint library from the design and add it to the fp-lib-table
830 // The footprints are saved in a new .pretty library.
831 // If this library already exists, all previous footprints will be deleted
832 std::vector<FOOTPRINT*> loadedFootprints = pi->GetImportedCachedLibraryFootprints();
833 wxString newLibPath = CreateNewProjectLibrary( libNickName );
834
835 // Only create the new library if CreateNewLibrary succeeded (note that this fails if
836 // the library already exists and the user aborts after seeing the warning message
837 // which prompts the user to continue with overwrite or abort)
838 if( newLibPath.Length() > 0 )
839 {
841
842 for( FOOTPRINT* footprint : loadedFootprints )
843 {
844 try
845 {
846 if( !footprint->GetFPID().GetLibItemName().empty() ) // Handle old boards.
847 {
848 footprint->SetReference( "REF**" );
849 piSexpr->FootprintSave( newLibPath, footprint );
850 delete footprint;
851 }
852 }
853 catch( const IO_ERROR& ioe )
854 {
855 wxLogError( _( "Error saving footprint %s to project specific library." )
856 + wxS( "\n%s" ),
857 footprint->GetFPID().GetUniStringLibItemName(),
858 ioe.What() );
859 }
860 }
861
863 const wxString& project_env = PROJECT_VAR_NAME;
864 wxString rel_path, env_path;
865
866 wxASSERT_MSG( wxGetEnv( project_env, &env_path ),
867 wxT( "There is no project variable?" ) );
868
869 wxString result( newLibPath );
870
871 if( result.Replace( env_path, wxT( "$(" ) + project_env + wxT( ")" ) ) )
872 rel_path = result;
873
874 FP_LIB_TABLE_ROW* row = new FP_LIB_TABLE_ROW( libNickName, rel_path,
875 wxT( "KiCad" ), wxEmptyString );
876 prjlibtable->InsertRow( row );
877
878 wxString tblName = Prj().FootprintLibTblName();
879
880 try
881 {
882 PROJECT_PCB::PcbFootprintLibs( &Prj() )->Save( tblName );
883 }
884 catch( const IO_ERROR& ioe )
885 {
886 wxLogError( _( "Error saving project specific footprint library table." )
887 + wxS( "\n%s" ),
888 ioe.What() );
889 }
890
891 // Update footprint LIB_IDs to point to the just imported library
892 for( FOOTPRINT* footprint : GetBoard()->Footprints() )
893 {
894 LIB_ID libId = footprint->GetFPID();
895
896 if( libId.GetLibItemName().empty() )
897 continue;
898
899 libId.SetLibNickname( libNickName );
900 footprint->SetFPID( libId );
901 }
902 }
903 }
904 }
905
906 {
907 wxFileName fn = fullFileName;
908
909 if( converted )
910 fn.SetExt( FILEEXT::PcbFileExtension );
911
912 wxString fname = fn.GetFullPath();
913
914 fname.Replace( WIN_STRING_DIR_SEP, UNIX_STRING_DIR_SEP );
915
916 GetBoard()->SetFileName( fname );
917 }
918
919 // Lock the file newly opened:
920 m_file_checker.reset( lock.release() );
921
922 if( !converted )
923 UpdateFileHistory( GetBoard()->GetFileName() );
924
925 std::vector<ZONE*> toFill;
926
927 // Rebuild list of nets (full ratsnest rebuild)
928 GetBoard()->BuildConnectivity( &progressReporter );
929
930 // Load project settings after setting up board; some of them depend on the nets list
932
933 // Syncs the UI (appearance panel, etc) with the loaded board and project
935
936 // Refresh the 3D view, if any
937 EDA_3D_VIEWER_FRAME* draw3DFrame = Get3DViewerFrame();
938
939 if( draw3DFrame )
940 draw3DFrame->NewDisplay();
941#if 0 && defined(DEBUG)
942 // Output the board object tree to stdout, but please run from command prompt:
943 GetBoard()->Show( 0, std::cout );
944#endif
945
946 // from EDA_APPL which was first loaded BOARD only:
947 {
948 /* For an obscure reason the focus is lost after loading a board file
949 * when starting up the process.
950 * (seems due to the recreation of the layer manager after loading the file)
951 * Give focus to main window and Drawpanel
952 * must be done for these 2 windows (for an obscure reason ...)
953 * Linux specific
954 * This is more a workaround than a fix.
955 */
956 SetFocus();
957 GetCanvas()->SetFocus();
958 }
959
960 return true;
961}
962
963
964bool PCB_EDIT_FRAME::SavePcbFile( const wxString& aFileName, bool addToHistory,
965 bool aChangeProject )
966{
967 // please, keep it simple. prompting goes elsewhere.
968 wxFileName pcbFileName = aFileName;
969
970 if( pcbFileName.GetExt() == FILEEXT::LegacyPcbFileExtension )
971 pcbFileName.SetExt( FILEEXT::KiCadPcbFileExtension );
972
973 // Write through symlinks, don't replace them
975
976 if( !IsWritable( pcbFileName ) )
977 {
978 wxString msg = wxString::Format( _( "Insufficient permissions to write file '%s'." ),
979 pcbFileName.GetFullPath() );
980
981 DisplayError( this, msg );
982 return false;
983 }
984
985 // TODO: these will break if we ever go multi-board
986 wxFileName projectFile( pcbFileName );
987 wxFileName rulesFile( pcbFileName );
988 wxString msg;
989
990 projectFile.SetExt( FILEEXT::ProjectFileExtension );
991 rulesFile.SetExt( FILEEXT::DesignRulesFileExtension );
992
993 if( projectFile.FileExists() )
994 {
996 }
997 else if( aChangeProject )
998 {
999 Prj().SetReadOnly( false );
1000 GetSettingsManager()->SaveProjectAs( projectFile.GetFullPath() );
1001 }
1002
1003 wxFileName currentRules( GetDesignRulesPath() );
1004
1005 if( currentRules.FileExists() && !rulesFile.FileExists() && aChangeProject )
1006 KiCopyFile( currentRules.GetFullPath(), rulesFile.GetFullPath(), msg );
1007
1008 if( !msg.IsEmpty() )
1009 {
1010 DisplayError( this, wxString::Format( _( "Error saving custom rules file '%s'." ),
1011 rulesFile.GetFullPath() ) );
1012 }
1013
1014 if( projectFile.FileExists() )
1015 {
1016 // Save various DRC parameters, such as violation severities (which may have been
1017 // edited via the DRC dialog as well as the Board Setup dialog), DRC exclusions, etc.
1019
1022 }
1023
1024 wxString tempFile = wxFileName::CreateTempFileName( wxS( "pcbnew" ) );
1025 wxString upperTxt;
1026 wxString lowerTxt;
1027
1028 try
1029 {
1031
1032 pi->SaveBoard( tempFile, GetBoard(), nullptr );
1033 }
1034 catch( const IO_ERROR& ioe )
1035 {
1036 DisplayError( this, wxString::Format( _( "Error saving board file '%s'.\n%s" ),
1037 pcbFileName.GetFullPath(),
1038 ioe.What() ) );
1039
1040 lowerTxt.Printf( _( "Failed to create temporary file '%s'." ), tempFile );
1041
1042 SetMsgPanel( upperTxt, lowerTxt );
1043
1044 // In case we started a file but didn't fully write it, clean up
1045 wxRemoveFile( tempFile );
1046
1047 return false;
1048 }
1049
1050 // Preserve the permissions of the current file
1051 KIPLATFORM::IO::DuplicatePermissions( pcbFileName.GetFullPath(), tempFile );
1052
1053 // If save succeeded, replace the original with what we just wrote
1054 if( !wxRenameFile( tempFile, pcbFileName.GetFullPath() ) )
1055 {
1056 DisplayError( this, wxString::Format( _( "Error saving board file '%s'.\n"
1057 "Failed to rename temporary file '%s." ),
1058 pcbFileName.GetFullPath(),
1059 tempFile ) );
1060
1061 lowerTxt.Printf( _( "Failed to rename temporary file '%s'." ),
1062 tempFile );
1063
1064 SetMsgPanel( upperTxt, lowerTxt );
1065
1066 return false;
1067 }
1068
1069 if( !Kiface().IsSingle() )
1070 {
1071 WX_STRING_REPORTER backupReporter( &upperTxt );
1072
1073 if( GetSettingsManager()->TriggerBackupIfNeeded( backupReporter ) )
1074 upperTxt.clear();
1075 }
1076
1077 GetBoard()->SetFileName( pcbFileName.GetFullPath() );
1078
1079 // Update the lock in case it was a Save As
1080 LockFile( pcbFileName.GetFullPath() );
1081
1082 // Put the saved file in File History if requested
1083 if( addToHistory )
1084 UpdateFileHistory( GetBoard()->GetFileName() );
1085
1086 // Delete auto save file on successful save.
1087 wxFileName autoSaveFileName = pcbFileName;
1088
1089 autoSaveFileName.SetName( FILEEXT::AutoSaveFilePrefix + pcbFileName.GetName() );
1090
1091 if( autoSaveFileName.FileExists() )
1092 wxRemoveFile( autoSaveFileName.GetFullPath() );
1093
1094 lowerTxt.Printf( _( "File '%s' saved." ), pcbFileName.GetFullPath() );
1095
1096 SetStatusText( lowerTxt, 0 );
1097
1098 // Get rid of the old version conversion warning, or any other dismissable warning :)
1100 m_infoBar->Dismiss();
1101
1102 if( m_infoBar->IsShownOnScreen() && m_infoBar->HasCloseButton() )
1103 m_infoBar->Dismiss();
1104
1105 GetScreen()->SetContentModified( false );
1106 UpdateTitle();
1107 return true;
1108}
1109
1110
1111bool PCB_EDIT_FRAME::SavePcbCopy( const wxString& aFileName, bool aCreateProject )
1112{
1113 wxFileName pcbFileName( EnsureFileExtension( aFileName, FILEEXT::KiCadPcbFileExtension ) );
1114
1115 if( !IsWritable( pcbFileName ) )
1116 {
1117 DisplayError( this, wxString::Format( _( "Insufficient permissions to write file '%s'." ),
1118 pcbFileName.GetFullPath() ) );
1119 return false;
1120 }
1121
1122 // Save various DRC parameters, such as violation severities (which may have been
1123 // edited via the DRC dialog as well as the Board Setup dialog), DRC exclusions, etc.
1125
1127
1128 try
1129 {
1131
1132 wxASSERT( pcbFileName.IsAbsolute() );
1133
1134 pi->SaveBoard( pcbFileName.GetFullPath(), GetBoard(), nullptr );
1135 }
1136 catch( const IO_ERROR& ioe )
1137 {
1138 DisplayError( this, wxString::Format( _( "Error saving board file '%s'.\n%s" ),
1139 pcbFileName.GetFullPath(),
1140 ioe.What() ) );
1141
1142 return false;
1143 }
1144
1145 wxFileName projectFile( pcbFileName );
1146 wxFileName rulesFile( pcbFileName );
1147 wxString msg;
1148
1149 projectFile.SetExt( FILEEXT::ProjectFileExtension );
1150 rulesFile.SetExt( FILEEXT::DesignRulesFileExtension );
1151
1152 if( aCreateProject && !projectFile.FileExists() )
1153 GetSettingsManager()->SaveProjectCopy( projectFile.GetFullPath() );
1154
1155 wxFileName currentRules( GetDesignRulesPath() );
1156
1157 if( aCreateProject && currentRules.FileExists() && !rulesFile.FileExists() )
1158 KiCopyFile( currentRules.GetFullPath(), rulesFile.GetFullPath(), msg );
1159
1160 if( !msg.IsEmpty() )
1161 {
1162 DisplayError( this, wxString::Format( _( "Error saving custom rules file '%s'." ),
1163 rulesFile.GetFullPath() ) );
1164 }
1165
1166 DisplayInfoMessage( this, wxString::Format( _( "Board copied to:\n%s" ),
1167 pcbFileName.GetFullPath() ) );
1168
1169 return true;
1170}
1171
1172
1174{
1175 wxFileName tmpFileName;
1176
1177 // Don't run autosave if content has not been modified
1178 if( !IsContentModified() )
1179 return true;
1180
1181 wxString title = GetTitle(); // Save frame title, that can be modified by the save process
1182
1183 if( GetBoard()->GetFileName().IsEmpty() )
1184 {
1185 tmpFileName = wxFileName( PATHS::GetDefaultUserProjectsPath(), NAMELESS_PROJECT,
1187 GetBoard()->SetFileName( tmpFileName.GetFullPath() );
1188 }
1189 else
1190 {
1191 tmpFileName = Prj().AbsolutePath( GetBoard()->GetFileName() );
1192 }
1193
1194 wxFileName autoSaveFileName = tmpFileName;
1195
1196 // Auto save file name is the board file name prepended with autosaveFilePrefix string.
1197 autoSaveFileName.SetName( FILEEXT::AutoSaveFilePrefix + autoSaveFileName.GetName() );
1198
1199 if( !autoSaveFileName.IsOk() )
1200 return false;
1201
1202 // If the board file path is not writable, try writing to a platform specific temp file
1203 // path. If that path isn't writable, give up.
1204 if( !autoSaveFileName.IsDirWritable() )
1205 {
1206 autoSaveFileName.SetPath( wxFileName::GetTempDir() );
1207
1208 if( !autoSaveFileName.IsOk() || !autoSaveFileName.IsDirWritable() )
1209 return false;
1210 }
1211
1212 wxLogTrace( traceAutoSave,
1213 wxT( "Creating auto save file <" ) + autoSaveFileName.GetFullPath() + wxT( ">" ) );
1214
1215 if( SavePcbFile( autoSaveFileName.GetFullPath(), false, false ) )
1216 {
1218 GetBoard()->SetFileName( tmpFileName.GetFullPath() );
1219 UpdateTitle();
1220 m_autoSaveRequired = false;
1221 m_autoSavePending = false;
1222
1223 if( !Kiface().IsSingle() &&
1224 GetSettingsManager()->GetCommonSettings()->m_Backup.backup_on_autosave )
1225 {
1227 }
1228
1229 SetTitle( title ); // Restore initial frame title
1230
1231 return true;
1232 }
1233
1234 GetBoard()->SetFileName( tmpFileName.GetFullPath() );
1235
1236 SetTitle( title ); // Restore initial frame title
1237
1238 return false;
1239}
1240
1241
1242bool PCB_EDIT_FRAME::importFile( const wxString& aFileName, int aFileType,
1243 const STRING_UTF8_MAP* aProperties )
1244{
1245 m_importProperties = aProperties;
1246
1247 switch( (PCB_IO_MGR::PCB_FILE_T) aFileType )
1248 {
1250 case PCB_IO_MGR::EAGLE:
1253 return OpenProjectFiles( std::vector<wxString>( 1, aFileName ),
1255
1256 default: break;
1257 }
1258
1259 m_importProperties = nullptr;
1260
1261 return false;
1262}
1263
1264
1265void PCB_EDIT_FRAME::GenIPC2581File( wxCommandEvent& event )
1266{
1267 DIALOG_EXPORT_2581 dlg( this );
1268
1269 if( dlg.ShowModal() != wxID_OK )
1270 return;
1271
1272 wxFileName pcbFileName = dlg.GetOutputPath();
1273
1274 // Write through symlinks, don't replace them
1276
1277 if( pcbFileName.GetName().empty() )
1278 {
1279 DisplayError( this, _( "The board must be saved before generating IPC2581 file." ) );
1280 return;
1281 }
1282
1283 if( !IsWritable( pcbFileName ) )
1284 {
1285 wxString msg = wxString::Format( _( "Insufficient permissions to write file '%s'." ),
1286 pcbFileName.GetFullPath() );
1287
1288 DisplayError( this, msg );
1289 return;
1290 }
1291
1292 wxString tempFile = wxFileName::CreateTempFileName( wxS( "pcbnew_ipc" ) );
1293 wxString upperTxt;
1294 wxString lowerTxt;
1295 WX_PROGRESS_REPORTER reporter( this, _( "Generating IPC2581 file" ), 5 );
1296 STRING_UTF8_MAP props;
1297
1298 props["units"] = dlg.GetUnitsString();
1299 props["sigfig"] = dlg.GetPrecision();
1300 props["version"] = dlg.GetVersion();
1301 props["OEMRef"] = dlg.GetOEM();
1302 props["mpn"] = dlg.GetMPN();
1303 props["mfg"] = dlg.GetMfg();
1304 props["dist"] = dlg.GetDist();
1305 props["distpn"] = dlg.GetDistPN();
1306
1307 auto saveFile = [&]() -> bool
1308 {
1309 try
1310 {
1312 pi->SetProgressReporter( &reporter );
1313 pi->SaveBoard( tempFile, GetBoard(), &props );
1314 return true;
1315 }
1316 catch( const IO_ERROR& ioe )
1317 {
1318 DisplayError( this, wxString::Format( _( "Error generating IPC2581 file '%s'.\n%s" ),
1319 pcbFileName.GetFullPath(), ioe.What() ) );
1320
1321 lowerTxt.Printf( _( "Failed to create temporary file '%s'." ), tempFile );
1322
1323 SetMsgPanel( upperTxt, lowerTxt );
1324
1325 // In case we started a file but didn't fully write it, clean up
1326 wxRemoveFile( tempFile );
1327
1328 return false;
1329 }
1330 };
1331
1333 auto ret = tp.submit( saveFile );
1334
1335
1336 std::future_status status = ret.wait_for( std::chrono::milliseconds( 250 ) );
1337
1338 while( status != std::future_status::ready )
1339 {
1340 reporter.KeepRefreshing();
1341 status = ret.wait_for( std::chrono::milliseconds( 250 ) );
1342 }
1343
1344 try
1345 {
1346 if( !ret.get() )
1347 return;
1348 }
1349 catch(const std::exception& e)
1350 {
1351 wxLogError( "Exception in IPC2581 generation: %s", e.what() );
1352 GetScreen()->SetContentModified( false );
1353 return;
1354 }
1355
1356 // Preserve the permissions of the current file
1357 KIPLATFORM::IO::DuplicatePermissions( pcbFileName.GetFullPath(), tempFile );
1358
1359 if( dlg.GetCompress() )
1360 {
1361 wxFileName tempfn = pcbFileName;
1362 tempfn.SetExt( FILEEXT::Ipc2581FileExtension );
1363 wxFileName zipfn = tempFile;
1364 zipfn.SetExt( "zip" );
1365
1366 wxFFileOutputStream fnout( zipfn.GetFullPath() );
1367 wxZipOutputStream zip( fnout );
1368 wxFFileInputStream fnin( tempFile );
1369
1370 zip.PutNextEntry( tempfn.GetFullName() );
1371 fnin.Read( zip );
1372 zip.Close();
1373 fnout.Close();
1374
1375 wxRemoveFile( tempFile );
1376 tempFile = zipfn.GetFullPath();
1377 }
1378
1379 // If save succeeded, replace the original with what we just wrote
1380 if( !wxRenameFile( tempFile, pcbFileName.GetFullPath() ) )
1381 {
1382 DisplayError( this, wxString::Format( _( "Error generating IPC2581 file '%s'.\n"
1383 "Failed to rename temporary file '%s." ),
1384 pcbFileName.GetFullPath(),
1385 tempFile ) );
1386
1387 lowerTxt.Printf( _( "Failed to rename temporary file '%s'." ),
1388 tempFile );
1389
1390 SetMsgPanel( upperTxt, lowerTxt );
1391 }
1392
1393 GetScreen()->SetContentModified( false );
1394}
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
Information pertinent to a Pcbnew printed circuit board.
Definition: board.h:282
bool m_LegacyDesignSettingsLoaded
True if the legacy board design settings were loaded from a file.
Definition: board.h:365
GAL_SET m_LegacyVisibleItems
Definition: board.h:362
void BuildListOfNets()
Definition: board.h:816
void SetFileName(const wxString &aFileName)
Definition: board.h:317
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:180
void SynchronizeNetsAndNetClasses(bool aResetTrackAndViaSizes)
Copy NETCLASS info to each NET, based on NET membership in a NETCLASS.
Definition: board.cpp:1943
LSET m_LegacyVisibleLayers
Visibility settings stored in board prior to 6.0, only used for loading legacy files.
Definition: board.h:361
void SetProject(PROJECT *aProject, bool aReferenceOnly=false)
Link a board to a given project.
Definition: board.cpp:190
const wxString & GetFileName() const
Definition: board.h:319
int GetFileFormatVersionAtLoad() const
Definition: board.h:386
const wxString & GetGenerator() const
Adds an item to the container.
Definition: board.h:389
void ClearProject()
Definition: board.cpp:229
BOARD_DESIGN_SETTINGS & GetDesignSettings() const
Definition: board.cpp:797
void SynchronizeProperties()
Copy the current project's text variables into the boards property cache.
Definition: board.cpp:1934
bool m_LegacyCopperEdgeClearanceLoaded
Definition: board.h:366
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::map< wxString, PCB_LAYER_ID > GetMapModal(wxWindow *aParent, const std::vector< INPUT_LAYER_DESC > &aLayerDesc)
Create and show a dialog (modal) and returns the data from it after completion.
static std::vector< IMPORT_PROJECT_DESC > GetSelectionsModal(wxWindow *aParent, const std::vector< IMPORT_PROJECT_DESC > &aProjectDesc)
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:105
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:226
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.
virtual void RegisterLayerMappingCallback(LAYER_MAPPING_HANDLER aLayerMappingHandler)
Register a different handler to be called when mapping of input layers to KiCad layers occurs.
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:119
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:542
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 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:40
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:551
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:557
bool KeepRefreshing(bool aWait=false) override
Update the UI dialog.
Plugin class for import plugins that support choosing a project.
virtual void RegisterChooseProjectCallback(CHOOSE_PROJECT_HANDLER aChooseProjectHandler)
Register a different handler to be called when a non-KiCad project contains multiple PCB+Schematic co...
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:301
bool HasCloseButton() const
Definition: wx_infobar.cpp:325
@ 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:187
void AddCloseButton(const wxString &aTooltip=_("Hide this message."))
Add the default close button to the infobar on the right side.
Definition: wx_infobar.cpp:291
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:415
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:36
bool IsOK(wxWindow *aParent, const wxString &aMessage)
Display a yes/no dialog with aMessage and returns the user response.
Definition: confirm.cpp:241
void DisplayError(wxWindow *aParent, const wxString &aText, int aDisplayTime)
Display an error or warning message box with aMessage.
Definition: confirm.cpp:161
void DisplayInfoMessage(wxWindow *aParent, const wxString &aMessage, const wxString &aExtraInfo)
Display an informational message box with aMessage.
Definition: confirm.cpp:213
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:121
void DisplayErrorMessage(wxWindow *aParent, const wxString &aText, const wxString &aExtraInfo)
Display an error message with aMessage.
Definition: confirm.cpp:186
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:272
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: gtk/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: gtk/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:39
std::vector< std::string > m_FileExtensions
Filter used for file pickers if m_IsFile is true.
Definition: io_base.h:41
bool m_CanRead
Whether the IO can read this file type.
Definition: io_base.h:44
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.