KiCad PCB EDA Suite
eda_base_frame.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) 2017 Jean-Pierre Charras, jp.charras at wanadoo.fr
5  * Copyright (C) 2013 Wayne Stambaugh <stambaughw@gmail.com>
6  * Copyright (C) 1992-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 
26 #include <bitmaps.h>
27 #include <dialog_shim.h>
30 #include <filehistory.h>
31 #include <id.h>
32 #include <kiface_i.h>
33 #include <menus_helpers.h>
34 #include <panel_hotkeys_editor.h>
35 #include <pgm_base.h>
36 #include <settings/app_settings.h>
39 #include <tool/action_manager.h>
40 #include <tool/action_menu.h>
41 #include <tool/actions.h>
42 #include <tool/common_control.h>
43 #include <tool/tool_manager.h>
44 #include <tool/tool_dispatcher.h>
45 #include <trace_helpers.h>
46 #include <widgets/paged_dialog.h>
47 #include <wx/display.h>
48 #include <wx/stdpaths.h>
49 #include <wx/string.h>
50 
51 wxDEFINE_EVENT( UNITS_CHANGED, wxCommandEvent );
52 
53 
54 // Minimum window size
55 static const int s_minsize_x = 500;
56 static const int s_minsize_y = 400;
57 
58 
59 BEGIN_EVENT_TABLE( EDA_BASE_FRAME, wxFrame )
60  EVT_MENU( wxID_ABOUT, EDA_BASE_FRAME::OnKicadAbout )
61  EVT_MENU( wxID_PREFERENCES, EDA_BASE_FRAME::OnPreferences )
62 
63  EVT_CHAR_HOOK( EDA_BASE_FRAME::OnCharHook )
64  EVT_MENU_OPEN( EDA_BASE_FRAME::OnMenuEvent )
65  EVT_MENU_CLOSE( EDA_BASE_FRAME::OnMenuEvent )
66  EVT_MENU_HIGHLIGHT_ALL( EDA_BASE_FRAME::OnMenuEvent )
67  EVT_MOVE( EDA_BASE_FRAME::OnMove )
68  EVT_MAXIMIZE( EDA_BASE_FRAME::OnMaximize )
69 END_EVENT_TABLE()
70 
71 EDA_BASE_FRAME::EDA_BASE_FRAME( wxWindow* aParent, FRAME_T aFrameType,
72  const wxString& aTitle, const wxPoint& aPos, const wxSize& aSize,
73  long aStyle, const wxString& aFrameName, KIWAY* aKiway ) :
74  wxFrame( aParent, wxID_ANY, aTitle, aPos, aSize, aStyle, aFrameName ),
75  TOOLS_HOLDER(),
76  KIWAY_HOLDER( aKiway, KIWAY_HOLDER::FRAME ),
77  m_Ident( aFrameType ),
78  m_infoBar( nullptr ),
79  m_settingsManager( nullptr ),
80  m_fileHistory( nullptr ),
81  m_hasAutoSave( false ),
82  m_autoSaveState( false ),
83  m_autoSaveInterval(-1 ),
84  m_userUnits( EDA_UNITS::MILLIMETRES )
85 {
86  m_autoSaveTimer = new wxTimer( this, ID_AUTO_SAVE_TIMER );
87  m_mruPath = wxStandardPaths::Get().GetDocumentsDir();
88  m_FrameSize = wxSize( s_minsize_x, s_minsize_y );
89 
90  m_settingsManager = &Pgm().GetSettingsManager();
91 
92  // Set a reasonable minimal size for the frame
93  SetSizeHints( s_minsize_x, s_minsize_y, -1, -1, -1, -1 );
94 
95  // Store dimensions of the user area of the main window.
96  GetClientSize( &m_FrameSize.x, &m_FrameSize.y );
97 
98  Connect( ID_AUTO_SAVE_TIMER, wxEVT_TIMER,
99  wxTimerEventHandler( EDA_BASE_FRAME::onAutoSaveTimer ) );
100 
101  // hook wxEVT_CLOSE_WINDOW so we can call SaveSettings(). This function seems
102  // to be called before any other hook for wxCloseEvent, which is necessary.
103  Connect( wxEVT_CLOSE_WINDOW, wxCloseEventHandler( EDA_BASE_FRAME::windowClosing ) );
104 }
105 
106 
108 {
109  for( auto& iter : GetChildren() )
110  {
111  DIALOG_SHIM* dlg = dynamic_cast<DIALOG_SHIM*>( iter );
112  if( dlg && dlg->IsQuasiModal() )
113  return dlg;
114  }
115 
116  // FIXME: CvPcb is currently implemented on top of KIWAY_PLAYER rather than DIALOG_SHIM,
117  // so we have to look for it separately.
118  if( m_Ident == FRAME_SCH )
119  {
120  wxWindow* cvpcb = wxWindow::FindWindowByName( "CvpcbFrame" );
121  if( cvpcb )
122  return cvpcb;
123  }
124 
125  return nullptr;
126 }
127 
128 
129 void EDA_BASE_FRAME::windowClosing( wxCloseEvent& event )
130 {
131  // Don't allow closing when a quasi-modal is open.
132  wxWindow* quasiModal = findQuasiModalDialog();
133 
134  if( quasiModal )
135  {
136  // Raise and notify; don't give the user a warning regarding "quasi-modal dialogs"
137  // when they have no idea what those are.
138  quasiModal->Raise();
139  wxBell();
140 
141  event.Veto();
142  return;
143  }
144 
145  APP_SETTINGS_BASE* cfg = config();
146 
147  if( cfg )
148  SaveSettings( cfg ); // virtual, wxFrame specific
149 
150  event.Skip(); // we did not "handle" the event, only eavesdropped on it.
151 }
152 
153 
155 {
156  delete m_autoSaveTimer;
157  delete m_fileHistory;
158 
160  {
162  }
163 }
164 
165 
167 {
168 #if defined( _WIN32 )
169  return true;
170 #else
171  return false;
172 #endif
173 }
174 
175 
177 {
178 #if defined( _WIN32 )
179  // Windows: Destroys any block reason that may have existed
180  ShutdownBlockReasonDestroy( GetHandle() );
181 #endif
182 }
183 
184 
185 void EDA_BASE_FRAME::SetShutdownBlockReason( const wxString& aReason )
186 {
187 #if defined( _WIN32 )
188  // Windows: sets up the pretty message on the shutdown page on why it's being "blocked"
189  // This is used in conjunction with handling WM_QUERYENDSESSION (wxCloseEvent)
190  // ShutdownBlockReasonCreate does not block by itself
191 
192  ShutdownBlockReasonDestroy( GetHandle() ); // Destroys any existing or nonexisting reason
193 
194  if( !ShutdownBlockReasonCreate( GetHandle(), aReason.wc_str() ) )
195  {
196  // Nothing bad happens if this fails, at worst it uses a generic application is preventing shutdown message
197  wxLogDebug( wxT( "ShutdownBlockReasonCreate failed to set reason: %s" ), aReason );
198  }
199 #endif
200 }
201 
202 
203 bool EDA_BASE_FRAME::ProcessEvent( wxEvent& aEvent )
204 {
205 #ifdef __WXMAC__
206  // Apple in its infinite wisdom will raise a disabled window before even passing
207  // us the event, so we have no way to stop it. Instead, we have to catch an
208  // improperly ordered disabled window and quasi-modal dialog here and reorder
209  // them.
210  if( !IsEnabled() && IsActive() )
211  {
212  wxWindow* dlg = findQuasiModalDialog();
213  if( dlg )
214  dlg->Raise();
215  }
216 #endif
217 
218  if( !wxFrame::ProcessEvent( aEvent ) )
219  return false;
220 
221  if( IsShown() && m_hasAutoSave && IsActive() &&
223  {
224  if( !m_autoSaveState )
225  {
226  wxLogTrace( traceAutoSave, wxT( "Starting auto save timer." ) );
227  m_autoSaveTimer->Start( m_autoSaveInterval * 1000, wxTIMER_ONE_SHOT );
228  m_autoSaveState = true;
229  }
230  else if( m_autoSaveTimer->IsRunning() )
231  {
232  wxLogTrace( traceAutoSave, wxT( "Stopping auto save timer." ) );
233  m_autoSaveTimer->Stop();
234  m_autoSaveState = false;
235  }
236  }
237 
238  return true;
239 }
240 
241 
243 {
244  m_autoSaveInterval = aInterval;
245 
246  if( m_autoSaveTimer->IsRunning() )
247  {
248  if( m_autoSaveInterval > 0 )
249  {
250  m_autoSaveTimer->Start( m_autoSaveInterval * 1000, wxTIMER_ONE_SHOT );
251  }
252  else
253  {
254  m_autoSaveTimer->Stop();
255  m_autoSaveState = false;
256  }
257  }
258 }
259 
260 
261 void EDA_BASE_FRAME::onAutoSaveTimer( wxTimerEvent& aEvent )
262 {
263  if( !doAutoSave() )
264  m_autoSaveTimer->Start( m_autoSaveInterval * 1000, wxTIMER_ONE_SHOT );
265 }
266 
267 
269 {
270  wxCHECK_MSG( false, true, wxT( "Auto save timer function not overridden. Bad programmer!" ) );
271 }
272 
273 
274 void EDA_BASE_FRAME::OnCharHook( wxKeyEvent& event )
275 {
276  wxLogTrace( kicadTraceKeyEvent, "EDA_BASE_FRAME::OnCharHook %s", dump( event ) );
277  // Key events can be filtered here.
278  // Currently no filtering is made.
279  event.Skip();
280 }
281 
282 
283 void EDA_BASE_FRAME::OnMenuEvent( wxMenuEvent& aEvent )
284 {
285  if( !m_toolDispatcher )
286  aEvent.Skip();
287  else
289 }
290 
291 
293 {
294 }
295 
296 
297 void EDA_BASE_FRAME::AddStandardHelpMenu( wxMenuBar* aMenuBar )
298 {
299  COMMON_CONTROL* commonControl = m_toolManager->GetTool<COMMON_CONTROL>();
300  ACTION_MENU* helpMenu = new ACTION_MENU( false );
301 
302  helpMenu->SetTool( commonControl );
303 
304  helpMenu->Add( ACTIONS::help );
305  helpMenu->Add( ACTIONS::gettingStarted );
306  helpMenu->Add( ACTIONS::listHotKeys );
307  helpMenu->Add( ACTIONS::getInvolved );
308  helpMenu->Add( ACTIONS::reportBug );
309 
310  helpMenu->AppendSeparator();
311  helpMenu->Add( _( "&About KiCad" ), "", wxID_ABOUT, about_xpm );
312 
313  aMenuBar->Append( helpMenu, _( "&Help" ) );
314 }
315 
316 
318 {
319  if( GetMenuBar() )
320  {
321  ReCreateMenuBar();
322  GetMenuBar()->Refresh();
323  }
324 }
325 
326 
327 void EDA_BASE_FRAME::CommonSettingsChanged( bool aEnvVarsChanged )
328 {
329  TOOLS_HOLDER::CommonSettingsChanged( aEnvVarsChanged );
330 
331  COMMON_SETTINGS* settings = Pgm().GetCommonSettings();
332 
333  if( m_fileHistory )
334  {
335  int historySize = settings->m_System.file_history_size;
336  m_fileHistory->SetMaxFiles( (unsigned) std::max( 0, historySize ) );
337  }
338 
339  if( GetMenuBar() )
340  {
341  // For icons in menus, icon scaling & hotkeys
342  ReCreateMenuBar();
343  GetMenuBar()->Refresh();
344  }
345 }
346 
347 
349 {
350  m_FramePos.x = aCfg->pos_x;
351  m_FramePos.y = aCfg->pos_y;
352  m_FrameSize.x = aCfg->size_x;
353  m_FrameSize.y = aCfg->size_y;
354 
355  wxLogTrace( traceDisplayLocation, "Config position (%d, %d) with size (%d, %d)",
357 
358  // Ensure minimum size is set if the stored config was zero-initialized
360  {
363 
364  wxLogTrace( traceDisplayLocation, "Using minimum size (%d, %d)", m_FrameSize.x, m_FrameSize.y );
365  }
366 
367  wxPoint upperRight( m_FramePos.x + m_FrameSize.x, m_FramePos.y );
368  wxPoint upperLeft( m_FramePos.x, m_FramePos.y );
369 
370  // Check to see if the requested display is still attached to the computer
371  int leftInd = wxDisplay::GetFromPoint( upperLeft );
372  int rightInd = wxDisplay::GetFromPoint( upperRight );
373 
374  wxLogTrace( traceDisplayLocation, "Number of displays: %d", wxDisplay::GetCount() );
375  wxLogTrace( traceDisplayLocation, "Previous display indices: %d and %d", leftInd, rightInd );
376 
377  if( rightInd == wxNOT_FOUND && leftInd == wxNOT_FOUND )
378  {
379  wxLogTrace( traceDisplayLocation, "Previous display not found" );
380 
381  // If it isn't attached, use the first display
382  // Warning wxDisplay has 2 ctor variants. the parameter needs a type:
383  const unsigned int index = 0;
384  wxDisplay display( index );
385  wxRect clientSize = display.GetClientArea();
386 
387  wxLogDebug( "Client size (%d, %d)", clientSize.width, clientSize.height );
388 
389  m_FramePos = wxDefaultPosition;
390 
391  // Ensure the window fits on the display, since the other one could have been larger
392  if( m_FrameSize.x > clientSize.width )
393  m_FrameSize.x = clientSize.width;
394 
395  if( m_FrameSize.y > clientSize.height )
396  m_FrameSize.y = clientSize.height;
397  }
398  else
399  {
400  wxRect clientSize;
401 
402  if( leftInd == wxNOT_FOUND )
403  {
404  // If the top-left point is off-screen, use the display for the top-right point
405  wxDisplay display( rightInd );
406  clientSize = display.GetClientArea();
407  }
408  else
409  {
410  wxDisplay display( leftInd );
411  clientSize = display.GetClientArea();
412  }
413 
414 // The percentage size (represented in decimal) of the region around the screen's border where
415 // an upper corner is not allowed
416 #define SCREEN_BORDER_REGION 0.10
417 
418  int yLim = clientSize.y + ( clientSize.height * ( 1.0 - SCREEN_BORDER_REGION ) );
419  int xLimLeft = clientSize.x + ( clientSize.width * SCREEN_BORDER_REGION );
420  int xLimRight = clientSize.x + ( clientSize.width * ( 1.0 - SCREEN_BORDER_REGION ) );
421 
422  if( upperLeft.x > xLimRight || // Upper left corner too close to right edge of screen
423  upperRight.x < xLimLeft || // Upper right corner too close to left edge of screen
424  upperRight.y > yLim ) // Upper corner too close to the bottom of the screen
425  {
426  m_FramePos = wxDefaultPosition;
427  wxLogTrace( traceDisplayLocation, "Resetting to default position" );
428  }
429  }
430 
431  // Ensure Window title bar is visible
432 #if defined( __WXOSX__ )
433  // for macOSX, the window must be below system (macOSX) toolbar
434  int Ypos_min = 20;
435 #else
436  int Ypos_min = 0;
437 #endif
438  if( m_FramePos.y < Ypos_min )
439  m_FramePos.y = Ypos_min;
440 
441  wxLogTrace( traceDisplayLocation, "Final window position (%d, %d) with size (%d, %d)",
443 
444  SetSize( m_FramePos.x, m_FramePos.y, m_FrameSize.x, m_FrameSize.y );
445 
446  // Center the window if we reset to default
447  if( m_FramePos.x == -1 )
448  {
449  wxLogTrace( traceDisplayLocation, "Centering window" );
450  Center();
451  m_FramePos = GetPosition();
452  }
453 
454  // Record the frame sizes in an un-maximized state
457 
458  // Maximize if we were maximized before
459  if( aCfg->maximized )
460  {
461  wxLogTrace( traceDisplayLocation, "Maximizing window" );
462  Maximize();
463  }
464 
465  if( m_hasAutoSave )
466  m_autoSaveInterval = Pgm().GetCommonSettings()->m_System.autosave_interval;
467 
468  m_perspective = aCfg->perspective;
469  m_mruPath = aCfg->mru_path;
470 
472 }
473 
474 
476 {
477  wxString text;
478 
479  if( IsIconized() )
480  return;
481 
482  wxString baseCfgName = ConfigBaseName();
483 
484  // If the window is maximized, we use the saved window size from before it was maximized
485  if( IsMaximized() )
486  {
489  }
490  else
491  {
493  m_FramePos = GetPosition();
494  }
495 
496  aCfg->pos_x = m_FramePos.x;
497  aCfg->pos_y = m_FramePos.y;
498  aCfg->size_x = m_FrameSize.x;
499  aCfg->size_y = m_FrameSize.y;
500  aCfg->maximized = IsMaximized();
501 
502  wxLogTrace( traceDisplayLocation, "Saving window maximized: %s", IsMaximized() ? "true" : "false" );
503  wxLogTrace( traceDisplayLocation, "Saving config position (%d, %d) with size (%d, %d)",
505 
506  // TODO(JE) should auto-save in common settings be overwritten by every app?
507  if( m_hasAutoSave )
508  Pgm().GetCommonSettings()->m_System.autosave_interval = m_autoSaveInterval;
509 
510  // Once this is fully implemented, wxAuiManager will be used to maintain
511  // the persistance of the main frame and all it's managed windows and
512  // all of the legacy frame persistence position code can be removed.
513  aCfg->perspective = m_auimgr.SavePerspective().ToStdString();
514 
515  aCfg->mru_path = m_mruPath;
516 }
517 
518 
520 {
522 
523  // Get file history size from common settings
524  int fileHistorySize = Pgm().GetCommonSettings()->m_System.file_history_size;
525 
526  // Load the recently used files into the history menu
527  m_fileHistory = new FILE_HISTORY( (unsigned) std::max( 0, fileHistorySize ),
529  m_fileHistory->Load( *aCfg );
530 }
531 
532 
534 {
536 
537  // Save the recently used files list
538  if( m_fileHistory )
539  {
540  // Save the currently opened file in the file history
541  wxString currentlyOpenedFile = GetCurrentFileName();
542 
543  if( !currentlyOpenedFile.IsEmpty() )
544  UpdateFileHistory( currentlyOpenedFile );
545 
546  m_fileHistory->Save( *aCfg );
547  }
548 }
549 
550 
552 {
553  return &aCfg->m_Window;
554 }
555 
556 
558 {
559  // KICAD_MANAGER_FRAME overrides this
560  return Kiface().KifaceSettings();
561 }
562 
563 
565 {
566  return Kiface().KifaceSearch();
567 }
568 
569 
571 {
572  return Kiface().GetHelpFileName();
573 }
574 
575 
576 void EDA_BASE_FRAME::PrintMsg( const wxString& text )
577 {
578  SetStatusText( text );
579 }
580 
581 
582 void EDA_BASE_FRAME::UpdateFileHistory( const wxString& FullFileName, FILE_HISTORY* aFileHistory )
583 {
584  if( !aFileHistory )
585  aFileHistory = m_fileHistory;
586 
587  wxASSERT( aFileHistory );
588 
589  aFileHistory->AddFileToHistory( FullFileName );
590 
591  // Update the menubar to update the file history menu
592  if( GetMenuBar() )
593  {
594  ReCreateMenuBar();
595  GetMenuBar()->Refresh();
596  }
597 }
598 
599 
600 wxString EDA_BASE_FRAME::GetFileFromHistory( int cmdId, const wxString& type,
601  FILE_HISTORY* aFileHistory )
602 {
603  if( !aFileHistory )
604  aFileHistory = m_fileHistory;
605 
606  wxASSERT( aFileHistory );
607 
608  int baseId = aFileHistory->GetBaseId();
609 
610  wxASSERT( cmdId >= baseId && cmdId < baseId + (int) aFileHistory->GetCount() );
611 
612  unsigned i = cmdId - baseId;
613 
614  if( i < aFileHistory->GetCount() )
615  {
616  wxString fn = aFileHistory->GetHistoryFile( i );
617 
618  if( wxFileName::FileExists( fn ) )
619  return fn;
620  else
621  {
622  wxString msg = wxString::Format( _( "File \"%s\" was not found." ), fn );
623  wxMessageBox( msg );
624 
625  aFileHistory->RemoveFileFromHistory( i );
626  }
627  }
628 
629  // Update the menubar to update the file history menu
630  if( GetMenuBar() )
631  {
632  ReCreateMenuBar();
633  GetMenuBar()->Refresh();
634  }
635 
636  return wxEmptyString;
637 }
638 
639 
641 {
642  if( !aFileHistory )
643  aFileHistory = m_fileHistory;
644 
645  wxASSERT( aFileHistory );
646 
647  aFileHistory->ClearFileHistory();
648 
649  // Update the menubar to update the file history menu
650  if( GetMenuBar() )
651  {
652  ReCreateMenuBar();
653  GetMenuBar()->Refresh();
654  }
655 }
656 
657 
658 void EDA_BASE_FRAME::OnKicadAbout( wxCommandEvent& event )
659 {
660  void ShowAboutDialog(EDA_BASE_FRAME * aParent); // See AboutDialog_main.cpp
661  ShowAboutDialog( this );
662 }
663 
664 
665 void EDA_BASE_FRAME::OnPreferences( wxCommandEvent& event )
666 {
667  PAGED_DIALOG dlg( this, _( "Preferences" ) );
668  wxTreebook* book = dlg.GetTreebook();
669 
670  book->AddPage( new PANEL_COMMON_SETTINGS( &dlg, book ), _( "Common" ) );
671 
672  book->AddPage( new PANEL_MOUSE_SETTINGS( &dlg, book ), _( "Mouse and Touchpad" ) );
673 
674  PANEL_HOTKEYS_EDITOR* hotkeysPanel = new PANEL_HOTKEYS_EDITOR( this, book, false );
675  book->AddPage( hotkeysPanel, _( "Hotkeys" ) );
676 
677  for( unsigned i = 0; i < KIWAY_PLAYER_COUNT; ++i )
678  {
679  KIWAY_PLAYER* frame = dlg.Kiway().Player( (FRAME_T) i, false );
680 
681  if( frame )
682  frame->InstallPreferences( &dlg, hotkeysPanel );
683  }
684 
685  // The Kicad manager frame is not a player so we have to add it by hand
686  wxWindow* manager = wxFindWindowByName( KICAD_MANAGER_FRAME_NAME );
687 
688  if( manager )
689  static_cast<EDA_BASE_FRAME*>( manager )->InstallPreferences( &dlg, hotkeysPanel );
690 
691  for( size_t i = 0; i < book->GetPageCount(); ++i )
692  book->GetPage( i )->Layout();
693 
694  if( dlg.ShowModal() == wxID_OK )
695  dlg.Kiway().CommonSettingsChanged( false );
696 }
697 
698 
699 bool EDA_BASE_FRAME::IsWritable( const wxFileName& aFileName )
700 {
701  wxString msg;
702  wxFileName fn = aFileName;
703 
704  // Check for absence of a file path with a file name. Unfortunately KiCad
705  // uses paths relative to the current project path without the ./ part which
706  // confuses wxFileName. Making the file name path absolute may be less than
707  // elegant but it solves the problem.
708  if( fn.GetPath().IsEmpty() && fn.HasName() )
709  fn.MakeAbsolute();
710 
711  wxCHECK_MSG( fn.IsOk(), false,
712  wxT( "File name object is invalid. Bad programmer!" ) );
713  wxCHECK_MSG( !fn.GetPath().IsEmpty(), false,
714  wxT( "File name object path <" ) + fn.GetFullPath() +
715  wxT( "> is not set. Bad programmer!" ) );
716 
717  if( fn.IsDir() && !fn.IsDirWritable() )
718  {
719  msg.Printf( _( "You do not have write permissions to folder \"%s\"." ),
720  GetChars( fn.GetPath() ) );
721  }
722  else if( !fn.FileExists() && !fn.IsDirWritable() )
723  {
724  msg.Printf( _( "You do not have write permissions to save file \"%s\" to folder \"%s\"." ),
725  GetChars( fn.GetFullName() ), GetChars( fn.GetPath() ) );
726  }
727  else if( fn.FileExists() && !fn.IsFileWritable() )
728  {
729  msg.Printf( _( "You do not have write permissions to save file \"%s\"." ),
730  GetChars( fn.GetFullPath() ) );
731  }
732 
733  if( !msg.IsEmpty() )
734  {
735  wxMessageBox( msg );
736  return false;
737  }
738 
739  return true;
740 }
741 
742 
743 void EDA_BASE_FRAME::CheckForAutoSaveFile( const wxFileName& aFileName )
744 {
745  wxCHECK_RET( aFileName.IsOk(), wxT( "Invalid file name!" ) );
746 
747  wxFileName autoSaveFileName = aFileName;
748 
749  // Check for auto save file.
750  autoSaveFileName.SetName( GetAutoSaveFilePrefix() + aFileName.GetName() );
751 
752  wxLogTrace( traceAutoSave,
753  wxT( "Checking for auto save file " ) + autoSaveFileName.GetFullPath() );
754 
755  if( !autoSaveFileName.FileExists() )
756  return;
757 
758  wxString msg = wxString::Format( _(
759  "Well this is potentially embarrassing!\n"
760  "It appears that the last time you were editing the file\n"
761  "\"%s\"\n"
762  "it was not saved properly. Do you wish to restore the last saved edits you made?" ),
763  GetChars( aFileName.GetFullName() )
764  );
765 
766  int response = wxMessageBox( msg, Pgm().App().GetAppName(), wxYES_NO | wxICON_QUESTION, this );
767 
768  // Make a backup of the current file, delete the file, and rename the auto save file to
769  // the file name.
770  if( response == wxYES )
771  {
772  if( !wxRenameFile( autoSaveFileName.GetFullPath(), aFileName.GetFullPath() ) )
773  {
774  wxMessageBox( _( "The auto save file could not be renamed to the board file name." ),
775  Pgm().App().GetAppName(), wxOK | wxICON_EXCLAMATION, this );
776  }
777  }
778  else
779  {
780  wxLogTrace( traceAutoSave,
781  wxT( "Removing auto save file " ) + autoSaveFileName.GetFullPath() );
782 
783  // Remove the auto save file when using the previous file as is.
784  wxRemoveFile( autoSaveFileName.GetFullPath() );
785  }
786 }
787 
788 
790 {
791  // This function should be overridden in child classes
792  return false;
793 }
794 
795 
797 {
798  SetUserUnits( aUnits );
800 
801  wxCommandEvent e( UNITS_CHANGED );
802  ProcessEventLocally( e );
803 }
804 
805 
806 void EDA_BASE_FRAME::OnMaximize( wxMaximizeEvent& aEvent )
807 {
808  // When we maximize the window, we want to save the old information
809  // so that we can add it to the settings on next window load.
810  // Contrary to the documentation, this event seems to be generated
811  // when the window is also being unmaximized on OSX, so we only
812  // capture the size information when we maximize the window when on OSX.
813 #ifdef __WXOSX__
814  if( !IsMaximized() )
815 #endif
816  {
818  m_NormalFramePos = GetPosition();
819  wxLogTrace( traceDisplayLocation, "Maximizing window - Saving position (%d, %d) with size (%d, %d)",
821  }
822 
823  // Skip event to actually maximize the window
824  aEvent.Skip();
825 }
826 
827 
829 {
830 #ifdef __WXGTK__
831  // GTK includes the window decorations in the normal GetSize call,
832  // so we have to use a GTK-specific sizing call that returns the
833  // non-decorated window size.
834  int width = 0;
835  int height = 0;
836  GTKDoGetSize( &width, &height );
837 
838  wxSize winSize( width, height );
839 #else
840  wxSize winSize = GetSize();
841 #endif
842 
843  return winSize;
844 }
EDA_UNITS
Definition: common.h:198
wxString mru_path
Definition: app_settings.h:71
static TOOL_ACTION listHotKeys
Definition: actions.h:172
void PrintMsg(const wxString &text)
KIWAY_HOLDER is a mix in class which holds the location of a wxWindow's KIWAY.
Definition: kiway_holder.h:39
KIWAY_PLAYER is a wxFrame capable of the OpenProjectFiles function, meaning it can load a portion of ...
Definition: kiway_player.h:59
KIWAY & Kiway() const
Function Kiway returns a reference to the KIWAY that this object has an opportunity to participate in...
Definition: kiway_holder.h:56
KIWAY Kiway & Pgm(), KFCTL_STANDALONE
The global Program "get" accessor.
Definition: single_top.cpp:104
wxString m_mruPath
void SetShutdownBlockReason(const wxString &reason)
Sets the block reason why the window/application is preventing OS shutdown.
virtual bool doAutoSave()
This should be overridden by the derived class to handle the auto save feature.
const wxChar *const traceAutoSave
Flag to enable auto save feature debug tracing.
virtual APP_SETTINGS_BASE * config() const
Returns the settings object used in SaveSettings(), and is overloaded in KICAD_MANAGER_FRAME.
virtual void SaveSettings(APP_SETTINGS_BASE *aCfg)
Saves common frame parameters to a configuration data file.
ACTION_MENU.
Definition: action_menu.h:44
VTBL_ENTRY void CommonSettingsChanged(bool aEnvVarsChanged)
Function CommonSettingsChanged Calls CommonSettingsChanged() on all KIWAY_PLAYERs.
Definition: kiway.cpp:472
void SaveWindowSettings(WINDOW_SETTINGS *aCfg)
Saves window settings to the given settings object Normally called by SaveSettings unless the window ...
void CommonSettingsChanged(bool aEnvVarsChanged) override
Notification event that some of the common (suite-wide) settings have changed.
FRAME_T
Enum FRAME_T is the set of EDA_BASE_FRAME derivatives, typically stored in EDA_BASE_FRAME::m_Ident.
Definition: frame_type.h:34
void windowClosing(wxCloseEvent &event)
(with its unexpected name so it does not collide with the real OnWindowClose() function provided in d...
virtual bool isAutoSaveRequired() const
Return the auto save status of the application.
void Save(APP_SETTINGS_BASE &aSettings)
Saves history into a JSON settings object.
Definition: filehistory.cpp:65
void onAutoSaveTimer(wxTimerEvent &aEvent)
Handle the auto save timer event.
static TOOL_ACTION reportBug
Definition: actions.h:174
APP_SETTINGS_BASE * KifaceSettings() const
Definition: kiface_i.h:103
const wxChar *const traceDisplayLocation
Flag to enable debug output of display positioning logic.
virtual bool IsContentModified()
Get if the contents of the frame have been modified since the last save.
void Load(const APP_SETTINGS_BASE &aSettings)
Loads history from a JSON settings object.
Definition: filehistory.cpp:45
void ChangeUserUnits(EDA_UNITS aUnits)
SEARCH_STACK looks for files in a number of places.
Definition: search_stack.h:41
Dialog helper object to sit in the inheritance tree between wxDialog and any class written by wxFormB...
Definition: dialog_shim.h:83
wxAuiManager m_auimgr
bool IsWritable(const wxFileName &aFileName)
Checks if aFileName can be written.
This class implements a file history object to store a list of files, that can then be added to a men...
Definition: filehistory.h:42
wxTimer * m_autoSaveTimer
void ClearFileHistory()
Clear all entries from the file history.
virtual void CommonSettingsChanged(bool aEnvVarsChanged)
Notification event that some of the common (suite-wide) settings have changed.
void UpdateFileHistory(const wxString &FullFileName, FILE_HISTORY *aFileHistory=nullptr)
Update the list of recently opened files.
wxString m_perspective
wxSize m_NormalFrameSize
#define SCREEN_BORDER_REGION
wxString GetFileFromHistory(int cmdId, const wxString &type, FILE_HISTORY *aFileHistory=nullptr)
Fetches the file name from the file history list.
wxTreebook * GetTreebook()
Definition: paged_dialog.h:45
void AddFileToHistory(const wxString &aFile) override
Adds a file to the history.
Definition: filehistory.cpp:94
SEARCH_STACK & KifaceSearch()
Only for DSO specific 'non-library' files.
Definition: kiface_i.h:127
wxWindow * findQuasiModalDialog()
Stores the common settings that are saved and loaded for each window / frame.
Definition: app_settings.h:68
const wxString & GetHelpFileName() const
Function GetHelpFileName returns just the basename portion of the current help file.
Definition: kiface_i.h:123
void ShowAboutDialog(EDA_BASE_FRAME *aParent)
virtual void OnCharHook(wxKeyEvent &event)
Capture the key event before it is sent to the GUI.
wxString perspective
Definition: app_settings.h:74
const BITMAP_OPAQUE about_xpm[1]
Definition: about.cpp:84
void CheckForAutoSaveFile(const wxFileName &aFileName)
Check if an auto save file exists for aFileName and takes the appropriate action depending on the use...
APP_SETTINGS_BASE is a settings class that should be derived for each standalone KiCad application.
Definition: app_settings.h:91
VTBL_ENTRY KIWAY_PLAYER * Player(FRAME_T aFrameType, bool doCreate=true, wxTopLevelWindow *aParent=NULL)
Function Player returns the KIWAY_PLAYER* given a FRAME_T.
Definition: kiway.cpp:342
wxString dump(const wxArrayString &aArray)
Debug helper for printing wxArrayString contents.
virtual void unitsChangeRefresh()
Called when when the units setting has changed to allow for any derived classes to handle refreshing ...
virtual const SEARCH_STACK & sys_search()
Return a SEARCH_STACK pertaining to entire program.
virtual void DispatchWxEvent(wxEvent &aEvent)
Function DispatchWxEvent() Processes wxEvents (mostly UI events), translates them to TOOL_EVENTs,...
KIFACE_I & Kiface()
Global KIFACE_I "get" accessor.
void AddStandardHelpMenu(wxMenuBar *aMenuBar)
Adds the standard KiCad help menu to the menubar.
bool IsQuasiModal()
Definition: dialog_shim.h:123
virtual WINDOW_SETTINGS * GetWindowSettings(APP_SETTINGS_BASE *aCfg)
Returns a pointer to the window settings for this frame.
KIWAY is a minimalistic software bus for communications between various DLLs/DSOs (DSOs) within the s...
Definition: kiway.h:273
wxLogTrace helper definitions.
void OnKicadAbout(wxCommandEvent &event)
COMMON_CONTROL.
void LoadWindowSettings(WINDOW_SETTINGS *aCfg)
Loads window settings from the given settings object Normally called by LoadSettings unless the windo...
wxDEFINE_EVENT(UNITS_CHANGED, wxCommandEvent)
TOOL_DISPATCHER * m_toolDispatcher
Definition: tools_holder.h:50
void ClearFileHistory(FILE_HISTORY *aFileHistory=nullptr)
Removes all files from the file history.
bool SupportsShutdownBlockReason()
Whether or not the window supports setting a shutdown block reason.
void RemoveShutdownBlockReason()
Removes any shutdown block reason set.
virtual void OnMove(wxMoveEvent &aEvent)
static wxString GetAutoSaveFilePrefix()
WINDOW_SETTINGS m_Window
Definition: app_settings.h:153
void SetMaxFiles(size_t aMaxFiles)
Update the number of files that will be contained inside the file history.
Definition: filehistory.cpp:83
void OnMaximize(wxMaximizeEvent &aEvent)
void SetAutoSaveInterval(int aInterval)
TOOL_MANAGER * m_toolManager
Definition: tools_holder.h:48
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:153
wxSize GetWindowSize()
Get the undecorated window size that can be used for restoring the window size.
see class PGM_BASE
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
wxString ConfigBaseName() override
#define KICAD_MANAGER_FRAME_NAME
#define _(s)
Definition: 3d_actions.cpp:33
The base frame for deriving all KiCad main window classes.
static TOOL_ACTION help
Definition: actions.h:171
const wxChar *const kicadTraceKeyEvent
Flag to enable wxKeyEvent debug tracing.
virtual wxString help_name()
void OnPreferences(wxCommandEvent &event)
void SetUserUnits(EDA_UNITS aUnits)
Definition: id.h:87
static const int s_minsize_x
virtual void InstallPreferences(PAGED_DIALOG *, PANEL_HOTKEYS_EDITOR *)
Function InstallPreferences Allow a frame to load its preference panels (if any) into the preferences...
static const int s_minsize_y
static TOOL_ACTION getInvolved
Definition: actions.h:173
virtual void ShowChangedLanguage()
Redraw the menus and what not in current language.
static TOOL_ACTION gettingStarted
Definition: actions.h:170
virtual wxString GetCurrentFileName() const
Get the full filename + path of the currently opened file in the frame.
bool ProcessEvent(wxEvent &aEvent) override
Override the default process event handler to implement the auto save feature.
FILE_HISTORY * m_fileHistory
wxPoint m_NormalFramePos
void OnMenuEvent(wxMenuEvent &event)
The TOOL_DISPATCHER needs these to work around some issues in wxWidgets where the menu events aren't ...
virtual void LoadSettings(APP_SETTINGS_BASE *aCfg)
Load common frame parameters from a configuration file.
virtual void ReCreateMenuBar()
Recreates the menu bar.