KiCad PCB EDA Suite
All Classes Namespaces Files Functions Variables Typedefs Enumerations Enumerator Friends Macros Modules Pages Concepts
panel_embedded_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 The KiCad Developers, see AUTHORS.TXT for contributors.
5 *
6 * This program is free software; you can redistribute it and/or
7 * modify it under the terms of the GNU General Public License
8 * as published by the Free Software Foundation; either version 3
9 * of the License, or (at your option) any later version.
10 *
11 * This program is distributed in the hope that it will be useful,
12 * but WITHOUT ANY WARRANTY; without even the implied warranty of
13 * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
14 * GNU General Public License for more details.
15 *
16 * You should have received a copy of the GNU General Public License
17 * along with this program; if not, you may find one here:
18 * http://www.gnu.org/licenses/gpl-3.0.html
19 * or you may search the http://www.gnu.org website for the version 3 license,
20 * or you may write to the Free Software Foundation, Inc.,
21 * 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301, USA
22 */
23
24#include <bitmaps.h>
26#include <embedded_files.h>
27#include <font/outline_font.h>
28#include <kidialog.h>
30#include <widgets/wx_grid.h>
31
32#include <wx/clipbrd.h>
33#include <wx/dirdlg.h>
34#include <wx/ffile.h>
35#include <wx/filedlg.h>
36#include <wx/filename.h>
37#include <wx/log.h>
38#include <wx/menu.h>
39#include <wx/wfstream.h>
40
41/* ---------- GRID_TRICKS for embedded files grid ---------- */
42
44 GRID_TRICKS( aGrid ), m_curRow( -1 )
45{
46}
47
48
49void EMBEDDED_FILES_GRID_TRICKS::showPopupMenu( wxMenu& menu, wxGridEvent& aEvent )
50{
51 if( const int row = aEvent.GetRow(); row >= 0 && row < m_grid->GetNumberRows() )
52 {
53 m_curRow = row;
54 menu.Append( EMBEDDED_FILES_GRID_TRICKS_COPY_FILENAME, _( "Copy Embedded Reference" ),
55 _( "Copy the reference for this embedded file" ) );
56 menu.AppendSeparator();
57 GRID_TRICKS::showPopupMenu( menu, aEvent );
58 }
59 else
60 {
61 m_curRow = -1;
62 }
63}
64
65
67{
68 if( event.GetId() == EMBEDDED_FILES_GRID_TRICKS_COPY_FILENAME )
69 {
70 if( m_curRow >= 0 )
71 {
72 const wxString cellValue = m_grid->GetCellValue( m_curRow, 1 );
73
74 if( wxTheClipboard->Open() )
75 {
76 wxTheClipboard->SetData( new wxTextDataObject( cellValue ) );
77 wxTheClipboard->Close();
78 }
79 }
80 }
81 else
82 {
84 }
85}
86
87
88/* ---------- End of GRID_TRICKS for embedded files grid ---------- */
89
90
92 PANEL_EMBEDDED_FILES_BASE( parent ), m_files( aFiles ), m_localFiles( new EMBEDDED_FILES() )
93{
94 for( auto& [name, file] : m_files->EmbeddedFileMap() )
95 {
97 m_localFiles->AddFile( newFile );
98 }
99
100 // Set up the standard buttons
101 m_delete_button->SetBitmap( KiBitmapBundle( BITMAPS::small_trash ) );
102 m_browse_button->SetBitmap( KiBitmapBundle( BITMAPS::small_folder ) );
103 m_files_grid->SetMargins( 0 - wxSYS_VSCROLL_X, 0 );
105
106 m_files_grid->PushEventHandler( new EMBEDDED_FILES_GRID_TRICKS( m_files_grid ) );
107
109
110 for( int ii = 0; ii < m_files_grid->GetNumberRows(); ii++ )
111 {
112 if( m_files_grid->GetCellValue( ii, 1 ) == file->GetLink() )
113 {
114 m_files_grid->DeleteRows( ii );
115 break;
116 }
117 }
118
119 m_files_grid->AppendRows( 1 );
120 int ii = m_files_grid->GetNumberRows() - 1;
121 m_files_grid->SetCellValue( ii, 0, file->name );
122 m_files_grid->SetCellValue( ii, 1, file->GetLink() );
123
124 });
125}
126
127
129{
130 // Remove the GRID_TRICKS handler
131 m_files_grid->PopEventHandler( true );
132}
133
134
135void PANEL_EMBEDDED_FILES::onSize( wxSizeEvent& event )
136{
137 resizeGrid();
138}
139
140
142{
143 int panel_width = GetClientRect().GetWidth();
144 int first_width = m_files_grid->GetColSize( 0 );
145 int second_width = m_files_grid->GetColSize( 1 );
146
147 double ratio;
148
149 if( first_width + second_width > 0 )
150 ratio = (double)first_width / (double)( first_width + second_width );
151 else
152 ratio = 0.3;
153
154
155 m_files_grid->SetColSize( 0, panel_width * ratio );
156 m_files_grid->SetColSize( 1, panel_width * ( 1 - ratio ) );
157 Layout();
158}
159
160
162{
163 m_files_grid->ClearGrid();
164
165 if( m_files_grid->GetNumberRows() > 0 )
166 m_files_grid->DeleteRows( 0, m_files_grid->GetNumberRows() );
167
168 int ii = 0;
169 for( auto& [name, file] : m_localFiles->EmbeddedFileMap() )
170 {
171 while( m_files_grid->GetNumberRows() < ii + 1 )
172 m_files_grid->AppendRows( 1 );
173
174 m_files_grid->SetCellValue( ii, 0, name );
175 m_files_grid->SetCellValue( ii, 1, file->GetLink() );
176
177 ii++;
178 }
179
181
182 resizeGrid();
183
184 return true;
185}
186
187
189{
191
192 std::vector<EMBEDDED_FILES::EMBEDDED_FILE*> files;
193
194 for( auto it = m_localFiles->EmbeddedFileMap().begin();
195 it != m_localFiles->EmbeddedFileMap().end(); it++ )
196 files.push_back( it->second );
197
198 for( auto& file : files )
199 {
200 m_files->AddFile( file );
201 m_localFiles->RemoveFile( file->name, false );
202 }
203
205
206 return true;
207}
208
209
210void PANEL_EMBEDDED_FILES::onFontEmbedClick( wxCommandEvent& event )
211{
212 Freeze();
213 int row_pos = m_files_grid->GetGridCursorRow();
214 int col_pos = m_files_grid->GetGridCursorCol();
215 wxString row_name;
216
217 if( row_pos >= 0 )
218 row_name = m_files_grid->GetCellValue( row_pos, 0 );
219
220 for( int ii = 0; ii < m_files_grid->GetNumberRows(); ii++ )
221 {
222 wxString name = m_files_grid->GetCellValue( ii, 0 );
223
225
227 {
228 m_files_grid->DeleteRows( ii );
229 ii--;
231 }
232 }
233
234 if( m_cbEmbedFonts->IsChecked() )
235 {
236 std::set<KIFONT::OUTLINE_FONT*> fonts = m_files->GetFonts();
237
238 for( KIFONT::OUTLINE_FONT* font : fonts )
239 {
241 m_localFiles->AddFile( font->GetFileName(), true );
242
243 if( !result )
244 {
245 wxLogTrace( wxT( "KICAD_EMBED" ), wxString::Format( "Could not embed font %s",
246 font->GetFileName() ) );
247 continue;
248 }
249
250 m_files_grid->AppendRows( 1 );
251 int ii = m_files_grid->GetNumberRows() - 1;
252 m_files_grid->SetCellValue( ii, 0, result->name );
253 m_files_grid->SetCellValue( ii, 1, result->GetLink() );
254 }
255 }
256
257 if( row_pos >= 0 )
258 {
259 col_pos = std::max( std::min( col_pos, m_files_grid->GetNumberCols() - 1 ), 0 );
260 row_pos = std::max( std::min( row_pos, m_files_grid->GetNumberRows() - 1 ), 0 );
261 m_files_grid->SetGridCursor( row_pos, col_pos );
262
263 for( int ii = 0; ii < m_files_grid->GetNumberRows(); ++ii )
264 {
265 if( m_files_grid->GetCellValue( ii, 0 ) == row_name )
266 {
267 m_files_grid->SetGridCursor( ii, col_pos );
268 break;
269 }
270 }
271 }
272
273 Thaw();
274}
275
276
278{
279 wxFileName fileName( aFile );
280 wxString name = fileName.GetFullName();
281
282 if( m_localFiles->HasFile( name ) )
283 {
284 wxString msg = wxString::Format( _( "File '%s' already exists." ), name );
285
286 KIDIALOG errorDlg( m_parent, msg, _( "Confirmation" ), wxOK | wxCANCEL | wxICON_WARNING );
287 errorDlg.SetOKLabel( _( "Overwrite" ) );
288
289 if( errorDlg.ShowModal() != wxID_OK )
290 return nullptr;
291
292 for( int ii = 0; ii < m_files_grid->GetNumberRows(); ii++ )
293 {
294 if( m_files_grid->GetCellValue( ii, 0 ) == name )
295 {
296 m_files_grid->DeleteRows( ii );
297 break;
298 }
299 }
300 }
301
302 EMBEDDED_FILES::EMBEDDED_FILE* result = m_localFiles->AddFile( fileName, true );
303
304 if( !result )
305 {
306 wxString msg = wxString::Format( _( "Failed to add file '%s'." ), name );
307
308 KIDIALOG errorDlg( m_parent, msg, _( "Error" ), wxOK | wxICON_ERROR );
309 errorDlg.ShowModal();
310 return nullptr;
311 }
312
313 return result;
314}
315
316
317void PANEL_EMBEDDED_FILES::onAddEmbeddedFiles( wxCommandEvent& event )
318{
319 // TODO: Update strings to reflect that multiple files can be selected.
320 wxFileDialog fileDialog( this, _( "Select a file to embed" ), wxEmptyString, wxEmptyString,
321 _( "All files|*.*" ),
322 wxFD_OPEN | wxFD_FILE_MUST_EXIST | wxFD_MULTIPLE );
323
324 if( fileDialog.ShowModal() == wxID_OK )
325 {
326 wxArrayString paths;
327 fileDialog.GetPaths( paths );
328
329 for( wxString path : paths )
331 }
332}
333
334
335bool PANEL_EMBEDDED_FILES::RemoveEmbeddedFile( const wxString& aFileName )
336{
337 wxString name = aFileName;
338
339 if( name.StartsWith( FILEEXT::KiCadUriPrefix ) )
340 name = name.Mid( FILEEXT::KiCadUriPrefix.size() + 3 );
341
342 int row = std::max( 0, m_files_grid->GetGridCursorRow() );
343
344 for( int ii = 0; ii < m_files_grid->GetNumberRows(); ii++ )
345 {
346 if( m_files_grid->GetCellValue( ii, 0 ) == name )
347 {
348 m_files_grid->DeleteRows( ii );
350
351 if( row < m_files_grid->GetNumberRows() )
352 m_files_grid->SetGridCursor( row, 0 );
353 else if( m_files_grid->GetNumberRows() > 0 )
354 m_files_grid->SetGridCursor( m_files_grid->GetNumberRows() - 1, 0 );
355
356 return true;
357 }
358 }
359
360 return false;
361}
362
363
365{
366 int row = m_files_grid->GetGridCursorRow();
367
368 if( row < 0 )
369 return;
370
371 wxString name = m_files_grid->GetCellValue( row, 0 );
372
374
375 m_files_grid->DeleteRows( row );
376
377 if( row < m_files_grid->GetNumberRows() )
378 m_files_grid->SetGridCursor( row, 0 );
379 else if( m_files_grid->GetNumberRows() > 0 )
380 m_files_grid->SetGridCursor( m_files_grid->GetNumberRows() - 1, 0 );
381}
382
383
384void PANEL_EMBEDDED_FILES::onExportFiles( wxCommandEvent& event )
385{
386 wxDirDialog dirDialog( this, _( "Select a directory to export files" ) );
387
388 if( dirDialog.ShowModal() != wxID_OK )
389 return;
390
391 wxString path = dirDialog.GetPath();
392
393 for( auto& [name, file] : m_localFiles->EmbeddedFileMap() )
394 {
395 wxFileName fileName( path, name );
396
397 if( fileName.FileExists() )
398 {
399 wxString msg = wxString::Format( _( "File '%s' already exists." ),
400 fileName.GetFullName() );
401
402 KIDIALOG errorDlg( m_parent, msg, _( "Confirmation" ),
403 wxOK | wxCANCEL | wxICON_WARNING );
404 errorDlg.SetOKCancelLabels( _( "Overwrite" ), _( "Skip" ) );
405 errorDlg.DoNotShowCheckbox( __FILE__, __LINE__ );
406
407 if( errorDlg.ShowModal() != wxID_OK )
408 continue;
409 }
410
411 bool skip_file = false;
412
413 while( 1 )
414 {
415 if( !fileName.IsDirWritable() )
416 {
417#ifndef __WXMAC__
418 wxString msg = wxString::Format( _( "Directory '%s' is not writable." ),
419 fileName.GetFullName() );
420#else
421 wxString msg = wxString::Format( _( "Folder '%s' is not writable." ),
422 fileName.GetPath() );
423#endif
424 // Don't set a 'do not show again' checkbox for this dialog
425 KIDIALOG errorDlg( m_parent, msg, _( "Error" ), wxYES_NO | wxCANCEL | wxICON_ERROR );
426 errorDlg.SetYesNoCancelLabels( _( "Retry" ), _( "Skip" ), _( "Cancel" ) );
427
428 int result = errorDlg.ShowModal();
429
430 if( result == wxID_CANCEL )
431 {
432 return;
433 }
434 else if( result == wxID_NO )
435 {
436 skip_file = true;
437 break;
438 }
439 }
440 else
441 {
442 break;
443 }
444 }
445
446 if( skip_file )
447 continue;
448
449
450 wxFFileOutputStream out( fileName.GetFullPath() );
451
452 if( !out.IsOk() )
453 {
454 wxString msg = wxString::Format( _( "Failed to open file '%s'." ),
455 fileName.GetFullName() );
456
457 KIDIALOG errorDlg( m_parent, msg, _( "Error" ), wxOK | wxICON_ERROR );
458 errorDlg.ShowModal();
459 continue;
460 }
461
462 out.Write( file->decompressedData.data(), file->decompressedData.size() );
463
464 if( !out.IsOk() || ( out.LastWrite() != file->decompressedData.size() ) )
465 {
466 wxString msg = wxString::Format( _( "Failed to write file '%s'." ),
467 fileName.GetFullName() );
468
469 KIDIALOG errorDlg( m_parent, msg, _( "Error" ), wxOK | wxICON_ERROR );
470
471 errorDlg.ShowModal();
472 }
473 }
474}
const char * name
Definition: DXF_plotter.cpp:59
wxBitmapBundle KiBitmapBundle(BITMAPS aBitmap, int aMinHeight)
Definition: bitmap.cpp:110
EMBEDDED_FILES_GRID_TRICKS(WX_GRID *aGrid)
void doPopupSelection(wxCommandEvent &event) override
void showPopupMenu(wxMenu &menu, wxGridEvent &aEvent) override
void RemoveFile(const wxString &name, bool aErase=true)
Remove a file from the collection and frees the memory.
EMBEDDED_FILE * GetEmbeddedFile(const wxString &aName) const
Returns the embedded file with the given name or nullptr if it does not exist.
bool HasFile(const wxString &name) const
void ClearEmbeddedFiles(bool aDeleteFiles=true)
virtual std::set< KIFONT::OUTLINE_FONT * > GetFonts() const
EMBEDDED_FILE * AddFile(const wxFileName &aName, bool aOverwrite)
Load a file from disk and adds it to the collection.
const std::map< wxString, EMBEDDED_FILE * > & EmbeddedFileMap() const
void SetAreFontsEmbedded(bool aEmbedFonts)
void SetFileAddedCallback(FileAddedCallback callback)
bool GetAreFontsEmbedded() const
Add mouse and command handling (such as cut, copy, and paste) to a WX_GRID instance.
Definition: grid_tricks.h:61
virtual void doPopupSelection(wxCommandEvent &event)
virtual void showPopupMenu(wxMenu &menu, wxGridEvent &aEvent)
WX_GRID * m_grid
I don't own the grid, but he owns me.
Definition: grid_tricks.h:125
Helper class to create more flexible dialogs, including 'do not show again' checkbox handling.
Definition: kidialog.h:43
void DoNotShowCheckbox(wxString file, int line)
Shows the 'do not show again' checkbox.
Definition: kidialog.cpp:51
bool SetOKCancelLabels(const ButtonLabel &ok, const ButtonLabel &cancel) override
Definition: kidialog.h:53
int ShowModal() override
Definition: kidialog.cpp:95
Class OUTLINE_FONT implements outline font drawing.
Definition: outline_font.h:53
Class PANEL_EMBEDDED_FILES_BASE.
bool RemoveEmbeddedFile(const wxString &aFileName)
EMBEDDED_FILES * m_files
PANEL_EMBEDDED_FILES(wxWindow *parent, EMBEDDED_FILES *aFiles)
void onFontEmbedClick(wxCommandEvent &event) override
void onAddEmbeddedFiles(wxCommandEvent &event) override
void onDeleteEmbeddedFile(wxCommandEvent &event) override
bool TransferDataToWindow() override
void onSize(wxSizeEvent &event) override
EMBEDDED_FILES * m_localFiles
void onExportFiles(wxCommandEvent &event) override
EMBEDDED_FILES::EMBEDDED_FILE * AddEmbeddedFile(const wxString &aFileName)
bool TransferDataFromWindow() override
void SetBitmap(const wxBitmapBundle &aBmp)
void EnableAlternateRowColors(bool aEnable=true)
Enable alternate row highlighting, where every odd row has a different background color than the even...
Definition: wx_grid.cpp:311
#define _(s)
static const std::string KiCadUriPrefix
This file is part of the common library.