1 ///////////////////////////////////////////////////////////////////////////////
2 //
3 // wxFormBuilder - A Visual Dialog Editor for wxWidgets.
4 // Copyright (C) 2005 José Antonio Hurtado
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, write to the Free Software
18 // Foundation, Inc., 59 Temple Place - Suite 330, Boston, MA 02111-1307, USA.
19 //
20 // Written by
21 // José Antonio Hurtado - joseantonio.hurtado@gmail.com
22 // Juan Antonio Ortega - jortegalalmolda@gmail.com
23 // Modified by
24 // Michal Bliznak
25 //
26 ///////////////////////////////////////////////////////////////////////////////
27
28 #include "pythonpanel.h"
29
30 #include "rad/codeeditor/codeeditor.h"
31 #include "rad/wxfbevent.h"
32 #include "rad/bitmaps.h"
33 #include "rad/appdata.h"
34 #include "utils/wxfbdefs.h"
35
36 #include "utils/typeconv.h"
37 #include "utils/encodingutils.h"
38 #include "utils/wxfbexception.h"
39
40 #include "model/objectbase.h"
41
42 #include "codegen/codewriter.h"
43 #include "codegen/pythoncg.h"
44
45 #include <wx/fdrepdlg.h>
46 #include <wx/config.h>
47
48 #if wxVERSION_NUMBER < 2900
49 #include <wx/wxScintilla/wxscintilla.h>
50 #else
51 #include <wx/stc/stc.h>
52 #endif
53
BEGIN_EVENT_TABLE(PythonPanel,wxPanel)54 BEGIN_EVENT_TABLE ( PythonPanel, wxPanel )
55 EVT_FB_CODE_GENERATION( PythonPanel::OnCodeGeneration )
56 EVT_FB_PROJECT_REFRESH( PythonPanel::OnProjectRefresh )
57 EVT_FB_PROPERTY_MODIFIED( PythonPanel::OnPropertyModified )
58 EVT_FB_OBJECT_CREATED( PythonPanel::OnObjectChange )
59 EVT_FB_OBJECT_REMOVED( PythonPanel::OnObjectChange )
60 EVT_FB_OBJECT_SELECTED( PythonPanel::OnObjectChange )
61 EVT_FB_EVENT_HANDLER_MODIFIED( PythonPanel::OnEventHandlerModified )
62
63 EVT_FIND( wxID_ANY, PythonPanel::OnFind )
64 EVT_FIND_NEXT( wxID_ANY, PythonPanel::OnFind )
65 END_EVENT_TABLE()
66
67 PythonPanel::PythonPanel( wxWindow *parent, int id )
68 :
69 wxPanel( parent, id )
70 {
71 AppData()->AddHandler( this->GetEventHandler() );
72 wxBoxSizer *top_sizer = new wxBoxSizer( wxVERTICAL );
73
74 m_pythonPanel = new CodeEditor( this, -1 );
75 InitStyledTextCtrl( m_pythonPanel->GetTextCtrl() );
76
77 top_sizer->Add( m_pythonPanel, 1, wxEXPAND, 0 );
78
79 SetSizer( top_sizer );
80 SetAutoLayout( true );
81 //top_sizer->SetSizeHints( this );
82 top_sizer->Fit( this );
83 top_sizer->Layout();
84
85 m_pythonCW = PTCCodeWriter( new TCCodeWriter( m_pythonPanel->GetTextCtrl() ) );
86 }
87
~PythonPanel()88 PythonPanel::~PythonPanel()
89 {
90 //delete m_icons;
91 AppData()->RemoveHandler( this->GetEventHandler() );
92 }
93
94 #if wxVERSION_NUMBER < 2900
InitStyledTextCtrl(wxScintilla * stc)95 void PythonPanel::InitStyledTextCtrl( wxScintilla *stc )
96 {
97 stc->SetLexer( wxSCI_LEX_PYTHON );
98 #else
99 void PythonPanel::InitStyledTextCtrl( wxStyledTextCtrl *stc )
100 {
101 stc->SetLexer( wxSTC_LEX_PYTHON );
102 #endif
103 stc->SetKeyWords( 0, wxT( "and assert break class continue def del elif else \
104 except exec finally for from global if import in \
105 is lambda not or pass print raise return try while" ) );
106
107 #ifdef __WXGTK__
108 wxFont font( 8, wxMODERN, wxNORMAL, wxNORMAL );
109 font.SetFaceName( wxT( "Monospace" ) );
110 #else
111 wxFont font( 10, wxMODERN, wxNORMAL, wxNORMAL );
112 #endif
113
114 #if wxVERSION_NUMBER < 2900
115 stc->StyleSetFont( wxSCI_STYLE_DEFAULT, font );
116 stc->StyleClearAll();
117 stc->StyleSetBold( wxSCI_C_WORD, true );
118 stc->StyleSetForeground( wxSCI_C_WORD, *wxBLUE );
119 stc->StyleSetForeground( wxSCI_C_STRING, *wxRED );
120 stc->StyleSetForeground( wxSCI_C_STRINGEOL, *wxRED );
121 stc->StyleSetForeground( wxSCI_C_PREPROCESSOR, wxColour( 49, 106, 197 ) );
122 stc->StyleSetForeground( wxSCI_C_COMMENT, wxColour( 0, 128, 0 ) );
123 stc->StyleSetForeground( wxSCI_C_COMMENTLINE, wxColour( 0, 128, 0 ) );
124 stc->StyleSetForeground( wxSCI_C_COMMENTDOC, wxColour( 0, 128, 0 ) );
125 stc->StyleSetForeground( wxSCI_C_COMMENTLINEDOC, wxColour( 0, 128, 0 ) );
126 stc->StyleSetForeground( wxSCI_C_NUMBER, *wxBLUE );
127 #else
128 stc->StyleSetFont( wxSTC_STYLE_DEFAULT, font );
129 stc->StyleClearAll();
130 stc->StyleSetBold( wxSTC_C_WORD, true );
131 stc->StyleSetForeground( wxSTC_C_WORD, *wxBLUE );
132 stc->StyleSetForeground( wxSTC_C_STRING, *wxRED );
133 stc->StyleSetForeground( wxSTC_C_STRINGEOL, *wxRED );
134 stc->StyleSetForeground( wxSTC_C_PREPROCESSOR, wxColour( 49, 106, 197 ) );
135 stc->StyleSetForeground( wxSTC_C_COMMENT, wxColour( 0, 128, 0 ) );
136 stc->StyleSetForeground( wxSTC_C_COMMENTLINE, wxColour( 0, 128, 0 ) );
137 stc->StyleSetForeground( wxSTC_C_COMMENTDOC, wxColour( 0, 128, 0 ) );
138 stc->StyleSetForeground( wxSTC_C_COMMENTLINEDOC, wxColour( 0, 128, 0 ) );
139 stc->StyleSetForeground( wxSTC_C_NUMBER, *wxBLUE );
140 #endif
141 stc->SetUseTabs( true );
142 stc->SetTabWidth( 4 );
143 stc->SetTabIndents( true );
144 stc->SetBackSpaceUnIndents( true );
145 stc->SetIndent( 4 );
146 stc->SetSelBackground( true, wxSystemSettings::GetColour( wxSYS_COLOUR_HIGHLIGHT ) );
147 stc->SetSelForeground( true, wxSystemSettings::GetColour( wxSYS_COLOUR_HIGHLIGHTTEXT ) );
148
149 stc->SetCaretWidth( 2 );
150 stc->SetReadOnly( true );
151 }
152
153 void PythonPanel::OnFind( wxFindDialogEvent& event )
154 {
155 m_pythonPanel->GetEventHandler()->ProcessEvent( event );
156 }
157
158 void PythonPanel::OnPropertyModified( wxFBPropertyEvent& event )
159 {
160 // Generate code to the panel only
161 event.SetId( 1 );
162 OnCodeGeneration( event );
163 }
164
165 void PythonPanel::OnProjectRefresh( wxFBEvent& event )
166 {
167 // Generate code to the panel only
168 event.SetId( 1 );
169 OnCodeGeneration( event );
170 }
171
172 void PythonPanel::OnObjectChange( wxFBObjectEvent& event )
173 {
174 // Generate code to the panel only
175 event.SetId( 1 );
176 OnCodeGeneration( event );
177 }
178
179 void PythonPanel::OnEventHandlerModified( wxFBEventHandlerEvent& event )
180 {
181 // Generate code to the panel only
182 event.SetId( 1 );
183 OnCodeGeneration( event );
184 }
185
186 void PythonPanel::OnCodeGeneration( wxFBEvent& event )
187 {
188 PObjectBase objectToGenerate;
189
190 // Generate code in the panel if the panel is active
191 bool doPanel = IsShown();
192
193 // Using the previously unused Id field in the event to carry a boolean
194 bool panelOnly = ( event.GetId() != 0 );
195
196 // Only generate to panel + panel is not shown = do nothing
197 if ( panelOnly && !doPanel )
198 {
199 return;
200 }
201
202 // For code preview generate only code relevant to selected form,
203 // otherwise generate full project code.
204
205 // Create copy of the original project due to possible temporary modifications
206 PObjectBase project = PObjectBase(new ObjectBase(*AppData()->GetProjectData()));
207
208 if(panelOnly)
209 {
210 objectToGenerate = AppData()->GetSelectedForm();
211 }
212
213 if(!panelOnly || !objectToGenerate)
214 {
215 objectToGenerate = project;
216 }
217
218 // If only one project item should be generated then remove the rest items
219 // from the temporary project
220 if(doPanel && panelOnly && (objectToGenerate != project))
221 {
222 if( project->GetChildCount() > 0)
223 {
224 unsigned int i = 0;
225 while( project->GetChildCount() > 1 )
226 {
227 if(project->GetChild( i ) != objectToGenerate)
228 {
229 project->RemoveChild( i );
230 }
231 else
232 i++;
233 }
234 }
235 }
236
237 if(!project || !objectToGenerate)return;
238
239 // Get Python properties from the project
240
241 // If Python generation is not enabled, do not generate the file
242 bool doFile = false;
243 PProperty pCodeGen = project->GetProperty( wxT( "code_generation" ) );
244 if ( pCodeGen )
245 {
246 //doFile = TypeConv::FlagSet( wxT("C++"), pCodeGen->GetValue() ) && !panelOnly;
247 doFile = TypeConv::FlagSet( wxT("Python"), pCodeGen->GetValue() ) && !panelOnly;
248 }
249
250 if ( !(doPanel || doFile ) )
251 {
252 return;
253 }
254
255 // Get First ID from Project File
256 unsigned int firstID = 1000;
257 PProperty pFirstID = project->GetProperty( wxT("first_id") );
258 if ( pFirstID )
259 {
260 firstID = pFirstID->GetValueAsInteger();
261 }
262
263 // Get the file name
264 wxString file;
265 PProperty pfile = project->GetProperty( wxT( "file" ) );
266 if ( pfile )
267 {
268 file = pfile->GetValue();
269 }
270 if ( file.empty() )
271 {
272 file = wxT("noname");
273 }
274
275 // Determine if the path is absolute or relative
276 bool useRelativePath = false;
277 PProperty pRelPath = project->GetProperty( wxT( "relative_path" ) );
278 if ( pRelPath )
279 {
280 useRelativePath = ( pRelPath->GetValueAsInteger() ? true : false );
281 }
282
283 // Get the output path
284 wxString path;
285 try
286 {
287 path = AppData()->GetOutputPath();
288 }
289 catch ( wxFBException& ex )
290 {
291 if ( doFile )
292 {
293 path = wxEmptyString;
294 wxLogWarning( ex.what() );
295 return;
296 }
297 }
298
299 // Generate code in the panel
300 if ( doPanel )
301 {
302 PythonCodeGenerator codegen;
303 codegen.UseRelativePath( useRelativePath, path );
304
305 if ( pFirstID )
306 {
307 codegen.SetFirstID( firstID );
308 }
309
310 codegen.SetSourceWriter( m_pythonCW );
311
312 Freeze();
313
314 #if wxVERSION_NUMBER < 2900
315 wxScintilla* pythonEditor = m_pythonPanel->GetTextCtrl();
316 #else
317 wxStyledTextCtrl* pythonEditor = m_pythonPanel->GetTextCtrl();
318 #endif
319 pythonEditor->SetReadOnly( false );
320 int pythonLine = pythonEditor->GetFirstVisibleLine() + pythonEditor->LinesOnScreen() - 1;
321 int pythonXOffset = pythonEditor->GetXOffset();
322
323 codegen.GenerateCode( project );
324
325 pythonEditor->SetReadOnly( true );
326 pythonEditor->GotoLine( pythonLine );
327 pythonEditor->SetXOffset( pythonXOffset );
328 pythonEditor->SetAnchor( 0 );
329 pythonEditor->SetCurrentPos( 0 );
330
331 Thaw();
332 }
333
334 // Generate code in the file
335 if ( doFile )
336 {
337 try
338 {
339 PythonCodeGenerator codegen;
340 codegen.UseRelativePath( useRelativePath, path );
341
342 if ( pFirstID )
343 {
344 codegen.SetFirstID( firstID );
345 }
346
347 // Determin if Microsoft BOM should be used
348 bool useMicrosoftBOM = false;
349
350 PProperty pUseMicrosoftBOM = project->GetProperty( wxT( "use_microsoft_bom" ) );
351
352 if ( pUseMicrosoftBOM )
353 {
354 useMicrosoftBOM = ( pUseMicrosoftBOM->GetValueAsInteger() != 0 );
355 }
356
357 // Determine if Utf8 or Ansi is to be created
358 bool useUtf8 = false;
359 PProperty pUseUtf8 = project->GetProperty( _("encoding") );
360
361 if ( pUseUtf8 )
362 {
363 useUtf8 = ( pUseUtf8->GetValueAsString() != wxT("ANSI") );
364 }
365
366 PCodeWriter python_cw( new FileCodeWriter( path + file + wxT( ".py" ), useMicrosoftBOM, useUtf8 ) );
367
368 codegen.SetSourceWriter( python_cw );
369 codegen.GenerateCode( project );
370 wxLogStatus( wxT( "Code generated on \'%s\'." ), path.c_str() );
371
372 // check if we have to convert to ANSI encoding
373 if (project->GetPropertyAsString(wxT("encoding")) == wxT("ANSI"))
374 {
375 UTF8ToAnsi(path + file + wxT( ".py" ));
376 }
377 }
378 catch ( wxFBException& ex )
379 {
380 wxLogError( ex.what() );
381 }
382 }
383 }
384