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/wx_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
53void 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
88void PL_EDITOR_FRAME::OnClearFileHistory( wxCommandEvent& aEvent )
89{
91}
92
93
94/* File commands. */
95void 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
233bool 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;
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." ),
261 }
262
263 if( fn.FileExists() && !fn.IsFileWritable() )
264 {
267 m_infoBar->ShowMessage( _( "Layout file is read only." ),
269 }
270
271 return true;
272 }
273
274 return false;
275}
276
277
278bool PL_EDITOR_FRAME::InsertDrawingSheetFile( const wxString& aFullFileName )
279{
280 if( wxFileExists( aFullFileName ) )
281 {
282 const bool append = true;
284 DS_DATA_MODEL::GetTheInstance().LoadDrawingSheet( aFullFileName, append );
285 return true;
286 }
287
288 return false;
289}
290
291
292bool PL_EDITOR_FRAME::SaveDrawingSheetFile( const wxString& aFullFileName )
293{
294 if( !aFullFileName.IsEmpty() )
295 {
296 wxString tempFile = wxFileName::CreateTempFileName( "pledit" );
297
298 try
299 {
301 }
302 catch( const IO_ERROR& )
303 {
304 // In case we started a file but didn't fully write it, clean up
305 wxRemoveFile( tempFile);
306
307 return false;
308 }
309
310 if( !wxRenameFile( tempFile, aFullFileName ) )
311 return false;
312
315
316 GetScreen()->SetContentModified( false );
317 return true;
318 }
319
320 return false;
321}
322
324{
325 for( const wxFileName& file : m_AcceptedFiles )
326 OpenProjectFiles( { file.GetFullPath() }, KICTL_CREATE );
327}
void SetContentModified(bool aModified=true)
Definition: base_screen.h:59
Handle the graphic items list to draw/plot the frame and title block.
Definition: ds_data_model.h:39
static DS_DATA_MODEL & GetTheInstance()
static function: returns the instance of DS_DATA_MODEL used in the application
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
void ClearList()
Erase the list of items.
void Save(const wxString &aFullFileName)
Save the description in a file.
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.
std::vector< wxFileName > m_AcceptedFiles
WX_INFOBAR * m_infoBar
void UpdateFileHistory(const wxString &FullFileName, FILE_HISTORY *aFileHistory=nullptr)
Update the list of recently opened files.
void ClearFileHistory(FILE_HISTORY *aFileHistory=nullptr)
Removes all files from the file history.
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...
virtual BASE_SCREEN * GetScreen() const
Return a pointer to a BASE_SCREEN or one of its derivatives.
Hold an error message and may be used when throwing exceptions containing meaningful error messages.
Definition: ki_exception.h:76
static wxString GetUserTemplatesPath()
Gets the user path for custom templates.
Definition: paths.cpp:86
bool OpenProjectFiles(const std::vector< wxString > &aFileSet, int aCtl) override
Open a project or set of files given by aFileList.
void OnNewDrawingSheet()
Must be called to initialize parameters when a new drawing sheet is loaded.
void SetCurrentFileName(const wxString &aName)
Store the current layout description file filename.
bool IsContentModified() const override
Get if the drawing sheet has been modified but not saved.
void Files_io(wxCommandEvent &event)
void OnClearFileHistory(wxCommandEvent &aEvent)
wxString GetCurrentFileName() const override
void OnFileHistory(wxCommandEvent &event)
void DoWithAcceptedFiles() override
Execute action on accepted dropped file.
bool SaveDrawingSheetFile(const wxString &aFullFileName)
Save the current layout in a .kicad_wks drawing sheet file.
bool InsertDrawingSheetFile(const wxString &aFullFileName)
Load a .kicad_wks drawing sheet file, and add items to the current layout list.
void SaveCopyInUndoList()
Save a copy of the description (in a S expr string) for Undo/redo commands.
void HardRedraw() override
Refresh the library tree and redraw the window.
bool LoadDrawingSheetFile(const wxString &aFullFileName)
Load a .kicad_wks drawing sheet file.
void RemoveAllButtons()
Remove all the buttons that have been added by the user.
Definition: wx_infobar.cpp:289
@ OUTDATED_SAVE
OUTDATED_SAVE Messages that should be cleared on save.
void Dismiss() override
Dismisses the infobar and updates the containing layout and AUI manager (if one is provided).
Definition: wx_infobar.cpp:175
void AddCloseButton(const wxString &aTooltip=_("Hide this message."))
Add the default close button to the infobar on the right side.
Definition: wx_infobar.cpp:279
MESSAGE_TYPE GetMessageType() const
Definition: wx_infobar.h:100
void ShowMessage(const wxString &aMessage, int aFlags=wxICON_INFORMATION) override
Show the info bar with the provided message and icon.
Definition: wx_infobar.cpp:142
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:260
void DisplayErrorMessage(wxWindow *aParent, const wxString &aText, const wxString &aExtraInfo)
Display an error message with aMessage.
Definition: confirm.cpp:325
This file is part of the common library.
#define SEXPR_WORKSHEET_FILE_VERSION
This file contains the file format version information for the s-expression drawing sheet file format...
#define _(s)
const std::string DrawingSheetFileExtension
wxString DrawingSheetFileWildcard()
#define KICTL_CREATE
caller thinks requested project files may not exist.
Definition: kiway_player.h:82
@ ID_APPEND_DESCR_FILE
Definition: pl_editor_id.h:41
Definition of file extensions used in Kicad.