You can not select more than 25 topics Topics must start with a letter or number, can include dashes ('-') and can be up to 35 characters long.

621 lines
20 KiB

18 years ago
18 years ago
18 years ago
18 years ago
++PCBNew * Removed Pcb_Frame argument from BOARD() constructor, since it precludes having a BOARD being edited by more than one editor, it was a bad design. And this meant removing m_PcbFrame from BOARD. * removed BOARD::SetWindowFrame(), and BOARD::m_PcbFrame * Removed the global BOARD_DESIGN_SETTINGS which was in class_board.cpp * added BOARD_DESIGN_SETTINGS to the BOARD class, a full instance * a couple dialogs now only change BOARD_DESIGN_SETTINGS when OK is pressed, such as dialog_mask_clearance, dialog_drc, etc. * Removed common/pcbcommon.cpp's int g_CurrentVersionPCB = 1 and replaced it with build_version.h's #define BOARD_FILE_VERSION, although there may be a better place for this constant. * Made the public functions in PARAM_CFG_ARRAY be type const. void SaveParam(..) const and void ReadParam(..) const * PARAM_CFG_BASE now has virtual destructor since we have various way of destroying the derived class and boost::ptr_vector must be told about this. * Pass const PARAM_CFG_ARRAY& instead of PARAM_CFG_ARRAY so that we can use an automatic PARAM_CFG_ARRAY which is on the stack.\ * PCB_EDIT_FRAME::GetProjectFileParameters() may no longer cache the array, since it has to access the current BOARD and the BOARD can change. Remember BOARD_DESIGN_SETTINGS are now in the BOARD. * Made the m_BoundingBox member private, this was a brutally hard task, and indicative of the lack of commitment to accessors and object oriented design on the part of KiCad developers. We must do better. Added BOARD::GetBoundingBox, SetBoundingBox(), ComputeBoundingBox(). * Added PCB_BASE_FRAME::GetBoardBoundingBox() which calls BOARD::ComputeBoundingBox()
14 years ago
++PCBNew * Removed Pcb_Frame argument from BOARD() constructor, since it precludes having a BOARD being edited by more than one editor, it was a bad design. And this meant removing m_PcbFrame from BOARD. * removed BOARD::SetWindowFrame(), and BOARD::m_PcbFrame * Removed the global BOARD_DESIGN_SETTINGS which was in class_board.cpp * added BOARD_DESIGN_SETTINGS to the BOARD class, a full instance * a couple dialogs now only change BOARD_DESIGN_SETTINGS when OK is pressed, such as dialog_mask_clearance, dialog_drc, etc. * Removed common/pcbcommon.cpp's int g_CurrentVersionPCB = 1 and replaced it with build_version.h's #define BOARD_FILE_VERSION, although there may be a better place for this constant. * Made the public functions in PARAM_CFG_ARRAY be type const. void SaveParam(..) const and void ReadParam(..) const * PARAM_CFG_BASE now has virtual destructor since we have various way of destroying the derived class and boost::ptr_vector must be told about this. * Pass const PARAM_CFG_ARRAY& instead of PARAM_CFG_ARRAY so that we can use an automatic PARAM_CFG_ARRAY which is on the stack.\ * PCB_EDIT_FRAME::GetProjectFileParameters() may no longer cache the array, since it has to access the current BOARD and the BOARD can change. Remember BOARD_DESIGN_SETTINGS are now in the BOARD. * Made the m_BoundingBox member private, this was a brutally hard task, and indicative of the lack of commitment to accessors and object oriented design on the part of KiCad developers. We must do better. Added BOARD::GetBoundingBox, SetBoundingBox(), ComputeBoundingBox(). * Added PCB_BASE_FRAME::GetBoardBoundingBox() which calls BOARD::ComputeBoundingBox()
14 years ago
++PCBNew * Removed Pcb_Frame argument from BOARD() constructor, since it precludes having a BOARD being edited by more than one editor, it was a bad design. And this meant removing m_PcbFrame from BOARD. * removed BOARD::SetWindowFrame(), and BOARD::m_PcbFrame * Removed the global BOARD_DESIGN_SETTINGS which was in class_board.cpp * added BOARD_DESIGN_SETTINGS to the BOARD class, a full instance * a couple dialogs now only change BOARD_DESIGN_SETTINGS when OK is pressed, such as dialog_mask_clearance, dialog_drc, etc. * Removed common/pcbcommon.cpp's int g_CurrentVersionPCB = 1 and replaced it with build_version.h's #define BOARD_FILE_VERSION, although there may be a better place for this constant. * Made the public functions in PARAM_CFG_ARRAY be type const. void SaveParam(..) const and void ReadParam(..) const * PARAM_CFG_BASE now has virtual destructor since we have various way of destroying the derived class and boost::ptr_vector must be told about this. * Pass const PARAM_CFG_ARRAY& instead of PARAM_CFG_ARRAY so that we can use an automatic PARAM_CFG_ARRAY which is on the stack.\ * PCB_EDIT_FRAME::GetProjectFileParameters() may no longer cache the array, since it has to access the current BOARD and the BOARD can change. Remember BOARD_DESIGN_SETTINGS are now in the BOARD. * Made the m_BoundingBox member private, this was a brutally hard task, and indicative of the lack of commitment to accessors and object oriented design on the part of KiCad developers. We must do better. Added BOARD::GetBoundingBox, SetBoundingBox(), ComputeBoundingBox(). * Added PCB_BASE_FRAME::GetBoardBoundingBox() which calls BOARD::ComputeBoundingBox()
14 years ago
++PCBNew * Removed Pcb_Frame argument from BOARD() constructor, since it precludes having a BOARD being edited by more than one editor, it was a bad design. And this meant removing m_PcbFrame from BOARD. * removed BOARD::SetWindowFrame(), and BOARD::m_PcbFrame * Removed the global BOARD_DESIGN_SETTINGS which was in class_board.cpp * added BOARD_DESIGN_SETTINGS to the BOARD class, a full instance * a couple dialogs now only change BOARD_DESIGN_SETTINGS when OK is pressed, such as dialog_mask_clearance, dialog_drc, etc. * Removed common/pcbcommon.cpp's int g_CurrentVersionPCB = 1 and replaced it with build_version.h's #define BOARD_FILE_VERSION, although there may be a better place for this constant. * Made the public functions in PARAM_CFG_ARRAY be type const. void SaveParam(..) const and void ReadParam(..) const * PARAM_CFG_BASE now has virtual destructor since we have various way of destroying the derived class and boost::ptr_vector must be told about this. * Pass const PARAM_CFG_ARRAY& instead of PARAM_CFG_ARRAY so that we can use an automatic PARAM_CFG_ARRAY which is on the stack.\ * PCB_EDIT_FRAME::GetProjectFileParameters() may no longer cache the array, since it has to access the current BOARD and the BOARD can change. Remember BOARD_DESIGN_SETTINGS are now in the BOARD. * Made the m_BoundingBox member private, this was a brutally hard task, and indicative of the lack of commitment to accessors and object oriented design on the part of KiCad developers. We must do better. Added BOARD::GetBoundingBox, SetBoundingBox(), ComputeBoundingBox(). * Added PCB_BASE_FRAME::GetBoardBoundingBox() which calls BOARD::ComputeBoundingBox()
14 years ago
14 years ago
14 years ago
14 years ago
14 years ago
14 years ago
14 years ago
14 years ago
14 years ago
14 years ago
16 years ago
16 years ago
14 years ago
14 years ago
16 years ago
17 years ago
16 years ago
16 years ago
18 years ago
14 years ago
14 years ago
14 years ago
  1. /*
  2. * This program source code file is part of KiCad, a free EDA CAD application.
  3. *
  4. * Copyright (C) 2004-2010 Jean-Pierre Charras, jean-pierre.charras@gpisa-lab.inpg.fr
  5. * Copyright (C) 2011 Wayne Stambaugh <stambaughw@verizon.net>
  6. * Copyright (C) 2010 KiCad Developers, see change_log.txt for contributors.
  7. *
  8. * This program is free software; you can redistribute it and/or
  9. * modify it under the terms of the GNU General Public License
  10. * as published by the Free Software Foundation; either version 2
  11. * of the License, or (at your option) any later version.
  12. *
  13. * This program is distributed in the hope that it will be useful,
  14. * but WITHOUT ANY WARRANTY; without even the implied warranty of
  15. * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
  16. * GNU General Public License for more details.
  17. *
  18. * You should have received a copy of the GNU General Public License
  19. * along with this program; if not, you may find one here:
  20. * http://www.gnu.org/licenses/old-licenses/gpl-2.0.html
  21. * or you may search the http://www.gnu.org website for the version 2 license,
  22. * or you may write to the Free Software Foundation, Inc.,
  23. * 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301, USA
  24. */
  25. /**
  26. * @file pcbnew/files.cpp
  27. * @brief Read and write board files.
  28. */
  29. #include <fctsys.h>
  30. #include <class_drawpanel.h>
  31. #include <confirm.h>
  32. #include <kicad_string.h>
  33. #include <gestfich.h>
  34. #include <wxPcbStruct.h>
  35. #include <macros.h>
  36. #include <pcbcommon.h>
  37. #include <3d_viewer.h>
  38. #include <richio.h>
  39. #include <filter_reader.h>
  40. #include <appl_wxstruct.h>
  41. #include <msgpanel.h>
  42. #include <pcbnew.h>
  43. #include <pcbnew_id.h>
  44. #include <io_mgr.h>
  45. #include <wildcards_and_files_ext.h>
  46. #include <class_board.h>
  47. #include <build_version.h> // LEGACY_BOARD_FILE_VERSION
  48. static const wxString backupFileExtensionSuffix( wxT( "-bak" ) );
  49. static const wxString autosaveFilePrefix( wxT( "_autosave-" ) );
  50. void PCB_EDIT_FRAME::OnFileHistory( wxCommandEvent& event )
  51. {
  52. wxString fn;
  53. fn = GetFileFromHistory( event.GetId(), _( "Printed circuit board" ) );
  54. if( fn != wxEmptyString )
  55. {
  56. m_canvas->EndMouseCapture( ID_NO_TOOL_SELECTED, m_canvas->GetDefaultCursor() );
  57. ::wxSetWorkingDirectory( ::wxPathOnly( fn ) );
  58. LoadOnePcbFile( fn );
  59. }
  60. }
  61. void PCB_EDIT_FRAME::Files_io( wxCommandEvent& event )
  62. {
  63. int id = event.GetId();
  64. wxString msg;
  65. // If an edition is in progress, stop it.
  66. // For something else than save, get rid of current tool.
  67. if( id == ID_SAVE_BOARD )
  68. m_canvas->EndMouseCapture( -1, m_canvas->GetDefaultCursor() );
  69. else
  70. m_canvas->EndMouseCapture( ID_NO_TOOL_SELECTED, m_canvas->GetDefaultCursor() );
  71. switch( id )
  72. {
  73. case ID_LOAD_FILE:
  74. LoadOnePcbFile( GetBoard()->GetFileName(), false, true );
  75. break;
  76. case ID_MENU_READ_BOARD_BACKUP_FILE:
  77. case ID_MENU_RECOVER_BOARD_AUTOSAVE:
  78. {
  79. wxFileName currfn = GetBoard()->GetFileName();
  80. wxFileName fn = currfn;
  81. if( id == ID_MENU_RECOVER_BOARD_AUTOSAVE )
  82. {
  83. wxString rec_name = autosaveFilePrefix + fn.GetName();
  84. fn.SetName( rec_name );
  85. }
  86. else
  87. {
  88. wxString backup_ext = fn.GetExt()+ backupFileExtensionSuffix;
  89. fn.SetExt( backup_ext );
  90. }
  91. if( !fn.FileExists() )
  92. {
  93. msg.Printf( _( "Recovery file <%s> not found." ),
  94. GetChars( fn.GetFullPath() ) );
  95. DisplayInfoMessage( this, msg );
  96. break;
  97. }
  98. msg.Printf( _( "OK to load recovery or backup file <%s>" ),
  99. GetChars(fn.GetFullPath() ) );
  100. if( !IsOK( this, msg ) )
  101. break;
  102. GetScreen()->ClrModify(); // do not prompt the user for changes
  103. LoadOnePcbFile( fn.GetFullPath(), false );
  104. // Re-set the name since name or extension was changed
  105. GetBoard()->SetFileName( currfn.GetFullPath() );
  106. UpdateTitle();
  107. }
  108. break;
  109. case ID_APPEND_FILE:
  110. LoadOnePcbFile( wxEmptyString, true );
  111. break;
  112. case ID_NEW_BOARD:
  113. {
  114. Clear_Pcb( true );
  115. wxFileName fn( wxT( "noname" ) );
  116. fn.AssignCwd();
  117. fn.SetExt( PcbFileExtension );
  118. GetBoard()->SetFileName( fn.GetFullPath() );
  119. UpdateTitle();
  120. ReCreateLayerBox( NULL );
  121. }
  122. break;
  123. case ID_SAVE_BOARD:
  124. SavePcbFile( GetBoard()->GetFileName() );
  125. break;
  126. case ID_SAVE_BOARD_AS:
  127. SavePcbFile( wxEmptyString );
  128. break;
  129. default:
  130. DisplayError( this, wxT( "File_io Internal Error" ) ); break;
  131. }
  132. }
  133. bool PCB_EDIT_FRAME::LoadOnePcbFile( const wxString& aFileName, bool aAppend,
  134. bool aForceFileDialog )
  135. {
  136. if( GetScreen()->IsModify() && !aAppend )
  137. {
  138. if( !IsOK( this,
  139. _( "The current board has been modified.\n"
  140. "Do you wish to discard the changes?" ) ) )
  141. return false;
  142. }
  143. if( aAppend )
  144. {
  145. GetBoard()->SetFileName( wxEmptyString );
  146. OnModify();
  147. GetBoard()->m_Status_Pcb = 0;
  148. }
  149. wxFileName fileName = aFileName;
  150. IO_MGR::PCB_FILE_T pluginType = IO_MGR::LEGACY;
  151. // This is a subset of all PLUGINs which are trusted to be able to
  152. // load a BOARD. Order is subject to change as KICAD plugin matures.
  153. // User may occasionally use the wrong plugin to load a *.brd file,
  154. // (since both legacy and eagle use *.brd extension),
  155. // but eventually *.kicad_pcb will be more common than legacy *.brd files.
  156. static const struct
  157. {
  158. const wxString& filter;
  159. IO_MGR::PCB_FILE_T pluginType;
  160. } loaders[] =
  161. {
  162. { PcbFileWildcard, IO_MGR::KICAD },
  163. { LegacyPcbFileWildcard, IO_MGR::LEGACY },
  164. { EaglePcbFileWildcard, IO_MGR::EAGLE },
  165. { PCadPcbFileWildcard, IO_MGR::PCAD },
  166. };
  167. if( !fileName.IsOk() || !fileName.FileExists() || aForceFileDialog )
  168. {
  169. wxString name;
  170. wxString path = wxGetCwd();
  171. wxString fileFilters;
  172. for( unsigned i=0; i<DIM( loaders ); ++i )
  173. {
  174. if( i > 0 )
  175. fileFilters += wxChar( '|' );
  176. fileFilters += wxGetTranslation( loaders[i].filter );
  177. }
  178. if( aForceFileDialog && fileName.FileExists() )
  179. {
  180. path = fileName.GetPath();
  181. name = fileName.GetFullName();
  182. }
  183. wxFileDialog dlg( this, _( "Open Board File" ), path, name, fileFilters,
  184. wxFD_OPEN | wxFD_FILE_MUST_EXIST );
  185. if( dlg.ShowModal() == wxID_CANCEL )
  186. return false;
  187. fileName = dlg.GetPath();
  188. int chosenFilter = dlg.GetFilterIndex();
  189. pluginType = loaders[chosenFilter].pluginType;
  190. }
  191. else // if a filename is given, force IO_MGR::KICAD if the file ext is kicad_pcb
  192. // for instance if the filename comes from file history
  193. // or it is a backup file with ext = kicad_pcb-bak
  194. {
  195. wxString backup_ext = IO_MGR::GetFileExtension( IO_MGR::KICAD ) +
  196. backupFileExtensionSuffix;
  197. if( fileName.GetExt() == IO_MGR::GetFileExtension( IO_MGR::KICAD ) ||
  198. fileName.GetExt() == backup_ext )
  199. pluginType = IO_MGR::KICAD;
  200. }
  201. PLUGIN::RELEASER pi( IO_MGR::PluginFind( pluginType ) );
  202. if( !fileName.HasExt() )
  203. fileName.SetExt( pi->GetFileExtension() );
  204. if( !aAppend )
  205. {
  206. if( !wxGetApp().LockFile( fileName.GetFullPath() ) )
  207. {
  208. DisplayError( this, _( "This file is already open." ) );
  209. return false;
  210. }
  211. Clear_Pcb( false ); // pass false since we prompted above for a modified board
  212. }
  213. CheckForAutoSaveFile( fileName, fileName.GetExt() );
  214. GetBoard()->SetFileName( fileName.GetFullPath() );
  215. if( !aAppend )
  216. {
  217. // Update the option toolbar
  218. m_DisplayPcbTrackFill = DisplayOpt.DisplayPcbTrackFill;
  219. m_DisplayModText = DisplayOpt.DisplayModText;
  220. m_DisplayModEdge = DisplayOpt.DisplayModEdge;
  221. m_DisplayPadFill = DisplayOpt.DisplayPadFill;
  222. m_DisplayViaFill = DisplayOpt.DisplayViaFill;
  223. // load project settings before BOARD, in case BOARD file has overrides.
  224. LoadProjectSettings( GetBoard()->GetFileName() );
  225. }
  226. else
  227. {
  228. GetBoard()->m_NetClasses.Clear();
  229. }
  230. BOARD* loadedBoard = 0; // it will be set to non-NULL if loaded OK
  231. try
  232. {
  233. PROPERTIES props;
  234. // EAGLE_PLUGIN can use this info to center the BOARD, but it does not yet.
  235. props["page_width"] = wxString::Format( wxT( "%d" ), GetPageSizeIU().x );
  236. props["page_height"] = wxString::Format( wxT( "%d" ), GetPageSizeIU().y );
  237. // load or append either:
  238. loadedBoard = pi->Load( GetBoard()->GetFileName(), aAppend ? GetBoard() : NULL, &props );
  239. // the Load plugin method makes a 'fresh' board, so we need to
  240. // set its own name
  241. GetBoard()->SetFileName( fileName.GetFullPath() );
  242. if( !aAppend )
  243. {
  244. if( pluginType == IO_MGR::LEGACY &&
  245. loadedBoard->GetFileFormatVersionAtLoad() < LEGACY_BOARD_FILE_VERSION )
  246. {
  247. DisplayInfoMessage( this,
  248. _( "This file was created by an older version of Pcbnew.\
  249. \nIt will be stored in the new file format when you save this file again." ) );
  250. }
  251. SetBoard( loadedBoard );
  252. }
  253. }
  254. catch( IO_ERROR ioe )
  255. {
  256. wxString msg = wxString::Format( _( "Error loading board.\n%s" ),
  257. ioe.errorText.GetData() );
  258. wxMessageBox( msg, _( "Open Board File" ), wxOK | wxICON_ERROR );
  259. }
  260. if( loadedBoard )
  261. {
  262. // we should not ask PLUGINs to do these items:
  263. loadedBoard->BuildListOfNets();
  264. loadedBoard->SynchronizeNetsAndNetClasses();
  265. SetStatusText( wxEmptyString );
  266. BestZoom();
  267. }
  268. GetScreen()->ClrModify();
  269. // If append option: change the initial board name to <oldname>-append.brd
  270. if( aAppend )
  271. {
  272. wxString new_filename = GetBoard()->GetFileName().BeforeLast( '.' );
  273. if ( ! new_filename.EndsWith( wxT( "-append" ) ) )
  274. new_filename += wxT( "-append" );
  275. new_filename += wxT( "." ) + PcbFileExtension;
  276. OnModify();
  277. GetBoard()->SetFileName( new_filename );
  278. }
  279. // Fix the directory separator on Windows and
  280. // force the new file format for not Kicad boards,
  281. // to ensure the right format when saving the board
  282. bool converted = pluginType != IO_MGR::LEGACY && pluginType != IO_MGR::KICAD;
  283. wxString fn;
  284. if( converted )
  285. fn = GetBoard()->GetFileName().BeforeLast( '.' );
  286. else
  287. fn = GetBoard()->GetFileName();
  288. fn.Replace( WIN_STRING_DIR_SEP, UNIX_STRING_DIR_SEP );
  289. if( converted )
  290. fn += wxT( "." ) + PcbFileExtension;
  291. GetBoard()->SetFileName( fn );
  292. UpdateTitle();
  293. if( !converted )
  294. UpdateFileHistory( GetBoard()->GetFileName() );
  295. // Rebuild the new pad list (for drc and ratsnet control ...)
  296. GetBoard()->m_Status_Pcb = 0;
  297. // Dick 5-Feb-2012: I do not agree with this. The layer widget will show what
  298. // is visible or not, and it would be nice for the board to look like it
  299. // did when I saved it, immediately after loading.
  300. #if 0
  301. /* Reset the items visibility flag when loading a new config
  302. * Because it could creates SERIOUS mistakes for the user,
  303. * if board items are not visible after loading a board...
  304. * Grid and ratsnest can be left to their previous state
  305. */
  306. bool showGrid = IsElementVisible( GRID_VISIBLE );
  307. bool showRats = IsElementVisible( RATSNEST_VISIBLE );
  308. SetVisibleAlls();
  309. SetElementVisibility( GRID_VISIBLE, showGrid );
  310. SetElementVisibility( RATSNEST_VISIBLE, showRats );
  311. #endif
  312. // Update info shown by the horizontal toolbars
  313. GetBoard()->SetCurrentNetClass( NETCLASS::Default );
  314. ReFillLayerWidget();
  315. ReCreateLayerBox( NULL );
  316. // upate the layer widget to match board visibility states, both layers and render columns.
  317. syncLayerVisibilities();
  318. syncLayerWidgetLayer();
  319. syncRenderStates();
  320. // Update the RATSNEST items, which were not loaded at the time
  321. // BOARD::SetVisibleElements() was called from within any PLUGIN.
  322. // See case RATSNEST_VISIBLE: in BOARD::SetElementVisibility()
  323. GetBoard()->SetVisibleElements( GetBoard()->GetVisibleElements() );
  324. updateTraceWidthSelectBox();
  325. updateViaSizeSelectBox();
  326. // Display the loaded board:
  327. Zoom_Automatique( false );
  328. // Compile ratsnest and displays net info
  329. wxBusyCursor dummy; // Displays an Hourglass while building connectivity
  330. Compile_Ratsnest( NULL, true );
  331. SetMsgPanel( GetBoard() );
  332. // Refresh the 3D view, if any
  333. if( m_Draw3DFrame )
  334. m_Draw3DFrame->NewDisplay();
  335. #if 0 && defined(DEBUG)
  336. // note this freezes up Pcbnew when run under the KiCad project
  337. // manager. runs fine from command prompt. This is because the KiCad
  338. // project manager redirects stdout of the child Pcbnew process to itself,
  339. // but never reads from that pipe, and that in turn eventually blocks
  340. // the Pcbnew program when the pipe it is writing to gets full.
  341. // Output the board object tree to stdout, but please run from command prompt:
  342. GetBoard()->Show( 0, std::cout );
  343. #endif
  344. return true;
  345. }
  346. bool PCB_EDIT_FRAME::SavePcbFile( const wxString& aFileName, bool aCreateBackupFile )
  347. {
  348. wxFileName backupFileName;
  349. wxFileName pcbFileName;
  350. wxString upperTxt;
  351. wxString lowerTxt;
  352. wxString msg;
  353. bool saveok = true;
  354. IO_MGR::PCB_FILE_T pluginType;
  355. if( aFileName == wxEmptyString )
  356. {
  357. wxString wildcard;
  358. wildcard << wxGetTranslation( PcbFileWildcard ) << wxChar( '|' ) <<
  359. wxGetTranslation( LegacyPcbFileWildcard );
  360. pcbFileName = GetBoard()->GetFileName();
  361. if( pcbFileName.GetName() == wxEmptyString )
  362. {
  363. pcbFileName.SetName( _( "Unnamed file" ) );
  364. }
  365. // Match the default wildcard filter choice, with the inital file extension shown.
  366. // That'll be the extension unless user changes filter dropdown listbox.
  367. pcbFileName.SetExt( KiCadPcbFileExtension );
  368. wxFileDialog dlg( this, _( "Save Board File As" ), pcbFileName.GetPath(),
  369. pcbFileName.GetFullName(),
  370. wildcard, wxFD_SAVE
  371. /* wxFileDialog is not equipped to handle multiple wildcards and
  372. wxFD_OVERWRITE_PROMPT both together.
  373. | wxFD_OVERWRITE_PROMPT
  374. */
  375. );
  376. if( dlg.ShowModal() != wxID_OK )
  377. return false;
  378. int filterNdx = dlg.GetFilterIndex();
  379. pluginType = ( filterNdx == 1 ) ? IO_MGR::LEGACY : IO_MGR::KICAD;
  380. // Note: on Linux wxFileDialog is not reliable for noticing a changed filename.
  381. // We probably need to file a bug report or implement our own derivation.
  382. pcbFileName = dlg.GetPath();
  383. // enforce file extension, must match plugin's policy.
  384. pcbFileName.SetExt( IO_MGR::GetFileExtension( pluginType ) );
  385. }
  386. else
  387. {
  388. pcbFileName = aFileName;
  389. if( pcbFileName.GetExt() == LegacyPcbFileExtension )
  390. pluginType = IO_MGR::LEGACY;
  391. else
  392. {
  393. pluginType = IO_MGR::KICAD;
  394. pcbFileName.SetExt( KiCadPcbFileExtension );
  395. }
  396. }
  397. if( !IsWritable( pcbFileName ) )
  398. return false;
  399. if( aCreateBackupFile )
  400. {
  401. // Get the backup file name
  402. backupFileName = pcbFileName;
  403. backupFileName.SetExt( pcbFileName.GetExt() + backupFileExtensionSuffix );
  404. // If an old backup file exists, delete it. If an old board file exists, rename
  405. // it to the backup file name.
  406. if( pcbFileName.FileExists() )
  407. {
  408. // Remove the old file xxx.000 if it exists.
  409. if( backupFileName.FileExists() )
  410. wxRemoveFile( backupFileName.GetFullPath() );
  411. // Rename the "old" file" from xxx.kicad_pcb to xxx.000
  412. if( !wxRenameFile( pcbFileName.GetFullPath(), backupFileName.GetFullPath() ) )
  413. {
  414. msg = _( "Warning: unable to create backup file " ) + backupFileName.GetFullPath();
  415. DisplayError( this, msg );
  416. saveok = false;
  417. }
  418. }
  419. else
  420. {
  421. backupFileName.Clear();
  422. }
  423. }
  424. GetBoard()->m_Status_Pcb &= ~CONNEXION_OK;
  425. GetBoard()->SynchronizeNetsAndNetClasses();
  426. // Select default Netclass before writing file.
  427. // Useful to save default values in headers
  428. GetBoard()->SetCurrentNetClass( GetBoard()->m_NetClasses.GetDefault()->GetName() );
  429. try
  430. {
  431. PLUGIN::RELEASER pi( IO_MGR::PluginFind( pluginType ) );
  432. /*
  433. if( (PLUGIN*)pi == NULL )
  434. THROW_IO_ERROR( wxString::Format( _( "cannot find file plug in for file format '%s'" ),
  435. GetChars( pcbFileName.GetExt() ) ) );
  436. */
  437. pi->Save( pcbFileName.GetFullPath(), GetBoard(), NULL );
  438. }
  439. catch( IO_ERROR ioe )
  440. {
  441. wxString msg = wxString::Format( _( "Error saving board.\n%s" ),
  442. ioe.errorText.GetData() );
  443. wxMessageBox( msg, _( "Save Board File" ), wxICON_ERROR | wxOK );
  444. saveok = false;
  445. }
  446. if( saveok )
  447. {
  448. GetBoard()->SetFileName( pcbFileName.GetFullPath() );
  449. UpdateTitle();
  450. // Put the saved file in File History, unless aCreateBackupFile
  451. // is false.
  452. // aCreateBackupFile == false is mainly used to write autosave files
  453. // and not need to have an autosave file in file history
  454. if( aCreateBackupFile )
  455. UpdateFileHistory( GetBoard()->GetFileName() );
  456. }
  457. // Display the file names:
  458. m_messagePanel->EraseMsgBox();
  459. if( saveok )
  460. {
  461. // Delete auto save file on successful save.
  462. wxFileName autoSaveFileName = pcbFileName;
  463. autoSaveFileName.SetName( autosaveFilePrefix + pcbFileName.GetName() );
  464. if( autoSaveFileName.FileExists() )
  465. wxRemoveFile( autoSaveFileName.GetFullPath() );
  466. upperTxt = _( "Backup file: " ) + backupFileName.GetFullPath();
  467. }
  468. if( saveok )
  469. lowerTxt = _( "Wrote board file: " );
  470. else
  471. lowerTxt = _( "Failed to create " );
  472. lowerTxt += pcbFileName.GetFullPath();
  473. ClearMsgPanel();
  474. AppendMsgPanel( upperTxt, lowerTxt, CYAN );
  475. GetScreen()->ClrSave();
  476. GetScreen()->ClrModify();
  477. return true;
  478. }
  479. bool PCB_EDIT_FRAME::doAutoSave()
  480. {
  481. wxFileName tmpFileName = GetBoard()->GetFileName();
  482. wxFileName fn = tmpFileName;
  483. // Auto save file name is the normal file name prepended with
  484. // autosaveFilePrefix string.
  485. fn.SetName( autosaveFilePrefix + fn.GetName() );
  486. wxLogTrace( traceAutoSave,
  487. wxT( "Creating auto save file <" + fn.GetFullPath() ) + wxT( ">" ) );
  488. if( SavePcbFile( fn.GetFullPath(), NO_BACKUP_FILE ) )
  489. {
  490. GetScreen()->SetModify();
  491. GetBoard()->SetFileName( tmpFileName.GetFullPath() );
  492. UpdateTitle();
  493. m_autoSaveState = false;
  494. return true;
  495. }
  496. GetBoard()->SetFileName( tmpFileName.GetFullPath() );
  497. return false;
  498. }