1 /*
2  * This program source code file is part of KiCad, a free EDA CAD application.
3  *
4  * Copyright (C) 1992-2021 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 2
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/old-licenses/gpl-2.0.html
19  * or you may search the http://www.gnu.org website for the version 2 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 <project.h>
25 #include <kiface_base.h>
26 #include <confirm.h>
27 #include <pcb_edit_frame.h>
28 #include <pcbnew_settings.h>
29 #include <reporter.h>
30 #include <bitmaps.h>
31 #include <tool/tool_manager.h>
32 #include <tools/pcb_actions.h>
33 #include <connectivity/connectivity_data.h>
34 #include <wildcards_and_files_ext.h>
35 #include <netlist_reader/pcb_netlist.h>
36 #include <netlist_reader/board_netlist_updater.h>
37 #include <project/project_file.h>  // LAST_PATH_TYPE
38 
39 #include <dialog_netlist.h>
40 
41 #include <wx_html_report_panel.h>
42 #include <wx/filedlg.h>
43 
44 
InstallNetlistFrame()45 void PCB_EDIT_FRAME::InstallNetlistFrame()
46 {
47     wxString netlistName = GetLastPath( LAST_PATH_NETLIST );
48 
49     DIALOG_NETLIST dlg( this, netlistName );
50 
51     dlg.ShowModal();
52 
53     SetLastPath( LAST_PATH_NETLIST, netlistName );
54 }
55 
56 bool DIALOG_NETLIST::m_matchByUUID = false;
57 
58 
DIALOG_NETLIST(PCB_EDIT_FRAME * aParent,wxString & aNetlistFullFilename)59 DIALOG_NETLIST::DIALOG_NETLIST( PCB_EDIT_FRAME* aParent, wxString& aNetlistFullFilename )
60     : DIALOG_NETLIST_BASE( aParent ),
61       m_parent( aParent ),
62       m_netlistPath( aNetlistFullFilename ),
63       m_initialized( false ),
64       m_runDragCommand( false )
65 {
66     m_NetlistFilenameCtrl->SetValue( m_netlistPath );
67     m_browseButton->SetBitmap( KiBitmap( BITMAPS::small_folder ) );
68 
69     auto cfg = m_parent->GetPcbNewSettings();
70 
71     m_cbUpdateFootprints->SetValue( cfg->m_NetlistDialog.update_footprints );
72     m_cbDeleteShortingTracks->SetValue( cfg->m_NetlistDialog.delete_shorting_tracks );
73     m_cbDeleteExtraFootprints->SetValue( cfg->m_NetlistDialog.delete_extra_footprints );
74 
75     m_matchByTimestamp->SetSelection( m_matchByUUID ? 0 : 1 );
76 
77     m_MessageWindow->SetLabel( _("Changes To Be Applied") );
78     m_MessageWindow->SetVisibleSeverities( cfg->m_NetlistDialog.report_filter );
79     m_MessageWindow->SetFileName( Prj().GetProjectPath() + wxT( "report.txt" ) );
80 
81     // We use a sdbSizer to get platform-dependent ordering of the action buttons, but
82     // that requires us to correct the button labels here.
83     m_sdbSizer1OK->SetLabel( _( "Update PCB" ) );
84     m_sdbSizer1Cancel->SetLabel( _( "Close" ) );
85     m_buttonsSizer->Layout();
86 
87     m_sdbSizer1OK->SetDefault();
88     finishDialogSettings();
89 
90     m_initialized = true;
91     loadNetlist( true );
92 }
93 
~DIALOG_NETLIST()94 DIALOG_NETLIST::~DIALOG_NETLIST()
95 {
96     m_matchByUUID = m_matchByTimestamp->GetSelection() == 0;
97 
98     PCBNEW_SETTINGS* cfg = m_parent->GetPcbNewSettings();
99 
100     cfg->m_NetlistDialog.report_filter           = m_MessageWindow->GetVisibleSeverities();
101     cfg->m_NetlistDialog.update_footprints       = m_cbUpdateFootprints->GetValue();
102     cfg->m_NetlistDialog.delete_shorting_tracks  = m_cbDeleteShortingTracks->GetValue();
103     cfg->m_NetlistDialog.delete_extra_footprints = m_cbDeleteExtraFootprints->GetValue();
104 
105     if( m_runDragCommand )
106     {
107         KIGFX::VIEW_CONTROLS* controls = m_parent->GetCanvas()->GetViewControls();
108         controls->SetCursorPosition( controls->GetMousePosition() );
109         m_parent->GetToolManager()->RunAction( PCB_ACTIONS::move, true );
110     }
111 }
112 
113 
OnOpenNetlistClick(wxCommandEvent & event)114 void DIALOG_NETLIST::OnOpenNetlistClick( wxCommandEvent& event )
115 {
116     wxString dirPath = wxFileName( Prj().GetProjectFullName() ).GetPath();
117 
118     wxString filename = m_parent->GetLastPath( LAST_PATH_NETLIST );
119 
120     if( !filename.IsEmpty() )
121     {
122         wxFileName fn = filename;
123         dirPath = fn.GetPath();
124         filename = fn.GetFullName();
125     }
126 
127     wxFileDialog FilesDialog( this, _( "Select Netlist" ), dirPath, filename,
128                               NetlistFileWildcard(), wxFD_DEFAULT_STYLE | wxFD_FILE_MUST_EXIST );
129 
130     if( FilesDialog.ShowModal() != wxID_OK )
131         return;
132 
133     m_NetlistFilenameCtrl->SetValue( FilesDialog.GetPath() );
134     onFilenameChanged();
135 }
136 
OnUpdatePCB(wxCommandEvent & event)137 void DIALOG_NETLIST::OnUpdatePCB( wxCommandEvent& event )
138 {
139     wxFileName fn = m_NetlistFilenameCtrl->GetValue();
140 
141     if( !fn.IsOk() )
142     {
143         wxMessageBox( _( "Please choose a valid netlist file." ) );
144         return;
145     }
146 
147     if( !fn.FileExists() )
148     {
149         wxMessageBox( _( "The netlist file does not exist." ) );
150         return;
151     }
152 
153     m_MessageWindow->SetLabel( _( "Changes Applied to PCB" ) );
154     loadNetlist( false );
155 
156     m_sdbSizer1Cancel->SetDefault();
157 }
158 
159 
OnFilenameKillFocus(wxFocusEvent & event)160 void DIALOG_NETLIST::OnFilenameKillFocus( wxFocusEvent& event )
161 {
162     onFilenameChanged();
163     event.Skip();
164 }
165 
166 
onFilenameChanged()167 void DIALOG_NETLIST::onFilenameChanged()
168 {
169     if( m_initialized )
170     {
171         wxFileName fn = m_NetlistFilenameCtrl->GetValue();
172 
173         if( fn.IsOk() )
174         {
175             if( fn.FileExists() )
176             {
177                 m_netlistPath = m_NetlistFilenameCtrl->GetValue();
178                 loadNetlist( true );
179             }
180             else
181             {
182                 m_MessageWindow->Clear();
183                 REPORTER& reporter = m_MessageWindow->Reporter();
184                 reporter.Report( _( "The netlist file does not exist." ), RPT_SEVERITY_ERROR );
185             }
186         }
187     }
188 }
189 
190 
OnMatchChanged(wxCommandEvent & event)191 void DIALOG_NETLIST::OnMatchChanged( wxCommandEvent& event )
192 {
193     if( m_initialized )
194         loadNetlist( true );
195 }
196 
197 
OnOptionChanged(wxCommandEvent & event)198 void DIALOG_NETLIST::OnOptionChanged( wxCommandEvent& event )
199 {
200     if( m_initialized )
201         loadNetlist( true );
202 }
203 
204 
loadNetlist(bool aDryRun)205 void DIALOG_NETLIST::loadNetlist( bool aDryRun )
206 {
207     wxString netlistFileName = m_NetlistFilenameCtrl->GetValue();
208     wxFileName fn = netlistFileName;
209 
210     if( !fn.IsOk() || !fn.FileExists() )
211         return;
212 
213     m_MessageWindow->Clear();
214     REPORTER& reporter = m_MessageWindow->Reporter();
215 
216     wxBusyCursor busy;
217 
218     wxString msg;
219     msg.Printf( _( "Reading netlist file '%s'.\n" ), netlistFileName  );
220     reporter.ReportHead( msg, RPT_SEVERITY_INFO );
221 
222     if( m_matchByTimestamp->GetSelection() == 1 )
223         msg = _( "Using reference designators to match symbols and footprints.\n" );
224     else
225         msg = _( "Using tstamps (unique IDs) to match symbols and footprints.\n" );
226 
227     reporter.ReportHead( msg, RPT_SEVERITY_INFO );
228     m_MessageWindow->SetLazyUpdate( true ); // Use lazy update to speed the creation of the report
229                                             // (the window is not updated for each message)
230     m_matchByUUID = m_matchByTimestamp->GetSelection() == 0;
231 
232     NETLIST netlist;
233 
234     netlist.SetFindByTimeStamp( m_matchByUUID );
235     netlist.SetReplaceFootprints( m_cbUpdateFootprints->GetValue() );
236 
237     if( !m_parent->ReadNetlistFromFile( netlistFileName, netlist, reporter ) )
238         return;
239 
240     BOARD_NETLIST_UPDATER updater( m_parent, m_parent->GetBoard() );
241     updater.SetReporter ( &reporter );
242     updater.SetIsDryRun( aDryRun );
243     updater.SetLookupByTimestamp( m_matchByUUID );
244     updater.SetDeleteUnusedFootprints( m_cbDeleteExtraFootprints->GetValue());
245     updater.SetReplaceFootprints( m_cbUpdateFootprints->GetValue() );
246     updater.UpdateNetlist( netlist );
247 
248     // The creation of the report was made without window update: the full page must be displayed
249     m_MessageWindow->Flush( true );
250 
251     if( aDryRun )
252         return;
253 
254     m_parent->OnNetlistChanged( updater, &m_runDragCommand );
255 }
256 
257 
258