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 = dlg.GetSelectedLibId( &sel.Unit );
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 
185  if( !id.IsValid() ) // Dialog closed by OK button,
186  // or the selection by lib browser was requested,
187  // but no symbol selected
188  return COMPONENT_SELECTION();
189 
190  if( sel.Unit == 0 )
191  sel.Unit = 1;
192 
193  sel.Fields = dlg.GetFields();
194  sel.LibId = id;
195 
196  if( sel.LibId.IsValid() )
197  {
198  aHistoryList.erase(
199  std::remove_if(
200  aHistoryList.begin(),
201  aHistoryList.end(),
202  [ &sel ]( COMPONENT_SELECTION const& i ){ return i.LibId == sel.LibId; } ),
203  aHistoryList.end() );
204 
205  aHistoryList.insert( aHistoryList.begin(), sel );
206  }
207 
208  return sel;
209 }
210 
211 
213  SCH_BASE_FRAME::HISTORY_LIST& aHistoryList,
214  bool aAllowBrowser )
215 {
216  wxString msg;
217 
218  SetRepeatItem( NULL );
220 
221  auto sel = SelectComponentFromLibTree( aFilter, aHistoryList, aAllowBrowser, 1, 1,
223 
224  if( !sel.LibId.IsValid() )
225  {
226  m_canvas->SetIgnoreMouseEvents( false );
228  return NULL;
229  }
230 
231  m_canvas->SetIgnoreMouseEvents( false );
233 
234  wxString libsource; // the library name to use. If empty, load from any lib
235 
236  if( aFilter )
237  libsource = aFilter->GetLibSource();
238 
239  LIB_ID libId = sel.LibId;
240 
241  LIB_PART* part = GetLibPart( libId, true );
242 
243  if( !part )
244  return NULL;
245 
246  SCH_COMPONENT* component = new SCH_COMPONENT( *part, libId, m_CurrentSheet,
247  sel.Unit, sel.Convert,
248  GetCrossHairPosition(), true );
249 
250  // Be sure the link to the corresponding LIB_PART is OK:
251  component->Resolve( *Prj().SchSymbolLibTable() );
252 
253  // Set any fields that have been modified
254  for( auto const& i : sel.Fields )
255  {
256  auto field = component->GetField( i.first );
257 
258  if( field )
259  field->SetText( i.second );
260  }
261 
262  MSG_PANEL_ITEMS items;
263 
264  component->SetCurrentSheetPath( &GetCurrentSheet() );
265  component->GetMsgPanelInfo( m_UserUnits, items );
266 
267  SetMsgPanel( items );
268  component->SetFlags( IS_NEW );
269 
270  if( m_autoplaceFields )
271  component->AutoplaceFields( /* aScreen */ NULL, /* aManual */ false );
272 
273  PrepareMoveItem( component );
274 
275  return component;
276 }
277 
278 
280 {
281  SCH_SCREEN* screen = GetScreen();
282  SCH_ITEM* item = screen->GetCurItem();
283  SCH_COMPONENT* component = (SCH_COMPONENT*) item;
284 
286 
287  if( item->GetFlags() == 0 )
288  SetUndoItem( item );
289 
290  component->SetOrientation( aOrientation );
291 
292  m_canvas->CrossHairOn( );
293 
294  if( item->GetFlags() == 0 )
295  {
297  SchematicCleanUp( true );
298  }
299 
301 
302  RefreshItem( item );
303  OnModify();
304 }
305 
306 
307 void SCH_EDIT_FRAME::OnSelectUnit( wxCommandEvent& aEvent )
308 {
309  SCH_SCREEN* screen = GetScreen();
310  SCH_ITEM* item = screen->GetCurItem();
311  SCH_COMPONENT* component = (SCH_COMPONENT*) item;
312 
314 
315  int unit = aEvent.GetId() + 1 - ID_POPUP_SCH_SELECT_UNIT1;
316 
317  LIB_PART* part = GetLibPart( component->GetLibId() );
318 
319  if( !part )
320  return;
321 
322  int unitCount = part->GetUnitCount();
323 
324  if( unitCount <= 1 || component->GetUnit() == unit )
325  return;
326 
327  if( unit > unitCount )
328  unit = unitCount;
329 
330  STATUS_FLAGS flags = component->GetFlags();
331 
332  if( !flags ) // No command in progress: save in undo list
333  SaveCopyInUndoList( component, UR_CHANGED );
334 
335  /* Update the unit number. */
336  component->SetUnitSelection( m_CurrentSheet, unit );
337  component->SetUnit( unit );
338  component->ClearFlags();
339  component->SetFlags( flags ); // Restore m_Flag modified by SetUnit()
340 
341  if( m_autoplaceFields )
342  component->AutoAutoplaceFields( GetScreen() );
343 
345 
346  RefreshItem( component );
347  OnModify();
348 }
349 
350 
352 {
353  if( !aComponent )
354  return;
355 
356  LIB_ID id = aComponent->GetLibId();
357  LIB_PART* part = GetLibPart( id );
358 
359  if( part )
360  {
361  wxString msg;
362 
363  if( !part->HasConversion() )
364  {
365  msg.Printf( _( "No alternate body style found for symbol \"%s\" in library \"%s\"." ),
366  id.GetLibItemName().wx_str(), id.GetLibNickname().wx_str() );
367  DisplayError( this, msg );
368  return;
369  }
370 
371  STATUS_FLAGS flags = aComponent->GetFlags();
372 
373  aComponent->SetConvert( aComponent->GetConvert() + 1 );
374 
375  // ensure m_Convert = 0, 1 or 2
376  // 0 and 1 = shape 1 = not converted
377  // 2 = shape 2 = first converted shape
378  // > 2 is not used but could be used for more shapes
379  // like multiple shapes for a programmable component
380  // When m_Convert = val max, return to the first shape
381  if( aComponent->GetConvert() > 2 )
382  aComponent->SetConvert( 1 );
383 
384  // The alternate symbol may cause a change in the connection status so test the
385  // connections so the connection indicators are drawn correctly.
386  aComponent->UpdatePinCache();
388  aComponent->ClearFlags();
389  aComponent->SetFlags( flags ); // Restore m_Flag (modified by SetConvert())
390 
391  RefreshItem( aComponent );
392  OnModify();
393  }
394 }
void OrientComponent(COMPONENT_ORIENTATION_T aOrientation=CMP_NORMAL)
Rotate and mirror a component.
Definition: getpart.cpp:279
int GetUnitCount() const
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.
Part library alias object definition.
bool SchematicCleanUp(bool aAppend=false)
Performs routine schematic cleaning including breaking wire and buses and deleting identical objects ...
const UTF8 & GetLibItemName() const
Definition: lib_id.h:114
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
bool HasLibrary(const wxString &aNickname, bool aCheckEnabled=false) const
Test for the existence of aNickname in the library table.
void SetUnitAndConvert(int aUnit, int aConvert)
Set unit and convert, and set flag preventing them from automatically resetting to 1.
const wxString & GetLibSource() const
bool ShowModal(wxString *aSymbol, wxWindow *aParent) override
Function ShowModal.
COMPONENT_ORIENTATION_T
enum used in RotationMiroir()
This file is part of the common library.
void Parse(void *yyp, int yymajor, ParseTOKENTYPE yyminor ParseARG_PDECL)
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 HasConversion() const
Test if part has more than one body conversion type (DeMorgan).
void OnModify()
Must be called after a schematic change in order to set the "modify" flag of the current screen* and ...
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.
int GetUnit() const
std::vector< COMPONENT_SELECTION > HISTORY_LIST
void ConvertPart(SCH_COMPONENT *DrawComponent)
Definition: getpart.cpp:351
LIB_PART * GetLibPart(const LIB_ID &aLibId, bool aUseCacheLib=false, bool aShowErrorMsg=false)
bool TestDanglingEnds()
Test all of the connectable objects in the schematic for unused connection points.
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.
bool IsValid() const
Definition: lib_id.h:171
void SetSelectedComponent(const wxString &aComponentName)
Set the selected component.
Symbol library viewer main window.
Definition: viewlib_frame.h:44
SCH_ITEM * GetCurItem() const
Return the currently selected SCH_ITEM, overriding BASE_SCREEN::GetCurItem().
Definition: sch_screen.h:196
void SetRepeatItem(SCH_ITEM *aItem)
Clone aItem and owns that clone in this container.
int GetConvert() const
SCH_FIELD * GetField(int aFieldNdx) const
Returns a field in this symbol.
void SetConvert(int aConvert)
#define IS_NEW
New item, just created.
Definition: base_struct.h:114
void SetCurrentSheetPath(const SCH_SHEET_PATH *aSheetPath)
SCH_SCREEN * GetScreen() const override
Return a pointer to a BASE_SCREEN or one of its derivatives.
Dialog class to select a component from the libraries.
SCH_SHEET_PATH * m_CurrentSheet
which sheet we are presently working on.
bool IsExternalBrowserSelected() const
Function IsExternalBrowserSelected.
void UpdatePinCache()
Updates the local cache of pin positions.
bool m_footprintPreview
whether to show footprint previews
a helper to handle the real device context used in KiCad
void PrepareMoveItem(SCH_ITEM *aItem)
Start moving aItem using the mouse.
Definition: schedit.cpp:744
void SetFlags(STATUS_FLAGS aMask)
Definition: base_struct.h:256
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
void SetMsgPanel(const std::vector< MSG_PANEL_ITEM > &aList)
Clear the message panel and populates it with the contents of aList.
std::vector< std::pair< int, wxString > > GetFields() const
Get a list of fields edited by the user.
virtual void CrossHairOn(wxDC *DC=nullptr)
int ShowQuasiModal()
PROJECT & Prj() const
Function Prj returns a reference to the PROJECT "associated with" this KIWAY.
SCH_DRAW_PANEL * GetCanvas() const override
SCH_SHEET_PATH & GetCurrentSheet()
void SaveCopyInUndoList(SCH_ITEM *aItemToCopy, UNDO_REDO_T aTypeCommand, bool aAppend=false, const wxPoint &aTransformPoint=wxPoint(0, 0))
Create a copy of the current schematic item, and put it in the undo list.
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:212
Define a library symbol object.
void OnSelectUnit(wxCommandEvent &aEvent)
Definition: getpart.cpp:307
unsigned STATUS_FLAGS
Definition: base_struct.h:147
const UTF8 & GetLibNickname() const
Return the logical library name portion of a LIB_ID.
Definition: lib_id.h:97
LIB_ALIAS * GetLibAlias(const LIB_ID &aLibId, bool aUseCacheLib=false, bool aShowError=false)
Load symbol from symbol library table.
void SetUnit(int aUnit)
Change the unit number to aUnit.
bool GetFilterPowerParts() const
UTF8 Format() const
Definition: lib_id.cpp:237
std::vector< std::pair< int, wxString > > Fields
bool m_autoplaceFields
automatically place component 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's internal state for displ...
EDA_DRAW_PANEL * m_canvas
The area to draw on.
Definition: draw_frame.h:126
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 wxArrayString & GetAllowedLibList() const
std::vector< MSG_PANEL_ITEM > MSG_PANEL_ITEMS
Definition: msgpanel.h:102
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
Definition of class LIB_EDIT_FRAME.
int GetConvert() const
void SetUndoItem(const SCH_ITEM *aItem)
Clone aItem which can be used to restore the state of the item being edited when the user cancels the...
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
void addCurrentItemToScreen()
Add the item currently being edited to the schematic and adds the changes to the undo/redo container.
Message panel definition file.
STATUS_FLAGS GetFlags() const
Definition: base_struct.h:258
const LIB_ID & GetLibId() const
EDA_UNITS_T m_UserUnits
Definition: draw_frame.h:123
void DisplayError(wxWindow *parent, const wxString &text, int displaytime)
Function DisplayError displays an error or warning message box with aMessage.
Definition: confirm.cpp:243
Class SCH_ITEM is a base class for any item which can be embedded within the SCHEMATIC container clas...
LIB_ID GetSelectedLibId(int *aUnit=nullptr) const
To be called after this dialog returns from ShowModal().
std::vector< wxString > GetLogicalLibs()
Return the logical library names, all of them that are pertinent to a look up done on this LIB_TABLE.
wxPoint GetCrossHairPosition(bool aInvertY=false) const
Return the current cross hair position in logical (drawing) coordinates.
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...