KiCad PCB EDA Suite
Loading...
Searching...
No Matches
gerbview/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) 2017 Jean-Pierre Charras, jp.charras at wanadoo.fr
5 * Copyright The KiCad Developers, see AUTHORS.txt for contributors.
6 *
7 * This program is free software; you can redistribute it and/or
8 * modify it under the terms of the GNU General Public License
9 * as published by the Free Software Foundation; either version 2
10 * of the License, or (at your option) any later version.
11 *
12 * This program is distributed in the hope that it will be useful,
13 * but WITHOUT ANY WARRANTY; without even the implied warranty of
14 * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
15 * GNU General Public License for more details.
16 *
17 * You should have received a copy of the GNU General Public License
18 * along with this program. If not, see <https://www.gnu.org/licenses/>.
19 */
20
21#include <memory>
22
23#include <wx/debug.h>
24#include <wx/filedlg.h>
25#include <wx/wfstream.h>
26#include <wx/zipstrm.h>
27#include <reporter.h>
29#include <gerbview_frame.h>
30#include <gerbview_id.h>
31#include <gerber_file_image.h>
33#include <excellon_image.h>
34#include <lset.h>
36#include <view/view.h>
39#include <tool/tool_manager.h>
40#include <kiplatform/ui.h>
41
42// HTML Messages used more than one time:
43#define MSG_NO_MORE_LAYER _( "<b>No more available layers</b> in GerbView to load files" )
44#define MSG_NOT_LOADED _( "<b>Not loaded:</b> <i>%s</i>" )
45#define MSG_OOM _( "<b>Memory was exhausted reading:</b> <i>%s</i>" )
46
47
48static bool isGerberFormatInsteadOfExcellon( const wxString& aFileName )
49{
51}
52
53
54void GERBVIEW_FRAME::OnGbrFileHistory( wxCommandEvent& event )
55{
56 wxString filename = GetFileFromHistory( event.GetId(), _( "Gerber files" ) );
57
58 if( !filename.IsEmpty() )
59 LoadGerberFiles( filename );
60}
61
62void GERBVIEW_FRAME::OnClearGbrFileHistory( wxCommandEvent& aEvent )
63{
65
66 if( GetMenuBar() )
67 {
69 GetMenuBar()->Refresh();
70 }
71}
72
73
74void GERBVIEW_FRAME::OnDrlFileHistory( wxCommandEvent& event )
75{
76 wxString filename = GetFileFromHistory( event.GetId(), _( "Drill files" ), &m_drillFileHistory );
77
78 if( !filename.IsEmpty() )
79 LoadExcellonFiles( filename );
80}
81
82
83void GERBVIEW_FRAME::OnClearDrlFileHistory( wxCommandEvent& aEvent )
84{
85 m_drillFileHistory.ClearFileHistory();
86
87 if( GetMenuBar() )
88 {
90 GetMenuBar()->Refresh();
91 }
92}
93
94
95void GERBVIEW_FRAME::OnZipFileHistory( wxCommandEvent& event )
96{
97 wxString filename = GetFileFromHistory( event.GetId(), _( "Zip files" ), &m_zipFileHistory );
98
99 if( !filename.IsEmpty() )
100 LoadZipArchiveFile( filename );
101}
102
103
104void GERBVIEW_FRAME::OnClearZipFileHistory( wxCommandEvent& aEvent )
105{
106 m_zipFileHistory.ClearFileHistory();
107
108 if( GetMenuBar() )
109 {
111 GetMenuBar()->Refresh();
112 }
113}
114
115
116void GERBVIEW_FRAME::OnJobFileHistory( wxCommandEvent& event )
117{
118 wxString filename = GetFileFromHistory( event.GetId(), _( "Job files" ), &m_jobFileHistory );
119
120 if( !filename.IsEmpty() )
121 LoadGerberJobFile( filename );
122}
123
124
125void GERBVIEW_FRAME::OnClearJobFileHistory( wxCommandEvent& aEvent )
126{
127 m_jobFileHistory.ClearFileHistory();
128
129 if( GetMenuBar() )
130 {
132 GetMenuBar()->Refresh();
133 }
134}
135
136
137bool GERBVIEW_FRAME::LoadFileOrShowDialog( const wxString& aFileName,
138 const wxString& dialogFiletypes,
139 const wxString& dialogTitle, const int filetype )
140{
141 static int lastGerberFileWildcard = 0;
142 wxArrayString filenamesList;
143 wxFileName filename = aFileName;
144 wxString currentPath;
145
146 if( !filename.IsOk() )
147 {
148 // Use the current working directory if the file name path does not exist.
149 if( filename.DirExists() )
150 currentPath = filename.GetPath();
151 else
152 {
153 currentPath = m_mruPath;
154
155 // On wxWidgets 3.1 (bug?) the path in wxFileDialog is ignored when
156 // finishing by the dir separator. Remove it if any:
157 if( currentPath.EndsWith( '\\' ) || currentPath.EndsWith( '/' ) )
158 currentPath.RemoveLast();
159 }
160
161 wxFileDialog dlg( this, dialogTitle, currentPath, filename.GetFullName(), dialogFiletypes,
162 wxFD_OPEN | wxFD_FILE_MUST_EXIST | wxFD_MULTIPLE | wxFD_CHANGE_DIR );
163
165
166 wxArrayString dummy1, dummy2;
167 const int nWildcards = wxParseCommonDialogsFilter( dialogFiletypes, dummy1, dummy2 );
168
169 if( lastGerberFileWildcard >= 0 && lastGerberFileWildcard < nWildcards )
170 dlg.SetFilterIndex( lastGerberFileWildcard );
171
172 if( dlg.ShowModal() == wxID_CANCEL )
173 return false;
174
175 lastGerberFileWildcard = dlg.GetFilterIndex();
176 dlg.GetPaths( filenamesList );
177 m_mruPath = currentPath = dlg.GetDirectory();
178 }
179 else
180 {
181 filenamesList.Add( aFileName );
182 currentPath = filename.GetPath();
183 m_mruPath = currentPath;
184 }
185
186 // Set the busy cursor
187 wxBusyCursor wait;
188
189 bool isFirstFile = GetImagesList()->GetLoadedImageCount() == 0;
190
191 std::vector<int> fileTypesVec( filenamesList.Count(), filetype );
192 bool success = LoadListOfGerberAndDrillFiles( currentPath, filenamesList, &fileTypesVec );
193
194 // Auto zoom / sort is only applied when no other files have been loaded
195 if( isFirstFile )
196 {
197 int ly = GetActiveLayer();
198
200 Zoom_Automatique( false );
201
202 // Ensure the initial active graphic layer is updated after sorting.
203 SetActiveLayer( ly, true );
204 }
205
206 return success;
207}
208
209
210bool GERBVIEW_FRAME::LoadAutodetectedFiles( const wxString& aFileName )
211{
212 // 2 = autodetect files
213 return LoadFileOrShowDialog( aFileName, FILEEXT::AllFilesWildcard(), _( "Open Autodetected File(s)" ),
214 2 );
215}
216
217
218bool GERBVIEW_FRAME::LoadGerberFiles( const wxString& aFileName )
219{
220 wxString filetypes;
221 wxFileName filename = aFileName;
222
223 /* Standard gerber filetypes
224 * (See http://en.wikipedia.org/wiki/Gerber_File)
225 * The .gbr (.pho in legacy files) extension is the default used in Pcbnew; however
226 * there are a lot of other extensions used for gerber files. Because the first letter
227 * is usually g, we accept g* as extension.
228 * (Mainly internal copper layers do not have specific extension, and filenames are like
229 * *.g1, *.g2 *.gb1 ...)
230 * Now (2014) Ucamco (the company which manages the Gerber format) encourages use of .gbr
231 * only and the Gerber X2 file format.
232 */
233 filetypes = _( "Gerber files" ) + wxT( " (*.g*; *.pho)|" )
234 + AddFileExtListToFilter( { "g*", "pho", "gbr", "gtl", "gbl", "gto", "gbo", "gts", "gbs",
235 "gtp", "gbp", "gta", "gba", "gko", "gpt", "gpb", "gm1", "gm2",
236 "gm3", "gm4", "gm5", "gm6", "gm7", "gm8", "gm9", "g1", "g2",
237 "g3", "g4", "g5", "g6", "g7", "g8", "g9" } )
238 .AfterFirst( '|' )
239 + wxT( "|" );
240
241 /* Special gerber filetypes */
242 filetypes += _( "Top layer" ) + AddFileExtListToFilter( { "gtl" } ) + wxT( "|" );
243 filetypes += _( "Bottom layer" ) + AddFileExtListToFilter( { "gbl" } ) + wxT( "|" );
244 filetypes += _( "Bottom solder resist" ) + AddFileExtListToFilter( { "gbs" } ) + wxT( "|" );
245 filetypes += _( "Top solder resist" ) + AddFileExtListToFilter( { "gts" } ) + wxT( "|" );
246 filetypes += _( "Bottom overlay" ) + AddFileExtListToFilter( { "gbo" } ) + wxT( "|" );
247 filetypes += _( "Top overlay" ) + AddFileExtListToFilter( { "gto" } ) + wxT( "|" );
248 filetypes += _( "Bottom paste" ) + AddFileExtListToFilter( { "gbp" } ) + wxT( "|" );
249 filetypes += _( "Top paste" ) + AddFileExtListToFilter( { "gtp" } ) + wxT( "|" );
250 filetypes += _( "Keep-out layer" ) + AddFileExtListToFilter( { "gko" } ) + wxT( "|" );
251 filetypes += _( "Mechanical layers" )
253 { "gm1", "gm2", "gm3", "gm4", "gm5", "gm6", "gm7", "gm8", "gm9" } )
254 + wxT( "|" );
255 filetypes += _( "Top Pad Master" ) + AddFileExtListToFilter( { "gpt" } ) + wxT( "|" );
256 filetypes += _( "Bottom Pad Master" ) + AddFileExtListToFilter( { "gpb" } ) + wxT( "|" );
257
258 // All filetypes
259 filetypes += FILEEXT::AllFilesWildcard();
260
261 // 0 = gerber files
262 return LoadFileOrShowDialog( aFileName, filetypes, _( "Open Gerber File(s)" ), 0 );
263}
264
265
266bool GERBVIEW_FRAME::LoadExcellonFiles( const wxString& aFileName )
267{
268 wxString filetypes = FILEEXT::DrillFileWildcard();
269 filetypes << wxT( "|" );
270 filetypes += FILEEXT::AllFilesWildcard();
271
272 // 1 = drill files
273 return LoadFileOrShowDialog( aFileName, filetypes, _( "Open NC (Excellon) Drill File(s)" ), 1 );
274}
275
276
278 const wxArrayString& aFilenameList,
279 std::vector<int>* aFileType )
280{
281 wxCHECK_MSG( aFilenameList.Count() == aFileType->size(), false,
282 "Mismatch in file names and file types count" );
283
284 wxFileName filename;
285
286 // Read gerber files: each file is loaded on a new GerbView layer
287 bool success = true;
288 int layer = GetActiveLayer();
289 int firstLoadedLayer = NO_AVAILABLE_LAYERS;
291
292 // Manage errors when loading files
294
295 // Create progress dialog (only used if more than 1 file to load
296 std::unique_ptr<WX_PROGRESS_REPORTER> progress = nullptr;
297
298 for( unsigned ii = 0; ii < aFilenameList.GetCount(); ii++ )
299 {
300 filename = aFilenameList[ii];
301
302 if( !filename.IsAbsolute() )
303 filename.SetPath( aPath );
304
305 // Check for non existing files, to avoid creating broken or useless data
306 // and report all in one error list:
307 if( !filename.FileExists() )
308 {
309 wxString warning;
310 warning << wxT( "<b>" ) << _( "File not found:" ) << wxT( "</b><br>" )
311 << filename.GetFullPath() << wxT( "<br>" );
312 reporter.Report( warning, RPT_SEVERITY_WARNING );
313 success = false;
314 continue;
315 }
316
317 if( filename.GetExt() == FILEEXT::GerberJobFileExtension.c_str() )
318 {
319 //We cannot read a gerber job file as a gerber plot file: skip it
320 wxString txt;
321 txt.Printf( _( "<b>A gerber job file cannot be loaded as a plot file</b> "
322 "<i>%s</i>" ),
323 filename.GetFullName() );
324 success = false;
325 reporter.Report( txt, RPT_SEVERITY_ERROR );
326 continue;
327 }
328
329
330 m_lastFileName = filename.GetFullPath();
331
332 if( !progress && ( aFilenameList.GetCount() > 1 ) )
333 {
334 progress = std::make_unique<WX_PROGRESS_REPORTER>( this, _( "Load Files" ), 1, PR_CAN_ABORT );
335 progress->SetMaxProgress( aFilenameList.GetCount() - 1 );
336 progress->Report( wxString::Format( _("Loading %u/%zu %s..." ),
337 ii+1,
338 aFilenameList.GetCount(),
339 m_lastFileName ) );
340 }
341 else if( progress )
342 {
343 progress->Report( wxString::Format( _("Loading %u/%zu %s..." ),
344 ii+1,
345 aFilenameList.GetCount(),
346 m_lastFileName ) );
347 progress->KeepRefreshing();
348 }
349
350
351 // Make sure we have a layer available to load into
352 layer = getNextAvailableLayer();
353
354 if( layer == NO_AVAILABLE_LAYERS )
355 {
356 success = false;
358
359 // Report the name of not loaded files:
360 while( ii < aFilenameList.GetCount() )
361 {
362 filename = aFilenameList[ii++];
363 wxString txt = wxString::Format( MSG_NOT_LOADED, filename.GetFullName() );
364 reporter.Report( txt, RPT_SEVERITY_ERROR );
365 }
366 break;
367 }
368
369 SetActiveLayer( layer, false );
370 visibility[ layer ] = true;
371
372 try
373 {
374 // 2 = Autodetect
375 if( ( *aFileType )[ii] == 2 )
376 {
377 if( EXCELLON_IMAGE::TestFileIsExcellon( filename.GetFullPath() ) )
378 ( *aFileType )[ii] = 1;
379 else if( GERBER_FILE_IMAGE::TestFileIsRS274( filename.GetFullPath() ) )
380 ( *aFileType )[ii] = 0;
381 }
382 else if( ( *aFileType )[ii] == 1 && isGerberFormatInsteadOfExcellon( filename.GetFullPath() ) )
383 {
384 // A file selected as drill data can use the Gerber format.
385 ( *aFileType )[ii] = 0;
386 }
387
388 bool read_ok = false;
389
390 switch( ( *aFileType )[ii] )
391 {
392 case 0:
393
394 read_ok = Read_GERBER_File( filename.GetFullPath() );
395
396 if( read_ok )
397 {
398 UpdateFileHistory( filename.GetFullPath() );
399
400 if( firstLoadedLayer == NO_AVAILABLE_LAYERS )
401 {
402 firstLoadedLayer = layer;
403 }
404 }
405
406 break;
407
408 case 1:
409
410 read_ok = Read_EXCELLON_File( filename.GetFullPath() );
411
412 if( read_ok )
413 {
414 UpdateFileHistory( filename.GetFullPath(), &m_drillFileHistory );
415
416 // Select the first added layer by default when done loading
417 if( firstLoadedLayer == NO_AVAILABLE_LAYERS )
418 {
419 firstLoadedLayer = layer;
420 }
421 }
422
423 break;
424 default:
425 break;
426 }
427
428 if( !read_ok )
429 {
430 success = false;
431 wxString txt = wxString::Format( MSG_NOT_LOADED, filename.GetFullName() );
432 reporter.Report( txt, RPT_SEVERITY_ERROR );
433 }
434 }
435 catch( const std::bad_alloc& )
436 {
437 wxString txt = wxString::Format( MSG_OOM, filename.GetFullName() );
438 reporter.Report( txt, RPT_SEVERITY_ERROR );
439 success = false;
440 continue;
441 }
442
443 if( progress )
444 progress->AdvanceProgress();
445 }
446
447 if( !success )
448 {
449 wxSafeYield(); // Allows slice of time to redraw the screen
450 // to refresh widgets, before displaying messages
451 HTML_MESSAGE_BOX mbox( this, _( "Errors" ) );
452 mbox.ListSet( reporter.GetMessages() );
453 mbox.ShowModal();
454 }
455
457
458 if( firstLoadedLayer != NO_AVAILABLE_LAYERS )
459 SetActiveLayer( firstLoadedLayer, true );
460
461 // Synchronize layers tools with actual active layer:
463
464 m_LayersManager->UpdateLayerIcons();
465 syncLayerBox( true );
466
467 GetCanvas()->Refresh();
468
469 return success;
470}
471
472
473bool GERBVIEW_FRAME::unarchiveFiles( const wxString& aFullFileName, REPORTER* aReporter, const wxArrayString* aMembers )
474{
475 bool foundX2Gerbers = false;
476 wxString msg;
477 int firstLoadedLayer = NO_AVAILABLE_LAYERS;
479
480 wxFFileInputStream zipFile( aFullFileName );
481
482 if( !zipFile.IsOk() )
483 {
484 if( aReporter )
485 {
486 msg.Printf( _( "Zip file '%s' cannot be opened." ), aFullFileName );
487 aReporter->Report( msg, RPT_SEVERITY_ERROR );
488 }
489
490 return false;
491 }
492
493 // Update the list of recent zip files.
494 UpdateFileHistory( aFullFileName, &m_zipFileHistory );
495
496 // The archive may live somewhere unwritable, such as a read-only network share, so unzip
497 // to the system temp dir rather than next to the archive
498 // TODO: make Read_GERBER_File() and Read_EXCELLON_File() able to
499 // accept a stream, and avoid using a temp file.
500 wxString unzipped_tempfile = wxFileName::CreateTempFileName( wxS( "gerbview" ) );
501
502 if( unzipped_tempfile.IsEmpty() )
503 {
504 if( aReporter )
505 {
506 msg.Printf( _( "Unable to create a temporary file to unzip '%s'." ), aFullFileName );
507 aReporter->Report( msg, RPT_SEVERITY_ERROR );
508 }
509
510 return false;
511 }
512
513 bool success = true;
514 wxZipInputStream zipArchive( zipFile );
515 bool reported_no_more_layer = false;
516 KIGFX::VIEW* view = GetCanvas()->GetView();
517
518 while( std::unique_ptr<wxZipEntry> entry{ zipArchive.GetNextEntry() } )
519 {
520 if( entry->IsDir() )
521 continue;
522
523 wxString fname = entry->GetName();
524
525 if( aMembers && aMembers->Index( fname ) == wxNOT_FOUND )
526 continue;
527
528 wxFileName uzfn = fname;
529 wxString curr_ext = uzfn.GetExt().Lower();
530
531 // The archive contains Gerber and/or Excellon drill files. Use the right loader.
532 // However it can contain a few other files (reports, pdf files...),
533 // which will be skipped.
534 if( curr_ext == FILEEXT::GerberJobFileExtension.c_str() )
535 {
536 //We cannot read a gerber job file as a gerber plot file: skip it
537 if( aReporter )
538 {
539 msg.Printf( _( "Skipped file '%s' (gerber job file)." ), entry->GetName() );
540 aReporter->Report( msg, RPT_SEVERITY_WARNING );
541 }
542
543 continue;
544 }
545
546 wxString matchedExt;
547 enum GERBER_ORDER_ENUM order;
548 GERBER_FILE_IMAGE_LIST::GetGerberLayerFromFilename( fname, order, matchedExt );
549
550 int layer = getNextAvailableLayer();
551
552 if( layer == NO_AVAILABLE_LAYERS )
553 {
554 success = false;
555
556 if( aReporter )
557 {
558 if( !reported_no_more_layer )
560
561 reported_no_more_layer = true;
562
563 // Report the name of not loaded files:
564 msg.Printf( MSG_NOT_LOADED, entry->GetName() );
565 aReporter->Report( msg, RPT_SEVERITY_ERROR );
566 }
567
568 continue;
569 }
570
571 SetActiveLayer( layer, false );
572
573 // Create the unzipped temporary file:
574 {
575 wxFFileOutputStream temporary_ofile( unzipped_tempfile );
576
577 if( !temporary_ofile.Ok() )
578 {
579 success = false;
580
581 if( aReporter )
582 {
583 msg.Printf( _( "<b>Unable to create temporary file '%s'.</b>" ),
584 unzipped_tempfile );
585 aReporter->Report( msg, RPT_SEVERITY_ERROR );
586 }
587
588 // Parsing the temp file now would read whatever the previous entry left in it
589 continue;
590 }
591
592 temporary_ofile.Write( zipArchive );
593
594 // IsOk() reports a closed stream as not-ok, so capture the write result first. A short
595 // write leaves a truncated file that TestFileIsRS274() still accepts as valid artwork
596 const bool writeOk = temporary_ofile.IsOk();
597 const bool closeOk = temporary_ofile.Close();
598
599 if( !writeOk || !closeOk )
600 {
601 success = false;
602
603 if( aReporter )
604 {
605 msg.Printf( _( "<b>Unable to write temporary file '%s'.</b>" ),
606 unzipped_tempfile );
607 aReporter->Report( msg, RPT_SEVERITY_ERROR );
608 }
609
610 continue;
611 }
612 }
613
614 // Use the file extension as a fallback when the format tests are inconclusive.
615 bool isDrillExt = order == GERBER_ORDER_ENUM::GERBER_DRILL;
616 bool isUnknownExt = order == GERBER_ORDER_ENUM::GERBER_LAYER_UNKNOWN;
617
618 // Drill data may use the Gerber format despite its filename.
619 bool isGerberDrill = isDrillExt && isGerberFormatInsteadOfExcellon( unzipped_tempfile );
620 bool isExcellonDrill = ( isDrillExt && !isGerberDrill )
621 || ( isUnknownExt && EXCELLON_IMAGE::TestFileIsExcellon( unzipped_tempfile ) );
622 bool isGerberLayer =
623 !isDrillExt
624 && ( !isUnknownExt || ( !isExcellonDrill && GERBER_FILE_IMAGE::TestFileIsRS274( unzipped_tempfile ) ) );
625
626 if( !isExcellonDrill && !isGerberDrill && !isGerberLayer )
627 {
628 if( aReporter )
629 {
630 msg.Printf( _( "Skipped file '%s' (unknown type)." ), entry->GetName() );
631 aReporter->Report( msg, RPT_SEVERITY_WARNING );
632 }
633
634 continue;
635 }
636
637 bool read_ok = true;
638
639 if( isExcellonDrill )
640 {
641 read_ok = Read_EXCELLON_File( unzipped_tempfile );
642 }
643 else if( isGerberDrill || isGerberLayer )
644 {
645 // Read gerber files: each file is loaded on a new GerbView layer
646 read_ok = Read_GERBER_File( unzipped_tempfile );
647
648 if( read_ok )
649 {
650 if( GERBER_FILE_IMAGE* gbrImage = GetGbrImage( layer ) )
651 view->SetLayerHasNegatives( GERBER_DRAW_LAYER( layer ), gbrImage->HasNegativeItems() );
652 }
653 }
654
655 // Select the first added layer by default when done loading
656 if( read_ok && firstLoadedLayer == NO_AVAILABLE_LAYERS )
657 {
658 firstLoadedLayer = layer;
659 }
660
661 if( !read_ok )
662 {
663 success = false;
664
665 if( aReporter )
666 {
667 msg.Printf( _( "<b>unzipped file %s read error</b>" ), unzipped_tempfile );
668 aReporter->Report( msg, RPT_SEVERITY_ERROR );
669 }
670 }
671 else
672 {
673 GERBER_FILE_IMAGE* gerber_image = GetGbrImage( layer );
674 visibility[ layer ] = true;
675
676 if( gerber_image )
677 {
678 gerber_image->m_FileName = fname;
679 gerber_image->m_ArchiveFileName = aFullFileName;
680 if( gerber_image->m_IsX2_file )
681 foundX2Gerbers = true;
682 }
683
684 layer = getNextAvailableLayer();
685 SetActiveLayer( layer, false );
686 }
687 }
688
689 wxRemoveFile( unzipped_tempfile );
690
691 if( foundX2Gerbers )
693 else
695
697
698 // Select the first layer loaded so we don't show another layer on top after
699 if( firstLoadedLayer != NO_AVAILABLE_LAYERS )
700 SetActiveLayer( firstLoadedLayer, true );
701
702 return success;
703}
704
705
706bool GERBVIEW_FRAME::LoadZipArchiveFile( const wxString& aFullFileName, const wxArrayString* aMembers )
707{
708#define ZipFileExtension "zip"
709
710 wxFileName filename = aFullFileName;
711 wxString currentPath;
712
713 if( !filename.IsOk() )
714 {
715 // Use the current working directory if the file name path does not exist.
716 if( filename.DirExists() )
717 currentPath = filename.GetPath();
718 else
719 currentPath = m_mruPath;
720
721 wxFileDialog dlg( this, _( "Open Zip File" ), currentPath, filename.GetFullName(),
723 wxFD_OPEN | wxFD_FILE_MUST_EXIST | wxFD_CHANGE_DIR );
724
726
727 if( dlg.ShowModal() == wxID_CANCEL )
728 return false;
729
730 filename = dlg.GetPath();
731 currentPath = wxGetCwd();
732 m_mruPath = currentPath;
733 }
734 else
735 {
736 currentPath = filename.GetPath();
737 m_mruPath = currentPath;
738 }
739
741
742 if( filename.IsOk() )
743 unarchiveFiles( filename.GetFullPath(), &reporter, aMembers );
744
745 Zoom_Automatique( false );
746
747 // Synchronize layers tools with actual active layer:
750 m_LayersManager->UpdateLayerIcons();
751 syncLayerBox();
752
753 if( reporter.HasMessage() )
754 {
755 wxSafeYield(); // Allows slice of time to redraw the screen
756 // to refresh widgets, before displaying messages
757 HTML_MESSAGE_BOX mbox( this, _( "Messages" ) );
758 mbox.ListSet( reporter.GetMessages() );
759 mbox.ShowModal();
760 }
761
762 return true;
763}
764
765
767{
768 m_drillFileHistory.ClearFileHistory();
769 m_zipFileHistory.ClearFileHistory();
770 m_jobFileHistory.ClearFileHistory();
771
773}
774
775
777{
778 wxString gerbFn; // param to be sent with action event.
779
780 for( const wxFileName& file : m_AcceptedFiles )
781 {
782 if( file.GetExt() == FILEEXT::ArchiveFileExtension )
783 {
784 wxString fn = file.GetFullPath();
785 // Open zip archive in editor
786 m_toolManager->RunAction<wxString*>( *m_acceptedExts.at( FILEEXT::ArchiveFileExtension ), &fn );
787 }
788 else
789 {
790 // Store FileName in variable to open later
791 gerbFn += '"' + file.GetFullPath() + '"';
792 }
793 }
794
795 // Open files in editor
796 if( !gerbFn.IsEmpty() )
797 m_toolManager->RunAction<wxString*>( *m_acceptedExts.at( FILEEXT::GerberFileExtension ), &gerbFn );
798}
int ShowModal() override
std::vector< wxFileName > m_AcceptedFiles
void UpdateFileHistory(const wxString &FullFileName, FILE_HISTORY *aFileHistory=nullptr)
Update the list of recently opened files.
FILE_HISTORY & GetFileHistory()
Get the frame's main file history.
virtual void ClearFileHistory()
Remove all files from the file history.
std::map< const wxString, TOOL_ACTION * > m_acceptedExts
Associate file extensions with action to execute.
wxString GetFileFromHistory(int cmdId, const wxString &type, FILE_HISTORY *aFileHistory=nullptr)
Fetch the file name from the file history list.
void ReCreateMenuBar()
Recreate the menu bar.
virtual void Zoom_Automatique(bool aWarpPointer)
Redraw the screen with best zoom level and the best centering that shows all the page or the board.
virtual EDA_DRAW_PANEL_GAL * GetCanvas() const
Return a pointer to GAL-based canvas of given EDA draw frame.
virtual KIGFX::VIEW * GetView() const
Return a pointer to the KIGFX::VIEW instance used in the panel.
virtual void Refresh(bool aEraseBackground=true, const wxRect *aRect=nullptr) override
static bool TestFileIsExcellon(const wxString &aFullFileName)
Performs a heuristics-based check of whether the file is an Excellon drill file.
void ClearFileHistory()
Clear all entries from the file history.
unsigned GetLoadedImageCount()
Get number of loaded images.
static void GetGerberLayerFromFilename(const wxString &filename, enum GERBER_ORDER_ENUM &order, wxString &matchedExtension)
Utility function to guess which PCB layer of a gerber/drill file corresponds to based on its file ext...
Hold the image data and parameters for one gerber file and layer parameters.
wxString m_FileName
Full File Name for this layer.
static bool TestFileIsRS274(const wxString &aFullFileName)
Performs a heuristics-based check of whether the file is an RS274 gerber file.
Definition readgerb.cpp:143
bool m_IsX2_file
True if a X2 gerber attribute was found in file.
wxString m_ArchiveFileName
Archive containing this layer, if loaded from a ZIP file.
void OnDrlFileHistory(wxCommandEvent &event)
Delete the current data and load a drill file in Excellon format selected from history list on curren...
void SortLayersByX2Attributes()
LSET GetVisibleLayers() const
A proxy function that calls the correspondent function in m_BoardSettings.
bool Read_EXCELLON_File(const wxString &aFullFileName)
bool LoadFileOrShowDialog(const wxString &aFileName, const wxString &dialogFiletypes, const wxString &dialogTitle, const int filetype)
Loads the file provided or shows a dialog to get the file(s) from the user.
bool LoadGerberJobFile(const wxString &aFileName)
Load a Gerber job file, and load gerber files found in job files.
void OnClearDrlFileHistory(wxCommandEvent &aEvent)
GERBER_FILE_IMAGE_LIST * GetImagesList() const
Accessors to GERBER_FILE_IMAGE_LIST and GERBER_FILE_IMAGE data.
wxString m_lastFileName
void syncLayerBox(bool aRebuildLayerBox=false)
Update the currently "selected" layer within m_SelLayerBox.
bool LoadGerberFiles(const wxString &aFileName)
Load a given Gerber file or selected file(s), if the filename is empty.
FILE_HISTORY m_jobFileHistory
void OnJobFileHistory(wxCommandEvent &event)
Delete the current data and load a gerber job file selected from the history list.
bool LoadZipArchiveFile(const wxString &aFileName, const wxArrayString *aMembers=nullptr)
Load a zipped archive file.
void OnZipFileHistory(wxCommandEvent &event)
Delete the current data and load a zip archive file selected from the history list.
int GetActiveLayer() const
Return the active layer.
GERBER_LAYER_WIDGET * m_LayersManager
void SetActiveLayer(int aLayer, bool doLayerWidgetUpdate=true)
change the currently active layer to aLayer and update the GERBER_LAYER_WIDGET.
void SetVisibleLayers(const LSET &aLayerMask)
A proxy function that calls the correspondent function in m_BoardSettings.
void ClearFileHistory() override
Remove all files from the file history.
bool Read_GERBER_File(const wxString &GERBER_FullFileName)
Definition readgerb.cpp:37
void SortLayersByFileExtension()
GERBER_FILE_IMAGE * GetGbrImage(int aIdx) const
bool LoadListOfGerberAndDrillFiles(const wxString &aPath, const wxArrayString &aFilenameList, std::vector< int > *aFileType)
Load a list of Gerber and NC drill files and updates the view based on them.
bool LoadAutodetectedFiles(const wxString &aFileName)
Load a given file or selected file(s), if the filename is empty.
void ReFillLayerWidget()
Change out all the layers in m_Layers; called upon loading new gerber files.
FILE_HISTORY m_zipFileHistory
int getNextAvailableLayer() const
Find the next empty layer.
void OnClearGbrFileHistory(wxCommandEvent &aEvent)
bool unarchiveFiles(const wxString &aFullFileName, REPORTER *aReporter=nullptr, const wxArrayString *aMembers=nullptr)
Extract gerber and drill files from the zip archive, and load them.
void OnClearZipFileHistory(wxCommandEvent &aEvent)
void DoWithAcceptedFiles() override
Execute action on accepted dropped file.
void OnGbrFileHistory(wxCommandEvent &event)
Delete the current data and loads a Gerber file selected from history list on current layer.
FILE_HISTORY m_drillFileHistory
bool LoadExcellonFiles(const wxString &aFileName)
Load a drill (EXCELLON) file or many files.
void OnClearJobFileHistory(wxCommandEvent &aEvent)
void ListSet(const wxString &aList)
Add a list of items.
Hold a (potentially large) number of VIEW_ITEMs and renders them on a graphics device provided by the...
Definition view.h:63
void SetLayerHasNegatives(int aLayer, bool aNegatives=true)
Set the status of negatives presense in a particular layer.
Definition view.h:475
LSET is a set of PCB_LAYER_IDs.
Definition lset.h:37
A pure virtual class used to derive REPORTER objects from.
Definition reporter.h:73
virtual REPORTER & Report(const wxString &aText, SEVERITY aSeverity=RPT_SEVERITY_UNDEFINED)
Report a string with a given severity.
Definition reporter.h:102
TOOL_MANAGER * m_toolManager
A wrapper for reporting to a wxString object.
Definition reporter.h:242
#define _(s)
static bool isGerberFormatInsteadOfExcellon(const wxString &aFileName)
#define MSG_NOT_LOADED
#define MSG_OOM
#define MSG_NO_MORE_LAYER
#define NO_AVAILABLE_LAYERS
static const std::string GerberJobFileExtension
static const std::string GerberFileExtension
static const std::string ArchiveFileExtension
static wxString AllFilesWildcard()
static wxString DrillFileWildcard()
static wxString ZipFileWildcard()
#define GERBER_DRAW_LAYER(x)
Definition layer_ids.h:562
void AllowNetworkFileSystems(wxDialog *aDialog)
Configure a file dialog to show network and virtual file systems.
Definition wxgtk/ui.cpp:533
@ RPT_SEVERITY_WARNING
@ RPT_SEVERITY_ERROR
IbisParser parser & reporter
wxString AddFileExtListToFilter(const std::vector< std::string > &aExts)
Build the wildcard extension file dialog wildcard filter to add to the base message dialog.
Definition of file extensions used in Kicad.
#define PR_CAN_ABORT