1 /*
2  * This file is part of the Code::Blocks IDE and licensed under the GNU General Public License, version 3
3  * http://www.gnu.org/licenses/gpl-3.0.html
4  *
5  * $Revision: 11883 $
6  * $Id: compileroptionsdlg.cpp 11883 2019-10-26 09:11:12Z fuscated $
7  * $HeadURL: svn://svn.code.sf.net/p/codeblocks/code/branches/release-20.xx/src/plugins/compilergcc/compileroptionsdlg.cpp $
8  */
9 
10 #include <sdk.h>
11 #include <prep.h>
12 #ifndef CB_PRECOMP
13     #include <algorithm>
14     #include <wx/arrstr.h>
15     #include <wx/button.h>
16     #include <wx/checkbox.h>
17     #include <wx/checklst.h>
18     #include <wx/choice.h>
19     #include <wx/event.h>
20     #include <wx/filename.h>
21     #include <wx/listbox.h>
22     #include <wx/menu.h>
23     #include <wx/notebook.h>
24     #include <wx/stattext.h>
25     #include <wx/sizer.h>
26     #include <wx/spinctrl.h>
27     #include <wx/textdlg.h>
28     #include <wx/treectrl.h>
29     #include <wx/xrc/xmlres.h>
30 
31     #include "compiler.h"
32     #include "compilerfactory.h"
33     #include "configmanager.h"
34     #include "globals.h"
35     #include "macrosmanager.h"
36     #include "manager.h"
37     #include "logmanager.h"
38     #include "projectmanager.h"
39 #endif
40 #include <wx/filedlg.h>
41 #include <wx/propgrid/propgrid.h>
42 #include <wx/xml/xml.h>
43 
44 #include "advancedcompileroptionsdlg.h"
45 #include "annoyingdialog.h"
46 #include "cbexception.h"
47 #include "compilergcc.h"
48 #include "compileroptionsdlg.h"
49 #include "debuggermanager.h"
50 #include "editpathdlg.h"
51 #include "editpairdlg.h"
52 #include "compilerflagdlg.h"
53 
54 // TO DO :  - add/edit/delete compiler : applies directly , so no cancel out (change this behaviour)
55 //          - compiler change of project/target -> check if the policy is still sound (both should have the same compiler)
56 //          - compiler change of project/target -> all options should be removed : different compiler is different options
57 //          - directory add/edit and library add/edit : check if it already existed
58 
59 BEGIN_EVENT_TABLE(CompilerOptionsDlg, wxPanel)
60     EVT_UPDATE_UI(            XRCID("btnEditDir"),                      CompilerOptionsDlg::OnUpdateUI)
61     EVT_UPDATE_UI(            XRCID("btnDelDir"),                       CompilerOptionsDlg::OnUpdateUI)
62     EVT_UPDATE_UI(            XRCID("btnClearDir"),                     CompilerOptionsDlg::OnUpdateUI)
63     EVT_UPDATE_UI(            XRCID("btnCopyDirs"),                     CompilerOptionsDlg::OnUpdateUI)
64     EVT_UPDATE_UI(            XRCID("btnMoveDirUp"),                    CompilerOptionsDlg::OnUpdateUI)
65     EVT_UPDATE_UI(            XRCID("btnMoveDirDown"),                  CompilerOptionsDlg::OnUpdateUI)
66     EVT_UPDATE_UI(            XRCID("btnEditVar"),                      CompilerOptionsDlg::OnUpdateUI)
67     EVT_UPDATE_UI(            XRCID("btnDeleteVar"),                    CompilerOptionsDlg::OnUpdateUI)
68     EVT_UPDATE_UI(            XRCID("btnClearVar"),                     CompilerOptionsDlg::OnUpdateUI)
69     EVT_UPDATE_UI(            XRCID("cmbCompilerPolicy"),               CompilerOptionsDlg::OnUpdateUI)
70     EVT_UPDATE_UI(            XRCID("cmbLinkerPolicy"),                 CompilerOptionsDlg::OnUpdateUI)
71     EVT_UPDATE_UI(            XRCID("cmbIncludesPolicy"),               CompilerOptionsDlg::OnUpdateUI)
72     EVT_UPDATE_UI(            XRCID("cmbLibDirsPolicy"),                CompilerOptionsDlg::OnUpdateUI)
73     EVT_UPDATE_UI(            XRCID("cmbResDirsPolicy"),                CompilerOptionsDlg::OnUpdateUI)
74     EVT_UPDATE_UI(            XRCID("btnSetDefaultCompiler"),           CompilerOptionsDlg::OnUpdateUI)
75     EVT_UPDATE_UI(            XRCID("btnAddCompiler"),                  CompilerOptionsDlg::OnUpdateUI)
76     EVT_UPDATE_UI(            XRCID("btnRenameCompiler"),               CompilerOptionsDlg::OnUpdateUI)
77     EVT_UPDATE_UI(            XRCID("btnDelCompiler"),                  CompilerOptionsDlg::OnUpdateUI)
78     EVT_UPDATE_UI(            XRCID("btnResetCompiler"),                CompilerOptionsDlg::OnUpdateUI)
79     EVT_UPDATE_UI(            XRCID("btnAddLib"),                       CompilerOptionsDlg::OnUpdateUI)
80     EVT_UPDATE_UI(            XRCID("btnEditLib"),                      CompilerOptionsDlg::OnUpdateUI)
81     EVT_UPDATE_UI(            XRCID("btnDelLib"),                       CompilerOptionsDlg::OnUpdateUI)
82     EVT_UPDATE_UI(            XRCID("btnClearLib"),                     CompilerOptionsDlg::OnUpdateUI)
83     EVT_UPDATE_UI(            XRCID("btnCopyLibs"),                     CompilerOptionsDlg::OnUpdateUI)
84     EVT_UPDATE_UI(            XRCID("btnMoveLibUp"),                    CompilerOptionsDlg::OnUpdateUI)
85     EVT_UPDATE_UI(            XRCID("btnMoveLibDown"),                  CompilerOptionsDlg::OnUpdateUI)
86     EVT_UPDATE_UI(            XRCID("txtMasterPath"),                   CompilerOptionsDlg::OnUpdateUI)
87     EVT_UPDATE_UI(            XRCID("btnMasterPath"),                   CompilerOptionsDlg::OnUpdateUI)
88     EVT_UPDATE_UI(            XRCID("btnExtraAdd"),                     CompilerOptionsDlg::OnUpdateUI)
89     EVT_UPDATE_UI(            XRCID("btnExtraEdit"),                    CompilerOptionsDlg::OnUpdateUI)
90     EVT_UPDATE_UI(            XRCID("btnExtraDelete"),                  CompilerOptionsDlg::OnUpdateUI)
91     EVT_UPDATE_UI(            XRCID("btnExtraClear"),                   CompilerOptionsDlg::OnUpdateUI)
92     EVT_UPDATE_UI(            XRCID("txtCcompiler"),                    CompilerOptionsDlg::OnUpdateUI)
93     EVT_UPDATE_UI(            XRCID("btnCcompiler"),                    CompilerOptionsDlg::OnUpdateUI)
94     EVT_UPDATE_UI(            XRCID("txtCPPcompiler"),                  CompilerOptionsDlg::OnUpdateUI)
95     EVT_UPDATE_UI(            XRCID("btnCPPcompiler"),                  CompilerOptionsDlg::OnUpdateUI)
96     EVT_UPDATE_UI(            XRCID("txtLinker"),                       CompilerOptionsDlg::OnUpdateUI)
97     EVT_UPDATE_UI(            XRCID("btnLinker"),                       CompilerOptionsDlg::OnUpdateUI)
98     EVT_UPDATE_UI(            XRCID("txtLibLinker"),                    CompilerOptionsDlg::OnUpdateUI)
99     EVT_UPDATE_UI(            XRCID("btnLibLinker"),                    CompilerOptionsDlg::OnUpdateUI)
100     EVT_UPDATE_UI(            XRCID("cmbDebugger"),                     CompilerOptionsDlg::OnUpdateUI)
101     EVT_UPDATE_UI(            XRCID("txtResComp"),                      CompilerOptionsDlg::OnUpdateUI)
102     EVT_UPDATE_UI(            XRCID("btnResComp"),                      CompilerOptionsDlg::OnUpdateUI)
103     EVT_UPDATE_UI(            XRCID("txtMake"),                         CompilerOptionsDlg::OnUpdateUI)
104     EVT_UPDATE_UI(            XRCID("btnMake"),                         CompilerOptionsDlg::OnUpdateUI)
105     EVT_UPDATE_UI(            XRCID("cmbCompiler"),                     CompilerOptionsDlg::OnUpdateUI)
106     EVT_UPDATE_UI(            XRCID("btnIgnoreAdd"),                    CompilerOptionsDlg::OnUpdateUI)
107     EVT_UPDATE_UI(            XRCID("btnIgnoreRemove"),                 CompilerOptionsDlg::OnUpdateUI)
108     //
109     EVT_TREE_SEL_CHANGED(      XRCID("tcScope"),                        CompilerOptionsDlg::OnTreeSelectionChange)
110     EVT_TREE_SEL_CHANGING(     XRCID("tcScope"),                        CompilerOptionsDlg::OnTreeSelectionChanging)
111     EVT_CHOICE(                XRCID("cmbCategory"),                    CompilerOptionsDlg::OnCategoryChanged)
112     EVT_CHOICE(                XRCID("cmbCompiler"),                    CompilerOptionsDlg::OnCompilerChanged)
113     EVT_LISTBOX_DCLICK(        XRCID("lstVars"),                        CompilerOptionsDlg::OnEditVarClick)
114     EVT_BUTTON(                XRCID("btnSetDefaultCompiler"),          CompilerOptionsDlg::OnSetDefaultCompilerClick)
115     EVT_BUTTON(                XRCID("btnAddCompiler"),                 CompilerOptionsDlg::OnAddCompilerClick)
116     EVT_BUTTON(                XRCID("btnRenameCompiler"),              CompilerOptionsDlg::OnEditCompilerClick)
117     EVT_BUTTON(                XRCID("btnDelCompiler"),                 CompilerOptionsDlg::OnRemoveCompilerClick)
118     EVT_BUTTON(                XRCID("btnResetCompiler"),               CompilerOptionsDlg::OnResetCompilerClick)
119     EVT_BUTTON(                XRCID("btnAddDir"),                      CompilerOptionsDlg::OnAddDirClick)
120     EVT_BUTTON(                XRCID("btnEditDir"),                     CompilerOptionsDlg::OnEditDirClick)
121     EVT_LISTBOX_DCLICK(        XRCID("lstIncludeDirs"),                 CompilerOptionsDlg::OnEditDirClick)
122     EVT_LISTBOX_DCLICK(        XRCID("lstLibDirs"),                     CompilerOptionsDlg::OnEditDirClick)
123     EVT_LISTBOX_DCLICK(        XRCID("lstResDirs"),                     CompilerOptionsDlg::OnEditDirClick)
124     EVT_BUTTON(                XRCID("btnDelDir"),                      CompilerOptionsDlg::OnRemoveDirClick)
125     EVT_BUTTON(                XRCID("btnClearDir"),                    CompilerOptionsDlg::OnClearDirClick)
126     EVT_BUTTON(                XRCID("btnCopyDirs"),                    CompilerOptionsDlg::OnCopyDirsClick)
127     EVT_BUTTON(                XRCID("btnAddLib"),                      CompilerOptionsDlg::OnAddLibClick)
128     EVT_BUTTON(                XRCID("btnEditLib"),                     CompilerOptionsDlg::OnEditLibClick)
129     EVT_LISTBOX_DCLICK(        XRCID("lstLibs"),                        CompilerOptionsDlg::OnEditLibClick)
130     EVT_BUTTON(                XRCID("btnDelLib"),                      CompilerOptionsDlg::OnRemoveLibClick)
131     EVT_BUTTON(                XRCID("btnClearLib"),                    CompilerOptionsDlg::OnClearLibClick)
132     EVT_BUTTON(                XRCID("btnCopyLibs"),                    CompilerOptionsDlg::OnCopyLibsClick)
133     EVT_LISTBOX_DCLICK(        XRCID("lstExtraPaths"),                  CompilerOptionsDlg::OnEditExtraPathClick)
134     EVT_BUTTON(                XRCID("btnExtraAdd"),                    CompilerOptionsDlg::OnAddExtraPathClick)
135     EVT_BUTTON(                XRCID("btnExtraEdit"),                   CompilerOptionsDlg::OnEditExtraPathClick)
136     EVT_BUTTON(                XRCID("btnExtraDelete"),                 CompilerOptionsDlg::OnRemoveExtraPathClick)
137     EVT_BUTTON(                XRCID("btnExtraClear"),                  CompilerOptionsDlg::OnClearExtraPathClick)
138     EVT_BUTTON(                XRCID("btnMoveLibUp"),                   CompilerOptionsDlg::OnMoveLibUpClick)
139     EVT_BUTTON(                XRCID("btnMoveLibDown"),                 CompilerOptionsDlg::OnMoveLibDownClick)
140     EVT_BUTTON(                XRCID("btnMoveDirUp"),                   CompilerOptionsDlg::OnMoveDirUpClick)
141     EVT_BUTTON(                XRCID("btnMoveDirDown"),                 CompilerOptionsDlg::OnMoveDirDownClick)
142     EVT_BUTTON(                XRCID("btnAddVar"),                      CompilerOptionsDlg::OnAddVarClick)
143     EVT_BUTTON(                XRCID("btnEditVar"),                     CompilerOptionsDlg::OnEditVarClick)
144     EVT_BUTTON(                XRCID("btnDeleteVar"),                   CompilerOptionsDlg::OnRemoveVarClick)
145     EVT_BUTTON(                XRCID("btnClearVar"),                    CompilerOptionsDlg::OnClearVarClick)
146     EVT_BUTTON(                XRCID("btnMasterPath"),                  CompilerOptionsDlg::OnMasterPathClick)
147     EVT_BUTTON(                XRCID("btnAutoDetect"),                  CompilerOptionsDlg::OnAutoDetectClick)
148     EVT_BUTTON(                XRCID("btnCcompiler"),                   CompilerOptionsDlg::OnSelectProgramClick)
149     EVT_BUTTON(                XRCID("btnCPPcompiler"),                 CompilerOptionsDlg::OnSelectProgramClick)
150     EVT_BUTTON(                XRCID("btnLinker"),                      CompilerOptionsDlg::OnSelectProgramClick)
151     EVT_BUTTON(                XRCID("btnLibLinker"),                   CompilerOptionsDlg::OnSelectProgramClick)
152     EVT_BUTTON(                XRCID("btnResComp"),                     CompilerOptionsDlg::OnSelectProgramClick)
153     EVT_BUTTON(                XRCID("btnMake"),                        CompilerOptionsDlg::OnSelectProgramClick)
154     EVT_BUTTON(                XRCID("btnAdvanced"),                    CompilerOptionsDlg::OnAdvancedClick)
155     EVT_BUTTON(                XRCID("btnIgnoreAdd"),                   CompilerOptionsDlg::OnIgnoreAddClick)
156     EVT_BUTTON(                XRCID("btnIgnoreRemove"),                CompilerOptionsDlg::OnIgnoreRemoveClick)
157     EVT_CHOICE(                XRCID("cmbCompilerPolicy"),              CompilerOptionsDlg::OnDirty)
158     EVT_CHOICE(                XRCID("cmbLinkerPolicy"),                CompilerOptionsDlg::OnDirty)
159     EVT_CHOICE(                XRCID("cmbIncludesPolicy"),              CompilerOptionsDlg::OnDirty)
160     EVT_CHOICE(                XRCID("cmbLibDirsPolicy"),               CompilerOptionsDlg::OnDirty)
161     EVT_CHOICE(                XRCID("cmbResDirsPolicy"),               CompilerOptionsDlg::OnDirty)
162     EVT_CHOICE(                XRCID("cmbLogging"),                     CompilerOptionsDlg::OnDirty)
163     EVT_CHOICE(                XRCID("chLinkerExe"),                    CompilerOptionsDlg::OnDirty)
164     EVT_CHECKBOX(              XRCID("chkAlwaysRunPost"),               CompilerOptionsDlg::OnDirty)
165     EVT_CHECKBOX(              XRCID("chkNonPlatComp"),                 CompilerOptionsDlg::OnDirty)
166     EVT_TEXT(                  XRCID("txtCompilerOptions"),             CompilerOptionsDlg::OnDirty)
167     EVT_TEXT(                  XRCID("txtResourceCompilerOptions"),     CompilerOptionsDlg::OnDirty)
168     EVT_TEXT(                  XRCID("txtCompilerDefines"),             CompilerOptionsDlg::OnDirty)
169     EVT_TEXT(                  XRCID("txtLinkerOptions"),               CompilerOptionsDlg::OnDirty)
170     EVT_TEXT(                  XRCID("txtCmdBefore"),                   CompilerOptionsDlg::OnDirty)
171     EVT_TEXT(                  XRCID("txtCmdAfter"),                    CompilerOptionsDlg::OnDirty)
172     EVT_TEXT(                  XRCID("txtMasterPath"),                  CompilerOptionsDlg::OnDirty)
173     EVT_TEXT(                  XRCID("txtCcompiler"),                   CompilerOptionsDlg::OnDirty)
174     EVT_TEXT(                  XRCID("txtCPPcompiler"),                 CompilerOptionsDlg::OnDirty)
175     EVT_TEXT(                  XRCID("txtLinker"),                      CompilerOptionsDlg::OnDirty)
176     EVT_TEXT(                  XRCID("txtLibLinker"),                   CompilerOptionsDlg::OnDirty)
177     EVT_TEXT(                  XRCID("txtResComp"),                     CompilerOptionsDlg::OnDirty)
178     EVT_TEXT(                  XRCID("txtMake"),                        CompilerOptionsDlg::OnDirty)
179     EVT_TEXT(                  XRCID("txtMakeCmd_Build"),               CompilerOptionsDlg::OnDirty)
180     EVT_TEXT(                  XRCID("txtMakeCmd_Compile"),             CompilerOptionsDlg::OnDirty)
181     EVT_TEXT(                  XRCID("txtMakeCmd_Clean"),               CompilerOptionsDlg::OnDirty)
182 //    EVT_TEXT(                  XRCID("txtMakeCmd_DistClean"),           CompilerOptionsDlg::OnDirty)
183     EVT_TEXT(                  XRCID("txtMakeCmd_AskRebuildNeeded"),    CompilerOptionsDlg::OnDirty)
184 //    EVT_TEXT(                  XRCID("txtMakeCmd_SilentBuild"),         CompilerOptionsDlg::OnDirty)
185     EVT_CHAR_HOOK(CompilerOptionsDlg::OnMyCharHook)
186 
187     EVT_PG_CHANGED(            XRCID("pgCompilerFlags"),                CompilerOptionsDlg::OnOptionChanged)
188     EVT_PG_RIGHT_CLICK(        XRCID("pgCompilerFlags"),                CompilerOptionsDlg::OnFlagsPopup)
189     EVT_PG_DOUBLE_CLICK(       XRCID("pgCompilerFlags"),                CompilerOptionsDlg::OnOptionDoubleClick)
190 END_EVENT_TABLE()
191 
192 class ScopeTreeData : public wxTreeItemData
193 {
194     public:
ScopeTreeData(cbProject * project,ProjectBuildTarget * target)195         ScopeTreeData(cbProject* project, ProjectBuildTarget* target){ m_Project = project; m_Target = target; }
GetProject()196         cbProject* GetProject(){ return m_Project; }
GetTarget()197         ProjectBuildTarget* GetTarget(){ return m_Target; }
198     private:
199         cbProject* m_Project;
200         ProjectBuildTarget* m_Target;
201 };
202 
203 struct DebuggerClientData : wxClientData
204 {
DebuggerClientDataDebuggerClientData205     DebuggerClientData(const wxString &s) : string(s) {}
206     wxString string;
207 };
208 
209 struct VariableListClientData : wxClientData
210 {
VariableListClientDataVariableListClientData211     VariableListClientData(const wxString &key, const wxString &value) : key(key), value(value) {}
212     wxString key, value;
213 };
214 
215 /*
216     CompilerOptions can exist on 3 different levels :
217     Level 1 : compiler level
218         - the options exist on the global level of the compiler
219     Level 2 : project level
220         - the options exist on the level of the project
221     Level 3 : the target level
222         - the options exist on the level of the target
223 */
224 
CompilerOptionsDlg(wxWindow * parent,CompilerGCC * compiler,cbProject * project,ProjectBuildTarget * target)225 CompilerOptionsDlg::CompilerOptionsDlg(wxWindow* parent, CompilerGCC* compiler, cbProject* project, ProjectBuildTarget* target) :
226     m_FlagsPG(nullptr),
227     m_Compiler(compiler),
228     m_CurrentCompilerIdx(0),
229     m_pProject(project),
230     m_pTarget(target),
231     m_bDirty(false),
232     m_BuildingTree(false)
233 {
234     wxXmlResource::Get()->LoadPanel(this, parent, _T("dlgCompilerOptions"));
235 
236     m_FlagsPG = new wxPropertyGrid(this, XRCID("pgCompilerFlags"), wxDefaultPosition, wxDefaultSize,
237                                    wxTAB_TRAVERSAL|wxPG_SPLITTER_AUTO_CENTER);
238     m_FlagsPG->SetExtraStyle(wxPG_EX_HELP_AS_TOOLTIPS);
239     m_FlagsPG->SetColumnProportion(0, 70);
240     m_FlagsPG->SetColumnProportion(1, 30);
241 
242     m_FlagsPG->SetMinSize(wxSize(400, 400));
243     wxXmlResource::Get()->AttachUnknownControl(wxT("pgCompilerFlags"), m_FlagsPG);
244 
245     if (m_pProject)
246     {
247         bool hasBuildScripts = m_pProject->GetBuildScripts().GetCount() != 0;
248         if (!hasBuildScripts)
249         {
250             // look in targets
251             for (int x = 0; x < m_pProject->GetBuildTargetsCount(); ++x)
252             {
253                 ProjectBuildTarget* curr_target = m_pProject->GetBuildTarget(x);
254                 hasBuildScripts = curr_target->GetBuildScripts().GetCount() != 0;
255                 if (hasBuildScripts)
256                     break;
257             }
258         }
259 
260         XRCCTRL(*this, "lblBuildScriptsNote", wxStaticText)->Show(hasBuildScripts);
261     }
262 
263     wxTreeCtrl* tree = XRCCTRL(*this, "tcScope", wxTreeCtrl);
264     wxSizer* sizer = tree->GetContainingSizer();
265     wxNotebook* nb = XRCCTRL(*this, "nbMain", wxNotebook);
266     if (!m_pProject)
267     {
268         // global settings
269         SetLabel(_("Compiler Settings"));
270         sizer->Show(tree,false);
271         sizer->Detach(tree);
272         nb->DeletePage(6); // remove "Make" page
273         nb->DeletePage(3); // remove "Commands" page
274     }
275     else
276     {
277         // project settings
278         nb->DeletePage(8); // remove "Other settings" page
279         nb->DeletePage(7); // remove "Build options" page
280         nb->DeletePage(4); // remove "Toolchain executables" page
281 
282         // remove "Compiler" buttons
283         wxWindow* win = XRCCTRL(*this, "btnAddCompiler", wxButton);
284         wxSizer* sizer2 = win->GetContainingSizer();
285         sizer2->Clear(true);
286         sizer2->Layout();
287 
288         // disable "Make" elements, if project is not using custom makefile
289         bool en = project->IsMakefileCustom();
290         XRCCTRL(*this, "txtMakeCmd_Build", wxTextCtrl)->Enable(en);
291         XRCCTRL(*this, "txtMakeCmd_Compile", wxTextCtrl)->Enable(en);
292         XRCCTRL(*this, "txtMakeCmd_Clean", wxTextCtrl)->Enable(en);
293         XRCCTRL(*this, "txtMakeCmd_DistClean", wxTextCtrl)->Enable(en);
294         XRCCTRL(*this, "txtMakeCmd_AskRebuildNeeded", wxTextCtrl)->Enable(en);
295         XRCCTRL(*this, "txtMakeCmd_SilentBuild", wxTextCtrl)->Enable(en);
296     }
297 
298     // let's start filling in all the panels of the configuration dialog
299     // there are compiler dependent settings and compiler independent settings
300 
301     // compiler independent (so settings these ones is sufficient)
302     DoFillOthers();
303     DoFillTree();
304     int compilerIdx = CompilerFactory::GetCompilerIndex(CompilerFactory::GetDefaultCompilerID());
305     if (m_pTarget)
306         compilerIdx = CompilerFactory::GetCompilerIndex(m_pTarget->GetCompilerID());
307     else if (m_pProject)
308         compilerIdx = CompilerFactory::GetCompilerIndex(m_pProject->GetCompilerID());
309     if ((m_pTarget || m_pProject) && compilerIdx == -1)
310     {   // unknown user compiler
311         // similar code can be found @ OnTreeSelectionChange()
312         // see there for more info : duplicate code now, since here we still need
313         // to fill in the compiler list for the choice control, where in
314         // OnTreeSelectionChange we just need to set an entry
315         // TODO : make 1 help method out of this, with some argument indicating
316         // to fill the choice list, or break it in 2 methods with the list filling in between them
317         // or maybe time will bring even brighter ideas
318         wxString CompilerId = m_pTarget?m_pTarget->GetCompilerID():m_pProject->GetCompilerID();
319         wxString msg;
320         msg.Printf(_("The defined compiler cannot be located (ID: %s).\n"
321                      "Please choose the compiler you want to use instead and click \"OK\".\n"
322                      "If you click \"Cancel\", the project/target will remain configured for\n"
323                      "that compiler and consequently can not be configured and will not be built."),
324                     CompilerId.wx_str());
325         Compiler* comp = 0;
326         if ((m_pTarget && m_pTarget->SupportsCurrentPlatform()) || (!m_pTarget && m_pProject))
327             comp = CompilerFactory::SelectCompilerUI(msg);
328 
329         if (comp)
330         {   // a new compiler was chosen, proceed as if the user manually selected another compiler
331             // that means set the compiler selection list accordingly
332             // and go directly to (On)CompilerChanged
333             int NewCompilerIdx = CompilerFactory::GetCompilerIndex(comp);
334             DoFillCompilerSets(NewCompilerIdx);
335             wxCommandEvent Dummy;
336             OnCompilerChanged(Dummy);
337         }
338         else
339         {   // the user cancelled and wants to keep the compiler
340             DoFillCompilerSets(compilerIdx);
341             if (nb)
342                 nb->Disable();
343         }
344     }
345     else
346     {
347         if (!CompilerFactory::GetCompiler(compilerIdx))
348             compilerIdx = 0;
349         DoFillCompilerSets(compilerIdx);
350         m_Options = CompilerFactory::GetCompiler(compilerIdx)->GetOptions();
351         m_CurrentCompilerIdx = compilerIdx;
352         // compiler dependent settings
353         DoFillCompilerDependentSettings();
354     }
355     if (m_pTarget && m_pTarget->GetTargetType() == ttCommandsOnly)
356     {
357         // disable pages for commands only target
358         nb->GetPage(0)->Disable(); // Compiler settings
359         nb->GetPage(1)->Disable(); // Linker settings
360         nb->GetPage(2)->Disable(); // Search directories
361         nb->GetPage(5)->Disable(); // "Make" commands
362         nb->SetSelection(3);       // Pre/post build steps
363     }
364     else
365         nb->SetSelection(0);
366     sizer->Layout();
367     Layout();
368     GetSizer()->Layout();
369     GetSizer()->SetSizeHints(this);
370 #ifdef __WXMAC__
371     // seems it's not big enough on the Apple/Mac : hacking time
372     int min_width, min_height;
373     GetSize(&min_width, &min_height);
374     this->SetSizeHints(min_width+140,min_height,-1,-1);
375 #endif
376     this->SetSize(-1, -1, 0, 0);
377     // disable some elements, if project is using custom makefile
378     // we do this after the layout is done, so the resulting dialog has always the same size
379     if (project && project->IsMakefileCustom())
380     {
381         nb->RemovePage(2); // remove "Search directories" page
382         nb->RemovePage(1); // remove "Linker settings" page
383         nb->RemovePage(0); // remove "Compiler settings" page
384         XRCCTRL(*this, "tabCompiler", wxPanel)->Show(false);
385         XRCCTRL(*this, "tabLinker", wxPanel)->Show(false);
386         XRCCTRL(*this, "tabDirs", wxPanel)->Show(false);
387     }
388 
389     Fit();
390 } // constructor
391 
~CompilerOptionsDlg()392 CompilerOptionsDlg::~CompilerOptionsDlg()
393 {
394     //dtor
395 }
396 
DoFillCompilerSets(int compilerIdx)397 void CompilerOptionsDlg::DoFillCompilerSets(int compilerIdx)
398 {
399     wxChoice* cmb = XRCCTRL(*this, "cmbCompiler", wxChoice);
400     cmb->Clear();
401     for (unsigned int i = 0; i < CompilerFactory::GetCompilersCount(); ++i)
402     {
403         cmb->Append(CompilerFactory::GetCompiler(i)->GetName());
404     }
405 
406 //    int compilerIdx = CompilerFactory::GetCompilerIndex(CompilerFactory::GetDefaultCompilerID());
407 //    if (m_pTarget)
408 //        compilerIdx = CompilerFactory::GetCompilerIndex(m_pTarget->GetCompilerID());
409 //    else if (m_pProject)
410 //        compilerIdx = CompilerFactory::GetCompilerIndex(m_pProject->GetCompilerID());
411 
412 //    if (!CompilerFactory::GetCompiler(compilerIdx))
413 //        compilerIdx = 0;
414 //    m_Options = CompilerFactory::GetCompiler(compilerIdx)->GetOptions();
415     if (compilerIdx != -1)
416         cmb->SetSelection(compilerIdx);
417 
418 //    m_CurrentCompilerIdx = compilerIdx;
419 } // DoFillCompilerSets
420 
DoFillCompilerDependentSettings()421 void CompilerOptionsDlg::DoFillCompilerDependentSettings()
422 {
423     DoFillCompilerPrograms();    // the programs executable's ...
424     DoLoadOptions();
425     DoFillVars();
426     // by the way we listen to changes in the textctrl, we also end up in the callbacks as
427     // a result of wxTextCtrl::SetValue, the preceding called methods did some of those -> reset dirty flag
428     m_bDirty = false;
429     m_bFlagsDirty = false;
430 } // DoFillCompilerDependentSettings
431 
DoSaveCompilerDependentSettings()432 void CompilerOptionsDlg::DoSaveCompilerDependentSettings()
433 {
434     DoSaveCompilerPrograms();
435     DoSaveOptions();
436     DoSaveVars();
437     if (m_bFlagsDirty)
438         DoSaveCompilerDefinition();
439     ProjectTargetCompilerAdjust();
440     m_bDirty = false;
441     m_bFlagsDirty = false;
442 } // DoSaveCompilerDependentSettings
443 
ArrayString2ListBox(const wxArrayString & array,wxListBox * control)444 inline void ArrayString2ListBox(const wxArrayString& array, wxListBox* control)
445 {
446     control->Clear();
447     int count = array.GetCount();
448     for (int i = 0; i < count; ++i)
449     {
450         if (!array[i].IsEmpty())
451             control->Append(array[i]);
452     }
453 } // ArrayString2ListBox
454 
ListBox2ArrayString(wxArrayString & array,const wxListBox * control)455 inline void ListBox2ArrayString(wxArrayString& array, const wxListBox* control)
456 {
457     array.Clear();
458     int count = control->GetCount();
459     for (int i = 0; i < count; ++i)
460     {
461         wxString tmp = control->GetString(i);
462         if (!tmp.IsEmpty())
463             array.Add(tmp);
464     }
465 } // ListBox2ArrayString
466 
DoFillCompilerPrograms()467 void CompilerOptionsDlg::DoFillCompilerPrograms()
468 {
469     if (m_pProject)
470         return; // no "Programs" page
471 
472     const Compiler* compiler = CompilerFactory::GetCompiler(m_CurrentCompilerIdx);
473     if (!compiler)
474         return;
475     const CompilerPrograms& progs = compiler->GetPrograms();
476 
477     XRCCTRL(*this, "txtMasterPath", wxTextCtrl)->SetValue(compiler->GetMasterPath());
478     XRCCTRL(*this, "txtCcompiler", wxTextCtrl)->SetValue(progs.C);
479     XRCCTRL(*this, "txtCPPcompiler", wxTextCtrl)->SetValue(progs.CPP);
480     XRCCTRL(*this, "txtLinker", wxTextCtrl)->SetValue(progs.LD);
481     XRCCTRL(*this, "txtLibLinker", wxTextCtrl)->SetValue(progs.LIB);
482     wxChoice *cmbDebugger = XRCCTRL(*this, "cmbDebugger", wxChoice);
483     if (cmbDebugger)
484     {
485         cmbDebugger->Clear();
486         // Add an invalid debugger entry and store the old value in the client data, so no user settings are changed.
487         cmbDebugger->Append(_("--- Invalid debugger ---"), new DebuggerClientData(progs.DBGconfig));
488         cmbDebugger->SetSelection(0);
489 
490         const DebuggerManager::RegisteredPlugins &plugins = Manager::Get()->GetDebuggerManager()->GetAllDebuggers();
491         for (DebuggerManager::RegisteredPlugins::const_iterator it = plugins.begin(); it != plugins.end(); ++it)
492         {
493             const DebuggerManager::PluginData &data = it->second;
494             for (DebuggerManager::ConfigurationVector::const_iterator itConf = data.GetConfigurations().begin();
495                  itConf != data.GetConfigurations().end();
496                  ++itConf)
497             {
498                 const wxString &def = it->first->GetSettingsName() + wxT(":") + (*itConf)->GetName();
499                 int index = cmbDebugger->Append(it->first->GetGUIName() + wxT(" : ") + (*itConf)->GetName(),
500                                                 new DebuggerClientData(def));
501                 if (def == progs.DBGconfig)
502                     cmbDebugger->SetSelection(index);
503             }
504         }
505     }
506 
507     XRCCTRL(*this, "txtResComp", wxTextCtrl)->SetValue(progs.WINDRES);
508     XRCCTRL(*this, "txtMake", wxTextCtrl)->SetValue(progs.MAKE);
509 
510     const wxArrayString& extraPaths = compiler->GetExtraPaths();
511     ArrayString2ListBox(extraPaths, XRCCTRL(*this, "lstExtraPaths", wxListBox));
512 } // DoFillCompilerPrograms
513 
DoFillVars()514 void CompilerOptionsDlg::DoFillVars()
515 {
516     wxListBox* lst = XRCCTRL(*this, "lstVars", wxListBox);
517     if (!lst)
518         return;
519     lst->Clear();
520     const StringHash* vars = 0;
521     const CompileOptionsBase* base = GetVarsOwner();
522     if (base)
523     {
524         vars = &base->GetAllVars();
525     }
526     if (!vars)
527         return;
528     for (StringHash::const_iterator it = vars->begin(); it != vars->end(); ++it)
529     {
530         wxString text = it->first + _T(" = ") + it->second;
531         lst->Append(text, new VariableListClientData(it->first, it->second));
532     }
533 } // DoFillVars
534 
DoFillOthers()535 void CompilerOptionsDlg::DoFillOthers()
536 {
537     if (m_pProject)
538         return; // projects don't have Other tab
539 
540     wxCheckBox* chk = XRCCTRL(*this, "chkIncludeFileCwd", wxCheckBox);
541     if (chk)
542         chk->SetValue(Manager::Get()->GetConfigManager(_T("compiler"))->ReadBool(_T("/include_file_cwd"), false));
543 
544     chk = XRCCTRL(*this, "chkIncludePrjCwd", wxCheckBox);
545     if (chk)
546         chk->SetValue(Manager::Get()->GetConfigManager(_T("compiler"))->ReadBool(_T("/include_prj_cwd"), false));
547 
548     chk = XRCCTRL(*this, "chkSkipIncludeDeps", wxCheckBox);
549     if (chk)
550         chk->SetValue(Manager::Get()->GetConfigManager(_T("compiler"))->ReadBool(_T("/skip_include_deps"), false));
551 
552     chk = XRCCTRL(*this, "chkSaveHtmlLog", wxCheckBox);
553     if (chk)
554         chk->SetValue(Manager::Get()->GetConfigManager(_T("compiler"))->ReadBool(_T("/save_html_build_log"), false));
555 
556     chk = XRCCTRL(*this, "chkFullHtmlLog", wxCheckBox);
557     if (chk)
558         chk->SetValue(Manager::Get()->GetConfigManager(_T("compiler"))->ReadBool(_T("/save_html_build_log/full_command_line"), false));
559 
560     chk = XRCCTRL(*this, "chkBuildProgressBar", wxCheckBox);
561     if (chk)
562         chk->SetValue(Manager::Get()->GetConfigManager(_T("compiler"))->ReadBool(_T("/build_progress/bar"), false));
563 
564     chk = XRCCTRL(*this, "chkBuildProgressPerc", wxCheckBox);
565     if (chk)
566         chk->SetValue(Manager::Get()->GetConfigManager(_T("compiler"))->ReadBool(_T("/build_progress/percentage"), false));
567 
568     wxSpinCtrl* spn = XRCCTRL(*this, "spnParallelProcesses", wxSpinCtrl);
569     if (spn)
570         spn->SetValue(Manager::Get()->GetConfigManager(_T("compiler"))->ReadInt(_T("/parallel_processes"), 0));
571 
572     spn = XRCCTRL(*this, "spnMaxErrors", wxSpinCtrl);
573     if (spn)
574     {
575         spn->SetRange(0, 1000);
576         spn->SetValue(Manager::Get()->GetConfigManager(_T("compiler"))->ReadInt(_T("/max_reported_errors"), 50));
577     }
578 
579     chk = XRCCTRL(*this, "chkRebuildSeperately", wxCheckBox);
580     if (chk)
581         chk->SetValue(Manager::Get()->GetConfigManager(_T("compiler"))->ReadBool(_T("/rebuild_seperately"), false));
582 
583     wxListBox* lst = XRCCTRL(*this, "lstIgnore", wxListBox);
584     if (lst)
585     {
586         wxArrayString IgnoreOutput;
587         IgnoreOutput = Manager::Get()->GetConfigManager(_T("compiler"))->ReadArrayString(_T("/ignore_output"));
588         ArrayString2ListBox(IgnoreOutput, lst);
589     }
590 
591     chk = XRCCTRL(*this, "chkNonPlatComp", wxCheckBox);
592     if (chk)
593         chk->SetValue(Manager::Get()->GetConfigManager(_T("compiler"))->ReadBool(_T("/non_plat_comp"), false));
594 } // DoFillOthers
595 
DoFillTree()596 void CompilerOptionsDlg::DoFillTree()
597 {
598     m_BuildingTree = true;
599     wxTreeCtrl* tc = XRCCTRL(*this, "tcScope", wxTreeCtrl);
600     tc->DeleteAllItems();
601 
602     wxTreeItemId root;
603     wxTreeItemId selectedItem;
604 
605     if (!m_pProject)
606     {
607         // global settings
608         root = tc->AddRoot(_("Global options"), -1, -1);
609         selectedItem = root;
610     }
611     else
612     {
613         // project settings
614         // in case you wonder : the delete of data will be done by the wxTreeCtrl
615         ScopeTreeData* data = new ScopeTreeData(m_pProject, 0L);
616         root = tc->AddRoot(m_pProject->GetTitle(), -1, -1, data);
617         selectedItem = root;
618         for (int x = 0; x < m_pProject->GetBuildTargetsCount(); ++x)
619         {
620             ProjectBuildTarget* target = m_pProject->GetBuildTarget(x);
621             data = new ScopeTreeData(m_pProject, target);
622             wxTreeItemId targetItem = tc->AppendItem(root, target->GetTitle(), -1, -1, data);
623             if (target == m_pTarget)
624                 selectedItem = targetItem;
625         }
626     }
627     // normally the target should be found in the targets of the project
628     // in case it is not, we will reset m_pTarget to 0 (in sync with tree selection)
629     if (selectedItem == root)
630         m_pTarget = 0;
631 
632     tc->Expand(root);
633     tc->SelectItem(selectedItem);
634     m_BuildingTree = false;
635 } // DoFillTree
636 
DoFillOptions()637 void CompilerOptionsDlg::DoFillOptions()
638 {
639     m_FlagsPG->Freeze();
640     m_FlagsPG->Clear();
641     typedef std::map<wxString, wxPropertyCategory*> MapCategories;
642     MapCategories categories;
643 
644     // If there is a "General" category make sure it is added first.
645     for (size_t i = 0; i < m_Options.GetCount(); ++i)
646     {
647         const CompOption* option = m_Options.GetOption(i);
648         if (option->category == wxT("General"))
649         {
650             wxPropertyCategory *categoryProp = new wxPropertyCategory(option->category);
651             m_FlagsPG->Append(categoryProp);
652             categories[option->category] = categoryProp;
653             break;
654         }
655     }
656 
657     // Add all flags and categories to the property grid
658     for (size_t i = 0; i < m_Options.GetCount(); ++i)
659     {
660         const CompOption* option = m_Options.GetOption(i);
661         wxPropertyCategory *categoryProp = nullptr;
662         MapCategories::iterator itCat = categories.find(option->category);
663         if (itCat != categories.end())
664             categoryProp = itCat->second;
665         else
666         {
667             categoryProp = new wxPropertyCategory(option->category);
668             m_FlagsPG->Append(categoryProp);
669             categories[option->category] = categoryProp;
670         }
671 
672         wxPGProperty *prop = new wxBoolProperty(option->name, wxPG_LABEL, option->enabled);
673         m_FlagsPG->AppendIn(categoryProp, prop);
674         m_FlagsPG->SetPropertyAttribute(prop, wxPG_BOOL_USE_CHECKBOX, true, wxPG_RECURSE);
675     }
676 
677     wxPGProperty *root = m_FlagsPG->GetRoot();
678     if (root)
679     {
680         unsigned count = root->GetChildCount();
681         for (unsigned ii = 0; ii < count; ++ii)
682 #if wxCHECK_VERSION(3, 0, 0)
683             m_FlagsPG->SortChildren(root->Item(ii), wxPG_RECURSE);
684 #else
685             m_FlagsPG->Sort(root->Item(ii));
686 #endif
687     }
688     m_FlagsPG->Thaw();
689 } // DoFillOptions
690 
TextToOptions()691 void CompilerOptionsDlg::TextToOptions()
692 {
693     // disable all options
694     for (size_t n = 0; n < m_Options.GetCount(); ++n)
695     {
696         if (CompOption* copt = m_Options.GetOption(n))
697             copt->enabled = false;
698     }
699 
700     wxString rest;
701 
702     Compiler* compiler = CompilerFactory::GetCompiler(m_CurrentCompilerIdx);
703 
704     XRCCTRL(*this, "txtCompilerDefines", wxTextCtrl)->Clear();
705     unsigned int i = 0;
706     while (i < m_CompilerOptions.GetCount())
707     {
708         wxString opt = m_CompilerOptions.Item(i);
709         opt = opt.Strip(wxString::both);
710         CompOption* copt = m_Options.GetOptionByOption(opt);
711         if (copt)
712         {
713 //            Manager::Get()->GetLogManager()->DebugLog("Enabling option %s", copt->option.c_str());
714             copt->enabled = true;
715             m_CompilerOptions.RemoveAt(i, 1);
716         }
717         else if (compiler && opt.StartsWith(compiler->GetSwitches().defines, &rest))
718         {
719             // definition
720             XRCCTRL(*this, "txtCompilerDefines", wxTextCtrl)->AppendText(rest);
721             XRCCTRL(*this, "txtCompilerDefines", wxTextCtrl)->AppendText(_T("\n"));
722             m_CompilerOptions.RemoveAt(i, 1);
723         }
724         else
725             ++i;
726     }
727     i = 0;
728     while (i < m_LinkerOptions.GetCount())
729     {
730         wxString opt = m_LinkerOptions.Item(i);
731         opt = opt.Strip(wxString::both);
732         CompOption* copt = m_Options.GetOptionByAdditionalLibs(opt);
733         if (copt)
734         {
735 //            Manager::Get()->GetLogManager()->DebugLog("Enabling option %s", copt->option.c_str());
736             copt->enabled = true;
737             m_LinkerOptions.RemoveAt(i, 1);
738         }
739         else
740             ++i;
741     }
742 
743     XRCCTRL(*this, "lstLibs", wxListBox)->Clear();
744     for (unsigned int j = 0; j < m_LinkLibs.GetCount(); ++j)
745         XRCCTRL(*this, "lstLibs", wxListBox)->Append(m_LinkLibs[j]);
746 
747     m_LinkLibs.Clear();
748 } // TextToOptions
749 
ArrayString2TextCtrl(const wxArrayString & array,wxTextCtrl * control)750 inline void ArrayString2TextCtrl(const wxArrayString& array, wxTextCtrl* control)
751 {
752     control->Clear();
753     int count = array.GetCount();
754     for (int i = 0; i < count; ++i)
755     {
756         if (!array[i].IsEmpty())
757         {
758             control->AppendText(array[i]);
759             control->AppendText(_T('\n'));
760         }
761     }
762 } // ArrayString2TextCtrl
763 
DoGetCompileOptions(wxArrayString & array,const wxTextCtrl * control)764 inline void DoGetCompileOptions(wxArrayString& array, const wxTextCtrl* control)
765 {
766 /* NOTE (mandrav#1#): Under Gnome2, wxTextCtrl::GetLineLength() returns always 0,
767                       so wxTextCtrl::GetLineText() is always empty...
768                       Now, we 're breaking up by newlines. */
769     array.Clear();
770 #if 1
771     wxString tmp = control->GetValue();
772     int nl = tmp.Find(_T('\n'));
773     wxString line;
774     if (nl == -1)
775     {
776         line = tmp;
777         tmp = _T("");
778     }
779     else
780         line = tmp.Left(nl);
781     while (nl != -1 || !line.IsEmpty())
782     {
783 //        Manager::Get()->GetLogManager()->DebugLog("%s text=%s", control->GetName().c_str(), line.c_str());
784         if (!line.IsEmpty())
785         {
786             // just to make sure..
787             line.Replace(_T("\r"), _T(" "), true); // remove CRs
788             line.Replace(_T("\n"), _T(" "), true); // remove LFs
789             array.Add(line.Strip(wxString::both));
790         }
791         tmp.Remove(0, nl + 1);
792         nl = tmp.Find(_T('\n'));
793         if (nl == -1)
794         {
795             line = tmp;
796             tmp = _T("");
797         }
798         else
799             line = tmp.Left(nl);
800     }
801 #else
802     int count = control->GetNumberOfLines();
803     for (int i = 0; i < count; ++i)
804     {
805         wxString tmp = control->GetLineText(i);
806         if (!tmp.IsEmpty())
807         {
808             tmp.Replace(_T("\r"), _T(" "), true); // remove CRs
809             tmp.Replace(_T("\n"), _T(" "), true); // remove LFs
810             array.Add(tmp.Strip(wxString::both));
811         }
812     }
813 #endif
814 } // DoGetCompileOptions
815 
DoLoadOptions()816 void CompilerOptionsDlg::DoLoadOptions()
817 {
818     wxArrayString CommandsBeforeBuild;
819     wxArrayString CommandsAfterBuild;
820     bool AlwaysUsePost = false;
821     wxArrayString IncludeDirs;
822     wxArrayString LibDirs;
823     wxArrayString ResDirs;
824 
825     if (!m_pProject && !m_pTarget)
826     {
827         // global options
828         const Compiler* compiler = CompilerFactory::GetCompiler(m_CurrentCompilerIdx);
829         if (compiler)
830         {
831             IncludeDirs = compiler->GetIncludeDirs();
832             ResDirs = compiler->GetResourceIncludeDirs();
833             LibDirs = compiler->GetLibDirs();
834             m_CompilerOptions = compiler->GetCompilerOptions();
835             m_ResourceCompilerOptions = compiler->GetResourceCompilerOptions();
836             m_LinkerOptions = compiler->GetLinkerOptions();
837             m_LinkLibs = compiler->GetLinkLibs();
838 
839             wxChoice* cmbLogging = XRCCTRL(*this, "cmbLogging", wxChoice);
840             if (cmbLogging)
841                 cmbLogging->SetSelection((int)compiler->GetSwitches().logging);
842 
843             wxChoice *cmbLinkerExe = XRCCTRL(*this, "chLinkerExe", wxChoice);
844             cmbLinkerExe->Show(false);
845             wxStaticText *txtLinkerExe = XRCCTRL(*this, "txtLinkerExe", wxStaticText);
846             txtLinkerExe->Show(false);
847         }
848     }
849     else
850     {
851         if (!m_pTarget)
852         {
853             // project options
854             SetLabel(_("Project build options"));
855             IncludeDirs = m_pProject->GetIncludeDirs();
856             ResDirs = m_pProject->GetResourceIncludeDirs();
857             LibDirs = m_pProject->GetLibDirs();
858             m_CompilerOptions = m_pProject->GetCompilerOptions();
859             m_ResourceCompilerOptions = m_pProject->GetResourceCompilerOptions();
860             m_LinkerOptions = m_pProject->GetLinkerOptions();
861             m_LinkLibs = m_pProject->GetLinkLibs();
862 
863             CommandsAfterBuild = m_pProject->GetCommandsAfterBuild();
864             CommandsBeforeBuild = m_pProject->GetCommandsBeforeBuild();
865             AlwaysUsePost = m_pProject->GetAlwaysRunPostBuildSteps();
866 
867             XRCCTRL(*this, "txtMakeCmd_Build",            wxTextCtrl)->SetValue(m_pProject->GetMakeCommandFor(mcBuild));
868             XRCCTRL(*this, "txtMakeCmd_Compile",          wxTextCtrl)->SetValue(m_pProject->GetMakeCommandFor(mcCompileFile));
869             XRCCTRL(*this, "txtMakeCmd_Clean",            wxTextCtrl)->SetValue(m_pProject->GetMakeCommandFor(mcClean));
870             XRCCTRL(*this, "txtMakeCmd_DistClean",        wxTextCtrl)->SetValue(m_pProject->GetMakeCommandFor(mcDistClean));
871             XRCCTRL(*this, "txtMakeCmd_AskRebuildNeeded", wxTextCtrl)->SetValue(m_pProject->GetMakeCommandFor(mcAskRebuildNeeded));
872             XRCCTRL(*this, "txtMakeCmd_SilentBuild",      wxTextCtrl)->SetValue(m_pProject->GetMakeCommandFor(mcSilentBuild));
873         }
874         else
875         {
876             // target options
877             SetLabel(_("Target build options: ") + m_pTarget->GetTitle());
878             IncludeDirs = m_pTarget->GetIncludeDirs();
879             ResDirs = m_pTarget->GetResourceIncludeDirs();
880             LibDirs = m_pTarget->GetLibDirs();
881             m_CompilerOptions = m_pTarget->GetCompilerOptions();
882             m_ResourceCompilerOptions = m_pTarget->GetResourceCompilerOptions();
883             m_LinkerOptions = m_pTarget->GetLinkerOptions();
884             m_LinkLibs = m_pTarget->GetLinkLibs();
885             CommandsAfterBuild = m_pTarget->GetCommandsAfterBuild();
886             CommandsBeforeBuild = m_pTarget->GetCommandsBeforeBuild();
887             AlwaysUsePost = m_pTarget->GetAlwaysRunPostBuildSteps();
888             XRCCTRL(*this, "cmbCompilerPolicy", wxChoice)->SetSelection(m_pTarget->GetOptionRelation(ortCompilerOptions));
889             XRCCTRL(*this, "cmbLinkerPolicy",   wxChoice)->SetSelection(m_pTarget->GetOptionRelation(ortLinkerOptions));
890             XRCCTRL(*this, "cmbIncludesPolicy", wxChoice)->SetSelection(m_pTarget->GetOptionRelation(ortIncludeDirs));
891             XRCCTRL(*this, "cmbLibDirsPolicy",  wxChoice)->SetSelection(m_pTarget->GetOptionRelation(ortLibDirs));
892             XRCCTRL(*this, "cmbResDirsPolicy",  wxChoice)->SetSelection(m_pTarget->GetOptionRelation(ortResDirs));
893 
894             XRCCTRL(*this, "txtMakeCmd_Build",            wxTextCtrl)->SetValue(m_pTarget->GetMakeCommandFor(mcBuild));
895             XRCCTRL(*this, "txtMakeCmd_Compile",          wxTextCtrl)->SetValue(m_pTarget->GetMakeCommandFor(mcCompileFile));
896             XRCCTRL(*this, "txtMakeCmd_Clean",            wxTextCtrl)->SetValue(m_pTarget->GetMakeCommandFor(mcClean));
897             XRCCTRL(*this, "txtMakeCmd_DistClean",        wxTextCtrl)->SetValue(m_pTarget->GetMakeCommandFor(mcDistClean));
898             XRCCTRL(*this, "txtMakeCmd_AskRebuildNeeded", wxTextCtrl)->SetValue(m_pTarget->GetMakeCommandFor(mcAskRebuildNeeded));
899             XRCCTRL(*this, "txtMakeCmd_SilentBuild",      wxTextCtrl)->SetValue(m_pTarget->GetMakeCommandFor(mcSilentBuild));
900 
901             const LinkerExecutableOption linkerExecutable = m_pTarget->GetLinkerExecutable();
902             XRCCTRL(*this, "chLinkerExe", wxChoice)->SetSelection(int(linkerExecutable));
903         }
904     }
905     TextToOptions();
906 
907     DoFillOptions();
908     ArrayString2ListBox(IncludeDirs,                XRCCTRL(*this, "lstIncludeDirs",             wxListBox));
909     ArrayString2ListBox(LibDirs,                    XRCCTRL(*this, "lstLibDirs",                 wxListBox));
910     ArrayString2ListBox(ResDirs,                    XRCCTRL(*this, "lstResDirs",                 wxListBox));
911     ArrayString2TextCtrl(m_CompilerOptions,         XRCCTRL(*this, "txtCompilerOptions",         wxTextCtrl));
912     ArrayString2TextCtrl(m_ResourceCompilerOptions, XRCCTRL(*this, "txtResourceCompilerOptions", wxTextCtrl));
913     ArrayString2TextCtrl(m_LinkerOptions,           XRCCTRL(*this, "txtLinkerOptions",           wxTextCtrl));
914 
915     // only if "Commands" page exists
916     if (m_pProject)
917     {
918         ArrayString2TextCtrl(CommandsBeforeBuild, XRCCTRL(*this, "txtCmdBefore", wxTextCtrl));
919         ArrayString2TextCtrl(CommandsAfterBuild, XRCCTRL(*this, "txtCmdAfter", wxTextCtrl));
920         XRCCTRL(*this, "chkAlwaysRunPost", wxCheckBox)->SetValue(AlwaysUsePost);
921     }
922 } // DoLoadOptions
923 
OptionsToText()924 void CompilerOptionsDlg::OptionsToText()
925 {
926     wxArrayString array;
927     DoGetCompileOptions(array, XRCCTRL(*this, "txtCompilerDefines", wxTextCtrl));
928 
929     int compilerIdx = XRCCTRL(*this, "cmbCompiler", wxChoice)->GetSelection();
930     const Compiler* compiler = CompilerFactory::GetCompiler(compilerIdx);
931 
932     for (unsigned int i = 0; i < array.GetCount(); ++i)
933     {
934         if (!array[i].IsEmpty())
935         {
936             if (array[i].StartsWith(compiler ? compiler->GetSwitches().genericSwitch : _T("-")))
937             {
938                 if (m_CompilerOptions.Index(array[i]) == wxNOT_FOUND)
939                     m_CompilerOptions.Add(array[i]);
940             }
941             else
942             {
943                 if (compiler && m_CompilerOptions.Index(compiler->GetSwitches().defines + array[i]) == wxNOT_FOUND)
944                     m_CompilerOptions.Add(compiler->GetSwitches().defines + array[i]);
945             }
946         }
947     }
948 
949     wxArrayString compilerOpConflicts;
950     wxArrayString linkerOpConflicts;
951     for (size_t i = 0; i < m_Options.GetCount(); ++i)
952     {
953         CompOption* copt = m_Options.GetOption(i);
954         if (copt->enabled)
955         {
956             if (!copt->option.Trim().IsEmpty()) // don't add empty options
957                 m_CompilerOptions.Insert(copt->option, 0);
958 
959             if (!copt->additionalLibs.Trim().IsEmpty())
960             {
961                 if (m_LinkerOptions.Index(copt->additionalLibs) == wxNOT_FOUND)
962                     m_LinkerOptions.Insert(copt->additionalLibs, 0);
963             }
964         }
965         else
966         {
967             // mark items for removal
968             if (m_CompilerOptions.Index(copt->option) != wxNOT_FOUND)
969                 compilerOpConflicts.Add(copt->option);
970             if (m_LinkerOptions.Index(copt->additionalLibs) != wxNOT_FOUND)
971                 linkerOpConflicts.Add(copt->additionalLibs);
972         }
973     }
974 
975     if (!compilerOpConflicts.IsEmpty() || !linkerOpConflicts.IsEmpty())
976     {
977         wxString msg = _("The compiler flags\n  ")
978                        + GetStringFromArray(compilerOpConflicts, wxT("\n  "))
979                        + GetStringFromArray(linkerOpConflicts,   wxT("\n  "));
980         msg.RemoveLast(2); // remove two trailing spaces
981         msg += _("were stated in 'Other Options' but unchecked in 'Compiler Flags'.\n"
982                  "Do you want to enable these flags?");
983         AnnoyingDialog dlg(_("Enable compiler flags?"), msg, wxART_QUESTION,
984                            AnnoyingDialog::YES_NO, AnnoyingDialog::rtNO);
985         if (dlg.ShowModal() == AnnoyingDialog::rtNO)
986         {
987             // for disabled options, remove relative text option *and*
988             // relative linker option
989             for (size_t i = 0; i < compilerOpConflicts.GetCount(); ++i)
990                 m_CompilerOptions.Remove(compilerOpConflicts[i]);
991             for (size_t i = 0; i < linkerOpConflicts.GetCount(); ++i)
992                 m_LinkerOptions.Remove(linkerOpConflicts[i]);
993         }
994     }
995 
996     // linker options and libs
997     wxListBox* lstLibs = XRCCTRL(*this, "lstLibs", wxListBox);
998     for (size_t i = 0; i < lstLibs->GetCount(); ++i)
999         m_LinkLibs.Add(lstLibs->GetString(i));
1000 } // OptionsToText
1001 
DoSaveOptions()1002 void CompilerOptionsDlg::DoSaveOptions()
1003 {
1004     wxArrayString IncludeDirs;
1005     wxArrayString LibDirs;
1006     wxArrayString ResDirs;
1007     ListBox2ArrayString(IncludeDirs,               XRCCTRL(*this, "lstIncludeDirs",             wxListBox));
1008     ListBox2ArrayString(LibDirs,                   XRCCTRL(*this, "lstLibDirs",                 wxListBox));
1009     ListBox2ArrayString(ResDirs,                   XRCCTRL(*this, "lstResDirs",                 wxListBox));
1010     DoGetCompileOptions(m_CompilerOptions,         XRCCTRL(*this, "txtCompilerOptions",         wxTextCtrl));
1011     DoGetCompileOptions(m_ResourceCompilerOptions, XRCCTRL(*this, "txtResourceCompilerOptions", wxTextCtrl));
1012     DoGetCompileOptions(m_LinkerOptions,           XRCCTRL(*this, "txtLinkerOptions",           wxTextCtrl));
1013     OptionsToText();
1014 
1015     if (!m_pProject && !m_pTarget)
1016     {
1017         // global options
1018         Compiler* compiler = CompilerFactory::GetCompiler(m_CurrentCompilerIdx);
1019         if (compiler)
1020         {
1021             compiler->SetIncludeDirs(IncludeDirs);
1022             compiler->SetLibDirs(LibDirs);
1023             compiler->SetResourceIncludeDirs(ResDirs);
1024             compiler->SetCompilerOptions(m_CompilerOptions);
1025             compiler->SetResourceCompilerOptions(m_ResourceCompilerOptions);
1026             compiler->SetLinkerOptions(m_LinkerOptions);
1027             compiler->SetLinkLibs(m_LinkLibs);
1028 
1029             wxChoice* cmb = XRCCTRL(*this, "cmbLogging", wxChoice);
1030             if (cmb)
1031             {
1032                 CompilerSwitches switches = compiler->GetSwitches();
1033                 switches.logging = (CompilerLoggingType)cmb->GetSelection();
1034                 compiler->SetSwitches(switches);
1035             }
1036         }
1037     }
1038     else
1039     {
1040         // only if "Commands" page exists
1041         wxArrayString CommandsBeforeBuild;
1042         wxArrayString CommandsAfterBuild;
1043         bool AlwaysUsePost = false;
1044         if (m_pProject)
1045         {
1046             AlwaysUsePost = XRCCTRL(*this, "chkAlwaysRunPost", wxCheckBox)->GetValue();
1047             DoGetCompileOptions(CommandsBeforeBuild, XRCCTRL(*this, "txtCmdBefore", wxTextCtrl));
1048             DoGetCompileOptions(CommandsAfterBuild, XRCCTRL(*this, "txtCmdAfter", wxTextCtrl));
1049         }
1050         if (!m_pTarget)
1051         {
1052             // project options
1053             m_pProject->SetIncludeDirs(IncludeDirs);
1054             m_pProject->SetResourceIncludeDirs(ResDirs);
1055             m_pProject->SetLibDirs(LibDirs);
1056             m_pProject->SetCompilerOptions(m_CompilerOptions);
1057             m_pProject->SetResourceCompilerOptions(m_ResourceCompilerOptions);
1058             m_pProject->SetLinkerOptions(m_LinkerOptions);
1059             m_pProject->SetLinkLibs(m_LinkLibs);
1060             m_pProject->SetCommandsBeforeBuild(CommandsBeforeBuild);
1061             m_pProject->SetCommandsAfterBuild(CommandsAfterBuild);
1062             m_pProject->SetAlwaysRunPostBuildSteps(AlwaysUsePost);
1063 
1064             m_pProject->SetMakeCommandFor(mcBuild, XRCCTRL(*this, "txtMakeCmd_Build", wxTextCtrl)->GetValue());
1065             m_pProject->SetMakeCommandFor(mcCompileFile, XRCCTRL(*this, "txtMakeCmd_Compile", wxTextCtrl)->GetValue());
1066             m_pProject->SetMakeCommandFor(mcClean, XRCCTRL(*this, "txtMakeCmd_Clean", wxTextCtrl)->GetValue());
1067             m_pProject->SetMakeCommandFor(mcDistClean, XRCCTRL(*this, "txtMakeCmd_DistClean", wxTextCtrl)->GetValue());
1068             m_pProject->SetMakeCommandFor(mcAskRebuildNeeded, XRCCTRL(*this, "txtMakeCmd_AskRebuildNeeded", wxTextCtrl)->GetValue());
1069 //            m_pProject->SetMakeCommandFor(mcSilentBuild, XRCCTRL(*this, "txtMakeCmd_SilentBuild", wxTextCtrl)->GetValue());
1070             m_pProject->SetMakeCommandFor(mcSilentBuild, XRCCTRL(*this, "txtMakeCmd_Build", wxTextCtrl)->GetValue() + _T(" > $(CMD_NULL)"));
1071         }
1072         else
1073         {
1074             // target options
1075             m_pTarget->SetIncludeDirs(IncludeDirs);
1076             m_pTarget->SetResourceIncludeDirs(ResDirs);
1077             m_pTarget->SetLibDirs(LibDirs);
1078             m_pTarget->SetCompilerOptions(m_CompilerOptions);
1079             m_pTarget->SetResourceCompilerOptions(m_ResourceCompilerOptions);
1080             m_pTarget->SetLinkerOptions(m_LinkerOptions);
1081             m_pTarget->SetLinkLibs(m_LinkLibs);
1082 
1083             {
1084                 int value = XRCCTRL(*this, "chLinkerExe", wxChoice)->GetSelection();
1085                 LinkerExecutableOption linkerExe;
1086                 if (value >= 0 && value < int(LinkerExecutableOption::Last))
1087                     linkerExe = LinkerExecutableOption(value);
1088                 else
1089                     linkerExe = LinkerExecutableOption::AutoDetect;
1090                 m_pTarget->SetLinkerExecutable(linkerExe);
1091             }
1092 
1093             m_pTarget->SetOptionRelation(ortCompilerOptions, OptionsRelation(XRCCTRL(*this, "cmbCompilerPolicy", wxChoice)->GetSelection()));
1094             m_pTarget->SetOptionRelation(ortLinkerOptions, OptionsRelation(XRCCTRL(*this, "cmbLinkerPolicy", wxChoice)->GetSelection()));
1095             m_pTarget->SetOptionRelation(ortIncludeDirs, OptionsRelation(XRCCTRL(*this, "cmbIncludesPolicy", wxChoice)->GetSelection()));
1096             m_pTarget->SetOptionRelation(ortLibDirs, OptionsRelation(XRCCTRL(*this, "cmbLibDirsPolicy", wxChoice)->GetSelection()));
1097             m_pTarget->SetOptionRelation(ortResDirs, OptionsRelation(XRCCTRL(*this, "cmbResDirsPolicy", wxChoice)->GetSelection()));
1098             m_pTarget->SetCommandsBeforeBuild(CommandsBeforeBuild);
1099             m_pTarget->SetCommandsAfterBuild(CommandsAfterBuild);
1100             m_pTarget->SetAlwaysRunPostBuildSteps(AlwaysUsePost);
1101 
1102             m_pTarget->SetMakeCommandFor(mcBuild, XRCCTRL(*this, "txtMakeCmd_Build", wxTextCtrl)->GetValue());
1103             m_pTarget->SetMakeCommandFor(mcCompileFile, XRCCTRL(*this, "txtMakeCmd_Compile", wxTextCtrl)->GetValue());
1104             m_pTarget->SetMakeCommandFor(mcClean, XRCCTRL(*this, "txtMakeCmd_Clean", wxTextCtrl)->GetValue());
1105             m_pTarget->SetMakeCommandFor(mcDistClean, XRCCTRL(*this, "txtMakeCmd_DistClean", wxTextCtrl)->GetValue());
1106             m_pTarget->SetMakeCommandFor(mcAskRebuildNeeded, XRCCTRL(*this, "txtMakeCmd_AskRebuildNeeded", wxTextCtrl)->GetValue());
1107 //            m_pTarget->SetMakeCommandFor(mcSilentBuild, XRCCTRL(*this, "txtMakeCmd_SilentBuild", wxTextCtrl)->GetValue());
1108             m_pTarget->SetMakeCommandFor(mcSilentBuild, XRCCTRL(*this, "txtMakeCmd_Build", wxTextCtrl)->GetValue() + _T(" > $(CMD_NULL)"));
1109         }
1110     }
1111 } // DoSaveOptions
1112 
DoSaveCompilerPrograms()1113 void CompilerOptionsDlg::DoSaveCompilerPrograms()
1114 {
1115     Compiler* compiler = CompilerFactory::GetCompiler(m_CurrentCompilerIdx);
1116     if (m_pProject || !compiler) // no "Programs" page or no compiler
1117         return;
1118 
1119     CompilerPrograms progs;
1120     wxString masterPath = XRCCTRL(*this, "txtMasterPath", wxTextCtrl)->GetValue();
1121     progs.C       = (XRCCTRL(*this, "txtCcompiler",   wxTextCtrl)->GetValue()).Trim();
1122     progs.CPP     = (XRCCTRL(*this, "txtCPPcompiler", wxTextCtrl)->GetValue()).Trim();
1123     progs.LD      = (XRCCTRL(*this, "txtLinker",      wxTextCtrl)->GetValue()).Trim();
1124     progs.LIB     = (XRCCTRL(*this, "txtLibLinker",   wxTextCtrl)->GetValue()).Trim();
1125     progs.WINDRES = (XRCCTRL(*this, "txtResComp",     wxTextCtrl)->GetValue()).Trim();
1126     progs.MAKE    = (XRCCTRL(*this, "txtMake",        wxTextCtrl)->GetValue()).Trim();
1127     wxChoice *cmbDebugger = XRCCTRL(*this, "cmbDebugger", wxChoice);
1128     if (cmbDebugger)
1129     {
1130         int index = cmbDebugger->GetSelection();
1131         const DebuggerClientData* data = static_cast<const DebuggerClientData*>(cmbDebugger->GetClientObject(index));
1132         progs.DBGconfig = data->string;
1133     }
1134     compiler->SetPrograms(progs);
1135     compiler->SetMasterPath(masterPath);
1136     // and the extra paths
1137     wxListBox* control = XRCCTRL(*this, "lstExtraPaths", wxListBox);
1138     if (control)
1139     {
1140         // get all listBox entries in array String
1141         wxArrayString extraPaths;
1142         ListBox2ArrayString(extraPaths, control);
1143         compiler->SetExtraPaths(extraPaths);
1144     }
1145 } // DoSaveCompilerPrograms
1146 
DoSaveVars()1147 void CompilerOptionsDlg::DoSaveVars()
1148 {
1149     CompileOptionsBase* pBase = GetVarsOwner();
1150     if (pBase)
1151     {
1152         // let's process all the stored CustomVarActions
1153         for (unsigned int idxAction = 0; idxAction < m_CustomVarActions.size(); ++idxAction)
1154         {
1155             CustomVarAction Action = m_CustomVarActions[idxAction];
1156             switch(Action.m_Action)
1157             {
1158                 case CVA_Add:
1159                     pBase->SetVar(Action.m_Key, Action.m_KeyValue);
1160                     break;
1161                 case CVA_Edit:
1162                 {
1163                     // first split up the KeyValue
1164                     wxString NewKey = Action.m_KeyValue.BeforeFirst(_T('=')).Trim(true).Trim(false);
1165                     wxString NewValue = Action.m_KeyValue.AfterFirst(_T('=')).Trim(true).Trim(false);
1166                     if (Action.m_Key != NewKey)
1167                     {   // the key name changed
1168                         pBase->UnsetVar(Action.m_Key);
1169                     }
1170                     pBase->SetVar(NewKey, NewValue);
1171                     break;
1172                 }
1173                 case CVA_Remove:
1174                     pBase->UnsetVar(Action.m_Key);
1175                     break;
1176                 default:
1177                     break;
1178             } // end switch
1179         } // end for : idx : idxAction
1180         m_CustomVarActions.clear();
1181     }
1182 } // DoSaveVars
1183 
DoSaveCompilerDefinition()1184 void CompilerOptionsDlg::DoSaveCompilerDefinition()
1185 {
1186     wxXmlNode* root = new wxXmlNode(wxXML_ELEMENT_NODE, wxT("CodeBlocks_compiler_options"));
1187     Compiler* compiler = CompilerFactory::GetCompiler(m_CurrentCompilerIdx);
1188     const wxString name = wxT("name");
1189     const wxString value = wxT("value");
1190     wxXmlNode* node = new wxXmlNode(root, wxXML_ELEMENT_NODE, wxT("Program"));
1191     node->AddAttribute(name, wxT("C"));
1192     node->AddAttribute(value, compiler->GetPrograms().C);
1193     node->SetNext(new wxXmlNode(wxXML_ELEMENT_NODE, wxT("Program")));
1194     node = node->GetNext();
1195     node->AddAttribute(name, wxT("CPP"));
1196     node->AddAttribute(value, compiler->GetPrograms().CPP);
1197     node->SetNext(new wxXmlNode(wxXML_ELEMENT_NODE, wxT("Program")));
1198     node = node->GetNext();
1199     node->AddAttribute(name, wxT("LD"));
1200     node->AddAttribute(value, compiler->GetPrograms().LD);
1201     node->SetNext(new wxXmlNode(wxXML_ELEMENT_NODE, wxT("Program")));
1202     node = node->GetNext();
1203     node->AddAttribute(name, wxT("DBGconfig"));
1204     node->AddAttribute(value, compiler->GetPrograms().DBGconfig);
1205     node->SetNext(new wxXmlNode(wxXML_ELEMENT_NODE, wxT("Program")));
1206     node = node->GetNext();
1207     node->AddAttribute(name, wxT("LIB"));
1208     node->AddAttribute(value, compiler->GetPrograms().LIB);
1209     node->SetNext(new wxXmlNode(wxXML_ELEMENT_NODE, wxT("Program")));
1210     node = node->GetNext();
1211     node->AddAttribute(name, wxT("WINDRES"));
1212     node->AddAttribute(value, compiler->GetPrograms().WINDRES);
1213     node->SetNext(new wxXmlNode(wxXML_ELEMENT_NODE, wxT("Program")));
1214     node = node->GetNext();
1215     node->AddAttribute(name, wxT("MAKE"));
1216     node->AddAttribute(value, compiler->GetPrograms().MAKE);
1217 
1218 
1219     node->SetNext(new wxXmlNode(wxXML_ELEMENT_NODE, wxT("Switch")));
1220     node = node->GetNext();
1221     node->AddAttribute(name, wxT("includeDirs"));
1222     node->AddAttribute(value, compiler->GetSwitches().includeDirs);
1223     node->SetNext(new wxXmlNode(wxXML_ELEMENT_NODE, wxT("Switch")));
1224     node = node->GetNext();
1225     node->AddAttribute(name, wxT("libDirs"));
1226     node->AddAttribute(value, compiler->GetSwitches().libDirs);
1227     node->SetNext(new wxXmlNode(wxXML_ELEMENT_NODE, wxT("Switch")));
1228     node = node->GetNext();
1229     node->AddAttribute(name, wxT("linkLibs"));
1230     node->AddAttribute(value, compiler->GetSwitches().linkLibs);
1231     node->SetNext(new wxXmlNode(wxXML_ELEMENT_NODE, wxT("Switch")));
1232     node = node->GetNext();
1233     node->AddAttribute(name, wxT("defines"));
1234     node->AddAttribute(value, compiler->GetSwitches().defines);
1235     node->SetNext(new wxXmlNode(wxXML_ELEMENT_NODE, wxT("Switch")));
1236     node = node->GetNext();
1237     node->AddAttribute(name, wxT("genericSwitch"));
1238     node->AddAttribute(value, compiler->GetSwitches().genericSwitch);
1239     node->SetNext(new wxXmlNode(wxXML_ELEMENT_NODE, wxT("Switch")));
1240     node = node->GetNext();
1241     node->AddAttribute(name, wxT("objectExtension"));
1242     node->AddAttribute(value, compiler->GetSwitches().objectExtension);
1243     node->SetNext(new wxXmlNode(wxXML_ELEMENT_NODE, wxT("Switch")));
1244     node = node->GetNext();
1245     node->AddAttribute(name, wxT("forceFwdSlashes"));
1246     node->AddAttribute(value, (compiler->GetSwitches().forceFwdSlashes ? wxT("true") : wxT("false")));
1247     node->SetNext(new wxXmlNode(wxXML_ELEMENT_NODE, wxT("Switch")));
1248     node = node->GetNext();
1249     node->AddAttribute(name, wxT("forceLinkerUseQuotes"));
1250     node->AddAttribute(value, (compiler->GetSwitches().forceLinkerUseQuotes ? wxT("true") : wxT("false")));
1251     node->SetNext(new wxXmlNode(wxXML_ELEMENT_NODE, wxT("Switch")));
1252     node = node->GetNext();
1253     node->AddAttribute(name, wxT("forceCompilerUseQuotes"));
1254     node->AddAttribute(value, (compiler->GetSwitches().forceCompilerUseQuotes ? wxT("true") : wxT("false")));
1255     node->SetNext(new wxXmlNode(wxXML_ELEMENT_NODE, wxT("Switch")));
1256     node = node->GetNext();
1257     node->AddAttribute(name, wxT("needDependencies"));
1258     node->AddAttribute(value, (compiler->GetSwitches().needDependencies ? wxT("true") : wxT("false")));
1259     node->SetNext(new wxXmlNode(wxXML_ELEMENT_NODE, wxT("Switch")));
1260     node = node->GetNext();
1261     node->AddAttribute(name, wxT("logging"));
1262     if (compiler->GetSwitches().logging == CompilerSwitches::defaultLogging)
1263         node->AddAttribute(value, wxT("default"));
1264     else if (compiler->GetSwitches().logging == clogFull)
1265         node->AddAttribute(value, wxT("full"));
1266     else if (compiler->GetSwitches().logging == clogSimple)
1267         node->AddAttribute(value, wxT("simple"));
1268     else if (compiler->GetSwitches().logging == clogNone)
1269         node->AddAttribute(value, wxT("none"));
1270     node->SetNext(new wxXmlNode(wxXML_ELEMENT_NODE, wxT("Switch")));
1271     node = node->GetNext();
1272     node->AddAttribute(name, wxT("libPrefix"));
1273     node->AddAttribute(value, compiler->GetSwitches().libPrefix);
1274     node->SetNext(new wxXmlNode(wxXML_ELEMENT_NODE, wxT("Switch")));
1275     node = node->GetNext();
1276     node->AddAttribute(name, wxT("libExtension"));
1277     node->AddAttribute(value, compiler->GetSwitches().libExtension);
1278     node->SetNext(new wxXmlNode(wxXML_ELEMENT_NODE, wxT("Switch")));
1279     node = node->GetNext();
1280     node->AddAttribute(name, wxT("linkerNeedsLibPrefix"));
1281     node->AddAttribute(value, (compiler->GetSwitches().linkerNeedsLibPrefix ? wxT("true") : wxT("false")));
1282     node->SetNext(new wxXmlNode(wxXML_ELEMENT_NODE, wxT("Switch")));
1283     node = node->GetNext();
1284     node->AddAttribute(name, wxT("linkerNeedsLibExtension"));
1285     node->AddAttribute(value, (compiler->GetSwitches().linkerNeedsLibExtension ? wxT("true") : wxT("false")));
1286     node->SetNext(new wxXmlNode(wxXML_ELEMENT_NODE, wxT("Switch")));
1287     node = node->GetNext();
1288     node->AddAttribute(name, wxT("linkerNeedsPathResolved"));
1289     node->AddAttribute(value, (compiler->GetSwitches().linkerNeedsPathResolved ? wxT("true") : wxT("false")));
1290     node->SetNext(new wxXmlNode(wxXML_ELEMENT_NODE, wxT("Switch")));
1291     node = node->GetNext();
1292     node->AddAttribute(name, wxT("supportsPCH"));
1293     node->AddAttribute(value, (compiler->GetSwitches().supportsPCH ? wxT("true") : wxT("false")));
1294     node->SetNext(new wxXmlNode(wxXML_ELEMENT_NODE, wxT("Switch")));
1295     node = node->GetNext();
1296     node->AddAttribute(name, wxT("PCHExtension"));
1297     node->AddAttribute(value, compiler->GetSwitches().PCHExtension);
1298     node->SetNext(new wxXmlNode(wxXML_ELEMENT_NODE, wxT("Switch")));
1299     node = node->GetNext();
1300     node->AddAttribute(name, wxT("UseFlatObjects"));
1301     node->AddAttribute(value, (compiler->GetSwitches().UseFlatObjects ? wxT("true") : wxT("false")));
1302     node->SetNext(new wxXmlNode(wxXML_ELEMENT_NODE, wxT("Switch")));
1303     node = node->GetNext();
1304     node->AddAttribute(name, wxT("UseFullSourcePaths"));
1305     node->AddAttribute(value, (compiler->GetSwitches().UseFullSourcePaths ? wxT("true") : wxT("false")));
1306     node->SetNext(new wxXmlNode(wxXML_ELEMENT_NODE, wxT("Switch")));
1307     node = node->GetNext();
1308     node->AddAttribute(name, wxT("includeDirSeparator"));
1309     node->AddAttribute(value, compiler->GetSwitches().includeDirSeparator);
1310     node->SetNext(new wxXmlNode(wxXML_ELEMENT_NODE, wxT("Switch")));
1311     node = node->GetNext();
1312     node->AddAttribute(name, wxT("libDirSeparator"));
1313     node->AddAttribute(value, compiler->GetSwitches().libDirSeparator);
1314     node->SetNext(new wxXmlNode(wxXML_ELEMENT_NODE, wxT("Switch")));
1315     node = node->GetNext();
1316     node->AddAttribute(name, wxT("objectSeparator"));
1317     node->AddAttribute(value, compiler->GetSwitches().objectSeparator);
1318     node->SetNext(new wxXmlNode(wxXML_ELEMENT_NODE, wxT("Switch")));
1319     node = node->GetNext();
1320     node->AddAttribute(name, wxT("statusSuccess"));
1321     node->AddAttribute(value, wxString::Format(wxT("%d"), compiler->GetSwitches().statusSuccess));
1322     node->SetNext(new wxXmlNode(wxXML_ELEMENT_NODE, wxT("Switch")));
1323     node = node->GetNext();
1324     node->AddAttribute(name, wxT("Use83Paths"));
1325     node->AddAttribute(value, (compiler->GetSwitches().Use83Paths ? wxT("true") : wxT("false")));
1326 
1327     for (size_t i = 0; i < m_Options.GetCount(); ++i)
1328     {
1329         CompOption* opt = m_Options.GetOption(i);
1330         node->SetNext(new wxXmlNode(wxXML_ELEMENT_NODE, wxT("Option")));
1331         node = node->GetNext();
1332         wxString oName;
1333         opt->name.EndsWith(wxT("[") + opt->option + wxT("]"), &oName);
1334         if (oName == wxEmptyString)
1335             opt->name.EndsWith(wxT("[") + opt->additionalLibs + wxT("]"), &oName);
1336         if (oName == wxEmptyString)
1337             oName = opt->name;
1338         node->AddAttribute(name, oName.Trim());
1339         if (opt->option != wxEmptyString)
1340             node->AddAttribute(wxT("option"), opt->option);
1341         if (opt->category != wxT("General"))
1342             node->AddAttribute(wxT("category"), opt->category);
1343         if (opt->additionalLibs != wxEmptyString)
1344             node->AddAttribute(wxT("additionalLibs"), opt->additionalLibs);
1345         if (opt->checkAgainst != wxEmptyString)
1346         {
1347             node->AddAttribute(wxT("checkAgainst"), opt->checkAgainst);
1348             node->AddAttribute(wxT("checkMessage"), opt->checkMessage);
1349         }
1350         if (opt->supersedes != wxEmptyString)
1351             node->AddAttribute(wxT("supersedes"), opt->supersedes);
1352         if (opt->exclusive)
1353             node->AddAttribute(wxT("exclusive"), wxT("true"));
1354     }
1355 
1356     for (int i = 0; i < ctCount; ++i)
1357     {
1358         const CompilerToolsVector& vec = compiler->GetCommandToolsVector((CommandType)i);
1359         wxString op;
1360         if (i == ctCompileObjectCmd)
1361             op = wxT("CompileObject");
1362         else if (i == ctGenDependenciesCmd)
1363             op = wxT("GenDependencies");
1364         else if (i == ctCompileResourceCmd)
1365             op = wxT("CompileResource");
1366         else if (i == ctLinkExeCmd)
1367             op = wxT("LinkExe");
1368         else if (i == ctLinkConsoleExeCmd)
1369             op = wxT("LinkConsoleExe");
1370         else if (i == ctLinkDynamicCmd)
1371             op = wxT("LinkDynamic");
1372         else if (i == ctLinkStaticCmd)
1373             op = wxT("LinkStatic");
1374         else if (i == ctLinkNativeCmd)
1375             op = wxT("LinkNative");
1376         for (size_t j = 0; j < vec.size(); ++j)
1377         {
1378             node->SetNext(new wxXmlNode(wxXML_ELEMENT_NODE, wxT("Command")));
1379             node = node->GetNext();
1380             node->AddAttribute(name, op);
1381             node->AddAttribute(value, vec[j].command);
1382             if (!vec[j].extensions.IsEmpty())
1383                 node->AddAttribute(wxT("ext"), GetStringFromArray(vec[j].extensions, DEFAULT_ARRAY_SEP, false));
1384             if (!vec[j].generatedFiles.IsEmpty())
1385                 node->AddAttribute(wxT("gen"), GetStringFromArray(vec[j].generatedFiles, DEFAULT_ARRAY_SEP, false));
1386         }
1387     }
1388 
1389     const RegExArray& regexes = compiler->GetRegExArray();
1390     for (size_t i = 0; i < regexes.size(); ++i)
1391     {
1392         node->SetNext(new wxXmlNode(wxXML_ELEMENT_NODE, wxT("RegEx")));
1393         node = node->GetNext();
1394         node->AddAttribute(name, regexes[i].desc);
1395         wxString tp;
1396         if (regexes[i].lt == cltNormal)
1397             tp = wxT("normal");
1398         else if (regexes[i].lt == cltWarning)
1399             tp = wxT("warning");
1400         else if (regexes[i].lt == cltError)
1401             tp = wxT("error");
1402         else if (regexes[i].lt == cltInfo)
1403             tp = wxT("info");
1404         node->AddAttribute(wxT("type"), tp);
1405         tp = wxString::Format(wxT("%d;%d;%d"), regexes[i].msg[0], regexes[i].msg[1], regexes[i].msg[2]);
1406         tp.Replace(wxT(";0"), wxEmptyString);
1407         node->AddAttribute(wxT("msg"), tp);
1408         if (regexes[i].filename != 0)
1409             node->AddAttribute(wxT("file"), wxString::Format(wxT("%d"), regexes[i].filename));
1410         if (regexes[i].line != 0)
1411             node->AddAttribute(wxT("line"), wxString::Format(wxT("%d"), regexes[i].line));
1412         tp = regexes[i].GetRegExString();
1413         tp.Replace(wxT("\t"), wxT("\\t"));
1414         node->AddChild(new wxXmlNode(wxXML_CDATA_SECTION_NODE, wxEmptyString, tp));
1415     }
1416 
1417     if (!compiler->GetCOnlyFlags().IsEmpty())
1418     {
1419         node->SetNext(new wxXmlNode(wxXML_ELEMENT_NODE, wxT("Sort")));
1420         node = node->GetNext();
1421         node->AddAttribute(wxT("CFlags"), compiler->GetCOnlyFlags());
1422     }
1423     if (!compiler->GetCPPOnlyFlags().IsEmpty())
1424     {
1425         node->SetNext(new wxXmlNode(wxXML_ELEMENT_NODE, wxT("Sort")));
1426         node = node->GetNext();
1427         node->AddAttribute(wxT("CPPFlags"), compiler->GetCPPOnlyFlags());
1428     }
1429 
1430     wxXmlDocument doc;
1431     doc.SetVersion(wxT("1.0"));
1432     doc.SetRoot(root);
1433     if (!wxDirExists(ConfigManager::GetFolder(sdDataUser) + wxT("/compilers")))
1434         wxMkdir(ConfigManager::GetFolder(sdDataUser) + wxT("/compilers"));
1435     doc.Save(ConfigManager::GetFolder(sdDataUser) + wxT("/compilers/options_") + compiler->GetID() + wxT(".xml"));
1436 
1437     // update the in-memory cache
1438     compiler->SetOptions(m_Options);
1439 } // DoSaveCompilerDefinition
1440 
1441 // events
1442 
OnDirty(cb_unused wxCommandEvent & event)1443 void CompilerOptionsDlg::OnDirty(cb_unused wxCommandEvent& event)
1444 {
1445     m_bDirty = true;
1446 } // OnDirty
1447 
ProjectTargetCompilerAdjust()1448 void CompilerOptionsDlg::ProjectTargetCompilerAdjust()
1449 {   // note this can also be called when on global compiler level, won't do anything (well reset a member which has
1450     // no use in this case)
1451     // check if the compilerID needs to be updated
1452     if (m_pTarget)
1453     { // target was the (tree) selection
1454         if (!m_NewProjectOrTargetCompilerId.IsEmpty() && m_pTarget->GetCompilerID() != m_NewProjectOrTargetCompilerId)
1455         {
1456             m_pTarget->SetCompilerID(m_NewProjectOrTargetCompilerId);
1457             cbMessageBox(_("You changed the compiler used for this target.\n"
1458                             "It is recommended that you fully rebuild this target, "
1459                             "otherwise linking errors might occur..."),
1460                             _("Notice"),
1461                             wxICON_EXCLAMATION);
1462         }
1463     }
1464     else if (m_pProject)
1465     {   // the project was the (tree) selection
1466         if (!m_NewProjectOrTargetCompilerId.IsEmpty() && m_pProject->GetCompilerID() != m_NewProjectOrTargetCompilerId)
1467         { // should be project then
1468             m_pProject->SetCompilerID(m_NewProjectOrTargetCompilerId);
1469             UpdateCompilerForTargets(m_CurrentCompilerIdx);
1470             cbMessageBox(_("You changed the compiler used for this project.\n"
1471                             "It is recommended that you fully rebuild this project, "
1472                             "otherwise linking errors might occur..."),
1473                             _("Notice"),
1474                             wxICON_EXCLAMATION);
1475         }
1476     }
1477     m_NewProjectOrTargetCompilerId = wxEmptyString;
1478 } // ProjectTargetCompilerAdjust
1479 
OnTreeSelectionChange(wxTreeEvent & event)1480 void CompilerOptionsDlg::OnTreeSelectionChange(wxTreeEvent& event)
1481 {
1482     if (m_BuildingTree)
1483         return;
1484     wxTreeCtrl* tc = XRCCTRL(*this, "tcScope", wxTreeCtrl);
1485     ScopeTreeData* data = (ScopeTreeData*)tc->GetItemData(event.GetItem());
1486     if (!data)
1487         return;
1488     int compilerIdx = data->GetTarget() ? CompilerFactory::GetCompilerIndex(data->GetTarget()->GetCompilerID()) :
1489                         (data->GetProject() ? CompilerFactory::GetCompilerIndex(data->GetProject()->GetCompilerID()) :
1490                         XRCCTRL(*this, "cmbCompiler", wxChoice)->GetSelection());
1491     // in order to support projects/targets which have an unknown "user compiler", that is on the current
1492     // system that compiler is not (or no longer) installed, we should check the compilerIdx, in such a case it will
1493     // be '-1' [NOTE : maybe to the check already on the Id ?]
1494     // we then allow the user to make a choice :
1495     // a) adjust to another compiler
1496     // b) leave that compiler --> no settings can be set then (done by disabling the notebook,
1497     // as a consequence might need to be re-enabled when another target/project is chosen in the tree)
1498     if (compilerIdx != -1)
1499     {
1500         wxNotebook* nb = XRCCTRL(*this, "nbMain", wxNotebook);
1501         XRCCTRL(*this, "cmbCompiler", wxChoice)->SetSelection(compilerIdx);
1502         // we don't update the compiler index yet, we leave that to CompilerChanged();
1503         m_pTarget = data->GetTarget();
1504         if (m_pTarget && !m_pTarget->SupportsCurrentPlatform())
1505         {
1506             if (nb)
1507                 nb->Disable();
1508         }
1509         else
1510         {
1511             if (nb)
1512             {
1513                 // enable/disable invalid pages for commands only target
1514                 const bool cmd = (m_pTarget && m_pTarget->GetTargetType() == ttCommandsOnly);
1515                 int pageOffset;
1516                 if (!m_pProject->IsMakefileCustom())
1517                 {
1518                     nb->GetPage(0)->Enable(!cmd); // Compiler settings
1519                     nb->GetPage(1)->Enable(!cmd); // Linker settings
1520                     nb->GetPage(2)->Enable(!cmd); // Search directories
1521                     pageOffset = 3;
1522                 }
1523                 else
1524                     pageOffset = 0;
1525                 nb->GetPage(pageOffset + 2)->Enable(!cmd); // "Make" commands
1526                 if (   cmd
1527                     && nb->GetSelection() != pageOffset   // Pre/post build steps
1528                     && nb->GetSelection() != pageOffset + 1 ) // Custom variables
1529                 {
1530                     nb->SetSelection(pageOffset);
1531                 }
1532 
1533                 nb->Enable();
1534             }
1535             // the new selection might have a different compiler settings and/or even a different compiler
1536             // load all those new settings
1537             m_CurrentCompilerIdx = compilerIdx;
1538             Compiler* compiler = CompilerFactory::GetCompiler(m_CurrentCompilerIdx);
1539             if (compiler)
1540                 m_Options = compiler->GetOptions();
1541             DoFillCompilerDependentSettings();
1542         }
1543     }
1544     else
1545     {
1546         m_pTarget = data->GetTarget();
1547         wxString CompilerId = m_pTarget?m_pTarget->GetCompilerID():data->GetProject()->GetCompilerID();
1548         wxString msg;
1549         msg.Printf(_("The defined compiler cannot be located (ID: %s).\n"
1550                     "Please choose the compiler you want to use instead and click \"OK\".\n"
1551                     "If you click \"Cancel\", the project/target will remain configured for that compiler and consequently can not be configured and will not be built."),
1552                     CompilerId.wx_str());
1553         Compiler* compiler = 0;
1554         if (m_pTarget && m_pTarget->SupportsCurrentPlatform())
1555             compiler = CompilerFactory::SelectCompilerUI(msg);
1556 
1557         if (compiler)
1558         {   // a new compiler was chosen, proceed as if the user manually selected another compiler
1559             // that means set the compiler selection list accordingly
1560             // and go directly to (On)CompilerChanged
1561             int NewCompilerIdx = CompilerFactory::GetCompilerIndex(compiler);
1562             XRCCTRL(*this, "cmbCompiler", wxChoice)->SetSelection(NewCompilerIdx);
1563             wxCommandEvent Dummy;
1564             OnCompilerChanged(Dummy);
1565         }
1566         else
1567         { // the user cancelled and wants to keep the compiler
1568             if (wxNotebook* nb = XRCCTRL(*this, "nbMain", wxNotebook))
1569                 nb->Disable();
1570         }
1571     }
1572 
1573     {
1574         const bool show = (m_pTarget != nullptr);
1575 
1576         // Hide linker executable because it doesn't make sense to change it in the project.
1577         wxChoice *cmbLinkerExe = XRCCTRL(*this, "chLinkerExe", wxChoice);
1578         cmbLinkerExe->Show(show);
1579         wxStaticText *txtLinkerExe = XRCCTRL(*this, "txtLinkerExe", wxStaticText);
1580         txtLinkerExe->Show(show);
1581     }
1582 } // OnTreeSelectionChange
1583 
OnTreeSelectionChanging(wxTreeEvent & event)1584 void CompilerOptionsDlg::OnTreeSelectionChanging(wxTreeEvent& event)
1585 {
1586     if (m_BuildingTree)
1587         return;
1588     wxTreeCtrl* tc = XRCCTRL(*this, "tcScope", wxTreeCtrl);
1589     ScopeTreeData* data = (ScopeTreeData*)tc->GetItemData(event.GetOldItem());
1590     if (data && (m_bDirty || m_bFlagsDirty))
1591     {   // data : should always be the case, since on global compiler level, there's no tree
1592         // when changes are made prompt the user if these changes should be applied
1593         // YES -> do the changes
1594         // NO -> no changes, just switch
1595         // CANCEL : don't switch
1596 
1597         AnnoyingDialog dlg(_("Project/Target change with changed settings"),
1598                     _("You have changed some settings. Do you want these settings saved ?\n\n"
1599                     "Yes    : will apply the changes\n"
1600                     "No     : will undo the changes\n"
1601                     "Cancel : will revert your selection in the project/target tree"),
1602                     wxART_QUESTION,
1603                     AnnoyingDialog::YES_NO_CANCEL);
1604 
1605         switch(dlg.ShowModal())
1606         {
1607             case AnnoyingDialog::rtYES :
1608                 DoSaveCompilerDependentSettings();
1609                 break;
1610             case AnnoyingDialog::rtCANCEL :
1611                 event.Veto();
1612                 break;
1613             case AnnoyingDialog::rtNO :
1614             default:
1615                 {
1616                     m_bDirty = false;
1617                     m_bFlagsDirty = false;
1618                 }
1619                 break;
1620         } // end switch
1621     }
1622 } // OnTreeSelectionChanging
1623 
OnCompilerChanged(cb_unused wxCommandEvent & event)1624 void CompilerOptionsDlg::OnCompilerChanged(cb_unused wxCommandEvent& event)
1625 {
1626     // when changes are made prompt the user if these changes should be applied
1627     // YES -> do the changes
1628     // NO -> no changes, just switch
1629     // CANCEL : don't switch
1630     bool bChanged = true;
1631     if (m_bDirty || m_bFlagsDirty)
1632     {
1633         switch(cbMessageBox(_("You have changed some settings. Do you want these settings saved ?\n\n"
1634                         "Yes    : will apply the changes\n"
1635                         "No     : will undo the changes\n"
1636                         "Cancel : will revert your compiler change."),
1637                         _("Compiler change with changed settings"),
1638                         wxICON_EXCLAMATION|wxYES|wxNO|wxCANCEL))
1639         {
1640             case wxID_CANCEL :
1641                 XRCCTRL(*this, "cmbCompiler", wxChoice)->SetSelection(m_CurrentCompilerIdx);
1642                 bChanged = false;
1643                 break;
1644             case wxID_YES :
1645                 DoSaveCompilerDependentSettings();
1646                 break;
1647             case wxID_NO :
1648             default:
1649                 m_bDirty = false;
1650                 m_bFlagsDirty = false;
1651                 break;
1652         } // end switch
1653     }
1654     if (bChanged)
1655     {
1656         CompilerChanged();
1657         if (m_pProject)
1658         {   // in case of project/target --> dirty
1659             m_bDirty = true;
1660         }
1661     }
1662 } // OnCompilerChanged
1663 
CompilerChanged()1664 void CompilerOptionsDlg::CompilerChanged()
1665 {
1666     m_CurrentCompilerIdx = XRCCTRL(*this, "cmbCompiler", wxChoice)->GetSelection();
1667     // in case we are not on the global level (== project/target) we need to remember this switch
1668     // so that on "SAVE" time we can adjust the project/target with it's new compiler
1669     // SAVE time for this particular setting means (Apply or TreeSelection change
1670     // not compiler change since we could (re)change the compiler of that project/target
1671     if (m_pProject)
1672     {
1673         m_NewProjectOrTargetCompilerId = CompilerFactory::GetCompiler(m_CurrentCompilerIdx)->GetID();
1674     }
1675     //load the new options (== options of the new selected compiler)
1676     Compiler* compiler = CompilerFactory::GetCompiler(m_CurrentCompilerIdx);
1677     if (compiler)
1678         m_Options = compiler->GetOptions();
1679     DoFillCompilerDependentSettings();
1680 } // CompilerChanged
1681 
UpdateCompilerForTargets(int compilerIdx)1682 void CompilerOptionsDlg::UpdateCompilerForTargets(int compilerIdx)
1683 {
1684     int ret = cbMessageBox(_("You have changed the compiler used for the project.\n"
1685                             "Do you want to use the same compiler for all the project's build targets too?"),
1686                             _("Question"),
1687                             wxICON_QUESTION | wxYES_NO);
1688     if (ret == wxID_YES)
1689     {
1690         for (int i = 0; i < m_pProject->GetBuildTargetsCount(); ++i)
1691         {
1692             ProjectBuildTarget* target = m_pProject->GetBuildTarget(i);
1693             Compiler* compiler = CompilerFactory::GetCompiler(compilerIdx);
1694             if (compiler)
1695                 target->SetCompilerID(compiler->GetID());
1696         }
1697     }
1698 } // UpdateCompilerForTargets
1699 
AutoDetectCompiler()1700 void CompilerOptionsDlg::AutoDetectCompiler()
1701 {
1702     Compiler* compiler = CompilerFactory::GetCompiler(m_CurrentCompilerIdx);
1703     if (!compiler)
1704         return;
1705 
1706     wxString backup = XRCCTRL(*this, "txtMasterPath", wxTextCtrl)->GetValue();
1707     wxArrayString ExtraPathsBackup = compiler->GetExtraPaths();
1708 
1709     wxArrayString empty;
1710     compiler->SetExtraPaths(empty);
1711 
1712     switch (compiler->AutoDetectInstallationDir())
1713     {
1714         case adrDetected:
1715         {
1716             wxString msg;
1717             msg.Printf(_("Auto-detected installation path of \"%s\"\nin \"%s\""), compiler->GetName().wx_str(), compiler->GetMasterPath().wx_str());
1718             cbMessageBox(msg);
1719         }
1720         break;
1721 
1722         case adrGuessed:
1723         {
1724             wxString msg;
1725             msg.Printf(_("Could not auto-detect installation path of \"%s\"...\n"
1726                         "Do you want to use this compiler's default installation directory?"),
1727                         compiler->GetName().wx_str());
1728             if (cbMessageBox(msg, _("Confirmation"), wxICON_QUESTION | wxYES_NO) == wxID_NO)
1729             {
1730                 compiler->SetMasterPath(backup);
1731                 compiler->SetExtraPaths(ExtraPathsBackup);
1732             }
1733         }
1734         break;
1735 
1736         default:
1737             break;
1738     }
1739     XRCCTRL(*this, "txtMasterPath", wxTextCtrl)->SetValue(compiler->GetMasterPath());
1740     XRCCTRL(*this, "lstExtraPaths", wxListBox)->Clear();
1741     const wxArrayString& extraPaths = CompilerFactory::GetCompiler(m_CurrentCompilerIdx)->GetExtraPaths();
1742        ArrayString2ListBox(extraPaths, XRCCTRL(*this, "lstExtraPaths", wxListBox));
1743     m_bDirty = true;
1744 } // AutoDetectCompiler
1745 
GetDirsListBox()1746 wxListBox* CompilerOptionsDlg::GetDirsListBox()
1747 {
1748     wxNotebook* nb = XRCCTRL(*this, "nbDirs", wxNotebook);
1749     if (!nb)
1750         return 0;
1751     switch (nb->GetSelection())
1752     {
1753         case 0: // compiler dirs
1754             return XRCCTRL(*this, "lstIncludeDirs", wxListBox);
1755         case 1: // linker dirs
1756             return XRCCTRL(*this, "lstLibDirs", wxListBox);
1757         case 2: // resource compiler dirs
1758             return XRCCTRL(*this, "lstResDirs", wxListBox);
1759         default: break;
1760     }
1761     return 0;
1762 } // GetDirsListBox
1763 
GetVarsOwner()1764 CompileOptionsBase* CompilerOptionsDlg::GetVarsOwner()
1765 {
1766     return m_pTarget ? m_pTarget
1767                      : (m_pProject ? m_pProject
1768                                    : (CompileOptionsBase*)(CompilerFactory::GetCompiler(m_CurrentCompilerIdx)));
1769 } // GetVarsOwner
1770 
OnCategoryChanged(cb_unused wxCommandEvent & event)1771 void CompilerOptionsDlg::OnCategoryChanged(cb_unused wxCommandEvent& event)
1772 {    // reshow the compiler options, but with different filter (category) applied
1773     DoFillOptions();
1774 } // OnCategoryChanged
1775 
OnOptionChanged(wxPropertyGridEvent & event)1776 void CompilerOptionsDlg::OnOptionChanged(wxPropertyGridEvent& event)
1777 {
1778     wxPGProperty* property = event.GetProperty();
1779     if (!property)
1780         return;
1781     // Make sure the property is bool. Other properties are ignored for now.
1782     if (!property->IsKindOf(CLASSINFO(wxBoolProperty)))
1783         return;
1784     CompOption* option = m_Options.GetOptionByName(property->GetLabel());
1785     wxVariant value = property->GetValue();
1786     if (value.IsNull() || !option)
1787         return;
1788     option->enabled = value.GetBool();
1789     if (option->enabled)
1790     {
1791         if (!option->checkAgainst.IsEmpty())
1792         {
1793             wxArrayString check = GetArrayFromString(option->checkAgainst, wxT(" "));
1794             for (size_t i = 0; i < check.Count(); ++i)
1795             {
1796                 CompOption* against = m_Options.GetOptionByOption(check[i]);
1797                 if (!against)
1798                     against = m_Options.GetOptionByAdditionalLibs(check[i]);
1799                 if (against && against->enabled)
1800                 {
1801                     wxString message = (option->checkMessage.IsEmpty() ?
1802                               wxT("\"") + option->name + _("\" conflicts with \"") + against->name + wxT("\".") :
1803                               option->checkMessage );
1804                     AnnoyingDialog dlg(_("Compiler options conflict"),
1805                                        message,
1806                                        wxART_INFORMATION,
1807                                        AnnoyingDialog::OK);
1808                     dlg.ShowModal();
1809                     break;
1810                 }
1811             }
1812         }
1813         if (option->supersedes != wxEmptyString)
1814         {
1815             wxArrayString supersede = GetArrayFromString(option->supersedes, wxT(" "));
1816             for (size_t i = 0; i < supersede.Count(); ++i)
1817             {
1818                 for (size_t j = 0; j < m_Options.GetCount(); ++j)
1819                 {
1820                     if (option != m_Options.GetOption(j) &&
1821                         (supersede[i] == m_Options.GetOption(j)->option ||
1822                          supersede[i] == m_Options.GetOption(j)->additionalLibs))
1823                     {
1824                         m_Options.GetOption(j)->enabled = false;
1825                     }
1826                 }
1827 
1828                 for (wxPropertyGridIterator it = m_FlagsPG->GetIterator(); !it.AtEnd(); ++it)
1829                 {
1830                     wxPGProperty* p = *it;
1831                     if (p->IsCategory() || p == property)
1832                         continue;
1833                     if (p->GetLabel().EndsWith(wxT("[") + supersede[i] + wxT("]")))
1834                         m_FlagsPG->SetPropertyValue(p, false);
1835                 }
1836             }
1837         }
1838         if (option->exclusive)
1839         {
1840             for (size_t i = 0; i < m_Options.GetCount(); ++i)
1841             {
1842                 if (option != m_Options.GetOption(i) &&
1843                     option->category == m_Options.GetOption(i)->category)
1844                 {
1845                     m_Options.GetOption(i)->enabled = false;
1846                 }
1847             }
1848             for (wxPropertyGridIterator it = m_FlagsPG->GetIterator(); !it.AtEnd(); ++it)
1849             {
1850                 wxPGProperty* p = *it;
1851                 if (p->IsCategory() || p == property)
1852                     continue;
1853                 CompOption* opt = m_Options.GetOptionByName(p->GetLabel());
1854                 if (option != opt && option->category == opt->category)
1855                     m_FlagsPG->SetPropertyValue(p, false);
1856             }
1857         }
1858     }
1859     m_bDirty = true;
1860 }
1861 
1862 // some handlers for adding/editing/removing/clearing of include/libraries/resources directories
OnAddDirClick(cb_unused wxCommandEvent & event)1863 void CompilerOptionsDlg::OnAddDirClick(cb_unused wxCommandEvent& event)
1864 {
1865     EditPathDlg dlg(this,
1866             m_pProject ? m_pProject->GetBasePath() : _T(""),
1867             m_pProject ? m_pProject->GetBasePath() : _T(""),
1868             _("Add directory"));
1869 
1870     PlaceWindow(&dlg);
1871     if (dlg.ShowModal() == wxID_OK)
1872     {
1873         wxString path = dlg.GetPath();
1874 
1875         wxListBox* control = GetDirsListBox();
1876         if (control)
1877         {
1878             control->Append(path);
1879             m_bDirty = true;
1880         }
1881     }
1882 } // OnAddDirClick
1883 
OnEditDirClick(cb_unused wxCommandEvent & event)1884 void CompilerOptionsDlg::OnEditDirClick(cb_unused wxCommandEvent& event)
1885 {
1886     wxListBox* control = GetDirsListBox();
1887     wxArrayInt selections;
1888     if (!control || control->GetSelections(selections) < 1)
1889         return;
1890 
1891     if (selections.GetCount()>1)
1892     {
1893         cbMessageBox(_("Please select only one directory you would like to edit."),
1894                     _("Error"), wxICON_ERROR);
1895         return;
1896     }
1897 
1898     EditPathDlg dlg(this,
1899                     control->GetString(selections[0]),
1900                     m_pProject ? m_pProject->GetBasePath() : _T(""),
1901                     _("Edit directory"));
1902 
1903     PlaceWindow(&dlg);
1904     if (dlg.ShowModal() == wxID_OK)
1905     {
1906         wxString path = dlg.GetPath();
1907         control->SetString(selections[0], path);
1908         m_bDirty = true;
1909     }
1910 } // OnEditDirClick
1911 
OnRemoveDirClick(cb_unused wxCommandEvent & event)1912 void CompilerOptionsDlg::OnRemoveDirClick(cb_unused wxCommandEvent& event)
1913 {
1914     wxListBox* control = GetDirsListBox();
1915     wxArrayInt selections;
1916     if (!control || control->GetSelections(selections) < 1)
1917         return;
1918 
1919     if (cbMessageBox(_("Remove selected folders from the list?"),
1920                      _("Confirmation"),
1921                      wxOK | wxCANCEL | wxICON_QUESTION) == wxID_OK)
1922     {
1923         std::sort(selections.begin(), selections.end());
1924         for (unsigned int i=selections.GetCount(); i>0; --i)
1925             control->Delete(selections[i-1]);
1926         m_bDirty = true;
1927     }
1928 } // OnRemoveDirClick
1929 
OnClearDirClick(cb_unused wxCommandEvent & event)1930 void CompilerOptionsDlg::OnClearDirClick(cb_unused wxCommandEvent& event)
1931 {
1932     wxListBox* control = GetDirsListBox();
1933     if (!control || control->GetCount() == 0)
1934         return;
1935 
1936     if (cbMessageBox(_("Remove all directories from the list?"),
1937                      _("Confirmation"),
1938                      wxOK | wxCANCEL | wxICON_QUESTION) == wxID_OK)
1939     {
1940         control->Clear();
1941         m_bDirty = true;
1942     }
1943 } // OnClearDirClick
1944 
OnCopyDirsClick(cb_unused wxCommandEvent & event)1945 void CompilerOptionsDlg::OnCopyDirsClick(cb_unused wxCommandEvent& event)
1946 {
1947     if (!m_pProject)
1948         return;
1949 
1950     wxListBox* control = GetDirsListBox();
1951     wxArrayInt selections;
1952     if (!control || control->GetSelections(selections) < 1)
1953         return;
1954 
1955     wxArrayString choices;
1956     choices.Add(m_pProject->GetTitle());
1957     for (int i = 0; i < m_pProject->GetBuildTargetsCount(); ++i)
1958     {
1959         ProjectBuildTarget* bt = m_pProject->GetBuildTarget(i);
1960         choices.Add(bt->GetTitle());
1961     }
1962 
1963     const wxArrayInt &sel = cbGetMultiChoiceDialog(_("Please select which target to copy these directories to:"),
1964                                                    _("Copy directories"), choices, this);
1965     if (sel.empty())
1966         return;
1967 
1968     wxNotebook* nb = XRCCTRL(*this, "nbDirs", wxNotebook);
1969     int notebookPage = nb->GetSelection();
1970 
1971     for (wxArrayInt::const_iterator itr = sel.begin(); itr != sel.end(); ++itr)
1972     {
1973         CompileOptionsBase* base;
1974         if((*itr) == 0)
1975             base = m_pProject; // "copy to project"
1976         else
1977             base = m_pProject->GetBuildTarget((*itr) - 1);
1978 
1979         if (!base)
1980         {
1981             Manager::Get()->GetLogManager()->LogWarning(_T("Could not get build target in CompilerOptionsDlg::OnCopyLibsClick"));
1982             continue;
1983         }
1984 
1985         for (size_t i = 0; i < selections.GetCount(); ++i)
1986         {
1987             switch (notebookPage)
1988             {
1989                 case 0: // compiler dirs
1990                     base->AddIncludeDir(control->GetString(selections[i]));
1991                     break;
1992                 case 1: // linker dirs
1993                     base->AddLibDir(control->GetString(selections[i]));
1994                     break;
1995                 case 2: // resource compiler dirs
1996                     base->AddResourceIncludeDir(control->GetString(selections[i]));
1997                     break;
1998                 default:
1999                     break;
2000             }
2001         }
2002     }
2003 } // OnCopyDirsClick
2004 
QuoteString(wxString & value,const wxString & caption)2005 static void QuoteString(wxString &value, const wxString &caption)
2006 {
2007     if (NeedQuotes(value))
2008     {
2009         AnnoyingDialog dlgQuestion(caption, wxT("Variable quote string"),
2010                                    _("The value contains spaces or strange characters. Do you want to quote it?"),
2011                                    wxART_QUESTION, AnnoyingDialog::YES_NO, AnnoyingDialog::rtSAVE_CHOICE,
2012                                    _("&Quote"), _("&Leave unquoted"));
2013         if (dlgQuestion.ShowModal() == AnnoyingDialog::rtYES)
2014             ::QuoteStringIfNeeded(value);
2015     }
2016 }
2017 
OnAddVarClick(cb_unused wxCommandEvent & event)2018 void CompilerOptionsDlg::OnAddVarClick(cb_unused wxCommandEvent& event)
2019 {
2020     wxString key;
2021     wxString value;
2022     EditPairDlg dlg(this, key, value, _("Add new variable"), EditPairDlg::bmBrowseForDirectory);
2023     PlaceWindow(&dlg);
2024     if (dlg.ShowModal() == wxID_OK)
2025     {
2026         key.Trim(true).Trim(false);
2027         value.Trim(true).Trim(false);
2028         QuoteString(value, _("Add variable quote string"));
2029         CustomVarAction Action = {CVA_Add, key, value};
2030         m_CustomVarActions.push_back(Action);
2031         XRCCTRL(*this, "lstVars", wxListBox)->Append(key + _T(" = ") + value, new VariableListClientData(key, value));
2032         m_bDirty = true;
2033     }
2034 } // OnAddVarClick
2035 
OnEditVarClick(cb_unused wxCommandEvent & event)2036 void CompilerOptionsDlg::OnEditVarClick(cb_unused wxCommandEvent& event)
2037 {
2038     wxListBox *list = XRCCTRL(*this, "lstVars", wxListBox);
2039     int sel = list->GetSelection();
2040     if (sel == -1)
2041         return;
2042 
2043     VariableListClientData *data = static_cast<VariableListClientData*>(list->GetClientObject(sel));
2044     wxString key = data->key;
2045     wxString value = data->value;
2046 
2047     EditPairDlg dlg(this, key, value, _("Edit variable"), EditPairDlg::bmBrowseForDirectory);
2048     PlaceWindow(&dlg);
2049     if (dlg.ShowModal() == wxID_OK)
2050     {
2051         key.Trim(true).Trim(false);
2052         value.Trim(true).Trim(false);
2053         QuoteString(value, _("Edit variable quote string"));
2054 
2055         if (value != data->value  ||  key != data->key)
2056         { // something has changed
2057             CustomVarAction Action = {CVA_Edit, data->key, key + _T(" = ") + value};
2058             m_CustomVarActions.push_back(Action);
2059             list->SetString(sel, key + _T(" = ") + value);
2060             data->key = key;
2061             data->value = value;
2062             m_bDirty = true;
2063         }
2064     }
2065 } // OnEditVarClick
2066 
OnRemoveVarClick(cb_unused wxCommandEvent & event)2067 void CompilerOptionsDlg::OnRemoveVarClick(cb_unused wxCommandEvent& event)
2068 {
2069     wxListBox *list = XRCCTRL(*this, "lstVars", wxListBox);
2070     int sel = list->GetSelection();
2071     if (sel == -1)
2072         return;
2073     const wxString &key = static_cast<VariableListClientData*>(list->GetClientObject(sel))->key;
2074     if (key.IsEmpty())
2075         return;
2076 
2077     if (cbMessageBox(_("Are you sure you want to delete this variable?"),
2078                     _("Confirmation"),
2079                     wxYES_NO | wxICON_QUESTION) == wxID_YES)
2080     {
2081         CustomVarAction Action = {CVA_Remove, key, wxEmptyString};
2082         m_CustomVarActions.push_back(Action);
2083         list->Delete(sel);
2084         m_bDirty = true;
2085     }
2086 } // OnRemoveVarClick
2087 
OnClearVarClick(cb_unused wxCommandEvent & event)2088 void CompilerOptionsDlg::OnClearVarClick(cb_unused wxCommandEvent& event)
2089 {
2090     wxListBox* lstVars = XRCCTRL(*this, "lstVars", wxListBox);
2091     if (lstVars->IsEmpty())
2092         return;
2093 
2094     if (cbMessageBox(_("Are you sure you want to clear all variables?"),
2095                         _("Confirmation"),
2096                         wxYES | wxNO | wxICON_QUESTION) == wxID_YES)
2097     {
2098         // Unset all variables of lstVars
2099         for (size_t i=0; i < lstVars->GetCount(); ++i)
2100         {
2101             const wxString &key = static_cast<VariableListClientData*>(lstVars->GetClientObject(i))->key;
2102             if (!key.IsEmpty())
2103             {
2104                 CustomVarAction Action = {CVA_Remove, key, wxEmptyString};
2105                 m_CustomVarActions.push_back(Action);
2106             }
2107         }
2108         lstVars->Clear();
2109         m_bDirty = true;
2110     }
2111 } // OnClearVarClick
2112 
OnSetDefaultCompilerClick(cb_unused wxCommandEvent & event)2113 void CompilerOptionsDlg::OnSetDefaultCompilerClick(cb_unused wxCommandEvent& event)
2114 {
2115     wxChoice* cmb = XRCCTRL(*this, "cmbCompiler", wxChoice);
2116     int idx = cmb->GetSelection();
2117     CompilerFactory::SetDefaultCompiler(idx);
2118     wxString msg;
2119     Compiler* compiler = CompilerFactory::GetDefaultCompiler();
2120     #if wxCHECK_VERSION(3, 0, 0)
2121     msg.Printf(_("%s is now selected as the default compiler for new projects"), compiler ? compiler->GetName().wx_str() : _("[invalid]").wx_str());
2122     #else
2123     msg.Printf(_("%s is now selected as the default compiler for new projects"), compiler ? compiler->GetName().c_str() : _("[invalid]"));
2124     #endif
2125     cbMessageBox(msg);
2126 } // OnSetDefaultCompilerClick
2127 
OnAddCompilerClick(cb_unused wxCommandEvent & event)2128 void CompilerOptionsDlg::OnAddCompilerClick(cb_unused wxCommandEvent& event)
2129 {
2130     if (m_bDirty)
2131     {   // changes had been made to the current selected compiler
2132         switch(cbMessageBox(_("You have changed some settings. Do you want these settings saved ?\n\n"
2133                         "Yes    : will apply the changes\n"
2134                         "No     : will undo the changes\n"
2135                         "Cancel : will cancel your compiler addition."),
2136                         _("Compiler change with changed settings"),
2137                         wxICON_EXCLAMATION|wxYES|wxNO|wxCANCEL))
2138         {
2139             case wxID_CANCEL :
2140                 return;
2141                 break;
2142             case wxID_YES :
2143                 DoSaveCompilerDependentSettings();
2144                 break;
2145             case wxID_NO :
2146             default:
2147                 // we don't clear the dirty flag yet (in case something goes wrong with the compiler copy we need to reload the
2148                 // 'selected compiler' options omitting the current 'No'-ed changes
2149                 break;
2150         } // end switch
2151     }
2152     wxChoice* cmb = 0;
2153     cmb = XRCCTRL(*this, "cmbCompiler", wxChoice);
2154     wxString value = cbGetTextFromUser(_("Please enter the new compiler's name:"),
2155                                     _("Add new compiler"),
2156                                     _("Copy of ") + CompilerFactory::GetCompiler(m_CurrentCompilerIdx)->GetName());
2157     if (!value.IsEmpty())
2158     {
2159         // make a copy of current compiler
2160         Compiler* newC = 0;
2161         try
2162         {
2163             newC = CompilerFactory::CreateCompilerCopy(CompilerFactory::GetCompiler(m_CurrentCompilerIdx), value);
2164         }
2165         catch (cbException& e)
2166         {
2167             // usually throws because of non-unique ID
2168             e.ShowErrorMessage(false);
2169             newC = 0; // just to be sure
2170         }
2171 
2172         if (!newC)
2173         {
2174             cbMessageBox(_("The new compiler could not be created.\n(maybe a compiler with the same name already exists?)"),
2175                         _("Error"), wxICON_ERROR);
2176             return;
2177         }
2178         else
2179         {
2180             m_CurrentCompilerIdx = CompilerFactory::GetCompilerIndex(newC);
2181 
2182             cmb->Append(value);
2183             cmb->SetSelection(cmb->GetCount() - 1);
2184             // refresh settings in dialog
2185             DoFillCompilerDependentSettings();
2186             cbMessageBox(_("The new compiler has been added! Don't forget to update the \"Toolchain executables\" page..."));
2187         }
2188     }
2189     if (m_bDirty)
2190     {   // something went wrong -> reload current settings omitting the NO-ed changes
2191         m_bDirty = false;
2192         CompilerChanged();
2193     }
2194 } // OnAddCompilerClick
2195 
OnEditCompilerClick(cb_unused wxCommandEvent & event)2196 void CompilerOptionsDlg::OnEditCompilerClick(cb_unused wxCommandEvent& event)
2197 {
2198     wxChoice* cmb = XRCCTRL(*this, "cmbCompiler", wxChoice);
2199     wxString value = cbGetTextFromUser(_("Please edit the compiler's name:"), _("Rename compiler"), cmb->GetStringSelection());
2200     if (!value.IsEmpty())
2201     {
2202         Compiler* compiler = CompilerFactory::GetCompiler(m_CurrentCompilerIdx);
2203         if (compiler)
2204             compiler->SetName(value);
2205         cmb->SetString(m_CurrentCompilerIdx, value);
2206         cmb->SetSelection(m_CurrentCompilerIdx);
2207     }
2208 } // OnEditCompilerClick
2209 
OnRemoveCompilerClick(cb_unused wxCommandEvent & event)2210 void CompilerOptionsDlg::OnRemoveCompilerClick(cb_unused wxCommandEvent& event)
2211 {
2212     if (cbMessageBox(_("Are you sure you want to remove this compiler?"),
2213                     _("Confirmation"),
2214                     wxYES | wxNO| wxICON_QUESTION | wxNO_DEFAULT) == wxID_YES)
2215     {
2216         wxChoice* cmb = XRCCTRL(*this, "cmbCompiler", wxChoice);
2217         int compilerIdx = m_CurrentCompilerIdx;
2218         CompilerFactory::RemoveCompiler(CompilerFactory::GetCompiler(compilerIdx));
2219         cmb->Delete(compilerIdx);
2220         while (compilerIdx >= (int)(cmb->GetCount()))
2221             --compilerIdx;
2222         cmb->SetSelection(compilerIdx);
2223         m_CurrentCompilerIdx = compilerIdx;
2224         DoFillCompilerDependentSettings();
2225     }
2226 } // OnRemoveCompilerClick
2227 
OnResetCompilerClick(cb_unused wxCommandEvent & event)2228 void CompilerOptionsDlg::OnResetCompilerClick(cb_unused wxCommandEvent& event)
2229 {
2230     if (cbMessageBox(_("Reset this compiler's settings to the defaults?"),
2231                     _("Confirmation"),
2232                     wxYES | wxNO| wxICON_QUESTION | wxNO_DEFAULT) == wxID_YES)
2233     if (cbMessageBox(_("Reset this compiler's settings to the defaults?\n"
2234                        "\nAre you REALLY sure?"),
2235                     _("Confirmation"),
2236                     wxYES | wxNO| wxICON_QUESTION | wxNO_DEFAULT) == wxID_YES)
2237     {
2238         Compiler* compiler = CompilerFactory::GetCompiler(m_CurrentCompilerIdx);
2239         if (compiler)
2240         {
2241             const wxString file = wxT("/compilers/options_") + compiler->GetID() + wxT(".xml");
2242             if (   wxFileExists(ConfigManager::GetDataFolder(true) + file)
2243                 && wxFileExists(ConfigManager::GetDataFolder(false) + file) )
2244             {
2245                 wxRemoveFile(ConfigManager::GetDataFolder(false) + file);
2246             }
2247             compiler->Reset();
2248         }
2249         // run auto-detection
2250         AutoDetectCompiler();
2251         CompilerFactory::SaveSettings();
2252         // refresh settings in dialog
2253         DoFillCompilerDependentSettings();
2254     }
2255 } // OnResetCompilerClick
2256 
2257 // 4 handlers for the adding/editing/removing/clearing of Linker Libs
OnAddLibClick(cb_unused wxCommandEvent & event)2258 void CompilerOptionsDlg::OnAddLibClick(cb_unused wxCommandEvent& event)
2259 {
2260     wxListBox* lstLibs = XRCCTRL(*this, "lstLibs", wxListBox);
2261 
2262     EditPathDlg dlg(this,
2263             _T(""),
2264             m_pProject ? m_pProject->GetBasePath() : _T(""),
2265             _("Add library"),
2266             _("Choose library to link"),
2267             false,
2268             true,
2269             _("Library files (*.a, *.so, *.lib, *.dylib, *.bundle)|*.a;*.so;*.lib;*.dylib;*.bundle|All files (*)|*"));
2270 
2271     PlaceWindow(&dlg);
2272     if (dlg.ShowModal() == wxID_OK)
2273     {
2274         wxArrayString paths = GetArrayFromString(dlg.GetPath());
2275         for (size_t i = 0; i < paths.GetCount(); ++i)
2276             lstLibs->Append(paths[i]);
2277         m_bDirty = true;
2278     }
2279 } // OnAddLibClick
2280 
OnEditLibClick(cb_unused wxCommandEvent & event)2281 void CompilerOptionsDlg::OnEditLibClick(cb_unused wxCommandEvent& event)
2282 {
2283     wxListBox* lstLibs = XRCCTRL(*this, "lstLibs", wxListBox);
2284     if (!lstLibs)
2285         return;
2286 
2287     wxArrayInt sels;
2288     int num = lstLibs->GetSelections(sels);
2289     if      (num<1)
2290     {
2291       cbMessageBox(_("Please select a library you wish to edit."),
2292                    _("Error"), wxICON_ERROR);
2293     }
2294     else if (num == 1)
2295     {
2296       EditPathDlg dlg(this,
2297               lstLibs->GetString(sels[0]),
2298               m_pProject ? m_pProject->GetBasePath() : _T(""),
2299               _("Edit library"),
2300               _("Choose library to link"),
2301               false,
2302               false,
2303               _("Library files (*.a, *.so, *.lib, *.dylib, *.bundle)|*.a;*.so;*.lib;*.dylib;*.bundle|All files (*)|*"));
2304 
2305       PlaceWindow(&dlg);
2306       if (dlg.ShowModal() == wxID_OK)
2307       {
2308           lstLibs->SetString(sels[0], dlg.GetPath());
2309           m_bDirty = true;
2310       }
2311     }
2312     else
2313     {
2314       cbMessageBox(_("Please select only *one* library you wish to edit."),
2315                    _("Error"), wxICON_ERROR);
2316     }
2317 } // OnEditLibClick
2318 
OnRemoveLibClick(cb_unused wxCommandEvent & event)2319 void CompilerOptionsDlg::OnRemoveLibClick(cb_unused wxCommandEvent& event)
2320 {
2321     wxListBox* lstLibs = XRCCTRL(*this, "lstLibs", wxListBox);
2322     if (!lstLibs)
2323         return;
2324 
2325     wxArrayInt sels;
2326     int num = lstLibs->GetSelections(sels);
2327     if (num == 1) // mimic old behaviour
2328     {
2329         if (cbMessageBox(_("Remove library '")+lstLibs->GetString(sels[0])+_("' from the list?"),
2330             _("Confirmation"), wxICON_QUESTION | wxOK | wxCANCEL) == wxID_OK)
2331         {
2332             lstLibs->Delete(sels[0]);
2333             m_bDirty = true;
2334         }
2335     }
2336     else if (num > 1)
2337     {
2338         wxString msg; msg.Printf(_("Remove all (%d) selected libraries from the list?"), num);
2339         if (cbMessageBox(msg, _("Confirmation"), wxICON_QUESTION | wxOK | wxCANCEL) == wxID_OK)
2340         {
2341             // remove starting with the last lib. otherwise indices will change
2342             for (size_t i = sels.GetCount(); i>0; --i)
2343                 lstLibs->Delete(sels[i-1]);
2344             m_bDirty = true;
2345         }
2346     }
2347     // else: No lib selected
2348 } // OnRemoveLibClick
2349 
OnClearLibClick(cb_unused wxCommandEvent & event)2350 void CompilerOptionsDlg::OnClearLibClick(cb_unused wxCommandEvent& event)
2351 {
2352     wxListBox* lstLibs = XRCCTRL(*this, "lstLibs", wxListBox);
2353     if (!lstLibs || lstLibs->GetCount() == 0)
2354         return;
2355     if (cbMessageBox(_("Remove all libraries from the list?"), _("Confirmation"), wxICON_QUESTION | wxOK | wxCANCEL) == wxID_OK)
2356     {
2357         lstLibs->Clear();
2358         m_bDirty = true;
2359     }
2360 } // OnClearLibClick
2361 
OnCopyLibsClick(cb_unused wxCommandEvent & event)2362 void CompilerOptionsDlg::OnCopyLibsClick(cb_unused wxCommandEvent& event)
2363 {
2364     if (!m_pProject)
2365         return;
2366     wxListBox* lstLibs = XRCCTRL(*this, "lstLibs", wxListBox);
2367     if (!lstLibs || lstLibs->GetCount() == 0)
2368         return;
2369 
2370     wxArrayString choices;
2371     choices.Add(m_pProject->GetTitle());
2372     for (int i = 0; i < m_pProject->GetBuildTargetsCount(); ++i)
2373     {
2374         ProjectBuildTarget* bt = m_pProject->GetBuildTarget(i);
2375         choices.Add(bt->GetTitle());
2376     }
2377 
2378     const wxArrayInt &sel = cbGetMultiChoiceDialog(_("Please select which target to copy these libraries to:"),
2379                                                    _("Copy libraries"), choices, this);
2380     if (sel.empty())
2381         return;
2382 
2383     for (wxArrayInt::const_iterator itr = sel.begin(); itr != sel.end(); ++itr)
2384     {
2385         CompileOptionsBase* base;
2386         if((*itr) == 0)
2387             base = m_pProject; // "copy to project"
2388         else
2389             base = m_pProject->GetBuildTarget((*itr) - 1);
2390 
2391         if (!base)
2392         {
2393             Manager::Get()->GetLogManager()->LogWarning(_T("Could not get build target in CompilerOptionsDlg::OnCopyLibsClick"));
2394             continue;
2395         }
2396 
2397         for (size_t i = 0; i < lstLibs->GetCount(); ++i)
2398         {
2399             if (lstLibs->IsSelected(i))
2400                 base->AddLinkLib(lstLibs->GetString(i));
2401         }
2402     }
2403 } // OnCopyLibsClick
2404 
OnAddExtraPathClick(cb_unused wxCommandEvent & event)2405 void CompilerOptionsDlg::OnAddExtraPathClick(cb_unused wxCommandEvent& event)
2406 {
2407     EditPathDlg dlg(this, _T(""), _T(""), _("Add directory"));
2408 
2409     PlaceWindow(&dlg);
2410     if (dlg.ShowModal() == wxID_OK)
2411     {
2412         wxListBox* control = XRCCTRL(*this, "lstExtraPaths", wxListBox);
2413         if (control)
2414         {
2415             wxString path = dlg.GetPath();
2416 
2417             // get all listBox entries in array String
2418             wxArrayString extraPaths;
2419             ListBox2ArrayString(extraPaths, control);
2420             if (extraPaths.Index(path) != wxNOT_FOUND)
2421             {
2422                 cbMessageBox(_("Path already in extra paths list!"), _("Warning"), wxICON_WARNING);
2423             }
2424             else
2425             {
2426                 control->Append(path);
2427                 m_bDirty = true;
2428             }
2429         }
2430     }
2431 } // OnAddExtraPathClick
2432 
OnEditExtraPathClick(cb_unused wxCommandEvent & event)2433 void CompilerOptionsDlg::OnEditExtraPathClick(cb_unused wxCommandEvent& event)
2434 {
2435     wxListBox* control = XRCCTRL(*this, "lstExtraPaths", wxListBox);
2436     if (!control || control->GetSelection() < 0)
2437         return;
2438 
2439     wxFileName dir(control->GetString(control->GetSelection()) + wxFileName::GetPathSeparator());
2440     wxString initial = control->GetString(control->GetSelection()); // might be a macro
2441     if (dir.DirExists())
2442         initial = dir.GetPath(wxPATH_GET_VOLUME);
2443 
2444     EditPathDlg dlg(this, initial, _T(""), _("Edit directory"));
2445 
2446     PlaceWindow(&dlg);
2447     if (dlg.ShowModal() == wxID_OK)
2448     {
2449         wxString path = dlg.GetPath();
2450 
2451         // get all listBox entries in array String
2452         wxArrayString extraPaths;
2453         ListBox2ArrayString(extraPaths, control);
2454         if (extraPaths.Index(path) != wxNOT_FOUND)
2455         {
2456             cbMessageBox(_("Path already in extra paths list!"), _("Warning"), wxICON_WARNING);
2457         }
2458         else
2459         {
2460             control->SetString(control->GetSelection(), path);
2461             m_bDirty = true;
2462         }
2463     }
2464 } // OnEditExtraPathClick
2465 
OnRemoveExtraPathClick(cb_unused wxCommandEvent & event)2466 void CompilerOptionsDlg::OnRemoveExtraPathClick(cb_unused wxCommandEvent& event)
2467 {
2468     wxListBox* control = XRCCTRL(*this, "lstExtraPaths", wxListBox);
2469     if (!control || control->GetSelection() < 0)
2470         return;
2471     control->Delete(control->GetSelection());
2472     m_bDirty = true;
2473 } // OnRemoveExtraPathClick
2474 
OnClearExtraPathClick(cb_unused wxCommandEvent & event)2475 void CompilerOptionsDlg::OnClearExtraPathClick(cb_unused wxCommandEvent& event)
2476 {
2477     wxListBox* control = XRCCTRL(*this, "lstExtraPaths", wxListBox);
2478     if (!control || control->IsEmpty())
2479         return;
2480 
2481     if (cbMessageBox(_("Remove all extra paths from the list?"), _("Confirmation"), wxICON_QUESTION | wxOK | wxCANCEL) == wxID_OK)
2482     {
2483         control->Clear();
2484         m_bDirty = true;
2485     }
2486 } // OnClearExtraPathClick
2487 
OnIgnoreAddClick(cb_unused wxCommandEvent & event)2488 void CompilerOptionsDlg::OnIgnoreAddClick(cb_unused wxCommandEvent& event)
2489 {
2490     wxListBox*  list = XRCCTRL(*this, "lstIgnore", wxListBox);
2491     wxTextCtrl* text = XRCCTRL(*this, "txtIgnore", wxTextCtrl);
2492 
2493     wxString ignore_str = text->GetValue().Trim();
2494     if (   (ignore_str.Len()>0)
2495         && (list->FindString(ignore_str)==wxNOT_FOUND) )
2496     {
2497         list->Append(ignore_str);
2498         m_bDirty = true;
2499     }
2500 } // OnIgnoreAddClick
2501 
OnIgnoreRemoveClick(cb_unused wxCommandEvent & event)2502 void CompilerOptionsDlg::OnIgnoreRemoveClick(cb_unused wxCommandEvent& event)
2503 {
2504     wxListBox* list = XRCCTRL(*this, "lstIgnore", wxListBox);
2505     if (!list || list->IsEmpty())
2506         return;
2507 
2508     int selection = list->GetSelection();
2509     if (selection!=wxNOT_FOUND)
2510     {
2511         list->Delete(selection);
2512         m_bDirty = true;
2513     }
2514 } // OnIgnoreRemoveClick
2515 
OnMoveLibUpClick(cb_unused wxCommandEvent & event)2516 void CompilerOptionsDlg::OnMoveLibUpClick(cb_unused wxCommandEvent& event)
2517 {
2518     wxListBox* lstLibs = XRCCTRL(*this, "lstLibs", wxListBox);
2519     if (!lstLibs)
2520         return;
2521 
2522     wxArrayInt sels;
2523     int num = lstLibs->GetSelections(sels);
2524     if (num == 0)
2525         return;
2526 
2527     // moving upwards: need to start from the first element
2528     // starting at second element, the first one cannot be moved upwards
2529     for (size_t i=1; i<lstLibs->GetCount(); ++i)
2530     {
2531         // do not move upwards if the lib before is selected, too
2532         if (lstLibs->IsSelected(i) && !lstLibs->IsSelected(i-1))
2533         {
2534             wxString lib = lstLibs->GetString(i);
2535             lstLibs->Delete(i);
2536 
2537             lstLibs->InsertItems(1, &lib, i - 1);
2538             lstLibs->SetSelection(i - 1);
2539 
2540             m_bDirty = true;
2541         }
2542     }
2543 } // OnMoveLibUpClick
2544 
OnMoveLibDownClick(cb_unused wxCommandEvent & event)2545 void CompilerOptionsDlg::OnMoveLibDownClick(cb_unused wxCommandEvent& event)
2546 {
2547     wxListBox* lstLibs = XRCCTRL(*this, "lstLibs", wxListBox);
2548     if (!lstLibs)
2549         return;
2550 
2551     wxArrayInt sels;
2552     int num = lstLibs->GetSelections(sels);
2553     if (num == 0)
2554         return;
2555 
2556     // moving downwards: need to start from the last element
2557     // starting at pre-last element, the last one cannot be moved downwards
2558     for (size_t i=lstLibs->GetCount()-1; i>0; --i)
2559     {
2560         // do not move downwards if the lib after is selected, too
2561         // notice here: as started with index+1 (due to GetCount)...
2562         // ... subtract 1 all the way to achieve the real index operated on
2563         if (lstLibs->IsSelected(i-1) && !lstLibs->IsSelected(i))
2564         {
2565             wxString lib = lstLibs->GetString(i-1);
2566             lstLibs->Delete(i-1);
2567 
2568             lstLibs->InsertItems(1, &lib, i);
2569             lstLibs->SetSelection(i);
2570 
2571             m_bDirty = true;
2572         }
2573     }
2574 } // OnMoveLibDownClick
2575 
OnMoveDirUpClick(cb_unused wxCommandEvent & event)2576 void CompilerOptionsDlg::OnMoveDirUpClick(cb_unused wxCommandEvent& event)
2577 {
2578     wxListBox* lst = GetDirsListBox();
2579     wxArrayInt sels;
2580     if (!lst || lst->GetSelections(sels) < 1)
2581         return;
2582 
2583     // moving upwards: need to start from the first element
2584     // starting at second element, the first one cannot be moved upwards
2585     for (size_t i=1; i<lst->GetCount(); ++i)
2586     {
2587         // do not move upwards if the dir before is selected, too
2588         if (lst->IsSelected(i) && !lst->IsSelected(i-1))
2589         {
2590             wxString dir = lst->GetString(i);
2591             lst->Delete(i);
2592 
2593             lst->InsertItems(1, &dir, i - 1);
2594             lst->SetSelection(i - 1);
2595 
2596             m_bDirty = true;
2597         }
2598     }
2599 } // OnMoveDirUpClick
2600 
OnMoveDirDownClick(cb_unused wxCommandEvent & event)2601 void CompilerOptionsDlg::OnMoveDirDownClick(cb_unused wxCommandEvent& event)
2602 {
2603     wxListBox* lst = GetDirsListBox();
2604     wxArrayInt sels;
2605     if (!lst || lst->GetSelections(sels) < 1)
2606         return;
2607 
2608     // moving downwards: need to start from the last element
2609     // starting at pre-last element, the last one cannot be moved downwards
2610     for (size_t i=lst->GetCount()-1; i>0; --i)
2611     {
2612         // do not move downwards if the dir after is selected, too
2613         // notice here: as started with index+1 (due to GetCount)...
2614         // ... subtract 1 all the way to achieve the real index operated on
2615         if (lst->IsSelected(i-1) && !lst->IsSelected(i))
2616         {
2617             wxString dir = lst->GetString(i-1);
2618             lst->Delete(i-1);
2619 
2620             lst->InsertItems(1, &dir, i);
2621             lst->SetSelection(i);
2622 
2623             m_bDirty = true;
2624         }
2625     }
2626 } // OnMoveDirDownClick
2627 
OnMasterPathClick(cb_unused wxCommandEvent & event)2628 void CompilerOptionsDlg::OnMasterPathClick(cb_unused wxCommandEvent& event)
2629 {
2630     wxString path = ChooseDirectory(this,
2631                                     _("Select directory"),
2632                                     XRCCTRL(*this, "txtMasterPath", wxTextCtrl)->GetValue());
2633     if (!path.IsEmpty())
2634     {
2635         XRCCTRL(*this, "txtMasterPath", wxTextCtrl)->SetValue(path);
2636         m_bDirty = true;
2637     }
2638 } // OnMasterPathClick
2639 
OnAutoDetectClick(cb_unused wxCommandEvent & event)2640 void CompilerOptionsDlg::OnAutoDetectClick(cb_unused wxCommandEvent& event)
2641 {
2642     AutoDetectCompiler();
2643 } // OnAutoDetectClick
2644 
OnSelectProgramClick(wxCommandEvent & event)2645 void CompilerOptionsDlg::OnSelectProgramClick(wxCommandEvent& event)
2646 {
2647     // see who called us
2648     wxTextCtrl* obj = 0L;
2649     if (event.GetId() == XRCID("btnCcompiler"))
2650         obj = XRCCTRL(*this, "txtCcompiler", wxTextCtrl);
2651     else if (event.GetId() == XRCID("btnCPPcompiler"))
2652         obj = XRCCTRL(*this, "txtCPPcompiler", wxTextCtrl);
2653     else if (event.GetId() == XRCID("btnLinker"))
2654         obj = XRCCTRL(*this, "txtLinker", wxTextCtrl);
2655     else if (event.GetId() == XRCID("btnLibLinker"))
2656         obj = XRCCTRL(*this, "txtLibLinker", wxTextCtrl);
2657     else if (event.GetId() == XRCID("btnResComp"))
2658         obj = XRCCTRL(*this, "txtResComp", wxTextCtrl);
2659     else if (event.GetId() == XRCID("btnMake"))
2660         obj = XRCCTRL(*this, "txtMake", wxTextCtrl);
2661 
2662     if (!obj)
2663         return; // called from invalid caller
2664 
2665     // common part follows
2666     wxString file_selection = _("All files (*)|*");
2667     if (platform::windows)
2668         file_selection = _("Executable files (*.exe)|*.exe");
2669     wxFileDialog dlg(this,
2670                      _("Select file"),
2671                      XRCCTRL(*this, "txtMasterPath", wxTextCtrl)->GetValue() + _T("/bin"),
2672                      obj->GetValue(),
2673                      file_selection,
2674                      wxFD_OPEN | wxFD_FILE_MUST_EXIST | compatibility::wxHideReadonly );
2675     dlg.SetFilterIndex(0);
2676 
2677     PlaceWindow(&dlg);
2678     if (dlg.ShowModal() != wxID_OK)
2679         return;
2680     wxFileName fname(dlg.GetPath());
2681     obj->SetValue(fname.GetFullName());
2682     m_bDirty = true;
2683 } // OnSelectProgramClick
2684 
OnAdvancedClick(cb_unused wxCommandEvent & event)2685 void CompilerOptionsDlg::OnAdvancedClick(cb_unused wxCommandEvent& event)
2686 {
2687     AnnoyingDialog dlg(_("Edit advanced compiler settings?"),
2688                         _("The compiler's advanced settings, need command-line "
2689                         "compiler knowledge to be tweaked.\nIf you don't know "
2690                         "*exactly* what you 're doing, it is suggested to "
2691                         "NOT tamper with these...\n\n"
2692                         "Are you sure you want to proceed?"),
2693                     wxART_QUESTION);
2694     if (dlg.ShowModal() == AnnoyingDialog::rtYES)
2695     {
2696         wxChoice* cmb = XRCCTRL(*this, "cmbCompiler", wxChoice);
2697         int compilerIdx = cmb->GetSelection();
2698         AdvancedCompilerOptionsDlg dlg2(this, CompilerFactory::GetCompiler(compilerIdx)->GetID());
2699         PlaceWindow(&dlg2);
2700         dlg2.ShowModal();
2701         // check if dirty
2702         if (dlg2.IsDirty())
2703         {
2704 //            m_bDirty = true;  // TO DO : Activate when implemented in the adv dialog
2705         }
2706     }
2707 } // OnAdvancedClick
2708 
UpdateUIListBoxAndButtons(wxListBox & list,wxButton & edit,wxButton & del,wxButton & clear,wxButton & copy,wxButton & up,wxButton & down)2709 static void UpdateUIListBoxAndButtons(wxListBox &list, wxButton &edit, wxButton &del, wxButton &clear, wxButton &copy,
2710                                       wxButton &up, wxButton &down)
2711 {
2712     wxArrayInt selections;
2713     int num = list.GetSelections(selections);
2714     int itemCount = list.GetCount();
2715     bool en = (num > 0);
2716 
2717     edit.Enable(num == 1);
2718     del.Enable(en);
2719     clear.Enable(itemCount != 0);
2720     copy.Enable(en);
2721 
2722     if (en)
2723     {
2724         int minIndex = selections.size();
2725         int maxIndex = 0;
2726         for (int index : selections)
2727         {
2728             minIndex = std::min(index, minIndex);
2729             maxIndex = std::max(index, maxIndex);
2730         }
2731         up.Enable(minIndex > 0);
2732         down.Enable(maxIndex < itemCount - 1);
2733     }
2734     else
2735     {
2736         up.Enable(false);
2737         down.Enable(false);
2738     }
2739 }
2740 
OnUpdateUI(cb_unused wxUpdateUIEvent & event)2741 void CompilerOptionsDlg::OnUpdateUI(cb_unused wxUpdateUIEvent& event)
2742 {
2743     bool en = false;
2744 
2745     wxListBox* control = GetDirsListBox();
2746     if (control)
2747     {
2748         UpdateUIListBoxAndButtons(*control, *XRCCTRL(*this, "btnEditDir",  wxButton),
2749                                   *XRCCTRL(*this, "btnDelDir",   wxButton), *XRCCTRL(*this, "btnClearDir", wxButton),
2750                                   *XRCCTRL(*this, "btnCopyDirs", wxButton), *XRCCTRL(*this, "btnMoveDirUp", wxButton),
2751                                   *XRCCTRL(*this, "btnMoveDirDown", wxButton));
2752     }
2753 
2754     // edit/delete/clear/copy/moveup/movedown lib dirs
2755     wxListBox* lstLibs = XRCCTRL(*this, "lstLibs", wxListBox);
2756     if (lstLibs)
2757     {
2758         UpdateUIListBoxAndButtons(*lstLibs, *XRCCTRL(*this, "btnEditLib",  wxButton),
2759                                   *XRCCTRL(*this, "btnDelLib",   wxButton), *XRCCTRL(*this, "btnClearLib", wxButton),
2760                                   *XRCCTRL(*this, "btnCopyLibs", wxButton), *XRCCTRL(*this, "btnMoveLibUp", wxButton),
2761                                   *XRCCTRL(*this, "btnMoveLibDown", wxButton));
2762     }
2763 
2764     // edit/delete/clear/copy/moveup/movedown extra path
2765     if (!m_pProject)
2766     {
2767         en = XRCCTRL(*this, "lstExtraPaths", wxListBox)->GetSelection() >= 0;
2768         XRCCTRL(*this, "btnExtraEdit",   wxButton)->Enable(en);
2769         XRCCTRL(*this, "btnExtraDelete", wxButton)->Enable(en);
2770         XRCCTRL(*this, "btnExtraClear",  wxButton)->Enable(XRCCTRL(*this, "lstExtraPaths", wxListBox)->GetCount() != 0);
2771     }
2772 
2773     // add/edit/delete/clear vars
2774     en = XRCCTRL(*this, "lstVars", wxListBox)->GetSelection() >= 0;
2775     XRCCTRL(*this, "btnEditVar",   wxButton)->Enable(en);
2776     XRCCTRL(*this, "btnDeleteVar", wxButton)->Enable(en);
2777     XRCCTRL(*this, "btnClearVar",  wxButton)->Enable(XRCCTRL(*this, "lstVars", wxListBox)->GetCount() != 0);
2778 
2779     // policies
2780     wxTreeCtrl* tc = XRCCTRL(*this, "tcScope", wxTreeCtrl);
2781     ScopeTreeData* data = (ScopeTreeData*)tc->GetItemData(tc->GetSelection());
2782     en = (data && data->GetTarget());
2783     XRCCTRL(*this, "cmbCompilerPolicy", wxChoice)->Enable(en);
2784     XRCCTRL(*this, "cmbLinkerPolicy",   wxChoice)->Enable(en);
2785     XRCCTRL(*this, "cmbIncludesPolicy", wxChoice)->Enable(en);
2786     XRCCTRL(*this, "cmbLibDirsPolicy",  wxChoice)->Enable(en);
2787     XRCCTRL(*this, "cmbResDirsPolicy",  wxChoice)->Enable(en);
2788 
2789     // compiler set buttons
2790     if (!m_pProject)
2791     {
2792         en = !data; // global options selected
2793         int idx   = XRCCTRL(*this, "cmbCompiler", wxChoice)->GetSelection();
2794         int count = XRCCTRL(*this, "cmbCompiler", wxChoice)->GetCount(); // compilers count
2795         Compiler* compiler = CompilerFactory::GetCompiler(idx);
2796 
2797         XRCCTRL(*this, "btnSetDefaultCompiler", wxButton)->Enable(CompilerFactory::GetCompilerIndex(CompilerFactory::GetDefaultCompiler()) != idx);
2798         XRCCTRL(*this, "btnAddCompiler",        wxButton)->Enable(en);
2799         XRCCTRL(*this, "btnRenameCompiler",     wxButton)->Enable(en && count);
2800         XRCCTRL(*this, "btnDelCompiler",        wxButton)->Enable(en &&
2801                                                                   compiler &&
2802                                                                  !compiler->GetParentID().IsEmpty());
2803         XRCCTRL(*this, "btnResetCompiler",      wxButton)->Enable(en &&
2804                                                                   compiler &&
2805                                                                   compiler->GetParentID().IsEmpty());
2806 
2807         XRCCTRL(*this, "chkFullHtmlLog", wxCheckBox)->Enable(XRCCTRL(*this, "chkSaveHtmlLog", wxCheckBox)->IsChecked());
2808         XRCCTRL(*this, "btnIgnoreRemove", wxButton)->Enable(XRCCTRL(*this, "lstIgnore", wxListBox)->GetCount()>0);
2809         XRCCTRL(*this, "btnIgnoreAdd", wxButton)->Enable(XRCCTRL(*this, "txtIgnore", wxTextCtrl)->GetValue().Trim().Len()>0);
2810     }
2811 } // OnUpdateUI
2812 
OnApply()2813 void CompilerOptionsDlg::OnApply()
2814 {
2815     m_CurrentCompilerIdx = XRCCTRL(*this, "cmbCompiler", wxChoice)->GetSelection();
2816     DoSaveCompilerDependentSettings();
2817     CompilerFactory::SaveSettings();
2818 
2819     //others (projects don't have Other tab)
2820     if (!m_pProject)
2821     {
2822         ConfigManager* cfg = Manager::Get()->GetConfigManager(_T("compiler"));
2823         wxCheckBox* chk = XRCCTRL(*this, "chkIncludeFileCwd", wxCheckBox);
2824         if (chk)
2825             cfg->Write(_T("/include_file_cwd"), (bool)chk->IsChecked());
2826         chk = XRCCTRL(*this, "chkIncludePrjCwd", wxCheckBox);
2827         if (chk)
2828             cfg->Write(_T("/include_prj_cwd"), (bool)chk->IsChecked());
2829         chk = XRCCTRL(*this, "chkSkipIncludeDeps", wxCheckBox);
2830         if (chk)
2831             cfg->Write(_T("/skip_include_deps"), (bool)chk->IsChecked());
2832         chk = XRCCTRL(*this, "chkSaveHtmlLog", wxCheckBox);
2833         if (chk)
2834             cfg->Write(_T("/save_html_build_log"), (bool)chk->IsChecked());
2835         chk = XRCCTRL(*this, "chkFullHtmlLog", wxCheckBox);
2836         if (chk)
2837             cfg->Write(_T("/save_html_build_log/full_command_line"), (bool)chk->IsChecked());
2838         chk = XRCCTRL(*this, "chkBuildProgressBar", wxCheckBox);
2839         if (chk)
2840             cfg->Write(_T("/build_progress/bar"), (bool)chk->IsChecked());
2841         chk = XRCCTRL(*this, "chkBuildProgressPerc", wxCheckBox);
2842         if (chk)
2843         {
2844             cfg->Write(_T("/build_progress/percentage"), (bool)chk->IsChecked());
2845             m_Compiler->m_LogBuildProgressPercentage = chk->IsChecked();
2846         }
2847         wxSpinCtrl* spn = XRCCTRL(*this, "spnParallelProcesses", wxSpinCtrl);
2848         if (spn && (((int)spn->GetValue()) != cfg->ReadInt(_T("/parallel_processes"), 0)))
2849         {
2850             if (m_Compiler->IsRunning())
2851                 cbMessageBox(_("You can't change the number of parallel processes while building!\nSetting ignored..."), _("Warning"), wxICON_WARNING);
2852             else
2853             {
2854                 cfg->Write(_T("/parallel_processes"), (int)spn->GetValue());
2855                 m_Compiler->ReAllocProcesses();
2856             }
2857         }
2858         spn = XRCCTRL(*this, "spnMaxErrors", wxSpinCtrl);
2859         if (spn)
2860             cfg->Write(_T("/max_reported_errors"), (int)spn->GetValue());
2861 
2862         chk = XRCCTRL(*this, "chkRebuildSeperately", wxCheckBox);
2863         if (chk)
2864             cfg->Write(_T("/rebuild_seperately"), (bool)chk->IsChecked());
2865 
2866         wxListBox* lst = XRCCTRL(*this, "lstIgnore", wxListBox);
2867         if (lst)
2868         {
2869             wxArrayString IgnoreOutput;
2870             ListBox2ArrayString(IgnoreOutput, lst);
2871             cfg->Write(_T("/ignore_output"), IgnoreOutput);
2872         }
2873 
2874         chk = XRCCTRL(*this, "chkNonPlatComp", wxCheckBox);
2875         if (chk && (chk->IsChecked() != cfg->ReadBool(_T("/non_plat_comp"), false)))
2876         {
2877             if (m_Compiler->IsRunning())
2878                 cbMessageBox(_("You can't change the option to enable or disable non-platform compilers while building!\nSetting ignored..."), _("Warning"), wxICON_WARNING);
2879             else
2880             {
2881                 cfg->Write(_T("/non_plat_comp"), (bool)chk->IsChecked());
2882                 CompilerFactory::UnregisterCompilers();
2883                 m_Compiler->DoRegisterCompilers();
2884                 m_Compiler->LoadOptions();
2885             }
2886         }
2887     }
2888 
2889     m_Compiler->SaveOptions();
2890     m_Compiler->SetupEnvironment();
2891     Manager::Get()->GetMacrosManager()->Reset();
2892     m_bDirty = false;
2893 } // OnApply
2894 
OnMyCharHook(wxKeyEvent & event)2895 void CompilerOptionsDlg::OnMyCharHook(wxKeyEvent& event)
2896 {
2897     wxWindow* focused = wxWindow::FindFocus();
2898     if (!focused)
2899     {
2900         event.Skip();
2901         return;
2902     }
2903     int keycode = event.GetKeyCode();
2904     int id      = focused->GetId();
2905 
2906     int myid = 0;
2907     unsigned int myidx = 0;
2908 
2909     const wxChar* str_libs[4] = { _T("btnEditLib"),  _T("btnAddLib"),  _T("btnDelLib"),     _T("btnClearLib")   };
2910     const wxChar* str_dirs[4] = { _T("btnEditDir"),  _T("btnAddDir"),  _T("btnDelDir"),     _T("btnClearDir")   };
2911     const wxChar* str_vars[4] = { _T("btnEditVar"),  _T("btnAddVar"),  _T("btnDeleteVar"),  _T("btnClearVar")   };
2912     const wxChar* str_xtra[4] = { _T("btnExtraEdit"),_T("btnExtraAdd"),_T("btnExtraDelete"),_T("btnExtraClear") };
2913 
2914     if (keycode == WXK_RETURN || keycode == WXK_NUMPAD_ENTER)
2915     { myidx = 0; } // Edit
2916     else if (keycode == WXK_INSERT || keycode == WXK_NUMPAD_INSERT)
2917     { myidx = 1; } // Add
2918     else if (keycode == WXK_DELETE || keycode == WXK_NUMPAD_DELETE)
2919     { myidx = 2; } // Delete
2920     else
2921     {
2922         event.Skip();
2923         return;
2924     }
2925 
2926     if (     id == XRCID("lstLibs")) // Link libraries
2927         { myid =  wxXmlResource::GetXRCID(str_libs[myidx]); }
2928     else if (id == XRCID("lstIncludeDirs") || id == XRCID("lstLibDirs") || id == XRCID("lstResDirs")) // Directories
2929         { myid =  wxXmlResource::GetXRCID(str_dirs[myidx]); }
2930     else if (id == XRCID("lstVars")) // Custom Vars
2931         { myid =  wxXmlResource::GetXRCID(str_vars[myidx]); }
2932     else if (id == XRCID("lstExtraPaths")) // Extra Paths
2933         { myid =  wxXmlResource::GetXRCID(str_xtra[myidx]); }
2934     else
2935         myid = 0;
2936 
2937     // Generate the event
2938     if (myid == 0)
2939         event.Skip();
2940     else
2941     {
2942         wxCommandEvent newevent(wxEVT_COMMAND_BUTTON_CLICKED,myid);
2943         this->ProcessEvent(newevent);
2944     }
2945 } // OnMyCharHook
2946 
2947 int CompilerOptionsDlg::m_MenuOption = -1;
2948 
OnFlagsPopup(wxPropertyGridEvent & event)2949 void CompilerOptionsDlg::OnFlagsPopup(wxPropertyGridEvent& event)
2950 {
2951     int scroll = m_FlagsPG->GetScrollPos(wxVERTICAL);
2952     wxPGProperty *property = event.GetProperty();
2953 
2954     enum FlagsMenuOptions
2955     {
2956         FMO_None = -1,
2957         FMO_New = 0,
2958         FMO_Modify,
2959         FMO_Delete,
2960         FMO_COnly,
2961         FMO_CPPOnly,
2962         FMO_ExpandAll,
2963         FMO_CollapseAll
2964     };
2965 
2966     wxMenu* pop = new wxMenu;
2967     pop->Append(FMO_New, _("New flag..."));
2968     if (property && !property->IsCategory())
2969     {
2970         pop->Append(FMO_Modify, _("Modify flag..."));
2971         pop->Append(FMO_Delete, _("Delete flag"));
2972     }
2973     pop->AppendSeparator();
2974     pop->Append(FMO_COnly, _("C - only flags..."));
2975     pop->Append(FMO_CPPOnly, _("C++ - only flags..."));
2976     pop->AppendSeparator();
2977     pop->Append(FMO_ExpandAll, _("Expand all categories"));
2978     pop->Append(FMO_CollapseAll, _("Collapse all categories"));
2979     pop->Connect(wxEVT_COMMAND_MENU_SELECTED, (wxObjectEventFunction)&CompilerOptionsDlg::OnFlagsPopupClick);
2980     m_MenuOption = FMO_None;
2981     m_FlagsPG->PopupMenu(pop);
2982     delete pop;
2983     if (m_MenuOption == FMO_None)
2984         return;
2985     if (m_MenuOption == FMO_COnly)
2986     {
2987         Compiler* compiler = CompilerFactory::GetCompiler(m_CurrentCompilerIdx);
2988         wxTextEntryDialog dlg(this, wxT("List flags that will only be used during C compilation"),
2989                               wxT("C - only flags"), compiler->GetCOnlyFlags(), wxTextEntryDialogStyle|wxTE_MULTILINE|wxRESIZE_BORDER);
2990         // TODO: Hack for Ubuntu, see here: http://forums.codeblocks.org/index.php/topic,16463.msg115270.html#msg115270 (Remove if no longer needed.)
2991         if (dlg.GetSize().GetHeight() < 220)
2992         {
2993             dlg.SetSize(dlg.GetPosition().x, dlg.GetPosition().y - (220 - dlg.GetSize().GetHeight()) / 2,
2994                         dlg.GetSize().GetWidth(), 220);
2995         }
2996         PlaceWindow(&dlg);
2997         dlg.ShowModal();
2998         wxString flags = dlg.GetValue();
2999         flags.Replace(wxT("\n"), wxT(" "));
3000         flags.Replace(wxT("\r"), wxT(" "));
3001         flags.Replace(wxT("\t"), wxT(" "));
3002         flags = MakeUniqueString(flags, wxT(" "));
3003         if (flags != compiler->GetCOnlyFlags())
3004         {
3005             compiler->SetCOnlyFlags(flags);
3006             m_bDirty = true;
3007         }
3008         return;
3009     }
3010     else if (m_MenuOption == FMO_CPPOnly)
3011     {
3012         Compiler* compiler = CompilerFactory::GetCompiler(m_CurrentCompilerIdx);
3013         wxTextEntryDialog dlg(this, wxT("List flags that will only be used during C++ compilation"),
3014                               wxT("C++ - only flags"), compiler->GetCPPOnlyFlags(), wxTextEntryDialogStyle|wxTE_MULTILINE|wxRESIZE_BORDER);
3015         // TODO: Hack for Ubuntu, see here: http://forums.codeblocks.org/index.php/topic,16463.msg115270.html#msg115270 (Remove if no longer needed.)
3016         if (dlg.GetSize().GetHeight() < 220)
3017         {
3018             dlg.SetSize(dlg.GetPosition().x, dlg.GetPosition().y - (220 - dlg.GetSize().GetHeight()) / 2,
3019                         dlg.GetSize().GetWidth(), 220);
3020         }
3021         dlg.ShowModal();
3022         wxString flags = dlg.GetValue();
3023         flags.Replace(wxT("\n"), wxT(" "));
3024         flags.Replace(wxT("\r"), wxT(" "));
3025         flags.Replace(wxT("\t"), wxT(" "));
3026         flags = MakeUniqueString(flags, wxT(" "));
3027         if (flags != compiler->GetCPPOnlyFlags())
3028         {
3029             compiler->SetCPPOnlyFlags(flags);
3030             m_bDirty = true;
3031         }
3032         return;
3033     }
3034     else if (m_MenuOption == FMO_Delete)
3035     {
3036         size_t i = 0;
3037         for (; i < m_Options.GetCount(); ++i)
3038         {
3039             if (m_Options.GetOption(i)->name == property->GetLabel())
3040                 break;
3041         }
3042         m_Options.RemoveOption(i);
3043     }
3044     else if (m_MenuOption == FMO_ExpandAll)
3045     {
3046         m_FlagsPG->ExpandAll();
3047         return;
3048     }
3049     else if (m_MenuOption == FMO_CollapseAll)
3050     {
3051         m_FlagsPG->CollapseAll();
3052         return;
3053     }
3054     else
3055     {
3056         wxArrayString categ;
3057         for (size_t i = 0; i < m_Options.GetCount(); ++i)
3058         {
3059             CompOption* opt = m_Options.GetOption(i);
3060             bool known = false;
3061             for (size_t j = 0; j < categ.GetCount(); ++j)
3062             {
3063                 if (categ[j] == opt->category)
3064                 {
3065                     known = true;
3066                     break;
3067                 }
3068             }
3069             if (!known)
3070                 categ.Add(opt->category);
3071         }
3072         if (categ.IsEmpty())
3073             categ.Add(wxT("General"));
3074         CompOption copt;
3075         if (m_MenuOption == FMO_Modify)
3076             copt = *m_Options.GetOptionByName(property->GetLabel());
3077 
3078         wxString categoryName;
3079         if (property)
3080         {
3081             // If we have a selected property try to find the name of the category.
3082             if (property->IsCategory())
3083                 categoryName = property->GetLabel();
3084             else
3085             {
3086                 wxPGProperty *category = property->GetParent();
3087                 if (category)
3088                     categoryName = category->GetLabel();
3089             }
3090         }
3091         CompilerFlagDlg dlg(nullptr, &copt, categ, categoryName);
3092         PlaceWindow(&dlg);
3093         if (dlg.ShowModal() != wxID_OK)
3094             return;
3095         if (m_MenuOption == FMO_New)
3096         {
3097             size_t i;
3098             if (property)
3099             {
3100                 wxString name;
3101                 if (property->IsCategory())
3102                 {
3103                     wxPGProperty *child = m_FlagsPG->GetFirstChild(property);
3104                     if (child)
3105                         name = child->GetLabel();
3106                 }
3107                 else
3108                     name = property->GetLabel();
3109                 for (i = 0; i < m_Options.GetCount(); ++i)
3110                 {
3111                     if (m_Options.GetOption(i)->name == name)
3112                         break;
3113                 }
3114             }
3115             else
3116                 i = m_Options.GetCount() - 1;
3117 
3118             m_Options.AddOption(copt.name, copt.option,
3119                                 copt.category, copt.additionalLibs,
3120                                 copt.checkAgainst, copt.checkMessage,
3121                                 copt.supersedes, copt.exclusive, i + 1);
3122         }
3123         else
3124         {
3125             CompOption* opt = m_Options.GetOptionByName(property->GetLabel());
3126             wxString name = copt.name + wxT("  [");
3127             if (copt.option.IsEmpty())
3128                 name += copt.additionalLibs;
3129             else
3130                 name += copt.option;
3131             name += wxT("]");
3132             opt->name           = name;
3133             opt->option         = copt.option;
3134             opt->additionalLibs = copt.additionalLibs;
3135             opt->category       = copt.category;
3136             opt->checkAgainst   = copt.checkAgainst;
3137             opt->checkMessage   = copt.checkMessage;
3138             opt->supersedes     = copt.supersedes;
3139             opt->exclusive      = copt.exclusive;
3140         }
3141     }
3142     DoFillOptions();
3143     m_FlagsPG->ScrollLines(scroll);
3144     m_bFlagsDirty = true;
3145 }
3146 
OnFlagsPopupClick(wxCommandEvent & event)3147 void CompilerOptionsDlg::OnFlagsPopupClick(wxCommandEvent& event)
3148 {
3149     m_MenuOption = event.GetId();
3150 }
3151 
OnOptionDoubleClick(wxPropertyGridEvent & event)3152 void CompilerOptionsDlg::OnOptionDoubleClick(wxPropertyGridEvent& event)
3153 {
3154     wxPGProperty* property = event.GetProperty();
3155     // For bool properties automatically toggle the checkbox on double click.
3156     if (property && property->IsKindOf(CLASSINFO(wxBoolProperty)))
3157     {
3158         bool realValue = m_FlagsPG->GetPropertyValue(property);
3159         m_FlagsPG->ChangePropertyValue(property, !realValue);
3160     }
3161     event.Skip();
3162 }
3163