KiCad PCB EDA Suite
dialog_rescue_each.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) 2015-2018 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 <sch_edit_frame.h>
25 #include <sch_component.h>
26 #include <invoke_sch_dialog.h>
28 #include <kiface_i.h>
29 #include <class_library.h>
30 #include <class_libentry.h>
31 #include <set>
32 #include <vector>
33 #include <project_rescue.h>
34 #include <eeschema_config.h>
35 
37 {
38 public:
48  DIALOG_RESCUE_EACH( SCH_EDIT_FRAME* aParent, RESCUER& aRescuer, bool aAskShowAgain );
49 
51 
52 private:
54  wxConfigBase* m_Config;
57 
58  bool TransferDataToWindow() override;
59  bool TransferDataFromWindow() override;
60  void PopulateConflictList();
61  void PopulateInstanceList();
62  void OnConflictSelect( wxDataViewEvent& event ) override;
63  void OnNeverShowClick( wxCommandEvent& event ) override;
64  void OnCancelClick( wxCommandEvent& event ) override;
65  void OnHandleCachePreviewRepaint( wxPaintEvent& aRepaintEvent ) override;
66  void OnHandleLibraryPreviewRepaint( wxPaintEvent& aRepaintEvent ) override;
67  void renderPreview( LIB_PART* aComponent, int aUnit, wxPanel* panel );
68 };
69 
70 
72  bool aAskShowAgain )
73  : DIALOG_RESCUE_EACH_BASE( aParent ),
74  m_Parent( aParent ),
75  m_Rescuer( &aRescuer ),
76  m_AskShowAgain( aAskShowAgain )
77 {
79  m_stdButtonsOK->SetDefault();
80 
81  // Set the info message, customized to include the proper suffix.
82  wxString info =
83  _( "This schematic was made using older symbol libraries which may break the "
84  "schematic. Some symbols may need to be linked to a different symbol name. "
85  "Some symbols may need to be \"rescued\" (copied and renamed) into a new library.\n\n"
86  "The following changes are recommended to update the project." );
87  m_htmlPrompt->AppendToPage( info );
88 
89  // wxDataViewListCtrl seems to do a poor job of laying itself out so help it along here.
90  wxString header = _( "Accept" );
91  wxFont font = m_ListOfConflicts->GetFont();
92 
93  font.MakeBold();
94 
95  wxClientDC dc( this );
96 
97  dc.SetFont( font );
98 
99  int padding = 30;
100  int width = dc.GetTextExtent( header ).GetWidth();
101 
102  m_ListOfConflicts->AppendToggleColumn( header, wxDATAVIEW_CELL_ACTIVATABLE, width,
103  wxALIGN_CENTER );
104 
105  header = _( "Symbol Name" );
106  width = dc.GetTextExtent( header ).GetWidth() + padding;
107  m_ListOfConflicts->AppendTextColumn( header, wxDATAVIEW_CELL_INERT, width );
108 
109  header = _( "Action Taken" );
110  width = dc.GetTextExtent( header ).GetWidth() + padding;
111  m_ListOfConflicts->AppendTextColumn( header, wxDATAVIEW_CELL_INERT, width );
112 
113  header = _( "Reference" );
114  width = dc.GetTextExtent( header ).GetWidth() + padding;
115  m_ListOfInstances->AppendTextColumn( header, wxDATAVIEW_CELL_INERT, width );
116 
117  header = _( "Value" );
118  width = dc.GetTextExtent( header ).GetWidth() + padding;
119  m_ListOfInstances->AppendTextColumn( header, wxDATAVIEW_CELL_INERT, width );
120 
121  m_componentViewOld->SetLayoutDirection( wxLayout_LeftToRight );
122  m_componentViewNew->SetLayoutDirection( wxLayout_LeftToRight );
123 
124  Layout();
125  SetSizeInDU( 280, 240 );
126 
127  // Make sure the HTML window is large enough. Some fun size juggling and
128  // fudge factors here but it does seem to work pretty reliably.
129  auto info_size = m_htmlPrompt->GetTextExtent( info );
130  auto prompt_size = m_htmlPrompt->GetSize();
131  auto font_size = m_htmlPrompt->GetTextExtent( "X" );
132  auto approx_info_height = ( 2 * info_size.x / prompt_size.x ) * font_size.y;
133  m_htmlPrompt->SetSizeHints( 2 * prompt_size.x / 3, approx_info_height );
134  Layout();
135  GetSizer()->SetSizeHints( this );
136  SetSizeInDU( 280, 240 );
137  Center();
138 }
139 
140 
142 {
143 }
144 
145 
147 {
148  if( !wxDialog::TransferDataToWindow() )
149  return false;
150 
153 
154  if( !m_AskShowAgain )
155  m_btnNeverShowAgain->Hide();
156 
157  return true;
158 }
159 
160 
162 {
163  wxVector<wxVariant> data;
164  for( RESCUE_CANDIDATE& each_candidate : m_Rescuer->m_all_candidates )
165  {
166  data.clear();
167  data.push_back( wxVariant( true ) );
168  data.push_back( each_candidate.GetRequestedName() );
169  data.push_back( each_candidate.GetActionDescription() );
170 
171  m_ListOfConflicts->AppendItem( data );
172  }
173 
174  if( !m_Rescuer->m_all_candidates.empty() )
175  {
176  // Select the first choice
177  m_ListOfConflicts->SelectRow( 0 );
178  }
179 }
180 
181 
183 {
184  m_ListOfInstances->DeleteAllItems();
185 
186  int row = m_ListOfConflicts->GetSelectedRow();
187 
188  if( row == wxNOT_FOUND )
189  row = 0;
190 
191  RESCUE_CANDIDATE& selected_part = m_Rescuer->m_all_candidates[row];
192 
193  wxVector<wxVariant> data;
194  int count = 0;
195 
196  for( SCH_COMPONENT* each_component : *m_Rescuer->GetComponents() )
197  {
198  if( each_component->GetLibId().Format() != UTF8( selected_part.GetRequestedName() ) )
199  continue;
200 
201  SCH_FIELD* valueField = each_component->GetField( 1 );
202 
203  data.clear();
204  data.push_back( each_component->GetRef( & m_Parent->GetCurrentSheet() ) );
205  data.push_back( valueField ? valueField->GetText() : wxT( "" ) );
206  m_ListOfInstances->AppendItem( data );
207  count++;
208  }
209 
210  m_titleInstances->SetLabelText( wxString::Format(
211  _( "Instances of this symbol (%d items):" ), count ) );
212 }
213 
214 
215 void DIALOG_RESCUE_EACH::OnHandleCachePreviewRepaint( wxPaintEvent& aRepaintEvent )
216 {
217  int row = m_ListOfConflicts->GetSelectedRow();
218 
219  if( row == wxNOT_FOUND )
220  row = 0;
221 
222  RESCUE_CANDIDATE& selected_part = m_Rescuer->m_all_candidates[row];
223 
224  if( selected_part.GetCacheCandidate() )
225  renderPreview( selected_part.GetCacheCandidate(), 0, m_componentViewOld );
226 }
227 
228 
229 void DIALOG_RESCUE_EACH::OnHandleLibraryPreviewRepaint( wxPaintEvent& aRepaintEvent )
230 {
231  int row = m_ListOfConflicts->GetSelectedRow();
232 
233  if( row == wxNOT_FOUND )
234  row = 0;
235 
236  RESCUE_CANDIDATE& selected_part = m_Rescuer->m_all_candidates[row];
237 
238  if( selected_part.GetLibCandidate() )
239  renderPreview( selected_part.GetLibCandidate(), 0, m_componentViewNew );
240 }
241 
242 
243 // Render the preview in our m_componentView. If this gets more complicated, we should
244 // probably have a derived class from wxPanel; but this keeps things local.
245 // Call it only from a Paint Event, because we are using a wxPaintDC to draw the component
246 void DIALOG_RESCUE_EACH::renderPreview( LIB_PART* aComponent, int aUnit, wxPanel* aPanel )
247 {
248  wxPaintDC dc( aPanel );
249  wxColour bgColor = m_Parent->GetDrawBgColor().ToColour();
250 
251  dc.SetBackground( wxBrush( bgColor ) );
252  dc.Clear();
253 
254  if( aComponent == NULL )
255  return;
256 
257  if( aUnit <= 0 )
258  aUnit = 1;
259 
260  const wxSize dc_size = dc.GetSize();
261  dc.SetDeviceOrigin( dc_size.x / 2, dc_size.y / 2 );
262 
263  // Find joint bounding box for everything we are about to draw.
264  EDA_RECT bBox = aComponent->GetUnitBoundingBox( aUnit, /* deMorganConvert */ 1 );
265  const double xscale = (double) dc_size.x / bBox.GetWidth();
266  const double yscale = (double) dc_size.y / bBox.GetHeight();
267  const double scale = std::min( xscale, yscale ) * 0.85;
268 
269  dc.SetUserScale( scale, scale );
270 
271  wxPoint offset = - bBox.Centre();
272 
273  // Avoid rendering when either dimension is zero
274  int width, height;
275 
276  dc.GetSize( &width, &height );
277  if( !width || !height )
278  return;
279 
280  aComponent->Draw( NULL, &dc, offset, aUnit, 1, PART_DRAW_OPTIONS::Default() );
281 }
282 
283 
284 void DIALOG_RESCUE_EACH::OnConflictSelect( wxDataViewEvent& aEvent )
285 {
286  // wxformbuilder connects this event to the _dialog_, not the data view.
287  // Make sure the correct item triggered it, otherwise we trigger recursively
288  // and get a stack overflow.
289  if( aEvent.GetEventObject() != m_ListOfConflicts )
290  return;
291 
293 
294  m_componentViewOld->Refresh();
295  m_componentViewNew->Refresh();
296 }
297 
298 
300 {
301  if( !wxDialog::TransferDataFromWindow() )
302  return false;
303 
304  for( size_t index = 0; index < m_Rescuer->GetCandidateCount(); ++index )
305  {
306  wxVariant val;
307  m_ListOfConflicts->GetValue( val, index, 0 );
308  bool rescue_part = val.GetBool();
309 
310  if( rescue_part )
312  }
313  return true;
314 }
315 
316 
317 void DIALOG_RESCUE_EACH::OnNeverShowClick( wxCommandEvent& aEvent )
318 {
319  wxMessageDialog dlg( m_Parent,
320  _( "Stop showing this tool?\n"
321  "No changes will be made.\n\n"
322  "This setting can be changed from the \"Symbol Libraries\" dialog,\n"
323  "and the tool can be activated manually from the \"Tools\" menu." ),
324  _( "Rescue Symbols" ), wxYES_NO | wxNO_DEFAULT | wxICON_QUESTION );
325  int resp = dlg.ShowModal ();
326 
327  if( resp == wxID_YES )
328  {
329  m_Config->Write( RescueNeverShowEntry, true );
331  Close();
332  }
333 }
334 
335 
336 void DIALOG_RESCUE_EACH::OnCancelClick( wxCommandEvent& aEvent )
337 {
340 }
341 
342 
343 int InvokeDialogRescueEach( SCH_EDIT_FRAME* aCaller, RESCUER& aRescuer, bool aAskShowAgain )
344 {
345  DIALOG_RESCUE_EACH dlg( aCaller, aRescuer, aAskShowAgain );
346  return dlg.ShowModal();
347 }
Class UTF8 is an 8 bit string that is assuredly encoded in UTF8, and supplies special conversion supp...
Definition: utf8.h:73
virtual LIB_PART * GetLibCandidate() const
Get the part the would be loaded from the libraries, if possible, or else NULL.
Class SCH_FIELD instances are attached to a component and provide a place for the component&#39;s value...
Definition: sch_field.h:56
void Draw(EDA_DRAW_PANEL *aPanel, wxDC *aDc, const wxPoint &aOffset, int aMulti, int aConvert, const PART_DRAW_OPTIONS &aOpts)
Draw part.
const EDA_RECT GetUnitBoundingBox(int aUnit, int aConvert) const
Get the bounding box for the symbol.
virtual LIB_PART * GetCacheCandidate() const
Get the part that can be loaded from the project cache, if possible, or else NULL.
SCH_EDIT_FRAME * m_Parent
virtual wxString GetActionDescription() const =0
Get a description of the action proposed, for displaying in the UI.
void OnNeverShowClick(wxCommandEvent &event) override
bool TransferDataFromWindow() override
Class DIALOG_RESCUE_EACH_BASE.
int GetHeight() const
Definition: eda_rect.h:118
const wxChar RescueNeverShowEntry[]
int InvokeDialogRescueEach(SCH_EDIT_FRAME *aCaller, RESCUER &aRescuer, bool aAskShowAgain)
Function InvokeDialogRescueEach This dialog asks the user which rescuable, cached parts he wants to r...
Schematic editor (Eeschema) main window.
virtual void OnCancelClick(wxCommandEvent &event)
KIFACE_I & Kiface()
Global KIFACE_I "get" accessor.
Definition: kicad.cpp:52
boost::ptr_vector< RESCUE_CANDIDATE > m_all_candidates
bool TransferDataToWindow() override
void OnHandleCachePreviewRepaint(wxPaintEvent &aRepaintEvent) override
Class LIB_ITEM definition.
const wxString & GetText() const
Function GetText returns the string associated with the text object.
Definition: eda_text.h:128
SCH_SHEET_PATH & GetCurrentSheet()
size_t GetCandidateCount()
Returen the number of rescue candidates found.
void SetSizeInDU(int x, int y)
Set the dialog to the given dimensions in "dialog units".
Define a library symbol object.
wxConfigBase * KifaceSettings() const
Definition: kiface_i.h:103
void OnHandleLibraryPreviewRepaint(wxPaintEvent &aRepaintEvent) override
wxPoint Centre() const
Definition: eda_rect.h:60
static PART_DRAW_OPTIONS Default()
COLOR4D GetDrawBgColor() const override
void renderPreview(LIB_PART *aComponent, int aUnit, wxPanel *panel)
Definition the SCH_COMPONENT class for Eeschema.
std::vector< RESCUE_CANDIDATE * > m_chosen_candidates
const int scale
void Format(OUTPUTFORMATTER *out, int aNestLevel, int aCtl, CPTREE &aTree)
Function Format outputs a PTREE into s-expression format via an OUTPUTFORMATTER derivative.
Definition: ptree.cpp:205
void OnConflictSelect(wxDataViewEvent &event) override
Class EDA_RECT handles the component boundary box.
Definition: eda_rect.h:44
Class SCH_COMPONENT describes a real schematic component.
Definition: sch_component.h:69
int GetWidth() const
Definition: eda_rect.h:117
std::vector< SCH_COMPONENT * > * GetComponents()
Get the list of symbols that need rescued.
wxDataViewListCtrl * m_ListOfConflicts
DIALOG_RESCUE_EACH(SCH_EDIT_FRAME *aParent, RESCUER &aRescuer, bool aAskShowAgain)
This dialog asks the user which rescuable, cached parts he wants to rescue.
void OnCancelClick(wxCommandEvent &event) override
Definition for part library class.
virtual wxString GetRequestedName() const
Get the name that was originally requested in the schematic.
#define min(a, b)
Definition: auxiliary.h:85
wxDataViewListCtrl * m_ListOfInstances