1
/***************************************************************
2
* Name: codestatexec.cpp
3
* Purpose: Code::Blocks CodeStat plugin: main window
8
**************************************************************/
12
#include <wx/stattext.h>
13
#include <wx/string.h>
14
#include <wx/xrc/xmlres.h>
15
#include "cbproject.h"
16
#include "configmanager.h"
17
#include "editormanager.h"
20
#include "logmanager.h"
21
#include "projectfile.h"
22
#include "projectmanager.h"
25
#include <wx/progdlg.h>
26
#include <wx/textfile.h>
27
#include "codestatexec.h"
29
/** Count the lines on all project's files and display the results.
30
* @param languages Languages definitions
31
* @param nb_languages Number of languages defined in the 'languages' array
33
int CodeStatExecDlg::Execute(LanguageDef languages[NB_FILETYPES_MAX], int nb_languages)
35
cbProject* project = Manager::Get()->GetProjectManager()->GetActiveProject();
36
long nb_files = project->GetFilesCount();
37
//wxMessageBox(wxString::Format(_T("Nb files: %ld"), nb_files), _("Error"), wxOK);
39
// Check if all files have been saved
40
bool all_files_saved = true;
41
for (int i=0; i<nb_files; ++i)
42
if (project->GetFile(i)->GetFileState() == fvsModified)
43
all_files_saved = false;
44
// If not, ask user if we can save them
47
if (cbMessageBox(_T("Some files are not saved.\nDo you want to save them before running the plugin?"), _("Warning"), wxICON_EXCLAMATION | wxYES_NO, Manager::Get()->GetAppWindow()) == wxID_YES)
49
for (int i=0; i<nb_files; ++i)
51
if (project->GetFile(i)->GetFileState() == fvsModified)
52
Manager::Get()->GetEditorManager()->Save(project->GetFile(i)->file.GetFullPath());
57
// Count code statistics on each file
58
long nb_files_not_found = 0;
59
long nb_skipped_files = 0;
63
long comment_lines = 0;
64
long codecomments_lines = 0;
66
wxProgressDialog progress(_("Code Statistics plugin"),_("Parsing project files. Please wait..."));
67
for (int i=0; i<nb_files; ++i)
69
ProjectFile* pf = project->GetFile(i);
70
wxFileName filename(pf->file.GetFullPath(), wxPATH_DOS);
71
if (!filename.FileExists())
74
//Manager::Get()->GetLogManager()->DebugLog(_T("Code Statistics: Ignoring file '%s' (file not found)"), filename.GetName());
78
// Find the language associated to the file extension
79
int num_language = -1;
80
for (int l = 0; l<nb_languages; ++l)
82
for (int j = 0; j<(int)languages[l].ext.Count(); ++j)
84
if (filename.GetExt() == languages[l].ext[j])
89
// If the language is found, analyse the source file
90
if (num_language > -1)
91
CountLines(filename, languages[num_language], code_lines, codecomments_lines, comment_lines, empty_lines, total_lines);
92
else ++nb_skipped_files;
95
progress.Update((100*i)/(nb_files-1));
99
// Setting-up the statistics dialog box
100
wxXmlResource::Get()->LoadDialog(this, parent, _T("dlgCodeStatExec"));
102
wxStaticText* txt_num_files = XRCCTRL(*this, "txt_num_files", wxStaticText);
103
txt_num_files->SetLabel(wxString::Format(_("%ld"), nb_files));
104
wxStaticText* txt_skipped_files = XRCCTRL(*this, "txt_skipped_files", wxStaticText);
105
txt_skipped_files->SetLabel(wxString::Format(_("%ld"), nb_skipped_files));
106
wxStaticText* txt_files_not_found = XRCCTRL(*this, "txt_files_not_found", wxStaticText);
107
txt_files_not_found->SetLabel(wxString::Format(_("%ld"), nb_files_not_found));
109
wxStaticText* txt_Code = XRCCTRL(*this, "txt_Code", wxStaticText);
110
txt_Code->SetLabel(wxString::Format(_("%ld"), code_lines));
111
wxStaticText* txt_Empty = XRCCTRL(*this, "txt_Empty", wxStaticText);
112
txt_Empty->SetLabel(wxString::Format(_("%ld"), empty_lines));
113
wxStaticText* txt_Comments = XRCCTRL(*this, "txt_Comments", wxStaticText);
114
txt_Comments->SetLabel(wxString::Format(_("%ld"), comment_lines));
115
wxStaticText* txt_Code_Comments = XRCCTRL(*this, "txt_Code_Comments", wxStaticText);
116
txt_Code_Comments->SetLabel(wxString::Format(_("%ld"), codecomments_lines));
117
wxStaticText* txt_Total = XRCCTRL(*this, "txt_Total", wxStaticText);
118
txt_Total->SetLabel(wxString::Format(_("%ld"), total_lines));
120
// If the project is not empty, display the main dialog box
121
if(total_lines) // avoid division by zero on empty document
123
int icode = static_cast<int>(round(static_cast<double>(100 * code_lines) / static_cast<double>(total_lines)));
124
wxGauge* Gauge_Code = XRCCTRL(*this, "Gauge_Code", wxGauge);
125
Gauge_Code->SetValue(icode);
126
wxStaticText* txt_Gauge_Code = XRCCTRL(*this, "txt_Gauge_Code", wxStaticText);
127
txt_Gauge_Code->SetLabel(wxString::Format(_("%3d%% Code only"), icode));
129
int icode_comments = static_cast<int>(round(static_cast<double>(100 * codecomments_lines) / static_cast<double>(total_lines)));
130
wxGauge* Gauge_Code_Comments = XRCCTRL(*this, "Gauge_Code_Comments", wxGauge);
131
Gauge_Code_Comments->SetValue(icode_comments);
132
wxStaticText* txt_Gauge_Code_Comments = XRCCTRL(*this, "txt_Gauge_Code_Comments", wxStaticText);
133
txt_Gauge_Code_Comments->SetLabel(wxString::Format(_("%3d%% Code + Comment"), icode_comments));
135
int icomments = static_cast<int>(round(static_cast<double>(100 * comment_lines) / static_cast<double>(total_lines)));
136
wxGauge* Gauge_Comments = XRCCTRL(*this, "Gauge_Comments", wxGauge);
137
Gauge_Comments->SetValue(icomments);
138
wxStaticText* txt_Gauge_Comments = XRCCTRL(*this, "txt_Gauge_Comments", wxStaticText);
139
txt_Gauge_Comments->SetLabel(wxString::Format(_("%3d%% Comments"), icomments));
141
int iempty = static_cast<int>(round(static_cast<double>(100 * empty_lines) / static_cast<double>(total_lines)));
142
wxGauge* Gauge_Empty = XRCCTRL(*this, "Gauge_Empty", wxGauge);
143
Gauge_Empty->SetValue(iempty);
144
wxStaticText* txt_Gauge_Empty = XRCCTRL(*this, "txt_Gauge_Empty", wxStaticText);
145
txt_Gauge_Empty->SetLabel(wxString::Format(_("%3d%% Empty"), iempty));
149
else cbMessageBox(_("The project is empty!"), _("Warning"), wxICON_EXCLAMATION | wxOK, Manager::Get()->GetAppWindow());
154
void CodeStatExecDlg::EndModal(int retCode)
156
wxDialog::EndModal(retCode);
159
/** This function analyses a given source file and count the lines of code, comments etc...
161
void CodeStatExecDlg::CountLines(wxFileName filename, LanguageDef &language,
162
long int &code_lines, long int &codecomments_lines,
163
long int &comment_lines, long int &empty_lines, long int &total_lines)
166
if (file.Open(filename.GetFullPath(),wxConvFile))
168
bool multi_line_comment = false;
169
total_lines += file.GetLineCount();
170
for (unsigned int i=0; i<file.GetLineCount(); ++i)
172
wxString line(file[i]);
173
line = line.Trim(true);
174
line = line.Trim(false);
175
bool comment = false;
181
AnalyseLine(language, line, comment, code, multi_line_comment);
182
if (comment&&code) ++codecomments_lines;
183
else if (comment) ++comment_lines;
184
else if (code) ++code_lines;
190
/** This function determines the caracteristics of a given line (code line, comment line etc...).
191
* It is called by the "CountLines" function.
194
void CodeStatExecDlg::AnalyseLine(LanguageDef &language, wxString line, bool &comment, bool &code, bool &multi_line_comment)
196
int first_single_line_comment, first_multi_line_comment_begin, first_multi_line_comment_end;
198
// Delete first and trailing spaces
199
line = line.Trim(true);
200
line = line.Trim(false);
205
// Searching for single and multi-lines comment signs
206
if (language.single_line_comment.Length() > 0)
207
first_single_line_comment = line.Find(language.single_line_comment);
208
else first_single_line_comment = -1;
209
if (language.multiple_line_comment[0].Length() > 0)
210
first_multi_line_comment_begin = line.Find(language.multiple_line_comment[0]);
211
else first_multi_line_comment_begin = -1;
212
if (language.multiple_line_comment[1].Length() > 0)
213
first_multi_line_comment_end = line.Find(language.multiple_line_comment[1]);
214
else first_multi_line_comment_end = -1;
216
// We are in a multiple line comment => finding the "end of multiple line comment" sign
217
if (multi_line_comment)
220
if (first_multi_line_comment_end > -1)
222
multi_line_comment = false;
223
if (first_multi_line_comment_end+language.multiple_line_comment[1].Length() < line.Length())
224
AnalyseLine(language, line.Mid(first_multi_line_comment_end+language.multiple_line_comment[1].Length()), comment, code, multi_line_comment);
227
// We are not in a multiple line comment
228
else if (!multi_line_comment)
230
// First comment sign found is a single line comment sign
231
if ( (first_single_line_comment>-1)
232
&&((first_multi_line_comment_begin==-1)||((first_multi_line_comment_begin>-1)&&(first_single_line_comment<first_multi_line_comment_begin))) )
235
if (first_single_line_comment > 0)
238
// First comment sign found is a multi-line comment begin sign
239
else if (first_multi_line_comment_begin>-1)
241
multi_line_comment = true;
243
if (first_multi_line_comment_begin > 0)
245
if (first_multi_line_comment_begin+language.multiple_line_comment[0].Length() < line.Length())
246
AnalyseLine(language, line.Mid(first_multi_line_comment_begin+language.multiple_line_comment[0].Length()), comment, code, multi_line_comment);
255
CodeStatExecDlg::~CodeStatExecDlg()