KiCad PCB EDA Suite
pagelayout_editor/files.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) 2013 CERN
5  * Copyright (C) 2017-2021 KiCad Developers, see AUTHORS.txt for contributors.
6  *
7  * @author Jean-Pierre Charras, jp.charras at wanadoo.fr
8  *
9  * This program is free software; you can redistribute it and/or
10  * modify it under the terms of the GNU General Public License
11  * as published by the Free Software Foundation; either version 2
12  * of the License, or (at your option) any later version.
13  *
14  * This program is distributed in the hope that it will be useful,
15  * but WITHOUT ANY WARRANTY; without even the implied warranty of
16  * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
17  * GNU General Public License for more details.
18  *
19  * You should have received a copy of the GNU General Public License
20  * along with this program; if not, you may find one here:
21  * http://www.gnu.org/licenses/old-licenses/gpl-2.0.html
22  * or you may search the http://www.gnu.org website for the version 2 license,
23  * or you may write to the Free Software Foundation, Inc.,
24  * 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301, USA
25  */
26 
27 #include <confirm.h>
28 #include <gestfich.h>
31 #include <paths.h>
32 #include <widgets/infobar.h>
34 
35 #include "pl_editor_frame.h"
36 #include "pl_editor_id.h"
37 #include "properties_frame.h"
38 
39 #include <wx/filedlg.h>
40 #include <wx/filename.h>
41 #include <wx/stdpaths.h>
42 
44 {
45  wxCommandEvent saveEvent;
46  saveEvent.SetId( wxID_SAVE );
47  Files_io( saveEvent );
48 
49  return !IsContentModified();
50 }
51 
52 
53 void PL_EDITOR_FRAME::OnFileHistory( wxCommandEvent& event )
54 {
55  wxString filename;
56 
57  filename = GetFileFromHistory( event.GetId(), _( "Drawing Sheet File" ) );
58 
59  if( filename != wxEmptyString )
60  {
61  if( IsContentModified() )
62  {
63  if( !HandleUnsavedChanges( this, _( "The current drawing sheet has been modified. "
64  "Save changes?" ),
65  [&]() -> bool
66  {
67  return saveCurrentPageLayout();
68  } ) )
69  {
70  return;
71  }
72  }
73 
74  ::wxSetWorkingDirectory( ::wxPathOnly( filename ) );
75 
76  if( LoadDrawingSheetFile( filename ) )
77  {
78  wxString msg;
79  msg.Printf( _( "File \"%s\" loaded"), filename );
80  SetStatusText( msg );
81  }
82 
84  }
85 }
86 
87 
88 void PL_EDITOR_FRAME::OnClearFileHistory( wxCommandEvent& aEvent )
89 {
91 }
92 
93 
94 /* File commands. */
95 void PL_EDITOR_FRAME::Files_io( wxCommandEvent& event )
96 {
97  wxString msg;
98  int id = event.GetId();
99  wxString filename = GetCurrentFileName();
101 
102  if( filename.IsEmpty() && id == wxID_SAVE )
103  id = wxID_SAVEAS;
104 
105  if( ( id == wxID_NEW || id == wxID_OPEN ) && IsContentModified() )
106  {
107  if( !HandleUnsavedChanges( this, _( "The current drawing sheet has been modified. "
108  "Save changes?" ),
109  [&]() -> bool
110  {
111  return saveCurrentPageLayout();
112  } ) )
113  {
114  return;
115  }
116  }
117 
118  switch( id )
119  {
120  case wxID_NEW:
121  pglayout.AllowVoidList( true );
122  SetCurrentFileName( wxEmptyString );
123  pglayout.ClearList();
125  break;
126 
128  {
129  wxFileDialog openFileDialog( this, _( "Append Existing Drawing Sheet" ),
130  wxEmptyString, wxEmptyString,
131  DrawingSheetFileWildcard(), wxFD_OPEN );
132 
133  if( openFileDialog.ShowModal() == wxID_CANCEL )
134  return;
135 
136  filename = openFileDialog.GetPath();
137 
138  if( !InsertDrawingSheetFile( filename ) )
139  {
140  msg.Printf( _( "Unable to load %s file" ), filename );
141  DisplayErrorMessage( this, msg );
142  }
143  else
144  {
146  HardRedraw();
147  msg.Printf( _( "File \"%s\" inserted" ), filename );
148  SetStatusText( msg );
149  }
150  }
151  break;
152 
153  case wxID_OPEN:
154  {
155  wxFileDialog openFileDialog( this, _( "Open" ), wxEmptyString, wxEmptyString,
156  DrawingSheetFileWildcard(), wxFD_OPEN );
157 
158  if( openFileDialog.ShowModal() == wxID_CANCEL )
159  return;
160 
161  filename = openFileDialog.GetPath();
162 
163  if( !LoadDrawingSheetFile( filename ) )
164  {
165  msg.Printf( _( "Unable to load %s file" ), filename );
166  DisplayErrorMessage( this, msg );
167  }
168  else
169  {
171  msg.Printf( _( "File \"%s\" saved." ), filename );
172  SetStatusText( msg );
173  }
174  }
175  break;
176 
177  case wxID_SAVE:
178  if( !SaveDrawingSheetFile( filename ) )
179  {
180  msg.Printf( _( "Unable to write '%s'." ), filename );
181  DisplayErrorMessage( this, msg );
182  }
183  else
184  {
185  msg.Printf( _("File '%s' saved."), filename );
186  SetStatusText( msg );
187  }
188  break;
189 
190  case wxID_SAVEAS:
191  {
192  wxString dir = PATHS::GetUserTemplatesPath();
193  wxFileDialog openFileDialog( this, _( "Save As" ), dir, wxEmptyString,
195  wxFD_SAVE | wxFD_OVERWRITE_PROMPT );
196 
197  if( openFileDialog.ShowModal() == wxID_CANCEL )
198  return;
199 
200  filename = openFileDialog.GetPath();
201  // Ensure the file has the right extension:
202  // because a name like name.subname.subsubname is legal,
203  // add the right extension without replacing the wxFileName
204  // extension
205  wxFileName fn(filename);
206 
207  if( fn.GetExt() != DrawingSheetFileExtension )
208  filename << wxT(".") << DrawingSheetFileExtension;
209 
210  if( !SaveDrawingSheetFile( filename ) )
211  {
212  msg.Printf( _( "Failed to create file '%s'." ), filename );
213  DisplayErrorMessage( this, msg );
214  }
215 
216  else
217  {
218  msg.Printf( _("File \"%s\" saved."), filename );
219  SetStatusText( msg );
220 
221  if( GetCurrentFileName().IsEmpty() )
222  SetCurrentFileName( filename );
223  }
224  }
225  break;
226 
227  default:
228  break;
229  }
230 }
231 
232 
233 bool PL_EDITOR_FRAME::LoadDrawingSheetFile( const wxString& aFullFileName )
234 {
235  if( wxFileExists( aFullFileName ) )
236  {
237  bool loaded = false;
238 
239  loaded = DS_DATA_MODEL::GetTheInstance().LoadDrawingSheet( aFullFileName );
240 
241  if( !loaded )
242  {
243  ShowInfoBarError( _( "Error reading drawing sheet" ), true );
244  return false;
245  }
246 
247  SetCurrentFileName( aFullFileName );
248  UpdateFileHistory( aFullFileName );
249  GetScreen()->SetContentModified( false );
250 
251  wxFileName fn = aFullFileName;
252  m_infoBar->Dismiss();
253 
254  if( DS_DATA_MODEL::GetTheInstance().GetFileFormatVersionAtLoad() < SEXPR_WORKSHEET_FILE_VERSION )
255  {
258  m_infoBar->ShowMessage( _( "This file was created by an older version of KiCad. "
259  "It will be converted to the new format when saved." ),
260  wxICON_WARNING, WX_INFOBAR::MESSAGE_TYPE::OUTDATED_SAVE );
261  }
262 
263  if( fn.FileExists() && !fn.IsFileWritable() )
264  {
265  ShowInfoBarWarning( _( "Layout file is read only." ), true );
266  }
267 
268  return true;
269  }
270 
271  return false;
272 }
273 
274 
275 bool PL_EDITOR_FRAME::InsertDrawingSheetFile( const wxString& aFullFileName )
276 {
277  if( wxFileExists( aFullFileName ) )
278  {
279  const bool append = true;
281  DS_DATA_MODEL::GetTheInstance().LoadDrawingSheet( aFullFileName, append );
282  return true;
283  }
284 
285  return false;
286 }
287 
288 
289 bool PL_EDITOR_FRAME::SaveDrawingSheetFile( const wxString& aFullFileName )
290 {
291  if( !aFullFileName.IsEmpty() )
292  {
293  wxStandardPaths& paths = wxStandardPaths::Get();
294  wxString tempFile = wxFileName::CreateTempFileName(
295  paths.GetTempDir() + wxFileName::GetPathSeparator() + wxT( "pledit" ) );
296 
297  try
298  {
299  DS_DATA_MODEL::GetTheInstance().Save( tempFile );
300  }
301  catch( const IO_ERROR& )
302  {
303  // In case we started a file but didn't fully write it, clean up
304  wxRemoveFile( tempFile);
305 
306  return false;
307  }
308 
309  if( !wxRenameFile( tempFile, aFullFileName ) )
310  return false;
311 
312  GetScreen()->SetContentModified( false );
313  return true;
314  }
315 
316  return false;
317 }
void OnFileHistory(wxCommandEvent &event)
void ShowMessage(const wxString &aMessage, int aFlags=wxICON_INFORMATION) override
Show the info bar with the provided message and icon.
Definition: infobar.cpp:142
void ClearList()
Erase the list of items.
bool HandleUnsavedChanges(wxWindow *aParent, const wxString &aMessage, const std::function< bool()> &aSaveFunction)
Display a dialog with Save, Cancel and Discard Changes buttons.
Definition: confirm.cpp:239
Handle the graphic items list to draw/plot the frame and title block.
Definition: ds_data_model.h:38
void HardRedraw() override
Refresh the library tree and redraw the window.
void DisplayErrorMessage(wxWindow *aParent, const wxString &aText, const wxString &aExtraInfo)
Display an error message with aMessage.
Definition: confirm.cpp:292
This file is part of the common library.
void OnClearFileHistory(wxCommandEvent &aEvent)
bool SaveDrawingSheetFile(const wxString &aFullFileName)
Save the current layout in a .kicad_wks drawing sheet file.
void Save(const wxString &aFullFileName)
Save the description in a file.
void ShowInfoBarWarning(const wxString &aWarningMsg, bool aShowCloseButton=false)
Show the WX_INFOBAR displayed on the top of the canvas with a message and a warning icon on the left ...
void UpdateFileHistory(const wxString &FullFileName, FILE_HISTORY *aFileHistory=nullptr)
Update the list of recently opened files.
wxString GetFileFromHistory(int cmdId, const wxString &type, FILE_HISTORY *aFileHistory=nullptr)
Fetches the file name from the file history list.
void ShowInfoBarError(const wxString &aErrorMsg, bool aShowCloseButton=false, WX_INFOBAR::MESSAGE_TYPE aType=WX_INFOBAR::MESSAGE_TYPE::GENERIC)
Show the WX_INFOBAR displayed on the top of the canvas with a message and an error icon on the left o...
bool InsertDrawingSheetFile(const wxString &aFullFileName)
Load a .kicad_wks drawing sheet file, and add items to the current layout list.
void Dismiss() override
Dismisses the infobar and updates the containing layout and AUI manager (if one is provided).
Definition: infobar.cpp:175
static DS_DATA_MODEL & GetTheInstance()
static function: returns the instance of DS_DATA_MODEL used in the application
wxString GetCurrentFileName() const override
void AllowVoidList(bool Allow)
In KiCad applications, a drawing sheet is needed So if the list is empty, a default drawing sheet is ...
Definition: ds_data_model.h:83
bool IsContentModified() const override
Get if the drawing sheet has been modified but not saved.
Definition of file extensions used in Kicad.
static wxString GetUserTemplatesPath()
Gets the user path for custom templates.
Definition: paths.cpp:86
#define SEXPR_WORKSHEET_FILE_VERSION
This file contains the file format version information for the s-expression drawing sheet file format...
#define _(s)
void RemoveAllButtons()
Remove all the buttons that have been added by the user.
Definition: infobar.cpp:286
void ClearFileHistory(FILE_HISTORY *aFileHistory=nullptr)
Removes all files from the file history.
void SetContentModified(bool aModified=true)
Definition: base_screen.h:59
void SetCurrentFileName(const wxString &aName)
Store the current layout description file filename.
const std::string DrawingSheetFileExtension
WX_INFOBAR * m_infoBar
bool LoadDrawingSheet(const wxString &aFullFileName=wxEmptyString, bool Append=false)
Populates the list with a custom layout or the default layout if no custom layout is available.
OUTDATED_SAVE Messages that should be cleared on save.
void OnNewDrawingSheet()
Must be called to initialize parameters when a new drawing sheet is loaded.
void SaveCopyInUndoList()
Save a copy of the description (in a S expr string) for Undo/redo commands.
wxString DrawingSheetFileWildcard()
Hold an error message and may be used when throwing exceptions containing meaningful error messages.
Definition: ki_exception.h:75
virtual BASE_SCREEN * GetScreen() const
Return a pointer to a BASE_SCREEN or one of its derivatives.
bool LoadDrawingSheetFile(const wxString &aFullFileName)
Load a .kicad_wks drawing sheet file.
void AddCloseButton(const wxString &aTooltip=_("Hide this message."))
Add the default close button to the infobar on the right side.
Definition: infobar.cpp:276
void Files_io(wxCommandEvent &event)