You can not select more than 25 topics Topics must start with a letter or number, can include dashes ('-') and can be up to 35 characters long.

481 lines
12 KiB

  1. /*
  2. * This program source code file is part of KiCad, a free EDA CAD application.
  3. *
  4. * Copyright (C) 2015 Cirilo Bernardo <cirilo.bernardo@gmail.com>
  5. *
  6. * This program is free software; you can redistribute it and/or
  7. * modify it under the terms of the GNU General Public License
  8. * as published by the Free Software Foundation; either version 2
  9. * of the License, or (at your option) any later version.
  10. *
  11. * This program is distributed in the hope that it will be useful,
  12. * but WITHOUT ANY WARRANTY; without even the implied warranty of
  13. * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
  14. * GNU General Public License for more details.
  15. *
  16. * You should have received a copy of the GNU General Public License
  17. * along with this program; if not, you may find one here:
  18. * http://www.gnu.org/licenses/old-licenses/gpl-2.0.html
  19. * or you may search the http://www.gnu.org website for the version 2 license,
  20. * or you may write to the Free Software Foundation, Inc.,
  21. * 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301, USA
  22. */
  23. #include <utility>
  24. #include <iostream>
  25. #include <unistd.h>
  26. #include <sys/types.h>
  27. #include <string>
  28. #include <wx/string.h>
  29. #include <wx/dir.h>
  30. #include <wx/config.h>
  31. #include <wx/stdpaths.h>
  32. #include <wx/filename.h>
  33. #ifdef _WIN32
  34. #include <windows.h>
  35. #else
  36. #include <dlfcn.h>
  37. #include <pwd.h>
  38. #endif
  39. #include "3d_plugin_manager.h"
  40. #include "plugins/3d/3d_plugin.h"
  41. #include "3d_cache/sg/scenegraph.h"
  42. #include "plugins/ldr/3d/pluginldr3D.h"
  43. S3D_PLUGIN_MANAGER::S3D_PLUGIN_MANAGER()
  44. {
  45. // create the initial file filter list entry
  46. m_FileFilters.push_back( _( "All Files (*.*)|*.*" ) );
  47. // discover and load plugins
  48. loadPlugins();
  49. #ifdef DEBUG
  50. if( !m_ExtMap.empty() )
  51. {
  52. std::multimap< const wxString, KICAD_PLUGIN_LDR_3D* >::const_iterator sM = m_ExtMap.begin();
  53. std::multimap< const wxString, KICAD_PLUGIN_LDR_3D* >::const_iterator eM = m_ExtMap.end();
  54. std::cout << "* Extension [plugin name]:\n";
  55. while( sM != eM )
  56. {
  57. std::cout << " + '" << sM->first.ToUTF8() << "' [";
  58. std::cout << sM->second->GetKicadPluginName() << "]\n";
  59. ++sM;
  60. }
  61. }
  62. else
  63. {
  64. std::cout << "* No plugins available\n";
  65. }
  66. if( !m_FileFilters.empty() )
  67. {
  68. /// list of file filters
  69. std::list< wxString >::const_iterator sFF = m_FileFilters.begin();
  70. std::list< wxString >::const_iterator eFF = m_FileFilters.end();
  71. std::cout << "* File filters:\n";
  72. while( sFF != eFF )
  73. {
  74. std::cout << " + '" << *sFF << "'\n";
  75. ++sFF;
  76. }
  77. }
  78. else
  79. {
  80. std::cout << "* No file filters available\n";
  81. }
  82. #endif // DEBUG
  83. return;
  84. }
  85. S3D_PLUGIN_MANAGER::~S3D_PLUGIN_MANAGER()
  86. {
  87. std::list< KICAD_PLUGIN_LDR_3D* >::iterator sP = m_Plugins.begin();
  88. std::list< KICAD_PLUGIN_LDR_3D* >::iterator eP = m_Plugins.end();
  89. while( sP != eP )
  90. {
  91. (*sP)->Close();
  92. delete *sP;
  93. ++sP;
  94. }
  95. m_Plugins.clear();
  96. return;
  97. }
  98. void S3D_PLUGIN_MANAGER::loadPlugins( void )
  99. {
  100. std::list< std::string > pathlist;
  101. std::list< wxString > searchpaths;
  102. std::list< wxString > pluginlist;
  103. wxFileName fn;
  104. #ifdef DEBUG
  105. // set up to work from the build directory
  106. fn.Assign( wxStandardPaths::Get().GetExecutablePath() );
  107. fn.AppendDir( wxT("..") );
  108. fn.AppendDir( wxT("plugins") );
  109. fn.AppendDir( wxT("3d") );
  110. std::string testpath = std::string( fn.GetPathWithSep().ToUTF8() );
  111. checkPluginPath( testpath, searchpaths );
  112. #endif
  113. fn.Assign( wxStandardPaths::Get().GetPluginsDir() );
  114. #ifndef _WIN32 // suppress 'kicad' subdir since it is redundant on MSWin
  115. fn.AppendDir( wxT( "kicad" ) );
  116. #endif
  117. fn.AppendDir( wxT( "plugins" ) );
  118. fn.AppendDir( wxT( "3d" ) );
  119. checkPluginPath( std::string( fn.GetPathWithSep().ToUTF8() ), searchpaths );
  120. checkPluginPath( wxT( "/usr/lib/kicad/plugins/3d" ), searchpaths );
  121. checkPluginPath( wxT( "/usr/local/lib/kicad/plugins/3d" ), searchpaths );
  122. checkPluginPath( wxT( "/opt/kicad/lib/kicad/plugins/3d" ), searchpaths );
  123. #ifdef __APPLE__
  124. // XXX - we want to use GetOSX... so add support for that somehow in order to avoid hard coding
  125. // "/Library/Application Support/kicad/plugins/3d"
  126. checkPluginPath( wxT( "/Library/Application Support/kicad/plugins/3d" ), searchpaths );
  127. // /Library/Application Support/kicad/plugins
  128. //fn.Assign( GetOSXKicadMachineDataDir() );
  129. //fn.AppendDir( wxT( "plugins" ) );
  130. //fn.AppendDir( wxT( "3d" ) );
  131. //checkPluginPath( fn.GetPathWithSep(), searchpaths );
  132. #endif
  133. // note: GetUserDataDir() gives '.pcbnew' rather than '.kicad' since it uses the exe name;
  134. fn.Assign( wxStandardPaths::Get().GetUserDataDir() );
  135. fn.AppendDir( wxT( ".kicad" ) );
  136. fn.AppendDir( wxT( "plugins" ) );
  137. fn.AppendDir( wxT( "3d" ) );
  138. checkPluginPath( fn.GetPathWithSep(), searchpaths );
  139. std::list< wxString >::iterator sPL = searchpaths.begin();
  140. std::list< wxString >::iterator ePL = searchpaths.end();
  141. while( sPL != ePL )
  142. {
  143. #ifdef DEBUG
  144. std::cout << __FILE__ << ":" << __FUNCTION__ << ":" << __LINE__ << ":\n";
  145. std::cout << "* [DEBUG] searching path: '" << (*sPL).ToUTF8() << "'\n";
  146. #endif
  147. listPlugins( *sPL, pluginlist );
  148. ++sPL;
  149. }
  150. if( pluginlist.empty() )
  151. return;
  152. sPL = pluginlist.begin();
  153. ePL = pluginlist.end();
  154. while( sPL != ePL )
  155. {
  156. KICAD_PLUGIN_LDR_3D* pp = new KICAD_PLUGIN_LDR_3D;
  157. if( pp->Open( sPL->ToUTF8() ) )
  158. {
  159. #ifdef DEBUG
  160. std::cout << __FILE__ << ":" << __FUNCTION__ << ":" << __LINE__ << ":\n";
  161. std::cout << "* [DEBUG] adding plugin\n";
  162. #endif
  163. m_Plugins.push_back( pp );
  164. int nf = pp->GetNFilters();
  165. #ifdef DEBUG
  166. std::cerr << __FILE__ << ": " << __FUNCTION__ << ": " << __LINE__ << "\n";
  167. std::cerr << " * [INFO] adding " << nf << " filters\n";
  168. #endif
  169. for( int i = 0; i < nf; ++i )
  170. {
  171. char const* cp = pp->GetFileFilter( i );
  172. if( cp )
  173. addFilterString( wxString::FromUTF8Unchecked( cp ) );
  174. }
  175. addExtensionMap( pp );
  176. // close the loaded library
  177. pp->Close();
  178. }
  179. else
  180. {
  181. #ifdef DEBUG
  182. std::cout << __FILE__ << ":" << __FUNCTION__ << ":" << __LINE__ << ":\n";
  183. std::cout << "* [DEBUG] deleting plugin\n";
  184. #endif
  185. delete pp;
  186. }
  187. ++sPL;
  188. }
  189. #ifdef DEBUG
  190. std::cout << __FILE__ << ":" << __FUNCTION__ << ":" << __LINE__ << ":\n";
  191. std::cout << "* [DEBUG] plugins loaded\n";
  192. #endif
  193. return;
  194. }
  195. void S3D_PLUGIN_MANAGER::listPlugins( const wxString& aPath,
  196. std::list< wxString >& aPluginList )
  197. {
  198. // list potential plugins given a search paths
  199. // note on typical plugin names:
  200. // Linux: *.so, *.so.* (note: *.so.* will not be supported)
  201. // MSWin: *.dll
  202. // OSX: *.dylib, *.bundle
  203. std::list< wxString > nameFilter; // filter to apply to files
  204. wxString lName; // stores name of enumerated files
  205. wxString fName; // full name of file
  206. #ifdef __linux
  207. nameFilter.push_back( wxString::FromUTF8Unchecked( "*.so" ) );
  208. #elif defined _WIN32
  209. nameFilter.push_back( wxString::FromUTF8Unchecked( "*.dll" ) );
  210. #elif defined __APPLE__
  211. nameFilter.push_back( wxString::FromUTF8Unchecked( "*.dylib" ) );
  212. nameFilter.push_back( wxString::FromUTF8Unchecked( "*.bundle" ) );
  213. #else
  214. // note: we need to positively identify a supported OS here
  215. // and add suffixes which may be used for 3D model plugins
  216. // on the specific OS
  217. #warning NOT IMPLEMENTED
  218. #endif
  219. wxDir wd;
  220. wd.Open( aPath );
  221. if( !wd.IsOpened() )
  222. return;
  223. wxString lp = wd.GetNameWithSep();
  224. std::list< wxString >::iterator sExt = nameFilter.begin();
  225. std::list< wxString >::iterator eExt = nameFilter.end();
  226. while( sExt != eExt )
  227. {
  228. if( wd.GetFirst( &lName, *sExt, wxDIR_FILES ) )
  229. {
  230. fName = lp + lName;
  231. checkPluginName( fName, aPluginList );
  232. while( wd.GetNext( &lName ) )
  233. {
  234. fName = lp + lName;
  235. checkPluginName( fName, aPluginList );
  236. }
  237. }
  238. ++sExt;
  239. }
  240. wd.Close();
  241. return;
  242. }
  243. void S3D_PLUGIN_MANAGER::checkPluginName( const wxString& aPath,
  244. std::list< wxString >& aPluginList )
  245. {
  246. // check the existence of a plugin name and add it to the list
  247. if( aPath.empty() || !wxFileName::FileExists( aPath ) )
  248. return;
  249. wxFileName path( aPath );
  250. path.Normalize();
  251. // determine if the path is already in the list
  252. wxString wxpath = path.GetFullPath();
  253. std::list< wxString >::iterator bl = aPluginList.begin();
  254. std::list< wxString >::iterator el = aPluginList.end();
  255. while( bl != el )
  256. {
  257. if( 0 == (*bl).Cmp( wxpath ) )
  258. return;
  259. ++bl;
  260. }
  261. aPluginList.push_back( wxpath );
  262. #ifdef DEBUG
  263. std::cerr << " * [INFO] found 3D plugin '" << wxpath.ToUTF8() << "'\n";
  264. #endif
  265. return;
  266. }
  267. void S3D_PLUGIN_MANAGER::checkPluginPath( const wxString& aPath,
  268. std::list< wxString >& aSearchList )
  269. {
  270. // check the existence of a path and add it to the path search list
  271. if( aPath.empty() )
  272. return;
  273. #ifdef DEBUG
  274. std::cerr << " * [INFO] checking for 3D plugins in '" << aPath << "'\n";
  275. #endif
  276. wxFileName path( wxFileName::DirName( aPath ) );
  277. path.Normalize();
  278. if( !wxFileName::DirExists( path.GetFullPath() ) )
  279. return;
  280. // determine if the directory is already in the list
  281. wxString wxpath = path.GetFullPath();
  282. std::list< wxString >::iterator bl = aSearchList.begin();
  283. std::list< wxString >::iterator el = aSearchList.end();
  284. while( bl != el )
  285. {
  286. if( 0 == (*bl).Cmp( wxpath ) )
  287. return;
  288. ++bl;
  289. }
  290. aSearchList.push_back( wxpath );
  291. return;
  292. }
  293. void S3D_PLUGIN_MANAGER::addFilterString( const wxString& aFilterString )
  294. {
  295. // add an entry to the file filter list
  296. if( aFilterString.empty() )
  297. return;
  298. std::list< wxString >::iterator sFF = m_FileFilters.begin();
  299. std::list< wxString >::iterator eFF = m_FileFilters.end();
  300. while( sFF != eFF )
  301. {
  302. if( 0 == (*sFF).Cmp( aFilterString ) )
  303. return;
  304. ++sFF;
  305. }
  306. m_FileFilters.push_back( aFilterString );
  307. return;
  308. }
  309. void S3D_PLUGIN_MANAGER::addExtensionMap( KICAD_PLUGIN_LDR_3D* aPlugin )
  310. {
  311. // add entries to the extension map
  312. if( NULL == aPlugin )
  313. return;
  314. int nExt = aPlugin->GetNExtensions();
  315. #ifdef DEBUG
  316. std::cerr << __FILE__ << ": " << __FUNCTION__ << ": " << __LINE__ << "\n";
  317. std::cerr << " * [INFO] adding " << nExt << " extensions\n";
  318. #endif
  319. for( int i = 0; i < nExt; ++i )
  320. {
  321. char const* cp = aPlugin->GetModelExtension( i );
  322. wxString ws;
  323. if( cp )
  324. ws = wxString::FromUTF8Unchecked( cp );
  325. if( !ws.empty() )
  326. {
  327. m_ExtMap.insert( std::pair< const wxString, KICAD_PLUGIN_LDR_3D* >( ws, aPlugin ) );
  328. }
  329. }
  330. return;
  331. }
  332. std::list< wxString > const* S3D_PLUGIN_MANAGER::GetFileFilters( void ) const
  333. {
  334. return &m_FileFilters;
  335. }
  336. SCENEGRAPH* S3D_PLUGIN_MANAGER::Load3DModel( const wxString& aFileName )
  337. {
  338. wxFileName raw( aFileName );
  339. wxString ext = raw.GetExt();
  340. std::pair < std::multimap< const wxString, KICAD_PLUGIN_LDR_3D* >::iterator,
  341. std::multimap< const wxString, KICAD_PLUGIN_LDR_3D* >::iterator > items;
  342. items = m_ExtMap.equal_range( ext );
  343. std::multimap< const wxString, KICAD_PLUGIN_LDR_3D* >::iterator sL = items.first;
  344. while( sL != items.second )
  345. {
  346. if( sL->second->CanRender() )
  347. {
  348. SCENEGRAPH* sp = sL->second->Load( aFileName );
  349. if( NULL != sp )
  350. return sp;
  351. }
  352. ++sL;
  353. }
  354. return NULL;
  355. }
  356. void S3D_PLUGIN_MANAGER::ClosePlugins( void )
  357. {
  358. std::list< KICAD_PLUGIN_LDR_3D* >::iterator sP = m_Plugins.begin();
  359. std::list< KICAD_PLUGIN_LDR_3D* >::iterator eP = m_Plugins.end();
  360. #ifdef DEBUG
  361. std::cerr << __FILE__ << ": " << __FUNCTION__ << ": " << __LINE__ << "\n";
  362. std::cerr << " * [INFO] closing " << m_Plugins.size() << " plugins\n";
  363. #endif
  364. while( sP != eP )
  365. {
  366. (*sP)->Close();
  367. ++sP;
  368. }
  369. return;
  370. }