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 
42 {
43  wxCommandEvent saveEvent;
44  saveEvent.SetId( wxID_SAVE );
45  Files_io( saveEvent );
46 
47  return !IsContentModified();
48 }
49 
50 
51 void PL_EDITOR_FRAME::OnFileHistory( wxCommandEvent& event )
52 {
53  wxString filename;
54 
55  filename = GetFileFromHistory( event.GetId(), _( "Drawing Sheet File" ) );
56 
57  if( filename != wxEmptyString )
58  {
59  if( IsContentModified() )
60  {
61  if( !HandleUnsavedChanges( this, _( "The current drawing sheet has been modified. "
62  "Save changes?" ),
63  [&]()->bool { return saveCurrentPageLayout(); } ) )
64  {
65  return;
66  }
67  }
68 
69  ::wxSetWorkingDirectory( ::wxPathOnly( filename ) );
70 
71  if( LoadDrawingSheetFile( filename ) )
72  {
73  wxString msg;
74  msg.Printf( _( "File \"%s\" loaded"), filename );
75  SetStatusText( msg );
76  }
77 
79  }
80 }
81 
82 
83 void PL_EDITOR_FRAME::OnClearFileHistory( wxCommandEvent& aEvent )
84 {
86 }
87 
88 
89 /* File commands. */
90 void PL_EDITOR_FRAME::Files_io( wxCommandEvent& event )
91 {
92  wxString msg;
93  int id = event.GetId();
94  wxString filename = GetCurrentFileName();
96 
97  if( filename.IsEmpty() && id == wxID_SAVE )
98  id = wxID_SAVEAS;
99 
100  if( ( id == wxID_NEW || id == wxID_OPEN ) && IsContentModified() )
101  {
102  if( !HandleUnsavedChanges( this, _( "The current drawing sheet has been modified. "
103  "Save changes?" ),
104  [&]()->bool { return saveCurrentPageLayout(); } ) )
105  {
106  return;
107  }
108  }
109 
110  switch( id )
111  {
112  case wxID_NEW:
113  pglayout.AllowVoidList( true );
114  SetCurrentFileName( wxEmptyString );
115  pglayout.ClearList();
117  break;
118 
120  {
121  wxFileDialog openFileDialog( this, _( "Append Existing Drawing Sheet" ),
122  wxEmptyString, wxEmptyString,
123  DrawingSheetFileWildcard(), wxFD_OPEN );
124 
125  if( openFileDialog.ShowModal() == wxID_CANCEL )
126  return;
127 
128  filename = openFileDialog.GetPath();
129 
130  if( !InsertDrawingSheetFile( filename ) )
131  {
132  msg.Printf( _( "Unable to load %s file" ), filename );
133  DisplayErrorMessage( this, msg );
134  }
135  else
136  {
138  HardRedraw();
139  msg.Printf( _( "File \"%s\" inserted" ), filename );
140  SetStatusText( msg );
141  }
142  }
143  break;
144 
145  case wxID_OPEN:
146  {
147  wxFileDialog openFileDialog( this, _( "Open" ), wxEmptyString, wxEmptyString,
148  DrawingSheetFileWildcard(), wxFD_OPEN );
149 
150  if( openFileDialog.ShowModal() == wxID_CANCEL )
151  return;
152 
153  filename = openFileDialog.GetPath();
154 
155  if( !LoadDrawingSheetFile( filename ) )
156  {
157  msg.Printf( _( "Unable to load %s file" ), filename );
158  DisplayErrorMessage( this, msg );
159  }
160  else
161  {
163  msg.Printf( _( "File \"%s\" saved." ), filename );
164  SetStatusText( msg );
165  }
166  }
167  break;
168 
169  case wxID_SAVE:
170  if( !SaveDrawingSheetFile( filename ) )
171  {
172  msg.Printf( _( "Unable to write '%s'." ), filename );
173  DisplayErrorMessage( this, msg );
174  }
175  else
176  {
177  msg.Printf( _("File '%s' saved."), filename );
178  SetStatusText( msg );
179  }
180  break;
181 
182  case wxID_SAVEAS:
183  {
184  wxString dir = PATHS::GetUserTemplatesPath();
185  wxFileDialog openFileDialog( this, _( "Save As" ), dir, wxEmptyString,
187  wxFD_SAVE | wxFD_OVERWRITE_PROMPT );
188 
189  if( openFileDialog.ShowModal() == wxID_CANCEL )
190  return;
191 
192  filename = openFileDialog.GetPath();
193  // Ensure the file has the right extension:
194  // because a name like name.subname.subsubname is legal,
195  // add the right extension without replacing the wxFileName
196  // extension
197  wxFileName fn(filename);
198 
199  if( fn.GetExt() != DrawingSheetFileExtension )
200  filename << wxT(".") << DrawingSheetFileExtension;
201 
202  if( !SaveDrawingSheetFile( filename ) )
203  {
204  msg.Printf( _( "Failed to create file '%s'." ), filename );
205  DisplayErrorMessage( this, msg );
206  }
207 
208  else
209  {
210  msg.Printf( _("File \"%s\" saved."), filename );
211  SetStatusText( msg );
212 
213  if( GetCurrentFileName().IsEmpty() )
214  SetCurrentFileName( filename );
215  }
216  }
217  break;
218 
219  default:
220  break;
221  }
222 }
223 
224 
225 bool PL_EDITOR_FRAME::LoadDrawingSheetFile( const wxString& aFullFileName )
226 {
227  if( wxFileExists( aFullFileName ) )
228  {
229  bool loaded = false;
230 
231  loaded = DS_DATA_MODEL::GetTheInstance().LoadDrawingSheet( aFullFileName );
232 
233  if( !loaded )
234  {
235  ShowInfoBarError( _( "Error reading drawing sheet" ), true );
236  return false;
237  }
238 
239  SetCurrentFileName( aFullFileName );
240  UpdateFileHistory( aFullFileName );
241  GetScreen()->SetContentModified( false );
242 
243  wxFileName fn = aFullFileName;
244  m_infoBar->Dismiss();
245 
246  if( DS_DATA_MODEL::GetTheInstance().GetFileFormatVersionAtLoad() < SEXPR_WORKSHEET_FILE_VERSION )
247  {
250  m_infoBar->ShowMessage( _( "This file was created by an older version of KiCad. "
251  "It will be converted to the new format when saved." ),
252  wxICON_WARNING, WX_INFOBAR::MESSAGE_TYPE::OUTDATED_SAVE );
253  }
254 
255  if( fn.FileExists() && !fn.IsFileWritable() )
256  {
257  ShowInfoBarWarning( _( "Layout file is read only." ), true );
258  }
259 
260  return true;
261  }
262 
263  return false;
264 }
265 
266 
267 bool PL_EDITOR_FRAME::InsertDrawingSheetFile( const wxString& aFullFileName )
268 {
269  if( wxFileExists( aFullFileName ) )
270  {
271  const bool append = true;
273  DS_DATA_MODEL::GetTheInstance().LoadDrawingSheet( aFullFileName, append );
274  return true;
275  }
276 
277  return false;
278 }
279 
280 
281 bool PL_EDITOR_FRAME::SaveDrawingSheetFile( const wxString& aFullFileName )
282 {
283  if( !aFullFileName.IsEmpty() )
284  {
285  wxFileName tempFile( aFullFileName );
286  tempFile.SetName( wxT( "." ) + tempFile.GetName() );
287  tempFile.SetExt( tempFile.GetExt() + wxT( "$" ) );
288 
289  try
290  {
291  DS_DATA_MODEL::GetTheInstance().Save( tempFile.GetFullPath() );
292  }
293  catch( const IO_ERROR& )
294  {
295  // In case we started a file but didn't fully write it, clean up
296  wxRemoveFile( tempFile.GetFullPath() );
297 
298  return false;
299  }
300 
301  if( !wxRenameFile( tempFile.GetFullPath(), aFullFileName ) )
302  return false;
303 
304  GetScreen()->SetContentModified( false );
305  return true;
306  }
307 
308  return false;
309 }
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:231
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:284
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)