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