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-2020 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 <pgm_base.h>
41 #include <tool/action_manager.h>
42 #include <tool/action_menu.h>
43 #include <tool/actions.h>
44 #include <tool/common_control.h>
45 #include <tool/tool_manager.h>
46 #include <tool/tool_dispatcher.h>
47 #include <trace_helpers.h>
48 #include <widgets/paged_dialog.h>
49 #include <widgets/infobar.h>
51 #include <wx/display.h>
52 #include <wx/stdpaths.h>
53 #include <wx/string.h>
54 #include <kiplatform/app.h>
55 
56 #include <functional>
57 
58 wxDEFINE_EVENT( UNITS_CHANGED, wxCommandEvent );
59 
60 
61 // Minimum window size
62 static const int s_minsize_x = 500;
63 static const int s_minsize_y = 400;
64 
65 static const int s_defaultSize_x = 1280;
66 static const int s_defaultSize_y = 720;
67 
68 
69 BEGIN_EVENT_TABLE( EDA_BASE_FRAME, wxFrame )
70  EVT_MENU( wxID_ABOUT, EDA_BASE_FRAME::OnKicadAbout )
71  EVT_MENU( wxID_PREFERENCES, EDA_BASE_FRAME::OnPreferences )
72 
73  EVT_CHAR_HOOK( EDA_BASE_FRAME::OnCharHook )
74  EVT_MENU_OPEN( EDA_BASE_FRAME::OnMenuEvent )
75  EVT_MENU_CLOSE( EDA_BASE_FRAME::OnMenuEvent )
76  EVT_MENU_HIGHLIGHT_ALL( EDA_BASE_FRAME::OnMenuEvent )
77  EVT_MOVE( EDA_BASE_FRAME::OnMove )
78  EVT_MAXIMIZE( EDA_BASE_FRAME::OnMaximize )
79 END_EVENT_TABLE()
80 
81 EDA_BASE_FRAME::EDA_BASE_FRAME( wxWindow* aParent, FRAME_T aFrameType,
82  const wxString& aTitle, const wxPoint& aPos, const wxSize& aSize,
83  long aStyle, const wxString& aFrameName, KIWAY* aKiway ) :
84  wxFrame( aParent, wxID_ANY, aTitle, aPos, aSize, aStyle, aFrameName ),
85  TOOLS_HOLDER(),
86  KIWAY_HOLDER( aKiway, KIWAY_HOLDER::FRAME ),
87  m_Ident( aFrameType ),
88  m_maximizeByDefault( false ),
89  m_infoBar( nullptr ),
90  m_settingsManager( nullptr ),
91  m_fileHistory( nullptr ),
92  m_hasAutoSave( false ),
93  m_autoSaveState( false ),
94  m_autoSaveInterval(-1 ),
95  m_UndoRedoCountMax( DEFAULT_MAX_UNDO_ITEMS ),
96  m_userUnits( EDA_UNITS::MILLIMETRES ),
97  m_isClosing( false ),
98  m_isNonUserClose( false )
99 {
100  m_autoSaveTimer = new wxTimer( this, ID_AUTO_SAVE_TIMER );
101  m_mruPath = wxStandardPaths::Get().GetDocumentsDir();
102  m_FrameSize = wxSize( s_defaultSize_x, s_defaultSize_y );
103 
104  m_auimgr.SetArtProvider( new WX_AUI_DOCK_ART() );
105 
106  m_settingsManager = &Pgm().GetSettingsManager();
107 
108  // Set a reasonable minimal size for the frame
109  SetSizeHints( s_minsize_x, s_minsize_y, -1, -1, -1, -1 );
110 
111  // Store dimensions of the user area of the main window.
112  GetClientSize( &m_FrameSize.x, &m_FrameSize.y );
113 
114  Connect( ID_AUTO_SAVE_TIMER, wxEVT_TIMER,
115  wxTimerEventHandler( EDA_BASE_FRAME::onAutoSaveTimer ) );
116 
117  // hook wxEVT_CLOSE_WINDOW so we can call SaveSettings(). This function seems
118  // to be called before any other hook for wxCloseEvent, which is necessary.
119  Connect( wxEVT_CLOSE_WINDOW, wxCloseEventHandler( EDA_BASE_FRAME::windowClosing ) );
120 }
121 
122 
124 {
125  for( auto& iter : GetChildren() )
126  {
127  DIALOG_SHIM* dlg = dynamic_cast<DIALOG_SHIM*>( iter );
128  if( dlg && dlg->IsQuasiModal() )
129  return dlg;
130  }
131 
132  // FIXME: CvPcb is currently implemented on top of KIWAY_PLAYER rather than DIALOG_SHIM,
133  // so we have to look for it separately.
134  if( m_Ident == FRAME_SCH )
135  {
136  wxWindow* cvpcb = wxWindow::FindWindowByName( "CvpcbFrame" );
137  if( cvpcb )
138  return cvpcb;
139  }
140 
141  return nullptr;
142 }
143 
144 
145 void EDA_BASE_FRAME::windowClosing( wxCloseEvent& event )
146 {
147  // Don't allow closing when a quasi-modal is open.
148  wxWindow* quasiModal = findQuasiModalDialog();
149 
150  if( quasiModal )
151  {
152  // Raise and notify; don't give the user a warning regarding "quasi-modal dialogs"
153  // when they have no idea what those are.
154  quasiModal->Raise();
155  wxBell();
156 
157  if( event.CanVeto() )
158  event.Veto();
159 
160  return;
161  }
162 
163 
164  if( event.GetId() == wxEVT_QUERY_END_SESSION
165  || event.GetId() == wxEVT_END_SESSION )
166  {
167  // End session means the OS is going to terminate us
168  m_isNonUserClose = true;
169  }
170 
171  if( canCloseWindow( event ) )
172  {
173  m_isClosing = true;
174  APP_SETTINGS_BASE* cfg = config();
175 
176  if( cfg )
177  SaveSettings( cfg ); // virtual, wxFrame specific
178 
179  doCloseWindow();
180 
181  // Destroy (safe delete frame) this frame only in non modal mode.
182  // In modal mode, the caller will call Destroy().
183  if( !IsModal() )
184  Destroy();
185  }
186  else
187  {
188  if( event.CanVeto() )
189  event.Veto();
190  }
191 }
192 
193 
195 {
196  delete m_autoSaveTimer;
197  delete m_fileHistory;
198 
200 
202 }
203 
204 
205 bool EDA_BASE_FRAME::ProcessEvent( wxEvent& aEvent )
206 {
207 #ifdef __WXMAC__
208  // Apple in its infinite wisdom will raise a disabled window before even passing
209  // us the event, so we have no way to stop it. Instead, we have to catch an
210  // improperly ordered disabled window and quasi-modal dialog here and reorder
211  // them.
212  if( !IsEnabled() && IsActive() )
213  {
214  wxWindow* dlg = findQuasiModalDialog();
215  if( dlg )
216  dlg->Raise();
217  }
218 #endif
219 
220  if( !wxFrame::ProcessEvent( aEvent ) )
221  return false;
222 
223  if( IsShown() && m_hasAutoSave && IsActive() &&
225  {
226  if( !m_autoSaveState )
227  {
228  wxLogTrace( traceAutoSave, wxT( "Starting auto save timer." ) );
229  m_autoSaveTimer->Start( m_autoSaveInterval * 1000, wxTIMER_ONE_SHOT );
230  m_autoSaveState = true;
231  }
232  else if( m_autoSaveTimer->IsRunning() )
233  {
234  wxLogTrace( traceAutoSave, wxT( "Stopping auto save timer." ) );
235  m_autoSaveTimer->Stop();
236  m_autoSaveState = false;
237  }
238  }
239 
240  return true;
241 }
242 
243 
245 {
246  m_autoSaveInterval = aInterval;
247 
248  if( m_autoSaveTimer->IsRunning() )
249  {
250  if( m_autoSaveInterval > 0 )
251  {
252  m_autoSaveTimer->Start( m_autoSaveInterval * 1000, wxTIMER_ONE_SHOT );
253  }
254  else
255  {
256  m_autoSaveTimer->Stop();
257  m_autoSaveState = false;
258  }
259  }
260 }
261 
262 
263 void EDA_BASE_FRAME::onAutoSaveTimer( wxTimerEvent& aEvent )
264 {
265  if( !doAutoSave() )
266  m_autoSaveTimer->Start( m_autoSaveInterval * 1000, wxTIMER_ONE_SHOT );
267 }
268 
269 
271 {
272  wxCHECK_MSG( false, true, wxT( "Auto save timer function not overridden. Bad programmer!" ) );
273 }
274 
275 
276 void EDA_BASE_FRAME::OnCharHook( wxKeyEvent& event )
277 {
278  wxLogTrace( kicadTraceKeyEvent, "EDA_BASE_FRAME::OnCharHook %s", dump( event ) );
279  // Key events can be filtered here.
280  // Currently no filtering is made.
281  event.Skip();
282 }
283 
284 
285 void EDA_BASE_FRAME::OnMenuEvent( wxMenuEvent& aEvent )
286 {
287  if( !m_toolDispatcher )
288  aEvent.Skip();
289  else
291 }
292 
293 
295 {
297  std::placeholders::_1,
298  this,
299  aConditions );
300 
301  m_uiUpdateMap[aID] = evtFunc;
302 
303  Bind( wxEVT_UPDATE_UI, evtFunc, aID );
304 }
305 
306 
308 {
309  const auto it = m_uiUpdateMap.find( aID );
310 
311  if( it == m_uiUpdateMap.end() )
312  return;
313 
314  Unbind( wxEVT_UPDATE_UI, it->second, aID );
315 }
316 
317 
318 void EDA_BASE_FRAME::HandleUpdateUIEvent( wxUpdateUIEvent& aEvent, EDA_BASE_FRAME* aFrame,
319  ACTION_CONDITIONS aCond )
320 {
321  bool checkRes = false;
322  bool enableRes = true;
323  bool showRes = true;
324  SELECTION& selection = aFrame->GetCurrentSelection();
325 
326  try
327  {
328  checkRes = aCond.checkCondition( selection );
329  enableRes = aCond.enableCondition( selection );
330  showRes = aCond.showCondition( selection );
331  }
332  catch( std::exception& )
333  {
334  // Something broke with the conditions, just skip the event.
335  aEvent.Skip();
336  return;
337  }
338 
339  aEvent.Enable( enableRes );
340  aEvent.Show( showRes );
341 
342  bool canCheck = true;
343 
344  // wxMenuItems don't want to be checked unless they actually are checkable, so we have to check to
345  // see if they can be and can't just universally apply a check in this event.
346  if( auto menu = dynamic_cast<wxMenu*>( aEvent.GetEventObject() ) )
347  canCheck = menu->FindItem( aEvent.GetId() )->IsCheckable();
348 
349  if( canCheck )
350  aEvent.Check( checkRes );
351 }
352 
353 
355 {
356  // Setup the conditions to check a language menu item
357  auto isCurrentLang =
358  [] ( const SELECTION& aSel, int aLangIdentifier )
359  {
360  return Pgm().GetSelectedLanguageIdentifier() == aLangIdentifier;
361  };
362 
363  for( unsigned ii = 0; LanguagesList[ii].m_KI_Lang_Identifier != 0; ii++ )
364  {
365  ACTION_CONDITIONS cond;
366  cond.Check( std::bind( isCurrentLang, std::placeholders::_1,
367  LanguagesList[ii].m_WX_Lang_Identifier ) );
368 
369  RegisterUIUpdateHandler( LanguagesList[ii].m_KI_Lang_Identifier, cond );
370  }
371 }
372 
373 
375 {
376 }
377 
378 
379 void EDA_BASE_FRAME::AddStandardHelpMenu( wxMenuBar* aMenuBar )
380 {
381  COMMON_CONTROL* commonControl = m_toolManager->GetTool<COMMON_CONTROL>();
382  ACTION_MENU* helpMenu = new ACTION_MENU( false, commonControl );
383 
384  helpMenu->Add( ACTIONS::help );
385  helpMenu->Add( ACTIONS::gettingStarted );
386  helpMenu->Add( ACTIONS::listHotKeys );
387  helpMenu->Add( ACTIONS::getInvolved );
388  helpMenu->Add( ACTIONS::reportBug );
389 
390  helpMenu->AppendSeparator();
391  helpMenu->Add( _( "&About KiCad" ), "", wxID_ABOUT, about_xpm );
392 
393  aMenuBar->Append( helpMenu, _( "&Help" ) );
394 }
395 
396 
398 {
399  if( GetMenuBar() )
400  {
401  ReCreateMenuBar();
402  GetMenuBar()->Refresh();
403  }
404 }
405 
406 
407 void EDA_BASE_FRAME::CommonSettingsChanged( bool aEnvVarsChanged, bool aTextVarsChanged )
408 {
409  TOOLS_HOLDER::CommonSettingsChanged( aEnvVarsChanged, aTextVarsChanged );
410 
411  COMMON_SETTINGS* settings = Pgm().GetCommonSettings();
412 
413  if( m_fileHistory )
414  {
415  int historySize = settings->m_System.file_history_size;
416  m_fileHistory->SetMaxFiles( (unsigned) std::max( 0, historySize ) );
417  }
418 
419  if( GetMenuBar() )
420  {
421  // For icons in menus, icon scaling & hotkeys
422  ReCreateMenuBar();
423  GetMenuBar()->Refresh();
424  }
425 }
426 
427 
428 void EDA_BASE_FRAME::LoadWindowState( const wxString& aFileName )
429 {
430  if( !Pgm().GetCommonSettings()->m_Session.remember_open_files )
431  return;
432 
433  const PROJECT_FILE_STATE* state = Prj().GetLocalSettings().GetFileState( aFileName );
434 
435  if( state != nullptr )
436  {
437  LoadWindowState( state->window );
438  }
439 }
440 
441 
443 {
444  bool wasDefault = false;
445 
446  m_FramePos.x = aState.pos_x;
447  m_FramePos.y = aState.pos_y;
448  m_FrameSize.x = aState.size_x;
449  m_FrameSize.y = aState.size_y;
450 
451  wxLogTrace( traceDisplayLocation, "Config position (%d, %d) with size (%d, %d)",
453 
454  // Ensure minimum size is set if the stored config was zero-initialized
456  {
459  wasDefault = true;
460 
461  wxLogTrace( traceDisplayLocation, "Using minimum size (%d, %d)", m_FrameSize.x, m_FrameSize.y );
462  }
463 
464  wxLogTrace( traceDisplayLocation, "Number of displays: %d", wxDisplay::GetCount() );
465 
466  if( aState.display >= wxDisplay::GetCount() )
467  {
468  wxLogTrace( traceDisplayLocation, "Previous display not found" );
469 
470  // If it isn't attached, use the first display
471  // Warning wxDisplay has 2 ctor variants. the parameter needs a type:
472  const unsigned int index = 0;
473  wxDisplay display( index );
474  wxRect clientSize = display.GetGeometry();
475 
476  m_FramePos = wxDefaultPosition;
477 
478  // Ensure the window fits on the display, since the other one could have been larger
479  if( m_FrameSize.x > clientSize.width )
480  m_FrameSize.x = clientSize.width;
481 
482  if( m_FrameSize.y > clientSize.height )
483  m_FrameSize.y = clientSize.height;
484  }
485  else
486  {
487  wxPoint upperRight( m_FramePos.x + m_FrameSize.x, m_FramePos.y );
488  wxPoint upperLeft( m_FramePos.x, m_FramePos.y );
489 
490  wxDisplay display( aState.display );
491  wxRect clientSize = display.GetClientArea();
492 
493  // The percentage size (represented in decimal) of the region around the screen's border where
494  // an upper corner is not allowed
495 #define SCREEN_BORDER_REGION 0.10
496 
497  int yLim = clientSize.y + ( clientSize.height * ( 1.0 - SCREEN_BORDER_REGION ) );
498  int xLimLeft = clientSize.x + ( clientSize.width * SCREEN_BORDER_REGION );
499  int xLimRight = clientSize.x + ( clientSize.width * ( 1.0 - SCREEN_BORDER_REGION ) );
500 
501  if( upperLeft.x > xLimRight || // Upper left corner too close to right edge of screen
502  upperRight.x < xLimLeft || // Upper right corner too close to left edge of screen
503  upperRight.y > yLim ) // Upper corner too close to the bottom of the screen
504  {
505  m_FramePos = wxDefaultPosition;
506  wxLogTrace( traceDisplayLocation, "Resetting to default position" );
507  }
508  }
509 
510  // Ensure Window title bar is visible
511 #if defined( __WXOSX__ )
512  // for macOSX, the window must be below system (macOSX) toolbar
513  int Ypos_min = 20;
514 #else
515  int Ypos_min = 0;
516 #endif
517  if( m_FramePos.y < Ypos_min )
518  m_FramePos.y = Ypos_min;
519 
520  wxLogTrace( traceDisplayLocation, "Final window position (%d, %d) with size (%d, %d)",
522 
523  SetSize( m_FramePos.x, m_FramePos.y, m_FrameSize.x, m_FrameSize.y );
524 
525  // Center the window if we reset to default
526  if( m_FramePos.x == -1 )
527  {
528  wxLogTrace( traceDisplayLocation, "Centering window" );
529  Center();
530  m_FramePos = GetPosition();
531  }
532 
533  // Record the frame sizes in an un-maximized state
536 
537  // Maximize if we were maximized before
538  if( aState.maximized || ( wasDefault && m_maximizeByDefault ) )
539  {
540  wxLogTrace( traceDisplayLocation, "Maximizing window" );
541  Maximize();
542  }
543 }
544 
545 
547 {
548  LoadWindowState( aCfg->state );
549 
550  if( m_hasAutoSave )
551  m_autoSaveInterval = Pgm().GetCommonSettings()->m_System.autosave_interval;
552 
553  m_perspective = aCfg->perspective;
554  m_mruPath = aCfg->mru_path;
555 
556  TOOLS_HOLDER::CommonSettingsChanged( false, false );
557 }
558 
559 
561 {
562  wxString text;
563 
564  if( IsIconized() )
565  return;
566 
567  wxString baseCfgName = ConfigBaseName();
568 
569  // If the window is maximized, we use the saved window size from before it was maximized
570  if( IsMaximized() )
571  {
574  }
575  else
576  {
578  m_FramePos = GetPosition();
579  }
580 
581  aCfg->state.pos_x = m_FramePos.x;
582  aCfg->state.pos_y = m_FramePos.y;
583  aCfg->state.size_x = m_FrameSize.x;
584  aCfg->state.size_y = m_FrameSize.y;
585  aCfg->state.maximized = IsMaximized();
586  aCfg->state.display = wxDisplay::GetFromWindow( this );
587 
588  wxLogTrace( traceDisplayLocation, "Saving window maximized: %s", IsMaximized() ? "true" : "false" );
589  wxLogTrace( traceDisplayLocation, "Saving config position (%d, %d) with size (%d, %d)",
591 
592  // TODO(JE) should auto-save in common settings be overwritten by every app?
593  if( m_hasAutoSave )
594  Pgm().GetCommonSettings()->m_System.autosave_interval = m_autoSaveInterval;
595 
596  // Once this is fully implemented, wxAuiManager will be used to maintain
597  // the persistance of the main frame and all it's managed windows and
598  // all of the legacy frame persistence position code can be removed.
599  aCfg->perspective = m_auimgr.SavePerspective().ToStdString();
600 
601  aCfg->mru_path = m_mruPath;
602 }
603 
604 
606 {
608 
609  // Get file history size from common settings
610  int fileHistorySize = Pgm().GetCommonSettings()->m_System.file_history_size;
611 
612  // Load the recently used files into the history menu
613  m_fileHistory = new FILE_HISTORY( (unsigned) std::max( 0, fileHistorySize ),
615  m_fileHistory->Load( *aCfg );
616 }
617 
618 
620 {
622 
623  bool fileOpen = m_isClosing && m_isNonUserClose;
624 
625  wxString currentlyOpenedFile = GetCurrentFileName();
626 
627  if( Pgm().GetCommonSettings()->m_Session.remember_open_files && !currentlyOpenedFile.IsEmpty() )
628  {
629  wxFileName rfn( currentlyOpenedFile );
630  rfn.MakeRelativeTo( Prj().GetProjectPath() );
631  Prj().GetLocalSettings().SaveFileState( rfn.GetFullPath(), &aCfg->m_Window, fileOpen );
632  }
633 
634  // Save the recently used files list
635  if( m_fileHistory )
636  {
637  // Save the currently opened file in the file history
638  if( !currentlyOpenedFile.IsEmpty() )
639  UpdateFileHistory( currentlyOpenedFile );
640 
641  m_fileHistory->Save( *aCfg );
642  }
643 }
644 
645 
647 {
648  return &aCfg->m_Window;
649 }
650 
651 
653 {
654  // KICAD_MANAGER_FRAME overrides this
655  return Kiface().KifaceSettings();
656 }
657 
658 
660 {
661  return Kiface().KifaceSearch();
662 }
663 
664 
666 {
667  return Kiface().GetHelpFileName();
668 }
669 
670 
671 void EDA_BASE_FRAME::PrintMsg( const wxString& text )
672 {
673  SetStatusText( text );
674 }
675 
676 
677 void EDA_BASE_FRAME::ShowInfoBarError( const wxString& aErrorMsg )
678 {
680  GetInfoBar()->ShowMessageFor( aErrorMsg, 5000, wxICON_ERROR );
681 }
682 
683 
684 void EDA_BASE_FRAME::ShowInfoBarWarning( const wxString& aWarningMsg )
685 {
687  GetInfoBar()->ShowMessageFor( aWarningMsg, 5000, wxICON_WARNING );
688 }
689 
690 
691 void EDA_BASE_FRAME::ShowInfoBarMsg( const wxString& aMsg )
692 {
694  GetInfoBar()->ShowMessageFor( aMsg, 10000, wxICON_INFORMATION );
695 }
696 
697 
698 void EDA_BASE_FRAME::UpdateFileHistory( const wxString& FullFileName, FILE_HISTORY* aFileHistory )
699 {
700  if( !aFileHistory )
701  aFileHistory = m_fileHistory;
702 
703  wxASSERT( aFileHistory );
704 
705  aFileHistory->AddFileToHistory( FullFileName );
706 
707  // Update the menubar to update the file history menu
708  if( !m_isClosing && GetMenuBar() )
709  {
710  ReCreateMenuBar();
711  GetMenuBar()->Refresh();
712  }
713 }
714 
715 
716 wxString EDA_BASE_FRAME::GetFileFromHistory( int cmdId, const wxString& type,
717  FILE_HISTORY* aFileHistory )
718 {
719  if( !aFileHistory )
720  aFileHistory = m_fileHistory;
721 
722  wxASSERT( aFileHistory );
723 
724  int baseId = aFileHistory->GetBaseId();
725 
726  wxASSERT( cmdId >= baseId && cmdId < baseId + (int) aFileHistory->GetCount() );
727 
728  unsigned i = cmdId - baseId;
729 
730  if( i < aFileHistory->GetCount() )
731  {
732  wxString fn = aFileHistory->GetHistoryFile( i );
733 
734  if( wxFileName::FileExists( fn ) )
735  return fn;
736  else
737  {
738  wxString msg = wxString::Format( _( "File \"%s\" was not found." ), fn );
739  wxMessageBox( msg );
740 
741  aFileHistory->RemoveFileFromHistory( i );
742  }
743  }
744 
745  // Update the menubar to update the file history menu
746  if( GetMenuBar() )
747  {
748  ReCreateMenuBar();
749  GetMenuBar()->Refresh();
750  }
751 
752  return wxEmptyString;
753 }
754 
755 
757 {
758  if( !aFileHistory )
759  aFileHistory = m_fileHistory;
760 
761  wxASSERT( aFileHistory );
762 
763  aFileHistory->ClearFileHistory();
764 
765  // Update the menubar to update the file history menu
766  if( GetMenuBar() )
767  {
768  ReCreateMenuBar();
769  GetMenuBar()->Refresh();
770  }
771 }
772 
773 
774 void EDA_BASE_FRAME::OnKicadAbout( wxCommandEvent& event )
775 {
776  void ShowAboutDialog(EDA_BASE_FRAME * aParent); // See AboutDialog_main.cpp
777  ShowAboutDialog( this );
778 }
779 
780 
781 void EDA_BASE_FRAME::OnPreferences( wxCommandEvent& event )
782 {
783  PAGED_DIALOG dlg( this, _( "Preferences" ), true );
784  wxTreebook* book = dlg.GetTreebook();
785 
786  book->AddPage( new PANEL_COMMON_SETTINGS( &dlg, book ), _( "Common" ) );
787 
788  book->AddPage( new PANEL_MOUSE_SETTINGS( &dlg, book ), _( "Mouse and Touchpad" ) );
789 
790  PANEL_HOTKEYS_EDITOR* hotkeysPanel = new PANEL_HOTKEYS_EDITOR( this, book, false );
791  book->AddPage( hotkeysPanel, _( "Hotkeys" ) );
792 
793  for( unsigned i = 0; i < KIWAY_PLAYER_COUNT; ++i )
794  {
795  KIWAY_PLAYER* frame = dlg.Kiway().Player( (FRAME_T) i, false );
796 
797  if( frame )
798  frame->InstallPreferences( &dlg, hotkeysPanel );
799  }
800 
801  // The Kicad manager frame is not a player so we have to add it by hand
802  wxWindow* manager = wxFindWindowByName( KICAD_MANAGER_FRAME_NAME );
803 
804  if( manager )
805  static_cast<EDA_BASE_FRAME*>( manager )->InstallPreferences( &dlg, hotkeysPanel );
806 
807  for( size_t i = 0; i < book->GetPageCount(); ++i )
808  book->GetPage( i )->Layout();
809 
810  if( dlg.ShowModal() == wxID_OK )
811  dlg.Kiway().CommonSettingsChanged( false, false );
812 }
813 
814 
815 bool EDA_BASE_FRAME::IsWritable( const wxFileName& aFileName )
816 {
817  wxString msg;
818  wxFileName fn = aFileName;
819 
820  // Check for absence of a file path with a file name. Unfortunately KiCad
821  // uses paths relative to the current project path without the ./ part which
822  // confuses wxFileName. Making the file name path absolute may be less than
823  // elegant but it solves the problem.
824  if( fn.GetPath().IsEmpty() && fn.HasName() )
825  fn.MakeAbsolute();
826 
827  wxCHECK_MSG( fn.IsOk(), false,
828  wxT( "File name object is invalid. Bad programmer!" ) );
829  wxCHECK_MSG( !fn.GetPath().IsEmpty(), false,
830  wxT( "File name object path <" ) + fn.GetFullPath() +
831  wxT( "> is not set. Bad programmer!" ) );
832 
833  if( fn.IsDir() && !fn.IsDirWritable() )
834  {
835  msg.Printf( _( "You do not have write permissions to folder \"%s\"." ),
836  fn.GetPath() );
837  }
838  else if( !fn.FileExists() && !fn.IsDirWritable() )
839  {
840  msg.Printf( _( "You do not have write permissions to save file \"%s\" to folder \"%s\"." ),
841  fn.GetFullName(), fn.GetPath() );
842  }
843  else if( fn.FileExists() && !fn.IsFileWritable() )
844  {
845  msg.Printf( _( "You do not have write permissions to save file \"%s\"." ),
846  fn.GetFullPath() );
847  }
848 
849  if( !msg.IsEmpty() )
850  {
851  wxMessageBox( msg );
852  return false;
853  }
854 
855  return true;
856 }
857 
858 
859 void EDA_BASE_FRAME::CheckForAutoSaveFile( const wxFileName& aFileName )
860 {
861  wxCHECK_RET( aFileName.IsOk(), wxT( "Invalid file name!" ) );
862 
863  wxFileName autoSaveFileName = aFileName;
864 
865  // Check for auto save file.
866  autoSaveFileName.SetName( GetAutoSaveFilePrefix() + aFileName.GetName() );
867 
868  wxLogTrace( traceAutoSave,
869  wxT( "Checking for auto save file " ) + autoSaveFileName.GetFullPath() );
870 
871  if( !autoSaveFileName.FileExists() )
872  return;
873 
874  wxString msg = wxString::Format( _(
875  "Well this is potentially embarrassing!\n"
876  "It appears that the last time you were editing the file\n"
877  "\"%s\"\n"
878  "it was not saved properly. Do you wish to restore the last saved edits you made?" ),
879  aFileName.GetFullName()
880  );
881 
882  int response = wxMessageBox( msg, Pgm().App().GetAppName(), wxYES_NO | wxICON_QUESTION, this );
883 
884  // Make a backup of the current file, delete the file, and rename the auto save file to
885  // the file name.
886  if( response == wxYES )
887  {
888  if( !wxRenameFile( autoSaveFileName.GetFullPath(), aFileName.GetFullPath() ) )
889  {
890  wxMessageBox( _( "The auto save file could not be renamed to the board file name." ),
891  Pgm().App().GetAppName(), wxOK | wxICON_EXCLAMATION, this );
892  }
893  }
894  else
895  {
896  wxLogTrace( traceAutoSave,
897  wxT( "Removing auto save file " ) + autoSaveFileName.GetFullPath() );
898 
899  // Remove the auto save file when using the previous file as is.
900  wxRemoveFile( autoSaveFileName.GetFullPath() );
901  }
902 }
903 
904 
906 {
907  // This function should be overridden in child classes
908  return false;
909 }
910 
911 
913 {
916 }
917 
918 
920 {
921  m_undoList.PushCommand( aNewitem );
922 
923  // Delete the extra items, if count max reached
924  if( m_UndoRedoCountMax > 0 )
925  {
926  int extraitems = GetUndoCommandCount() - m_UndoRedoCountMax;
927 
928  if( extraitems > 0 )
929  ClearUndoORRedoList( UNDO_LIST, extraitems );
930  }
931 }
932 
933 
935 {
936  m_redoList.PushCommand( aNewitem );
937 
938  // Delete the extra items, if count max reached
939  if( m_UndoRedoCountMax > 0 )
940  {
941  int extraitems = GetRedoCommandCount() - m_UndoRedoCountMax;
942 
943  if( extraitems > 0 )
944  ClearUndoORRedoList( REDO_LIST, extraitems );
945  }
946 }
947 
948 
950 {
951  return m_undoList.PopCommand();
952 }
953 
954 
956 {
957  return m_redoList.PopCommand();
958 }
959 
960 
962 {
963  SetUserUnits( aUnits );
965 
966  wxCommandEvent e( UNITS_CHANGED );
967  ProcessEventLocally( e );
968 }
969 
970 
971 void EDA_BASE_FRAME::OnMaximize( wxMaximizeEvent& aEvent )
972 {
973  // When we maximize the window, we want to save the old information
974  // so that we can add it to the settings on next window load.
975  // Contrary to the documentation, this event seems to be generated
976  // when the window is also being unmaximized on OSX, so we only
977  // capture the size information when we maximize the window when on OSX.
978 #ifdef __WXOSX__
979  if( !IsMaximized() )
980 #endif
981  {
983  m_NormalFramePos = GetPosition();
984  wxLogTrace( traceDisplayLocation, "Maximizing window - Saving position (%d, %d) with size (%d, %d)",
986  }
987 
988  // Skip event to actually maximize the window
989  aEvent.Skip();
990 }
991 
992 
994 {
995 #ifdef __WXGTK__
996  // GTK includes the window decorations in the normal GetSize call,
997  // so we have to use a GTK-specific sizing call that returns the
998  // non-decorated window size.
999  int width = 0;
1000  int height = 0;
1001  GTKDoGetSize( &width, &height );
1002 
1003  wxSize winSize( width, height );
1004 #else
1005  wxSize winSize = GetSize();
1006 #endif
1007 
1008  return winSize;
1009 }
SELECTION_CONDITION showCondition
Returns true if the UI control should be shown.
void ShowMessageFor(const wxString &aMessage, int aTime, int aFlags=wxICON_INFORMATION)
Show the infobar with the provided message and icon for a specific period of time.
Definition: infobar.cpp:109
wxString mru_path
Definition: app_settings.h:84
static TOOL_ACTION listHotKeys
Definition: actions.h:177
LANGUAGE_DESCR LanguagesList[]
An array containing all the languages that KiCad supports.
Definition: pgm_base.cpp:71
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:61
static const int s_defaultSize_x
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
void SaveFileState(const wxString &aFileName, const WINDOW_SETTINGS *aWindowCfg, bool aOpen)
wxString m_mruPath
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.
Defines the structure of a menu based on ACTIONs.
Definition: action_menu.h:43
void SaveWindowSettings(WINDOW_SETTINGS *aCfg)
Saves window settings to the given settings object Normally called by SaveSettings unless the window ...
VTBL_ENTRY PROJECT_LOCAL_SETTINGS & GetLocalSettings() const
Definition: project.h:149
UNDO_REDO_CONTAINER m_undoList
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
SELECTION_CONDITION enableCondition
Returns true if the UI control should be enabled.
void windowClosing(wxCloseEvent &event)
(with its unexpected name so it does not collide with the real OnWindowClose() function provided in d...
virtual void PushCommandToRedoList(PICKED_ITEMS_LIST *aItem)
Function PushCommandToRedoList add a command to redo in redo list delete the very old commands when t...
static const int s_defaultSize_y
SELECTION_CONDITION checkCondition
Returns true if the UI control should be checked.
static void HandleUpdateUIEvent(wxUpdateUIEvent &aEvent, EDA_BASE_FRAME *aFrame, ACTION_CONDITIONS aCond)
Handles events generated when the UI is trying to figure out the current state of the UI controls rel...
int m_KI_Lang_Identifier
KiCad identifier used in menu selection (See id.h)
Definition: pgm_base.h:63
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:67
virtual void setupUIConditions()
Setup the UI conditions for the various actions and their controls in this frame.
void onAutoSaveTimer(wxTimerEvent &aEvent)
Handle the auto save timer event.
static TOOL_ACTION reportBug
Definition: actions.h:179
virtual void doCloseWindow()
void ShowInfoBarMsg(const wxString &aMsg)
virtual void RegisterUIUpdateHandler(int aID, const ACTION_CONDITIONS &aConditions) override
Register a UI update handler for the control with ID aID.
APP_SETTINGS_BASE * KifaceSettings() const
Definition: kiface_i.h:103
const wxChar *const traceDisplayLocation
Flag to enable debug output of display positioning logic.
virtual void PushCommandToUndoList(PICKED_ITEMS_LIST *aItem)
Function PushCommandToUndoList add a command to undo in undo list delete the very old commands when t...
virtual bool IsModal() const
Return true if the frame is shown in our modal mode and false if the frame is shown as an usual frame...
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
virtual int GetRedoCommandCount() const
void ChangeUserUnits(EDA_UNITS aUnits)
SEARCH_STACK looks for files in a number of places.
Definition: search_stack.h:41
virtual PICKED_ITEMS_LIST * PopCommandFromRedoList()
PopCommandFromRedoList return the last command to undo and remove it from list nothing is deleted.
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
#define DEFAULT_MAX_UNDO_ITEMS
KIWAY Kiway & Pgm(), KFCTL_STANDALONE
The global Program "get" accessor.
Definition: single_top.cpp:102
wxTimer * m_autoSaveTimer
void LoadWindowState(const wxString &aFileName)
PICKED_ITEMS_LIST * PopCommand()
void ClearFileHistory()
Clear all entries from the file history.
std::function< void(wxUpdateUIEvent &) > UIUpdateHandler
This is the handler functor for the update UI events.
virtual void ClearUndoORRedoList(UNDO_REDO_LIST aList, int aItemCount=-1)
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.
void PushCommand(PICKED_ITEMS_LIST *aCommand)
wxTreebook * GetTreebook()
Definition: paged_dialog.h:50
void AddFileToHistory(const wxString &aFile) override
Adds a file to the history.
Definition: filehistory.cpp:96
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:81
void ShowInfoBarWarning(const wxString &aWarningMsg)
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:85
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:99
virtual int GetUndoCommandCount() const
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:343
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 ...
std::map< int, UIUpdateHandler > m_uiUpdateMap
virtual void UnregisterUIUpdateHandler(int aID) override
Unregister a UI handler for a given ID that was registered using RegisterUIUpdateHandler.
virtual const SEARCH_STACK & sys_search()
Return a SEARCH_STACK pertaining to entire program.
PROJECT & Prj() const
Function Prj returns a reference to the PROJECT "associated with" this KIWAY.
virtual void DispatchWxEvent(wxEvent &aEvent)
Processes wxEvents (mostly UI events), translates them to TOOL_EVENTs, and makes tools handle those.
struct WINDOW_STATE window
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:124
virtual WINDOW_SETTINGS * GetWindowSettings(APP_SETTINGS_BASE *aCfg)
Returns a pointer to the window settings for this frame.
virtual PICKED_ITEMS_LIST * PopCommandFromUndoList()
PopCommandFromUndoList return the last command to undo and remove it from list nothing is deleted.
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)
PICKED_ITEMS_LIST is a holder to handle information on schematic or board items.
void ShowInfoBarError(const wxString &aErrorMsg)
COMMON_CONTROL.
Stores the window positioning/state.
Definition: app_settings.h:68
UNDO_REDO_CONTAINER m_redoList
void RemoveAllButtons()
Remove all the buttons that have been added by the user.
Definition: infobar.cpp:226
virtual bool canCloseWindow(wxCloseEvent &aCloseEvent)
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.
const PROJECT_FILE_STATE * GetFileState(const wxString &aFileName)
virtual void OnMove(wxMoveEvent &aEvent)
EDA_UNITS
Definition: eda_units.h:38
static wxString GetAutoSaveFilePrefix()
void CommonSettingsChanged(bool aEnvVarsChanged, bool aTextVarsChanged) override
Notification event that some of the common (suite-wide) settings have changed.
WINDOW_SETTINGS m_Window
Definition: app_settings.h:173
void SetMaxFiles(size_t aMaxFiles)
Update the number of files that will be contained inside the file history.
Definition: filehistory.cpp:85
void OnMaximize(wxMaximizeEvent &aEvent)
void SetAutoSaveInterval(int aInterval)
virtual SELECTION & GetCurrentSelection()
Get the current selection from the canvas area.
Definition: tools_holder.h:123
TOOL_MANAGER * m_toolManager
Definition: tools_holder.h:48
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:201
wxString ConfigBaseName() override
WX_INFOBAR * m_infoBar
#define KICAD_MANAGER_FRAME_NAME
#define _(s)
Definition: 3d_actions.cpp:33
WINDOW_STATE state
Definition: app_settings.h:83
Functors that can be used to figure out how the action controls should be displayed in the UI and if ...
The base frame for deriving all KiCad main window classes.
void LoadWindowSettings(const WINDOW_SETTINGS *aCfg)
Loads window settings from the given settings object Normally called by LoadSettings unless the windo...
static TOOL_ACTION help
Definition: actions.h:176
const wxChar *const kicadTraceKeyEvent
Flag to enable wxKeyEvent debug tracing.
virtual wxString help_name()
virtual void CommonSettingsChanged(bool aEnvVarsChanged, bool aTextVarsChanged)
Notification event that some of the common (suite-wide) settings have changed.
void OnPreferences(wxCommandEvent &event)
VTBL_ENTRY void CommonSettingsChanged(bool aEnvVarsChanged, bool aTextVarsChanged)
Function CommonSettingsChanged Calls CommonSettingsChanged() on all KIWAY_PLAYERs.
Definition: kiway.cpp:513
WX_INFOBAR * GetInfoBar()
ACTION_CONDITIONS & Check(const SELECTION_CONDITION &aCondition)
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
unsigned int display
Definition: app_settings.h:75
static TOOL_ACTION getInvolved
Definition: actions.h:178
virtual void ShowChangedLanguage()
Redraw the menus and what not in current language.
static TOOL_ACTION gettingStarted
Definition: actions.h:175
virtual void ClearUndoRedoList()
Function ClearUndoRedoList clear undo and redo list, using ClearUndoORRedoList() picked items are del...
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.
void RemoveShutdownBlockReason(wxWindow *aWindow)
Removes any shutdown block reason set.
Definition: gtk/app.cpp:46
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.