// THIS FILE IS PROVIDED FOR INFORMATIONAL PURPOSE ONLY.
// NO COMERCIAL USE!!!
// Information: decl_spec@yahoo.com
#include "stdafx.h"
#include "LineCounter.h"
#include "LineCounterDlg.h"
#include "linecounter_.h"
#include "lcprojectparser.h"
#include "ViewCodeDlg.h"
#ifdef _DEBUG
#define new DEBUG_NEW
#undef THIS_FILE
static char THIS_FILE[] = __FILE__;
#endif
class CAboutDlg : public CDialog
{
public:
CAboutDlg();
// Dialog Data
//{{AFX_DATA(CAboutDlg)
enum { IDD = IDD_ABOUTBOX };
//}}AFX_DATA
// ClassWizard generated virtual function overrides
//{{AFX_VIRTUAL(CAboutDlg)
protected:
virtual void DoDataExchange(CDataExchange* pDX); // DDX/DDV support
//}}AFX_VIRTUAL
// Implementation
protected:
//{{AFX_MSG(CAboutDlg)
//}}AFX_MSG
DECLARE_MESSAGE_MAP()
};
CAboutDlg::CAboutDlg() : CDialog(CAboutDlg::IDD)
{
//{{AFX_DATA_INIT(CAboutDlg)
//}}AFX_DATA_INIT
}
void CAboutDlg::DoDataExchange(CDataExchange* pDX)
{
CDialog::DoDataExchange(pDX);
//{{AFX_DATA_MAP(CAboutDlg)
//}}AFX_DATA_MAP
}
BEGIN_MESSAGE_MAP(CAboutDlg, CDialog)
//{{AFX_MSG_MAP(CAboutDlg)
// No message handlers
//}}AFX_MSG_MAP
END_MESSAGE_MAP()
CLineCounterDlg::CLineCounterDlg(CWnd* pParent /*=NULL*/) : m_compare_struct(NULL), m_imagelist(NULL),
CDialog(CLineCounterDlg::IDD, pParent)
{
//{{AFX_DATA_INIT(CLineCounterDlg)
//}}AFX_DATA_INIT
// Note that LoadIcon does not require a subsequent DestroyIcon in Win32
m_hIcon = AfxGetApp()->LoadIcon(IDR_MAINFRAME);
}
CLineCounterDlg::~CLineCounterDlg()
{
delete [] m_compare_struct;
delete m_imagelist;
}
void CLineCounterDlg::DoDataExchange(CDataExchange* pDX)
{
CDialog::DoDataExchange(pDX);
//{{AFX_DATA_MAP(CLineCounterDlg)
DDX_Control(pDX, ID_LINES_TOTAL, m_LinesTotal);
DDX_Control(pDX, ID_LINES_SOURCE, m_LinesSource);
DDX_Control(pDX, ID_LINES_COMMENT, m_LinesComment);
DDX_Control(pDX, ID_LINES_BLANK, m_LinesBlank);
DDX_Control(pDX, ID_PROGRESS_LABEL, m_ProgressLabel);
DDX_Control(pDX, ID_PROGRESSBAR, m_Progress);
DDX_Control(pDX, ID_PROJECTNAME, m_ProjectName);
DDX_Control(pDX, ID_FILELIST, m_FileList);
//}}AFX_DATA_MAP
}
BEGIN_MESSAGE_MAP(CLineCounterDlg, CDialog)
//{{AFX_MSG_MAP(CLineCounterDlg)
ON_COMMAND(ID_FILE_EXIT, OnFileExit)
ON_NOTIFY(LVN_COLUMNCLICK, ID_FILELIST, OnColumnclickFilelist)
ON_COMMAND(ID_FILE_SELECTPROJECT, OnFileSelectproject)
ON_COMMAND(ID_FILE_COUNT, OnFileCount)
ON_WM_CLOSE()
ON_NOTIFY(NM_RCLICK, ID_FILELIST, OnRclickFilelist)
ON_COMMAND(ID_SOURCE_VIEW, OnSourceView)
ON_COMMAND(ID_HELP_ABOUT, OnHelpAbout)
//}}AFX_MSG_MAP
END_MESSAGE_MAP()
/////////////////////////////////////////////////////////////////////////////
// CLineCounterDlg message handlers
BOOL CLineCounterDlg::OnInitDialog()
{
CDialog::OnInitDialog();
UpdateData(TRUE);
HMENU sys_menu = ::GetSystemMenu(GetSafeHwnd(), FALSE);
RemoveMenu(sys_menu, 2, MF_BYPOSITION);
RemoveMenu(sys_menu, 3, MF_BYPOSITION);
SetIcon(m_hIcon, TRUE); // Set big icon
SetIcon(m_hIcon, FALSE); // Set small icon
ListView_SetExtendedListViewStyle(m_FileList.GetSafeHwnd(), LVS_EX_FULLROWSELECT);
m_FileList.InsertColumn(0, "File Name", LVCFMT_LEFT, 150);
m_FileList.InsertColumn(1, "Total Lines", LVCFMT_LEFT, 85);
m_FileList.InsertColumn(2, "Source Lines", LVCFMT_LEFT, 100);
m_FileList.InsertColumn(3, "Comment Lines", LVCFMT_LEFT, 100);
m_FileList.InsertColumn(4, "Blank Lines", LVCFMT_LEFT, 100);
m_imagelist = new CImageList;
m_imagelist->Create(16, 16, ILC_MASK, 2, 2);
m_imagelist->Add(AfxGetApp()->LoadIcon(MAKEINTRESOURCE(IDI_PERCENT)));
HD_ITEM curItem;
CHeaderCtrl* pHdrCtrl= NULL;
pHdrCtrl= m_FileList.GetHeaderCtrl();
CImageList *result = pHdrCtrl->SetImageList(m_imagelist);
curItem.mask= HDI_IMAGE | HDI_FORMAT;
curItem.iImage= 0;
curItem.fmt= HDF_LEFT | HDF_IMAGE | HDF_STRING;
for (int h = 0; h < 5; h++)
{
pHdrCtrl->GetItem(h, &curItem);
pHdrCtrl->SetItem(h, &curItem);
}
char *message = "[No Project Selected]";
m_ProjectName.SetWindowText(message);
m_Progress.SetPos(0);
m_ProgressLabel.SetWindowText(message);
m_LinesTotal.SetWindowText(message);
m_LinesSource.SetWindowText(message);
m_LinesComment.SetWindowText(message);
m_LinesBlank.SetWindowText(message);
m_compare_order[0] = 1;
m_compare_order[1] = m_compare_order[2] = m_compare_order[3] = m_compare_order[4] = m_compare_order[0];
return TRUE; // return TRUE unless you set the focus to a control
}
void CLineCounterDlg::OnFileExit()
{
// We call OnOK to safely close the application
CDialog::OnOK();
}
// This one is tricky...
// We have 4 columns showing number (percent), i.e. 100 (78%), meaning
// the file has 100 lines of that type, which is 78% from the total amount
// of lines in the file.
// To sort the columns using the number you must click on 3/4's of the column header
// To sort the column using the percent you must click on the last 1/4 of the column header
//
// "That's all folks" :)
void CLineCounterDlg::OnColumnclickFilelist(NMHDR* pNMHDR, LRESULT* pResult)
{
NM_LISTVIEW* pNMListView = (NM_LISTVIEW*)pNMHDR;
m_sorting_column = pNMListView->iSubItem;
SetCursor(LoadCursor(NULL, IDC_WAIT));
// if user clicked one of the "percent column"...
if (m_sorting_column > 1)
{
POINT p;
DWORD pos;
pos = GetMessagePos();
p.x = LOWORD(pos);
p.y = HIWORD(pos);
::ScreenToClient(m_FileList.GetHeaderCtrl()->GetSafeHwnd(), &p);
int width = 0;
for (int i = 0; i < m_sorting_column; i++)
width += ListView_GetColumnWidth(m_FileList.GetSafeHwnd(), i);
int current_width = ListView_GetColumnWidth(m_FileList.GetSafeHwnd(), m_sorting_column);
// ...checkin coords...
if (p.x > (width + (current_width / 1.2)))
m_sorting_column = -m_sorting_column;
}
::SendMessage(m_FileList.GetSafeHwnd(), LVM_SORTITEMS, (LPARAM)this, (LPARAM)(PFNLVCOMPARE)CLineCounterDlg::CompareFunc);
SetCursor(LoadCursor(NULL, IDC_ARROW));
if (m_sorting_column < 0)
m_sorting_column = -m_sorting_column;
m_compare_order[m_sorting_column] = !m_compare_order[m_sorting_column];
*pResult = 0;
}
void CLineCounterDlg::OnFileSelectproject()
{
static char extension[] = "Microsoft Visual C++ 6.0 Projects (*.dsp)|*.dsp|All Files (*.*)|*.*||";
CFileDialog dlg(TRUE, NULL, NULL, OFN_HIDEREADONLY | OFN_FILEMUSTEXIST, extension);
int result = dlg.DoModal();
if (result != 1)
return;
static char message[] = "Select Count! to start...";
delete [] m_compare_struct;
m_compare_struct = NULL;
m_project = dlg.GetPathName();
m_ProjectName.SetWindowText(m_project);
m_ProgressLabel.SetWindowText(message);
ListView_DeleteAllItems(m_FileList.GetSafeHwnd());
m_LinesTotal.SetWindowText(message);
m_LinesSource.SetWindowText(message);
m_LinesComment.SetWindowText(message);
m_LinesBlank.SetWindowText(message);
}
void CLineCounterDlg::OnFileCount()
{
if (m_project.IsEmpty())
{
MessageBox("No project selected!", "Error", MB_ICONERROR);
return;
}
srcmng sources;
int nf = ProcessDSP(m_project, sources);
lsrc_item *item;
item = sources.srcs;
ListView_DeleteAllItems(m_FileList.GetSafeHwnd());
if (!item)
{
MessageBox("Empty project or not a project file!", "Info", MB_ICONEXCLAMATION);
m_FileList.UnlockWindowUpdate();
return;
}
int size = m_project.GetLength();
const char *project = (const char*)m_project;
while (size > -1 && project[size--] != '\\')
;
if (size == -1)
return;
size += 2;
char *dir = new char[size + 1];
memcpy(dir, project, size);
dir[size] = 0;
int dir_size = strlen(dir);
m_LinesTotal.SetWindowText("Working...");
m_LinesSource.SetWindowText("Working...");
m_LinesComment.SetWindowText("Working...");
m_LinesBlank.SetWindowText("Working...");
UpdateWindow();
SetCursor(LoadCursor(NULL, IDC_WAIT));
m_FileList.LockWindowUpdate();
int count = sources.getcount();
char progress[18];
m_Progress.SetPos(0);
m_Progress.SetRange(0, count);
m_ProgressLabel.ShowWindow(SW_SHOW);
m_Progress.ShowWindow(SW_SHOW);
char *filename = NULL;
LVITEM list_item;
int id = 0;
char format[128];
int lines_total = 0;
int lines_source = 0;
int lines_comment = 0;
int lines_blank = 0;
float percent = 0;
delete [] m_compare_struct;
m_compare_struct = new compare_struct[count];
while (item)
{
filename = new char[dir_size + strlen(item->filename) + 1];
sprintf(filename, "%s%s", dir, item->filename);
ProcessFile(filename, item);
delete [] filename;
m_compare_struct[id].m_filename = new char[strlen(item->filename) + 1];
strcpy(m_compare_struct[id].m_filename, item->filename);
m_compare_struct[id].m_total = item->lc;
m_compare_struct[id].m_source = item->elc;
m_compare_struct[id].m_comment = item->cc;
m_compare_struct[id].m_blank = item->blc;
list_item.mask = LVIF_TEXT | LVIF_PARAM;
list_item.iItem = id++;
list_item.iSubItem = 0;
list_item.lParam = (LPARAM)id-1;
list_item.pszText = item->filename;
int index = ListView_InsertItem(m_FileList.GetSafeHwnd(), &list_item);
// LinesTotal
lines_total += item->lc;
list_item.mask = LVIF_TEXT;
list_item.iItem = id-1;
list_item.iSubItem = 1;
sprintf(format, "%d", item->lc);
list_item.lParam = item->lc;
list_item.pszText = format;
ListView_SetItem(m_FileList.GetSafeHwnd(), &list_item);
// LinesSource
lines_source += item->elc;
list_item.mask = LVIF_TEXT;
list_item.iItem = id-1;
list_item.iSubItem = 2;
percent = (item->elc == 0 || item->lc == 0) ? 0 : (float)(100 * item->elc) / item->lc;
m_compare_struct[id-1].m_source_percent = percent;
sprintf(format, "%d (%.2f%%)", item->elc, percent);
list_item.pszText = format;
ListView_SetItem(m_FileList.GetSafeHwnd(), &list_item);
// LinesComment
lines_comment += item->cc;
list_item.mask = LVIF_TEXT;
list_item.iItem = id-1;
percent = (item->cc == 0 || item->lc == 0) ? 0 : (float)(100 * item->cc) / item->lc;
m_compare_struct[id-1].m_comment_percent = percent;
sprintf(format, "%d (%.2f%%)", item->cc, percent);
list_item.pszText = format;
list_item.iSubItem = 3;
ListView_SetItem(m_FileList.GetSafeHwnd(), &list_item);
// LinesBlank
lines_blank += item->blc;
list_item.mask = LVIF_TEXT;
list_item.iItem = id-1;
percent = (item->blc == 0 || item->lc == 0) ? 0 : (float)(100 * item->blc) / item->lc;
m_compare_struct[id-1].m_blank_percent = percent;
sprintf(format, "%d (%.2f%%)", item->blc, percent);
list_item.pszText = format;
list_item.iSubItem = 4;
ListView_SetItem(m_FileList.GetSafeHwnd(), &list_item);
sprintf(progress, "%d%% processed...", (100 * (id+1))/ count);
m_ProgressLabel.SetWindowText(progress);
m_Progress.SetPos(id);
item = item->next; // Next, please!
}
sprintf(format, "%d", lines_total);
m_LinesTotal.SetWindowText(format);
sprintf(format, "%d (%.9f%% of total)", lines_source,
(lines_source == 0 || lines_total == 0) ? 0 : (float)(100 * lines_source) / lines_total);
m_LinesSource.SetWindowText(format);
sprintf(format, "%d (%.9f%% of total)", lines_comment,
(lines_comment == 0 || lines_total == 0) ? 0 : (float)(100 * lines_comment) / lines_total);
m_LinesComment.SetWindowText(format);
sprintf(format, "%d (%.9f%% of total)", lines_blank,
(lines_blank == 0 || lines_total == 0) ? 0 : (float)(100 * lines_blank) / lines_total);
m_LinesBlank.SetWindowText(format);
m_ProgressLabel.SetWindowText("All done");
m_Progress.ShowWindow(SW_HIDE);
delete [] dir;
m_sorting_column = 0;
::SendMessage(m_FileList.GetSafeHwnd(), LVM_SORTITEMS, (LPARAM)this, (LPARAM)(PFNLVCOMPARE)CLineCounterDlg::CompareFunc);
SetCursor(LoadCursor(NULL, IDC_ARROW));
m_FileList.UnlockWindowUpdate();
}
// OnOK and OnCancel are declared here to prevent the CDialog functions from being called,
// thus preventing closing the dialog when clicking ENTER or ESC
void CLineCounterDlg::OnOK()
{
}
void CLineCounterDlg::OnCancel()
{
}
void CLineCounterDlg::OnClose()
{
CDialog::OnOK();
}
void CLineCounterDlg::OnRclickFilelist(NMHDR* pNMHDR, LRESULT* pResult)
{
NM_LISTVIEW* pList = (NM_LISTVIEW*)pNMHDR;
HMENU menu = LoadMenu(AfxGetInstanceHandle(), MAKEINTRESOURCE(ID_POPUP));
menu = GetSubMenu(menu, 0);
if (m_project.IsEmpty())
ModifyMenu(menu, 0, MF_BYPOSITION | MF_GRAYED, NULL, "[No Project Selected]");
else
if (pList->iItem < 0)
ModifyMenu(menu, 0, MF_BYPOSITION | MF_GRAYED, NULL, "No File Selected");
POINT p;
GetCursorPos(&p);
TrackPopupMenu(menu, TPM_LEFTALIGN, p.x, p.y, NULL, GetSafeHwnd(), NULL);
*pResult = 0;
}
void CLineCounterDlg::OnSourceView()
{
CViewCodeDlg dlg;
char file_name[1024];
POSITION pos = m_FileList.GetFirstSelectedItemPosition();
if (!pos)
return;
int id = m_FileList.GetNextSelectedItem(pos);
m_FileList.GetItemText(id, 0, file_name, 1024);
int size = m_project.GetLength();
const char *project = (const char*)m_project;
while (size > -1 && project[size--] != '\\')
;
if (size == -1)
return;
size += 2;
char *filename = new char[size + strlen(file_name) + 1];
memcpy(filename, project, size);
strcpy(filename + size, file_name);
dlg.SetFileName(filename);
delete [] filename;
dlg.DoModal();
}
int CALLBACK CLineCounterDlg::CompareFunc(LPARAM lParam1, LPARAM lParam2, LPARAM lParamSort)
{
CLineCounterDlg *dlg = (CLineCounterDlg*)lParamSort;
if (dlg->m_sorting_column == 0) // sorting by File Name
{
if (!dlg->m_compare_struct)
return 0;
const char *data1 = dlg->m_compare_struct[lParam1].m_filename;
const char *data2 = dlg->m_compare_struct[lParam2].m_filename;
if (dlg->m_compare_order[0])
return (strcmpi(data1, data2));
else
return (strcmpi(data2, data1));
}
else // Sorting by Total Lines/Source Lines/Comment Lines/Blank Lines
{
float data1 = -1;
float data2 = -1;
if (dlg->m_sorting_column > 0)
{
if (!dlg->m_compare_struct)
return 0;
if (dlg->m_sorting_column == 1)
{
data1 = (float)dlg->m_compare_struct[lParam1].m_total;
data2 = (float)dlg->m_compare_struct[lParam2].m_total;
}
else
{
if (dlg->m_sorting_column == 2)
{
data1 = (float)dlg->m_compare_struct[lParam1].m_source;
data2 = (float)dlg->m_compare_struct[lParam2].m_source;
}
else
{
if (dlg->m_sorting_column == 3)
{
data1 = (float)dlg->m_compare_struct[lParam1].m_comment;
data2 = (float)dlg->m_compare_struct[lParam2].m_comment;
}
else
{
if (dlg->m_sorting_column == 4)
{
data1 = (float)dlg->m_compare_struct[lParam1].m_blank;
data2 = (float)dlg->m_compare_struct[lParam2].m_blank;
}
}
}
}
}
else // percent sorting
{
if (dlg->m_sorting_column == -2)
{
data1 = dlg->m_compare_struct[lParam1].m_source_percent;
data2 = dlg->m_compare_struct[lParam2].m_source_percent;
}
else
{
if (dlg->m_sorting_column == -3)
{
data1 = dlg->m_compare_struct[lParam1].m_comment_percent;
data2 = dlg->m_compare_struct[lParam2].m_comment_percent;
}
else
{
if (dlg->m_sorting_column == -4)
{
data1 = dlg->m_compare_struct[lParam1].m_blank_percent;
data2 = dlg->m_compare_struct[lParam2].m_blank_percent;
}
}
}
}
if (dlg->m_compare_order[dlg->m_sorting_column > 0 ? dlg->m_sorting_column : -dlg->m_sorting_column])
return (int)data1 - (int)data2;
else
return (int)data2 - (int)data1;
}
return 0;
}
void CLineCounterDlg::OnHelpAbout()
{
CDialog about(IDD_ABOUTBOX);
about.DoModal();
}