KiCad PCB EDA Suite
dialog_edit_components_libid.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 2017 Jean-Pierre Charras, jp.charras@wanadoo.fr
5  * Copyright 1992-2021 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, you may find one here:
19  * http://www.gnu.org/licenses/old-licenses/gpl-2.0.html
20  * or you may search the http://www.gnu.org website for the version 2 license,
21  * or you may write to the Free Software Foundation, Inc.,
22  * 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301, USA
23  */
24 
31 #include <confirm.h>
32 #include <sch_edit_frame.h>
33 #include <sch_draw_panel.h>
34 #include <sch_symbol.h>
35 #include <sch_reference_list.h>
36 #include <schematic.h>
37 #include <pgm_base.h>
38 #include <symbol_lib_table.h>
39 #include <trace_helpers.h>
40 #include <widgets/wx_grid.h>
41 
43 #include <wx/tokenzr.h>
44 #include <wx/choicdlg.h>
45 #include <wx/dcclient.h>
46 #include <grid_tricks.h>
48 
49 #define COL_REFS 0
50 #define COL_CURR_LIBID 1
51 #define COL_NEW_LIBID 2
52 
53 // a re-implementation of wxGridCellAutoWrapStringRenderer to allow workaround to autorowsize bug
54 class GRIDCELL_AUTOWRAP_STRINGRENDERER : public wxGridCellAutoWrapStringRenderer
55 {
56 public:
57  int GetHeight( wxDC& aDC, wxGrid* aGrid, int aRow, int aCol );
58 
59  wxGridCellRenderer *Clone() const override
60  { return new GRIDCELL_AUTOWRAP_STRINGRENDERER; }
61 
62 private:
63  // HELPER ROUTINES UNCHANGED FROM wxWidgets IMPLEMENTATION
64 
65  wxArrayString GetTextLines( wxGrid& grid,
66  wxDC& dc,
67  const wxGridCellAttr& attr,
68  const wxRect& rect,
69  int row, int col);
70 
71  // Helper methods of GetTextLines()
72 
73  // Break a single logical line of text into several physical lines, all of
74  // which are added to the lines array. The lines are broken at maxWidth and
75  // the dc is used for measuring text extent only.
76  void BreakLine(wxDC& dc,
77  const wxString& logicalLine,
78  wxCoord maxWidth,
79  wxArrayString& lines);
80 
81  // Break a word, which is supposed to be wider than maxWidth, into several
82  // lines, which are added to lines array and the last, incomplete, of which
83  // is returned in line output parameter.
84  //
85  // Returns the width of the last line.
86  wxCoord BreakWord(wxDC& dc,
87  const wxString& word,
88  wxCoord maxWidth,
89  wxArrayString& lines,
90  wxString& line);
91 };
92 
93 
94 // PRIVATE METHOD UNCHANGED FROM wxWidgets IMPLEMENTATION
95 wxArrayString
97  wxDC& dc,
98  const wxGridCellAttr& attr,
99  const wxRect& rect,
100  int row, int col)
101 {
102  dc.SetFont( attr.GetFont() );
103  const wxCoord maxWidth = rect.GetWidth();
104 
105  // Transform logical lines into physical ones, wrapping the longer ones.
106  const wxArrayString
107  logicalLines = wxSplit(grid.GetCellValue(row, col), '\n', '\0');
108 
109  // Trying to do anything if the column is hidden anyhow doesn't make sense
110  // and we run into problems in BreakLine() in this case.
111  if ( maxWidth <= 0 )
112  return logicalLines;
113 
114  wxArrayString physicalLines;
115  for ( wxArrayString::const_iterator it = logicalLines.begin();
116  it != logicalLines.end();
117  ++it )
118  {
119  const wxString& line = *it;
120 
121  if ( dc.GetTextExtent(line).x > maxWidth )
122  {
123  // Line does not fit, break it up.
124  BreakLine(dc, line, maxWidth, physicalLines);
125  }
126  else // The entire line fits as is
127  {
128  physicalLines.push_back(line);
129  }
130  }
131 
132  return physicalLines;
133 }
134 
135 
136 // PRIVATE METHOD UNCHANGED FROM wxWidgets IMPLEMENTATION
137 void
139  const wxString& logicalLine,
140  wxCoord maxWidth,
141  wxArrayString& lines)
142 {
143  wxCoord lineWidth = 0;
144  wxString line;
145 
146  // For each word
147  wxStringTokenizer wordTokenizer(logicalLine, wxS(" \t"), wxTOKEN_RET_DELIMS);
148  while ( wordTokenizer.HasMoreTokens() )
149  {
150  const wxString word = wordTokenizer.GetNextToken();
151  const wxCoord wordWidth = dc.GetTextExtent(word).x;
152  if ( lineWidth + wordWidth < maxWidth )
153  {
154  // Word fits, just add it to this line.
155  line += word;
156  lineWidth += wordWidth;
157  }
158  else
159  {
160  // Word does not fit, check whether the word is itself wider that
161  // available width
162  if ( wordWidth < maxWidth )
163  {
164  // Word can fit in a new line, put it at the beginning
165  // of the new line.
166  lines.push_back(line);
167  line = word;
168  lineWidth = wordWidth;
169  }
170  else // Word cannot fit in available width at all.
171  {
172  if ( !line.empty() )
173  {
174  lines.push_back(line);
175  line.clear();
176  lineWidth = 0;
177  }
178 
179  // Break it up in several lines.
180  lineWidth = BreakWord(dc, word, maxWidth, lines, line);
181  }
182  }
183  }
184 
185  if ( !line.empty() )
186  lines.push_back(line);
187 }
188 
189 
190 // PRIVATE METHOD UNCHANGED FROM wxWidgets IMPLEMENTATION
191 wxCoord
193  const wxString& word,
194  wxCoord maxWidth,
195  wxArrayString& lines,
196  wxString& line)
197 {
198  wxArrayInt widths;
199  dc.GetPartialTextExtents(word, widths);
200 
201  // TODO: Use binary search to find the first element > maxWidth.
202  const unsigned count = widths.size();
203  unsigned n;
204  for ( n = 0; n < count; n++ )
205  {
206  if ( widths[n] > maxWidth )
207  break;
208  }
209 
210  if ( n == 0 )
211  {
212  // This is a degenerate case: the first character of the word is
213  // already wider than the available space, so we just can't show it
214  // completely and have to put the first character in this line.
215  n = 1;
216  }
217 
218  lines.push_back( word.substr(0, n) );
219 
220  // Check if the remainder of the string fits in one line.
221  //
222  // Unfortunately we can't use the existing partial text extents as the
223  // extent of the remainder may be different when it's rendered in a
224  // separate line instead of as part of the same one, so we have to
225  // recompute it.
226  const wxString rest = word.substr(n);
227  const wxCoord restWidth = dc.GetTextExtent(rest).x;
228 
229  if ( restWidth <= maxWidth )
230  {
231  line = rest;
232  return restWidth;
233  }
234 
235  // Break the rest of the word into lines.
236  //
237  // TODO: Perhaps avoid recursion? The code is simpler like this but using a
238  // loop in this function would probably be more efficient.
239  return BreakWord(dc, rest, maxWidth, lines, line);
240 }
241 
242 
243 #define GRID_CELL_MARGIN 4
244 
245 int GRIDCELL_AUTOWRAP_STRINGRENDERER::GetHeight( wxDC& aDC, wxGrid* aGrid, int aRow, int aCol )
246 {
247  wxGridCellAttr* attr = aGrid->GetOrCreateCellAttr( aRow, aCol );
248  wxRect rect;
249 
250  aDC.SetFont( attr->GetFont() );
251  rect.SetWidth( aGrid->GetColSize( aCol ) - ( 2 * GRID_CELL_MARGIN ) );
252 
253  const size_t numLines = GetTextLines( *aGrid, aDC, *attr, rect, aRow, aCol ).size();
254  const int textHeight = numLines * aDC.GetCharHeight();
255 
256  attr->DecRef();
257 
258  return textHeight + ( 2 * GRID_CELL_MARGIN );
259 }
260 
261 
262 // a helper class to handle components to edit
264 {
265 public:
266  SCH_COMPONENT* m_Component; // the schematic component
267  int m_Row; // the row index in m_grid
268  SCH_SCREEN* m_Screen; // the screen where m_Component lives
269  wxString m_Reference; // the schematic reference, only to display it in list
270  wxString m_InitialLibId; // the Lib Id of the component before any change
271  bool m_IsOrphan; // true if a component has no corresponding symbol found in libs
272 
274  {
275  m_Component = aComponent;
277  m_Row = -1;
278  m_IsOrphan = false;
279  m_Screen = nullptr;
280  }
281 
282  // Returns a string like mylib:symbol_name from the LIB_ID of the component
283  wxString GetStringLibId()
284  {
286  }
287 
288  // Returns a string containing the reference of the component
290  {
291  return m_Reference;
292  }
293 };
294 
295 
305 {
306 public:
309 
311 
313 
314 private:
315  bool m_isModified; // set to true if the schematic is modified
316  std::vector<int> m_OrphansRowIndexes; // list of rows containing orphan lib_id
317 
318  std::vector<CMP_CANDIDATE> m_components;
319 
321 
322  void initDlg();
323 
330  void AddRowToGrid( bool aMarkRow, const wxString& aReferences, const wxString& aStrLibId );
331 
333  bool validateLibIds();
334 
339  bool setLibIdByBrowser( int aRow );
340 
341  // Events handlers
342 
343  // called on a right click or a left double click:
344  void onCellBrowseLib( wxGridEvent& event ) override;
345 
346  // Cancel all changes, and close the dialog
347  void onCancel( wxCommandEvent& event ) override
348  {
349  // Just skipping the event doesn't work after the library browser was run
350  if( IsQuasiModal() )
351  EndQuasiModal( wxID_CANCEL );
352  else
353  event.Skip();
354  }
355 
356  // Try to find a candidate for non existing symbols
357  void onClickOrphansButton( wxCommandEvent& event ) override;
358 
359  // Automatically called when click on OK button
360  bool TransferDataFromWindow() override;
361 
362  void AdjustGridColumns( int aWidth );
363 
364  void OnSizeGrid( wxSizeEvent& event ) override;
365 };
366 
367 
370 {
372 
373  m_grid->PushEventHandler( new GRID_TRICKS( m_grid ) );
374 
375  initDlg();
376 
378 }
379 
380 
382 {
383  // Delete the GRID_TRICKS.
384  m_grid->PopEventHandler( true );
385 
386  m_autoWrapRenderer->DecRef();
387 }
388 
389 
390 // A sort compare function to sort components list by LIB_ID and then reference
391 static bool sort_by_libid( const CMP_CANDIDATE& cmp1, const CMP_CANDIDATE& cmp2 )
392 {
393  if( cmp1.m_Component->GetLibId() == cmp2.m_Component->GetLibId() )
394  return cmp1.m_Reference.Cmp( cmp2.m_Reference ) < 0;
395 
396  return cmp1.m_Component->GetLibId() < cmp2.m_Component->GetLibId();
397 }
398 
399 
401 {
402  // Clear the FormBuilder rows
403  m_grid->DeleteRows( 0, m_grid->GetNumberRows() );
404 
405  m_isModified = false;
406 
407  // This option build the full component list
408  // In complex hierarchies, the same component is in fact duplicated, but
409  // it is listed with different references (one by sheet instance)
410  // the list is larger and looks like it contains all components
411  const SCH_SHEET_LIST& sheets = GetParent()->Schematic().GetSheets();
412  SCH_REFERENCE_LIST references;
413  // build the full list of components including component having no symbol in loaded libs
414  // (orphan components)
415  sheets.GetSymbols( references, /* include power symbols */true,
416  /* include orphan components */true );
417 
418  for( unsigned ii = 0; ii < references.GetCount(); ii++ )
419  {
420  SCH_REFERENCE& item = references[ii];
421  CMP_CANDIDATE candidate( item.GetSymbol() );
422  candidate.m_Screen = item.GetSheetPath().LastScreen();
423  SCH_SHEET_PATH sheetpath = item.GetSheetPath();
424  candidate.m_Reference = candidate.m_Component->GetRef( &sheetpath );
425  int unitcount = candidate.m_Component->GetUnitCount();
426  candidate.m_IsOrphan = ( unitcount == 0 );
427  m_components.push_back( candidate );
428  }
429 
430  if( m_components.size() == 0 )
431  return;
432 
433  // now sort by lib id to create groups of items having the same lib id
434  std::sort( m_components.begin(), m_components.end(), sort_by_libid );
435 
436  // Now, fill m_grid
437  wxString last_str_libid = m_components.front().GetStringLibId();
438  int row = 0;
439  wxString refs;
440  wxString last_ref;
441  bool mark_cell = m_components.front().m_IsOrphan;
442 
443  for( auto& cmp : m_components )
444  {
445  wxString str_libid = cmp.GetStringLibId();
446 
447  if( last_str_libid != str_libid )
448  {
449  // Add last group to grid
450  AddRowToGrid( mark_cell, refs, last_str_libid );
451 
452  // prepare next entry
453  mark_cell = cmp.m_IsOrphan;
454  last_str_libid = str_libid;
455  refs.Empty();
456  row++;
457  }
458  else if( cmp.GetSchematicReference() == last_ref )
459  {
460  cmp.m_Row = row;
461  continue;
462  }
463 
464  last_ref = cmp.GetSchematicReference();
465 
466  if( !refs.IsEmpty() )
467  refs += wxT( ", " );
468 
469  refs += cmp.GetSchematicReference();
470  cmp.m_Row = row;
471  }
472 
473  // Add last component group:
474  AddRowToGrid( mark_cell, refs, last_str_libid );
475 
476  // Allows only the selection by row
477  m_grid->SetSelectionMode( wxGrid::wxGridSelectRows );
478 
479  m_buttonOrphanItems->Enable( m_OrphansRowIndexes.size() > 0 );
480  Layout();
481 }
482 
483 
485 {
486  return dynamic_cast<SCH_EDIT_FRAME*>( wxDialog::GetParent() );
487 }
488 
489 
490 void DIALOG_EDIT_COMPONENTS_LIBID::AddRowToGrid( bool aMarkRow, const wxString& aReferences,
491  const wxString& aStrLibId )
492 {
493  int row = m_grid->GetNumberRows();
494 
495  if( aMarkRow ) // a orphan component exists, set m_AsOrphanCmp as true
496  m_OrphansRowIndexes.push_back( row );
497 
498  m_grid->AppendRows( 1 );
499 
500  m_grid->SetCellValue( row, COL_REFS, aReferences );
501  m_grid->SetReadOnly( row, COL_REFS );
502 
503  m_grid->SetCellValue( row, COL_CURR_LIBID, aStrLibId );
504  m_grid->SetReadOnly( row, COL_CURR_LIBID );
505 
506  if( aMarkRow ) // A symbol is not existing in libraries: mark the cell
507  {
508  wxFont font = m_grid->GetDefaultCellFont();
509  font.MakeBold();
510  font.MakeItalic();
511  m_grid->SetCellFont( row, COL_CURR_LIBID, font );
512  }
513 
514  m_grid->SetCellRenderer( row, COL_REFS, m_autoWrapRenderer->Clone() );
515 
516  // wxWidgets' AutoRowHeight fails when used with wxGridCellAutoWrapStringRenderer
517  // (fixed in 2014, but didn't get in to wxWidgets 3.0.2)
518  wxClientDC dc( this );
519  m_grid->SetRowSize( row, m_autoWrapRenderer->GetHeight( dc, m_grid, row, COL_REFS ) );
520 
521  // set new libid column browse button
522  wxGridCellAttr* attr = new wxGridCellAttr;
523  attr->SetEditor( new GRID_CELL_SYMBOL_ID_EDITOR( this, aStrLibId ) );
524  m_grid->SetAttr( row, COL_NEW_LIBID, attr );
525 }
526 
527 
529 {
530  if( !m_grid->CommitPendingChanges() )
531  return false;
532 
533  int row_max = m_grid->GetNumberRows() - 1;
534 
535  for( int row = 0; row <= row_max; row++ )
536  {
537  wxString new_libid = m_grid->GetCellValue( row, COL_NEW_LIBID );
538 
539  if( new_libid.IsEmpty() )
540  continue;
541 
542  // a new lib id is found. validate this new value
543  LIB_ID id;
544  id.Parse( new_libid );
545 
546  if( !id.IsValid() )
547  {
548  wxString msg;
549  msg.Printf( _( "Symbol library identifier \"%s\" is not valid." ), new_libid );
550  wxMessageBox( msg );
551 
552  m_grid->SetFocus();
553  m_grid->MakeCellVisible( row, COL_NEW_LIBID );
554  m_grid->SetGridCursor( row, COL_NEW_LIBID );
555 
556  m_grid->EnableCellEditControl( true );
557  m_grid->ShowCellEditControl();
558 
559  return false;
560  }
561  }
562 
563  return true;
564 }
565 
566 
568 {
569  int row = event.GetRow();
570  m_grid->SelectRow( row ); // only for user, to show the selected line
571 
572  setLibIdByBrowser( row );
573 
574 }
575 
576 
578 {
579  std::vector< wxString > libs = Prj().SchSymbolLibTable()->GetLogicalLibs();
580  wxArrayString aliasNames;
581  wxArrayString candidateSymbNames;
582 
583  unsigned fixesCount = 0;
584 
585  // Try to find a candidate for non existing symbols in any loaded library
586  for( int orphanRow : m_OrphansRowIndexes )
587  {
588  wxString orphanLibid = m_grid->GetCellValue( orphanRow, COL_CURR_LIBID );
589  int grid_row_idx = orphanRow; //row index in m_grid for the current item
590 
591  LIB_ID curr_libid;
592  curr_libid.Parse( orphanLibid, true );
593  wxString symbName = curr_libid.GetLibItemName();
594  // number of full LIB_ID candidates (because we search for a symbol name
595  // inside all avaiable libraries, perhaps the same symbol name can be found
596  // in more than one library, giving ambiguity
597  int libIdCandidateCount = 0;
598  candidateSymbNames.Clear();
599 
600  // now try to find a candidate
601  for( auto &lib : libs )
602  {
603  aliasNames.Clear();
604 
605  try
606  {
607  Prj().SchSymbolLibTable()->EnumerateSymbolLib( lib, aliasNames );
608  }
609  catch( const IO_ERROR& ) {} // ignore, it is handled below
610 
611  if( aliasNames.IsEmpty() )
612  continue;
613 
614  // Find a symbol name in symbols inside this library:
615  int index = aliasNames.Index( symbName );
616 
617  if( index != wxNOT_FOUND )
618  {
619  // a candidate is found!
620  libIdCandidateCount++;
621  wxString newLibid = lib + ':' + symbName;
622 
623  // Uses the first found. Most of time, it is alone.
624  // Others will be stored in a candidate list
625  if( libIdCandidateCount <= 1 )
626  {
627  m_grid->SetCellValue( grid_row_idx, COL_NEW_LIBID, newLibid );
628  candidateSymbNames.Add( m_grid->GetCellValue( grid_row_idx, COL_NEW_LIBID ) );
629  fixesCount++;
630  }
631  else // Store other candidates for later selection
632  {
633  candidateSymbNames.Add( newLibid );
634  }
635  }
636  }
637 
638  // If more than one LIB_ID candidate, ask for selection between candidates:
639  if( libIdCandidateCount > 1 )
640  {
641  // Mainly for user: select the row being edited
642  m_grid->SelectRow( grid_row_idx );
643 
644  wxString msg;
645  msg.Printf( _( "Available Candidates for %s " ),
646  m_grid->GetCellValue( grid_row_idx, COL_CURR_LIBID ) );
647 
648  wxSingleChoiceDialog dlg ( this, msg,
649  wxString::Format( _( "Candidates count %d " ), libIdCandidateCount ),
650  candidateSymbNames );
651 
652  if( dlg.ShowModal() == wxID_OK )
653  m_grid->SetCellValue( grid_row_idx, COL_NEW_LIBID, dlg.GetStringSelection() );
654  }
655  }
656 
657  if( fixesCount < m_OrphansRowIndexes.size() ) // Not all orphan components are fixed
658  {
659  wxMessageBox( wxString::Format( _( "%u link(s) mapped, %u not found" ),
660  fixesCount,
661  (unsigned) m_OrphansRowIndexes.size() - fixesCount ) );
662  }
663  else
664  wxMessageBox( wxString::Format( _( "All %u link(s) resolved" ), fixesCount ) );
665 }
666 
667 
669 {
670 #if 0
671  // Use dialog symbol selector to choose a symbol
672  SCH_BASE_FRAME::HISTORY_LIST dummy;
673  SCH_BASE_FRAME::PICKED_SYMBOL sel = m_frame->SelectComponentFromLibrary( NULL, dummy, true,
674  0, 0, false );
675 #else
676  // Use library viewer to choose a symbol
677  LIB_ID preselected;
678  wxString current = m_grid->GetCellValue( aRow, COL_NEW_LIBID );
679 
680  if( current.IsEmpty() )
681  current = m_grid->GetCellValue( aRow, COL_CURR_LIBID );
682 
683  if( !current.IsEmpty() )
684  preselected.Parse( current, true );
685 
686  PICKED_SYMBOL sel = GetParent()->PickSymbolFromLibBrowser( this, NULL, preselected, 0, 0 );
687 #endif
688 
689  if( sel.LibId.empty() ) // command aborted
690  return false;
691 
692  if( !sel.LibId.IsValid() ) // Should not occur
693  {
694  wxMessageBox( _( "Invalid symbol library identifier" ) );
695  return false;
696  }
697 
698  wxString new_libid;
699  new_libid = sel.LibId.Format();
700 
701  m_grid->SetCellValue( aRow, COL_NEW_LIBID, new_libid );
702 
703  return true;
704 }
705 
706 
708 {
709  if( !validateLibIds() )
710  return false;
711 
712  int row_max = m_grid->GetNumberRows() - 1;
713 
714  for( int row = 0; row <= row_max; row++ )
715  {
716  wxString new_libid = m_grid->GetCellValue( row, COL_NEW_LIBID );
717 
718  if( new_libid.IsEmpty() || new_libid == m_grid->GetCellValue( row, COL_CURR_LIBID ) )
719  continue;
720 
721  // A new lib id is found and was already validated.
722  LIB_ID id;
723  id.Parse( new_libid, true );
724 
725  for( CMP_CANDIDATE& cmp : m_components )
726  {
727  if( cmp.m_Row != row )
728  continue;
729 
730  LIB_PART* symbol = nullptr;
731 
732  try
733  {
734  symbol = Prj().SchSymbolLibTable()->LoadSymbol( id );
735  }
736  catch( const IO_ERROR& ioe )
737  {
738  wxString msg;
739 
740  msg.Printf( _( "Error occurred loading symbol %s from library %s.\n\n%s" ),
741  id.GetLibItemName().wx_str(),
742  id.GetLibNickname().wx_str(),
743  ioe.What() );
744 
745  DisplayError( this, msg );
746  }
747 
748  if( symbol == nullptr )
749  continue;
750 
751  GetParent()->SaveCopyInUndoList( cmp.m_Screen, cmp.m_Component, UNDO_REDO::CHANGED,
752  m_isModified );
753  m_isModified = true;
754 
755  cmp.m_Screen->Remove( cmp.m_Component );
756  SCH_FIELD* value = cmp.m_Component->GetField( VALUE_FIELD );
757 
758  // If value is a proxy for the itemName then make sure it gets updated
759  if( cmp.m_Component->GetLibId().GetLibItemName().wx_str() == value->GetText() )
760  cmp.m_Component->SetValue( id.GetLibItemName().wx_str() );
761 
762  cmp.m_Component->SetLibId( id );
763  cmp.m_Component->SetLibSymbol( symbol->Flatten().release() );
764  cmp.m_Screen->Append( cmp.m_Component );
765  cmp.m_Screen->SetModify();
766 
767  if ( m_checkBoxUpdateFields->IsChecked() )
768  cmp.m_Component->UpdateFields( false, false );
769 
770  }
771  }
772 
773  return true;
774 }
775 
776 
778 {
779  // Account for scroll bars
780  aWidth -= ( m_grid->GetSize().x - m_grid->GetClientSize().x );
781 
782  int colWidth = aWidth / 3;
783 
784  m_grid->SetColSize( COL_REFS, colWidth );
785  aWidth -= colWidth;
786 
787  colWidth = 0;
788  for( int row = 0; row < m_grid->GetNumberRows(); ++row )
789  {
790  wxString cellValue = m_grid->GetCellValue( row, COL_CURR_LIBID );
791  colWidth = std::max( colWidth, KIUI::GetTextSize( cellValue, m_grid ).x );
792  }
793 
794  colWidth += 20;
795  m_grid->SetColSize( COL_CURR_LIBID, colWidth );
796  aWidth -= colWidth;
797 
798  colWidth = 0;
799  for( int row = 0; row < m_grid->GetNumberRows(); ++row )
800  {
801  wxString cellValue = m_grid->GetCellValue( row, COL_NEW_LIBID );
802  colWidth = std::max( colWidth, KIUI::GetTextSize( cellValue, m_grid ).x );
803  }
804 
805  colWidth += 20;
806  m_grid->SetColSize( COL_NEW_LIBID, std::max( colWidth, aWidth ) );
807 }
808 
809 
811 {
812  AdjustGridColumns( event.GetSize().GetX() );
813 
814  wxClientDC dc( this );
815 
816  // wxWidgets' AutoRowHeight fails when used with wxGridCellAutoWrapStringRenderer
817  for( int row = 0; row < m_grid->GetNumberRows(); ++row )
818  m_grid->SetRowSize( row, m_autoWrapRenderer->GetHeight( dc, m_grid, row, COL_REFS ) );
819 
820  event.Skip();
821 }
822 
823 
825 {
826  // This dialog itself subsequently can invoke a KIWAY_PLAYER as a quasimodal
827  // frame. Therefore this dialog as a modal frame parent, MUST be run under
828  // quasimodal mode for the quasimodal frame support to work. So don't use
829  // the QUASIMODAL macros here.
830  DIALOG_EDIT_COMPONENTS_LIBID dlg( aCaller );
831  // DO NOT use ShowModal() here, otherwise the library browser will not work
832  // properly.
833  dlg.ShowQuasiModal();
834 
835  return dlg.IsSchematicModified();
836 }
DIALOG_EDIT_COMPONENTS_LIBID(SCH_EDIT_FRAME *aParent)
void DisplayError(wxWindow *aParent, const wxString &aText, int aDisplayTime)
Display an error or warning message box with aMessage.
Definition: confirm.cpp:253
A container for handling SCH_SHEET_PATH objects in a flattened hierarchy.
SCH_FIELD instances are attached to a component and provide a place for the component's value,...
Definition: sch_field.h:51
const UTF8 & GetLibItemName() const
Definition: lib_id.h:106
void GetSymbols(SCH_REFERENCE_LIST &aReferences, bool aIncludePowerSymbols=true, bool aForceIncludeOrphanComponents=false) const
Add a SCH_REFERENCE object to aReferences for each component in the list of sheets.
std::vector< CMP_CANDIDATE > m_components
This file is part of the common library.
const SCH_SHEET_PATH & GetSheetPath() const
wxCoord BreakWord(wxDC &dc, const wxString &word, wxCoord maxWidth, wxArrayString &lines, wxString &line)
bool setLibIdByBrowser(int aRow)
run the lib browser and set the selected LIB_ID for row aRow
void OnSizeGrid(wxSizeEvent &event) override
GRIDCELL_AUTOWRAP_STRINGRENDERER * m_autoWrapRenderer
void BreakLine(wxDC &dc, const wxString &logicalLine, wxCoord maxWidth, wxArrayString &lines)
Add mouse and command handling (such as cut, copy, and paste) to a WX_GRID instance.
Definition: grid_tricks.h:52
bool IsQuasiModal() const
Definition: dialog_shim.h:107
static LIB_PART * dummy()
Used to draw a dummy shape when a LIB_PART is not found in library.
Definition: sch_symbol.cpp:69
Schematic editor (Eeschema) main window.
wxArrayString GetTextLines(wxGrid &grid, wxDC &dc, const wxGridCellAttr &attr, const wxRect &rect, int row, int col)
#define COL_CURR_LIBID
A logical library item identifier and consists of various portions much like a URI.
Definition: lib_id.h:51
bool IsValid() const
Check if this LID_ID is valid.
Definition: lib_id.h:168
bool empty() const
Definition: lib_id.h:189
Container to create a flattened list of symbols because in a complex hierarchy, a symbol can be used ...
Field Value of part, i.e. "3.3K".
CMP_CANDIDATE(SCH_COMPONENT *aComponent)
#define GRID_CELL_MARGIN
Dialog to globally edit the LIB_ID of groups if components having the same initial LIB_ID.
#define NULL
wxSize GetTextSize(const wxString &aSingleLine, wxWindow *aWindow)
Return the size of aSingleLine of text when it is rendered in aWindow using whatever font is currentl...
Definition: ui_common.cpp:58
virtual const wxString What() const
A composite of Problem() and Where()
Definition: exceptions.cpp:29
int ShowQuasiModal()
PROJECT & Prj() const
Return a reference to the PROJECT associated with this KIWAY.
int GetHeight(wxDC &aDC, wxGrid *aGrid, int aRow, int aCol)
static bool sort_by_libid(const CMP_CANDIDATE &cmp1, const CMP_CANDIDATE &cmp2)
void onCancel(wxCommandEvent &event) override
SCHEMATIC & Schematic() const
Define a library symbol object.
Definition: lib_symbol.h:93
bool InvokeDialogEditComponentsLibId(SCH_EDIT_FRAME *aCaller)
Run a dialog to modify the LIB_ID of components for instance when a symbol has moved from a symbol li...
wxLogTrace helper definitions.
Handle access to a stack of flattened SCH_SHEET objects by way of a path for creating a flattened sch...
bool CommitPendingChanges(bool aQuietMode=false)
Close any open cell edit controls.
Definition: wx_grid.cpp:182
std::unique_ptr< LIB_PART > Flatten() const
Return a flattened symbol inheritance to the caller.
Definition: lib_symbol.cpp:327
UTF8 Format() const
Definition: lib_id.cpp:233
PICKED_SYMBOL PickSymbolFromLibBrowser(wxTopLevelWindow *aParent, const SCHLIB_FILTER *aFilter, const LIB_ID &aPreselectedLibId, int aUnit, int aConvert)
Function PickSymbolFromLibBrowser Calls the library viewer to select component to import into schemat...
Definition: getpart.cpp:43
SCH_COMPONENT * GetSymbol() const
void Format(OUTPUTFORMATTER *out, int aNestLevel, int aCtl, const CPTREE &aTree)
Output a PTREE into s-expression format via an OUTPUTFORMATTER derivative.
Definition: ptree.cpp:200
unsigned GetCount() const
void finishDialogSettings()
In all dialogs, we must call the same functions to fix minimal dlg size, the default position and per...
SCH_SHEET_LIST GetSheets() const override
Builds and returns an updated schematic hierarchy TODO: can this be cached?
Definition: schematic.h:111
wxGridCellRenderer * Clone() const override
void EndQuasiModal(int retCode)
void onCellBrowseLib(wxGridEvent &event) override
int Parse(const UTF8 &aId, bool aFix=false)
Parse LIB_ID with the information from aId.
Definition: lib_id.cpp:122
see class PGM_BASE
SCH_SCREEN * LastScreen()
void SaveCopyInUndoList(SCH_SCREEN *aScreen, SCH_ITEM *aItemToCopy, UNDO_REDO aTypeCommand, bool aAppend)
Create a copy of the current schematic item, and put it in the undo list.
#define _(s)
Definition: 3d_actions.cpp:33
#define COL_NEW_LIBID
void AddRowToGrid(bool aMarkRow, const wxString &aReferences, const wxString &aStrLibId)
Add a new row (new entry) in m_grid.
Schematic symbol object.
Definition: sch_symbol.h:79
Class DIALOG_EDIT_COMPONENTS_LIBID_BASE.
wxString GetUniStringLibId() const
Definition: lib_id.h:142
LIB_ID LibId
Definition: sch_screen.h:82
const LIB_ID & GetLibId() const
Definition: sch_symbol.h:189
Hold an error message and may be used when throwing exceptions containing meaningful error messages.
Definition: ki_exception.h:75
void onClickOrphansButton(wxCommandEvent &event) override
virtual const wxString & GetText() const
Return the string associated with the text object.
Definition: eda_text.h:133
A helper to define a symbol's reference designator in a schematic.
bool validateLibIds()
returns true if all new lib id are valid