basicframe.cpp 20.4 KB
Newer Older
1 2 3
/*
 * This program source code file is part of KiCad, a free EDA CAD application.
 *
4
 * Copyright (C) 2013 Jean-Pierre Charras, jp.charras at wanadoo.fr
Lorenzo Marcantonio's avatar
Lorenzo Marcantonio committed
5
 * Copyright (C) 2013 Wayne Stambaugh <stambaughw@verizon.net>
6
 * Copyright (C) 1992-2013 KiCad Developers, see AUTHORS.txt for contributors.
7 8 9 10 11 12 13 14 15 16 17 18 19 20 21 22 23 24 25
 *
 * This program is free software; you can redistribute it and/or
 * modify it under the terms of the GNU General Public License
 * as published by the Free Software Foundation; either version 2
 * of the License, or (at your option) any later version.
 *
 * This program is distributed in the hope that it will be useful,
 * but WITHOUT ANY WARRANTY; without even the implied warranty of
 * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
 * GNU General Public License for more details.
 *
 * You should have received a copy of the GNU General Public License
 * along with this program; if not, you may find one here:
 * http://www.gnu.org/licenses/old-licenses/gpl-2.0.html
 * or you may search the http://www.gnu.org website for the version 2 license,
 * or you may write to the Free Software Foundation, Inc.,
 * 51 Franklin Street, Fifth Floor, Boston, MA  02110-1301, USA
 */

26 27
/**
 * @file basicframe.cpp
28
 * @brief EDA_BASE_FRAME class implementation.
29
 */
plyatov's avatar
plyatov committed
30

31
#include <wx/aboutdlg.h>
32
#include <wx/fontdlg.h>
33 34 35
#include <wx/clipbrd.h>
#include <wx/statline.h>
#include <wx/platinfo.h>
36

37 38
#include <build_version.h>
#include <fctsys.h>
39 40
#include <pgm_base.h>
#include <kiface_i.h>
41 42 43 44 45
#include <online_help.h>
#include <id.h>
#include <eda_doc.h>
#include <wxstruct.h>
#include <macros.h>
46
#include <menus_helpers.h>
47

48
#include <boost/version.hpp>
49
#include <typeinfo>
50

51 52 53 54
/// The default auto save interval is 10 minutes.
#define DEFAULT_AUTO_SAVE_INTERVAL 600


55
const wxChar traceAutoSave[] = wxT( "KicadAutoSave" );
56 57

/// Configuration file entry name for auto save interval.
58
static const wxChar entryAutoSaveInterval[] = wxT( "AutoSaveInterval" );
59

60
/// Configuration file entry for wxAuiManger perspective.
61
static const wxChar entryPerspective[] = wxT( "Perspective" );
62 63


64

65
EDA_BASE_FRAME::EDA_BASE_FRAME( wxWindow* aParent, FRAME_T aFrameType,
66 67
        const wxString& aTitle, const wxPoint& aPos, const wxSize& aSize,
        long aStyle, const wxString& aFrameName ) :
68
    wxFrame( aParent, wxID_ANY, aTitle, aPos, aSize, aStyle, aFrameName )
plyatov's avatar
plyatov committed
69
{
70 71
    wxSize minsize;

72
    m_Ident = aFrameType;
73
    m_mainToolBar = NULL;
74 75 76 77 78
    m_FrameIsActive = true;
    m_hasAutoSave = false;
    m_autoSaveState = false;
    m_autoSaveInterval = -1;
    m_autoSaveTimer = new wxTimer( this, ID_AUTO_SAVE_TIMER );
79

80
    minsize.x = 470;
81
    minsize.y = 350;
82

83 84
    SetSizeHints( minsize.x, minsize.y, -1, -1, -1, -1 );

85
    if( ( aSize.x < minsize.x ) || ( aSize.y < minsize.y ) )
86 87 88
        SetSize( 0, 0, minsize.x, minsize.y );

    // Create child subwindows.
89 90 91 92

    // Dimensions of the user area of the main window.
    GetClientSize( &m_FrameSize.x, &m_FrameSize.y );

93
    m_FramePos.x = m_FramePos.y = 0;
94

95 96
    Connect( ID_HELP_COPY_VERSION_STRING,
             wxEVT_COMMAND_MENU_SELECTED,
97
             wxCommandEventHandler( EDA_BASE_FRAME::CopyVersionInfoToClipboard ) );
98 99 100

    Connect( ID_AUTO_SAVE_TIMER, wxEVT_TIMER,
             wxTimerEventHandler( EDA_BASE_FRAME::onAutoSaveTimer ) );
101 102 103 104 105 106 107 108 109

    // hook wxEVT_CLOSE_WINDOW so we can call SaveSettings().  This function seems
    // to be called before any other hook for wxCloseEvent, which is necessary.
    Connect( wxEVT_CLOSE_WINDOW, wxCloseEventHandler( EDA_BASE_FRAME::windowClosing ) );
}


void EDA_BASE_FRAME::windowClosing( wxCloseEvent& event )
{
110 111 112 113
    wxConfigBase* cfg = config();

    if( cfg )
        SaveSettings( cfg );       // virtual, wxFrame specific
114 115

    event.Skip();       // we did not "handle" the event, only eavesdropped on it.
plyatov's avatar
plyatov committed
116 117
}

118

119
EDA_BASE_FRAME::~EDA_BASE_FRAME()
120
{
121 122
    delete m_autoSaveTimer;

123 124
    // This is needed for OSX: avoids further OnDraw processing after this
    // destructor and before the native window is destroyed
125
    this->Freeze();
plyatov's avatar
plyatov committed
126 127
}

128

129
bool EDA_BASE_FRAME::ProcessEvent( wxEvent& aEvent )
plyatov's avatar
plyatov committed
130
{
131 132
    if( !wxFrame::ProcessEvent( aEvent ) )
        return false;
133

134
    if( m_hasAutoSave && (m_autoSaveState != isAutoSaveRequired()) && (m_autoSaveInterval > 0) )
135 136 137
    {
        if( !m_autoSaveState )
        {
138
            wxLogTrace( traceAutoSave, wxT( "Starting auto save timer." ) );
139 140 141
            m_autoSaveTimer->Start( m_autoSaveInterval * 1000, wxTIMER_ONE_SHOT );
            m_autoSaveState = true;
        }
142
        else if( m_autoSaveTimer->IsRunning() )
143
        {
144
            wxLogTrace( traceAutoSave, wxT( "Stopping auto save timer." ) );
145 146 147 148 149 150
            m_autoSaveTimer->Stop();
            m_autoSaveState = false;
        }
    }

    return true;
plyatov's avatar
plyatov committed
151 152
}

153

154 155
bool EDA_BASE_FRAME::Enable( bool enable )
{
156 157
    // so we can do logging of this state change:

158 159
#if defined(DEBUG)
    const char* type_id = typeid( *this ).name();
160
    printf( "wxFrame %-28s: %s\n", type_id, enable ? "enabled" : "disabled" );
161 162 163 164 165 166
#endif

    return wxFrame::Enable( enable );
}


167 168 169 170 171 172 173 174 175 176 177 178 179 180 181 182 183 184
void EDA_BASE_FRAME::onAutoSaveTimer( wxTimerEvent& aEvent )
{
    if( !doAutoSave() )
        m_autoSaveTimer->Start( m_autoSaveInterval * 1000, wxTIMER_ONE_SHOT );
}


bool EDA_BASE_FRAME::doAutoSave()
{
    wxCHECK_MSG( false, true, wxT( "Auto save timer function not overridden.  Bad programmer!" ) );
}


void EDA_BASE_FRAME::ReCreateMenuBar()
{
}


185
void EDA_BASE_FRAME::ShowChangedLanguage()
186
{
jean-pierre charras's avatar
jean-pierre charras committed
187 188
    ReCreateMenuBar();
    GetMenuBar()->Refresh();
189 190
}

plyatov's avatar
plyatov committed
191

192
void EDA_BASE_FRAME::LoadSettings( wxConfigBase* aCfg )
plyatov's avatar
plyatov committed
193
{
194
    int maximized = 0;
195

196 197
    wxString text = m_FrameName + wxT( "Pos_x" );
    aCfg->Read( text, &m_FramePos.x );
198

199 200
    text = m_FrameName + wxT( "Pos_y" );
    aCfg->Read( text, &m_FramePos.y );
201

202 203
    text = m_FrameName + wxT( "Size_x" );
    aCfg->Read( text, &m_FrameSize.x, 600 );
204

205 206
    text = m_FrameName + wxT( "Size_y" );
    aCfg->Read( text, &m_FrameSize.y, 400 );
207

208 209
    text = m_FrameName + wxT( "Maximized" );
    aCfg->Read( text, &maximized, 0 );
210

211 212 213 214
    if( m_hasAutoSave )
    {
        text = m_FrameName + entryAutoSaveInterval;
        aCfg->Read( text, &m_autoSaveInterval, DEFAULT_AUTO_SAVE_INTERVAL );
215 216 217
    }

    // Ensure Window title bar is visible
218
#if defined( __WXMAC__ )
219
    // for macOSX, the window must be below system (macOSX) toolbar
220 221
    // Ypos_min = GetMBarHeight(); seems no more exist in new API (subject to change)
    int Ypos_min = 20;
plyatov's avatar
plyatov committed
222
#else
223
    int Ypos_min = 0;
plyatov's avatar
plyatov committed
224
#endif
225 226
    if( m_FramePos.y < Ypos_min )
        m_FramePos.y = Ypos_min;
227 228 229

    if( maximized )
        Maximize();
230

231
    aCfg->Read( m_FrameName + entryPerspective, &m_perspective );
plyatov's avatar
plyatov committed
232 233 234
}


235
void EDA_BASE_FRAME::SaveSettings( wxConfigBase* aCfg )
plyatov's avatar
plyatov committed
236
{
237
    wxString        text;
plyatov's avatar
plyatov committed
238

239
    if( IsIconized() )
240
        return;
plyatov's avatar
plyatov committed
241

242 243
    m_FrameSize = GetSize();
    m_FramePos  = GetPosition();
plyatov's avatar
plyatov committed
244

245
    text = m_FrameName + wxT( "Pos_x" );
246
    aCfg->Write( text, (long) m_FramePos.x );
247

248
    text = m_FrameName + wxT( "Pos_y" );
249
    aCfg->Write( text, (long) m_FramePos.y );
250

251
    text = m_FrameName + wxT( "Size_x" );
252
    aCfg->Write( text, (long) m_FrameSize.x );
253

254
    text = m_FrameName + wxT( "Size_y" );
255
    aCfg->Write( text, (long) m_FrameSize.y );
256

257
    text = m_FrameName + wxT( "Maximized" );
258
    aCfg->Write( text, IsMaximized() );
259 260 261 262

    if( m_hasAutoSave )
    {
        text = m_FrameName + entryAutoSaveInterval;
263
        aCfg->Write( text, m_autoSaveInterval );
264
    }
265

266 267 268 269 270 271 272
    // Once this is fully implemented, wxAuiManager will be used to maintain
    // the persistance of the main frame and all it's managed windows and
    // all of the legacy frame persistence position code can be removed.
    wxString perspective = m_auimgr.SavePerspective();

    // printf( "perspective(%s): %s\n",
    //    TO_UTF8( m_FrameName + entryPerspective ), TO_UTF8( perspective ) );
273 274
    aCfg->Write( m_FrameName + entryPerspective, perspective );
}
275

276 277 278 279 280

wxConfigBase* EDA_BASE_FRAME::config()
{
    // KICAD_MANAGER_FRAME overrides this
    wxConfigBase* ret = Kiface().KifaceSettings();
281
    //wxASSERT( ret );
282
    return ret;
plyatov's avatar
plyatov committed
283 284 285
}


286 287 288 289 290 291 292 293 294 295 296 297
const SEARCH_STACK& EDA_BASE_FRAME::sys_search()
{
    return Kiface().KifaceSearch();
}


wxString EDA_BASE_FRAME::help_name()
{
    return Kiface().GetHelpFileName();
}


298
void EDA_BASE_FRAME::PrintMsg( const wxString& text )
plyatov's avatar
plyatov committed
299
{
300
    SetStatusText( text );
plyatov's avatar
plyatov committed
301 302
}

303

304
void EDA_BASE_FRAME::UpdateFileHistory( const wxString& FullFileName,
305
                                        wxFileHistory* aFileHistory )
plyatov's avatar
plyatov committed
306
{
307
    wxFileHistory* fileHistory = aFileHistory;
308

309 310
    if( !fileHistory )
        fileHistory = &Kiface().GetFileHistory();
311 312

    fileHistory->AddFileToHistory( FullFileName );
313
}
plyatov's avatar
plyatov committed
314 315


316
wxString EDA_BASE_FRAME::GetFileFromHistory( int cmdId, const wxString& type,
317
                                             wxFileHistory* aFileHistory )
318
{
319
    wxFileHistory* fileHistory = aFileHistory;
320

321 322
    if( !fileHistory )
        fileHistory = &Kiface().GetFileHistory();
323

324
    int baseId = fileHistory->GetBaseId();
325

326
    wxASSERT( cmdId >= baseId && cmdId < baseId + (int) fileHistory->GetCount() );
327

328
    unsigned i = cmdId - baseId;
329

330
    if( i < fileHistory->GetCount() )
331
    {
332
        wxString fn = fileHistory->GetHistoryFile( i );
333

334 335 336
        if( wxFileName::FileExists( fn ) )
            return fn;
        else
337
        {
338 339 340 341
            wxString msg = wxString::Format(
                        wxT( "file '%s' was not found." ),
                        GetChars( fn ) );

342
            wxMessageBox( msg );
343

344
            fileHistory->RemoveFileFromHistory( i );
345 346
        }
    }
plyatov's avatar
plyatov committed
347

348
    return wxEmptyString;
plyatov's avatar
plyatov committed
349 350 351
}


352
void EDA_BASE_FRAME::GetKicadHelp( wxCommandEvent& event )
plyatov's avatar
plyatov committed
353
{
354
    const SEARCH_STACK& search = sys_search();
355

356
    /* We have to get document for beginners,
357
     * or the full specific doc
358
     * if event id is wxID_INDEX, we want the document for beginners.
359
     * else the specific doc file (its name is in Kiface().GetHelpFileName())
360
     * The document for beginners is the same for all KiCad utilities
361 362 363
     */
    if( event.GetId() == wxID_INDEX )
    {
364
        // Search for "getting_started_in_kicad.pdf" or "Getting_Started_in_KiCad.pdf"
365
        wxString helpFile = SearchHelpFileFullPath( search, wxT( "getting_started_in_kicad.pdf" ) );
366

367
        if( !helpFile )
368
            helpFile = SearchHelpFileFullPath( search, wxT( "Getting_Started_in_KiCad.pdf" ) );
369

370 371
        if( !helpFile )
        {
372 373 374 375
            wxString msg = wxString::Format( _(
                "Help file '%s' could not be found." ),
                wxT( "getting_started_in_kicad.pdf" )
                );
376
            wxMessageBox( msg );
377 378
        }
        else
379
        {
380
            GetAssociatedDocument( this, helpFile );
381 382
        }

383 384 385
        return;
    }

386 387
    wxString base_name = help_name();

388
#if defined ONLINE_HELP_FILES_FORMAT_IS_HTML
389

390
    wxHtmlHelpController* hc = Pgm().GetHtmlHelpController();
391

392
    wxString helpFile = SearchHelpFileFullPath( search,   );
393

394
    if( !!helpFile )
395
    {
396 397 398
        hc->UseConfig( Pgm().CommonSettings() );
        hc->SetTitleFormat( wxT( "KiCad Help" ) );
        hc->AddBook( helpFile );
399
    }
400

401 402 403
    hc->DisplayContents();
    hc->Display( helpFile );

404
#elif defined ONLINE_HELP_FILES_FORMAT_IS_PDF
405
    wxString helpFile = SearchHelpFileFullPath( search, base_name );
406

407
    if( !helpFile )
408
    {
409 410 411 412
        wxString msg = wxString::Format( _(
            "Help file '%s' could not be found." ),
            GetChars( base_name )
            );
413
        wxMessageBox( msg );
414
    }
415
    else
416
    {
417
        GetAssociatedDocument( this, helpFile );
418
    }
419 420

#else
421
#   error Help files format not defined
422
#endif
plyatov's avatar
plyatov committed
423 424
}

425

426 427
void EDA_BASE_FRAME::OnSelectPreferredEditor( wxCommandEvent& event )
{
428 429
    wxFileName  fn = Pgm().GetEditorName();
    wxString    wildcard( wxT( "*" ) );
430 431 432 433 434

#ifdef __WINDOWS__
    wildcard += wxT( ".exe" );
#endif

435
    wildcard.Printf( _( "Executable file (%s)|%s" ),
436
                     GetChars( wildcard ), GetChars( wildcard ) );
437

438
    wxFileDialog dlg( this, _( "Select Preferred Editor" ), fn.GetPath(),
439 440 441 442 443 444
                      fn.GetFullName(), wildcard,
                      wxFD_OPEN | wxFD_FILE_MUST_EXIST );

    if( dlg.ShowModal() == wxID_CANCEL )
        return;

445
    wxString editor = dlg.GetPath();
446

447
    Pgm().SetEditorName( editor );
448 449
}

450

451
void EDA_BASE_FRAME::GetKicadAbout( wxCommandEvent& event )
plyatov's avatar
plyatov committed
452
{
453
    bool ShowAboutDialog(wxWindow * parent);
454
    ShowAboutDialog( this );
plyatov's avatar
plyatov committed
455
}
456 457


458
void EDA_BASE_FRAME::AddHelpVersionInfoMenuEntry( wxMenu* aMenu )
459 460 461 462
{
    wxASSERT( aMenu != NULL );

    // Copy version string to clipboard for bug report purposes.
463 464 465 466
    AddMenuItem( aMenu, ID_HELP_COPY_VERSION_STRING,
                 _( "Copy &Version Information" ),
                 _( "Copy the version string to clipboard to send with bug reports" ),
                 KiBitmap( copy_button_xpm ) );
467 468 469
}


470 471 472
// This is an enhanced version of the compiler build macro provided by wxWidgets
// in <wx/build.h>. Please do not make any of these strings translatable.  They
// are used for conveying troubleshooting information to developers.
473 474 475 476 477 478 479 480 481 482 483 484 485 486 487 488 489 490 491 492 493 494 495 496 497 498

#if defined(__GXX_ABI_VERSION)
    #define __ABI_VERSION  ",compiler with C++ ABI " __WX_BO_STRINGIZE(__GXX_ABI_VERSION)
#else
    #define __ABI_VERSION  ",compiler without C++ ABI "
#endif

#if defined(__INTEL_COMPILER)
    #define __BO_COMPILER ",Intel C++"
#elif defined(__GNUG__)
    #define __BO_COMPILER ",GCC " \
            __WX_BO_STRINGIZE(__GNUC__) "." \
            __WX_BO_STRINGIZE(__GNUC_MINOR__) "." \
            __WX_BO_STRINGIZE(__GNUC_PATCHLEVEL__)
#elif defined(__VISUALC__)
    #define __BO_COMPILER ",Visual C++"
#elif defined(__BORLANDC__)
    #define __BO_COMPILER ",Borland C++"
#elif defined(__DIGITALMARS__)
    #define __BO_COMPILER ",DigitalMars"
#elif defined(__WATCOMC__)
    #define __BO_COMPILER ",Watcom C++"
#else
    #define __BO_COMPILER ",unknown"
#endif

499
#if wxCHECK_VERSION( 2, 9, 0 )
500 501 502 503

static inline const char* KICAD_BUILD_OPTIONS_SIGNATURE()
{
    return
504 505 506 507 508 509
#ifdef __WXDEBUG__
    " (debug,"
#else
    " (release,"
#endif
    __WX_BO_UNICODE __ABI_VERSION __BO_COMPILER __WX_BO_STL
510 511 512 513 514 515

#if !wxCHECK_VERSION( 3, 0, 0 )
    __WX_BO_WXWIN_COMPAT_2_6
#endif

    __WX_BO_WXWIN_COMPAT_2_8 ")"
516 517 518
    ;
}

519
#else
520 521 522 523

static inline const char* KICAD_BUILD_OPTIONS_SIGNATURE()
{
    return
524 525 526 527 528
#ifdef __WXDEBUG__
    " (debug,"
#else
    " (release,"
#endif
529 530 531 532 533
    __WX_BO_UNICODE __ABI_VERSION __BO_COMPILER __WX_BO_STL
    __WX_BO_WXWIN_COMPAT_2_4 __WX_BO_WXWIN_COMPAT_2_6 ")"
    ;
}

534
#endif
535

536
void EDA_BASE_FRAME::CopyVersionInfoToClipboard( wxCommandEvent&  event )
537 538 539 540 541 542 543 544 545 546 547
{
    if( !wxTheClipboard->Open() )
    {
        wxMessageBox( _( "Could not open clipboard to write version information." ),
                      _( "Clipboard Error" ), wxOK | wxICON_EXCLAMATION, this );
        return;
    }

    wxString tmp;
    wxPlatformInfo info;

548
    tmp = wxT( "Application: " ) + Pgm().App().GetAppName() + wxT( "\n" );
549 550 551 552 553 554 555 556
    tmp << wxT( "Version: " ) << GetBuildVersion()
#ifdef DEBUG
        << wxT( " Debug" )
#else
        << wxT( " Release" )
#endif
        << wxT( " build\n" );
    tmp << wxT( "wxWidgets: Version " ) << FROM_UTF8( wxVERSION_NUM_DOT_STRING )
557
        << FROM_UTF8( KICAD_BUILD_OPTIONS_SIGNATURE() ) << wxT( "\n" )
558 559
        << wxT( "Platform: " ) << wxGetOsDescription() << wxT( ", " )
        << info.GetArchName() << wxT( ", " ) << info.GetEndiannessName() << wxT( ", " )
560 561
        << info.GetPortIdName() << wxT( "\n" );

562 563 564 565 566
    // Just in case someone builds KiCad with the platform native of Boost instead of
    // the version included with the KiCad source.
    tmp << wxT( "Boost version: " ) << ( BOOST_VERSION / 100000 ) << wxT( "." )
        << ( BOOST_VERSION / 100 % 1000 ) << wxT( "." ) << ( BOOST_VERSION % 100 ) << wxT( "\n" );

567 568 569 570 571 572 573 574 575 576 577 578 579 580
    tmp << wxT( "         USE_WX_GRAPHICS_CONTEXT=" );
#ifdef USE_WX_GRAPHICS_CONTEXT
    tmp << wxT( "ON\n" );
#else
    tmp << wxT( "OFF\n" );
#endif

    tmp << wxT( "         USE_WX_OVERLAY=" );
#ifdef USE_WX_OVERLAY
    tmp << wxT( "ON\n" );
#else
    tmp << wxT( "OFF\n" );
#endif

581 582 583 584 585 586 587
    tmp << wxT( "         KICAD_SCRIPTING=" );
#ifdef KICAD_SCRIPTING
    tmp << wxT( "ON\n" );
#else
    tmp << wxT( "OFF\n" );
#endif

588 589 590 591 592 593 594 595 596 597 598 599 600
    tmp << wxT( "         KICAD_SCRIPTING_MODULES=" );
#ifdef KICAD_SCRIPTING_MODULES
    tmp << wxT( "ON\n" );
#else
    tmp << wxT( "OFF\n" );
#endif

    tmp << wxT( "         KICAD_SCRIPTING_WXPYTHON=" );
#ifdef KICAD_SCRIPTING_WXPYTHON
    tmp << wxT( "ON\n" );
#else
    tmp << wxT( "OFF\n" );
#endif
601

602
    tmp << wxT( "         USE_FP_LIB_TABLE=HARD_CODED_ON\n" );
603

604 605
    tmp << wxT( "         BUILD_GITHUB_PLUGIN=" );
#ifdef BUILD_GITHUB_PLUGIN
606 607 608 609 610
    tmp << wxT( "ON\n" );
#else
    tmp << wxT( "OFF\n" );
#endif

611 612
    wxMessageBox( tmp, _("Version Information (copied to the clipboard)") );

613 614 615
    wxTheClipboard->SetData( new wxTextDataObject( tmp ) );
    wxTheClipboard->Close();
}
616 617 618 619 620


bool EDA_BASE_FRAME::IsWritable( const wxFileName& aFileName )
{
    wxString msg;
621
    wxFileName fn = aFileName;
622

623 624 625 626 627 628 629 630
    // Check for absence of a file path with a file name.  Unfortunately KiCad
    // uses paths relative to the current project path without the ./ part which
    // confuses wxFileName. Making the file name path absolute may be less than
    // elegant but it solves the problem.
    if( fn.GetPath().IsEmpty() && fn.HasName() )
        fn.MakeAbsolute();

    wxCHECK_MSG( fn.IsOk(), false,
631
                 wxT( "File name object is invalid.  Bad programmer!" ) );
632 633
    wxCHECK_MSG( !fn.GetPath().IsEmpty(), false,
                 wxT( "File name object path <" ) + fn.GetFullPath() +
634
                 wxT( "> is not set.  Bad programmer!" ) );
635

636
    if( fn.IsDir() && !fn.IsDirWritable() )
637 638
    {
        msg.Printf( _( "You do not have write permissions to folder <%s>." ),
639
                    GetChars( fn.GetPath() ) );
640
    }
641
    else if( !fn.FileExists() && !fn.IsDirWritable() )
642
    {
643
        msg.Printf( _( "You do not have write permissions to save file <%s> to folder <%s>." ),
644
                    GetChars( fn.GetFullName() ), GetChars( fn.GetPath() ) );
645
    }
646
    else if( fn.FileExists() && !fn.IsFileWritable() )
647 648
    {
        msg.Printf( _( "You do not have write permissions to save file <%s>." ),
649
                    GetChars( fn.GetFullPath() ) );
650 651 652 653
    }

    if( !msg.IsEmpty() )
    {
654
        wxMessageBox( msg );
655 656 657 658 659
        return false;
    }

    return true;
}
660 661 662 663 664 665 666 667 668 669 670 671 672 673 674 675 676 677 678


void EDA_BASE_FRAME::CheckForAutoSaveFile( const wxFileName& aFileName,
                                           const wxString&   aBackupFileExtension )
{
    wxCHECK_RET( aFileName.IsOk(), wxT( "Invalid file name!" ) );
    wxCHECK_RET( !aBackupFileExtension.IsEmpty(), wxT( "Invalid backup file extension!" ) );

    wxFileName autoSaveFileName = aFileName;

    // Check for auto save file.
    autoSaveFileName.SetName( wxT( "$" ) + aFileName.GetName() );

    wxLogTrace( traceAutoSave,
                wxT( "Checking for auto save file " ) + autoSaveFileName.GetFullPath() );

    if( !autoSaveFileName.FileExists() )
        return;

679 680 681 682 683 684
    wxString msg = wxString::Format( _(
            "Well this is potentially embarrassing!  It appears that the last time "
            "you were editing the file '%s' it was not saved properly.  Do you wish to restore the last "
            "edits you made?" ),
            GetChars( aFileName.GetFullName() )
        );
685

686
    int response = wxMessageBox( msg, Pgm().App().GetAppName(), wxYES_NO | wxICON_QUESTION, this );
687 688 689 690 691 692 693 694 695 696 697 698 699 700 701 702 703 704 705 706

    // Make a backup of the current file, delete the file, and rename the auto save file to
    // the file name.
    if( response == wxYES )
    {
        // Get the backup file name.
        wxFileName backupFileName = aFileName;
        backupFileName.SetExt( aBackupFileExtension );

        // If an old backup file exists, delete it.  If an old copy of the file exists, rename
        // it to the backup file name
        if( aFileName.FileExists() )
        {
            // Remove the old file backup file.
            if( backupFileName.FileExists() )
                wxRemoveFile( backupFileName.GetFullPath() );

            // Rename the old file to the backup file name.
            if( !wxRenameFile( aFileName.GetFullPath(), backupFileName.GetFullPath() ) )
            {
707 708
                msg.Printf( _( "Could not create backup file <%s>" ),
                            GetChars( backupFileName.GetFullPath() ) );
709
                wxMessageBox( msg );
710 711 712 713 714 715
            }
        }

        if( !wxRenameFile( autoSaveFileName.GetFullPath(), aFileName.GetFullPath() ) )
        {
            wxMessageBox( _( "The auto save file could not be renamed to the board file name." ),
716
                          Pgm().App().GetAppName(), wxOK | wxICON_EXCLAMATION, this );
717 718 719 720 721 722 723 724 725 726 727
        }
    }
    else
    {
        wxLogTrace( traceAutoSave,
                    wxT( "Removing auto save file " ) + autoSaveFileName.GetFullPath() );

        // Remove the auto save file when using the previous file as is.
        wxRemoveFile( autoSaveFileName.GetFullPath() );
    }
}
728