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