KiCad PCB EDA Suite
load_select_footprint.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) 2018 Jean-Pierre Charras, jean-pierre.charras@ujf-grenoble.fr
5  * Copyright (C) 2012 SoftPLC Corporation, Dick Hollenbeck <dick@softplc.com>
6  * Copyright (C) 1992-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 
26 #include <functional>
27 using namespace std::placeholders;
28 
29 #include <class_board.h>
30 #include <class_module.h>
31 #include <confirm.h>
35 #include <dialog_helpers.h>
36 #include <footprint_edit_frame.h>
37 #include <footprint_info_impl.h>
38 #include <footprint_tree_pane.h>
39 #include <footprint_viewer_frame.h>
40 #include <fp_lib_table.h>
41 #include <io_mgr.h>
42 #include <kicad_string.h>
43 #include <kiway.h>
44 #include <lib_id.h>
45 #include <macros.h>
46 #include <pcb_draw_panel_gal.h>
47 #include <pcb_edit_frame.h>
48 #include <pcbnew.h>
49 #include <pcbnew_settings.h>
50 #include <pgm_base.h>
51 #include <view/view_controls.h>
52 #include <widgets/lib_tree.h>
54 
55 #include "fp_tree_model_adapter.h"
56 
57 
58 static wxArrayString s_ModuleHistoryList;
59 static unsigned s_ModuleHistoryMaxCount = 8;
60 
61 static void AddModuleToHistory( const wxString& aName )
62 {
63  // Remove duplicates
64  for( int ii = s_ModuleHistoryList.GetCount() - 1; ii >= 0; --ii )
65  {
66  if( s_ModuleHistoryList[ ii ] == aName )
67  s_ModuleHistoryList.RemoveAt( (size_t) ii );
68  }
69 
70  // Add the new name at the beginning of the history list
71  s_ModuleHistoryList.Insert( aName, 0 );
72 
73  // Remove extra names
74  while( s_ModuleHistoryList.GetCount() >= s_ModuleHistoryMaxCount )
75  s_ModuleHistoryList.RemoveAt( s_ModuleHistoryList.GetCount() - 1 );
76 }
77 
78 
79 static void clearModuleItemFlags( BOARD_ITEM* aItem )
80 {
81  aItem->ClearFlags();
82 }
83 
84 #include <bitmaps.h>
86 {
87  bool is_last_fp_from_brd = IsCurrentFPFromBoard();
88 
89  MODULE* newModule;
91 
92  if( frame == NULL ) // happens if no board editor opened
93  return false;
94 
95  if( aModule == NULL )
96  {
97  if( !frame->GetBoard() || !frame->GetBoard()->GetFirstModule() )
98  return false;
99 
100  aModule = SelectFootprintFromBoard( frame->GetBoard() );
101  }
102 
103  if( aModule == NULL )
104  return false;
105 
106  if( !Clear_Pcb( true ) )
107  return false;
108 
109  newModule = (MODULE*) aModule->Duplicate();
110  newModule->SetParent( GetBoard() );
111  newModule->SetLink( aModule->m_Uuid );
112 
113  newModule->ClearFlags();
114  newModule->RunOnChildren( std::bind( &clearModuleItemFlags, _1 ) );
115 
116  AddModuleToBoard( newModule );
117 
118  // Clear references to any net info, because the footprint editor
119  // does know any thing about nets handled by the current edited board.
120  // Morever we do not want to save any reference to an unknown net when
121  // saving the footprint in lib cache
122  // so we force the ORPHANED dummy net info for all pads
123  newModule->ClearAllNets();
124 
125  GetCanvas()->GetViewControls()->SetCrossHairCursorPosition( VECTOR2D( 0, 0 ), false );
126  PlaceModule( newModule );
127  newModule->SetPosition( wxPoint( 0, 0 ) ); // cursor in GAL may not be initialized at the moment
128 
129  // Put it on FRONT layer,
130  // because this is the default in ModEdit, and in libs
131  if( newModule->GetLayer() != F_Cu )
132  newModule->Flip( newModule->GetPosition(), frame->Settings().m_FlipLeftRight );
133 
134  // Put it in orientation 0,
135  // because this is the default orientation in ModEdit, and in libs
136  newModule->SetOrientation( 0 );
137 
138  Zoom_Automatique( false );
139 
140  m_adapter->SetPreselectNode( newModule->GetFPID(), 0 );
141 
142  GetScreen()->ClearUndoRedoList();
143  GetScreen()->ClrModify();
144 
145  // Update the save items if needed.
146  if( !is_last_fp_from_brd )
147  {
148  ReCreateMenuBar();
149  ReCreateHToolbar();
150 
151  if( IsSearchTreeShown() )
152  ToggleSearchTree();
153  }
154 
155  Update3DView( true );
156  updateView();
157  GetCanvas()->Refresh();
158  m_treePane->GetLibTree()->RefreshLibTree(); // update any previously-highlighted items
159 
160  return true;
161 }
162 
163 
165 {
166  // Close the current non-modal Lib browser if opened, and open a new one, in "modal" mode:
167  FOOTPRINT_VIEWER_FRAME* viewer;
169 
170  if( viewer )
171  {
172  viewer->Destroy();
173  // Destroy() does not immediately delete the viewer, if some events are pending.
174  // (for this reason delete operator cannot be used blindly with "top level" windows)
175  // so gives a slice of time to delete the viewer frame.
176  // This is especially important in OpenGL mode to avoid recreating context before
177  // the old one is deleted
178  wxSafeYield();
179  }
180 
181  SetFocus();
182 
183  // Creates the modal Lib browser:
185 
186  wxString fpid;
187  int ret = viewer->ShowModal( &fpid, this );
188  (void) ret; // make static analyser quiet
189 
190  viewer->Destroy();
191 
192  return fpid;
193 }
194 
195 
197 {
198  FP_LIB_TABLE* fpTable = Prj().PcbFootprintLibs();
199  wxString moduleName;
200  LIB_ID fpid;
201  MODULE* module = NULL;
202 
203  static wxString lastComponentName;
204 
205  // Load footprint files:
206  WX_PROGRESS_REPORTER* progressReporter = new WX_PROGRESS_REPORTER( this,
207  _( "Loading Footprint Libraries" ), 3 );
208  GFootprintList.ReadFootprintFiles( fpTable, nullptr, progressReporter );
209  bool cancel = progressReporter->WasCancelled();
210  progressReporter->Destroy();
211 
212  if( cancel )
213  return nullptr;
214 
217 
218  auto adapterPtr( FP_TREE_MODEL_ADAPTER::Create( this, fpTable ) );
219  auto adapter = static_cast<FP_TREE_MODEL_ADAPTER*>( adapterPtr.get() );
220 
221  std::vector<LIB_TREE_ITEM*> historyInfos;
222 
223  for( auto const& item : s_ModuleHistoryList )
224  {
225  LIB_TREE_ITEM* fp_info = GFootprintList.GetModuleInfo( item );
226 
227  // this can be null, for example, if the footprint has been deleted from a library.
228  if( fp_info != nullptr )
229  historyInfos.push_back( fp_info );
230  }
231 
232  adapter->DoAddLibrary( "-- " + _( "Recently Used" ) + " --", wxEmptyString, historyInfos, true );
233 
234  if( aPreselect.IsValid() )
235  adapter->SetPreselectNode( aPreselect, 0 );
236  else if( historyInfos.size() )
237  adapter->SetPreselectNode( historyInfos[0]->GetLibId(), 0 );
238 
239  adapter->AddLibraries();
240 
241  wxString title;
242  title.Printf( _( "Choose Footprint (%d items loaded)" ), adapter->GetItemCount() );
243 
244  DIALOG_CHOOSE_FOOTPRINT dialog( this, title, adapterPtr );
245 
246  if( dialog.ShowQuasiModal() == wxID_CANCEL )
247  return NULL;
248 
249  if( dialog.IsExternalBrowserSelected() )
250  {
251  // SelectFootprintFromLibBrowser() returns the "full" footprint name, i.e.
252  // <lib_name>/<footprint name> or LIB_ID format "lib_name:fp_name:rev#"
253  moduleName = SelectFootprintFromLibBrowser();
254 
255  if( moduleName.IsEmpty() ) // Cancel command
256  return NULL;
257  else
258  fpid.Parse( moduleName, LIB_ID::ID_PCB );
259  }
260  else
261  {
262  fpid = dialog.GetSelectedLibId();
263 
264  if( !fpid.IsValid() )
265  return NULL;
266  else
267  moduleName = fpid.Format();
268  }
269 
270  try
271  {
272  module = loadFootprint( fpid );
273  }
274  catch( const IO_ERROR& ioe )
275  {
276  wxLogDebug( wxT( "Error loading footprint '%s'.\n\nError: %s" ),
277  fpid.Format().c_str(),
278  ioe.What() );
279  }
280 
281  if( module )
282  {
283  lastComponentName = moduleName;
284  AddModuleToHistory( moduleName );
285  }
286 
287  return module;
288 }
289 
290 
292 {
293  MODULE* module = NULL;
294 
295  try
296  {
297  module = loadFootprint( aFootprintId );
298  }
299  catch( const IO_ERROR& ioe )
300  {
301  wxLogDebug( wxT( "An error occurred attemping to load footprint '%s'.\n\nError: %s" ),
302  aFootprintId.Format().c_str(), GetChars( ioe.What() ) );
303  }
304 
305  return module;
306 }
307 
308 
310 {
311  FP_LIB_TABLE* fptbl = Prj().PcbFootprintLibs();
312 
313  wxCHECK_MSG( fptbl, NULL, wxT( "Cannot look up LIB_ID in NULL FP_LIB_TABLE." ) );
314 
315  MODULE *module = nullptr;
316  try
317  {
318  module = fptbl->FootprintLoadWithOptionalNickname( aFootprintId );
319  }
320  catch( const IO_ERROR& ioe )
321  {
322  wxLogDebug( wxT( "An error occurred attemping to load footprint '%s'.\n\nError: %s" ),
323  aFootprintId.Format().c_str(), GetChars( ioe.What() ) );
324  }
325 
326  // If the module is found, clear all net info,
327  // to be sure there is no broken links
328  // to any netinfo list (should be not needed, but it can be edited from
329  // the footprint editor )
330  if( module )
331  module->ClearAllNets();
332 
333  return module;
334 }
335 
336 
338 {
339  static wxString oldName; // Save name of last module selected.
340 
341  wxString fpname;
342  wxString msg;
343  wxArrayString listnames;
344 
345  for( auto module : aPcb->Modules() )
346  listnames.Add( module->GetReference() );
347 
348  msg.Printf( _( "Footprints [%u items]" ), (unsigned) listnames.GetCount() );
349 
350  wxArrayString headers;
351 
352  headers.Add( _( "Footprint" ) );
353 
354  std::vector<wxArrayString> itemsToDisplay;
355 
356  // Conversion from wxArrayString to vector of ArrayString
357  for( unsigned i = 0; i < listnames.GetCount(); i++ )
358  {
359  wxArrayString item;
360 
361  item.Add( listnames[i] );
362  itemsToDisplay.push_back( item );
363  }
364 
365  EDA_LIST_DIALOG dlg( this, msg, headers, itemsToDisplay, wxEmptyString );
366 
367  if( dlg.ShowModal() == wxID_OK )
368  fpname = dlg.GetTextSelection();
369  else
370  return NULL;
371 
372  oldName = fpname;
373 
374  for( auto mod : aPcb->Modules() )
375  {
376  if( fpname == mod->GetReference() )
377  return mod;
378  }
379 
380  return nullptr;
381 }
382 
383 
384 bool FOOTPRINT_EDIT_FRAME::SaveLibraryAs( const wxString& aLibraryPath )
385 {
386  const wxString& curLibPath = aLibraryPath;
387  wxString dstLibPath = CreateNewLibrary();
388 
389  if( !dstLibPath )
390  return false; // user aborted in CreateNewLibrary()
391 
392  wxBusyCursor dummy;
393  wxString msg;
394 
397 
398  try
399  {
400  PLUGIN::RELEASER cur( IO_MGR::PluginFind( curType ) );
401  PLUGIN::RELEASER dst( IO_MGR::PluginFind( dstType ) );
402 
403  wxArrayString footprints;
404 
405  cur->FootprintEnumerate( footprints, curLibPath, false );
406 
407  for( unsigned i = 0; i < footprints.size(); ++i )
408  {
409  const MODULE* footprint = cur->GetEnumeratedFootprint( curLibPath, footprints[i] );
410  dst->FootprintSave( dstLibPath, footprint );
411 
412  msg = wxString::Format( _( "Footprint \"%s\" saved" ), footprints[i] );
413  SetStatusText( msg );
414  }
415  }
416  catch( const IO_ERROR& ioe )
417  {
418  DisplayError( this, ioe.What() );
419  return false;
420  }
421 
422  msg = wxString::Format( _( "Footprint library \"%s\" saved as \"%s\"." ),
423  curLibPath,
424  dstLibPath );
425 
426  DisplayInfoMessage( this, msg );
427 
428  SetStatusText( wxEmptyString );
429  return true;
430 }
431 
432 
433 static MODULE* s_ModuleInitialCopy = NULL; // Copy of module for abort/undo command
434 
435 static PICKED_ITEMS_LIST s_PickedList; // a pick-list to save initial module
436 // and dragged tracks
437 
438 
440 {
441  wxString moduleName;
442  wxArrayString fplist;
443 
444  // Build list of available fp references, to display them in dialog
445  for( auto fp : GetBoard()->Modules() )
446  fplist.Add( fp->GetReference() + wxT(" ( ") + fp->GetValue() + wxT(" )") );
447 
448  fplist.Sort();
449 
450  DIALOG_GET_FOOTPRINT_BY_NAME dlg( this, fplist );
451 
452  if( dlg.ShowModal() != wxID_OK ) //Aborted by user
453  return NULL;
454 
455  moduleName = dlg.GetValue();
456  moduleName.Trim( true );
457  moduleName.Trim( false );
458 
459  if( !moduleName.IsEmpty() )
460  {
461  for( auto mod : GetBoard()->Modules() )
462  {
463  if( mod->GetReference().CmpNoCase( moduleName ) == 0 )
464  return mod;
465  }
466  }
467 
468  return nullptr;
469 }
470 
471 
472 void PCB_BASE_FRAME::PlaceModule( MODULE* aModule, bool aRecreateRatsnest )
473 {
474  if( aModule == 0 )
475  return;
476 
477  OnModify();
478 
479  if( aModule->IsNew() )
480  {
481  SaveCopyInUndoList( aModule, UR_NEW );
482  }
483  else if( aModule->IsMoving() )
484  {
485  ITEM_PICKER picker( aModule, UR_CHANGED );
486  picker.SetLink( s_ModuleInitialCopy );
487  s_PickedList.PushItem( picker );
488  s_ModuleInitialCopy = NULL; // the picker is now owner of s_ModuleInitialCopy.
489  }
490 
491  if( s_PickedList.GetCount() )
492  {
493  SaveCopyInUndoList( s_PickedList, UR_UNSPECIFIED );
494 
495  // Clear list, but DO NOT delete items, because they are owned by the saved undo
496  // list and they therefore in use
498  }
499 
500  aModule->SetPosition( (wxPoint) GetCanvas()->GetViewControls()->GetCursorPosition() );
501  aModule->ClearFlags();
502 
503  delete s_ModuleInitialCopy;
505 
506  if( aRecreateRatsnest )
507  m_Pcb->GetConnectivity()->Update( aModule );
508 
509  if( aRecreateRatsnest )
510  Compile_Ratsnest( true );
511 
512  SetMsgPanel( aModule );
513 }
514 
515 
void DisplayError(wxWindow *aParent, const wxString &aText, int aDisplayTime)
Display an error or warning message box with aMessage.
Definition: confirm.cpp:239
wxString SelectFootprintFromLibBrowser()
Function SelectFootprintFromLibBrowser launches the footprint viewer to select the name of a footprin...
void SetLink(const KIID &aLink)
Definition: class_module.h:547
static void AddModuleToHistory(const wxString &aName)
bool ShowModal(wxString *aFootprint, wxWindow *aParent) override
Function ShowModal.
wxString GetTextSelection(int aColumn=0)
Function GetTextSelection return the selected text from aColumn in the wxListCtrl in the dialog.
Definition: displlst.cpp:141
void RunOnChildren(const std::function< void(BOARD_ITEM *)> &aFunction)
Function RunOnChildren.
FOOTPRINT_INFO * GetModuleInfo(const wxString &aFootprintId)
Get info for a module by id.
bool IsExternalBrowserSelected() const
Function IsExternalBrowserSelected.
This file is part of the common library.
BOARD_ITEM is a base class for any item which can be embedded within the BOARD container class,...
VIEW_CONTROLS class definition.
A mix-in to provide polymorphism between items stored in libraries (symbols, aliases and footprints).
Definition: lib_tree_item.h:39
PROJECT & Prj()
Definition: kicad.cpp:317
static PICKED_ITEMS_LIST s_PickedList
bool IsMoving() const
Definition: base_struct.h:200
Component library viewer main window.
void DisplayErrors(wxTopLevelWindow *aCaller=NULL)
MODULE * SelectFootprintFromLibTree(LIB_ID aPreselect=LIB_ID())
Function SelectFootprintFromLibTree opens a dialog to select a footprint.
EDA_LIST_DIALOG.
void PushItem(const ITEM_PICKER &aItem)
Function PushItem pushes aItem to the top of the list.
const LIB_ID & GetFPID() const
Definition: class_module.h:215
Dialog class to select a footprint from the libraries.
A logical library item identifier and consists of various portions much like a URI.
Definition: lib_id.h:51
bool IsValid() const
Definition: lib_id.h:171
void SetLink(EDA_ITEM *aItem)
unsigned GetCount() const
Function GetCount.
static PCB_FILE_T GuessPluginTypeFromLibPath(const wxString &aLibPath)
Function GuessPluginTypeFromLibPath returns a plugin type given a footprint library's libPath.
Definition: io_mgr.cpp:127
virtual void SetParent(EDA_ITEM *aParent)
Definition: base_struct.h:196
This file contains miscellaneous commonly used macros and functions.
bool IsNew() const
Definition: base_struct.h:199
const char * c_str() const
Definition: utf8.h:107
MODULE * SelectFootprintFromBoard(BOARD *aPcb)
Display the list of modules currently existing on the BOARD.
RELEASER releases a PLUGIN in the context of a potential thrown exception, through its destructor.
Definition: io_mgr.h:579
DIALOG_GET_FOOTPRINT_BY_NAME is a helper dialog to select a footprint by its reference One can enter ...
FOOTPRINT_LIST_IMPL GFootprintList
The global footprint info table.
static PTR Create(EDA_BASE_FRAME *aParent, LIB_TABLE *aLibs)
Factory function: create a model adapter in a reference-counting container.
void ClearAllNets()
Function ClearAllNets Clear (i.e.
static MODULE * s_ModuleInitialCopy
#define NULL
VECTOR2< double > VECTOR2D
Definition: vector2d.h:593
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:342
virtual const wxString What() const
A composite of Problem() and Where()
Definition: exceptions.cpp:33
MODULES & Modules()
Definition: class_board.h:266
bool SaveLibraryAs(const wxString &aLibraryPath)
Save a library to a new name and/or library type.
int ShowQuasiModal()
void Flip(const wxPoint &aCentre, bool aFlipLeftRight) override
Function Flip Flip this object, i.e.
MODULE * GetFirstModule() const
Gets the first module in the list (used in footprint viewer/editor) or NULL if none.
Definition: class_board.h:330
LIB_ID GetSelectedLibId() const
To be called after this dialog returns from ShowModal().
Helper dialog and control classes.
bool Load_Module_From_BOARD(MODULE *Module)
Load in Modedit a footprint from the main board.
void SetPosition(const wxPoint &aPos) override
PICKED_ITEMS_LIST is a holder to handle information on schematic or board items.
UTF8 Format() const
Definition: lib_id.cpp:237
void Add(BOARD_ITEM *aItem, ADD_MODE aMode=ADD_MODE::INSERT) override
static unsigned s_ModuleHistoryMaxCount
BOARD * GetBoard()
const KIID m_Uuid
Definition: base_struct.h:162
VTBL_ENTRY FP_LIB_TABLE * PcbFootprintLibs(KIWAY &aKiway)
Return the table of footprint libraries.
Definition: project.cpp:284
static const wxChar * GetChars(const wxString &s)
Function GetChars returns a wxChar* to the actual wxChar* data within a wxString, and is helpful for ...
Definition: macros.h:153
see class PGM_BASE
MODULE * LoadFootprint(const LIB_ID &aFootprintId)
Function LoadFootprint attempts to load aFootprintId from the footprint library table.
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
static LIB_PART * dummy()
Used to draw a dummy shape when a LIB_PART is not found in library.
BOARD holds information pertinent to a Pcbnew printed circuit board.
Definition: class_board.h:180
#define _(s)
Definition: 3d_actions.cpp:33
void SetOrientation(double newangle)
static PLUGIN * PluginFind(PCB_FILE_T aFileType)
Function PluginFind returns a PLUGIN which the caller can use to import, export, save,...
Definition: io_mgr.cpp:61
PCB_EDIT_FRAME is the main frame for Pcbnew.
PCBNEW_SETTINGS & Settings()
unsigned GetErrorCount() const
void ClearItemsList()
Function ClearItemsList deletes only the list of pickers, NOT the picked data itself.
bool Destroy() override
Our version of Destroy() which is virtual from wxWidgets.
bool ReadFootprintFiles(FP_LIB_TABLE *aTable, const wxString *aNickname=nullptr, PROGRESS_REPORTER *aProgressReporter=nullptr) override
Read all the footprints provided by the combination of aTable and aNickname.
void ClearFlags(STATUS_FLAGS aMask=EDA_ITEM_ALL_FLAGS)
Definition: base_struct.h:233
static void clearModuleItemFlags(BOARD_ITEM *aItem)
MODULE * FootprintLoadWithOptionalNickname(const LIB_ID &aFootprintId)
Function FootprintLoadWithOptionalNickname loads a footprint having aFootprintId with possibly an emp...
MODULE * GetFootprintFromBoardByReference()
Function GetFootprintFromBoardByReference.
BOARD * GetBoard() const
void PlaceModule(MODULE *aModule, bool aRecreateRatsnest=true)
Function PlaceModule places aModule at the current cursor position and updates module coordinates wit...
int Parse(const UTF8 &aId, LIB_ID_TYPE aType, bool aFix=false)
Parse LIB_ID with the information from aId.
Definition: lib_id.cpp:122
PCB_FILE_T
Enum PCB_FILE_T is a set of file types that the IO_MGR knows about, and for which there has been a pl...
Definition: io_mgr.h:54
void DisplayInfoMessage(wxWindow *aParent, const wxString &aMessage, const wxString &aExtraInfo)
Display an informational message box with aMessage.
Definition: confirm.cpp:267
virtual PCB_LAYER_ID GetLayer() const
Function GetLayer returns the primary layer this item is on.
Struct IO_ERROR is a class used to hold an error message and may be used when throwing exceptions con...
Definition: ki_exception.h:76
const wxPoint GetPosition() const override
Definition: class_module.h:206
MODULE * loadFootprint(const LIB_ID &aFootprintId)
Function loadFootprint attempts to load aFootprintId from the footprint library table.
BOARD_ITEM * Duplicate() const
Function Duplicate creates a copy of a BOARD_ITEM.
static wxArrayString s_ModuleHistoryList
KIWAY Kiway