KiCad PCB EDA Suite
Loading...
Searching...
No Matches
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 ),
45 m_curRow( -1 )
46{
47}
48
49
50void EMBEDDED_FILES_GRID_TRICKS::showPopupMenu( wxMenu& menu, wxGridEvent& aEvent )
51{
52 if( const int row = aEvent.GetRow(); row >= 0 && row < m_grid->GetNumberRows() )
53 {
54 m_curRow = row;
55 menu.Append( EMBEDDED_FILES_GRID_TRICKS_COPY_FILENAME, _( "Copy Embedded Reference" ),
56 _( "Copy the reference for this embedded file" ) );
57 menu.AppendSeparator();
58 GRID_TRICKS::showPopupMenu( menu, aEvent );
59 }
60 else
61 {
62 m_curRow = -1;
63 }
64}
65
66
68{
69 if( event.GetId() == EMBEDDED_FILES_GRID_TRICKS_COPY_FILENAME )
70 {
71 if( m_curRow >= 0 )
72 {
73 const wxString cellValue = m_grid->GetCellValue( m_curRow, 1 );
74
75 if( wxTheClipboard->Open() )
76 {
77 wxTheClipboard->SetData( new wxTextDataObject( cellValue ) );
78 wxTheClipboard->Close();
79 }
80 }
81 }
82 else
83 {
85 }
86}
87
88
89/* ---------- End of GRID_TRICKS for embedded files grid ---------- */
90
91
94 m_files( aFiles ),
95 m_localFiles( new EMBEDDED_FILES() )
96{
97 for( auto& [name, file] : m_files->EmbeddedFileMap() )
98 {
100 m_localFiles->AddFile( newFile );
101 }
102
103 // Set up the standard buttons
104 m_delete_button->SetBitmap( KiBitmapBundle( BITMAPS::small_trash ) );
105 m_browse_button->SetBitmap( KiBitmapBundle( BITMAPS::small_folder ) );
106 m_files_grid->SetMargins( 0 - wxSYS_VSCROLL_X, 0 );
108
109 m_files_grid->PushEventHandler( new EMBEDDED_FILES_GRID_TRICKS( m_files_grid ) );
110
113 {
114 for( int ii = 0; ii < m_files_grid->GetNumberRows(); ii++ )
115 {
116 if( m_files_grid->GetCellValue( ii, 1 ) == file->GetLink() )
117 {
118 m_files_grid->DeleteRows( ii );
119 break;
120 }
121 }
122
123 m_files_grid->AppendRows( 1 );
124 int ii = m_files_grid->GetNumberRows() - 1;
125 m_files_grid->SetCellValue( ii, 0, file->name );
126 m_files_grid->SetCellValue( ii, 1, file->GetLink() );
127
128 } );
129}
130
131
133{
134 // Remove the GRID_TRICKS handler
135 m_files_grid->PopEventHandler( true );
136}
137
138
139void PANEL_EMBEDDED_FILES::onSize( wxSizeEvent& event )
140{
141 resizeGrid();
142}
143
144
146{
147 int panel_width = GetClientRect().GetWidth();
148 int first_width = m_files_grid->GetColSize( 0 );
149 int second_width = m_files_grid->GetColSize( 1 );
150
151 double ratio;
152
153 if( first_width + second_width > 0 )
154 ratio = (double)first_width / (double)( first_width + second_width );
155 else
156 ratio = 0.3;
157
158
159 m_files_grid->SetColSize( 0, panel_width * ratio );
160 m_files_grid->SetColSize( 1, panel_width * ( 1 - ratio ) );
161 Layout();
162}
163
164
166{
167 m_files_grid->ClearGrid();
168
169 if( m_files_grid->GetNumberRows() > 0 )
170 m_files_grid->DeleteRows( 0, m_files_grid->GetNumberRows() );
171
172 int ii = 0;
173
174 for( auto& [name, file] : m_localFiles->EmbeddedFileMap() )
175 {
176 while( m_files_grid->GetNumberRows() < ii + 1 )
177 m_files_grid->AppendRows( 1 );
178
179 m_files_grid->SetCellValue( ii, 0, name );
180 m_files_grid->SetCellValue( ii, 1, file->GetLink() );
181
182 ii++;
183 }
184
186
187 resizeGrid();
188
189 return true;
190}
191
192
194{
196
197 std::vector<EMBEDDED_FILES::EMBEDDED_FILE*> files;
198
199 for( const auto& [name, file] : m_localFiles->EmbeddedFileMap() )
200 files.push_back( file );
201
202 for( EMBEDDED_FILES::EMBEDDED_FILE* file : files )
203 {
204 m_files->AddFile( file );
205 m_localFiles->RemoveFile( file->name, false );
206 }
207
209
210 return true;
211}
212
213
214void PANEL_EMBEDDED_FILES::onFontEmbedClick( wxCommandEvent& event )
215{
216 Freeze();
217 int row_pos = m_files_grid->GetGridCursorRow();
218 int col_pos = m_files_grid->GetGridCursorCol();
219 wxString row_name;
220
221 if( row_pos >= 0 )
222 row_name = m_files_grid->GetCellValue( row_pos, 0 );
223
224 for( int ii = 0; ii < m_files_grid->GetNumberRows(); ii++ )
225 {
226 wxString name = m_files_grid->GetCellValue( ii, 0 );
227
229
231 {
232 m_files_grid->DeleteRows( ii );
233 ii--;
235 }
236 }
237
238 if( m_cbEmbedFonts->IsChecked() )
239 {
240 std::set<KIFONT::OUTLINE_FONT*> fonts = m_files->GetFonts();
241
242 for( KIFONT::OUTLINE_FONT* font : fonts )
243 {
244 EMBEDDED_FILES::EMBEDDED_FILE* result = m_localFiles->AddFile( font->GetFileName(), true );
245
246 if( !result )
247 {
248 wxLogTrace( wxT( "KICAD_EMBED" ), wxString::Format( "Could not embed font %s",
249 font->GetFileName() ) );
250 continue;
251 }
252
253 m_files_grid->AppendRows( 1 );
254 int ii = m_files_grid->GetNumberRows() - 1;
255 m_files_grid->SetCellValue( ii, 0, result->name );
256 m_files_grid->SetCellValue( ii, 1, result->GetLink() );
257 }
258 }
259
260 if( row_pos >= 0 )
261 {
262 col_pos = std::max( std::min( col_pos, m_files_grid->GetNumberCols() - 1 ), 0 );
263 row_pos = std::max( std::min( row_pos, m_files_grid->GetNumberRows() - 1 ), 0 );
264 m_files_grid->SetGridCursor( row_pos, col_pos );
265
266 for( int ii = 0; ii < m_files_grid->GetNumberRows(); ++ii )
267 {
268 if( m_files_grid->GetCellValue( ii, 0 ) == row_name )
269 {
270 m_files_grid->SetGridCursor( ii, col_pos );
271 break;
272 }
273 }
274 }
275
276 Thaw();
277}
278
279
281{
282 wxFileName fileName( aFile );
283 wxString name = fileName.GetFullName();
284
285 if( m_localFiles->HasFile( name ) )
286 {
287 wxString msg = wxString::Format( _( "File '%s' already exists." ), name );
288
289 KIDIALOG errorDlg( m_parent, msg, _( "Confirmation" ), wxOK | wxCANCEL | wxICON_WARNING );
290 errorDlg.SetOKLabel( _( "Overwrite" ) );
291
292 if( errorDlg.ShowModal() != wxID_OK )
293 return nullptr;
294
295 for( int ii = 0; ii < m_files_grid->GetNumberRows(); ii++ )
296 {
297 if( m_files_grid->GetCellValue( ii, 0 ) == name )
298 {
299 m_files_grid->DeleteRows( ii );
300 break;
301 }
302 }
303 }
304
305 EMBEDDED_FILES::EMBEDDED_FILE* result = m_localFiles->AddFile( fileName, true );
306
307 if( !result )
308 {
309 wxString msg = wxString::Format( _( "Failed to add file '%s'." ), name );
310
311 KIDIALOG errorDlg( m_parent, msg, _( "Error" ), wxOK | wxICON_ERROR );
312 errorDlg.ShowModal();
313 return nullptr;
314 }
315
316 return result;
317}
318
319
320void PANEL_EMBEDDED_FILES::onAddEmbeddedFiles( wxCommandEvent& event )
321{
322 // TODO: Update strings to reflect that multiple files can be selected.
323 wxFileDialog fileDialog( this, _( "Select a file to embed" ), wxEmptyString, wxEmptyString,
324 _( "All Files" ) + wxT( " (*.*)|*.*" ),
325 wxFD_OPEN | wxFD_FILE_MUST_EXIST | wxFD_MULTIPLE );
326
327 if( fileDialog.ShowModal() == wxID_OK )
328 {
329 wxArrayString paths;
330 fileDialog.GetPaths( paths );
331
332 for( const wxString& path : paths )
334 }
335}
336
337
338bool PANEL_EMBEDDED_FILES::RemoveEmbeddedFile( const wxString& aFileName )
339{
340 wxString name = aFileName;
341
342 if( name.StartsWith( FILEEXT::KiCadUriPrefix ) )
343 name = name.Mid( FILEEXT::KiCadUriPrefix.size() + 3 );
344
345 int row = std::max( 0, m_files_grid->GetGridCursorRow() );
346
347 for( int ii = 0; ii < m_files_grid->GetNumberRows(); ii++ )
348 {
349 if( m_files_grid->GetCellValue( ii, 0 ) == name )
350 {
351 m_files_grid->DeleteRows( ii );
353
354 if( row < m_files_grid->GetNumberRows() )
355 m_files_grid->SetGridCursor( row, 0 );
356 else if( m_files_grid->GetNumberRows() > 0 )
357 m_files_grid->SetGridCursor( m_files_grid->GetNumberRows() - 1, 0 );
358
359 return true;
360 }
361 }
362
363 return false;
364}
365
366
368{
369 int row = m_files_grid->GetGridCursorRow();
370
371 if( row < 0 )
372 return;
373
374 wxString name = m_files_grid->GetCellValue( row, 0 );
375
377
378 m_files_grid->DeleteRows( row );
379
380 if( row < m_files_grid->GetNumberRows() )
381 m_files_grid->SetGridCursor( row, 0 );
382 else if( m_files_grid->GetNumberRows() > 0 )
383 m_files_grid->SetGridCursor( m_files_grid->GetNumberRows() - 1, 0 );
384}
385
386
387void PANEL_EMBEDDED_FILES::onExportFiles( wxCommandEvent& event )
388{
389 wxDirDialog dirDialog( this, _( "Select a directory to export files" ) );
390
391 if( dirDialog.ShowModal() != wxID_OK )
392 return;
393
394 wxString path = dirDialog.GetPath();
395
396 for( auto& [name, file] : m_localFiles->EmbeddedFileMap() )
397 {
398 wxFileName fileName( path, name );
399
400 if( fileName.FileExists() )
401 {
402 wxString msg = wxString::Format( _( "File '%s' already exists." ), fileName.GetFullName() );
403
404 KIDIALOG errorDlg( m_parent, msg, _( "Confirmation" ), wxOK | wxCANCEL | wxICON_WARNING );
405 errorDlg.SetOKCancelLabels( _( "Overwrite" ), _( "Skip" ) );
406 errorDlg.DoNotShowCheckbox( __FILE__, __LINE__ );
407
408 if( errorDlg.ShowModal() != wxID_OK )
409 continue;
410 }
411
412 bool skip_file = false;
413
414 while( 1 )
415 {
416 if( !fileName.IsDirWritable() )
417 {
418#ifndef __WXMAC__
419 wxString msg = wxString::Format( _( "Directory '%s' is not writable." ), fileName.GetFullName() );
420#else
421 wxString msg = wxString::Format( _( "Folder '%s' is not writable." ), fileName.GetPath() );
422#endif
423 // Don't set a 'do not show again' checkbox for this dialog
424 KIDIALOG errorDlg( m_parent, msg, _( "Error" ), wxYES_NO | wxCANCEL | wxICON_ERROR );
425 errorDlg.SetYesNoCancelLabels( _( "Retry" ), _( "Skip" ), _( "Cancel" ) );
426
427 int result = errorDlg.ShowModal();
428
429 if( result == wxID_CANCEL )
430 {
431 return;
432 }
433 else if( result == wxID_NO )
434 {
435 skip_file = true;
436 break;
437 }
438 }
439 else
440 {
441 break;
442 }
443 }
444
445 if( skip_file )
446 continue;
447
448
449 wxFFileOutputStream out( fileName.GetFullPath() );
450
451 if( !out.IsOk() )
452 {
453 wxString msg = wxString::Format( _( "Failed to open file '%s'." ), fileName.GetFullName() );
454
455 KIDIALOG errorDlg( m_parent, msg, _( "Error" ), wxOK | wxICON_ERROR );
456 errorDlg.ShowModal();
457 continue;
458 }
459
460 out.Write( file->decompressedData.data(), file->decompressedData.size() );
461
462 if( !out.IsOk() || ( out.LastWrite() != file->decompressedData.size() ) )
463 {
464 wxString msg = wxString::Format( _( "Failed to write file '%s'." ), fileName.GetFullName() );
465
466 KIDIALOG errorDlg( m_parent, msg, _( "Error" ), wxOK | wxICON_ERROR );
467
468 errorDlg.ShowModal();
469 }
470 }
471}
const char * name
Definition: DXF_plotter.cpp:62
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:50
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:60
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:308
#define _(s)
static const std::string KiCadUriPrefix
This file is part of the common library.