tasklisthtmlexporter.cpp
来自「管理项目进度工具的原代码」· C++ 代码 · 共 331 行
CPP
331 行
// TaskFileHtmlExporter.cpp: implementation of the CTaskListHtmlExporter class.
//
//////////////////////////////////////////////////////////////////////
#include "stdafx.h"
#include "todolist.h"
#include "TasklistHtmlExporter.h"
#include "tdlschemadef.h"
#include "recurringtaskedit.h"
#include "..\shared\xmlfile.h"
#include <locale.h>
#ifdef _DEBUG
#undef THIS_FILE
static char THIS_FILE[]=__FILE__;
#define new DEBUG_NEW
#endif
//////////////////////////////////////////////////////////////////////
// Construction/Destruction
//////////////////////////////////////////////////////////////////////
const LPCTSTR ENDL = "\n";
CTaskListHtmlExporter::CTaskListHtmlExporter()
{
}
CTaskListHtmlExporter::~CTaskListHtmlExporter()
{
}
bool CTaskListHtmlExporter::Export(const ITaskList* pSrcTaskFile, const char* szDestFilePath)
{
// what follows is definitely a hack!
// but that's the joy of programming :)
CString sFont = AfxGetApp()->GetProfileString("Preferences", "HTMLFont", "Verdana");
int nFontSize = AfxGetApp()->GetProfileInt("Preferences", "HtmlFontSize", 3);
DEFAULTFONT.Format("<font face='%s' size='%d'>", sFont, nFontSize);
HTMLNOTES = AfxGetApp()->GetProfileInt("Preferences", "ExportSpaceForNotes", FALSE) ?
"<pre>\n\n\n\n\n\n\n\n</pre>" : "";
STRIKETHRUDONE = AfxGetApp()->GetProfileInt("Preferences", "StrikethroughDone", TRUE);
ROUNDTIMEFRACTIONS = AfxGetApp()->GetProfileInt("Preferences", "RoundTimeFractions", FALSE);
CStdioFile fileOut;
if (fileOut.Open(szDestFilePath, CFile::modeCreate | CFile::modeWrite))
{
CString sOutput;
const ITaskList6* pTasks6 = static_cast<const ITaskList6*>(pSrcTaskFile);
if (!ExportTask(pTasks6, NULL, 0, 0, sOutput).IsEmpty())
{
fileOut.WriteString("<html>\n<head>\n");
fileOut.WriteString(FormatCharSet(pTasks6));
fileOut.WriteString("</head>\n<body>\n");
fileOut.WriteString(sOutput);
fileOut.WriteString("</body>\n</html>\n");
return true;
}
}
return false;
}
CString CTaskListHtmlExporter::FormatCharSet(const ITaskList6* pTasks) const
{
// charset
CString sCharSet, sCS = pTasks->GetHtmlCharSet();
if (!sCS.IsEmpty())
sCharSet.Format("<meta http-equiv=\"content-type\" content=\"text/html; charset=%s\">\n", sCS);
return sCharSet;
}
CString& CTaskListHtmlExporter::ExportTask(const ITaskList6* pTasks, HTASKITEM hTask, int nDepth, int nPos, CString& sOutput) const
{
// handle locale specific decimal separator
setlocale(LC_NUMERIC, "");
// if depth == 0 then we're at the root so just add sub-tasks
// else insert pItem first
if (nDepth > 0)
{
// if there is a POS child item then this replaces nPos
if (pTasks->TaskHasAttribute(hTask, TDL_TASKPOS))
nPos = pTasks->GetTaskPosition(hTask);
CString sTitle, sID, sItem, sPriority, sStartDate, sDueDate, sDoneDate;
CString sAllocTo, sAllocBy, sCategory, sStatus, sColor("#000000");
CString sComments, sPercent, sTimeEst, sTimeSpent, sFileRef;
CString sLastMod, sRisk, sExtID, sCreateDate, sCreateBy, sCost;
CString sVersion, sRecurrence;
char cTemp;
// ID
FormatAttribute(pTasks, hTask, TDL_TASKID, "(ID: %s) ", sID);
// title
if (nDepth == 1) // toplevel == bold
sTitle.Format("<b>%s</b>", pTasks->GetTaskTitle(hTask));
else
sTitle = pTasks->GetTaskTitle(hTask);
// priority, start/due/done dates
int nPercent = pTasks->GetTaskPercentDone(hTask, TRUE);
BOOL bDone = pTasks->IsTaskDone(hTask) || (nPercent == 100);
// format color string
if (bDone)
sColor = "#c4c4c4";
else
sColor = pTasks->GetTaskWebColor(hTask);
if (bDone && pTasks->TaskHasAttribute(hTask, TDL_TASKDONEDATESTRING))
sDoneDate.Format(" (completed: %s)", pTasks->GetTaskDoneDateString(hTask));
else
{
if (pTasks->TaskHasAttribute(hTask, TDL_TASKHIGHESTPRIORITY) ||
pTasks->TaskHasAttribute(hTask, TDL_TASKPRIORITY))
{
CString sPriorityCol = pTasks->GetTaskPriorityWebColor(hTask);
sPriority.Format("[<font color='%s'>%d</font>] ", sPriorityCol, pTasks->GetTaskPriority(hTask, TRUE));
}
FormatAttribute(pTasks, hTask, TDL_TASKSTARTDATESTRING, " (start: %s)", sStartDate);
FormatAttribute(pTasks, hTask, TDL_TASKDUEDATESTRING, " (due: %s)", sDueDate);
int nTimePlaces = ROUNDTIMEFRACTIONS ? 0 : 2;
if (pTasks->TaskHasAttribute(hTask, TDL_TASKTIMEESTIMATE) ||
pTasks->TaskHasAttribute(hTask, TDL_TASKCALCTIMEESTIMATE))
sTimeEst.Format(" (time est: %.*f hrs)", nTimePlaces, pTasks->GetTaskTimeEstimate(hTask, cTemp, TRUE));
if (pTasks->TaskHasAttribute(hTask, TDL_TASKTIMESPENT) ||
pTasks->TaskHasAttribute(hTask, TDL_TASKCALCTIMESPENT))
sTimeEst.Format(" (time spent: %.*f hrs)", nTimePlaces, pTasks->GetTaskTimeSpent(hTask, cTemp, TRUE));
if (pTasks->TaskHasAttribute(hTask, TDL_TASKPERCENTDONE))
sPercent.Format(" (%d%%) ", nPercent);
}
FormatAttribute(pTasks, hTask, TDL_TASKCREATIONDATESTRING, " (created: %s)", sCreateDate);
FormatAttribute(pTasks, hTask, TDL_TASKCREATEDBY, " (created by: %s)", sCreateBy);
FormatAttributeList(pTasks, hTask, TDL_TASKNUMALLOCTO, TDL_TASKALLOCTO, " (allocated to: %s)", sAllocTo);
FormatAttribute(pTasks, hTask, TDL_TASKALLOCBY, " (allocated by: %s)", sAllocBy);
FormatAttributeList(pTasks, hTask, TDL_TASKNUMCATEGORY, TDL_TASKCATEGORY, " (category: %s)", sCategory);
FormatAttribute(pTasks, hTask, TDL_TASKSTATUS, " (status: %s)", sStatus);
FormatAttribute(pTasks, hTask, TDL_TASKRISK, " (risk: %s)", sRisk);
FormatAttribute(pTasks, hTask, TDL_TASKEXTERNALID, " (ext.ID: %s)", sExtID);
FormatAttribute(pTasks, hTask, TDL_TASKLASTMODSTRING, " (last mod: %s)", sLastMod);
FormatAttribute(pTasks, hTask, TDL_TASKCOST, " (cost: %.2f)", sCost);
FormatAttribute(pTasks, hTask, TDL_TASKVERSION, " (version: %s)", sVersion);
FormatAttribute(pTasks, hTask, TDL_TASKRECURRENCE, " (occurs: %s)", sRecurrence);
// fileref
if (pTasks->TaskHasAttribute(hTask, TDL_TASKFILEREFPATH))
{
CString sFilePath = pTasks->GetTaskFileReferencePath(hTask);
sFileRef.Format("<br>(link: <a href=\"%s\">%s</a>)", sFilePath, sFilePath);
}
// comments
if (pTasks->TaskHasAttribute(hTask, TDL_TASKHTMLCOMMENTS))
{
CString sItemComments = pTasks->GetTaskAttribute(hTask, TDL_TASKHTMLCOMMENTS);
sItemComments.TrimRight();
if (!sItemComments.IsEmpty())
{
// note: we reset the font after the comments because the font
// face and size may well have been changed
sComments.Format(bDone ?
"<br><font color='#c4c4c4'>[</font>%s%s<font color='#c4c4c4'>]</font>" : "<br>[%s%s]",
sItemComments, DEFAULTFONT);
}
}
else if (pTasks->TaskHasAttribute(hTask, TDL_TASKCOMMENTS))
{
CString sItemComments = pTasks->GetTaskComments(hTask);
sItemComments.TrimRight();
if (!sItemComments.IsEmpty())
{
TXT2XML(sItemComments); // TODO
sComments.Format(bDone ? "<br><font color='#c4c4c4'>[%s] </font>" : "<br><font color='#606060'>[%s] </font>",
sItemComments);
// replace carriage returns with <br>
sComments.Replace(ENDL, "<br>");
sComments.Replace("\n", "<br>");
// replace tab characters with multiple
sComments.Replace("\t", " ");
}
}
CString sFormat;
if (bDone)
{
if (STRIKETHRUDONE)
sFormat = "%s%s%s<font color='%s'><s>%s%s%s%s%s%s%s%s%s%s%s%s%s%s%s%s</s></font>%s<s>%s</s>%s";
else
sFormat = "%s%s%s<font color='%s'>%s%s%s%s%s%s%s%s%s%s%s%s%s%s%s%s</font>%s%s%s";
}
else
sFormat = "%s%s%s<font color='%s'>%s</font>%s%s%s%s%s%s%s%s%s%s%s%s%s%s%s%s%s%s";
sItem.Format(sFormat, sID, sPriority, sPercent, sColor, sTitle, sRisk,
sAllocTo, sAllocBy, sVersion, sRecurrence, sCategory, sStatus,
sCreateDate, sCreateBy, sStartDate, sDueDate, sTimeEst,
sCost, sDoneDate, sExtID, sLastMod, sComments, sFileRef);
// notes section
if (!bDone)
sItem += HTMLNOTES;
if (nDepth == 1) // toplevel
sOutput += "<br>";
sOutput += "<li>";
sOutput += sItem;
}
else
{
sOutput += DEFAULTFONT;
// title and date
CString sTitle = pTasks->GetReportTitle();
CString sDate = pTasks->GetReportDate();
if (!sTitle.IsEmpty())
{
CString sProjTitle;
sProjTitle.Format("<h2>%s</h2>%s<br>", sTitle, sDate);
sOutput += sProjTitle;
}
else if (!sDate.IsEmpty())
{
sOutput += sDate;
sOutput += "<br>";
}
}
// begin new ordered list for sub-tasks
hTask = pTasks->GetFirstTask(hTask);
if (hTask) // at least one sub-task
{
sOutput += ENDL;
sOutput += "<ol>";
sOutput += ENDL;
int nChildPos = 1;
while (hTask)
{
CString sTask;
sOutput += ENDL;
sOutput += ExportTask(pTasks, hTask, nDepth + 1, nChildPos++, sTask);
hTask = pTasks->GetNextTask(hTask);
}
// end ordered list
sOutput += "</ol>";
sOutput += ENDL;
}
// end of item
if (nDepth > 0)
{
sOutput += "</li>";
sOutput += ENDL;
}
else
sOutput += "</font>"; // we're done
// restore decimal separator to '.'
setlocale(LC_NUMERIC, "English");
return sOutput;
}
BOOL CTaskListHtmlExporter::FormatAttribute(const ITaskList6* pTasks, HTASKITEM hTask,
LPCTSTR szAttribName, LPCTSTR szFormat, CString& sAttribText)
{
if (pTasks->TaskHasAttribute(hTask, szAttribName))
{
sAttribText.Format(szFormat, pTasks->GetTaskAttribute(hTask, szAttribName));
return TRUE;
}
return FALSE;
}
BOOL CTaskListHtmlExporter::FormatAttributeList(const ITaskList6* pTasks, HTASKITEM hTask,
LPCTSTR szNumAttribName, LPCTSTR szAttribName,
LPCTSTR szFormat, CString& sAttribText)
{
int nItemCount = atoi(pTasks->GetTaskAttribute(hTask, szNumAttribName));
if (nItemCount <= 1)
return FormatAttribute(pTasks, hTask, szAttribName, szFormat, sAttribText);
// 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);
}
sAttribText.Format(szFormat, sAttribs);
return TRUE;
}
⌨️ 快捷键说明
复制代码Ctrl + C
搜索代码Ctrl + F
全屏模式F11
增大字号Ctrl + =
减小字号Ctrl + -
显示快捷键?