Code::Blocks  SVN r11506
projectfileoptionsdlg.cpp
Go to the documentation of this file.
1 /*
2  * This file is part of the Code::Blocks IDE and licensed under the GNU Lesser General Public License, version 3
3  * http://www.gnu.org/licenses/lgpl-3.0.html
4  *
5  * $Revision: 11119 $
6  * $Id: projectfileoptionsdlg.cpp 11119 2017-08-01 21:49:34Z fuscated $
7  * $HeadURL: https://svn.code.sf.net/p/codeblocks/code/trunk/src/sdk/projectfileoptionsdlg.cpp $
8  */
9 
10 #include "sdk_precomp.h"
11 
12 #ifndef CB_PRECOMP
13  #include "cbproject.h"
14  #include "compilerfactory.h"
15  #include "editormanager.h"
16  #include "editorcolourset.h"
17  #include "logmanager.h"
18  #include "projectmanager.h"
19  #include <wx/xrc/xmlres.h>
20  #include <wx/intl.h>
21  #include <wx/choice.h>
22  #include <wx/checkbox.h>
23  #include <wx/textctrl.h>
24  #include <wx/button.h>
25  #include <wx/filename.h>
26  #include <wx/file.h>
27  #include <wx/checklst.h>
28  #include <wx/stattext.h>
29  #include <wx/sizer.h>
30 #endif
31 
32 #ifdef __WXMSW__
33 // TODO: equivalent??? -> #include <errno.h>
34 #else
35 #include <errno.h>
36 #endif
37 
38 #include "projectfileoptionsdlg.h"
39 #include <wx/slider.h>
40 #include <wx/notebook.h>
41 #include <wx/textfile.h>
42 
43 BEGIN_EVENT_TABLE(ProjectFileOptionsDlg, wxScrollingDialog)
44  EVT_CHECKBOX (XRCID("chkReadOnly"), ProjectFileOptionsDlg::OnReadOnlyCheck)
45  EVT_CHOICE (XRCID("cmbBuildStageCompiler"), ProjectFileOptionsDlg::OnCompilerCombo)
46  EVT_UPDATE_UI(-1, ProjectFileOptionsDlg::OnUpdateUI)
47 END_EVENT_TABLE()
48 
49 // some help functions (copied and adapted from the codestat plug-in)
50 
51 inline void AnalyseLine(const CommentToken &language, wxString line, bool &comment, bool &code, bool &multi_line_comment)
52 {
53  int first_single_line_comment, first_multi_line_comment_begin, first_multi_line_comment_end;
54 
55  // Delete first and trailing spaces
56  line = line.Trim(true);
57  line = line.Trim(false);
58 
59  if (line.IsEmpty())
60  return;
61 
62  // Searching for single and multi-lines comment signs
63  if (language.lineComment.Length() > 0)
64  first_single_line_comment = line.Find(language.lineComment);
65  else first_single_line_comment = -1;
66  if (language.streamCommentStart.Length() > 0)
67  first_multi_line_comment_begin = line.Find(language.streamCommentStart);
68  else first_multi_line_comment_begin = -1;
69  if (language.streamCommentEnd.Length() > 0)
70  first_multi_line_comment_end = line.Find(language.streamCommentEnd);
71  else first_multi_line_comment_end = -1;
72 
73  // We are in a multiple line comment => finding the "end of multiple line comment" sign
74  if (multi_line_comment)
75  {
76  comment = true;
77  if (first_multi_line_comment_end > -1)
78  {
79  multi_line_comment = false;
80  if (first_multi_line_comment_end+language.streamCommentEnd.Length() < line.Length())
81  AnalyseLine(language, line.Mid(first_multi_line_comment_end+language.streamCommentEnd.Length()), comment, code, multi_line_comment);
82  }
83  }
84  // We are not in a multiple line comment
85  else if (!multi_line_comment)
86  {
87  // First comment sign found is a single line comment sign
88  if ( (first_single_line_comment>-1)
89  &&((first_multi_line_comment_begin==-1)||((first_multi_line_comment_begin>-1)&&(first_single_line_comment<first_multi_line_comment_begin))) )
90  {
91  comment = true;
92  if (first_single_line_comment > 0)
93  code = true;
94  }
95  // First comment sign found is a multi-line comment begin sign
96  else if (first_multi_line_comment_begin>-1)
97  {
98  multi_line_comment = true;
99  comment = true;
100  if (first_multi_line_comment_begin > 0)
101  code = true;
102  if (first_multi_line_comment_begin+language.streamCommentStart.Length() < line.Length())
103  AnalyseLine(language, line.Mid(first_multi_line_comment_begin+language.streamCommentStart.Length()), comment, code, multi_line_comment);
104  }
105  else
106  {
107  code = true;
108  }
109  }
110 }
111 
112 inline void CountLines(wxFileName filename, const CommentToken &language,
113  long int &code_lines, long int &codecomments_lines,
114  long int &comment_lines, long int &empty_lines,
115  long int &total_lines)
116 {
117  wxTextFile file;
118  if (file.Open(filename.GetFullPath(), wxConvFile))
119  {
120  bool multi_line_comment = false;
121  total_lines += file.GetLineCount();
122  for (unsigned int i = 0; i < file.GetLineCount(); ++i)
123  {
124  wxString line = file[i];
125  line = line.Trim(true);
126  line = line.Trim(false);
127  bool comment = false;
128  bool code = false;
129  if (line.IsEmpty())
130  {
131  ++empty_lines;
132  }
133  else
134  {
135  AnalyseLine(language, line, comment, code, multi_line_comment);
136  if (comment&&code) ++codecomments_lines;
137  else if (comment) ++comment_lines;
138  else if (code) ++code_lines;
139  }
140  } // end for : idx : i
141  }
142 }
143 
145  m_ProjectFile(pf),
146  m_FileNameStr(wxEmptyString),
147  m_FileName(),
148  m_LastBuildStageCompilerSel(-1)
149 {
150  wxXmlResource::Get()->LoadObject(this, parent, _T("dlgProjectFileOptions"),_T("wxScrollingDialog"));
151  XRCCTRL(*this, "wxID_OK", wxButton)->SetDefault();
152 
153  if (pf)
154  {
155  cbProject* prj = pf->GetParentProject();
156  wxCheckListBox *list = XRCCTRL(*this, "lstTargets", wxCheckListBox);
157  for (int i = 0; i < prj->GetBuildTargetsCount(); ++i)
158  {
159  wxString targetName = prj->GetBuildTarget(i)->GetTitle();
160  list->Append(targetName);
161  if (pf->buildTargets.Index(targetName) != -1)
162  list->Check(i, true);
163  }
164 
167 
168  XRCCTRL(*this, "txtCompiler", wxTextCtrl)->SetValue(pf->compilerVar);
169  XRCCTRL(*this, "chkCompile", wxCheckBox)->SetValue(pf->compile);
170  XRCCTRL(*this, "chkLink", wxCheckBox)->SetValue(pf->link);
171  XRCCTRL(*this, "sliderWeight", wxSlider)->SetValue(pf->weight);
172  XRCCTRL(*this, "txtObjName", wxTextCtrl)->SetValue(pf->GetObjName());
173 
174  FillCompilers();
176 
177  XRCCTRL(*this, "txtProject", wxTextCtrl)->SetValue(prj?(prj->GetTitle() + _T("\n") + prj->GetFilename()):_T("-"));
178  XRCCTRL(*this, "txtProjectBasePath", wxTextCtrl)->SetValue(prj?prj->GetCommonTopLevelPath():_T("-"));
179  XRCCTRL(*this, "txtAbsName", wxTextCtrl)->SetValue(m_FileNameStr);
180  XRCCTRL(*this, "txtRelName", wxTextCtrl)->SetValue(pf->relativeFilename);
181 
182  SetTitle(_("Properties of ") + wxString(_("\"")) + pf->relativeFilename + wxString(_("\"")));
183  }
184  XRCCTRL(*this, "txtObjName", wxTextCtrl)->Enable(false);
185  // included files not implemented yet -> hide it
186  XRCCTRL(*this, "staticIncludedFilesLabel", wxStaticText)->Hide();
187  XRCCTRL(*this, "staticIncludedFiles", wxStaticText)->Hide();
188 
189  if (pf->AutoGeneratedBy())
190  {
191  XRCCTRL(*this, "tabBuild", wxPanel)->Enable(false);
192  XRCCTRL(*this, "tabAdvanced", wxPanel)->Enable(false);
193  }
194  XRCCTRL(*this, "lblAutoGen", wxStaticText)->Show(pf->AutoGeneratedBy());
195 }
196 
199  m_FileNameStr(fileName),
200  m_FileName(),
202 {
203  wxXmlResource::Get()->LoadObject(this, parent, _T("dlgProjectFileOptions"),_T("wxScrollingDialog"));
204  XRCCTRL(*this, "wxID_OK", wxButton)->SetDefault();
205 
207 
208  XRCCTRL(*this, "txtAbsName", wxTextCtrl)->SetValue(m_FileNameStr);
209  // This must be always hidden for non-project files.
210  XRCCTRL(*this, "lblAutoGen", wxStaticText)->Show(false);
211 
212  SetTitle(_("Properties of ") + wxString(_("\"")) + m_FileNameStr + wxString(_("\"")));
213 }
214 
216 {
217 }
218 
220 {
222  return;
223 
224  if (event.IsChecked())
225  {
226  // make read-only
227  if ( !ToggleFileReadOnly(true) )
228  Manager::Get()->GetLogManager()->DebugLog(F(_T("Unable to set file '%s' read-only (probably missing access rights)."), m_FileNameStr.wx_str()));
229  }
230  else
231  {
232  // make writeable
233  if ( !ToggleFileReadOnly(false) )
234  Manager::Get()->GetLogManager()->DebugLog(F(_T("Unable to set file '%s' writeable (probably missing access rights)."), m_FileNameStr.wx_str()));
235  }
236 
237  // Update UI
238  XRCCTRL(*this, "chkReadOnly", wxCheckBox)->SetValue(!m_FileName.IsFileWritable());
239 
241 }
242 
244 {
245  if (m_LastBuildStageCompilerSel != event.GetSelection())
246  {
247  // first save old selection
249  m_LastBuildStageCompilerSel = event.GetSelection();
250 
251  // then load new selection
253  }
254 }
255 
257 {
258  if (m_ProjectFile)
259  {
260  bool en = XRCCTRL(*this, "chkBuildStage", wxCheckBox)->GetValue();
261  XRCCTRL(*this, "txtBuildStage", wxTextCtrl)->Enable(en);
262  }
263  else
264  {
265  XRCCTRL(*this, "txtCompiler", wxTextCtrl)->Enable(false);
266  XRCCTRL(*this, "lstTargets", wxCheckListBox)->Enable(false);
267  XRCCTRL(*this, "chkCompile", wxCheckBox)->Enable(false);
268  XRCCTRL(*this, "chkLink", wxCheckBox)->Enable(false);
269  XRCCTRL(*this, "txtObjName", wxTextCtrl)->Enable(false);
270  XRCCTRL(*this, "chkBuildStage", wxCheckBox)->Enable(false);
271  XRCCTRL(*this, "txtBuildStage", wxTextCtrl)->Enable(false);
272  XRCCTRL(*this, "sliderWeight", wxSlider)->Enable(false);
273  }
274 }
275 
277 {
278  if (retCode == wxID_OK && m_ProjectFile)
279  {
280  wxCheckListBox *list = XRCCTRL(*this, "lstTargets", wxCheckListBox);
281  for (size_t i = 0; i < list->GetCount(); i++)
282  {
283  if (list->IsChecked(i))
285  else
287  }
288 
289  m_ProjectFile->compile = XRCCTRL(*this, "chkCompile", wxCheckBox)->GetValue();
290  m_ProjectFile->link = XRCCTRL(*this, "chkLink", wxCheckBox)->GetValue();
291  m_ProjectFile->weight = XRCCTRL(*this, "sliderWeight", wxSlider)->GetValue();
292 // m_ProjectFile->SetObjName(XRCCTRL(*this, "txtObjName", wxTextCtrl)->GetValue());
294  m_ProjectFile->compilerVar = XRCCTRL(*this, "txtCompiler", wxTextCtrl)->GetValue();
295 
296  // make sure we have a compiler var, if the file is to be compiled
298  m_ProjectFile->compilerVar = _T("CPP");
299 
301  prj->SetModified(true);
303  }
304 
306 }
307 
309 {
310  // count some statistics of the file
312  if (!m_FileName.FileExists())
313  return;
314 
316  if (!colour_set)
317  return;
318 
319  const HighlightLanguage& lang = colour_set->GetLanguageForFilename(m_FileNameStr);
320  if (lang != HL_NONE)
321  {
322  long int total_lines = 0;
323  long int code_lines = 0;
324  long int empty_lines = 0;
325  long int comment_lines = 0;
326  long int codecomments_lines = 0;
327  CountLines(m_FileName, colour_set->GetCommentToken(lang), code_lines, codecomments_lines, comment_lines, empty_lines, total_lines);
328  XRCCTRL(*this, "staticTotalLines", wxStaticText)->SetLabel(wxString::Format(_T("%ld"), total_lines));
329  XRCCTRL(*this, "staticEmptyLines", wxStaticText)->SetLabel(wxString::Format(_T("%ld"), empty_lines));
330  XRCCTRL(*this, "staticActualLines", wxStaticText)->SetLabel(wxString::Format(_T("%ld"), code_lines + codecomments_lines));
331  XRCCTRL(*this, "staticCommentLines", wxStaticText)->SetLabel(wxString::Format(_T("%ld"), comment_lines));
332  XRCCTRL(*this, "staticEmptyLines", wxStaticText)->GetContainingSizer()->Layout();
333  }
334  wxFile file(m_FileName.GetFullPath());
335  if (file.IsOpened())
336  {
337  long length = static_cast<long>(file.Length());
338  XRCCTRL(*this, "staticFileSize", wxStaticText)->SetLabel(wxString::Format(_("%ld Bytes"), length));
339  XRCCTRL(*this, "staticFileSize", wxStaticText)->GetContainingSizer()->Layout();
340  file.Close();
341  }
342  XRCCTRL(*this, "chkReadOnly", wxCheckBox)->SetValue(!m_FileName.IsFileWritable());
344  XRCCTRL(*this, "staticDateTimeStamp", wxStaticText)->SetLabel(
345  wxString::Format(_("%02hd/%02hd/%d %02hd:%02hd:%02hd"), modTime.GetDay(),
346  modTime.GetMonth() + 1, modTime.GetYear(), modTime.GetHour(), // seems I have to add 1 for the month ?
347  modTime.GetMinute(), modTime.GetSecond())); // because the return value of GetMonth() is an enum
348 }
349 
351 {
352  // fill compilers combo
353  wxChoice* cmb = XRCCTRL(*this, "cmbBuildStageCompiler", wxChoice);
354  cmb->Clear();
355  for (unsigned int i = 0; i < CompilerFactory::GetCompilersCount(); ++i)
356  {
357  Compiler* compiler = CompilerFactory::GetCompiler(i);
358  if (compiler)
359  cmb->Append(compiler->GetName());
360  }
361  // select project default compiler
364 }
365 
367 {
368  wxChoice* cmb = XRCCTRL(*this, "cmbBuildStageCompiler", wxChoice);
369  int idx = cmb->GetSelection();
370  Compiler* compiler = CompilerFactory::GetCompiler(idx);
371  if (!compiler)
372  return;
373 
375  wxString cmd;
376  if (ft == ftResource)
377  cmd = compiler->GetCommand(ctCompileResourceCmd);
378  else if (ft == ftSource || ft == ftHeader)
379  cmd = compiler->GetCommand(ctCompileObjectCmd);
380  XRCCTRL(*this, "lblBuildCommand", wxStaticText)->SetLabel(_("Default: ") + cmd);
381  Layout();
382 
383  XRCCTRL(*this, "chkBuildStage", wxCheckBox)->SetValue(m_ProjectFile->customBuild[compiler->GetID()].useCustomBuildCommand);
384  XRCCTRL(*this, "txtBuildStage", wxTextCtrl)->SetValue(m_ProjectFile->customBuild[compiler->GetID()].buildCommand);
385 }
386 
388 {
390  if (compiler)
391  {
392  m_ProjectFile->customBuild[compiler->GetID()].useCustomBuildCommand = XRCCTRL(*this, "chkBuildStage", wxCheckBox)->GetValue();
393  m_ProjectFile->customBuild[compiler->GetID()].buildCommand = XRCCTRL(*this, "txtBuildStage", wxTextCtrl)->GetValue();
394  }
395 }
396 
398 {
399 #ifdef __WXMSW__
400  // Check for failure
401  const int MS_MODE_MASK = 0x0000ffff; // low word
402  int mask = setReadOnly ? _S_IREAD : ( _S_IREAD | _S_IWRITE );
403  int res = _chmod(m_FileNameStr.mb_str(wxConvUTF8), mask & MS_MODE_MASK);
404  if (res != 0)
405  {
406  if (errno == ENOENT)
407  Manager::Get()->GetLogManager()->DebugLog(_T("Error calling chmod (ENOENT)."));
408  else if (errno == EINVAL)
409  Manager::Get()->GetLogManager()->DebugLog(_T("Error calling chmod (EINVAL)."));
410  else if (errno == EBADF)
411  Manager::Get()->GetLogManager()->DebugLog(_T("Error calling chmod (EBADF)."));
412  else
413  Manager::Get()->GetLogManager()->DebugLog(_T("Error calling chmod."));
414  return false; // chmod error
415  }
416 #else
417  const int X_MODE_MASK = S_IRGRP | S_IROTH; // should be always the case
418  int mask = setReadOnly ? S_IRUSR : ( S_IRUSR | S_IWUSR );
419  int res = chmod(m_FileNameStr.mb_str(wxConvUTF8), mask | X_MODE_MASK);
420  if (res != 0)
421  {
422  Manager::Get()->GetLogManager()->DebugLog(F(_T("Error calling chmod : errno = %d."), errno));
423  return false; // chmod error
424  }
425 
426 #endif
427 
428  return ( ( setReadOnly && !m_FileName.IsFileWritable())
429  || (!setReadOnly && m_FileName.IsFileWritable()) );
430 }
wxString F(const wxChar *msg,...)
sprintf-like function
Definition: logmanager.h:20
void EndModal(int retCode)
Definition: sc_dialog.cpp:112
unsigned short int weight
The weight.
Definition: projectfile.h:145
void OnCompilerCombo(wxCommandEvent &event)
bool ToggleFileReadOnly(bool setReadOnly)
void AnalyseLine(const CommentToken &language, wxString line, bool &comment, bool &code, bool &multi_line_comment)
wxString relativeFilename
The relative (to the project) filename of this file.
Definition: projectfile.h:131
void OnUpdateUI(wxUpdateUIEvent &event)
void Assign(const wxFileName &filepath)
virtual void RebuildTree()=0
Rebuild the project manager&#39;s tree.
static Manager * Get()
Use Manager::Get() to get a pointer to its instance Manager::Get() is guaranteed to never return an i...
Definition: manager.cpp:182
virtual int GetSelection() const
virtual wxString GetString(unsigned int n) const
const wxString & GetObjName()
wxFileName file
The full filename of this file.
Definition: projectfile.h:126
HighlightLanguage GetLanguageForFilename(const wxString &filename)
bool compile
Compile flag.
Definition: projectfile.h:138
int Index(const wxString &sz, bool bCase=true, bool bFromEnd=false) const
void SetModified(bool modified=true) override
Mark the project as modified or not.
Definition: cbproject.cpp:179
static Compiler * GetCompiler(size_t index)
static int GetCompilerIndex(const wxString &id)
void CountLines(wxFileName filename, const CommentToken &language, long int &code_lines, long int &codecomments_lines, long int &comment_lines, long int &empty_lines, long int &total_lines)
#define _T(string)
size_t GetLineCount() const
FileType
Known file types.
Definition: globals.h:49
cbProjectManagerUI & GetUI()
const wxCharBuffer mb_str(const wxMBConv &conv=wxConvLibc) const
DLLIMPORT FileType FileTypeOf(const wxString &filename)
Definition: globals.cpp:285
Compile object command, e.g. "$compiler $options $includes -c $file -o $object".
Definition: compiler.h:168
bool IsChecked(unsigned int item) const
Represents a file in a Code::Blocks project.
Definition: projectfile.h:39
CommentToken GetCommentToken(HighlightLanguage lang)
virtual const wxString & GetCommand(CommandType ct, const wxString &fileExtension=wxEmptyString) const
Get a command based on CommandType.
Definition: compiler.cpp:305
Month GetMonth(const TimeZone &tz=Local) const
EditorManager * GetEditorManager() const
Definition: manager.cpp:434
ProjectManager * GetProjectManager() const
Functions returning pointers to the respective sub-manager instances.
Definition: manager.cpp:429
const wxString & GetID() const
Get this compiler&#39;s unique ID.
Definition: compiler.h:351
Represents a Code::Blocks project.
Definition: cbproject.h:96
virtual const wxString & GetFilename() const
null_pointer_t nullptr
Definition: nullptr.cpp:16
virtual const wxString & GetTitle() const
Read the target&#39;s title.
void RemoveBuildTarget(const wxString &targetName)
Remove this file from the specified build target.
bool Close()
void Check(unsigned int item, bool check=true)
#define HL_NONE
Definition: globals.h:167
unsigned short GetSecond(const TimeZone &tz=Local) const
LogManager * GetLogManager() const
Definition: manager.cpp:439
pfCustomBuildMap customBuild
A map for custom builds.
Definition: projectfile.h:184
bool IsFileWritable() const
const wxStringCharType * wx_str() const
unsigned short GetDay(const TimeZone &tz=Local) const
wxString wxEmptyString
bool Open(const wxMBConv &conv=wxConvAuto())
const wxString & _(const wxString &string)
wxString & Trim(bool fromRight=true)
int GetBuildTargetsCount()
Definition: cbproject.h:200
wxString compilerVar
The compiler variable used for this file (e.g CPP, CC, etc).
Definition: projectfile.h:187
void CheckForExternallyModifiedFiles()
Check if one of the open files has been modified outside the IDE.
ProjectBuildTarget * GetBuildTarget(int index)
Access a build target.
Definition: cbproject.cpp:1392
Compile Win32 resources command, e.g. "$rescomp -i $file -J rc -o $resource_output -O coff $includes"...
Definition: compiler.h:170
Abstract base class for compilers.
Definition: compiler.h:274
EditorColourSet * GetColourSet()
bool IsEmpty() const
void EndModal(int retCode) override
virtual const wxString & GetCompilerID() const
Read the target&#39;s compiler.
unsigned short GetMinute(const TimeZone &tz=Local) const
void OnReadOnlyCheck(wxCommandEvent &event)
virtual const wxString & GetName() const
Get the compiler&#39;s name.
Definition: compiler.h:293
void DebugLog(const wxString &msg, Logger::level lv=Logger::info)
Definition: logmanager.h:146
int GetYear(const TimeZone &tz=Local) const
wxString GetCommonTopLevelPath() const
Definition: cbproject.cpp:423
cbProject * GetParentProject()
Definition: projectfile.h:93
static size_t GetCompilersCount()
ProjectFile * AutoGeneratedBy() const
If this is an auto-generated file, which file is generating it?
Definition: projectfile.h:201
static wxXmlResource * Get()
ProjectFileOptionsDlg(wxWindow *parent, ProjectFile *pf)
bool FileExists() const
void AddBuildTarget(const wxString &targetName)
Make this file belong to an additional build target.
Definition: projectfile.cpp:78
unsigned short GetHour(const TimeZone &tz=Local) const
wxDateTime GetModificationTime() const
virtual void SetSelection(int n)
wxString GetFullPath(wxPathFormat format=wxPATH_NATIVE) const
static wxString Format(const wxString &format,...)
wxObject * LoadObject(wxWindow *parent, const wxString &name, const wxString &classname)
virtual unsigned int GetCount() const
wxArrayString buildTargets
An array of strings, containing the names of all the build targets this file belongs to...
Definition: projectfile.h:190