1 /*
2 * This file is part of wxSmith plugin for Code::Blocks Studio
3 * Copyright (C) 2006-2007 Bartlomiej Swiecki
4 *
5 * wxSmith is free software; you can redistribute it and/or modify
6 * it under the terms of the GNU General Public License as published by
7 * the Free Software Foundation; either version 3 of the License, or
8 * (at your option) any later version.
9 *
10 * wxSmith is distributed in the hope that it will be useful,
11 * but WITHOUT ANY WARRANTY; without even the implied warranty of
12 * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
13 * GNU General Public License for more details.
14 *
15 * You should have received a copy of the GNU General Public License
16 * along with wxSmith. If not, see <http://www.gnu.org/licenses/>.
17 *
18 * $Revision: 10686 $
19 * $Id: wxsmith.cpp 10686 2016-01-22 10:53:43Z mortenmacfly $
20 * $HeadURL: svn://svn.code.sf.net/p/codeblocks/code/branches/release-20.xx/src/plugins/contrib/wxSmith/wxsmith.cpp $
21 */
22
23 #include "wxsmith.h"
24 #include "wxsproject.h"
25 #include "wxsmithmime.h"
26 #include "wxssettings.h"
27 #include "wxsextresmanager.h"
28 #include "wxsresourcefactory.h"
29 #include "properties/wxsproperties.h"
30
31 #include <prep.h>
32 #include <cbauibook.h>
33 #include <projectloader_hooks.h>
34 #include <manager.h>
35 #include <configmanager.h>
36 #include <projectmanager.h>
37 #include <logmanager.h>
38 #include <sqplus.h>
39 #include <sc_base_types.h>
40
41 namespace
42 {
43 const int ConfigureId = wxNewId();
44 const int ViewWxSmithId = wxNewId();
45 const int ViewWxSmithResourceId = wxNewId();
46 const int ViewWxSmithPropertyId = wxNewId();
47
48 /* XPM */
49 static const char * Events_xpm[] = {
50 "16 16 2 1",
51 " c None",
52 ". c #000000",
53 " ",
54 " .. .. ",
55 " . . ",
56 " . . ",
57 " . . ",
58 " . . ",
59 " . . ",
60 " .. .. ",
61 " . . ",
62 " . . ",
63 " . . ",
64 " . . ",
65 " . . ",
66 " .. .. ",
67 " ",
68 " "};
69
70 const int placementManagementPane = 0;
71 const int placementOnePane = 1;
72 const int placementTwoPanes = 2;
73
GetBrowserPlacements()74 inline int GetBrowserPlacements() { return Manager::Get()->GetConfigManager(_T("wxsmith"))->ReadInt(_T("/browserplacements"),0); }
75 }
76
77 wxSmith* wxSmith::m_Singleton = 0;
78
BEGIN_EVENT_TABLE(wxSmith,cbPlugin)79 BEGIN_EVENT_TABLE(wxSmith, cbPlugin)
80 EVT_UPDATE_UI(ViewWxSmithId,wxSmith::OnUpdateUI)
81 EVT_UPDATE_UI(ViewWxSmithResourceId,wxSmith::OnUpdateUI)
82 EVT_UPDATE_UI(ViewWxSmithPropertyId,wxSmith::OnUpdateUI)
83 EVT_MENU(ConfigureId,wxSmith::OnConfigure)
84 EVT_MENU(ViewWxSmithId,wxSmith::OnViewBrowsers)
85 EVT_MENU(ViewWxSmithResourceId,wxSmith::OnViewResourceBrowser)
86 EVT_MENU(ViewWxSmithPropertyId,wxSmith::OnViewPropertyBrowser)
87 EVT_MENU(-1,wxSmith::OnMenu)
88 END_EVENT_TABLE()
89
90 wxSmith::wxSmith()
91 {
92 }
93
~wxSmith()94 wxSmith::~wxSmith()
95 {
96 }
97
OnAttach()98 void wxSmith::OnAttach()
99 {
100 // No more instances of wxSmith class can be found here,
101 // even if it's on another dll/so, m_Singleton will point
102 // to different memory locations
103 wxASSERT(m_Singleton == 0);
104
105 // Creating properties and resource browser
106 BuildBrowsers();
107
108 // Registering function for loading / saving extra XML configuration inside CBP files
109 ProjectLoaderHooks::HookFunctorBase* wxSmithHook = new ProjectLoaderHooks::HookFunctor<wxSmith>(this, &wxSmith::OnProjectHook);
110 m_HookId = ProjectLoaderHooks::RegisterHook(wxSmithHook);
111
112 m_Singleton = this;
113
114 wxsResourceFactory::OnAttachAll();
115
116 // register event sink
117 Manager::Get()->RegisterEventSink(cbEVT_PROJECT_OPEN, new cbEventFunctor<wxSmith, CodeBlocksEvent>(this, &wxSmith::OnProjectOpened));
118 Manager::Get()->RegisterEventSink(cbEVT_PROJECT_CLOSE, new cbEventFunctor<wxSmith, CodeBlocksEvent>(this, &wxSmith::OnProjectClose));
119 Manager::Get()->RegisterEventSink(cbEVT_PROJECT_RENAMED, new cbEventFunctor<wxSmith, CodeBlocksEvent>(this, &wxSmith::OnProjectRenamed));
120
121 // register scripting stuff
122 RegisterScripting();
123 }
124
BuildBrowserParents()125 void wxSmith::BuildBrowserParents()
126 {
127 // Zero pointers to minimize segfault possibility ;)
128 m_Splitter = 0;
129 m_ResourceBrowserParent = 0;
130 m_PropertyBrowserParent = 0;
131
132 switch ( GetBrowserPlacements() )
133 {
134 case placementOnePane:
135 {
136 m_Splitter = new wxsStoringSplitterWindow(Manager::Get()->GetAppWindow());
137 m_ResourceBrowserParent = new wxPanel(m_Splitter->GetSplitter(),-1,wxDefaultPosition,wxDefaultSize,0);
138 m_PropertyBrowserParent = new wxPanel(m_Splitter->GetSplitter(),-1,wxDefaultPosition,wxDefaultSize,0);
139 m_Splitter->Split(m_ResourceBrowserParent,m_PropertyBrowserParent);
140 m_Splitter->SetSize(150,450);
141
142 CodeBlocksDockEvent evt(cbEVT_ADD_DOCK_WINDOW);
143 evt.name = _T("wxSmithOnePane");
144 evt.title = _("wxSmith");
145 evt.pWindow = m_Splitter;
146 evt.dockSide = CodeBlocksDockEvent::dsFloating;
147 evt.desiredSize.Set(150, 450);
148 evt.floatingSize.Set(150, 450);
149 evt.minimumSize.Set(50, 50);
150 Manager::Get()->ProcessEvent(evt);
151 break;
152 }
153
154 case placementTwoPanes:
155 {
156 m_ResourceBrowserParent = new wxPanel(Manager::Get()->GetAppWindow(),-1,wxDefaultPosition,wxDefaultSize,0);
157 m_PropertyBrowserParent = new wxPanel(Manager::Get()->GetAppWindow(),-1,wxDefaultPosition,wxDefaultSize,0);
158
159 CodeBlocksDockEvent evt(cbEVT_ADD_DOCK_WINDOW);
160 evt.name = _T("wxSmithTwoPanes_ResourceBrowser");
161 evt.title = _("wxSmith - Resource Browser");
162 evt.pWindow = m_ResourceBrowserParent;
163 evt.dockSide = CodeBlocksDockEvent::dsFloating;
164 evt.desiredSize.Set(150, 450);
165 evt.floatingSize.Set(150, 450);
166 evt.minimumSize.Set(50, 50);
167 Manager::Get()->ProcessEvent(evt);
168
169 evt.name = _T("wxSmithTwoPanes_PropertyBrowser");
170 evt.title = _("wxSmith - Property Browser");
171 evt.pWindow = m_PropertyBrowserParent;
172 Manager::Get()->ProcessEvent(evt);
173 break;
174 }
175
176 default:
177 {
178 cbAuiNotebook* Notebook = Manager::Get()->GetProjectManager()->GetUI().GetNotebook();
179 wxASSERT(Notebook!=0);
180
181 // Creating main splitting object
182 m_Splitter = new wxsStoringSplitterWindow(Notebook);
183 Notebook->AddPage(m_Splitter,_("Resources"));
184
185 m_ResourceBrowserParent = new wxPanel(m_Splitter->GetSplitter(),-1,wxDefaultPosition,wxDefaultSize,0);
186 m_PropertyBrowserParent = new wxPanel(m_Splitter->GetSplitter(),-1,wxDefaultPosition,wxDefaultSize,0);
187 m_Splitter->Split(m_ResourceBrowserParent,m_PropertyBrowserParent);
188 }
189 }
190 }
191
192
BuildBrowsers()193 void wxSmith::BuildBrowsers()
194 {
195 // Building background windows for panes
196 BuildBrowserParents();
197
198 // Adding resource browser
199 wxSizer* Sizer = new wxGridSizer(1);
200 wxTreeCtrl* ResourceBrowser = new wxsResourceTree(m_ResourceBrowserParent);
201 Sizer->Add(ResourceBrowser,1,wxGROW|wxALL);
202 m_ResourceBrowserParent->SetSizer(Sizer);
203
204 // Adding properties / events browser
205 Sizer = new wxGridSizer(1);
206 wxsPropertyGridManager* PGManager = new wxsPropertyGridManager(m_PropertyBrowserParent,-1,wxDefaultPosition,wxDefaultSize,wxPG_TOOLBAR|wxTAB_TRAVERSAL|wxPG_SPLITTER_AUTO_CENTER);
207 PGManager->AddPage(_("Properties"));
208 PGManager->AddPage(_("Events"),wxBitmap(Events_xpm));
209 PGManager->SelectPage(0);
210 Sizer->Add(PGManager,1,wxGROW);
211 m_PropertyBrowserParent->SetSizer(Sizer);
212 }
213
OnRelease(cb_unused bool appShutDown)214 void wxSmith::OnRelease(cb_unused bool appShutDown)
215 {
216 UnregisterScripting();
217
218 ProjectLoaderHooks::UnregisterHook(m_HookId,true);
219 for ( ProjectMapI i = m_ProjectMap.begin(); i!=m_ProjectMap.end(); ++i )
220 {
221 if ( i->second )
222 {
223 delete i->second;
224 i->second = 0;
225 }
226 }
227 wxsExtResManager::Get()->DeleteAll();
228
229 m_ProjectMap.clear();
230
231 wxsResourceFactory::OnReleaseAll();
232
233 if ( m_Singleton == this )
234 {
235 m_Singleton = 0;
236 }
237 }
238
GetConfigurationPanel(wxWindow * parent)239 cbConfigurationPanel* wxSmith::GetConfigurationPanel(wxWindow* parent)
240 {
241 return new wxsSettings(parent);
242 }
243
GetProjectConfigurationPanel(wxWindow * parent,cbProject * project)244 cbConfigurationPanel* wxSmith::GetProjectConfigurationPanel(wxWindow* parent, cbProject* project)
245 {
246 ProjectMapI i = m_ProjectMap.find(project);
247 if ( i == m_ProjectMap.end() ) return 0;
248 return i->second->GetProjectConfigurationPanel(parent);
249 }
250
BuildMenu(wxMenuBar * menuBar)251 void wxSmith::BuildMenu(wxMenuBar* menuBar)
252 {
253 // Generating separate wxSmith menu entry
254 wxMenu* SmithMenu = new wxMenu;
255
256 wxsResourceFactory::BuildSmithMenu(SmithMenu);
257
258 SmithMenu->AppendSeparator();
259 SmithMenu->Append(ConfigureId,_("&Configure wxSmith for current project"));
260
261 int ToolsPos = menuBar->FindMenu(_("&Tools"));
262 if ( ToolsPos == wxNOT_FOUND )
263 {
264 menuBar->Append(SmithMenu,_("&wxSmith"));
265 }
266 else
267 {
268 menuBar->Insert(ToolsPos,SmithMenu,_("&wxSmith"));
269 }
270
271 // Generate entries in "view" menu
272 int idx = menuBar->FindMenu(_("&View"));
273 if (idx != wxNOT_FOUND)
274 {
275 wxMenu* view = menuBar->GetMenu(idx);
276 wxMenuItemList& items = view->GetMenuItems();
277 // find the first separator and insert before it
278 for (size_t i = 0; i < items.GetCount(); ++i)
279 {
280 if (items[i]->IsSeparator())
281 {
282 switch ( GetBrowserPlacements() )
283 {
284 case placementOnePane:
285 view->InsertCheckItem(i,ViewWxSmithId, _("wxSmith browsers"), _("Toggle displaying the wxSmith resource and property browsers"));
286 break;
287
288 case placementTwoPanes:
289 view->InsertCheckItem(i,ViewWxSmithResourceId, _("wxSmith resource browser"), _("Toggle displaying the wxSmith resource browser"));
290 view->InsertCheckItem(i,ViewWxSmithPropertyId, _("wxSmith property browser"), _("Toggle displaying the wxSmith property browser"));
291 break;
292
293 default:
294 break;
295 }
296 return;
297 }
298 }
299
300 // not found, just append
301 switch ( GetBrowserPlacements() )
302 {
303 case placementOnePane:
304 view->AppendCheckItem(ViewWxSmithId, _("wxSmith browsers"), _("Toggle displaying the wxSmith resource and property browsers"));
305 break;
306
307 case placementTwoPanes:
308 view->AppendCheckItem(ViewWxSmithResourceId, _("wxSmith resource browser"), _("Toggle displaying the wxSmith resource browser"));
309 view->AppendCheckItem(ViewWxSmithPropertyId, _("wxSmith property browser"), _("Toggle displaying the wxSmith property browser"));
310 break;
311
312 default:
313 break;
314 }
315 return;
316 }
317 }
318
BuildModuleMenu(cb_unused const ModuleType type,cb_unused wxMenu * menu,const FileTreeData *)319 void wxSmith::BuildModuleMenu(cb_unused const ModuleType type, cb_unused wxMenu* menu, const FileTreeData* /*data*/)
320 {
321 }
322
BuildToolBar(cb_unused wxToolBar * toolBar)323 bool wxSmith::BuildToolBar(cb_unused wxToolBar* toolBar)
324 {
325 return false;
326 }
327
OnProjectHook(cbProject * project,TiXmlElement * elem,bool loading)328 void wxSmith::OnProjectHook(cbProject* project,TiXmlElement* elem,bool loading)
329 {
330 assert(project);
331 wxsProject* Proj = GetSmithProject(project);
332 assert(Proj);
333 if ( loading ) Proj->ReadConfiguration(elem);
334 else Proj->WriteConfiguration(elem);
335 }
336
OnProjectOpened(CodeBlocksEvent & event)337 void wxSmith::OnProjectOpened(CodeBlocksEvent& event)
338 {
339 cbProject* Proj = event.GetProject();
340 wxsProject* wxsProj = GetSmithProject(Proj);
341 wxsProj->UpdateName();
342 Proj->SetModified(wxsProj->GetWasModifiedDuringLoad());
343 event.Skip();
344 }
345
OnProjectClose(CodeBlocksEvent & event)346 void wxSmith::OnProjectClose(CodeBlocksEvent& event)
347 {
348 cbProject* Proj = event.GetProject();
349 ProjectMapI i = m_ProjectMap.find(Proj);
350 if ( i == m_ProjectMap.end() ) return;
351 delete i->second;
352 m_ProjectMap.erase(i);
353 event.Skip();
354 }
355
OnProjectRenamed(cb_unused CodeBlocksEvent & event)356 void wxSmith::OnProjectRenamed(cb_unused CodeBlocksEvent& event)
357 {
358 cbProject* Proj = event.GetProject();
359 ProjectMapI i = m_ProjectMap.find(Proj);
360 if ( i == m_ProjectMap.end() ) return;
361 i->second->UpdateName();
362 event.Skip();
363 }
364
OnConfigure(cb_unused wxCommandEvent & event)365 void wxSmith::OnConfigure(cb_unused wxCommandEvent& event)
366 {
367 cbProject* Proj = Manager::Get()->GetProjectManager()->GetActiveProject();
368 if ( Proj )
369 {
370 GetSmithProject(Proj)->Configure();
371 }
372 }
373
OnMenu(wxCommandEvent & event)374 void wxSmith::OnMenu(wxCommandEvent& event)
375 {
376 cbProject* Proj = Manager::Get()->GetProjectManager()->GetActiveProject();
377 if ( Proj )
378 {
379 if ( wxsResourceFactory::NewResourceMenu(event.GetId(),GetSmithProject(Proj)) )
380 {
381 return;
382 }
383 }
384 event.Skip();
385 }
386
OnViewBrowsers(wxCommandEvent & event)387 void wxSmith::OnViewBrowsers(wxCommandEvent& event)
388 {
389 CodeBlocksDockEvent evt(event.IsChecked() ? cbEVT_SHOW_DOCK_WINDOW : cbEVT_HIDE_DOCK_WINDOW);
390 evt.pWindow = m_Splitter;
391 Manager::Get()->ProcessEvent(evt);
392 }
393
OnViewPropertyBrowser(wxCommandEvent & event)394 void wxSmith::OnViewPropertyBrowser(wxCommandEvent& event)
395 {
396 CodeBlocksDockEvent evt(event.IsChecked() ? cbEVT_SHOW_DOCK_WINDOW : cbEVT_HIDE_DOCK_WINDOW);
397 evt.pWindow = m_PropertyBrowserParent;
398 Manager::Get()->ProcessEvent(evt);
399 }
400
OnViewResourceBrowser(cb_unused wxCommandEvent & event)401 void wxSmith::OnViewResourceBrowser(cb_unused wxCommandEvent& event)
402 {
403 CodeBlocksDockEvent evt(event.IsChecked() ? cbEVT_SHOW_DOCK_WINDOW : cbEVT_HIDE_DOCK_WINDOW);
404 evt.pWindow = m_ResourceBrowserParent;
405 Manager::Get()->ProcessEvent(evt);
406 }
407
OnUpdateUI(cb_unused wxUpdateUIEvent & event)408 void wxSmith::OnUpdateUI(cb_unused wxUpdateUIEvent& event)
409 {
410 wxMenuBar* Bar = Manager::Get()->GetAppFrame()->GetMenuBar();
411
412 Bar->Check(ViewWxSmithId,IsWindowReallyShown(m_Splitter));
413 Bar->Check(ViewWxSmithResourceId,IsWindowReallyShown(m_ResourceBrowserParent));
414 Bar->Check(ViewWxSmithPropertyId,IsWindowReallyShown(m_PropertyBrowserParent));
415 }
416
GetCBProject(wxsProject * Proj)417 cbProject* wxSmith::GetCBProject(wxsProject* Proj)
418 {
419 return Proj->GetCBProject();
420 }
421
GetSmithProject(cbProject * Proj)422 wxsProject* wxSmith::GetSmithProject(cbProject* Proj)
423 {
424 assert(Proj);
425 ProjectMapI i = m_ProjectMap.find(Proj);
426 if ( i == m_ProjectMap.end() )
427 {
428 wxsProject* NewProj = new wxsProject(Proj);
429 m_ProjectMap[Proj] = NewProj;
430 return NewProj;
431 }
432 return i->second;
433 }
434
ShowResourcesTab()435 void wxSmith::ShowResourcesTab()
436 {
437 cbAuiNotebook* Notebook = Manager::Get()->GetProjectManager()->GetUI().GetNotebook();
438 Notebook->SetSelection( Notebook->GetPageIndex(m_Splitter) );
439 }
440
RegisterScripting()441 void wxSmith::RegisterScripting()
442 {
443 Manager::Get()->GetScriptingManager();
444 if ( SquirrelVM::GetVMPtr() )
445 {
446 SqPlus::RegisterGlobal( &wxSmith::RecoverWxsFile, "WxsRecoverWxsFile" );
447 }
448 }
449
UnregisterScripting()450 void wxSmith::UnregisterScripting()
451 {
452 Manager::Get()->GetScriptingManager();
453 HSQUIRRELVM v = SquirrelVM::GetVMPtr();
454 if ( v )
455 {
456 sq_pushroottable(v);
457 sq_pushstring(v,"WxsRecoverWxsFile",-1);
458 sq_deleteslot(v,-2,false);
459 sq_poptop(v);
460 }
461 }
462
RecoverWxsFile(const wxString & WxsResourceSettings)463 bool wxSmith::RecoverWxsFile( const wxString& WxsResourceSettings )
464 {
465 wxSmith* This = wxSmith::Get();
466 if ( !This ) return false;
467 if ( !ProjectManager::Get()->GetActiveProject() ) return false;
468
469 wxsProject* project = This->GetSmithProject( ProjectManager::Get()->GetActiveProject() );
470 if ( !project ) return false;
471
472 return project->RecoverWxsFile( WxsResourceSettings );
473 }
474
475 // TODO: Move to resources\wxwidgets
476 /*
477
478 void wxSmith::OnImportXrc(wxCommandEvent& event)
479 {
480 if ( !CheckIntegration() ) return;
481
482 wxString FileName = ::wxFileSelector(
483 _("Select XRC file"),
484 _T(""),
485 _T(""),
486 _T("xrc"),
487 _("XRC files (*.xrc)|*.xrc|All files (*)|*"),
488 wxOPEN|wxFILE_MUST_EXIST|wxHIDE_READONLY);
489
490 if ( FileName.empty() ) return;
491
492 // Loading xrc file into xml document
493
494 TiXmlDocument Doc(cbU2C(FileName));
495 TiXmlElement* Resource;
496 if ( !Doc.LoadFile() || !(Resource = Doc.FirstChildElement("resource")) )
497 {
498 wxMessageBox(_("Couldn't load XRC file."));
499 return;
500 }
501
502 // Generating list of objects
503 wxArrayString Resources;
504 TiXmlElement* Element = Resource->FirstChildElement("object");
505 while ( Element )
506 {
507 const char* Class = Element->Attribute("class");
508 const char* Name = Element->Attribute("name");
509 if ( !Class || !Name ) continue;
510
511 if ( !strcmp(Class,"wxDialog") ||
512 !strcmp(Class,"wxPanel") ||
513 !strcmp(Class,"wxFrame") )
514 {
515 Resources.Add(cbC2U(Name));
516 }
517
518 Element = Element->NextSiblingElement("object");
519 }
520
521 if ( Resources.Count() == 0 )
522 {
523 wxMessageBox(_("Didn't find any editable resources"));
524 return;
525 }
526
527 // Selecting resource to edit
528 wxString Name;
529
530 if ( Resources.Count() == 1 )
531 {
532 Name = Resources[0];
533 }
534 else
535 {
536 int Index = ::cbGetSingleChoiceIndex(
537 _("Select resource to import"),
538 _("Importing XRC"),
539 Resources );
540 if ( Index == -1 ) return;
541 Name = Resources[Index];
542 }
543
544 Element = Resource->FirstChildElement("object");
545 while ( Element )
546 {
547 if ( !strcmp(Element->Attribute("name"),cbU2C(Name)) )
548 {
549 break;
550 }
551 Element = Element->NextSiblingElement("object");
552 }
553 if ( !Element ) return;
554
555 // Creating fake resource and testing if xrc can be loaded without any errors
556 wxsItem* Test = wxsGEN(cbC2U(Element->Attribute("class")),0);
557 if ( !Test )
558 {
559 // Something went wrong - default factory is not working ?
560 Manager::Get()->GetLogManager()->DebugLog(F(_T("wxSmith: Internal error - did not found one of base items when importing XRC")));
561 return;
562 }
563
564 if ( !Test->XmlRead(Element,true,false) )
565 {
566 if ( wxMessageBox(_("Resource was not loaded properly. Some widgets may be\n"
567 "damaged or will be removed. Continue ?"),
568 _("XRC Load error"),
569 wxYES_NO|wxICON_QUESTION) == wxNO )
570 {
571 delete Test;
572 return;
573 }
574 }
575 delete Test;
576
577 // Displaying configuration dialog - it will handle adding resource to project
578 wxsImportXrcDlg Dlg(0,Element);
579 Dlg.ShowModal();
580 }
581 */
582