KiCad PCB EDA Suite
Loading...
Searching...
No Matches
dialog_export_2581.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 modify it
7 * under the terms of the GNU General Public License as published by the
8 * Free Software Foundation, either version 3 of the License, or (at your
9 * option) any later version.
10 *
11 * This program is distributed in the hope that it will be useful, but
12 * WITHOUT ANY WARRANTY; without even the implied warranty of
13 * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU
14 * General Public License for more details.
15 *
16 * You should have received a copy of the GNU General Public License along
17 * with this program. If not, see <http://www.gnu.org/licenses/>.
18 */
19
21
22#include <set>
23#include <map>
24#include <vector>
25
26#include <wx/filedlg.h>
27#include <wx/filefn.h>
28#include <kiplatform/ui.h>
29
30#include <board.h>
31#include <footprint.h>
32#include <kiway_holder.h>
33#include <pcb_edit_frame.h>
34#include <pcbnew_settings.h>
35#include <pgm_base.h>
36#include <project.h>
38#include <pcb_io/pcb_io_mgr.h>
42#include <string_utils.h>
45#include <wx_filename.h>
46
47
48
50 DIALOG_EXPORT_2581_BASE( aParent ),
51 m_parent( aParent ),
52 m_job( nullptr )
53{
55
56 SetupStandardButtons( { { wxID_OK, _( "Export" ) },
57 { wxID_CANCEL, _( "Close" ) } } );
58
59 // DIALOG_SHIM needs a unique hash_key because classname will be the same for both job and
60 // non-job versions.
61 m_hash_key = TO_UTF8( GetTitle() );
62
63 init();
64
65 // Now all widgets have the size fixed, call FinishDialogSettings
67}
68
69
71 wxWindow* aParent ) :
72 DIALOG_EXPORT_2581_BASE( aParent ),
73 m_parent( aEditFrame ),
74 m_job( aJob )
75{
76 m_browseButton->Hide();
77
79
80 SetTitle( m_job->GetSettingsDialogTitle() );
81
82 // DIALOG_SHIM needs a unique hash_key because classname will be the same for both job and
83 // non-job versions.
84 m_hash_key = TO_UTF8( GetTitle() );
85
86 init();
87
88 // Now all widgets have the size fixed, call FinishDialogSettings
90}
91
92
93void DIALOG_EXPORT_2581::onBrowseClicked( wxCommandEvent& event )
94{
95 // Build the absolute path of current output directory to preselect it in the file browser.
96 wxString path = ExpandEnvVarSubstitutions( m_outputFileName->GetValue(), &Prj() );
97 wxFileName fn( Prj().AbsolutePath( path ) );
98 wxString ipc_files = _( "IPC-2581 Files (*.xml)|*.xml" );
99 wxString compressed_files = _( "IPC-2581 Compressed Files (*.zip)|*.zip" );
100
101 wxFileDialog dlg( this, _( "Export IPC-2581 File" ), fn.GetPath(), fn.GetFullName(),
102 m_cbCompress->IsChecked() ? compressed_files : ipc_files,
103 wxFD_SAVE | wxFD_OVERWRITE_PROMPT );
104
106
107 if( dlg.ShowModal() == wxID_CANCEL )
108 return;
109
110 m_outputFileName->SetValue( dlg.GetPath() );
111
112}
113
114void DIALOG_EXPORT_2581::onCompressCheck( wxCommandEvent& event )
115{
116 if( m_cbCompress->GetValue() )
117 {
118 wxFileName fn = m_outputFileName->GetValue();
119
120 fn.SetExt( "zip" );
121 m_outputFileName->SetValue( fn.GetFullPath() );
122 }
123 else
124 {
125 wxFileName fn = m_outputFileName->GetValue();
126
127 fn.SetExt( "xml" );
128 m_outputFileName->SetValue( fn.GetFullPath() );
129 }
130}
131
132
133void DIALOG_EXPORT_2581::onMfgPNChange( wxCommandEvent& event )
134{
135 if( event.GetSelection() == 0 )
136 {
137 m_choiceMfg->Enable( false );
138 }
139 else
140 {
141 m_choiceMfg->Enable( true );
142
143 // Don't try to guess the manufacturer if the user has already selected one
144 if( m_choiceMfg->GetSelection() > 0 )
145 return;
146
147 int it = 0;
148
149 if( it = m_choiceMfg->FindString( wxT( "manufacturer" ) ); it != wxNOT_FOUND )
150 m_choiceMfg->Select( it );
151 else if( it = m_choiceMfg->FindString( _( "manufacturer" ) ); it != wxNOT_FOUND )
152 m_choiceMfg->Select( it );
153 else if( it = m_choiceMfg->FindString( wxT( "mfg" ) ); it != wxNOT_FOUND )
154 m_choiceMfg->Select( it );
155 else if( it = m_choiceMfg->FindString( _( "mfg" ) ); it != wxNOT_FOUND )
156 m_choiceMfg->Select( it );
157 }
158}
159
160
161void DIALOG_EXPORT_2581::onDistPNChange( wxCommandEvent& event )
162{
163 if( event.GetSelection() == 0 )
164 {
165 m_textDistributor->Enable( false );
166 m_textDistributor->SetValue( _( "N/A" ) );
167 }
168 else
169 {
170 m_textDistributor->Enable( true );
171
172 // Don't try to guess the distributor if the user has already selected one
173 if( m_textDistributor->GetValue() != _( "N/A" ) )
174 return;
175
176 wxString dist = m_choiceDistPN->GetStringSelection();
177 dist.MakeUpper();
178
179 // Try to guess the distributor from the part number column
180
181 if( dist.Contains( wxT( "DIGIKEY" ) ) )
182 {
183 m_textDistributor->SetValue( wxT( "Digi-Key" ) );
184 }
185 else if( dist.Contains( wxT( "DIGI-KEY" ) ) )
186 {
187 m_textDistributor->SetValue( wxT( "Digi-Key" ) );
188 }
189 else if( dist.Contains( wxT( "MOUSER" ) ) )
190 {
191 m_textDistributor->SetValue( wxT( "Mouser" ) );
192 }
193 else if( dist.Contains( wxT( "NEWARK" ) ) )
194 {
195 m_textDistributor->SetValue( wxT( "Newark" ) );
196 }
197 else if( dist.Contains( wxT( "RS COMPONENTS" ) ) )
198 {
199 m_textDistributor->SetValue( wxT( "RS Components" ) );
200 }
201 else if( dist.Contains( wxT( "FARNELL" ) ) )
202 {
203 m_textDistributor->SetValue( wxT( "Farnell" ) );
204 }
205 else if( dist.Contains( wxT( "ARROW" ) ) )
206 {
207 m_textDistributor->SetValue( wxT( "Arrow" ) );
208 }
209 else if( dist.Contains( wxT( "AVNET" ) ) )
210 {
211 m_textDistributor->SetValue( wxT( "Avnet" ) );
212 }
213 else if( dist.Contains( wxT( "TME" ) ) )
214 {
215 m_textDistributor->SetValue( wxT( "TME" ) );
216 }
217 else if( dist.Contains( wxT( "LCSC" ) ) )
218 {
219 m_textDistributor->SetValue( wxT( "LCSC" ) );
220 }
221 }
222}
223
224
225void DIALOG_EXPORT_2581::onOKClick( wxCommandEvent& event )
226{
227 if( m_job )
228 {
230 EndModal( wxID_OK );
231
232 return;
233 }
234
236 return;
237
238 m_messagesPanel->Clear();
239
240 REPORTER& reporter = m_messagesPanel->Reporter();
241
242 wxFileName pcbFileName = GetOutputPath();
244
245 if( pcbFileName.GetName().empty() )
246 {
247 reporter.Report( _( "The board must be saved before generating IPC-2581 file." ),
249 return;
250 }
251
252 if( !m_parent->IsWritable( pcbFileName ) )
253 {
254 reporter.Report( wxString::Format( _( "Insufficient permissions to write file '%s'." ),
255 pcbFileName.GetFullPath() ),
257 return;
258 }
259
260 wxString tempFile = wxFileName::CreateTempFileName( wxS( "pcbnew_ipc" ) );
261
262 WX_PROGRESS_REPORTER progress( this, _( "Generate IPC-2581 File" ), 5, PR_CAN_ABORT );
263
264 std::map<std::string, UTF8> props;
265
266 props[ "units" ] = TO_UTF8( GetUnitsString() );
267 props[ "sigfig" ] = TO_UTF8( GetPrecision() );
268 props[ "version" ] = TO_UTF8( wxString( GetVersion() ) );
269 props[ "OEMRef" ] = TO_UTF8( GetOEM() );
270 props[ "mpn" ] = TO_UTF8( GetMPN() );
271 props[ "mfg" ] = TO_UTF8( GetMfg() );
272 props[ "dist" ] = TO_UTF8( GetDist() );
273 props[ "distpn" ] = TO_UTF8( GetDistPN() );
274
275 try
276 {
278 pi->SetProgressReporter( &progress );
279 pi->SetReporter( &reporter );
280 pi->SaveBoard( tempFile, m_parent->GetBoard(), &props );
281 }
282 catch( const IO_ERROR& ioe )
283 {
284 reporter.Report( wxString::Format( _( "Error generating IPC-2581 file '%s'.\n%s" ),
285 pcbFileName.GetFullPath(), ioe.What() ),
287
288 wxRemoveFile( tempFile );
289 return;
290 }
291
292 if( wxFileExists( pcbFileName.GetFullPath() ) )
293 wxRemoveFile( pcbFileName.GetFullPath() );
294
295 if( !wxRenameFile( tempFile, pcbFileName.GetFullPath() ) )
296 {
297 reporter.Report( wxString::Format( _( "Failed to create file '%s'." ), pcbFileName.GetFullPath() ),
299 wxRemoveFile( tempFile );
300 return;
301 }
302
303 reporter.Report( _( "IPC-2581 file generated successfully." ), RPT_SEVERITY_ACTION );
304}
305
306
308{
309 m_textDistributor->SetSize( m_choiceDistPN->GetSize() );
310
311 std::set<wxString> options;
312
313 for( FOOTPRINT* fp : m_parent->GetBoard()->Footprints() )
314 {
315 for( PCB_FIELD* field : fp->GetFields() )
316 {
317 wxCHECK2( field, continue );
318
319 options.insert( field->GetName() );
320 }
321 }
322
323 std::vector<wxString> items( options.begin(), options.end() );
324 m_oemRef->Append( items );
325 m_choiceMPN->Append( items );
326 m_choiceMfg->Append( items );
327 m_choiceDistPN->Append( items );
328}
329
330
332{
333 if( !m_job )
334 {
335 wxString path = m_outputFileName->GetValue();
336
337 if( path.IsEmpty() )
338 {
339 wxFileName brdFile( m_parent->GetBoard()->GetFileName() );
340 brdFile.SetExt( wxT( "xml" ) );
341 path = brdFile.GetFullPath();
342 m_outputFileName->SetValue( path );
343 }
344 }
345 else
346 {
347 m_choiceUnits->SetSelection( m_job->m_units == JOB_EXPORT_PCB_IPC2581::IPC2581_UNITS::MM ? 0 : 1 );
348 m_precision->SetValue( static_cast<int>( m_job->m_precision ) );
349 m_versionChoice->SetSelection( m_job->m_version == JOB_EXPORT_PCB_IPC2581::IPC2581_VERSION::B ? 0 : 1 );
350 m_cbCompress->SetValue( m_job->m_compress );
351 m_outputFileName->SetValue( m_job->GetConfiguredOutputPath() );
352 }
353
354 wxCommandEvent dummy;
356
358
359 wxString internalIdCol;
360 wxString mpnCol;
361 wxString distPnCol;
362 wxString mfgCol;
363 wxString distCol;
364
365 if( !m_job )
366 {
367 internalIdCol = prj.m_IP2581Bom.id;
368 mpnCol = prj.m_IP2581Bom.MPN;
369 distPnCol = prj.m_IP2581Bom.distPN;
370 mfgCol = prj.m_IP2581Bom.mfg;
371 distCol = prj.m_IP2581Bom.dist;
372 }
373 else
374 {
375 internalIdCol = m_job->m_colInternalId;
376 mpnCol = m_job->m_colMfgPn;
377 distPnCol = m_job->m_colDistPn;
378 mfgCol = m_job->m_colMfg;
379 distCol = m_job->m_colDist;
380 }
381
382 if( !m_choiceMPN->SetStringSelection( internalIdCol ) )
383 m_choiceMPN->SetSelection( 0 );
384
385 if( m_choiceMPN->SetStringSelection( mpnCol ) )
386 {
387 m_choiceMfg->Enable( true );
388
389 if( !m_choiceMfg->SetStringSelection( mfgCol ) )
390 m_choiceMfg->SetSelection( 0 );
391 }
392 else
393 {
394 m_choiceMPN->SetSelection( 0 );
395 m_choiceMfg->SetSelection( 0 );
396 m_choiceMfg->Enable( false );
397 }
398
399 if( m_choiceDistPN->SetStringSelection( distPnCol ) )
400 {
401 m_textDistributor->Enable( true );
402
403 // The combo box selection can be fixed, so any value can be entered
404 if( !prj.m_IP2581Bom.distPN.empty() )
405 {
406 m_textDistributor->SetValue( distCol );
407 }
408 else
409 {
410 wxCommandEvent evt;
411 onDistPNChange( evt );
412 }
413 }
414 else
415 {
416 m_choiceDistPN->SetSelection( 0 );
417 m_textDistributor->SetValue( _( "N/A" ) );
418 m_textDistributor->Enable( false );
419 }
420
421 return true;
422}
423
424
426{
427 if( !m_job )
428 {
430
431 prj.m_IP2581Bom.id = GetOEM();
432 prj.m_IP2581Bom.mfg = GetMfg();
433 prj.m_IP2581Bom.MPN = GetMPN();
435 prj.m_IP2581Bom.dist = GetDist();
436 }
437 else
438 {
439 m_job->SetConfiguredOutputPath( m_outputFileName->GetValue() );
440
441 m_job->m_colInternalId = GetOEM();
442 m_job->m_colDist = GetDist();
443 m_job->m_colDistPn = GetDistPN();
444 m_job->m_colMfg = GetMfg();
445 m_job->m_colMfgPn = GetMPN();
446
451 m_job->m_precision = m_precision->GetValue();
452 m_job->m_compress = GetCompress();
453 }
454
455 return true;
456}
wxBitmapBundle KiBitmapBundle(BITMAPS aBitmap, int aMinHeight)
Definition bitmap.cpp:110
DIALOG_EXPORT_2581_BASE(wxWindow *parent, wxWindowID id=wxID_ANY, const wxString &title=_("Export IPC-2581"), const wxPoint &pos=wxDefaultPosition, const wxSize &size=wxSize(-1,-1), long style=wxDEFAULT_DIALOG_STYLE|wxRESIZE_BORDER)
WX_HTML_REPORT_PANEL * m_messagesPanel
STD_BITMAP_BUTTON * m_browseButton
void onMfgPNChange(wxCommandEvent &event) override
wxString GetOEM() const
wxString GetPrecision() const
bool TransferDataToWindow() override
void onCompressCheck(wxCommandEvent &event) override
void onOKClick(wxCommandEvent &event) override
wxString GetMPN() const
void onDistPNChange(wxCommandEvent &event) override
bool TransferDataFromWindow() override
wxString GetDistPN() const
DIALOG_EXPORT_2581(PCB_EDIT_FRAME *aParent)
PCB_EDIT_FRAME * m_parent
wxString GetDist() const
wxString GetMfg() const
void onBrowseClicked(wxCommandEvent &event) override
wxString GetUnitsString() const
JOB_EXPORT_PCB_IPC2581 * m_job
wxString GetOutputPath() const
void SetupStandardButtons(std::map< int, wxString > aLabels={})
std::string m_hash_key
void finishDialogSettings()
In all dialogs, we must call the same functions to fix minimal dlg size, the default position and per...
Hold an error message and may be used when throwing exceptions containing meaningful error messages.
virtual const wxString What() const
A composite of Problem() and Where()
PROJECT & Prj() const
Return a reference to the PROJECT associated with this KIWAY.
The main frame for Pcbnew.
static PCB_IO * FindPlugin(PCB_FILE_T aFileType)
Return a #PLUGIN which the caller can use to import, export, save, or load design documents.
The backing store for a PROJECT, in JSON format.
struct IP2581_BOM m_IP2581Bom
Layer pair list for the board.
virtual PROJECT_FILE & GetProjectFile() const
Definition project.h:203
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
static void ResolvePossibleSymlinks(wxFileName &aFilename)
Multi-thread safe progress reporter dialog, intended for use of tasks that parallel reporting back of...
const wxString ExpandEnvVarSubstitutions(const wxString &aString, const PROJECT *aProject)
Replace any environment variable & text variable references with their values.
Definition common.cpp:558
#define _(s)
std::unique_ptr< T > IO_RELEASER
Helper to hold and release an IO_BASE object when exceptions are thrown.
Definition io_mgr.h:33
void AllowNetworkFileSystems(wxDialog *aDialog)
Configure a file dialog to show network and virtual file systems.
Definition wxgtk/ui.cpp:717
see class PGM_BASE
@ RPT_SEVERITY_ERROR
@ RPT_SEVERITY_ACTION
std::vector< FAB_LAYER_COLOR > dummy
#define TO_UTF8(wxstring)
Convert a wxString to a UTF8 encoded C string for all wxWidgets build modes.
wxString mfg
Manufacturer name column.
wxString MPN
Manufacturer part number column.
wxString id
Internal ID column.
wxString dist
Distributor name column.
wxString distPN
Distributor part number column.
std::string path
#define PR_CAN_ABORT