bool PCB_EDIT_FRAME::doAutoSave() { wxFileName tmpFileName = Prj().AbsolutePath( GetBoard()->GetFileName() ); wxFileName fn = tmpFileName; // Auto save file name is the normal file name prepended with // autosaveFilePrefix string. fn.SetName( wxString( autosavePrefix ) + fn.GetName() ); wxLogTrace( traceAutoSave, wxT( "Creating auto save file <" + fn.GetFullPath() ) + wxT( ">" ) ); if( !fn.IsOk() ) return false; else if( SavePcbFile( fn.GetFullPath(), NO_BACKUP_FILE ) ) { GetScreen()->SetModify(); GetBoard()->SetFileName( tmpFileName.GetFullPath() ); UpdateTitle(); m_autoSaveState = false; return true; } GetBoard()->SetFileName( tmpFileName.GetFullPath() ); return false; }
void PCB_EDIT_FRAME::OnCloseWindow( wxCloseEvent& Event ) { m_canvas->SetAbortRequest( true ); if( GetScreen()->IsModify() ) { wxString msg = wxString::Format( _( "Save the changes in\n" "'%s'\n" "before closing?" ), GetChars( GetBoard()->GetFileName() ) ); int ii = DisplayExitDialog( this, msg ); switch( ii ) { case wxID_CANCEL: Event.Veto(); return; case wxID_NO: break; case wxID_YES: SavePcbFile( GetBoard()->GetFileName() ); break; } } GetGalCanvas()->StopDrawing(); // Delete the auto save file if it exists. wxFileName fn = GetBoard()->GetFileName(); // Auto save file name is the normal file name prefixed with a '$'. fn.SetName( wxT( "$" ) + fn.GetName() ); // Remove the auto save file on a normal close of Pcbnew. if( fn.FileExists() && !wxRemoveFile( fn.GetFullPath() ) ) { wxString msg = wxString::Format( _( "The auto save file '%s' could not be removed!" ), GetChars( fn.GetFullPath() ) ); wxMessageBox( msg, Pgm().App().GetAppName(), wxOK | wxICON_ERROR, this ); } // Delete board structs and undo/redo lists, to avoid crash on exit // when deleting some structs (mainly in undo/redo lists) too late Clear_Pcb( false ); // do not show the window because ScreenPcb will be deleted and we do not // want any paint event Show( false ); Destroy(); }
void WinEDA_PcbFrame::OnCloseWindow(wxCloseEvent & Event) /********************************************************/ { PCB_SCREEN * screen; DrawPanel->m_AbortRequest = TRUE; screen = ScreenPcb ; while( screen ) { if(screen->IsModify()) break; screen = screen->Next(); } if ( screen ) { unsigned ii; wxMessageDialog dialog(this, _("Board modified, Save before exit ?"), _("Confirmation"), wxYES_NO | wxCANCEL | wxICON_EXCLAMATION | wxYES_DEFAULT); ii = dialog.ShowModal(); switch ( ii ) { case wxID_CANCEL: Event.Veto(); return; case wxID_NO: break; case wxID_OK: case wxID_YES: SavePcbFile(GetScreen()->m_FileName); break; } } while( screen ) // suppression flag modify pour eviter d'autres message { screen->ClrModify(); screen = screen->Next(); } /* Reselection de l'ecran de base, pour les evenements de refresh générés par wxWindows */ m_CurrentScreen = ActiveScreen = ScreenPcb; SaveSettings(); Destroy(); }
bool PCB_EDIT_FRAME::doAutoSave() { wxFileName tmpFileName; if( GetBoard()->GetFileName().IsEmpty() ) { tmpFileName = wxFileName( wxStandardPaths::Get().GetDocumentsDir(), wxT( "noname" ), KiCadPcbFileExtension ); GetBoard()->SetFileName( tmpFileName.GetFullPath() ); } else { tmpFileName = Prj().AbsolutePath( GetBoard()->GetFileName() ); } wxFileName autoSaveFileName = tmpFileName; // Auto save file name is the board file name prepended with autosaveFilePrefix string. autoSaveFileName.SetName( GetAutoSaveFilePrefix() + autoSaveFileName.GetName() ); if( !autoSaveFileName.IsOk() ) return false; // If the board file path is not writable, try writing to a platform specific temp file // path. If that path isn't writabe, give up. if( !autoSaveFileName.IsDirWritable() ) { autoSaveFileName.SetPath( wxFileName::GetTempDir() ); if( !autoSaveFileName.IsOk() || !autoSaveFileName.IsDirWritable() ) return false; } wxLogTrace( traceAutoSave, "Creating auto save file <" + autoSaveFileName.GetFullPath() + ">" ); if( SavePcbFile( autoSaveFileName.GetFullPath(), NO_BACKUP_FILE ) ) { GetScreen()->SetModify(); GetBoard()->SetFileName( tmpFileName.GetFullPath() ); UpdateTitle(); m_autoSaveState = false; return true; } GetBoard()->SetFileName( tmpFileName.GetFullPath() ); return false; }
bool PCB_EDIT_FRAME::OpenProjectFiles( const std::vector<wxString>& aFileSet, int aCtl ) { // This is for python: if( aFileSet.size() != 1 ) { UTF8 msg = StrPrintf( "Pcbnew:%s() takes only a single filename", __func__ ); DisplayError( this, msg ); return false; } wxString fullFileName( aFileSet[0] ); // We insist on caller sending us an absolute path, if it does not, we say it's a bug. wxASSERT_MSG( wxFileName( fullFileName ).IsAbsolute(), wxT( "Path is not absolute!" ) ); std::unique_ptr<wxSingleInstanceChecker> lockFile = ::LockFile( fullFileName ); if( !lockFile ) { wxString msg = wxString::Format( _( "PCB file \"%s\" is already open." ), fullFileName ); DisplayError( this, msg ); return false; } if( GetScreen()->IsModify() && !GetBoard()->IsEmpty() ) { if( !HandleUnsavedChanges( this, _( "The current PCB has been modified. Save changes?" ), [&]()->bool { return SavePcbFile( GetBoard()->GetFileName(), CREATE_BACKUP_FILE ); } ) ) { return false; } } // Release the lock file, until the new file is actually loaded ReleaseFile(); wxFileName pro = fullFileName; pro.SetExt( ProjectFileExtension ); bool is_new = !wxFileName::IsFileReadable( fullFileName ); // If its a non-existent schematic and caller thinks it exists if( is_new && !( aCtl & KICTL_CREATE ) ) { // notify user that fullFileName does not exist, ask if user wants to create it. wxString ask = wxString::Format( _( "PCB \"%s\" does not exist. Do you wish to create it?" ), fullFileName ); if( !IsOK( this, ask ) ) return false; } Clear_Pcb( false ); // pass false since we prompted above for a modified board IO_MGR::PCB_FILE_T pluginType = plugin_type( fullFileName, aCtl ); bool converted = pluginType != IO_MGR::LEGACY && pluginType != IO_MGR::KICAD_SEXP; if( !converted ) { // PROJECT::SetProjectFullName() is an impactful function. It should only be // called under carefully considered circumstances. // The calling code should know not to ask me here to change projects unless // it knows what consequences that will have on other KIFACEs running and using // this same PROJECT. It can be very harmful if that calling code is stupid. Prj().SetProjectFullName( pro.GetFullPath() ); // load project settings before BOARD LoadProjectSettings(); } if( is_new ) { OnModify(); } else { BOARD* loadedBoard = 0; // it will be set to non-NULL if loaded OK PLUGIN::RELEASER pi( IO_MGR::PluginFind( pluginType ) ); // This will rename the file if there is an autosave and the user want to recover CheckForAutoSaveFile( fullFileName ); try { PROPERTIES props; char xbuf[30]; char ybuf[30]; // EAGLE_PLUGIN can use this info to center the BOARD, but it does not yet. sprintf( xbuf, "%d", GetPageSizeIU().x ); sprintf( ybuf, "%d", GetPageSizeIU().y ); props["page_width"] = xbuf; props["page_height"] = ybuf; #if USE_INSTRUMENTATION // measure the time to load a BOARD. unsigned startTime = GetRunningMicroSecs(); #endif loadedBoard = pi->Load( fullFileName, NULL, &props ); #if USE_INSTRUMENTATION unsigned stopTime = GetRunningMicroSecs(); printf( "PLUGIN::Load(): %u usecs\n", stopTime - startTime ); #endif } catch( const IO_ERROR& ioe ) { if( ioe.Problem() != wxT( "CANCEL" ) ) { wxString msg = wxString::Format( _( "Error loading board file:\n%s" ), fullFileName ); DisplayErrorMessage( this, msg, ioe.What() ); } return false; } // 6.0 TODO: some settings didn't make it into the board file in 5.1 so as not to // change the file format. For 5.1 we must copy them across from the config-initialized // board. BOARD_DESIGN_SETTINGS& bds = loadedBoard->m_designSettings; BOARD_DESIGN_SETTINGS& configBds = GetBoard()->GetDesignSettings(); bds.m_RequireCourtyards = configBds.m_RequireCourtyards; bds.m_ProhibitOverlappingCourtyards = configBds.m_ProhibitOverlappingCourtyards; bds.m_HoleToHoleMin = configBds.m_HoleToHoleMin; bds.m_LineThickness[LAYER_CLASS_OTHERS] = configBds.m_LineThickness[LAYER_CLASS_OTHERS]; bds.m_TextSize[LAYER_CLASS_OTHERS] = configBds.m_TextSize[LAYER_CLASS_OTHERS]; bds.m_TextThickness[LAYER_CLASS_OTHERS] = configBds.m_TextThickness[LAYER_CLASS_OTHERS]; std::copy( configBds.m_TextItalic, configBds.m_TextItalic + 4, bds.m_TextItalic ); std::copy( configBds.m_TextUpright, configBds.m_TextUpright + 4, bds.m_TextUpright ); bds.m_DiffPairDimensionsList = configBds.m_DiffPairDimensionsList; bds.m_CopperEdgeClearance = configBds.m_CopperEdgeClearance; SetBoard( loadedBoard ); // we should not ask PLUGINs to do these items: loadedBoard->BuildListOfNets(); loadedBoard->SynchronizeNetsAndNetClasses(); // If this is a legacy board then we set the copper edge clearance to 1/2 the edge-cut // line width (which was a legacy kludge for implementing edge clearances). if( bds.m_CopperEdgeClearance == Millimeter2iu( LEGACY_COPPEREDGECLEARANCE ) ) bds.SetCopperEdgeClearance( inferLegacyEdgeClearance( loadedBoard ) ); if( loadedBoard->IsModified() ) OnModify(); else GetScreen()->ClrModify(); if( pluginType == IO_MGR::LEGACY && loadedBoard->GetFileFormatVersionAtLoad() < LEGACY_BOARD_FILE_VERSION ) { DisplayInfoMessage( this, _( "This file was created by an older version of Pcbnew.\n" "It will be stored in the new file format when you save this file again." ) ); } } { wxFileName fn = fullFileName; if( converted ) fn.SetExt( PcbFileExtension ); wxString fname = fn.GetFullPath(); fname.Replace( WIN_STRING_DIR_SEP, UNIX_STRING_DIR_SEP ); GetBoard()->SetFileName( fname ); } // Lock the file newly opened: m_file_checker.reset( lockFile.release() ); if( !converted ) UpdateFileHistory( GetBoard()->GetFileName() ); // Rebuild the new pad list (for drc and ratsnet control ...) GetBoard()->m_Status_Pcb = 0; // Select netclass Default as current netclass (it always exists) SetCurrentNetClass( NETCLASS::Default ); // Rebuild list of nets (full ratsnest rebuild) Compile_Ratsnest( NULL, true ); GetBoard()->BuildConnectivity(); onBoardLoaded(); // Refresh the 3D view, if any EDA_3D_VIEWER* draw3DFrame = Get3DViewerFrame(); if( draw3DFrame ) draw3DFrame->NewDisplay(); #if 0 && defined(DEBUG) // Output the board object tree to stdout, but please run from command prompt: GetBoard()->Show( 0, std::cout ); #endif // from EDA_APPL which was first loaded BOARD only: { /* For an obscure reason the focus is lost after loading a board file * when starting up the process. * (seems due to the recreation of the layer manager after loading the file) * Give focus to main window and Drawpanel * must be done for these 2 windows (for an obscure reason ...) * Linux specific * This is more a workaround than a fix. */ SetFocus(); GetCanvas()->SetFocus(); } return true; }
bool PCB_EDIT_FRAME::Files_io_from_id( int id ) { wxString msg; // If an edit is in progress, stop it. // For something else than save, get rid of current tool. if( id == ID_SAVE_BOARD ) m_canvas->EndMouseCapture( -1, m_canvas->GetDefaultCursor() ); else m_canvas->EndMouseCapture( ID_NO_TOOL_SELECTED, m_canvas->GetDefaultCursor() ); switch( id ) { case ID_LOAD_FILE: { int open_ctl = 0; wxString fileName = Prj().AbsolutePath( GetBoard()->GetFileName() ); return AskLoadBoardFileName( this, &open_ctl, &fileName, true ) && OpenProjectFiles( std::vector<wxString>( 1, fileName ), open_ctl ); } case ID_IMPORT_NON_KICAD_BOARD: { int open_ctl = 1; wxString fileName; // = Prj().AbsolutePath( GetBoard()->GetFileName() ); return AskLoadBoardFileName( this, &open_ctl, &fileName, false ) && OpenProjectFiles( std::vector<wxString>( 1, fileName ), open_ctl ); } case ID_MENU_READ_BOARD_BACKUP_FILE: case ID_MENU_RECOVER_BOARD_AUTOSAVE: { wxFileName currfn = Prj().AbsolutePath( GetBoard()->GetFileName() ); wxFileName fn = currfn; if( id == ID_MENU_RECOVER_BOARD_AUTOSAVE ) { wxString rec_name = GetAutoSaveFilePrefix() + fn.GetName(); fn.SetName( rec_name ); } else { wxString backup_ext = fn.GetExt() + GetBackupSuffix(); fn.SetExt( backup_ext ); } if( !fn.FileExists() ) { msg.Printf( _( "Recovery file \"%s\" not found." ), fn.GetFullPath() ); DisplayInfoMessage( this, msg ); return false; } msg.Printf( _( "OK to load recovery or backup file \"%s\"" ), fn.GetFullPath() ); if( !IsOK( this, msg ) ) return false; GetScreen()->ClrModify(); // do not prompt the user for changes if( OpenProjectFiles( std::vector<wxString>( 1, fn.GetFullPath() ) ) ) { // Re-set the name since name or extension was changed GetBoard()->SetFileName( currfn.GetFullPath() ); UpdateTitle(); return true; } return false; } case ID_APPEND_FILE: wxFAIL_MSG( "OBSOLETE! Should have gone though modern toolset." ); case ID_NEW_BOARD: { if( !Clear_Pcb( true ) ) return false; wxFileName fn( wxStandardPaths::Get().GetDocumentsDir(), wxT( "noname" ), ProjectFileExtension ); Prj().SetProjectFullName( fn.GetFullPath() ); fn.SetExt( PcbFileExtension ); GetBoard()->SetFileName( fn.GetFullPath() ); onBoardLoaded(); OnModify(); return true; } case ID_SAVE_BOARD: if( !GetBoard()->GetFileName().IsEmpty() ) return SavePcbFile( Prj().AbsolutePath( GetBoard()->GetFileName() ) ); // Fall through case ID_COPY_BOARD_AS: case ID_SAVE_BOARD_AS: { wxString pro_dir = wxPathOnly( Prj().GetProjectFullName() ); wxFileName fn( pro_dir, _( "noname" ), KiCadPcbFileExtension ); wxString filename = fn.GetFullPath(); if( AskSaveBoardFileName( this, &filename ) ) { if( id == ID_COPY_BOARD_AS ) return SavePcbCopy( filename ); else return SavePcbFile( filename, NO_BACKUP_FILE ); } return false; } default: wxLogDebug( wxT( "File_io Internal Error" ) ); return false; } }
bool PCB_EDIT_FRAME::OpenProjectFiles( const std::vector<wxString>& aFileSet, int aCtl ) { // This is for python: if( aFileSet.size() != 1 ) { UTF8 msg = StrPrintf( "Pcbnew:%s() takes only a single filename", __func__ ); DisplayError( this, msg ); return false; } wxString fullFileName( aFileSet[0] ); // We insist on caller sending us an absolute path, if it does not, we say it's a bug. wxASSERT_MSG( wxFileName( fullFileName ).IsAbsolute(), wxT( "bug in single_top.cpp or project manager." ) ); if( !LockFile( fullFileName ) ) { wxString msg = wxString::Format( _( "PCB file '%s' is already open." ), GetChars( fullFileName ) ); DisplayError( this, msg ); return false; } if( GetScreen()->IsModify() ) { int response = YesNoCancelDialog( this, _( "The current board has been modified. Do you wish to save the changes?" ), wxEmptyString, _( "Save and Load" ), _( "Load Without Saving" ) ); if( response == wxID_CANCEL ) return false; else if( response == wxID_YES ) SavePcbFile( GetBoard()->GetFileName(), CREATE_BACKUP_FILE ); else { // response == wxID_NO, fall thru } } wxFileName pro = fullFileName; pro.SetExt( ProjectFileExtension ); bool is_new = !wxFileName::IsFileReadable( fullFileName ); // If its a non-existent schematic and caller thinks it exists if( is_new && !( aCtl & KICTL_CREATE ) ) { // notify user that fullFileName does not exist, ask if user wants to create it. wxString ask = wxString::Format( _( "Board '%s' does not exist. Do you wish to create it?" ), GetChars( fullFileName ) ); if( !IsOK( this, ask ) ) return false; } Clear_Pcb( false ); // pass false since we prompted above for a modified board IO_MGR::PCB_FILE_T pluginType = plugin_type( fullFileName, aCtl ); bool converted = pluginType != IO_MGR::LEGACY && pluginType != IO_MGR::KICAD; if( !converted ) { // PROJECT::SetProjectFullName() is an impactful function. It should only be // called under carefully considered circumstances. // The calling code should know not to ask me here to change projects unless // it knows what consequences that will have on other KIFACEs running and using // this same PROJECT. It can be very harmful if that calling code is stupid. Prj().SetProjectFullName( pro.GetFullPath() ); // load project settings before BOARD LoadProjectSettings(); } if( is_new ) { OnModify(); } else { BOARD* loadedBoard = 0; // it will be set to non-NULL if loaded OK PLUGIN::RELEASER pi( IO_MGR::PluginFind( pluginType ) ); try { PROPERTIES props; char xbuf[30]; char ybuf[30]; // EAGLE_PLUGIN can use this info to center the BOARD, but it does not yet. sprintf( xbuf, "%d", GetPageSizeIU().x ); sprintf( ybuf, "%d", GetPageSizeIU().y ); props["page_width"] = xbuf; props["page_height"] = ybuf; #if USE_INSTRUMENTATION // measure the time to load a BOARD. unsigned startTime = GetRunningMicroSecs(); #endif loadedBoard = pi->Load( fullFileName, NULL, &props ); #if USE_INSTRUMENTATION unsigned stopTime = GetRunningMicroSecs(); printf( "PLUGIN::Load(): %u usecs\n", stopTime - startTime ); #endif } catch( const IO_ERROR& ioe ) { wxString msg = wxString::Format( _( "Error loading board.\n%s" ), GetChars( ioe.errorText ) ); DisplayError( this, msg ); return false; } SetBoard( loadedBoard ); // we should not ask PLUGINs to do these items: loadedBoard->BuildListOfNets(); loadedBoard->SynchronizeNetsAndNetClasses(); SetStatusText( wxEmptyString ); BestZoom(); // update the layer names in the listbox ReCreateLayerBox( false ); GetScreen()->ClrModify(); { wxFileName fn = fullFileName; CheckForAutoSaveFile( fullFileName, fn.GetExt() ); } if( pluginType == IO_MGR::LEGACY && loadedBoard->GetFileFormatVersionAtLoad() < LEGACY_BOARD_FILE_VERSION ) { DisplayInfoMessage( this, _( "This file was created by an older version of Pcbnew.\n" "It will be stored in the new file format when you save this file again." ) ); } } { wxFileName fn = fullFileName; if( converted ) fn.SetExt( PcbFileExtension ); wxString fname = fn.GetFullPath(); fname.Replace( WIN_STRING_DIR_SEP, UNIX_STRING_DIR_SEP ); GetBoard()->SetFileName( fname ); } UpdateTitle(); if( !converted ) UpdateFileHistory( GetBoard()->GetFileName() ); // Rebuild the new pad list (for drc and ratsnet control ...) GetBoard()->m_Status_Pcb = 0; // Update info shown by the horizontal toolbars SetCurrentNetClass( NETCLASS::Default ); ReFillLayerWidget(); ReCreateLayerBox(); // upate the layer widget to match board visibility states, both layers and render columns. syncLayerVisibilities(); syncLayerWidgetLayer(); syncRenderStates(); // Update the tracks / vias available sizes list: ReCreateAuxiliaryToolbar(); // Update the RATSNEST items, which were not loaded at the time // BOARD::SetVisibleElements() was called from within any PLUGIN. // See case RATSNEST_VISIBLE: in BOARD::SetElementVisibility() GetBoard()->SetVisibleElements( GetBoard()->GetVisibleElements() ); // Display the loaded board: Zoom_Automatique( false ); // Compile ratsnest and displays net info { wxBusyCursor dummy; // Displays an Hourglass while building connectivity Compile_Ratsnest( NULL, true ); GetBoard()->GetRatsnest()->ProcessBoard(); } SetMsgPanel( GetBoard() ); // Refresh the 3D view, if any if( m_Draw3DFrame ) m_Draw3DFrame->NewDisplay(); #if 0 && defined(DEBUG) // Output the board object tree to stdout, but please run from command prompt: GetBoard()->Show( 0, std::cout ); #endif // from EDA_APPL which was first loaded BOARD only: { /* For an obscure reason the focus is lost after loading a board file * when starting up the process. * (seems due to the recreation of the layer manager after loading the file) * Give focus to main window and Drawpanel * must be done for these 2 windows (for an obscure reason ...) * Linux specific * This is more a workaround than a fix. */ SetFocus(); GetCanvas()->SetFocus(); } return true; }
void PCB_EDIT_FRAME::Files_io_from_id( int id ) { wxString msg; // If an edition is in progress, stop it. // For something else than save, get rid of current tool. if( id == ID_SAVE_BOARD ) m_canvas->EndMouseCapture( -1, m_canvas->GetDefaultCursor() ); else m_canvas->EndMouseCapture( ID_NO_TOOL_SELECTED, m_canvas->GetDefaultCursor() ); switch( id ) { case ID_LOAD_FILE: { // LoadOnePcbFile( GetBoard()->GetFileName(), append=false, aForceFileDialog=true ); int open_ctl; wxString fileName = Prj().AbsolutePath( GetBoard()->GetFileName() ); if( !AskLoadBoardFileName( this, &open_ctl, &fileName ) ) return; OpenProjectFiles( std::vector<wxString>( 1, fileName ), open_ctl ); } break; case ID_MENU_READ_BOARD_BACKUP_FILE: case ID_MENU_RECOVER_BOARD_AUTOSAVE: { wxFileName currfn = Prj().AbsolutePath( GetBoard()->GetFileName() ); wxFileName fn = currfn; if( id == ID_MENU_RECOVER_BOARD_AUTOSAVE ) { wxString rec_name = wxString( autosavePrefix ) + fn.GetName(); fn.SetName( rec_name ); } else { wxString backup_ext = fn.GetExt()+ backupSuffix; fn.SetExt( backup_ext ); } if( !fn.FileExists() ) { msg.Printf( _( "Recovery file '%s' not found." ), GetChars( fn.GetFullPath() ) ); DisplayInfoMessage( this, msg ); break; } msg.Printf( _( "OK to load recovery or backup file '%s'" ), GetChars(fn.GetFullPath() ) ); if( !IsOK( this, msg ) ) break; GetScreen()->ClrModify(); // do not prompt the user for changes // LoadOnePcbFile( fn.GetFullPath(), aAppend=false, aForceFileDialog=false ); OpenProjectFiles( std::vector<wxString>( 1, fn.GetFullPath() ) ); // Re-set the name since name or extension was changed GetBoard()->SetFileName( currfn.GetFullPath() ); UpdateTitle(); } break; case ID_APPEND_FILE: { int open_ctl; wxString fileName; if( !AskLoadBoardFileName( this, &open_ctl, &fileName, true ) ) break; AppendBoardFile( fileName, open_ctl ); m_canvas->Refresh(); } break; case ID_NEW_BOARD: { if( !Clear_Pcb( true ) ) break; wxFileName fn( wxStandardPaths::Get().GetDocumentsDir(), wxT( "noname" ), ProjectFileExtension ); Prj().SetProjectFullName( fn.GetFullPath() ); fn.SetExt( PcbFileExtension ); GetBoard()->SetFileName( fn.GetFullPath() ); UpdateTitle(); ReCreateLayerBox(); break; } case ID_SAVE_BOARD: if( ! GetBoard()->GetFileName().IsEmpty() ) { SavePcbFile( Prj().AbsolutePath( GetBoard()->GetFileName() ) ); break; } // Fall through case ID_COPY_BOARD_AS: case ID_SAVE_BOARD_AS: { wxString pro_dir = wxPathOnly( Prj().GetProjectFullName() ); wxFileName fn( pro_dir, _( "noname" ), KiCadPcbFileExtension ); wxString filename = fn.GetFullPath(); if( AskSaveBoardFileName( this, &filename ) ) { if( id == ID_COPY_BOARD_AS ) SavePcbCopy( filename ); else SavePcbFile( filename, NO_BACKUP_FILE ); } } break; default: DisplayError( this, wxT( "File_io Internal Error" ) ); break; } }