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.

489 lines
13 KiB

  1. /*
  2. * This program source code file is part of KiCad, a free EDA CAD application.
  3. *
  4. * Copyright (C) 2013 Jean-Pierre Charras, jp.charras@wanadoo.fr
  5. * Copyright (C) 1992-2013 KiCad Developers, see AUTHORS.txt for contributors.
  6. *
  7. * This program is free software; you can redistribute it and/or
  8. * modify it under the terms of the GNU General Public License
  9. * as published by the Free Software Foundation; either version 2
  10. * of the License, or (at your option) any later version.
  11. *
  12. * This program is distributed in the hope that it will be useful,
  13. * but WITHOUT ANY WARRANTY; without even the implied warranty of
  14. * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
  15. * GNU General Public License for more details.
  16. *
  17. * You should have received a copy of the GNU General Public License
  18. * along with this program; if not, you may find one here:
  19. * http://www.gnu.org/licenses/old-licenses/gpl-2.0.html
  20. * or you may search the http://www.gnu.org website for the version 2 license,
  21. * or you may write to the Free Software Foundation, Inc.,
  22. * 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301, USA
  23. */
  24. /**
  25. * @file eeschema/dialogs/dialog_bom.cpp
  26. * @brief Dialog box for creating bom and other documents from generic netlist.
  27. */
  28. #include <fctsys.h>
  29. #include <appl_wxstruct.h>
  30. #include <confirm.h>
  31. #include <gestfich.h>
  32. #include <wxEeschemaStruct.h>
  33. #include <netlist.h>
  34. #include <sch_sheet.h>
  35. #include <invoke_sch_dialog.h>
  36. #include <dialog_helpers.h>
  37. #include <dialog_bom_base.h>
  38. #include <html_messagebox.h>
  39. #define BOM_PLUGINS_KEY wxT("bom_plugins")
  40. #define BOM_PLUGIN_SELECTED_KEY wxT("bom_plugin_selected")
  41. const char * s_bomHelpInfo =
  42. #include <dialog_bom_help_html.h>
  43. ;
  44. #include <dialog_bom_cfg_lexer.h>
  45. using namespace T_BOMCFG_T;
  46. /**
  47. * Class BOM_CFG_READER_PARSER
  48. * holds data and functions pertinent to parsing a S-expression file
  49. * for a WORKSHEET_LAYOUT.
  50. */
  51. class BOM_CFG_READER_PARSER : public DIALOG_BOM_CFG_LEXER
  52. {
  53. wxArrayString* m_pluginsList;
  54. public:
  55. BOM_CFG_READER_PARSER( wxArrayString* aPlugins,
  56. const char* aData, const wxString& aSource );
  57. void Parse() throw( PARSE_ERROR, IO_ERROR );
  58. private:
  59. void parsePlugin() throw( IO_ERROR, PARSE_ERROR );
  60. };
  61. // PCB_PLOT_PARAMS_PARSER
  62. BOM_CFG_READER_PARSER::BOM_CFG_READER_PARSER( wxArrayString* aPlugins,
  63. const char* aLine,
  64. const wxString& aSource ) :
  65. DIALOG_BOM_CFG_LEXER( aLine, aSource )
  66. {
  67. m_pluginsList = aPlugins;
  68. }
  69. void BOM_CFG_READER_PARSER::Parse() throw( PARSE_ERROR, IO_ERROR )
  70. {
  71. T token;
  72. while( ( token = NextTok() ) != T_RIGHT )
  73. {
  74. if( token == T_EOF)
  75. break;
  76. if( token == T_LEFT )
  77. token = NextTok();
  78. if( token == T_plugins )
  79. continue;
  80. switch( token )
  81. {
  82. case T_plugin: // Defines a new plugin
  83. parsePlugin();
  84. break;
  85. default:
  86. // Unexpected( CurText() );
  87. break;
  88. }
  89. }
  90. }
  91. void BOM_CFG_READER_PARSER::parsePlugin() throw( IO_ERROR, PARSE_ERROR )
  92. {
  93. wxString title, command;
  94. NeedSYMBOLorNUMBER();
  95. title = FromUTF8();
  96. T token;
  97. while( ( token = NextTok() ) != T_RIGHT )
  98. {
  99. if( token == T_EOF)
  100. break;
  101. switch( token )
  102. {
  103. case T_LEFT:
  104. break;
  105. case T_cmd:
  106. NeedSYMBOLorNUMBER();
  107. command = FromUTF8();
  108. NeedRIGHT();
  109. break;
  110. case T_opts:
  111. while( ( token = NextTok() ) != T_RIGHT && token != T_EOF );
  112. break;
  113. default:
  114. Unexpected( CurText() );
  115. break;
  116. }
  117. }
  118. if( ! title.IsEmpty() )
  119. {
  120. m_pluginsList->Add( title );
  121. m_pluginsList->Add( command );
  122. }
  123. }
  124. // The main dialog frame tu run scripts to build bom
  125. class DIALOG_BOM : public DIALOG_BOM_BASE
  126. {
  127. private:
  128. SCH_EDIT_FRAME* m_parent;
  129. // The list of scripts (or plugins):
  130. // a script descr uses 2 lines:
  131. // the first is the title
  132. // the second is the command line
  133. wxArrayString m_plugins;
  134. wxConfig* m_config; // to store the "plugins"
  135. public:
  136. // Constructor and destructor
  137. DIALOG_BOM( SCH_EDIT_FRAME* parent );
  138. ~DIALOG_BOM();
  139. private:
  140. void OnPluginSelected( wxCommandEvent& event );
  141. void OnRunPlugin( wxCommandEvent& event );
  142. void OnCancelClick( wxCommandEvent& event );
  143. void OnHelp( wxCommandEvent& event );
  144. void OnAddPlugin( wxCommandEvent& event );
  145. void OnChoosePlugin( wxCommandEvent& event );
  146. void OnRemovePlugin( wxCommandEvent& event );
  147. void OnEditPlugin( wxCommandEvent& event );
  148. void OnCommandLineEdited( wxCommandEvent& event );
  149. void OnNameEdited( wxCommandEvent& event );
  150. void pluginInit();
  151. void installPluginsList();
  152. };
  153. // Create and show DIALOG_BOM.
  154. int InvokeDialogCreateBOM( SCH_EDIT_FRAME* aCaller )
  155. {
  156. DIALOG_BOM dlg( aCaller );
  157. return dlg.ShowModal();
  158. }
  159. DIALOG_BOM::DIALOG_BOM( SCH_EDIT_FRAME* parent ) :
  160. DIALOG_BOM_BASE( parent )
  161. {
  162. m_parent = parent;
  163. m_config = wxGetApp().GetSettings();
  164. installPluginsList();
  165. GetSizer()->SetSizeHints( this );
  166. Centre();
  167. }
  168. DIALOG_BOM::~DIALOG_BOM()
  169. {
  170. // Save the plugin descriptions in config.
  171. // the config stores only one string.
  172. // plugins are saved inside a S expr:
  173. // ( plugins
  174. // ( plugin "plugin name" (cmd "command line") )
  175. // ....
  176. // )
  177. STRING_FORMATTER writer;
  178. writer.Print( 0, "(plugins" );
  179. for( unsigned ii = 0; ii < m_plugins.GetCount(); ii += 2 )
  180. {
  181. writer.Print( 1, "(plugin %s (cmd %s))",
  182. writer.Quotew( m_plugins[ii] ).c_str(),
  183. writer.Quotew( m_plugins[ii+1] ).c_str() );
  184. }
  185. writer.Print( 0, ")" );
  186. wxString list( FROM_UTF8( writer.GetString().c_str() ) );
  187. m_config->Write( BOM_PLUGINS_KEY, list );
  188. wxString active_plugin_name = m_lbPlugins->GetStringSelection( );
  189. m_config->Write( BOM_PLUGIN_SELECTED_KEY, active_plugin_name );
  190. }
  191. /* Read the initialized plugins in config and fill the list
  192. * of names
  193. */
  194. void DIALOG_BOM::installPluginsList()
  195. {
  196. wxString list, active_plugin_name;
  197. m_config->Read( BOM_PLUGINS_KEY, &list );
  198. m_config->Read( BOM_PLUGIN_SELECTED_KEY, &active_plugin_name );
  199. if( !list.IsEmpty() )
  200. {
  201. BOM_CFG_READER_PARSER cfg_parser( &m_plugins, TO_UTF8( list ),
  202. wxT( "plugins" ) );
  203. try
  204. {
  205. cfg_parser.Parse();
  206. }
  207. catch( IO_ERROR ioe )
  208. {
  209. // wxLogMessage( ioe.errorText );
  210. }
  211. }
  212. // Populate list box
  213. for( unsigned ii = 0; ii < m_plugins.GetCount(); ii+=2 )
  214. {
  215. m_lbPlugins->Append( m_plugins[ii] );
  216. if( active_plugin_name == m_plugins[ii] )
  217. m_lbPlugins->SetSelection( ii/2 );
  218. }
  219. pluginInit();
  220. }
  221. void DIALOG_BOM::OnPluginSelected( wxCommandEvent& event )
  222. {
  223. pluginInit();
  224. }
  225. void DIALOG_BOM::pluginInit()
  226. {
  227. int ii = m_lbPlugins->GetSelection();
  228. if( ii < 0 )
  229. {
  230. m_textCtrlName->SetValue( wxEmptyString );
  231. m_textCtrlCommand->SetValue( wxEmptyString );
  232. return;
  233. }
  234. m_textCtrlName->SetValue( m_plugins[2 * ii] );
  235. m_textCtrlCommand->SetValue( m_plugins[(2 * ii)+1] );
  236. }
  237. /**
  238. * Function RunPlugin
  239. * run the plugin command line
  240. */
  241. void DIALOG_BOM::OnRunPlugin( wxCommandEvent& event )
  242. {
  243. wxFileName fn;
  244. wxString fileWildcard;
  245. wxString title = _( "Save Netlist File" );
  246. // Calculate the xml netlist filename
  247. fn = g_RootSheet->GetScreen()->GetFileName();
  248. if( fn.GetPath().IsEmpty() )
  249. fn.SetPath( wxGetCwd() );
  250. fn.ClearExt();
  251. wxString fullfilename = fn.GetFullPath();
  252. m_parent->ClearMsgPanel();
  253. m_parent->SetNetListerCommand( m_textCtrlCommand->GetValue() );
  254. m_parent->CreateNetlist( -1, fullfilename, 0 );
  255. }
  256. void DIALOG_BOM::OnCancelClick( wxCommandEvent& event )
  257. {
  258. EndModal( wxID_CANCEL );
  259. }
  260. /**
  261. * Function OnRemovePlugin
  262. * Remove a plugin from the list
  263. */
  264. void DIALOG_BOM::OnRemovePlugin( wxCommandEvent& event )
  265. {
  266. int ii = m_lbPlugins->GetSelection();
  267. if( ii < 0 )
  268. return;
  269. m_lbPlugins->Delete( ii );
  270. m_plugins.RemoveAt( 2*ii, 2 ); // Remove title and command line
  271. // Select the next item, if exists
  272. if( (int)m_lbPlugins->GetCount() >= ii )
  273. ii = m_lbPlugins->GetCount() - 1;
  274. if( ii >= 0 )
  275. m_lbPlugins->SetSelection( ii );
  276. pluginInit();
  277. }
  278. /**
  279. * Function OnAddPlugin
  280. * Add a new panel for a new netlist plugin
  281. */
  282. void DIALOG_BOM::OnAddPlugin( wxCommandEvent& event )
  283. {
  284. // Creates a new plugin entry
  285. wxString name = wxGetTextFromUser( _("Plugin") );
  286. if( name.IsEmpty() )
  287. return;
  288. // Verify if it does not exists
  289. for( unsigned ii = 0; ii < m_plugins.GetCount(); ii += 2 )
  290. {
  291. if( name == m_plugins[ii] )
  292. {
  293. wxMessageBox( _("This plugin already exists. Abort") );
  294. return;
  295. }
  296. }
  297. m_plugins.Add( name );
  298. m_plugins.Add( wxEmptyString );
  299. m_lbPlugins->Append( name );
  300. m_lbPlugins->SetSelection( m_lbPlugins->GetCount() - 1 );
  301. pluginInit();
  302. }
  303. /*
  304. * Browse plugin files, and set m_CommandStringCtrl field
  305. */
  306. void DIALOG_BOM::OnChoosePlugin( wxCommandEvent& event )
  307. {
  308. wxString FullFileName, Mask, Path;
  309. Mask = wxT( "*" );
  310. Path = wxGetApp().GetExecutablePath();
  311. FullFileName = EDA_FileSelector( _( "Plugin files:" ),
  312. Path,
  313. FullFileName,
  314. wxEmptyString,
  315. Mask,
  316. this,
  317. wxFD_OPEN,
  318. true
  319. );
  320. if( FullFileName.IsEmpty() )
  321. return;
  322. // Creates a default command line,
  323. // suitable to run the external tool xslproc or python
  324. // The default command line depending on plugin extension, currently
  325. // "xsl" or "exe" or "py"
  326. wxString cmdLine;
  327. wxFileName fn( FullFileName );
  328. wxString ext = fn.GetExt();
  329. if( ext == wxT("xsl" ) )
  330. cmdLine.Printf(wxT("xsltproc -o \"%%O\" \"%s\" \"%%I\""), GetChars(FullFileName) );
  331. else if( ext == wxT("exe" ) || ext.IsEmpty() )
  332. cmdLine.Printf(wxT("\"%s\" < \"%%I\" > \"%%O\""), GetChars(FullFileName) );
  333. else if( ext == wxT("py" ) || ext.IsEmpty() )
  334. cmdLine.Printf(wxT("python \"%s\" \"%%I\" \"%%O\""), GetChars(FullFileName) );
  335. else
  336. cmdLine.Printf(wxT("\"%s\""), GetChars(FullFileName) );
  337. m_textCtrlCommand->SetValue( cmdLine );
  338. }
  339. void DIALOG_BOM::OnEditPlugin( wxCommandEvent& event )
  340. {
  341. wxString pluginName, cmdline;
  342. // Try to find the plugin name.
  343. // This is possible if the name ends by .py or .xsl
  344. cmdline = m_textCtrlCommand->GetValue();
  345. int pos = -1;
  346. if( (pos = cmdline.Find( wxT(".py") )) != wxNOT_FOUND )
  347. pos += 2;
  348. else if( (pos = cmdline.Find( wxT(".xsl") )) != wxNOT_FOUND )
  349. pos += 3;
  350. // the end of plugin name is at position pos.
  351. if( pos > 0 )
  352. {
  353. // Be sure this is the end of the name: the next char is " or space
  354. int eos = cmdline[pos+1];
  355. if( eos == ' '|| eos == '\"' )
  356. {
  357. // search for the starting point of the name
  358. int jj = pos-1;
  359. while( jj >= 0 )
  360. if( cmdline[jj] != eos )
  361. jj--;
  362. else
  363. break;
  364. // extract the name
  365. if( jj >= 0 )
  366. pluginName = cmdline.SubString( jj, pos );
  367. }
  368. }
  369. AddDelimiterString( pluginName );
  370. wxString editorname = wxGetApp().GetEditorName();
  371. if( !editorname.IsEmpty() )
  372. ExecuteFile( this, editorname, pluginName );
  373. else
  374. wxMessageBox( _("No text editor selected in KiCad. Please choose it") );
  375. }
  376. void DIALOG_BOM::OnHelp( wxCommandEvent& event )
  377. {
  378. HTML_MESSAGE_BOX help_Dlg( this, _("Bom Generation Help"),
  379. wxDefaultPosition, wxSize( 750,550 ) );
  380. wxString msg = FROM_UTF8(s_bomHelpInfo);
  381. help_Dlg.m_htmlWindow->AppendToPage( msg );
  382. help_Dlg.ShowModal();
  383. }
  384. void DIALOG_BOM::OnCommandLineEdited( wxCommandEvent& event )
  385. {
  386. int ii = m_lbPlugins->GetSelection();
  387. if( ii < 0 )
  388. return;
  389. m_plugins[(2 * ii)+1] = m_textCtrlCommand->GetValue();
  390. }
  391. void DIALOG_BOM::OnNameEdited( wxCommandEvent& event )
  392. {
  393. int ii = m_lbPlugins->GetSelection();
  394. if( ii < 0 )
  395. return;
  396. m_plugins[2 * ii] = m_textCtrlName->GetValue();
  397. m_lbPlugins->SetString( ii, m_plugins[2 * ii] );
  398. }