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 < arrayDim( 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  wxLogDebug( 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  if( ioe.Problem() != wxT( "CANCEL" ) )
509  {
510  wxString msg = wxString::Format( _( "Error loading board file:\n%s" ), fullFileName );
511  DisplayErrorMessage( this, msg, ioe.What() );
512  }
513 
514  return false;
515  }
516 
517  // 6.0 TODO: some settings didn't make it into the board file in 5.1 so as not to
518  // change the file format. For 5.1 we must copy them across from the config-initialized
519  // board.
520  BOARD_DESIGN_SETTINGS& bds = loadedBoard->m_designSettings;
522 
525  bds.m_HoleToHoleMin = configBds.m_HoleToHoleMin;
529  std::copy( configBds.m_TextItalic, configBds.m_TextItalic + 4, bds.m_TextItalic );
530  std::copy( configBds.m_TextUpright, configBds.m_TextUpright + 4, bds.m_TextUpright );
532 
533  SetBoard( loadedBoard );
534 
535  // we should not ask PLUGINs to do these items:
536  loadedBoard->BuildListOfNets();
537  loadedBoard->SynchronizeNetsAndNetClasses();
538 
539  GetScreen()->ClrModify();
540 
541  {
542  wxFileName fn = fullFileName;
543  CheckForAutoSaveFile( fullFileName, fn.GetExt() );
544  }
545 
546  if( pluginType == IO_MGR::LEGACY &&
547  loadedBoard->GetFileFormatVersionAtLoad() < LEGACY_BOARD_FILE_VERSION )
548  {
549  DisplayInfoMessage( this,
550  _( "This file was created by an older version of Pcbnew.\n"
551  "It will be stored in the new file format when you save this file again." ) );
552  }
553  }
554 
555  {
556  wxFileName fn = fullFileName;
557 
558  if( converted )
559  fn.SetExt( PcbFileExtension );
560 
561  wxString fname = fn.GetFullPath();
562 
563  fname.Replace( WIN_STRING_DIR_SEP, UNIX_STRING_DIR_SEP );
564 
565  GetBoard()->SetFileName( fname );
566  }
567 
568  if( !converted )
569  UpdateFileHistory( GetBoard()->GetFileName() );
570 
571  // Rebuild the new pad list (for drc and ratsnet control ...)
572  GetBoard()->m_Status_Pcb = 0;
573 
574  // Select netclass Default as current netclass (it always exists)
576 
577  // When GAL is active, the connectivity is rebuilt when the board is loaded
578  // For legacy, we keep these calls to ensure ratsnest
579  // todo: Remove legacy code
580  if( !IsGalCanvasActive() )
581  {
582  // Rebuild list of nets (full ratsnest rebuild)
583  Compile_Ratsnest( NULL, true );
585  }
586 
587  onBoardLoaded();
588 
589  // Refresh the 3D view, if any
590  EDA_3D_VIEWER* draw3DFrame = Get3DViewerFrame();
591 
592  if( draw3DFrame )
593  draw3DFrame->NewDisplay();
594 
595 #if 0 && defined(DEBUG)
596  // Output the board object tree to stdout, but please run from command prompt:
597  GetBoard()->Show( 0, std::cout );
598 #endif
599 
600  // from EDA_APPL which was first loaded BOARD only:
601  {
602  /* For an obscure reason the focus is lost after loading a board file
603  * when starting up the process.
604  * (seems due to the recreation of the layer manager after loading the file)
605  * Give focus to main window and Drawpanel
606  * must be done for these 2 windows (for an obscure reason ...)
607  * Linux specific
608  * This is more a workaround than a fix.
609  */
610  SetFocus();
611  GetCanvas()->SetFocus();
612  }
613 
614  return true;
615 }
616 
617 
618 static wxString create_backup_file( const wxString& aFileName )
619 {
620  wxFileName fn = aFileName;
621  wxFileName backupFileName = aFileName;
622 
623  backupFileName.SetExt( fn.GetExt() + backupSuffix );
624 
625  // If an old backup file exists, delete it. If an old board file exists,
626  // rename it to the backup file name.
627  if( fn.FileExists() )
628  {
629  // Remove the old file xxx.000 if it exists.
630  if( backupFileName.FileExists() )
631  wxRemoveFile( backupFileName.GetFullPath() );
632 
633  // Rename the current file from <xxx>.kicad_pcb to <xxx>.kicad_pcb-bak
634  if( !wxRenameFile( fn.GetFullPath(), backupFileName.GetFullPath() ) )
635  {
636  wxString msg = wxString::Format( _(
637  "Warning: unable to create backup file \"%s\"" ),
638  GetChars( backupFileName.GetFullPath() )
639  );
640  DisplayError( NULL, msg );
641  }
642  }
643  else
644  {
645  backupFileName.Clear();
646  }
647 
648  return backupFileName.GetFullPath();
649 }
650 
651 
652 bool PCB_EDIT_FRAME::SavePcbFile( const wxString& aFileName, bool aCreateBackupFile )
653 {
654  // please, keep it simple. prompting goes elsewhere.
655 
656  wxFileName pcbFileName = aFileName;
657 
658  if( pcbFileName.GetExt() == LegacyPcbFileExtension )
659  pcbFileName.SetExt( KiCadPcbFileExtension );
660 
661  if( !IsWritable( pcbFileName ) )
662  {
663  wxString msg = wxString::Format( _(
664  "No access rights to write to file \"%s\"" ),
665  GetChars( pcbFileName.GetFullPath() )
666  );
667 
668  DisplayError( this, msg );
669  return false;
670  }
671 
672  wxString backupFileName;
673 
674  // aCreateBackupFile == false is mainly used to write autosave files
675  // or new files in save as... command
676  if( aCreateBackupFile )
677  {
678  backupFileName = create_backup_file( aFileName );
679  }
680 
682 
683  // Select default Netclass before writing file.
684  // Useful to save default values in headers
686 
687  ClearMsgPanel();
688 
689  wxString upperTxt;
690  wxString lowerTxt;
691 
692  try
693  {
695 
696  wxASSERT( pcbFileName.IsAbsolute() );
697 
698  pi->Save( pcbFileName.GetFullPath(), GetBoard(), NULL );
699  }
700  catch( const IO_ERROR& ioe )
701  {
702  wxString msg = wxString::Format( _(
703  "Error saving board file \"%s\".\n%s" ),
704  GetChars( pcbFileName.GetFullPath() ),
705  GetChars( ioe.What() )
706  );
707  DisplayError( this, msg );
708 
709  lowerTxt.Printf( _( "Failed to create \"%s\"" ), GetChars( pcbFileName.GetFullPath() ) );
710 
711  AppendMsgPanel( upperTxt, lowerTxt, CYAN );
712 
713  return false;
714  }
715 
716  GetBoard()->SetFileName( pcbFileName.GetFullPath() );
717  UpdateTitle();
718 
719  // Put the saved file in File History, unless aCreateBackupFile
720  // is false.
721  // aCreateBackupFile == false is mainly used to write autosave files
722  // and not need to have an autosave file in file history
723  if( aCreateBackupFile )
724  UpdateFileHistory( GetBoard()->GetFileName() );
725 
726  // Delete auto save file on successful save.
727  wxFileName autoSaveFileName = pcbFileName;
728 
729  autoSaveFileName.SetName( wxString( autosavePrefix ) + pcbFileName.GetName() );
730 
731  if( autoSaveFileName.FileExists() )
732  wxRemoveFile( autoSaveFileName.GetFullPath() );
733 
734  if( !!backupFileName )
735  upperTxt.Printf( _( "Backup file: \"%s\"" ), GetChars( backupFileName ) );
736 
737  lowerTxt.Printf( _( "Wrote board file: \"%s\"" ), GetChars( pcbFileName.GetFullPath() ) );
738 
739  AppendMsgPanel( upperTxt, lowerTxt, CYAN );
740 
741  GetScreen()->ClrModify();
742  GetScreen()->ClrSave();
743  return true;
744 }
745 
746 
747 bool PCB_EDIT_FRAME::SavePcbCopy( const wxString& aFileName )
748 {
749  wxFileName pcbFileName = aFileName;
750 
751  // Ensure the file ext is the right ext:
752  pcbFileName.SetExt( KiCadPcbFileExtension );
753 
754  if( !IsWritable( pcbFileName ) )
755  {
756  wxString msg = wxString::Format( _(
757  "No access rights to write to file \"%s\"" ),
758  GetChars( pcbFileName.GetFullPath() )
759  );
760 
761  DisplayError( this, msg );
762  return false;
763  }
764 
766 
767  // Select default Netclass before writing file.
768  // Useful to save default values in headers
770 
771  try
772  {
774 
775  wxASSERT( pcbFileName.IsAbsolute() );
776 
777  pi->Save( pcbFileName.GetFullPath(), GetBoard(), NULL );
778  }
779  catch( const IO_ERROR& ioe )
780  {
781  wxString msg = wxString::Format( _(
782  "Error saving board file \"%s\".\n%s" ),
783  GetChars( pcbFileName.GetFullPath() ),
784  GetChars( ioe.What() )
785  );
786  DisplayError( this, msg );
787 
788  return false;
789  }
790 
791  DisplayInfoMessage( this, wxString::Format( _( "Board copied to:\n\"%s\"" ),
792  GetChars( pcbFileName.GetFullPath() ) ) );
793 
794  return true;
795 }
796 
797 
799 {
800  wxFileName tmpFileName;
801 
802  if( GetBoard()->GetFileName().IsEmpty() )
803  {
804  tmpFileName = wxFileName( wxStandardPaths::Get().GetDocumentsDir(), wxT( "noname" ),
806  GetBoard()->SetFileName( tmpFileName.GetFullPath() );
807  }
808  else
809  {
810  tmpFileName = Prj().AbsolutePath( GetBoard()->GetFileName() );
811  }
812 
813  wxFileName autoSaveFileName = tmpFileName;
814 
815  // Auto save file name is the board file name prepended with autosaveFilePrefix string.
816  autoSaveFileName.SetName( wxString( autosavePrefix ) + autoSaveFileName.GetName() );
817 
818  if( !autoSaveFileName.IsOk() )
819  return false;
820 
821  // If the board file path is not writable, try writing to a platform specific temp file
822  // path. If that path isn't writabe, give up.
823  if( !autoSaveFileName.IsDirWritable() )
824  {
825  autoSaveFileName.SetPath( wxFileName::GetTempDir() );
826 
827  if( !autoSaveFileName.IsOk() || !autoSaveFileName.IsDirWritable() )
828  return false;
829  }
830 
831  wxLogTrace( traceAutoSave, "Creating auto save file <" + autoSaveFileName.GetFullPath() + ">" );
832 
833  if( SavePcbFile( autoSaveFileName.GetFullPath(), NO_BACKUP_FILE ) )
834  {
835  GetScreen()->SetModify();
836  GetBoard()->SetFileName( tmpFileName.GetFullPath() );
837  UpdateTitle();
838  m_autoSaveState = false;
839  return true;
840  }
841 
842  GetBoard()->SetFileName( tmpFileName.GetFullPath() );
843 
844  return false;
845 }
846 
847 
848 bool PCB_EDIT_FRAME::importFile( const wxString& aFileName, int aFileType )
849 {
850  switch( (IO_MGR::PCB_FILE_T) aFileType )
851  {
852  case IO_MGR::EAGLE:
853  if( OpenProjectFiles( std::vector<wxString>( 1, aFileName ), KICTL_EAGLE_BRD ) )
854  {
855  wxString projectpath = Kiway().Prj().GetProjectPath();
856  wxFileName newfilename;
857 
858  newfilename.SetPath( Prj().GetProjectPath() );
859  newfilename.SetName( Prj().GetProjectName() );
860  newfilename.SetExt( KiCadPcbFileExtension );
861 
862  GetBoard()->SetFileName( newfilename.GetFullPath() );
863  UpdateTitle();
864  OnModify();
865 
866  // Extract a footprint library from the design and add it to the fp-lib-table
867  wxString newLibPath;
868  ArchiveModulesOnBoard( true, newfilename.GetName(), &newLibPath );
869 
870  if( newLibPath.Length() > 0 )
871  {
872  FP_LIB_TABLE* prjlibtable = Prj().PcbFootprintLibs();
873  const wxString& project_env = PROJECT_VAR_NAME;
874  wxString rel_path, env_path;
875 
876  wxGetEnv( project_env, &env_path );
877 
878  wxString result( newLibPath );
879  rel_path = result.Replace( env_path,
880  wxString( "$(" + project_env + ")" ) ) ? result : "" ;
881 
882  if( !rel_path.IsEmpty() )
883  newLibPath = rel_path;
884 
885  FP_LIB_TABLE_ROW* row = new FP_LIB_TABLE_ROW( newfilename.GetName(),
886  newLibPath, wxT( "KiCad" ), wxEmptyString );
887  prjlibtable->InsertRow( row );
888  }
889 
890  if( !GetBoard()->GetFileName().IsEmpty() )
891  {
892  wxString tblName = Prj().FootprintLibTblName();
893 
894  try
895  {
896  Prj().PcbFootprintLibs()->Save( tblName );
897  }
898  catch( const IO_ERROR& ioe )
899  {
900  wxString msg = wxString::Format( _(
901  "Error occurred saving project specific footprint library "
902  "table:\n\n%s" ),
903  GetChars( ioe.What() ) );
904  wxMessageBox( msg, _( "File Save Error" ), wxOK | wxICON_ERROR );
905  }
906  }
907 
908 
909  // Update module LIB_IDs to point to the just imported Eagle library
910  for( MODULE* module : GetBoard()->Modules() )
911  {
912  LIB_ID libId = module->GetFPID();
913 
914  if( libId.GetLibItemName().empty() )
915  continue;
916 
917  libId.SetLibNickname( newfilename.GetName() );
918  module->SetFPID( libId );
919  }
920 
921 
922  // Store net names for all pads, to create net remap information
923  std::unordered_map<D_PAD*, wxString> netMap;
924 
925  for( const auto& pad : GetBoard()->GetPads() )
926  {
927  NETINFO_ITEM* netinfo = pad->GetNet();
928 
929  if( netinfo->GetNet() > 0 && !netinfo->GetNetname().IsEmpty() )
930  netMap[pad] = netinfo->GetNetname();
931  }
932 
933  // Two stage netlist update:
934  // - first, assign valid timestamps to footprints (no reannotation)
935  // - second, perform schematic annotation and update footprint references
936  // based on timestamps
938  "no-annotate;by-reference", this );
940  "quiet-annotate;by-timestamp", this );
941 
942  std::unordered_map<wxString, wxString> netRemap;
943 
944  // Compare the old net names with the new net names and create a net map
945  for( const auto& pad : GetBoard()->GetPads() )
946  {
947  auto it = netMap.find( pad );
948 
949  if( it == netMap.end() )
950  continue;
951 
952  NETINFO_ITEM* netinfo = pad->GetNet();
953 
954  // Net name has changed, create a remap entry
955  if( netinfo->GetNet() > 0 && netMap[pad] != netinfo->GetNetname() )
956  netRemap[netMap[pad]] = netinfo->GetNetname();
957  }
958 
959  if( !netRemap.empty() )
960  fixEagleNets( netRemap );
961 
962  return true;
963  }
964 
965  return false;
966 
967  default:
968  return false;
969  }
970 
971  return false;
972 }
973 
974 
975 bool PCB_EDIT_FRAME::fixEagleNets( const std::unordered_map<wxString, wxString>& aRemap )
976 {
977  bool result = true;
978  BOARD* board = GetBoard();
979 
980  // perform netlist matching to prevent orphaned zones.
981  for( auto zone : board->Zones() )
982  {
983  auto it = aRemap.find( zone->GetNet()->GetNetname() );
984 
985  if( it != aRemap.end() )
986  {
987  NETINFO_ITEM* net = board->FindNet( it->second );
988 
989  if( !net )
990  {
991  wxFAIL;
992  result = false;
993  continue;
994  }
995 
996  zone->SetNet( net );
997  }
998  }
999 
1000 
1001  // perform netlist matching to prevent orphaned tracks/vias.
1002  for( auto track : board->Tracks() )
1003  {
1004  auto it = aRemap.find( track->GetNet()->GetNetname() );
1005 
1006  if( it != aRemap.end() )
1007  {
1008  NETINFO_ITEM* net = board->FindNet( it->second );
1009 
1010  if( !net )
1011  {
1012  wxFAIL;
1013  result = false;
1014  continue;
1015  }
1016 
1017  track->SetNet( net );
1018  }
1019  }
1020 
1021  return result;
1022 }
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
bool m_autoSaveState
Flag to indicate the last auto save state.
void BuildListOfNets()
Definition: class_board.h:735
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:385
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:155
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]
virtual const wxString Problem() const
what was the problem?
Definition: exceptions.cpp:49
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:273
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]
Definition of file extensions used in Kicad.
BOARD_DESIGN_SETTINGS & GetDesignSettings() const
Function GetDesignSettings.
Definition: class_board.h:539
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:918
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:236
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:282
void Compile_Ratsnest(wxDC *aDC, bool aDisplayStatus)
Function Compile_Ratsnest Create the entire board ratsnest.
Definition: ratsnest.cpp:53
constexpr std::size_t arrayDim(T const (&)[N]) noexcept
of elements in an array. This implements type-safe compile time checking
Definition: macros.h:99
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:257
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:171
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.
Create and handle a window for the 3d viewer connected to a Kiway and a pcbboard. ...
Definition: eda_3d_viewer.h:49
DLIST_ITERATOR_WRAPPER< TRACK > Tracks()
Definition: class_board.h:254
BOARD_DESIGN_SETTINGS m_designSettings
Definition: class_board.h:195
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:241