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 
31 #include <fctsys.h>
32 #include <class_drawpanel.h>
33 #include <confirm.h>
34 #include <kicad_string.h>
35 #include <gestfich.h>
36 #include <pcb_edit_frame.h>
37 #include <macros.h>
39 #include <richio.h>
40 #include <filter_reader.h>
41 #include <pgm_base.h>
42 #include <msgpanel.h>
43 #include <fp_lib_table.h>
44 #include <ratsnest_data.h>
45 #include <kiway.h>
46 #include <kiway_player.h>
47 #include <trace_helpers.h>
48 #include <lockfile.cpp>
49 
50 #include <pcbnew.h>
51 #include <pcbnew_id.h>
52 #include <io_mgr.h>
54 
55 #include <class_board.h>
56 #include <build_version.h> // LEGACY_BOARD_FILE_VERSION
57 
58 #include <wx/stdpaths.h>
59 
60 
61 //#define USE_INSTRUMENTATION 1
62 #define USE_INSTRUMENTATION 0
63 
64 
65 static const wxChar backupSuffix[] = wxT( "-bak" );
66 static const wxChar autosavePrefix[] = wxT( "_autosave-" );
67 
68 
70 {
71  return wxString( autosavePrefix );
72 }
73 
74 
87 bool AskLoadBoardFileName( wxWindow* aParent, int* aCtl, wxString* aFileName, bool aKicadFilesOnly )
88 {
89  // This is a subset of all PLUGINs which are trusted to be able to
90  // load a BOARD. User may occasionally use the wrong plugin to load a
91  // *.brd file (since both legacy and eagle use *.brd extension),
92  // but eventually *.kicad_pcb will be more common than legacy *.brd files.
93  static const struct
94  {
95  const wxString& filter;
96  IO_MGR::PCB_FILE_T pluginType;
97  } loaders[] =
98  {
99  { PcbFileWildcard(), IO_MGR::KICAD_SEXP }, // Current Kicad board files
100  { LegacyPcbFileWildcard(), IO_MGR::LEGACY }, // Old Kicad board files
101  { EaglePcbFileWildcard(), IO_MGR::EAGLE }, // Import board files
102  { PCadPcbFileWildcard(), IO_MGR::PCAD }, // Import board files
103  };
104 
105  wxFileName fileName( *aFileName );
106  wxString fileFilters;
107 
108  if( aKicadFilesOnly )
109  {
110  for( unsigned ii = 0; ii < 2; ++ii )
111  {
112  if( !fileFilters.IsEmpty() )
113  fileFilters += wxChar( '|' );
114 
115  fileFilters += wxGetTranslation( loaders[ii].filter );
116  }
117  }
118  else
119  {
120  for( unsigned ii = 2; ii < DIM( loaders ); ++ii )
121  {
122  if( !fileFilters.IsEmpty() )
123  fileFilters += wxChar( '|' );
124 
125  fileFilters += wxGetTranslation( loaders[ii].filter );
126  }
127  }
128 
129  wxString path;
130  wxString name;
131 
132  if( fileName.FileExists() )
133  {
134  path = fileName.GetPath();
135  name = fileName.GetFullName();
136  }
137  else
138  {
139  path = wxStandardPaths::Get().GetDocumentsDir();
140  // leave name empty
141  }
142 
143  wxFileDialog dlg( aParent,
144  aKicadFilesOnly ? _( "Open Board File" ) : _( "Import Non KiCad Board File" ),
145  path, name, fileFilters,
146  wxFD_OPEN | wxFD_FILE_MUST_EXIST );
147 
148  if( dlg.ShowModal() == wxID_OK )
149  {
150  // For import option, if Eagle (*.brd files), tell OpenProjectFiles() to use Eagle plugin.
151  // It's the only special case because of the duplicate use of the *.brd file extension.
152  // Other cases are clear because of unique file extensions.
153  *aCtl = aKicadFilesOnly ? 0 : KICTL_EAGLE_BRD;
154  *aFileName = dlg.GetPath();
155  return true;
156  }
157  else
158  return false;
159 }
160 
161 
172 bool AskSaveBoardFileName( wxWindow* aParent, wxString* aFileName )
173 {
174  wxString wildcard = PcbFileWildcard();
175  wxFileName fn = *aFileName;
176 
177  fn.SetExt( KiCadPcbFileExtension );
178 
179  wxFileDialog dlg( aParent,
180  _( "Save Board File As" ),
181  fn.GetPath(),
182  fn.GetFullName(),
183  wildcard,
184  wxFD_SAVE | wxFD_OVERWRITE_PROMPT
185  );
186 
187  if( dlg.ShowModal() != wxID_OK )
188  return false;
189 
190  fn = dlg.GetPath();
191 
192  // always enforce filename extension, user may not have entered it.
193  fn.SetExt( KiCadPcbFileExtension );
194 
195  *aFileName = fn.GetFullPath();
196 
197  return true;
198 }
199 
200 
201 void PCB_EDIT_FRAME::OnFileHistory( wxCommandEvent& event )
202 {
203  wxString fn = GetFileFromHistory( event.GetId(), _( "Printed circuit board" ) );
204 
205  if( !!fn )
206  {
207  int open_ctl = 0;
208 
210 
211  if( !wxFileName::IsFileReadable( fn ) )
212  {
213  if( !AskLoadBoardFileName( this, &open_ctl, &fn, true ) )
214  return;
215  }
216 
217  OpenProjectFiles( std::vector<wxString>( 1, fn ), open_ctl );
218  }
219 }
220 
221 
222 void PCB_EDIT_FRAME::Files_io( wxCommandEvent& event )
223 {
224  int id = event.GetId();
225  Files_io_from_id( id );
226 }
227 
228 
230 {
231  wxString msg;
232 
233  // If an edit is in progress, stop it.
234  // For something else than save, get rid of current tool.
235  if( id == ID_SAVE_BOARD )
237  else
239 
240  switch( id )
241  {
242  case ID_LOAD_FILE:
243  {
244  int open_ctl = 0;
245  wxString fileName = Prj().AbsolutePath( GetBoard()->GetFileName() );
246 
247  return AskLoadBoardFileName( this, &open_ctl, &fileName, true )
248  && OpenProjectFiles( std::vector<wxString>( 1, fileName ), open_ctl );
249  }
250 
252  {
253  int open_ctl = 1;
254  wxString fileName; // = Prj().AbsolutePath( GetBoard()->GetFileName() );
255 
256  return AskLoadBoardFileName( this, &open_ctl, &fileName, false )
257  && OpenProjectFiles( std::vector<wxString>( 1, fileName ), open_ctl );
258  }
259 
262  {
263  wxFileName currfn = Prj().AbsolutePath( GetBoard()->GetFileName() );
264  wxFileName fn = currfn;
265 
267  {
268  wxString rec_name = wxString( autosavePrefix ) + fn.GetName();
269  fn.SetName( rec_name );
270  }
271  else
272  {
273  wxString backup_ext = fn.GetExt()+ backupSuffix;
274  fn.SetExt( backup_ext );
275  }
276 
277  if( !fn.FileExists() )
278  {
279  msg.Printf( _( "Recovery file \"%s\" not found." ), fn.GetFullPath() );
280  DisplayInfoMessage( this, msg );
281  return false;
282  }
283 
284  msg.Printf( _( "OK to load recovery or backup file \"%s\"" ), fn.GetFullPath() );
285 
286  if( !IsOK( this, msg ) )
287  return false;
288 
289  GetScreen()->ClrModify(); // do not prompt the user for changes
290 
291  if( OpenProjectFiles( std::vector<wxString>( 1, fn.GetFullPath() ) ) )
292  {
293  // Re-set the name since name or extension was changed
294  GetBoard()->SetFileName( currfn.GetFullPath() );
295  UpdateTitle();
296  return true;
297  }
298  return false;
299  }
300 
301  case ID_APPEND_FILE:
302  {
303  int open_ctl;
304  wxString fileName;
305 
306  if( !AskLoadBoardFileName( this, &open_ctl, &fileName, true ) )
307  return false;
308 
309  if( AppendBoardFile( fileName, open_ctl ) )
310  {
311  m_canvas->Refresh();
312  return true;
313  }
314  return false;
315  }
316 
317  case ID_NEW_BOARD:
318  {
319  if( !Clear_Pcb( true ) )
320  return false;
321 
322  wxFileName fn( wxStandardPaths::Get().GetDocumentsDir(), wxT( "noname" ),
324 
325  Prj().SetProjectFullName( fn.GetFullPath() );
326 
327  fn.SetExt( PcbFileExtension );
328 
329  GetBoard()->SetFileName( fn.GetFullPath() );
330 
331  onBoardLoaded();
332 
333  OnModify();
334  return true;
335  }
336 
337  case ID_SAVE_BOARD:
338  if( !GetBoard()->GetFileName().IsEmpty() )
339  return SavePcbFile( Prj().AbsolutePath( GetBoard()->GetFileName() ) );
340  // Fall through
341 
342  case ID_COPY_BOARD_AS:
343  case ID_SAVE_BOARD_AS:
344  {
345  wxString pro_dir = wxPathOnly( Prj().GetProjectFullName() );
346  wxFileName fn( pro_dir, _( "noname" ), KiCadPcbFileExtension );
347  wxString filename = fn.GetFullPath();
348 
349  if( AskSaveBoardFileName( this, &filename ) )
350  {
351  if( id == ID_COPY_BOARD_AS )
352  return SavePcbCopy( filename );
353  else
354  return SavePcbFile( filename, NO_BACKUP_FILE );
355  }
356  return false;
357  }
358 
359  default:
360  DisplayError( this, wxT( "File_io Internal Error" ) );
361  return false;
362  }
363 }
364 
365 
366 // The KIWAY_PLAYER::OpenProjectFiles() API knows nothing about plugins, so
367 // determine how to load the BOARD here, with minor assistance from KICTL_EAGLE_BRD
368 // bit flag.
369 IO_MGR::PCB_FILE_T plugin_type( const wxString& aFileName, int aCtl )
370 {
371  IO_MGR::PCB_FILE_T pluginType;
372 
373  wxFileName fn = aFileName;
374 
375  // Note: file extensions are expected to be in ower case.
376  // This is not always true, especially when importing files, so the string
377  // comparisons are case insensitive to try to find the suitable plugin.
378 
379  if( fn.GetExt().CmpNoCase( IO_MGR::GetFileExtension( IO_MGR::LEGACY ) ) == 0 )
380  {
381  // both legacy and eagle share a common file extension.
382  pluginType = ( aCtl & KICTL_EAGLE_BRD ) ? IO_MGR::EAGLE : IO_MGR::LEGACY;
383  }
384  else if( fn.GetExt().CmpNoCase( IO_MGR::GetFileExtension( IO_MGR::LEGACY ) + backupSuffix ) == 0 )
385  {
386  pluginType = IO_MGR::LEGACY;
387  }
388  else if( fn.GetExt().CmpNoCase( IO_MGR::GetFileExtension( IO_MGR::PCAD ) ) == 0 )
389  {
390  pluginType = IO_MGR::PCAD;
391  }
392  else
393  {
394  pluginType = IO_MGR::KICAD_SEXP;
395  }
396 
397  return pluginType;
398 }
399 
400 
401 bool PCB_EDIT_FRAME::OpenProjectFiles( const std::vector<wxString>& aFileSet, int aCtl )
402 {
403  // This is for python:
404  if( aFileSet.size() != 1 )
405  {
406  UTF8 msg = StrPrintf( "Pcbnew:%s() takes only a single filename", __func__ );
407  DisplayError( this, msg );
408  return false;
409  }
410 
411  wxString fullFileName( aFileSet[0] );
412 
413  // We insist on caller sending us an absolute path, if it does not, we say it's a bug.
414  wxASSERT_MSG( wxFileName( fullFileName ).IsAbsolute(), wxT( "Path is not absolute!" ) );
415 
416  std::unique_ptr<wxSingleInstanceChecker> lockFile = ::LockFile( fullFileName );
417 
418  if( !lockFile )
419  {
420  wxString msg = wxString::Format( _( "PCB file \"%s\" is already open." ), fullFileName );
421  DisplayError( this, msg );
422  return false;
423  }
424 
425  m_file_checker.reset( lockFile.release() );
426 
427  if( GetScreen()->IsModify() && !GetBoard()->IsEmpty() )
428  {
429  if( !HandleUnsavedChanges( this, _( "The current PCB has been modified. Save changes?" ),
430  [&]()->bool { return SavePcbFile( GetBoard()->GetFileName(), CREATE_BACKUP_FILE ); } ) )
431  {
432  return false;
433  }
434  }
435 
436  wxFileName pro = fullFileName;
437  pro.SetExt( ProjectFileExtension );
438 
439  bool is_new = !wxFileName::IsFileReadable( fullFileName );
440 
441  // If its a non-existent schematic and caller thinks it exists
442  if( is_new && !( aCtl & KICTL_CREATE ) )
443  {
444  // notify user that fullFileName does not exist, ask if user wants to create it.
445  wxString ask = wxString::Format( _( "PCB \"%s\" does not exist. Do you wish to create it?" ),
446  fullFileName );
447  if( !IsOK( this, ask ) )
448  return false;
449  }
450 
451  Clear_Pcb( false ); // pass false since we prompted above for a modified board
452 
453  IO_MGR::PCB_FILE_T pluginType = plugin_type( fullFileName, aCtl );
454 
455  bool converted = pluginType != IO_MGR::LEGACY && pluginType != IO_MGR::KICAD_SEXP;
456 
457  if( !converted )
458  {
459  // PROJECT::SetProjectFullName() is an impactful function. It should only be
460  // called under carefully considered circumstances.
461 
462  // The calling code should know not to ask me here to change projects unless
463  // it knows what consequences that will have on other KIFACEs running and using
464  // this same PROJECT. It can be very harmful if that calling code is stupid.
465  Prj().SetProjectFullName( pro.GetFullPath() );
466 
467  // load project settings before BOARD
469  }
470 
471  if( is_new )
472  {
473  OnModify();
474  }
475  else
476  {
477  BOARD* loadedBoard = 0; // it will be set to non-NULL if loaded OK
478 
479  PLUGIN::RELEASER pi( IO_MGR::PluginFind( pluginType ) );
480 
481  try
482  {
483  PROPERTIES props;
484  char xbuf[30];
485  char ybuf[30];
486 
487  // EAGLE_PLUGIN can use this info to center the BOARD, but it does not yet.
488  sprintf( xbuf, "%d", GetPageSizeIU().x );
489  sprintf( ybuf, "%d", GetPageSizeIU().y );
490 
491  props["page_width"] = xbuf;
492  props["page_height"] = ybuf;
493 
494 #if USE_INSTRUMENTATION
495  // measure the time to load a BOARD.
496  unsigned startTime = GetRunningMicroSecs();
497 #endif
498 
499  loadedBoard = pi->Load( fullFileName, NULL, &props );
500 
501 #if USE_INSTRUMENTATION
502  unsigned stopTime = GetRunningMicroSecs();
503  printf( "PLUGIN::Load(): %u usecs\n", stopTime - startTime );
504 #endif
505  }
506  catch( const IO_ERROR& ioe )
507  {
508  DisplayErrorMessage( this,
509  wxString::Format( _( "Error loading board file:\n%s" ), fullFileName ),
510  ioe.What() );
511  return false;
512  }
513 
514  // 6.0 TODO: some settings didn't make it into the board file in 5.1 so as not to
515  // change the file format. For 5.1 we must copy them across from the config-initialized
516  // board.
517  BOARD_DESIGN_SETTINGS& bds = loadedBoard->m_designSettings;
519 
522  bds.m_HoleToHoleMin = configBds.m_HoleToHoleMin;
526  std::copy( configBds.m_TextItalic, configBds.m_TextItalic + 4, bds.m_TextItalic );
527  std::copy( configBds.m_TextUpright, configBds.m_TextUpright + 4, bds.m_TextUpright );
529 
530  SetBoard( loadedBoard );
531 
532  // we should not ask PLUGINs to do these items:
533  loadedBoard->BuildListOfNets();
534  loadedBoard->SynchronizeNetsAndNetClasses();
535 
536  GetScreen()->ClrModify();
537 
538  {
539  wxFileName fn = fullFileName;
540  CheckForAutoSaveFile( fullFileName, fn.GetExt() );
541  }
542 
543  if( pluginType == IO_MGR::LEGACY &&
544  loadedBoard->GetFileFormatVersionAtLoad() < LEGACY_BOARD_FILE_VERSION )
545  {
546  DisplayInfoMessage( this,
547  _( "This file was created by an older version of Pcbnew.\n"
548  "It will be stored in the new file format when you save this file again." ) );
549  }
550  }
551 
552  {
553  wxFileName fn = fullFileName;
554 
555  if( converted )
556  fn.SetExt( PcbFileExtension );
557 
558  wxString fname = fn.GetFullPath();
559 
560  fname.Replace( WIN_STRING_DIR_SEP, UNIX_STRING_DIR_SEP );
561 
562  GetBoard()->SetFileName( fname );
563  }
564 
565  if( !converted )
566  UpdateFileHistory( GetBoard()->GetFileName() );
567 
568  // Rebuild the new pad list (for drc and ratsnet control ...)
569  GetBoard()->m_Status_Pcb = 0;
570 
571  // Select netclass Default as current netclass (it always exists)
573 
574  // When GAL is active, the connectivity is rebuilt when the board is loaded
575  // For legacy, we keep these calls to ensure ratsnest
576  // todo: Remove legacy code
577  if( !IsGalCanvasActive() )
578  {
579  // Rebuild list of nets (full ratsnest rebuild)
580  Compile_Ratsnest( NULL, true );
582  }
583 
584  onBoardLoaded();
585 
586  // Refresh the 3D view, if any
587  EDA_3D_VIEWER* draw3DFrame = Get3DViewerFrame();
588 
589  if( draw3DFrame )
590  draw3DFrame->NewDisplay();
591 
592 #if 0 && defined(DEBUG)
593  // Output the board object tree to stdout, but please run from command prompt:
594  GetBoard()->Show( 0, std::cout );
595 #endif
596 
597  // from EDA_APPL which was first loaded BOARD only:
598  {
599  /* For an obscure reason the focus is lost after loading a board file
600  * when starting up the process.
601  * (seems due to the recreation of the layer manager after loading the file)
602  * Give focus to main window and Drawpanel
603  * must be done for these 2 windows (for an obscure reason ...)
604  * Linux specific
605  * This is more a workaround than a fix.
606  */
607  SetFocus();
608  GetCanvas()->SetFocus();
609  }
610 
611  return true;
612 }
613 
614 
615 static wxString create_backup_file( const wxString& aFileName )
616 {
617  wxFileName fn = aFileName;
618  wxFileName backupFileName = aFileName;
619 
620  backupFileName.SetExt( fn.GetExt() + backupSuffix );
621 
622  // If an old backup file exists, delete it. If an old board file exists,
623  // rename it to the backup file name.
624  if( fn.FileExists() )
625  {
626  // Remove the old file xxx.000 if it exists.
627  if( backupFileName.FileExists() )
628  wxRemoveFile( backupFileName.GetFullPath() );
629 
630  // Rename the current file from <xxx>.kicad_pcb to <xxx>.kicad_pcb-bak
631  if( !wxRenameFile( fn.GetFullPath(), backupFileName.GetFullPath() ) )
632  {
633  wxString msg = wxString::Format( _(
634  "Warning: unable to create backup file \"%s\"" ),
635  GetChars( backupFileName.GetFullPath() )
636  );
637  DisplayError( NULL, msg );
638  }
639  }
640  else
641  {
642  backupFileName.Clear();
643  }
644 
645  return backupFileName.GetFullPath();
646 }
647 
648 
649 bool PCB_EDIT_FRAME::SavePcbFile( const wxString& aFileName, bool aCreateBackupFile )
650 {
651  // please, keep it simple. prompting goes elsewhere.
652 
653  wxFileName pcbFileName = aFileName;
654 
655  if( pcbFileName.GetExt() == LegacyPcbFileExtension )
656  pcbFileName.SetExt( KiCadPcbFileExtension );
657 
658  if( !IsWritable( pcbFileName ) )
659  {
660  wxString msg = wxString::Format( _(
661  "No access rights to write to file \"%s\"" ),
662  GetChars( pcbFileName.GetFullPath() )
663  );
664 
665  DisplayError( this, msg );
666  return false;
667  }
668 
669  wxString backupFileName;
670 
671  // aCreateBackupFile == false is mainly used to write autosave files
672  // or new files in save as... command
673  if( aCreateBackupFile )
674  {
675  backupFileName = create_backup_file( aFileName );
676  }
677 
679 
680  // Select default Netclass before writing file.
681  // Useful to save default values in headers
683 
684  ClearMsgPanel();
685 
686  wxString upperTxt;
687  wxString lowerTxt;
688 
689  try
690  {
692 
693  wxASSERT( pcbFileName.IsAbsolute() );
694 
695  pi->Save( pcbFileName.GetFullPath(), GetBoard(), NULL );
696  }
697  catch( const IO_ERROR& ioe )
698  {
699  wxString msg = wxString::Format( _(
700  "Error saving board file \"%s\".\n%s" ),
701  GetChars( pcbFileName.GetFullPath() ),
702  GetChars( ioe.What() )
703  );
704  DisplayError( this, msg );
705 
706  lowerTxt.Printf( _( "Failed to create \"%s\"" ), GetChars( pcbFileName.GetFullPath() ) );
707 
708  AppendMsgPanel( upperTxt, lowerTxt, CYAN );
709 
710  return false;
711  }
712 
713  GetBoard()->SetFileName( pcbFileName.GetFullPath() );
714  UpdateTitle();
715 
716  // Put the saved file in File History, unless aCreateBackupFile
717  // is false.
718  // aCreateBackupFile == false is mainly used to write autosave files
719  // and not need to have an autosave file in file history
720  if( aCreateBackupFile )
721  UpdateFileHistory( GetBoard()->GetFileName() );
722 
723  // Delete auto save file on successful save.
724  wxFileName autoSaveFileName = pcbFileName;
725 
726  autoSaveFileName.SetName( wxString( autosavePrefix ) + pcbFileName.GetName() );
727 
728  if( autoSaveFileName.FileExists() )
729  wxRemoveFile( autoSaveFileName.GetFullPath() );
730 
731  if( !!backupFileName )
732  upperTxt.Printf( _( "Backup file: \"%s\"" ), GetChars( backupFileName ) );
733 
734  lowerTxt.Printf( _( "Wrote board file: \"%s\"" ), GetChars( pcbFileName.GetFullPath() ) );
735 
736  AppendMsgPanel( upperTxt, lowerTxt, CYAN );
737 
738  GetScreen()->ClrModify();
739  GetScreen()->ClrSave();
740  return true;
741 }
742 
743 
744 bool PCB_EDIT_FRAME::SavePcbCopy( const wxString& aFileName )
745 {
746  wxFileName pcbFileName = aFileName;
747 
748  // Ensure the file ext is the right ext:
749  pcbFileName.SetExt( KiCadPcbFileExtension );
750 
751  if( !IsWritable( pcbFileName ) )
752  {
753  wxString msg = wxString::Format( _(
754  "No access rights to write to file \"%s\"" ),
755  GetChars( pcbFileName.GetFullPath() )
756  );
757 
758  DisplayError( this, msg );
759  return false;
760  }
761 
763 
764  // Select default Netclass before writing file.
765  // Useful to save default values in headers
767 
768  try
769  {
771 
772  wxASSERT( pcbFileName.IsAbsolute() );
773 
774  pi->Save( pcbFileName.GetFullPath(), GetBoard(), NULL );
775  }
776  catch( const IO_ERROR& ioe )
777  {
778  wxString msg = wxString::Format( _(
779  "Error saving board file \"%s\".\n%s" ),
780  GetChars( pcbFileName.GetFullPath() ),
781  GetChars( ioe.What() )
782  );
783  DisplayError( this, msg );
784 
785  return false;
786  }
787 
788  DisplayInfoMessage( this, wxString::Format( _( "Board copied to:\n\"%s\"" ),
789  GetChars( pcbFileName.GetFullPath() ) ) );
790 
791  return true;
792 }
793 
794 
796 {
797  wxFileName tmpFileName;
798 
799  if( GetBoard()->GetFileName().IsEmpty() )
800  {
801  tmpFileName = wxFileName( wxStandardPaths::Get().GetDocumentsDir(), wxT( "noname" ),
803  GetBoard()->SetFileName( tmpFileName.GetFullPath() );
804  }
805  else
806  {
807  tmpFileName = Prj().AbsolutePath( GetBoard()->GetFileName() );
808  }
809 
810  wxFileName autoSaveFileName = tmpFileName;
811 
812  // Auto save file name is the board file name prepended with autosaveFilePrefix string.
813  autoSaveFileName.SetName( wxString( autosavePrefix ) + autoSaveFileName.GetName() );
814 
815  if( !autoSaveFileName.IsOk() )
816  return false;
817 
818  // If the board file path is not writable, try writing to a platform specific temp file
819  // path. If that path isn't writabe, give up.
820  if( !autoSaveFileName.IsDirWritable() )
821  {
822  autoSaveFileName.SetPath( wxFileName::GetTempDir() );
823 
824  if( !autoSaveFileName.IsOk() || !autoSaveFileName.IsDirWritable() )
825  return false;
826  }
827 
828  wxLogTrace( traceAutoSave, "Creating auto save file <" + autoSaveFileName.GetFullPath() + ">" );
829 
830  if( SavePcbFile( autoSaveFileName.GetFullPath(), NO_BACKUP_FILE ) )
831  {
832  GetScreen()->SetModify();
833  GetBoard()->SetFileName( tmpFileName.GetFullPath() );
834  UpdateTitle();
835  m_autoSaveState = false;
836  return true;
837  }
838 
839  GetBoard()->SetFileName( tmpFileName.GetFullPath() );
840 
841  return false;
842 }
843 
844 
845 bool PCB_EDIT_FRAME::importFile( const wxString& aFileName, int aFileType )
846 {
847  switch( (IO_MGR::PCB_FILE_T) aFileType )
848  {
849  case IO_MGR::EAGLE:
850  if( OpenProjectFiles( std::vector<wxString>( 1, aFileName ), KICTL_EAGLE_BRD ) )
851  {
852  wxString projectpath = Kiway().Prj().GetProjectPath();
853  wxFileName newfilename;
854 
855  newfilename.SetPath( Prj().GetProjectPath() );
856  newfilename.SetName( Prj().GetProjectName() );
857  newfilename.SetExt( KiCadPcbFileExtension );
858 
859  GetBoard()->SetFileName( newfilename.GetFullPath() );
860  UpdateTitle();
861  OnModify();
862 
863  // Extract a footprint library from the design and add it to the fp-lib-table
864  wxString newLibPath;
865  ArchiveModulesOnBoard( true, newfilename.GetName(), &newLibPath );
866 
867  if( newLibPath.Length() > 0 )
868  {
869  FP_LIB_TABLE* prjlibtable = Prj().PcbFootprintLibs();
870  const wxString& project_env = PROJECT_VAR_NAME;
871  wxString rel_path, env_path;
872 
873  wxGetEnv( project_env, &env_path );
874 
875  wxString result( newLibPath );
876  rel_path = result.Replace( env_path,
877  wxString( "$(" + project_env + ")" ) ) ? result : "" ;
878 
879  if( !rel_path.IsEmpty() )
880  newLibPath = rel_path;
881 
882  FP_LIB_TABLE_ROW* row = new FP_LIB_TABLE_ROW( newfilename.GetName(),
883  newLibPath, wxT( "KiCad" ), wxEmptyString );
884  prjlibtable->InsertRow( row );
885  }
886 
887  if( !GetBoard()->GetFileName().IsEmpty() )
888  {
889  wxString tblName = Prj().FootprintLibTblName();
890 
891  try
892  {
893  Prj().PcbFootprintLibs()->Save( tblName );
894  }
895  catch( const IO_ERROR& ioe )
896  {
897  wxString msg = wxString::Format( _(
898  "Error occurred saving project specific footprint library "
899  "table:\n\n%s" ),
900  GetChars( ioe.What() ) );
901  wxMessageBox( msg, _( "File Save Error" ), wxOK | wxICON_ERROR );
902  }
903  }
904 
905 
906  // Update module LIB_IDs to point to the just imported Eagle library
907  for( MODULE* module : GetBoard()->Modules() )
908  {
909  LIB_ID libId = module->GetFPID();
910 
911  if( libId.GetLibItemName().empty() )
912  continue;
913 
914  libId.SetLibNickname( newfilename.GetName() );
915  module->SetFPID( libId );
916  }
917 
918 
919  // Store net names for all pads, to create net remap information
920  std::unordered_map<D_PAD*, wxString> netMap;
921 
922  for( const auto& pad : GetBoard()->GetPads() )
923  {
924  NETINFO_ITEM* netinfo = pad->GetNet();
925 
926  if( netinfo->GetNet() > 0 && !netinfo->GetNetname().IsEmpty() )
927  netMap[pad] = netinfo->GetNetname();
928  }
929 
930  // Two stage netlist update:
931  // - first, assign valid timestamps to footprints (no reannotation)
932  // - second, perform schematic annotation and update footprint references
933  // based on timestamps
935  "no-annotate;by-reference", this );
937  "quiet-annotate;by-timestamp", this );
938 
939  std::unordered_map<wxString, wxString> netRemap;
940 
941  // Compare the old net names with the new net names and create a net map
942  for( const auto& pad : GetBoard()->GetPads() )
943  {
944  auto it = netMap.find( pad );
945 
946  if( it == netMap.end() )
947  continue;
948 
949  NETINFO_ITEM* netinfo = pad->GetNet();
950 
951  // Net name has changed, create a remap entry
952  if( netinfo->GetNet() > 0 && netMap[pad] != netinfo->GetNetname() )
953  netRemap[netMap[pad]] = netinfo->GetNetname();
954  }
955 
956  if( !netRemap.empty() )
957  fixEagleNets( netRemap );
958 
959  return true;
960  }
961 
962  return false;
963 
964  default:
965  return false;
966  }
967 
968  return false;
969 }
970 
971 
972 bool PCB_EDIT_FRAME::fixEagleNets( const std::unordered_map<wxString, wxString>& aRemap )
973 {
974  bool result = true;
975  BOARD* board = GetBoard();
976 
977  // perform netlist matching to prevent orphaned zones.
978  for( auto zone : board->Zones() )
979  {
980  auto it = aRemap.find( zone->GetNet()->GetNetname() );
981 
982  if( it != aRemap.end() )
983  {
984  NETINFO_ITEM* net = board->FindNet( it->second );
985 
986  if( !net )
987  {
988  wxFAIL;
989  result = false;
990  continue;
991  }
992 
993  zone->SetNet( net );
994  }
995  }
996 
997 
998  // perform netlist matching to prevent orphaned tracks/vias.
999  for( auto track : board->Tracks() )
1000  {
1001  auto it = aRemap.find( track->GetNet()->GetNetname() );
1002 
1003  if( it != aRemap.end() )
1004  {
1005  NETINFO_ITEM* net = board->FindNet( it->second );
1006 
1007  if( !net )
1008  {
1009  wxFAIL;
1010  result = false;
1011  continue;
1012  }
1013 
1014  track->SetNet( net );
1015  }
1016  }
1017 
1018  return result;
1019 }
void CheckForAutoSaveFile(const wxFileName &aFileName, const wxString &aBackupFileExtension)
Function CheckForAutoSaveFile checks if an auto save file exists for aFileName and takes the appropri...
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
#define DIM(x)
of elements in an array
Definition: macros.h:98
bool m_autoSaveState
Flag to indicate the last auto save state.
void BuildListOfNets()
Definition: class_board.h:729
virtual 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)
Function HandleUnsavedChanges displays a dialog with Save, Cancel and Discard Changes buttons...
Definition: confirm.cpp:213
#define WIN_STRING_DIR_SEP
Definition: gestfich.h:44
KIWAY & Kiway() const
Function Kiway returns a reference to the KIWAY that this object has an opportunity to participate in...
Definition: kiway_player.h:60
wxString EaglePcbFileWildcard()
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
virtual void Save(const wxString &aFileName, BOARD *aBoard, const PROPERTIES *aProperties=NULL)
Function Save will write aBoard to a storage file in a format that this PLUGIN implementation knows a...
Definition: plugin.cpp:53
virtual EDA_DRAW_PANEL * GetCanvas() const
Definition: draw_frame.h:388
bool importFile(const wxString &aFileName, int aFileType)
Load the given filename but sets the path to the current project path.
static wxString GetAutoSaveFilePrefix()
Function GetAutoSaveFilePrefix.
void DisplayErrorMessage(wxWindow *aParent, const wxString &aText, const wxString &aExtraInfo)
Function DisplayErrorMessage displays an error message with aMessage.
Definition: confirm.cpp:259
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.
Class FP_LIB_TABLE_ROW.
Definition: fp_lib_table.h:42
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, does not make anything else (no backup, borad fliename change, no flag changes ...) Used under a project mgr to save under a new name the current board.
bool m_ProhibitOverlappingCourtyards
check for overlapping courtyards in DRC
static wxString create_backup_file(const wxString &aFileName)
std::vector< DIFF_PAIR_DIMENSION > m_DiffPairDimensionsList
#define UNIX_STRING_DIR_SEP
Definition: gestfich.h:43
virtual 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:140
Class BOARD to handle a board.
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
bool Clear_Pcb(bool aQuery)
Function Clear_Pcb delete all and reinitialize the current board.
Definition: initpcb.cpp:39
virtual void EndMouseCapture(int aId=-1, int aCursorId=-1, const wxString &aTitle=wxEmptyString, bool aCallEndFunc=true)
Function EndMouseCapture ends mouse a capture.
bool LoadProjectSettings()
Load the current project&#39;s file configuration settings which are pertinent to this PCB_EDIT_FRAME ins...
BOARD * GetBoard() const
bool IsModify() const
Definition: base_screen.h:328
#define KICTL_EAGLE_BRD
chosen *.brd file is Eagle according to user.
Definition: kiway_player.h:139
const std::string KiCadPcbFileExtension
bool IsWritable(const wxFileName &aFileName)
Function IsWritable 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
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.
Definition: draw_frame.h:103
void UpdateFileHistory(const wxString &FullFileName, wxFileHistory *aFileHistory=NULL)
Function UpdateFileHistory Updates the list of recently opened files.
This file contains miscellaneous commonly used macros and functions.
VTBL_ENTRY void ExpressMail(FRAME_T aDestination, MAIL_T aCommand, std::string aPayload, wxWindow *aSource=NULL)
Function ExpressMail send aPayload to aDestination from aSource.
Definition: kiway.cpp:386
Class RELEASER releases a PLUGIN in the context of a potential thrown exception, through its destruct...
Definition: io_mgr.h:563
wxSize m_TextSize[LAYER_CLASS_COUNT]
bool AppendBoardFile(const wxString &aFullFileName, int aCtl)
Function AppendBoardFile appends a board file onto the current one, creating God knows what...
void SynchronizeNetsAndNetClasses()
Function SynchronizeNetsAndNetClasses copies NETCLASS info to each NET, based on NET membership in a ...
Definition: netclass.cpp:160
PROJECT & Prj() const
Function Prj returns a reference to the PROJECT "associated with" this KIWAY.
wxString LegacyPcbFileWildcard()
int m_HoleToHoleMin
Min width of peninsula between two drilled holes.
int m_TextThickness[LAYER_CLASS_COUNT]
bool empty() const
Definition: utf8.h:108
bool OpenProjectFiles(const std::vector< wxString > &aFileSet, int aCtl=0) override
Function OpenProjectFiles (was LoadOnePcbFile) loads a KiCad board (.kicad_pcb) from aFileName...
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.
const UTF8 & GetLibItemName() const
Definition: lib_id.h:114
bool IsEmpty() const
Definition: class_board.h:272
VTBL_ENTRY PROJECT & Prj() const
Function Prj returns the PROJECT associated with this KIWAY.
Definition: kiway.cpp:142
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
VTBL_ENTRY const wxString AbsolutePath(const wxString &aFileName) const
Function AbsolutePath fixes up aFileName if it is relative to the project&#39;s directory to be an absolu...
Definition: project.cpp:380
bool m_TextItalic[LAYER_CLASS_COUNT]
The common library.
BOARD_DESIGN_SETTINGS & GetDesignSettings() const
Function GetDesignSettings.
Definition: class_board.h:538
wxLogTrace helper definitions.
bool IsGalCanvasActive() const
Function IsGalCanvasActive is used to check which canvas (GAL-based or standard) is currently in use...
Definition: draw_frame.h:911
void Save(const wxString &aFileName) const
Write this library table to aFileName in s-expression form.
static const wxChar backupSuffix[]
#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:235
int GetNet() const
Function GetNet.
Definition: netinfo.h:231
VTBL_ENTRY const wxString FootprintLibTblName() const
Function FootprintLibTblName returns the path and filename of this project&#39;s fp-lib-table, i.e.
Definition: project.cpp:120
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
int m_LineThickness[LAYER_CLASS_COUNT]
int GetFileFormatVersionAtLoad() const
Definition: class_board.h:281
void Compile_Ratsnest(wxDC *aDC, bool aDisplayStatus)
Function Compile_Ratsnest Create the entire board ratsnest.
Definition: ratsnest.cpp:53
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 const wxChar autosavePrefix[]
EDA_DRAW_PANEL * m_canvas
The area to draw on.
Definition: draw_frame.h:123
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:69
virtual const wxString What() const
A composite of Problem() and Where()
Definition: exceptions.cpp:33
void OnFileHistory(wxCommandEvent &event)
ZONE_CONTAINERS & Zones()
Definition: class_board.h:256
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:92
Legacy Pcbnew file formats prior to s-expression.
Definition: io_mgr.h:54
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 ArchiveModulesOnBoard(bool aStoreInNewLib, const wxString &aLibName=wxEmptyString, wxString *aLibPath=NULL)
Function ArchiveModulesOnBoard Save modules in a library:
Class BOARD holds information pertinent to a Pcbnew printed circuit board.
Definition: class_board.h:170
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, or load design documents.
Definition: io_mgr.cpp:58
bool AskSaveBoardFileName(wxWindow *aParent, wxString *aFileName)
Function AskSaveBoardFileName puts up a wxFileDialog asking for a BOARD filename to save...
wxString GetFileFromHistory(int cmdId, const wxString &type, wxFileHistory *aFileHistory=NULL)
Function GetFileFromHistory fetches the file name from the file history list.
void ClrModify()
Definition: base_screen.h:325
wxString PcbFileWildcard()
NETINFO_ITEM * FindNet(int aNetcode) const
Function FindNet searches for a net with the given netcode.
VTBL_ENTRY const wxString GetProjectPath() const
Function GetProjectPath returns the full path of the project.
Definition: project.cpp:102
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.
Class EDA_3D_VIEWER Create and handle a window for the 3d viewer connected to a Kiway and a pcbboard...
Definition: eda_3d_viewer.h:50
DLIST_ITERATOR_WRAPPER< TRACK > Tracks()
Definition: class_board.h:253
BOARD_DESIGN_SETTINGS m_designSettings
Definition: class_board.h:194
const wxString & GetNetname() const
Function GetNetname.
Definition: netinfo.h:239
static const struct @9 fileFilters[FILTER_COUNT]
virtual void Refresh(bool eraseBackground=true, const wxRect *rect=NULL)
void SetModify()
Definition: base_screen.h:324
Message panel definition file.
int GetDefaultCursor() const
Function GetDefaultCursor.
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:52
void DisplayInfoMessage(wxWindow *aParent, const wxString &aMessage, const wxString &aExtraInfo)
Function DisplayInfoMessage displays an informational message box with aMessage.
Definition: confirm.cpp:277
void NewDisplay(bool aForceImmediateRedraw=false)
Reload and refresh (rebuild) the 3D scene.
wxString PCadPcbFileWildcard()
EDA_3D_VIEWER * Get3DViewerFrame()
void DisplayError(wxWindow *parent, const wxString &text, int displaytime)
Function DisplayError displays an error or warning message box with aMessage.
Definition: confirm.cpp:245
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)
Function IsOK displays a yes/no dialog with aMessage and returns the user response.
Definition: confirm.cpp:295
void ClrSave()
Definition: base_screen.h:327
void ClearMsgPanel(void)
Clear all messages from the message panel.
bool m_TextUpright[LAYER_CLASS_COUNT]
bool LockFile(const wxString &aFileName)
Mark a schematic file as being in use.
virtual BOARD * Load(const wxString &aFileName, BOARD *aAppendToMe, const PROPERTIES *aProperties=NULL)
Function Load loads information from some input file format that this PLUGIN implementation knows abo...
Definition: plugin.cpp:46
S-expression Pcbnew file format.
Definition: io_mgr.h:55
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
int m_Status_Pcb
Flags used in ratsnest calculation and update.
Definition: class_board.h:240