tasklistcsvexporter.cpp

来自「管理项目进度工具的原代码」· C++ 代码 · 共 364 行

CPP
364
字号
// TaskListCsvExporter.cpp: implementation of the CTaskListCsvExporter class.
//
//////////////////////////////////////////////////////////////////////

#include "stdafx.h"
#include "TaskListCsvExporter.h"
#include "tdlschemadef.h"
#include "resource.h"
#include "recurringtaskedit.h"

#include <locale.h>

#include "..\shared\timehelper.h"
#include "..\shared\enstring.h"
#include "..\shared\misc.h"

#ifdef _DEBUG
#undef THIS_FILE
static char THIS_FILE[]=__FILE__;
#define new DEBUG_NEW
#endif

//////////////////////////////////////////////////////////////////////
// Construction/Destruction
//////////////////////////////////////////////////////////////////////

const LPCTSTR SPACE = " ";
const LPCTSTR ENDL = "\n";
const LPCTSTR ONEDBLQUOTE = "\"";
const LPCTSTR TWODBLQUOTE = "\"\"";

CTaskListCsvExporter::CTaskListCsvExporter()
{

}

CTaskListCsvExporter::~CTaskListCsvExporter()
{

}

bool CTaskListCsvExporter::Export(const ITaskList* pSrcTaskFile, const char* szDestFilePath)
{
	const ITaskList6* pTasks6 = NULL;
	
	if ((const_cast<ITaskList*>(pSrcTaskFile))->QueryInterface(IID_TASKLIST6, (void**)&pTasks6))
		return false;

	DELIM = Misc::GetListSeparator();
	
	// what follows is definitely a hack!
	// but that's the joy of programming :)
	ROUNDTIMEFRACTIONS = AfxGetApp()->GetProfileInt("Preferences", "RoundTimeFractions", FALSE);

	CStdioFile fileOut;

	if (fileOut.Open(szDestFilePath, CFile::modeCreate | CFile::modeWrite))
	{
		BuildAttribList(pTasks6, NULL);
		
		CString sOutput;

		if (!ExportTask(pTasks6, NULL, 0, 0, "", sOutput).IsEmpty())
		{
			fileOut.WriteString(ColumnHeadings());
			fileOut.WriteString(sOutput);
			return true;
		}
	}

	return false;
}

CString& CTaskListCsvExporter::ExportTask(const ITaskList6* pTasks, HTASKITEM hTask, int nDepth, 
										  int nPos, const CString& sParentPos, CString& sOutput) const
{
	CString sPos; // becomes parent pos for sub-tasks

	// handle locale specific decimal separator
	setlocale(LC_NUMERIC, "");

	if (hTask)
	{
		// same order as columns

		if (WantAttribute(TDL_TASKPOS))
		{
			// if there is a POS child item then this replaces nPos
			if (pTasks->TaskHasAttribute(hTask, TDL_TASKPOS))
			{
				nPos = pTasks->GetTaskPosition(hTask);

				if (nDepth == 1) // top level tasks
					sPos.Format("%d", nPos);
				else
					sPos.Format("%s.%d", sParentPos, nPos);
			}

			AppendAttribute(sPos, sOutput);
		}

		AppendAttribute(pTasks, hTask, TDL_TASKID, NULL, sOutput);

        // title is slightly different because we indent it for subtasks
        CString sPrefix(' ', (nDepth > 1) ? (nDepth - 1) * 4 : 0);
		AppendAttribute(pTasks, hTask, TDL_TASKTITLE, NULL, sOutput, sPrefix);
      
		AppendAttribute(pTasks, hTask, TDL_TASKCALCCOMPLETION, TDL_TASKPERCENTDONE, sOutput);
		AppendAttribute(pTasks, hTask, TDL_TASKHIGHESTPRIORITY, TDL_TASKPRIORITY, sOutput);
		AppendAttribute(pTasks, hTask, TDL_TASKCALCTIMEESTIMATE, TDL_TASKTIMEESTIMATE, sOutput);
		AppendAttribute(pTasks, hTask, TDL_TASKCALCTIMESPENT, TDL_TASKTIMESPENT, sOutput);
		AppendAttribute(pTasks, hTask, TDL_TASKCREATIONDATESTRING, NULL, sOutput);
		AppendAttribute(pTasks, hTask, TDL_TASKCREATEDBY, NULL, sOutput);
		AppendAttribute(pTasks, hTask, TDL_TASKSTARTDATESTRING, NULL, sOutput);
		AppendAttribute(pTasks, hTask, TDL_TASKEARLIESTDUEDATESTRING, TDL_TASKDUEDATESTRING, sOutput);
		AppendAttribute(pTasks, hTask, TDL_TASKDONEDATESTRING, NULL, sOutput);
		AppendAttributeList(pTasks, hTask, TDL_TASKNUMALLOCTO, TDL_TASKALLOCTO, sOutput);
		AppendAttribute(pTasks, hTask, TDL_TASKALLOCBY, NULL, sOutput);
		AppendAttribute(pTasks, hTask, TDL_TASKVERSION, NULL, sOutput);
		AppendAttribute(pTasks, hTask, TDL_TASKRECURRENCE, NULL, sOutput);
		AppendAttributeList(pTasks, hTask, TDL_TASKNUMCATEGORY, TDL_TASKCATEGORY, sOutput);
		AppendAttribute(pTasks, hTask, TDL_TASKSTATUS, NULL, sOutput);
		AppendAttribute(pTasks, hTask, TDL_TASKHIGHESTRISK, TDL_TASKRISK, sOutput);
		AppendAttribute(pTasks, hTask, TDL_TASKEXTERNALID, NULL, sOutput);
		AppendAttribute(pTasks, hTask, TDL_TASKLASTMODSTRING, NULL, sOutput);
		AppendAttribute(pTasks, hTask, TDL_TASKCALCCOST, TDL_TASKCOST, sOutput);
		AppendAttribute(pTasks, hTask, TDL_TASKFILEREFPATH, NULL, sOutput);
		AppendAttribute(pTasks, hTask, TDL_TASKDEPENDENCY, NULL, sOutput);
		AppendAttribute(pTasks, hTask, TDL_TASKCOMMENTS, NULL, sOutput);
	}

	// add sub-tasks
	hTask = pTasks->GetFirstTask(hTask);

	if (hTask) // at least one sub-task
	{
		int nChildPos = 1;

		while (hTask)
		{
			CString sTask;
			sOutput += ENDL;
			sOutput += ExportTask(pTasks, hTask, nDepth + 1, nChildPos++, sPos, sTask);

			hTask = pTasks->GetNextTask(hTask);
		}
	}

	// extra line between top level items
	if (nDepth == 1)
		sOutput += ENDL;

	// restore decimal separator to '.'
	setlocale(LC_NUMERIC, "English");

	return sOutput;
}

void CTaskListCsvExporter::CheckAddAttribtoList(const ITaskList6* pTasks, HTASKITEM hTask, LPCTSTR szAttribName)
{
	if (pTasks->TaskHasAttribute(hTask, szAttribName))
	{
		// have we already got it ?
		if (!WantAttribute(szAttribName))
			m_aAttribs.Add(szAttribName); // add it
	}
}

void CTaskListCsvExporter::AppendAttributeList(const ITaskList6* pTasks, HTASKITEM hTask, 
										   LPCTSTR szNumAttribName, LPCTSTR szAttribName, 
                                          CString& sOutput) const
{
	int nItemCount = atoi(pTasks->GetTaskAttribute(hTask, szNumAttribName));

	if (nItemCount <= 1)
		AppendAttribute(pTasks, hTask, szAttribName, NULL, sOutput);

	else // more than one (use plus sign as delimiter)
	{
		CString sAttribs = pTasks->GetTaskAttribute(hTask, szAttribName);

		for (int nItem = 1; nItem < nItemCount; nItem++)
		{
			CString sAttribName;
			sAttribName.Format("%s%d", szAttribName, nItem);

			sAttribs += '+';
			sAttribs += pTasks->GetTaskAttribute(hTask, sAttribName);
		}

		AppendAttribute(sAttribs, sOutput);
	}
}

void CTaskListCsvExporter::AppendAttribute(const ITaskList6* pTasks, HTASKITEM hTask, 
										   LPCTSTR szAttribName, LPCTSTR szAltAttribName, 
										   CString& sOutput, LPCTSTR szPrefix) const
{
	if (WantAttribute(szAttribName) || (szAltAttribName && WantAttribute(szAltAttribName)))
	{
		if (pTasks->TaskHasAttribute(hTask, szAttribName))
		{
			CString sAttrib(szPrefix);
			sAttrib += pTasks->GetTaskAttribute(hTask, szAttribName);
			
			AppendAttribute(sAttrib, sOutput);
		}
		else if (szAltAttribName && pTasks->TaskHasAttribute(hTask, szAltAttribName))
		{
			CString sAttrib(szPrefix);
			sAttrib += pTasks->GetTaskAttribute(hTask, szAltAttribName);
			
			AppendAttribute(sAttrib, sOutput);
		}
		else
			sOutput += DELIM;
	}
}

void CTaskListCsvExporter::AppendAttribute(LPCTSTR szAttrib, CString& sOutput) const
{
	BOOL bNeedQuoting = FALSE;
	CString sAttrib(szAttrib);
	
	// double up quotes
	if (sAttrib.Find(ONEDBLQUOTE) != -1)
	{
		sAttrib.Replace(ONEDBLQUOTE, TWODBLQUOTE);
		bNeedQuoting = TRUE;
	}
	
	if (sAttrib.Find(DELIM) != -1)
		bNeedQuoting = TRUE;
	
	if (bNeedQuoting)
		sAttrib = ONEDBLQUOTE + sAttrib + ONEDBLQUOTE;
	
	// replace carriage returns
	sAttrib.Replace(ENDL, SPACE);
	
	sAttrib += DELIM;
	sOutput += sAttrib;
}

void CTaskListCsvExporter::AppendAttribute(double dAttrib, LPCTSTR szFormat, CString& sOutput) const
{
	CString sAttrib;

	sAttrib.Format(szFormat, dAttrib);
	AppendAttribute(sAttrib, sOutput);
}

void CTaskListCsvExporter::AppendAttribute(int nAttrib, LPCTSTR szFormat, CString& sOutput) const
{
	CString sAttrib;

	sAttrib.Format(szFormat, nAttrib);
	AppendAttribute(sAttrib, sOutput);
}

CString CTaskListCsvExporter::CheckGetColumnHeading(LPCTSTR szAttribName, UINT nIDHeading) const
{
	if (WantAttribute(szAttribName))
		return CEnString(nIDHeading) + DELIM;

	// else
	return "";
}

CString CTaskListCsvExporter::ColumnHeadings() const
{
	ASSERT (m_aAttribs.GetSize());

	CString sHeadings;

	sHeadings += CheckGetColumnHeading(TDL_TASKPOS, IDS_TDLBC_POS);
	sHeadings += CheckGetColumnHeading(TDL_TASKID, IDS_TDLBC_ID);
	sHeadings += CheckGetColumnHeading(TDL_TASKTITLE, IDS_TDLBC_TITLE);
	sHeadings += CheckGetColumnHeading(TDL_TASKPERCENTDONE, IDS_TDLBC_PERCENT);
	sHeadings += CheckGetColumnHeading(TDL_TASKPRIORITY, IDS_TDLBC_PRIORITY);
	sHeadings += CheckGetColumnHeading(TDL_TASKTIMEESTIMATE, IDS_TDLBC_TIMEEST);
	sHeadings += CheckGetColumnHeading(TDL_TASKTIMESPENT, IDS_TDLBC_TIMESPENT);
	sHeadings += CheckGetColumnHeading(TDL_TASKCREATIONDATESTRING, IDS_TDLBC_CREATEDATE);
	sHeadings += CheckGetColumnHeading(TDL_TASKCREATEDBY, IDS_TDLBC_CREATEDBY);
	sHeadings += CheckGetColumnHeading(TDL_TASKSTARTDATESTRING, IDS_TDLBC_STARTDATE);
	sHeadings += CheckGetColumnHeading(TDL_TASKDUEDATESTRING, IDS_TDLBC_DUEDATE);
	sHeadings += CheckGetColumnHeading(TDL_TASKDONEDATESTRING, IDS_TDLBC_DONEDATE);
	sHeadings += CheckGetColumnHeading(TDL_TASKALLOCTO, IDS_TDLBC_ALLOCTO);
	sHeadings += CheckGetColumnHeading(TDL_TASKALLOCBY, IDS_TDLBC_ALLOCBY);
	sHeadings += CheckGetColumnHeading(TDL_TASKVERSION, IDS_TDLBC_VERSION);
	sHeadings += CheckGetColumnHeading(TDL_TASKRECURRENCE, IDS_TDLBC_RECURRENCE);
	sHeadings += CheckGetColumnHeading(TDL_TASKCATEGORY, IDS_TDLBC_CATEGORY);
	sHeadings += CheckGetColumnHeading(TDL_TASKSTATUS, IDS_TDLBC_STATUS);
	sHeadings += CheckGetColumnHeading(TDL_TASKRISK, IDS_TDLBC_RISK);
	sHeadings += CheckGetColumnHeading(TDL_TASKEXTERNALID, IDS_TDLBC_EXTERNALID);
	sHeadings += CheckGetColumnHeading(TDL_TASKLASTMODSTRING, IDS_TDLBC_MODIFYDATE);
	sHeadings += CheckGetColumnHeading(TDL_TASKCOST, IDS_TDLBC_COST);
	sHeadings += CheckGetColumnHeading(TDL_TASKFILEREFPATH, IDS_TDLBC_FILEREF);
	sHeadings += CheckGetColumnHeading(TDL_TASKDEPENDENCY, IDS_TDLBC_DEPENDS);
	sHeadings += CheckGetColumnHeading(TDL_TASKCOMMENTS, IDS_TDLBC_COMMENTS);

	return sHeadings;
}

int CTaskListCsvExporter::BuildAttribList(const ITaskList6* pTasks, HTASKITEM hTask)
{
	if (hTask)
	{
		CheckAddAttribtoList(pTasks, hTask, TDL_TASKPOS);					
		CheckAddAttribtoList(pTasks, hTask, TDL_TASKID);					
		CheckAddAttribtoList(pTasks, hTask, TDL_TASKTITLE);				
		CheckAddAttribtoList(pTasks, hTask, TDL_TASKCOMMENTS); 			
		CheckAddAttribtoList(pTasks, hTask, TDL_TASKALLOCTO);				
		CheckAddAttribtoList(pTasks, hTask, TDL_TASKALLOCBY);				
		CheckAddAttribtoList(pTasks, hTask, TDL_TASKCATEGORY); 			
		CheckAddAttribtoList(pTasks, hTask, TDL_TASKSTATUS);				
		CheckAddAttribtoList(pTasks, hTask, TDL_TASKFILEREFPATH);			
		CheckAddAttribtoList(pTasks, hTask, TDL_TASKCREATEDBY);			
		CheckAddAttribtoList(pTasks, hTask, TDL_TASKFLAG);				
		CheckAddAttribtoList(pTasks, hTask, TDL_TASKDONEDATESTRING);		
		CheckAddAttribtoList(pTasks, hTask, TDL_TASKDUEDATESTRING);
		CheckAddAttribtoList(pTasks, hTask, TDL_TASKSTARTDATESTRING);		
		CheckAddAttribtoList(pTasks, hTask, TDL_TASKCREATIONDATESTRING);	
		CheckAddAttribtoList(pTasks, hTask, TDL_TASKTIMEESTIMATE);	
		CheckAddAttribtoList(pTasks, hTask, TDL_TASKTIMESPENT);		
		CheckAddAttribtoList(pTasks, hTask, TDL_TASKPERCENTDONE);		
		CheckAddAttribtoList(pTasks, hTask, TDL_TASKPRIORITY);		
		CheckAddAttribtoList(pTasks, hTask, TDL_TASKRISK);			
		CheckAddAttribtoList(pTasks, hTask, TDL_TASKLASTMODSTRING);		
		CheckAddAttribtoList(pTasks, hTask, TDL_TASKEXTERNALID);			
		CheckAddAttribtoList(pTasks, hTask, TDL_TASKCOST);			
		CheckAddAttribtoList(pTasks, hTask, TDL_TASKDEPENDENCY);			
		CheckAddAttribtoList(pTasks, hTask, TDL_TASKVERSION);			
		CheckAddAttribtoList(pTasks, hTask, TDL_TASKRECURRENCE);			
	}

	// subtasks
	hTask = pTasks->GetFirstTask(hTask);

	while (hTask) // at least one sub-task
	{
		BuildAttribList(pTasks, hTask);

		// next subtask
		hTask = pTasks->GetNextTask(hTask);
	}

	return m_aAttribs.GetSize();
}

BOOL CTaskListCsvExporter::WantAttribute(LPCTSTR szAttribName) const
{
	int nAttrib = m_aAttribs.GetSize();

	while (nAttrib--)
	{
		if (m_aAttribs[nAttrib] == szAttribName)
			return TRUE;
	}

	// nope
	return FALSE;
}

⌨️ 快捷键说明

复制代码Ctrl + C
搜索代码Ctrl + F
全屏模式F11
增大字号Ctrl + =
减小字号Ctrl + -
显示快捷键?