#include "AnalyseGui.h"
#include "Analyse.h"
#define IMAGECLASS Images
#define IMAGEFILE <CodeMetric/AnalyseGui.iml>
#include <Draw/iml.h>
String defaultCode =
"/*"
" This tool measures certain source code metrics.\n"
" You can type, paste, or load the code you would like measure into this text area.\n"
" Metrics provided are:\n"
" - Cyclomatic complexity 1: counts the decision points per method, thus estimating the\n"
" number of testcases needed for each method.\n"
" - Cyclomatic complexity 2: CC1 extended with the implicit decisions created by the\n"
" && || and ?: operators. Evaluation:\n"
" CC2 1-10 simple, low risk method\n"
" CC2 10-20 moderate complexity & risk method\n"
" CC2 21-50 high complexity & risk method\n"
" CC2 >50 too complex, untestable method, should be refactored\n"
" - Depth: measures deepest scope embedding level per method. This estimates the human\n"
" memory needed to keep in mind the current context. Any methods with depth > 5 is\n"
" considered too complex, and candidate for refactoring\n"
" - Logical Lines Of Code: estimates the amount of source code per method in a way\n"
" which is mostly independent from code formatting style. Methods longer than 80 LLOC are\n"
" too long, and should be refactored.\n"
"*/\n"
"int main()\n"
"{\n"
" return 0;\n"
"}\n";
String defaultTitle = "CodeMetric GUI";
WarningDisplay::WarningDisplay(int limit, Color warningColor) :
limit(limit), warningColor(warningColor)
{
}
void WarningDisplay::PaintBackground(Draw& w, const Rect& r, const Value& q,
Color ink, Color paper, dword style) const
{
int v = (int)q;
if(v >= limit)
paper = warningColor;
Display::PaintBackground(w, r, q, ink, paper, style);
}
void AnalyseGui::MainMenu(Bar &bar)
{
bar.Add("Load file", THISBACK(Open));
}
void AnalyseGui::Open()
{
FileSelector fsel;
fsel.ExecuteOpen("Select file");
String fileName = fsel.Get();
if(fileName == "")
return;
source <<= LoadFile(fileName);
UpdateMetric();
Title(defaultTitle + " [" + fileName + "]");
}
void AnalyseGui::UpdateMetric()
{
String s = ~source;
CodeMetric metric(s);
chart.Clear();
for(int i = 0; i < metric.functions.GetCount(); i++)
{
CodeMetric::FunctionEntry & entry =
metric.functions[i];
chart.Add(entry.name,
entry.pos,
entry.cyclomaticComplexity1,
entry.cyclomaticComplexity2,
entry.logicalLinesOfCode,
entry.scopeDepth);
}
textMetric.SetData(metric.ToString());
}
void AnalyseGui::GotoFunction()
{
int cursor = chart.GetCursor();
if(cursor >= 0 && cursor < chart.GetCount())
{
int pos = (int)chart.Get(cursor, 1);
source.SetCursor( source.GetPos(pos) );
source.CenterCursor();
}
}
AnalyseGui::AnalyseGui() :
ccDisplay(50), llocDisplay(80), depthDisplay(5)
{
Title(defaultTitle);
Icon(Images::GaugeIcon);
AddFrame(menu);
menu.Set( THISBACK(MainMenu) );
source <<= THISBACK(UpdateMetric);
source <<= defaultCode;
textMetric.SetEditable(false);
chart.AddColumn("Function", 80);
chart.AddColumn("Pos", 15);
chart.AddColumn("CC1", 15).SetDisplay(ccDisplay);
chart.AddColumn("CC2", 15).SetDisplay(ccDisplay);
chart.AddColumn("LLOC", 15).SetDisplay(llocDisplay);
chart.AddColumn("Depth", 15).SetDisplay(depthDisplay);
chart.WhenLeftDouble = THISBACK(GotoFunction);
UpdateMetric();
splitter.Vert() << source << chart << textMetric;
splitter.SetPos(9000, 1);
splitter.SetPos(6500, 0);
Add(splitter.SizePos());
Sizeable().Zoomable();
}
GUI_APP_MAIN
{
AnalyseGui().Run();
}
syntax highlighted by Code2HTML, v. 0.9.1