KiCad PCB EDA Suite
getpart.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 Jean-Pierre Charras, jp.charras at wanadoo.fr
5  * Copyright (C) 2008 Wayne Stambaugh <stambaughw@gmail.com>
6  * Copyright (C) 2004-2018 KiCad Developers, see AUTHORS.txt for contributors.
7  *
8  * This program is free software; you can redistribute it and/or
9  * modify it under the terms of the GNU General Public License
10  * as published by the Free Software Foundation; either version 2
11  * of the License, or (at your option) any later version.
12  *
13  * This program is distributed in the hope that it will be useful,
14  * but WITHOUT ANY WARRANTY; without even the implied warranty of
15  * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
16  * GNU General Public License for more details.
17  *
18  * You should have received a copy of the GNU General Public License
19  * along with this program; if not, you may find one here:
20  * http://www.gnu.org/licenses/old-licenses/gpl-2.0.html
21  * or you may search the http://www.gnu.org website for the version 2 license,
22  * or you may write to the Free Software Foundation, Inc.,
23  * 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301, USA
24  */
25 
31 #include <algorithm>
32 #include <fctsys.h>
33 #include <pgm_base.h>
34 #include <kiway.h>
35 #include <gr_basic.h>
36 #include <sch_draw_panel.h>
37 #include <confirm.h>
38 #include <sch_edit_frame.h>
39 #include <kicad_device_context.h>
40 #include <msgpanel.h>
41 
42 #include <general.h>
43 #include <class_library.h>
44 #include <sch_component.h>
45 #include <lib_edit_frame.h>
46 #include <viewlib_frame.h>
47 #include <eeschema_id.h>
48 #include <symbol_lib_table.h>
49 
52 
53 
55  wxTopLevelWindow* aParent,
56  const SCHLIB_FILTER* aFilter, const LIB_ID& aPreselectedLibId,
57  int aUnit, int aConvert )
58 {
59  // Close any open non-modal Lib browser, and open a new one, in "modal" mode:
60  LIB_VIEW_FRAME* viewlibFrame = (LIB_VIEW_FRAME*) Kiway().Player( FRAME_SCH_VIEWER, false );
61 
62  if( viewlibFrame )
63  viewlibFrame->Destroy();
64 
65  viewlibFrame = (LIB_VIEW_FRAME*) Kiway().Player( FRAME_SCH_VIEWER_MODAL, true, aParent );
66 
67  if( aFilter )
68  viewlibFrame->SetFilter( aFilter );
69 
70  if( aPreselectedLibId.IsValid() )
71  {
72  viewlibFrame->SetSelectedLibrary( aPreselectedLibId.GetLibNickname() );
73  viewlibFrame->SetSelectedComponent( aPreselectedLibId.GetLibItemName() );
74  }
75 
76  viewlibFrame->SetUnitAndConvert( aUnit, aConvert );
77 
78  viewlibFrame->Refresh();
79 
81 
82  wxString symbol = sel.LibId.Format();
83 
84  if( viewlibFrame->ShowModal( &symbol, aParent ) )
85  {
86  LIB_ID id;
87 
88  if( id.Parse( symbol, LIB_ID::ID_SCH ) == -1 )
89  sel.LibId = id;
90 
91  sel.Unit = viewlibFrame->GetUnit();
92  sel.Convert = viewlibFrame->GetConvert();
93  }
94 
95  viewlibFrame->Destroy();
96 
97  return sel;
98 }
99 
100 
102  const SCHLIB_FILTER* aFilter,
103  std::vector<COMPONENT_SELECTION>& aHistoryList,
104  bool aAllowBrowser,
105  int aUnit,
106  int aConvert,
107  bool aShowFootprints,
108  const LIB_ID* aHighlight,
109  bool aAllowFields )
110 {
111  std::unique_lock<std::mutex> dialogLock( DIALOG_CHOOSE_COMPONENT::g_Mutex, std::defer_lock );
112  wxString dialogTitle;
113  SYMBOL_LIB_TABLE* libs = Prj().SchSymbolLibTable();
114 
115  // One CHOOSE_COMPONENT dialog at a time. User probaby can't handle more anyway.
116  if( !dialogLock.try_lock() )
117  return COMPONENT_SELECTION();
118 
119  auto adapterPtr( SYMBOL_TREE_MODEL_ADAPTER::Create( libs ) );
120  auto adapter = static_cast<SYMBOL_TREE_MODEL_ADAPTER*>( adapterPtr.get() );
121  bool loaded = false;
122 
123  if( aFilter )
124  {
125  const wxArrayString& liblist = aFilter->GetAllowedLibList();
126 
127  for( unsigned ii = 0; ii < liblist.GetCount(); ii++ )
128  {
129  if( libs->HasLibrary( liblist[ii], true ) )
130  {
131  loaded = true;
132  adapter->AddLibrary( liblist[ii] );
133  }
134  }
135 
136  adapter->AssignIntrinsicRanks();
137 
138  if( aFilter->GetFilterPowerParts() )
139  adapter->SetFilter( SYMBOL_TREE_MODEL_ADAPTER::CMP_FILTER_POWER );
140  }
141 
142  std::vector< LIB_TREE_ITEM* > history_list;
143 
144  for( auto const& i : aHistoryList )
145  {
146  LIB_ALIAS* alias = GetLibAlias( i.LibId );
147 
148  if( alias )
149  history_list.push_back( alias );
150  }
151 
152  adapter->DoAddLibrary( "-- " + _( "Recently Used" ) + " --", wxEmptyString, history_list, true );
153 
154  if( !aHistoryList.empty() )
155  adapter->SetPreselectNode( aHistoryList[0].LibId, aHistoryList[0].Unit );
156 
157  const std::vector< wxString > libNicknames = libs->GetLogicalLibs();
158 
159  if( !loaded )
160  adapter->AddLibraries( libNicknames, this );
161 
162  if( aHighlight && aHighlight->IsValid() )
163  adapter->SetPreselectNode( *aHighlight, /* aUnit */ 0 );
164 
165  if( adapter->GetFilter() == SYMBOL_TREE_MODEL_ADAPTER::CMP_FILTER_POWER )
166  dialogTitle.Printf( _( "Choose Power Symbol (%d items loaded)" ), adapter->GetItemCount() );
167  else
168  dialogTitle.Printf( _( "Choose Symbol (%d items loaded)" ), adapter->GetItemCount() );
169 
170  DIALOG_CHOOSE_COMPONENT dlg( this, dialogTitle, adapterPtr, aConvert,
171  aAllowFields, aShowFootprints, aAllowBrowser );
172 
173  if( dlg.ShowQuasiModal() == wxID_CANCEL )
174  return COMPONENT_SELECTION();
175 
177  LIB_ID id;
178 
179  if( dlg.IsExternalBrowserSelected() ) // User requested component browser.
180  {
181  sel = SelectComponentFromLibBrowser( this, aFilter, id, sel.Unit, sel.Convert );
182  id = sel.LibId;
183  }
184  else
185  id = dlg.GetSelectedLibId( &sel.Unit );
186 
187  if( !id.IsValid() ) // Dialog closed by OK button,
188  // or the selection by lib browser was requested,
189  // but no symbol selected
190  return COMPONENT_SELECTION();
191 
192  if( sel.Unit == 0 )
193  sel.Unit = 1;
194 
195  sel.Fields = dlg.GetFields();
196  sel.LibId = id;
197 
198  if( sel.LibId.IsValid() )
199  {
200  aHistoryList.erase(
201  std::remove_if(
202  aHistoryList.begin(),
203  aHistoryList.end(),
204  [ &sel ]( COMPONENT_SELECTION const& i ){ return i.LibId == sel.LibId; } ),
205  aHistoryList.end() );
206 
207  aHistoryList.insert( aHistoryList.begin(), sel );
208  }
209 
210  return sel;
211 }
212 
213 
215  SCH_BASE_FRAME::HISTORY_LIST& aHistoryList,
216  bool aAllowBrowser )
217 {
218  wxString msg;
219 
220  SetRepeatItem( NULL );
222 
223  auto sel = SelectComponentFromLibTree( aFilter, aHistoryList, aAllowBrowser, 1, 1,
224  m_footprintPreview );
225 
226  if( !sel.LibId.IsValid() )
227  {
228  m_canvas->SetIgnoreMouseEvents( false );
230  return NULL;
231  }
232 
233  m_canvas->SetIgnoreMouseEvents( false );
235 
236  wxString libsource; // the library name to use. If empty, load from any lib
237 
238  if( aFilter )
239  libsource = aFilter->GetLibSource();
240 
241  LIB_ID libId = sel.LibId;
242 
243  LIB_PART* part = GetLibPart( libId, true );
244 
245  if( !part )
246  return NULL;
247 
248  SCH_COMPONENT* component = new SCH_COMPONENT( *part, m_CurrentSheet, sel.Unit, sel.Convert,
249  GetCrossHairPosition(), true );
250 
251  // Set the m_ChipName value, from component name in lib, for aliases
252  // Note if part is found, and if name is an alias of a component,
253  // alias exists because its root component was found
254  component->SetLibId( libId );
255 
256  // Be sure the link to the corresponding LIB_PART is OK:
257  component->Resolve( *Prj().SchSymbolLibTable() );
258 
259  // Set any fields that have been modified
260  for( auto const& i : sel.Fields )
261  {
262  auto field = component->GetField( i.first );
263 
264  if( field )
265  field->SetText( i.second );
266  }
267 
268  // Set the component value that can differ from component name in lib, for aliases
269  component->GetField( VALUE )->SetText( sel.LibId.GetLibItemName() );
270 
271  // If there is no field defined in the component, copy one over from the library
272  // ( from the .dcm file )
273  // This way the Datasheet field will not be empty and can be changed from the schematic
274  if( component->GetField( DATASHEET )->GetText().IsEmpty() )
275  {
276  LIB_ALIAS* entry = GetLibAlias( component->GetLibId(), true, true );
277 
278  if( entry && !!entry->GetDocFileName() )
279  component->GetField( DATASHEET )->SetText( entry->GetDocFileName() );
280  }
281 
282  MSG_PANEL_ITEMS items;
283 
284  component->SetCurrentSheetPath( &GetCurrentSheet() );
285  component->GetMsgPanelInfo( m_UserUnits, items );
286 
287  SetMsgPanel( items );
288  component->SetFlags( IS_NEW );
289 
290  if( m_autoplaceFields )
291  component->AutoplaceFields( /* aScreen */ NULL, /* aManual */ false );
292 
293  PrepareMoveItem( component );
294 
295  return component;
296 }
297 
298 
300 {
301  SCH_SCREEN* screen = GetScreen();
302  SCH_ITEM* item = screen->GetCurItem();
303  SCH_COMPONENT* component = (SCH_COMPONENT*) item;
304 
306 
307  if( item->GetFlags() == 0 )
308  SetUndoItem( item );
309 
310  component->SetOrientation( aOrientation );
311 
312  m_canvas->CrossHairOn( );
313 
314  if( item->GetFlags() == 0 )
315  {
316  addCurrentItemToScreen();
317  SchematicCleanUp( true );
318  }
319 
320  TestDanglingEnds();
321 
322  RefreshItem( item );
323  OnModify();
324 }
325 
326 
327 void SCH_EDIT_FRAME::OnSelectUnit( wxCommandEvent& aEvent )
328 {
329  SCH_SCREEN* screen = GetScreen();
330  SCH_ITEM* item = screen->GetCurItem();
331  SCH_COMPONENT* component = (SCH_COMPONENT*) item;
332 
334 
335  int unit = aEvent.GetId() + 1 - ID_POPUP_SCH_SELECT_UNIT1;
336 
337  LIB_PART* part = GetLibPart( component->GetLibId() );
338 
339  if( !part )
340  return;
341 
342  int unitCount = part->GetUnitCount();
343 
344  if( unitCount <= 1 || component->GetUnit() == unit )
345  return;
346 
347  if( unit > unitCount )
348  unit = unitCount;
349 
350  STATUS_FLAGS flags = component->GetFlags();
351 
352  if( !flags ) // No command in progress: save in undo list
353  SaveCopyInUndoList( component, UR_CHANGED );
354 
355  /* Update the unit number. */
356  component->SetUnitSelection( m_CurrentSheet, unit );
357  component->SetUnit( unit );
358  component->ClearFlags();
359  component->SetFlags( flags ); // Restore m_Flag modified by SetUnit()
360 
361  if( m_autoplaceFields )
362  component->AutoAutoplaceFields( GetScreen() );
363 
364  TestDanglingEnds();
365 
366  RefreshItem( component );
367  OnModify();
368 }
369 
370 
372 {
373  if( !aComponent )
374  return;
375 
376  LIB_ID id = aComponent->GetLibId();
377  LIB_PART* part = GetLibPart( id );
378 
379  if( part )
380  {
381  wxString msg;
382 
383  if( !part->HasConversion() )
384  {
385  msg.Printf( _( "No alternate body style found for symbol \"%s\" in library \"%s\"." ),
386  id.GetLibItemName().wx_str(), id.GetLibNickname().wx_str() );
387  DisplayError( this, msg );
388  return;
389  }
390 
391  STATUS_FLAGS flags = aComponent->GetFlags();
392 
393  aComponent->SetConvert( aComponent->GetConvert() + 1 );
394 
395  // ensure m_Convert = 0, 1 or 2
396  // 0 and 1 = shape 1 = not converted
397  // 2 = shape 2 = first converted shape
398  // > 2 is not used but could be used for more shapes
399  // like multiple shapes for a programmable component
400  // When m_Convert = val max, return to the first shape
401  if( aComponent->GetConvert() > 2 )
402  aComponent->SetConvert( 1 );
403 
404  // The alternate symbol may cause a change in the connection status so test the
405  // connections so the connection indicators are drawn correctly.
406  TestDanglingEnds();
407  aComponent->ClearFlags();
408  aComponent->SetFlags( flags ); // Restore m_Flag (modified by SetConvert())
409 
410  RefreshItem( aComponent );
411  OnModify();
412  }
413 }
bool IsValid() const
Definition: lib_id.h:171
void OrientComponent(COMPONENT_ORIENTATION_T aOrientation=CMP_NORMAL)
Rotate and mirror a component.
Definition: getpart.cpp:299
void SetFilter(const SCHLIB_FILTER *aFilter)
Set a filter to display only libraries and/or components which match the filter.
void AutoAutoplaceFields(SCH_SCREEN *aScreen)
Autoplace fields only if correct to do so automatically.
STATUS_FLAGS GetFlags() const
Definition: base_struct.h:258
Part library alias object definition.
KIWAY & Kiway() const
Function Kiway returns a reference to the KIWAY that this object has an opportunity to participate in...
Definition: kiway_player.h:60
name of datasheet
void Parse(void *yyp, int yymajor, ParseTOKENTYPE yyminorParseARG_PDECL)
void SetUnitAndConvert(int aUnit, int aConvert)
Set unit and convert, and set flag preventing them from automatically resetting to 1...
bool HasConversion() const
Test if part has more than one body conversion type (DeMorgan).
COMPONENT_ORIENTATION_T
enum used in RotationMiroir()
This file is part of the common library.
COMPONENT_SELECTION SelectComponentFromLibBrowser(wxTopLevelWindow *aParent, const SCHLIB_FILTER *aFilter, const LIB_ID &aPreselectedLibid, int aUnit, int aConvert)
Function SelectComponentFromLibBrowser Calls the library viewer to select component to import into sc...
Definition: getpart.cpp:54
bool Resolve(PART_LIBS *aLibs)
Assigns the current LIB_PART from aLibs which this symbol is based on.
virtual void MoveCursorToCrossHair() override
Function MoveCursorToCrossHair warps the cursor to the current cross hair position.
SCH_SCREEN * GetScreen() const override
Return a pointer to a BASE_SCREEN or one of its derivatives.
std::vector< COMPONENT_SELECTION > HISTORY_LIST
void ConvertPart(SCH_COMPONENT *DrawComponent)
Definition: getpart.cpp:371
LIB_PART * GetLibPart(const LIB_ID &aLibId, bool aUseCacheLib=false, bool aShowErrorMsg=false)
void SetUnitSelection(SCH_SHEET_PATH *aSheet, int aUnitSelection)
A logical library item identifier and consists of various portions much like a URI.
Definition: lib_id.h:51
virtual void MoveCursorToCrossHair()
Function MoveCursorToCrossHair warps the cursor to the current cross hair position.
void SetSelectedComponent(const wxString &aComponentName)
Set the selected component.
int GetUnit() const
Symbol library viewer main window.
Definition: viewlib_frame.h:44
void SetConvert(int aConvert)
#define IS_NEW
New item, just created.
Definition: base_struct.h:114
void SetCurrentSheetPath(const SCH_SHEET_PATH *aSheetPath)
Dialog class to select a component from the libraries.
int GetConvert() const
PROJECT & Prj() const
Function Prj returns a reference to the PROJECT "associated with" this KIWAY.
void SetLibId(const LIB_ID &aName, PART_LIBS *aLibs=NULL)
std::vector< std::pair< int, wxString > > GetFields() const
Get a list of fields edited by the user.
a helper to handle the real device context used in KiCad
bool HasLibrary(const wxString &aNickname, bool aCheckEnabled=false) const
Test for the existence of aNickname in the library table.
void SetFlags(STATUS_FLAGS aMask)
Definition: base_struct.h:256
SCH_FIELD * GetField(int aFieldNdx) const
Returns a field in this symbol.
bool IsExternalBrowserSelected() const
Function IsExternalBrowserSelected.
VTBL_ENTRY KIWAY_PLAYER * Player(FRAME_T aFrameType, bool doCreate=true, wxTopLevelWindow *aParent=NULL)
Function Player returns the KIWAY_PLAYER* given a FRAME_T.
Definition: kiway.cpp:300
const wxArrayString & GetAllowedLibList() const
void SetMsgPanel(const std::vector< MSG_PANEL_ITEM > &aList)
Clear the message panel and populates it with the contents of aList.
SCH_ITEM * GetCurItem() const
Return the currently selected SCH_ITEM, overriding BASE_SCREEN::GetCurItem().
Definition: sch_screen.h:196
virtual void CrossHairOn(wxDC *DC=nullptr)
const UTF8 & GetLibItemName() const
Definition: lib_id.h:114
int ShowQuasiModal()
int GetConvert() const
const wxString & GetText() const
Function GetText returns the string associated with the text object.
Definition: eda_text.h:143
SCH_DRAW_PANEL * GetCanvas() const override
SCH_COMPONENT * Load_Component(const SCHLIB_FILTER *aFilter, SCH_BASE_FRAME::HISTORY_LIST &aHistoryList, bool aUseLibBrowser)
Load a symbol library and places it on the current schematic.
Definition: getpart.cpp:214
Define a library symbol object.
void OnSelectUnit(wxCommandEvent &aEvent)
Definition: getpart.cpp:327
unsigned STATUS_FLAGS
Definition: base_struct.h:147
LIB_ALIAS * GetLibAlias(const LIB_ID &aLibId, bool aUseCacheLib=false, bool aShowError=false)
Load symbol from symbol library table.
bool GetFilterPowerParts() const
void SetUnit(int aUnit)
Change the unit number to aUnit.
std::vector< std::pair< int, wxString > > Fields
void GetMsgPanelInfo(EDA_UNITS_T aUnits, std::vector< MSG_PANEL_ITEM > &aList) override
Function GetMsgPanelInfo populates aList of MSG_PANEL_ITEM objects with it&#39;s internal state for displ...
int GetUnitCount() const
const wxString & GetDocFileName() const
EDA_DRAW_PANEL * m_canvas
The area to draw on.
Definition: draw_frame.h:123
Definition the SCH_COMPONENT class for Eeschema.
static PTR Create(LIB_TABLE *aLibs)
Factory function: create a model adapter in a reference-counting container.
see class PGM_BASE
void AutoplaceFields(SCH_SCREEN *aScreen, bool aManual)
Automatically orient all the fields in the component.
void RefreshItem(SCH_ITEM *aItem, bool isAddOrDelete=false)
Mark an item for refresh.
size_t i
Definition: json11.cpp:597
void SetIgnoreMouseEvents(bool aIgnore)
Class SCH_COMPONENT describes a real schematic component.
Definition: sch_component.h:69
const LIB_ID & GetLibId() const
std::vector< MSG_PANEL_ITEM > MSG_PANEL_ITEMS
Definition: msgpanel.h:102
UTF8 Format() const
Definition: lib_id.cpp:237
bool Destroy() override
Our version of Destroy() which is virtual from wxWidgets.
void ClearFlags(STATUS_FLAGS aMask=EDA_ITEM_ALL_FLAGS)
Definition: base_struct.h:257
LIB_ID GetSelectedLibId(int *aUnit=nullptr) const
To be called after this dialog returns from ShowModal().
Definition of class LIB_EDIT_FRAME.
Definition for part library class.
COMPONENT_SELECTION SelectComponentFromLibTree(const SCHLIB_FILTER *aFilter, std::vector< COMPONENT_SELECTION > &aHistoryList, bool aUseLibBrowser, int aUnit, int aConvert, bool aShowFootprints, const LIB_ID *aHighlight=nullptr, bool aAllowFields=true)
Function SelectComponentFromLib Calls the library viewer to select component to import into schematic...
Definition: getpart.cpp:101
const wxString & GetLibSource() const
const UTF8 & GetLibNickname() const
Return the logical library name portion of a LIB_ID.
Definition: lib_id.h:97
Message panel definition file.
EDA_UNITS_T m_UserUnits
Definition: draw_frame.h:120
#define VALUE
void DisplayError(wxWindow *parent, const wxString &text, int displaytime)
Function DisplayError displays an error or warning message box with aMessage.
Definition: confirm.cpp:245
wxPoint GetCrossHairPosition(bool aInvertY=false) const
Return the current cross hair position in logical (drawing) coordinates.
Class SCH_ITEM is a base class for any item which can be embedded within the SCHEMATIC container clas...
VTBL_ENTRY bool ShowModal(wxString *aResult=NULL, wxWindow *aResultantFocusWindow=NULL)
Function ShowModal puts up this wxFrame as if it were a modal dialog, with all other instantiated wxF...
std::vector< wxString > GetLogicalLibs()
Return the logical library names, all of them that are pertinent to a look up done on this LIB_TABLE...
void SetSelectedLibrary(const wxString &aLibName)
Set the selected library in the library window.
virtual void SetText(const wxString &aText)
Definition: eda_text.h:154
void SetOrientation(int aOrientation)
Compute the new transform matrix based on aOrientation for the symbol which is applied to the current...