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, libId, m_CurrentSheet,
249  sel.Unit, sel.Convert,
250  GetCrossHairPosition(), true );
251 
252  // Be sure the link to the corresponding LIB_PART is OK:
253  component->Resolve( *Prj().SchSymbolLibTable() );
254 
255  // Set any fields that have been modified
256  for( auto const& i : sel.Fields )
257  {
258  auto field = component->GetField( i.first );
259 
260  if( field )
261  field->SetText( i.second );
262  }
263 
264  MSG_PANEL_ITEMS items;
265 
266  component->SetCurrentSheetPath( &GetCurrentSheet() );
267  component->GetMsgPanelInfo( m_UserUnits, items );
268 
269  SetMsgPanel( items );
270  component->SetFlags( IS_NEW );
271 
272  if( m_autoplaceFields )
273  component->AutoplaceFields( /* aScreen */ NULL, /* aManual */ false );
274 
275  PrepareMoveItem( component );
276 
277  return component;
278 }
279 
280 
282 {
283  SCH_SCREEN* screen = GetScreen();
284  SCH_ITEM* item = screen->GetCurItem();
285  SCH_COMPONENT* component = (SCH_COMPONENT*) item;
286 
288 
289  if( item->GetFlags() == 0 )
290  SetUndoItem( item );
291 
292  component->SetOrientation( aOrientation );
293 
294  m_canvas->CrossHairOn( );
295 
296  if( item->GetFlags() == 0 )
297  {
298  addCurrentItemToScreen();
299  SchematicCleanUp( true );
300  }
301 
302  TestDanglingEnds();
303 
304  RefreshItem( item );
305  OnModify();
306 }
307 
308 
309 void SCH_EDIT_FRAME::OnSelectUnit( wxCommandEvent& aEvent )
310 {
311  SCH_SCREEN* screen = GetScreen();
312  SCH_ITEM* item = screen->GetCurItem();
313  SCH_COMPONENT* component = (SCH_COMPONENT*) item;
314 
316 
317  int unit = aEvent.GetId() + 1 - ID_POPUP_SCH_SELECT_UNIT1;
318 
319  LIB_PART* part = GetLibPart( component->GetLibId() );
320 
321  if( !part )
322  return;
323 
324  int unitCount = part->GetUnitCount();
325 
326  if( unitCount <= 1 || component->GetUnit() == unit )
327  return;
328 
329  if( unit > unitCount )
330  unit = unitCount;
331 
332  STATUS_FLAGS flags = component->GetFlags();
333 
334  if( !flags ) // No command in progress: save in undo list
335  SaveCopyInUndoList( component, UR_CHANGED );
336 
337  /* Update the unit number. */
338  component->SetUnitSelection( m_CurrentSheet, unit );
339  component->SetUnit( unit );
340  component->ClearFlags();
341  component->SetFlags( flags ); // Restore m_Flag modified by SetUnit()
342 
343  if( m_autoplaceFields )
344  component->AutoAutoplaceFields( GetScreen() );
345 
346  TestDanglingEnds();
347 
348  RefreshItem( component );
349  OnModify();
350 }
351 
352 
354 {
355  if( !aComponent )
356  return;
357 
358  LIB_ID id = aComponent->GetLibId();
359  LIB_PART* part = GetLibPart( id );
360 
361  if( part )
362  {
363  wxString msg;
364 
365  if( !part->HasConversion() )
366  {
367  msg.Printf( _( "No alternate body style found for symbol \"%s\" in library \"%s\"." ),
368  id.GetLibItemName().wx_str(), id.GetLibNickname().wx_str() );
369  DisplayError( this, msg );
370  return;
371  }
372 
373  STATUS_FLAGS flags = aComponent->GetFlags();
374 
375  aComponent->SetConvert( aComponent->GetConvert() + 1 );
376 
377  // ensure m_Convert = 0, 1 or 2
378  // 0 and 1 = shape 1 = not converted
379  // 2 = shape 2 = first converted shape
380  // > 2 is not used but could be used for more shapes
381  // like multiple shapes for a programmable component
382  // When m_Convert = val max, return to the first shape
383  if( aComponent->GetConvert() > 2 )
384  aComponent->SetConvert( 1 );
385 
386  // The alternate symbol may cause a change in the connection status so test the
387  // connections so the connection indicators are drawn correctly.
388  TestDanglingEnds();
389  aComponent->ClearFlags();
390  aComponent->SetFlags( flags ); // Restore m_Flag (modified by SetConvert())
391 
392  RefreshItem( aComponent );
393  OnModify();
394  }
395 }
bool IsValid() const
Definition: lib_id.h:171
void OrientComponent(COMPONENT_ORIENTATION_T aOrientation=CMP_NORMAL)
Rotate and mirror a component.
Definition: getpart.cpp:281
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
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:353
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.
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
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:309
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
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:70
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
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...