KiCad PCB EDA Suite
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 <stambaughw@gmail.com>
6  * Copyright (C) 2016-2018 KiCad Developers, see AUTHORS.txt for contributors.
7  *
8  * This program is free software; you can redistribute it and/or
9  * modify it under the terms of the GNU General Public License
10  * as published by the Free Software Foundation; either version 2
11  * of the License, or (at your option) any later version.
12  *
13  * This program is distributed in the hope that it will be useful,
14  * but WITHOUT ANY WARRANTY; without even the implied warranty of
15  * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
16  * GNU General Public License for more details.
17  *
18  * You should have received a copy of the GNU General Public License
19  * along with this program; if not, you may find one here:
20  * http://www.gnu.org/licenses/old-licenses/gpl-2.0.html
21  * or you may search the http://www.gnu.org website for the version 2 license,
22  * or you may write to the Free Software Foundation, Inc.,
23  * 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301, USA
24  */
25 
26 #include <fctsys.h>
27 #include <confirm.h>
28 #include <kicad_string.h>
29 #include <gestfich.h>
30 #include <pcb_edit_frame.h>
31 #include <macros.h>
33 #include <richio.h>
34 #include <filter_reader.h>
35 #include <pgm_base.h>
36 #include <msgpanel.h>
37 #include <fp_lib_table.h>
38 #include <ratsnest_data.h>
39 #include <kiway.h>
40 #include <kiway_player.h>
41 #include <trace_helpers.h>
42 #include <lockfile.cpp>
44 #include <pcbnew.h>
45 #include <pcbnew_id.h>
46 #include <io_mgr.h>
48 
49 #include <class_board.h>
50 #include <build_version.h> // LEGACY_BOARD_FILE_VERSION
51 
52 #include <wx/stdpaths.h>
53 #include <pcb_layer_widget.h>
54 #include <wx/wupdlock.h>
55 
56 
57 //#define USE_INSTRUMENTATION 1
58 #define USE_INSTRUMENTATION 0
59 
60 
73 bool AskLoadBoardFileName( wxWindow* aParent, int* aCtl, wxString* aFileName, bool aKicadFilesOnly )
74 {
75  // This is a subset of all PLUGINs which are trusted to be able to
76  // load a BOARD. User may occasionally use the wrong plugin to load a
77  // *.brd file (since both legacy and eagle use *.brd extension),
78  // but eventually *.kicad_pcb will be more common than legacy *.brd files.
79  static const struct
80  {
81  const wxString& filter;
82  IO_MGR::PCB_FILE_T pluginType;
83  } loaders[] =
84  {
85  { PcbFileWildcard(), IO_MGR::KICAD_SEXP }, // Current Kicad board files
86  { LegacyPcbFileWildcard(), IO_MGR::LEGACY }, // Old Kicad board files
87  { EaglePcbFileWildcard(), IO_MGR::EAGLE }, // Import board files
88  { PCadPcbFileWildcard(), IO_MGR::PCAD }, // Import board files
89  };
90 
91  wxFileName fileName( *aFileName );
92  wxString fileFilters;
93 
94  if( aKicadFilesOnly )
95  {
96  for( unsigned ii = 0; ii < 2; ++ii )
97  {
98  if( !fileFilters.IsEmpty() )
99  fileFilters += wxChar( '|' );
100 
101  fileFilters += wxGetTranslation( loaders[ii].filter );
102  }
103  }
104  else
105  {
106  for( unsigned ii = 2; ii < arrayDim( loaders ); ++ii )
107  {
108  if( !fileFilters.IsEmpty() )
109  fileFilters += wxChar( '|' );
110 
111  fileFilters += wxGetTranslation( loaders[ii].filter );
112  }
113  }
114 
115  wxString path;
116  wxString name;
117 
118  if( fileName.FileExists() )
119  {
120  path = fileName.GetPath();
121  name = fileName.GetFullName();
122  }
123  else
124  {
125  path = wxStandardPaths::Get().GetDocumentsDir();
126  // leave name empty
127  }
128 
129  wxFileDialog dlg( aParent,
130  aKicadFilesOnly ? _( "Open Board File" ) : _( "Import Non KiCad Board File" ),
131  path, name, fileFilters,
132  wxFD_OPEN | wxFD_FILE_MUST_EXIST );
133 
134  if( dlg.ShowModal() == wxID_OK )
135  {
136  // For import option, if Eagle (*.brd files), tell OpenProjectFiles() to use Eagle plugin.
137  // It's the only special case because of the duplicate use of the *.brd file extension.
138  // Other cases are clear because of unique file extensions.
139  *aCtl = aKicadFilesOnly ? 0 : KICTL_EAGLE_BRD;
140  *aFileName = dlg.GetPath();
141  return true;
142  }
143  else
144  return false;
145 }
146 
147 
158 bool AskSaveBoardFileName( wxWindow* aParent, wxString* aFileName )
159 {
160  wxString wildcard = PcbFileWildcard();
161  wxFileName fn = *aFileName;
162 
163  fn.SetExt( KiCadPcbFileExtension );
164 
165  wxFileDialog dlg( aParent,
166  _( "Save Board File As" ),
167  fn.GetPath(),
168  fn.GetFullName(),
169  wildcard,
170  wxFD_SAVE | wxFD_OVERWRITE_PROMPT
171  );
172 
173  if( dlg.ShowModal() != wxID_OK )
174  return false;
175 
176  fn = dlg.GetPath();
177 
178  // always enforce filename extension, user may not have entered it.
179  fn.SetExt( KiCadPcbFileExtension );
180 
181  *aFileName = fn.GetFullPath();
182 
183  return true;
184 }
185 
186 
187 void PCB_EDIT_FRAME::OnFileHistory( wxCommandEvent& event )
188 {
189  wxString fn = GetFileFromHistory( event.GetId(), _( "Printed circuit board" ) );
190 
191  if( !!fn )
192  {
193  int open_ctl = 0;
194 
195  if( !wxFileName::IsFileReadable( fn ) )
196  {
197  if( !AskLoadBoardFileName( this, &open_ctl, &fn, true ) )
198  return;
199  }
200 
201  OpenProjectFiles( std::vector<wxString>( 1, fn ), open_ctl );
202  }
203 }
204 
205 
206 void PCB_EDIT_FRAME::Files_io( wxCommandEvent& event )
207 {
208  int id = event.GetId();
209  Files_io_from_id( id );
210 }
211 
212 
214 {
215  wxString msg;
216 
217  switch( id )
218  {
219  case ID_LOAD_FILE:
220  {
221  int open_ctl = 0;
222  wxString fileName = Prj().AbsolutePath( GetBoard()->GetFileName() );
223 
224  return AskLoadBoardFileName( this, &open_ctl, &fileName, true )
225  && OpenProjectFiles( std::vector<wxString>( 1, fileName ), open_ctl );
226  }
227 
229  {
230  int open_ctl = 1;
231  wxString fileName; // = Prj().AbsolutePath( GetBoard()->GetFileName() );
232 
233  return AskLoadBoardFileName( this, &open_ctl, &fileName, false )
234  && OpenProjectFiles( std::vector<wxString>( 1, fileName ), open_ctl );
235  }
236 
239  {
240  wxFileName currfn = Prj().AbsolutePath( GetBoard()->GetFileName() );
241  wxFileName fn = currfn;
242 
244  {
245  wxString rec_name = GetAutoSaveFilePrefix() + fn.GetName();
246  fn.SetName( rec_name );
247  }
248  else
249  {
250  wxString backup_ext = fn.GetExt() + GetBackupSuffix();
251  fn.SetExt( backup_ext );
252  }
253 
254  if( !fn.FileExists() )
255  {
256  msg.Printf( _( "Recovery file \"%s\" not found." ), fn.GetFullPath() );
257  DisplayInfoMessage( this, msg );
258  return false;
259  }
260 
261  msg.Printf( _( "OK to load recovery or backup file \"%s\"" ), fn.GetFullPath() );
262 
263  if( !IsOK( this, msg ) )
264  return false;
265 
266  GetScreen()->ClrModify(); // do not prompt the user for changes
267 
268  if( OpenProjectFiles( std::vector<wxString>( 1, fn.GetFullPath() ) ) )
269  {
270  // Re-set the name since name or extension was changed
271  GetBoard()->SetFileName( currfn.GetFullPath() );
272  UpdateTitle();
273  return true;
274  }
275  return false;
276  }
277 
278  case ID_NEW_BOARD:
279  {
280  if( GetScreen()->IsModify() && !GetBoard()->IsEmpty() )
281  {
282  wxFileName fileName = GetBoard()->GetFileName();
283  wxString saveMsg =
284  _( "Current board will be closed, save changes to \"%s\" before continuing?" );
285 
286  if( !HandleUnsavedChanges( this, wxString::Format( saveMsg, fileName.GetFullName() ),
287  [&]()->bool { return Files_io_from_id( ID_SAVE_BOARD ); } ) )
288  return false;
289  }
290  else if( !GetBoard()->IsEmpty() )
291  {
292  if( !IsOK( this, _( "Current Board will be closed. Continue?" ) ) )
293  return false;
294  }
295 
296  if( !Clear_Pcb( false ) )
297  return false;
298 
299  wxFileName fn( wxStandardPaths::Get().GetDocumentsDir(), wxT( "noname" ),
301 
302  Prj().SetProjectFullName( fn.GetFullPath() );
303 
304  onBoardLoaded();
305 
306  OnModify();
307  return true;
308  }
309 
310  case ID_SAVE_BOARD:
311  if( !GetBoard()->GetFileName().IsEmpty() )
312  return SavePcbFile( Prj().AbsolutePath( GetBoard()->GetFileName() ) );
313  // Fall through
314 
315  case ID_COPY_BOARD_AS:
316  case ID_SAVE_BOARD_AS:
317  {
318  wxString pro_dir = wxPathOnly( Prj().GetProjectFullName() );
319  wxFileName fn( pro_dir, _( "noname" ), KiCadPcbFileExtension );
320  wxString filename = fn.GetFullPath();
321 
322  if( AskSaveBoardFileName( this, &filename ) )
323  {
324  if( id == ID_COPY_BOARD_AS )
325  return SavePcbCopy( filename );
326  else
327  return SavePcbFile( filename, NO_BACKUP_FILE );
328  }
329  return false;
330  }
331 
332  default:
333  wxLogDebug( wxT( "File_io Internal Error" ) );
334  return false;
335  }
336 }
337 
338 
339 // The KIWAY_PLAYER::OpenProjectFiles() API knows nothing about plugins, so
340 // determine how to load the BOARD here, with minor assistance from KICTL_EAGLE_BRD
341 // bit flag.
342 IO_MGR::PCB_FILE_T plugin_type( const wxString& aFileName, int aCtl )
343 {
344  IO_MGR::PCB_FILE_T pluginType;
345 
346  wxFileName fn = aFileName;
347 
348  // Note: file extensions are expected to be in ower case.
349  // This is not always true, especially when importing files, so the string
350  // comparisons are case insensitive to try to find the suitable plugin.
351 
352  if( fn.GetExt().CmpNoCase( IO_MGR::GetFileExtension( IO_MGR::LEGACY ) ) == 0 )
353  {
354  // both legacy and eagle share a common file extension.
355  pluginType = ( aCtl & KICTL_EAGLE_BRD ) ? IO_MGR::EAGLE : IO_MGR::LEGACY;
356  }
357  else if( fn.GetExt().CmpNoCase( IO_MGR::GetFileExtension( IO_MGR::PCAD ) ) == 0 )
358  {
359  pluginType = IO_MGR::PCAD;
360  }
361  else
362  {
363  pluginType = IO_MGR::KICAD_SEXP;
364  }
365 
366  return pluginType;
367 }
368 
369 
371 {
372  PCB_LAYER_COLLECTOR collector;
373 
374  collector.SetLayerId( Edge_Cuts );
375  collector.Collect( aBoard, GENERAL_COLLECTOR::AllBoardItems );
376 
377  int edgeWidth = -1;
378  bool mixed = false;
379 
380  for( int i = 0; i < collector.GetCount(); i++ )
381  {
382  if( collector[i]->Type() == PCB_LINE_T )
383  {
384  int itemWidth = static_cast<DRAWSEGMENT*>( collector[i] )->GetWidth();
385 
386  if( edgeWidth != -1 && edgeWidth != itemWidth )
387  {
388  mixed = true;
389  edgeWidth = std::max( edgeWidth, itemWidth );
390  }
391  else
392  {
393  edgeWidth = itemWidth;
394  }
395  }
396  }
397 
398  if( mixed )
399  {
400  // If they had different widths then we can't ensure that fills will be the same.
401  wxMessageBox( _( "If the zones on this board are refilled the Copper Edge Clearance\n"
402  "setting will be used (see Board Setup > Design Rules). This may\n"
403  "result in different fills from previous Kicad versions which used\n"
404  "the line thickness of the board boundary on the Edge Cuts layer." ),
405  _( "Edge Clearance Warning" ), wxOK|wxICON_WARNING, this );
406  }
407 
408  return std::max( 0, edgeWidth / 2 );
409 }
410 
411 
412 bool PCB_EDIT_FRAME::OpenProjectFiles( const std::vector<wxString>& aFileSet, int aCtl )
413 {
414  // This is for python:
415  if( aFileSet.size() != 1 )
416  {
417  UTF8 msg = StrPrintf( "Pcbnew:%s() takes only a single filename", __func__ );
418  DisplayError( this, msg );
419  return false;
420  }
421 
422  wxString fullFileName( aFileSet[0] );
423 
424  // We insist on caller sending us an absolute path, if it does not, we say it's a bug.
425  wxASSERT_MSG( wxFileName( fullFileName ).IsAbsolute(), wxT( "Path is not absolute!" ) );
426 
427  std::unique_ptr<wxSingleInstanceChecker> lockFile = ::LockFile( fullFileName );
428 
429  if( !lockFile )
430  {
431  wxString msg = wxString::Format( _( "PCB file \"%s\" is already open." ), fullFileName );
432  DisplayError( this, msg );
433  return false;
434  }
435 
436  if( GetScreen()->IsModify() && !GetBoard()->IsEmpty() )
437  {
438  if( !HandleUnsavedChanges( this, _( "The current PCB has been modified. Save changes?" ),
439  [&]()->bool { return SavePcbFile( GetBoard()->GetFileName(), CREATE_BACKUP_FILE ); } ) )
440  {
441  return false;
442  }
443  }
444 
445  // Release the lock file, until the new file is actually loaded
446  ReleaseFile();
447 
448  wxFileName pro = fullFileName;
449  pro.SetExt( ProjectFileExtension );
450 
451  bool is_new = !wxFileName::IsFileReadable( fullFileName );
452 
453  // If its a non-existent schematic and caller thinks it exists
454  if( is_new && !( aCtl & KICTL_CREATE ) )
455  {
456  // notify user that fullFileName does not exist, ask if user wants to create it.
457  wxString ask = wxString::Format( _( "PCB \"%s\" does not exist. Do you wish to create it?" ),
458  fullFileName );
459  if( !IsOK( this, ask ) )
460  return false;
461  }
462 
463  wxWindowUpdateLocker no_update( m_Layers ); // Avoid flicker when rebuilding m_Layers
464 
465  Clear_Pcb( false ); // pass false since we prompted above for a modified board
466 
467  IO_MGR::PCB_FILE_T pluginType = plugin_type( fullFileName, aCtl );
468 
469  bool converted = pluginType != IO_MGR::LEGACY && pluginType != IO_MGR::KICAD_SEXP;
470 
471  if( !converted )
472  {
473  // PROJECT::SetProjectFullName() is an impactful function. It should only be
474  // called under carefully considered circumstances.
475 
476  // The calling code should know not to ask me here to change projects unless
477  // it knows what consequences that will have on other KIFACEs running and using
478  // this same PROJECT. It can be very harmful if that calling code is stupid.
479  Prj().SetProjectFullName( pro.GetFullPath() );
480 
481  // load project settings before BOARD
483  }
484 
485  if( is_new )
486  {
487  OnModify();
488  }
489  else
490  {
491  BOARD* loadedBoard = 0; // it will be set to non-NULL if loaded OK
492 
493  PLUGIN::RELEASER pi( IO_MGR::PluginFind( pluginType ) );
494 
495  // This will rename the file if there is an autosave and the user want to recover
496  CheckForAutoSaveFile( fullFileName );
497 
498  try
499  {
500  PROPERTIES props;
501  char xbuf[30];
502  char ybuf[30];
503 
504  // EAGLE_PLUGIN can use this info to center the BOARD, but it does not yet.
505  sprintf( xbuf, "%d", GetPageSizeIU().x );
506  sprintf( ybuf, "%d", GetPageSizeIU().y );
507 
508  props["page_width"] = xbuf;
509  props["page_height"] = ybuf;
510 
511 #if USE_INSTRUMENTATION
512  // measure the time to load a BOARD.
513  unsigned startTime = GetRunningMicroSecs();
514 #endif
515 
516  loadedBoard = pi->Load( fullFileName, NULL, &props );
517 
518 #if USE_INSTRUMENTATION
519  unsigned stopTime = GetRunningMicroSecs();
520  printf( "PLUGIN::Load(): %u usecs\n", stopTime - startTime );
521 #endif
522  }
523  catch( const IO_ERROR& ioe )
524  {
525  if( ioe.Problem() != wxT( "CANCEL" ) )
526  {
527  wxString msg = wxString::Format( _( "Error loading board file:\n%s" ), fullFileName );
528  DisplayErrorMessage( this, msg, ioe.What() );
529  }
530 
531  return false;
532  }
533 
534  BOARD_DESIGN_SETTINGS& bds = loadedBoard->m_designSettings;
535 
536  if( bds.m_CopperEdgeClearance == Millimeter2iu( LEGACY_COPPEREDGECLEARANCE ) )
537  {
538  // 5.1 boards stored some settings in the config so as not to bump the file version.
539  // These will have been loaded into the config-initialized board, so we copy them
540  // from there.
542 
545  bds.m_HoleToHoleMin = configBds.m_HoleToHoleMin;
549  std::copy( configBds.m_TextItalic, configBds.m_TextItalic + 4, bds.m_TextItalic );
550  std::copy( configBds.m_TextUpright, configBds.m_TextUpright + 4, bds.m_TextUpright );
553 
554  // Before we had a copper edge clearance setting, the edge line widths could be used
555  // as a kludge to control them. So if there's no setting then infer it from the
556  // edge widths.
557  if( bds.m_CopperEdgeClearance == Millimeter2iu( LEGACY_COPPEREDGECLEARANCE ) )
558  bds.SetCopperEdgeClearance( inferLegacyEdgeClearance( loadedBoard ) );
559  }
560 
561  // 6.0 TODO: some of the 5.1 settings still haven't moved because they're waiting on
562  // the new DRC architecture
566  bds.m_HoleToHoleMin = configBds.m_HoleToHoleMin;
567 
568  SetBoard( loadedBoard );
569 
570  // we should not ask PLUGINs to do these items:
571  loadedBoard->BuildListOfNets();
572  loadedBoard->SynchronizeNetsAndNetClasses();
573 
574  if( loadedBoard->IsModified() )
575  OnModify();
576  else
577  GetScreen()->ClrModify();
578 
579  if( pluginType == IO_MGR::LEGACY &&
580  loadedBoard->GetFileFormatVersionAtLoad() < LEGACY_BOARD_FILE_VERSION )
581  {
582  DisplayInfoMessage( this,
583  _( "This file was created by an older version of Pcbnew.\n"
584  "It will be stored in the new file format when you save this file again." ) );
585  }
586  }
587 
588  {
589  wxFileName fn = fullFileName;
590 
591  if( converted )
592  fn.SetExt( PcbFileExtension );
593 
594  wxString fname = fn.GetFullPath();
595 
596  fname.Replace( WIN_STRING_DIR_SEP, UNIX_STRING_DIR_SEP );
597 
598  GetBoard()->SetFileName( fname );
599  }
600 
601  // Lock the file newly opened:
602  m_file_checker.reset( lockFile.release() );
603 
604  if( !converted )
605  UpdateFileHistory( GetBoard()->GetFileName() );
606 
607  // Select netclass Default as current netclass (it always exists)
609 
610  // Rebuild list of nets (full ratsnest rebuild)
611  Compile_Ratsnest( true );
613 
614  onBoardLoaded();
615 
616  // Refresh the 3D view, if any
617  EDA_3D_VIEWER* draw3DFrame = Get3DViewerFrame();
618 
619  if( draw3DFrame )
620  draw3DFrame->NewDisplay();
621 
622 #if 0 && defined(DEBUG)
623  // Output the board object tree to stdout, but please run from command prompt:
624  GetBoard()->Show( 0, std::cout );
625 #endif
626 
627  // from EDA_APPL which was first loaded BOARD only:
628  {
629  /* For an obscure reason the focus is lost after loading a board file
630  * when starting up the process.
631  * (seems due to the recreation of the layer manager after loading the file)
632  * Give focus to main window and Drawpanel
633  * must be done for these 2 windows (for an obscure reason ...)
634  * Linux specific
635  * This is more a workaround than a fix.
636  */
637  SetFocus();
638  GetCanvas()->SetFocus();
639  }
640 
641  return true;
642 }
643 
644 
645 wxString PCB_EDIT_FRAME::createBackupFile( const wxString& aFileName )
646 {
647  wxFileName fn = aFileName;
648  wxFileName backupFileName = aFileName;
649 
650  backupFileName.SetExt( fn.GetExt() + GetBackupSuffix() );
651 
652  // If an old backup file exists, delete it. If an old board file exists,
653  // rename it to the backup file name.
654  if( fn.FileExists() )
655  {
656  // Remove the old file xxx.000 if it exists.
657  if( backupFileName.FileExists() )
658  wxRemoveFile( backupFileName.GetFullPath() );
659 
660  // Rename the current file from <xxx>.kicad_pcb to <xxx>.kicad_pcb-bak
661  if( !wxRenameFile( fn.GetFullPath(), backupFileName.GetFullPath() ) )
662  {
663  wxString msg = wxString::Format( _(
664  "Warning: unable to create backup file \"%s\"" ),
665  GetChars( backupFileName.GetFullPath() )
666  );
667  DisplayError( NULL, msg );
668  }
669  }
670  else
671  {
672  backupFileName.Clear();
673  }
674 
675  return backupFileName.GetFullPath();
676 }
677 
678 
679 bool PCB_EDIT_FRAME::SavePcbFile( const wxString& aFileName, bool aCreateBackupFile )
680 {
681  // please, keep it simple. prompting goes elsewhere.
682 
683  wxFileName pcbFileName = aFileName;
684 
685  if( pcbFileName.GetExt() == LegacyPcbFileExtension )
686  pcbFileName.SetExt( KiCadPcbFileExtension );
687 
688  if( !IsWritable( pcbFileName ) )
689  {
690  wxString msg = wxString::Format( _(
691  "No access rights to write to file \"%s\"" ),
692  GetChars( pcbFileName.GetFullPath() )
693  );
694 
695  DisplayError( this, msg );
696  return false;
697  }
698 
699  wxString backupFileName;
700 
701  if( aCreateBackupFile )
702  {
703  backupFileName = createBackupFile( aFileName );
704  }
705 
707 
708  // Select default Netclass before writing file.
709  // Useful to save default values in headers
711 
712  ClearMsgPanel();
713 
714  wxString upperTxt;
715  wxString lowerTxt;
716 
717  try
718  {
720 
721  wxASSERT( pcbFileName.IsAbsolute() );
722 
723  pi->Save( pcbFileName.GetFullPath(), GetBoard(), NULL );
724  }
725  catch( const IO_ERROR& ioe )
726  {
727  wxString msg = wxString::Format( _(
728  "Error saving board file \"%s\".\n%s" ),
729  GetChars( pcbFileName.GetFullPath() ),
730  GetChars( ioe.What() )
731  );
732  DisplayError( this, msg );
733 
734  lowerTxt.Printf( _( "Failed to create \"%s\"" ), GetChars( pcbFileName.GetFullPath() ) );
735 
736  AppendMsgPanel( upperTxt, lowerTxt, CYAN );
737 
738  return false;
739  }
740 
741  GetBoard()->SetFileName( pcbFileName.GetFullPath() );
742  UpdateTitle();
743 
744  // Put the saved file in File History, unless aCreateBackupFile
745  // is false.
746  // aCreateBackupFile == false is mainly used to write autosave files
747  // and not need to have an autosave file in file history
748  if( aCreateBackupFile )
749  UpdateFileHistory( GetBoard()->GetFileName() );
750 
751  // Delete auto save file on successful save.
752  wxFileName autoSaveFileName = pcbFileName;
753 
754  autoSaveFileName.SetName( GetAutoSaveFilePrefix() + pcbFileName.GetName() );
755 
756  if( autoSaveFileName.FileExists() )
757  wxRemoveFile( autoSaveFileName.GetFullPath() );
758 
759  if( !!backupFileName )
760  upperTxt.Printf( _( "Backup file: \"%s\"" ), GetChars( backupFileName ) );
761 
762  lowerTxt.Printf( _( "Wrote board file: \"%s\"" ), GetChars( pcbFileName.GetFullPath() ) );
763 
764  AppendMsgPanel( upperTxt, lowerTxt, CYAN );
765 
766  GetScreen()->ClrModify();
767  GetScreen()->ClrSave();
768  return true;
769 }
770 
771 
772 bool PCB_EDIT_FRAME::SavePcbCopy( const wxString& aFileName )
773 {
774  wxFileName pcbFileName = aFileName;
775 
776  // Ensure the file ext is the right ext:
777  pcbFileName.SetExt( KiCadPcbFileExtension );
778 
779  if( !IsWritable( pcbFileName ) )
780  {
781  wxString msg = wxString::Format( _(
782  "No access rights to write to file \"%s\"" ),
783  GetChars( pcbFileName.GetFullPath() )
784  );
785 
786  DisplayError( this, msg );
787  return false;
788  }
789 
791 
792  // Select default Netclass before writing file.
793  // Useful to save default values in headers
795 
796  try
797  {
799 
800  wxASSERT( pcbFileName.IsAbsolute() );
801 
802  pi->Save( pcbFileName.GetFullPath(), GetBoard(), NULL );
803  }
804  catch( const IO_ERROR& ioe )
805  {
806  wxString msg = wxString::Format( _(
807  "Error saving board file \"%s\".\n%s" ),
808  GetChars( pcbFileName.GetFullPath() ),
809  GetChars( ioe.What() )
810  );
811  DisplayError( this, msg );
812 
813  return false;
814  }
815 
816  DisplayInfoMessage( this, wxString::Format( _( "Board copied to:\n\"%s\"" ),
817  GetChars( pcbFileName.GetFullPath() ) ) );
818 
819  return true;
820 }
821 
822 
824 {
825  wxFileName tmpFileName;
826 
827  if( GetBoard()->GetFileName().IsEmpty() )
828  {
829  tmpFileName = wxFileName( wxStandardPaths::Get().GetDocumentsDir(), wxT( "noname" ),
831  GetBoard()->SetFileName( tmpFileName.GetFullPath() );
832  }
833  else
834  {
835  tmpFileName = Prj().AbsolutePath( GetBoard()->GetFileName() );
836  }
837 
838  wxFileName autoSaveFileName = tmpFileName;
839 
840  // Auto save file name is the board file name prepended with autosaveFilePrefix string.
841  autoSaveFileName.SetName( GetAutoSaveFilePrefix() + autoSaveFileName.GetName() );
842 
843  if( !autoSaveFileName.IsOk() )
844  return false;
845 
846  // If the board file path is not writable, try writing to a platform specific temp file
847  // path. If that path isn't writabe, give up.
848  if( !autoSaveFileName.IsDirWritable() )
849  {
850  autoSaveFileName.SetPath( wxFileName::GetTempDir() );
851 
852  if( !autoSaveFileName.IsOk() || !autoSaveFileName.IsDirWritable() )
853  return false;
854  }
855 
856  wxLogTrace( traceAutoSave, "Creating auto save file <" + autoSaveFileName.GetFullPath() + ">" );
857 
858  if( SavePcbFile( autoSaveFileName.GetFullPath(), NO_BACKUP_FILE ) )
859  {
860  GetScreen()->SetModify();
861  GetBoard()->SetFileName( tmpFileName.GetFullPath() );
862  UpdateTitle();
863  m_autoSaveState = false;
864  return true;
865  }
866 
867  GetBoard()->SetFileName( tmpFileName.GetFullPath() );
868 
869  return false;
870 }
871 
872 
873 bool PCB_EDIT_FRAME::importFile( const wxString& aFileName, int aFileType )
874 {
875  switch( (IO_MGR::PCB_FILE_T) aFileType )
876  {
877  case IO_MGR::EAGLE:
878  if( OpenProjectFiles( std::vector<wxString>( 1, aFileName ), KICTL_EAGLE_BRD ) )
879  {
880  wxString projectpath = Kiway().Prj().GetProjectPath();
881  wxFileName newfilename;
882 
883  newfilename.SetPath( Prj().GetProjectPath() );
884  newfilename.SetName( Prj().GetProjectName() );
885  newfilename.SetExt( KiCadPcbFileExtension );
886 
887  GetBoard()->SetFileName( newfilename.GetFullPath() );
888  UpdateTitle();
889  OnModify();
890 
891  // Extract a footprint library from the design and add it to the fp-lib-table
892  wxString newLibPath;
893  ArchiveModulesOnBoard( true, newfilename.GetName(), &newLibPath );
894 
895  if( newLibPath.Length() > 0 )
896  {
897  FP_LIB_TABLE* prjlibtable = Prj().PcbFootprintLibs();
898  const wxString& project_env = PROJECT_VAR_NAME;
899  wxString rel_path, env_path;
900 
901  wxGetEnv( project_env, &env_path );
902 
903  wxString result( newLibPath );
904  rel_path = result.Replace( env_path,
905  wxString( "$(" + project_env + ")" ) ) ? result : "" ;
906 
907  if( !rel_path.IsEmpty() )
908  newLibPath = rel_path;
909 
910  FP_LIB_TABLE_ROW* row = new FP_LIB_TABLE_ROW( newfilename.GetName(),
911  newLibPath, wxT( "KiCad" ), wxEmptyString );
912  prjlibtable->InsertRow( row );
913  }
914 
915  if( !GetBoard()->GetFileName().IsEmpty() )
916  {
917  wxString tblName = Prj().FootprintLibTblName();
918 
919  try
920  {
921  Prj().PcbFootprintLibs()->Save( tblName );
922  }
923  catch( const IO_ERROR& ioe )
924  {
925  wxString msg = wxString::Format( _(
926  "Error occurred saving project specific footprint library "
927  "table:\n\n%s" ),
928  GetChars( ioe.What() ) );
929  wxMessageBox( msg, _( "File Save Error" ), wxOK | wxICON_ERROR );
930  }
931  }
932 
933 
934  // Update module LIB_IDs to point to the just imported Eagle library
935  for( MODULE* module : GetBoard()->Modules() )
936  {
937  LIB_ID libId = module->GetFPID();
938 
939  if( libId.GetLibItemName().empty() )
940  continue;
941 
942  libId.SetLibNickname( newfilename.GetName() );
943  module->SetFPID( libId );
944  }
945 
946 
947  // Store net names for all pads, to create net remap information
948  std::unordered_map<D_PAD*, wxString> netMap;
949 
950  for( const auto& pad : GetBoard()->GetPads() )
951  {
952  NETINFO_ITEM* netinfo = pad->GetNet();
953 
954  if( netinfo->GetNet() > 0 && !netinfo->GetNetname().IsEmpty() )
955  netMap[pad] = netinfo->GetNetname();
956  }
957 
958  // Two stage netlist update:
959  // - first, assign valid timestamps to footprints (no reannotation)
960  // - second, perform schematic annotation and update footprint references
961  // based on timestamps
962  NETLIST netlist;
964  DoUpdatePCBFromNetlist( netlist, false );
966  DoUpdatePCBFromNetlist( netlist, true );
967 
968  std::unordered_map<wxString, wxString> netRemap;
969 
970  // Compare the old net names with the new net names and create a net map
971  for( const auto& pad : GetBoard()->GetPads() )
972  {
973  auto it = netMap.find( pad );
974 
975  if( it == netMap.end() )
976  continue;
977 
978  NETINFO_ITEM* netinfo = pad->GetNet();
979 
980  // Net name has changed, create a remap entry
981  if( netinfo->GetNet() > 0 && netMap[pad] != netinfo->GetNetname() )
982  netRemap[netMap[pad]] = netinfo->GetNetname();
983  }
984 
985  if( !netRemap.empty() )
986  fixEagleNets( netRemap );
987 
988  return true;
989  }
990 
991  return false;
992 
993  default:
994  return false;
995  }
996 
997  return false;
998 }
999 
1000 
1001 bool PCB_EDIT_FRAME::fixEagleNets( const std::unordered_map<wxString, wxString>& aRemap )
1002 {
1003  bool result = true;
1004  BOARD* board = GetBoard();
1005 
1006  // perform netlist matching to prevent orphaned zones.
1007  for( auto zone : board->Zones() )
1008  {
1009  auto it = aRemap.find( zone->GetNet()->GetNetname() );
1010 
1011  if( it != aRemap.end() )
1012  {
1013  NETINFO_ITEM* net = board->FindNet( it->second );
1014 
1015  if( !net )
1016  {
1017  wxFAIL;
1018  result = false;
1019  continue;
1020  }
1021 
1022  zone->SetNet( net );
1023  }
1024  }
1025 
1026 
1027  // perform netlist matching to prevent orphaned tracks/vias.
1028  for( auto track : board->Tracks() )
1029  {
1030  auto it = aRemap.find( track->GetNet()->GetNetname() );
1031 
1032  if( it != aRemap.end() )
1033  {
1034  NETINFO_ITEM* net = board->FindNet( it->second );
1035 
1036  if( !net )
1037  {
1038  wxFAIL;
1039  result = false;
1040  continue;
1041  }
1042 
1043  track->SetNet( net );
1044  }
1045  }
1046 
1047  return result;
1048 }
void DisplayError(wxWindow *aParent, const wxString &aText, int aDisplayTime)
Display an error or warning message box with aMessage.
Definition: confirm.cpp:236
void UpdateTitle()
Function UpdateTitle sets the main window title bar text.
Class UTF8 is an 8 bit string that is assuredly encoded in UTF8, and supplies special conversion supp...
Definition: utf8.h:73
NETINFO_ITEM * FindNet(int aNetcode) const
Function FindNet searches for a net with the given netcode.
void BuildListOfNets()
Definition: class_board.h:717
void OnModify() override
Function OnModify must be called after a board change to set the modified flag.
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:201
void SetCopperEdgeClearance(int aDistance)
Function SetCopperEdgeClearance.
const UTF8 & GetLibItemName() const
Definition: lib_id.h:114
KIWAY & Kiway() const
Function Kiway returns a reference to the KIWAY that this object has an opportunity to participate in...
Definition: kiway_holder.h:56
#define WIN_STRING_DIR_SEP
Definition: gestfich.h:44
wxString EaglePcbFileWildcard()
static const KICAD_T AllBoardItems[]
A scan list for all editable board items.
Definition: collectors.h:267
int StrPrintf(std::string *aResult, const char *aFormat,...)
Function StrPrintf is like sprintf() but the output is appended to a std::string instead of to a char...
Definition: richio.cpp:74
bool importFile(const wxString &aFileName, int aFileType)
Load the given filename but sets the path to the current project path.
void DisplayErrorMessage(wxWindow *aParent, const wxString &aText, const wxString &aExtraInfo)
Display an error message with aMessage.
Definition: confirm.cpp:249
This file is part of the common library TODO brief description.
IO_MGR::PCB_FILE_T plugin_type(const wxString &aFileName, int aCtl)
const wxChar *const traceAutoSave
Flag to enable auto save feature debug tracing.
bool IsModified() const
Definition: base_struct.h:229
Class FP_LIB_TABLE_ROW.
Definition: fp_lib_table.h:42
void Compile_Ratsnest(bool aDisplayStatus)
Function Compile_Ratsnest Create the entire board ratsnest.
Definition: ratsnest.cpp:44
bool InsertRow(LIB_TABLE_ROW *aRow, bool doReplace=false)
Adds aRow if it does not already exist or if doReplace is true.
This file is part of the common library.
const std::string ProjectFileExtension
const std::string LegacyPcbFileExtension
bool SavePcbCopy(const wxString &aFileName)
Function SavePcbCopy writes the board data structures to a aFileName but unlike SavePcbFile,...
bool m_ProhibitOverlappingCourtyards
check for overlapping courtyards in DRC
std::vector< DIFF_PAIR_DIMENSION > m_DiffPairDimensionsList
#define UNIX_STRING_DIR_SEP
Definition: gestfich.h:43
VTBL_ENTRY PROJECT & Prj() const
Function Prj returns the PROJECT associated with this KIWAY.
Definition: kiway.cpp:171
bool doAutoSave() override
Function doAutoSave performs auto save when the board has been modified and not saved within the auto...
#define KICTL_CREATE
caller thinks requested project files may not exist
Definition: kiway_player.h:79
PCB_DRAW_PANEL_GAL * GetCanvas() const override
Return a pointer to GAL-based canvas of given EDA draw frame.
Class that computes missing connections on a PCB.
#define PROJECT_VAR_NAME
A variable name whose value holds the current project directory.
Definition: project.h:37
#define LEGACY_COPPEREDGECLEARANCE
wxString createBackupFile(const wxString &aFileName)
bool LoadProjectSettings()
Load the current project's file configuration settings which are pertinent to this PCB_EDIT_FRAME ins...
void ReleaseFile()
Release the current file marked in use.
void Collect(BOARD_ITEM *aBoard, const KICAD_T aScanList[])
Tests a BOARD_ITEM using this class's Inspector method, which does the collection.
Definition: collectors.cpp:543
BOARD_DESIGN_SETTINGS & GetDesignSettings() const
Function GetDesignSettings.
Definition: class_board.h:531
#define KICTL_EAGLE_BRD
chosen *.brd file is Eagle according to user.
Definition: kiway_player.h:78
int inferLegacyEdgeClearance(BOARD *aBoard)
Use the existing edge_cut line thicknesses to infer the edge clearace.
Collect all BOARD_ITEM objects on a given layer.
Definition: collectors.h:650
const std::string KiCadPcbFileExtension
bool IsWritable(const wxFileName &aFileName)
Checks if aFileName can be written.
A logical library item identifier and consists of various portions much like a URI.
Definition: lib_id.h:51
#define NO_BACKUP_FILE
bool SetCurrentNetClass(const wxString &aNetClassName)
Function SetCurrentNetClass Must be called after a netclass selection (or after a netclass parameter ...
Class PROPERTIES is a name/value tuple with unique names and optional values.
Definition: properties.h:34
const wxString & GetFileName() const
Definition: class_board.h:216
virtual const wxString Problem() const
what was the problem?
Definition: exceptions.cpp:49
VTBL_ENTRY const wxString GetProjectPath() const
Function GetProjectPath returns the full path of the project.
Definition: project.cpp:102
bool fixEagleNets(const std::unordered_map< wxString, wxString > &aRemap)
Rematch orphaned zones and vias to schematic nets.
std::unique_ptr< wxSingleInstanceChecker > m_file_checker
prevents opening same file multiple times.
void SetLayerId(PCB_LAYER_ID aLayerId)
Definition: collectors.h:660
VTBL_ENTRY const wxString AbsolutePath(const wxString &aFileName) const
Function AbsolutePath fixes up aFileName if it is relative to the project's directory to be an absolu...
Definition: project.cpp:385
This file contains miscellaneous commonly used macros and functions.
void UpdateFileHistory(const wxString &FullFileName, FILE_HISTORY *aFileHistory=NULL)
Update the list of recently opened files.
Class RELEASER releases a PLUGIN in the context of a potential thrown exception, through its destruct...
Definition: io_mgr.h:577
wxSize m_TextSize[LAYER_CLASS_COUNT]
int GetCount() const
Function GetCount returns the number of objects in the list.
Definition: collector.h:113
void SynchronizeNetsAndNetClasses()
Function SynchronizeNetsAndNetClasses copies NETCLASS info to each NET, based on NET membership in a ...
Definition: netclass.cpp:155
wxString LegacyPcbFileWildcard()
int m_HoleToHoleMin
Min width of peninsula between two drilled holes.
int m_TextThickness[LAYER_CLASS_COUNT]
void CheckForAutoSaveFile(const wxFileName &aFileName)
Check if an auto save file exists for aFileName and takes the appropriate action depending on the use...
Class NETLIST stores all of information read from a netlist along with the flags used to update the N...
Definition: pcb_netlist.h:217
virtual const wxString What() const
A composite of Problem() and Where()
Definition: exceptions.cpp:33
bool OpenProjectFiles(const std::vector< wxString > &aFileSet, int aCtl=0) override
Function OpenProjectFiles (was LoadOnePcbFile) loads a KiCad board (.kicad_pcb) from aFileName.
static wxString GetBackupSuffix()
static const char Default[]
the name of the default NETCLASS
Definition: netclass.h:80
void onBoardLoaded()
Updates the state of the GUI after a new board is loaded or created.
PROJECT & Prj() const
Function Prj returns a reference to the PROJECT "associated with" this KIWAY.
bool AskLoadBoardFileName(wxWindow *aParent, int *aCtl, wxString *aFileName, bool aKicadFilesOnly)
Function AskLoadBoardFileName puts up a wxFileDialog asking for a BOARD filename to open.
Definition: colors.h:59
PCB_LAYER_WIDGET * m_Layers
Layer manager. It is the responsibility of the child frames to instantiate this.
bool m_TextItalic[LAYER_CLASS_COUNT]
Definition of file extensions used in Kicad.
const wxString & GetNetname() const
Function GetNetname.
Definition: netinfo.h:233
wxLogTrace helper definitions.
virtual void SetFocus() override
#define PcbFileExtension
void BuildConnectivity()
Builds or rebuilds the board connectivity database for the board, especially the list of connected it...
void SetFileName(const wxString &aFileName)
Definition: class_board.h:214
virtual void ClearMsgPanel()
Clear all messages from the message panel.
VTBL_ENTRY void SetProjectFullName(const wxString &aFullPathAndName)
Function SetProjectFullName sets the: 1) full directory, 2) basename, and 3) extension of the project...
Definition: project.cpp:64
#define _(s)
int m_LineThickness[LAYER_CLASS_COUNT]
int GetFileFormatVersionAtLoad() const
Definition: class_board.h:266
constexpr std::size_t arrayDim(T const (&)[N]) noexcept
Definition: macros.h:108
VTBL_ENTRY FP_LIB_TABLE * PcbFootprintLibs(KIWAY &aKiway)
Return the table of footprint libraries.
int SetLibNickname(const UTF8 &aNickname)
Override the logical library name portion of the LIB_ID to aNickname.
Definition: lib_id.cpp:193
static wxString GetAutoSaveFilePrefix()
void AppendMsgPanel(const wxString &textUpper, const wxString &textLower, COLOR4D color, int pad=6)
Append a message to the message panel.
bool m_RequireCourtyards
require courtyard definitions in footprints
#define CREATE_BACKUP_FILE
Class NETINFO_ITEM handles the data for a net.
Definition: netinfo.h:65
void OnFileHistory(wxCommandEvent &event)
wxString GetFileFromHistory(int cmdId, const wxString &type, FILE_HISTORY *aFileHistory=NULL)
Fetches the file name from the file history list.
static const struct @8 fileFilters[FILTER_COUNT]
ZONE_CONTAINERS & Zones()
Definition: class_board.h:241
static const wxChar * GetChars(const wxString &s)
Function GetChars returns a wxChar* to the actual wxChar* data within a wxString, and is helpful for ...
Definition: macros.h:101
Legacy Pcbnew file formats prior to s-expression.
Definition: io_mgr.h:56
see class PGM_BASE
void SetBoard(BOARD *aBoard) override
Declaration of the eda_3d_viewer class.
const char * name
Definition: DXF_plotter.cpp:61
void Format(OUTPUTFORMATTER *out, int aNestLevel, int aCtl, CPTREE &aTree)
Function Format outputs a PTREE into s-expression format via an OUTPUTFORMATTER derivative.
Definition: ptree.cpp:205
void DoUpdatePCBFromNetlist(NETLIST &aNetlist, bool aUseTimestamps)
Function DoUpdatePCBFromNetlist An automated version of UpdatePCBFromNetlist which skips the UI dialo...
void ArchiveModulesOnBoard(bool aStoreInNewLib, const wxString &aLibName=wxEmptyString, wxString *aLibPath=NULL)
Function ArchiveModulesOnBoard Save modules in a library:
int GetNet() const
Function GetNet.
Definition: netinfo.h:225
#define max(a, b)
Definition: auxiliary.h:86
Class BOARD holds information pertinent to a Pcbnew printed circuit board.
Definition: class_board.h:161
void Files_io(wxCommandEvent &event)
Function Files_io.
unsigned GetRunningMicroSecs()
Function GetRunningMicroSecs An alternate way to calculate an elapset time (in microsecondes) to clas...
static PLUGIN * PluginFind(PCB_FILE_T aFileType)
Function PluginFind returns a PLUGIN which the caller can use to import, export, save,...
Definition: io_mgr.cpp:58
size_t i
Definition: json11.cpp:649
bool AskSaveBoardFileName(wxWindow *aParent, wxString *aFileName)
Function AskSaveBoardFileName puts up a wxFileDialog asking for a BOARD filename to save.
void ClrModify()
Definition: base_screen.h:225
wxString PcbFileWildcard()
void Save(const wxString &aFileName) const
Write this library table to aFileName in s-expression form.
PCB_SCREEN * GetScreen() const override
Return a pointer to a BASE_SCREEN or one of its derivatives.
const wxSize GetPageSizeIU() const override
Works off of GetPageSettings() to return the size of the paper page in the internal units of this par...
bool Files_io_from_id(int aId)
Function Files_io_from_id Read and write board files.
Create and handle a window for the 3d viewer connected to a Kiway and a pcbboard.
Definition: eda_3d_viewer.h:56
BOARD_DESIGN_SETTINGS m_designSettings
Definition: class_board.h:194
BOARD * GetBoard() const
void SetModify()
Definition: base_screen.h:224
class DRAWSEGMENT, a segment not on copper layers
Definition: typeinfo.h:91
Message panel definition file.
PCB_FILE_T
Enum PCB_FILE_T is a set of file types that the IO_MGR knows about, and for which there has been a pl...
Definition: io_mgr.h:54
void DisplayInfoMessage(wxWindow *aParent, const wxString &aMessage, const wxString &aExtraInfo)
Display an informational message box with aMessage.
Definition: confirm.cpp:264
void NewDisplay(bool aForceImmediateRedraw=false)
Reload and refresh (rebuild) the 3D scene.
wxString PCadPcbFileWildcard()
EDA_3D_VIEWER * Get3DViewerFrame()
bool Clear_Pcb(bool aQuery, bool aFinal=false)
Function Clear_Pcb delete all and reinitialize the current board.
Definition: initpcb.cpp:39
bool SavePcbFile(const wxString &aFileName, bool aCreateBackupFile=CREATE_BACKUP_FILE)
Function SavePcbFile writes the board data structures to a aFileName Creates backup when requested an...
Struct IO_ERROR is a class used to hold an error message and may be used when throwing exceptions con...
Definition: ki_exception.h:76
bool IsOK(wxWindow *aParent, const wxString &aMessage)
Display a yes/no dialog with aMessage and returns the user response.
Definition: confirm.cpp:280
bool IsEmpty() const
Definition: class_board.h:257
void ClrSave()
Definition: base_screen.h:227
bool FetchNetlistFromSchematic(NETLIST &aNetlist, FETCH_NETLIST_MODE aMode)
TRACKS & Tracks()
Definition: class_board.h:218
bool m_TextUpright[LAYER_CLASS_COUNT]
VTBL_ENTRY const wxString FootprintLibTblName() const
Function FootprintLibTblName returns the path and filename of this project's fp-lib-table,...
Definition: project.cpp:120
bool LockFile(const wxString &aFileName)
Mark a schematic file as being in use.
bool empty() const
Definition: utf8.h:108
S-expression Pcbnew file format.
Definition: io_mgr.h:57
Class BOARD_DESIGN_SETTINGS contains design settings for a BOARD object.
static const wxString GetFileExtension(PCB_FILE_T aFileType)
Function GetFileExtension returns the file extension for aFileType.
Definition: io_mgr.cpp:109