Skip to content

Commit

Permalink
Generate reports in tabular format for table comparisons. (#1983)
Browse files Browse the repository at this point in the history
Generate reports in tabular format for table comparisons
  • Loading branch information
sdottaka authored Aug 18, 2023
1 parent 2fe32d5 commit 409280b
Show file tree
Hide file tree
Showing 8 changed files with 431 additions and 158 deletions.
45 changes: 33 additions & 12 deletions Externals/crystaledit/Sample/SampleView.cpp
Original file line number Diff line number Diff line change
Expand Up @@ -175,15 +175,29 @@ bool CSampleView::ConvertToHTML(const CString& filename)
CString linemax;
linemax.Format(_T("%d"), GetLineCount());
double marginWidth = GetViewLineNumbers() ? linemax.GetLength() / 1.5 + 0.5 : 0.5;
const int nColumnCountMax = m_pTextBuffer->GetColumnCountMax();
CString tableStyle;
tableStyle.Format(
_T("table { table-layout: fixed; width: 100%%; height: 100%%; border-collapse: collapse; font-size: %dpt;}\n"), nFontSize);
CString tdthStyle;
CString colgroup;
colgroup.Format(
_T("<colgroup>\n")
_T("<col style=\"width: %.1fem;\" />\n")
_T("<col style=\"width: calc(100%% - %.1fem);\" />\n")
_T("</colgroup>\n"), marginWidth, marginWidth);
switch (GetTextLayoutMode())
{
case TEXTLAYOUT_TABLE_NOWORDWRAP:
case TEXTLAYOUT_TABLE_WORDWRAP:
tableStyle.Format(
_T("table { table-layout: fixed; width: max-content; height: 100%%; border-collapse: collapse; font-size: %dpt;}\n"), nFontSize);
tdthStyle = _T("td,th {word-break: break-all; padding: 0 3px; border: 1px solid #a0a0a0; }\n");
break;
default:
tableStyle.Format(
_T("table { table-layout: fixed; width: 100%%; height: 100%%; border-collapse: collapse; font-size: %dpt;}\n"), nFontSize);
tdthStyle = _T("td,th {word-break: break-all; padding: 0 3px; }\n");
colgroup.Format(
_T("<colgroup>\n")
_T("<col style=\"width: %.1fem;\" />\n")
_T("<col style=\"width: calc(100%% - %.1fem);\" />\n")
_T("</colgroup>\n"), marginWidth, marginWidth);
break;
}

#pragma warning(disable: 4996)
try
Expand All @@ -195,17 +209,24 @@ bool CSampleView::ConvertToHTML(const CString& filename)
_T("<head>\n")
_T("<meta charset=\"UTF-8\">\n")
_T("<title>") + GetDocument()->GetPathName() + _T("</title>\n")
_T("<style type=\"text/css\">\n")
+ tableStyle +
_T("td,th {word-break: break-all; padding: 0 3px;}\n")
_T(".ln { text - align: right; word - break: normal; color: #000000; background - color: #f0f0f0; }\n")
_T("<style>\n")
+ tableStyle + tdthStyle +
_T(".ln { text-align: right; word-break: normal; color: #000000; background-color: #f0f0f0; }\n")
+ GetHTMLStyles() +
_T("</style>\n")
_T("</head>\n")
_T("<body>\n")
_T("<table>\n")
+ colgroup
);
if (m_pTextBuffer->GetTableEditing())
{
CString columnHeader = _T("<th class=\"cn\"></th>");
for (int nColumn = 0; nColumn < nColumnCountMax; nColumn++)
columnHeader += _T("<th class=\"cn\">") + GetColumnName(nColumn) + _T("</th>");
file.WriteString(columnHeader);
file.WriteString(_T("</tr>"));
}
for (int line = 0; line < GetLineCount(); ++line)
{
CString ln;
Expand All @@ -215,7 +236,7 @@ bool CSampleView::ConvertToHTML(const CString& filename)
ln.Format(_T("<td class=\"ln\"></td>"));
file.WriteString(_T("<tr>"));
file.WriteString(ln);
file.WriteString(GetHTMLLine(line, _T("td")));
file.WriteString(GetHTMLLine(line, _T("td"), nColumnCountMax));
file.WriteString(_T("</tr>\n"));
}
file.WriteString(
Expand Down
19 changes: 18 additions & 1 deletion Externals/crystaledit/editlib/ccrystaltextbuffer.cpp
Original file line number Diff line number Diff line change
Expand Up @@ -2017,8 +2017,10 @@ void CCrystalTextBuffer::SetColumnWidths (const std::vector<int>& columnWidths)

int CCrystalTextBuffer::GetColumnCount (int nLineIndex) const
{
if (!GetTableEditing ())
return 1;
ASSERT( nLineIndex >= 0 );
int nColumnCount = 0;
int nColumnCount = 1;
const tchar_t* pszLine = GetLineChars (nLineIndex);
int nLength = GetLineLength (nLineIndex);
bool bInQuote = false;
Expand All @@ -2032,6 +2034,21 @@ int CCrystalTextBuffer::GetColumnCount (int nLineIndex) const
return nColumnCount;
}

int CCrystalTextBuffer::GetColumnCountMax () const
{
if (!GetTableEditing ())
return 1;
int nColumnCountMax = 0;
const int nLineCount = GetLineCount ();
for (int i = 0; i < nLineCount; ++i)
{
const int nColumnCount = GetColumnCount (i);
if (nColumnCountMax < nColumnCount)
nColumnCountMax = nColumnCount;
}
return nColumnCountMax;
}

std::basic_string<tchar_t> CCrystalTextBuffer::GetCellText (int nLineIndex, int nColumnIndex) const
{
ASSERT( nLineIndex >= 0 && nColumnIndex >= 0 && GetTableEditing() );
Expand Down
1 change: 1 addition & 0 deletions Externals/crystaledit/editlib/ccrystaltextbuffer.h
Original file line number Diff line number Diff line change
Expand Up @@ -297,6 +297,7 @@ public :
const std::vector<int>& GetColumnWidths () const { return m_pSharedTableProps->m_aColumnWidths; }
void SetColumnWidths (const std::vector<int>& columnWidths);
int GetColumnCount (int nLineIndex) const;
int GetColumnCountMax () const;
std::basic_string<tchar_t> GetCellText (int nLineIndex, int nColumnIndex) const;
void SetAllowNewlinesInQuotes (bool bAllowNewlinesInQuotes) { m_bAllowNewlinesInQuotes = bAllowNewlinesInQuotes; }
tchar_t GetAllowNewlinesInQuotes () const { return m_bAllowNewlinesInQuotes; }
Expand Down
183 changes: 137 additions & 46 deletions Externals/crystaledit/editlib/ccrystaltextview.cpp
Original file line number Diff line number Diff line change
Expand Up @@ -2229,7 +2229,10 @@ GetHTMLStyles ()
}
CEColor clrSelMargin = GetColor(COLORINDEX_SELMARGIN);
CEColor clrNormalText = GetColor(COLORINDEX_NORMALTEXT);
strStyles += Fmt(_T(".ln {text-align: right; word-break: normal; color: #%02x%02x%02x; background-color: #%02x%02x%02x;}\n"),
strStyles += Fmt(_T(".cn {text-align: center; word-break: normal; color: #%02x%02x%02x; background-color: #%02x%02x%02x;}\n")
_T(".ln {text-align: right; word-break: normal; color: #%02x%02x%02x; background-color: #%02x%02x%02x;}\n"),
GetRValue(clrNormalText), GetGValue(clrNormalText), GetBValue(clrNormalText),
GetRValue(clrSelMargin), GetGValue(clrSelMargin), GetBValue(clrSelMargin),
GetRValue(clrNormalText), GetGValue(clrNormalText), GetBValue(clrNormalText),
GetRValue(clrSelMargin), GetGValue(clrSelMargin), GetBValue(clrSelMargin));
return strStyles;
Expand Down Expand Up @@ -2277,14 +2280,30 @@ GetHTMLAttribute (int nColorIndex, int nBgColorIndex, CEColor crText, CEColor cr
return strAttr;
}

CString CCrystalTextView::
GetColumnName(int nColumn)
{
CString columnName;
for (int i = 0; ; ++i)
{
tchar_t c = 'A' + (nColumn % 26) - (i == 0 ? 0 : 1);
columnName.Insert (0, c);
nColumn /= 26;
if (nColumn == 0)
break;
}
return columnName;
};

/**
* @brief Retrieve the html version of the line
* @param [in] nLineIndex Index of line in view
* @param [in] pszTag The HTML tag to enclose the line
* @param [in] nColumnCountMax Maximum number of columns
* @return The html version of the line
*/
CString CCrystalTextView::
GetHTMLLine (int nLineIndex, const tchar_t* pszTag)
GetHTMLLine (int nLineIndex, const tchar_t* pszTag, int nColumnCountMax)
{
ASSERT (nLineIndex >= -1 && nLineIndex < GetLineCount ());

Expand All @@ -2296,47 +2315,133 @@ GetHTMLLine (int nLineIndex, const tchar_t* pszTag)
GetLineColors (nLineIndex, crBkgnd, crText, bDrawWhitespace);

std::vector<TEXTBLOCK> blocks = GetTextBlocks(nLineIndex);

int nColumn = 0;
const int nColumnCount = m_pTextBuffer->GetColumnCount (nLineIndex);
CString strHTML;
CString strExpanded;
size_t i;
int nNonbreakChars = 0;
bool bLastCharSpace = false;
const int nScreenChars = 40; // GetScreenChars();

strHTML += _T("<");
strHTML += pszTag;
strHTML += _T(" ");
strHTML += GetHTMLAttribute (COLORINDEX_NORMALTEXT, COLORINDEX_BKGND, crText, crBkgnd);
strHTML += _T("><code>");

auto MakeSpan = [&](const TEXTBLOCK& block, const CString& strExpanded) {
CString strHTML;
strHTML += _T("<span ");
strHTML += GetHTMLAttribute (block.m_nColorIndex, block.m_nBgColorIndex, crText, crBkgnd);
strHTML += _T(">");
strHTML += EscapeHTML (strExpanded, bLastCharSpace, nNonbreakChars, nScreenChars);
strHTML += _T("</span>");
return strHTML;
};
CString strHTML;
strHTML += _T("<span ");
strHTML += GetHTMLAttribute (block.m_nColorIndex, block.m_nBgColorIndex, crText, crBkgnd);
strHTML += _T(">");
strHTML += EscapeHTML (strExpanded, bLastCharSpace, nNonbreakChars, nScreenChars);
strHTML += _T("</span>");
return strHTML;
};

for (i = 0; i < blocks.size() - 1; i++)
const TextLayoutMode layoutMode = GetTextLayoutMode ();
if (layoutMode == TEXTLAYOUT_TABLE_NOWORDWRAP ||
layoutMode == TEXTLAYOUT_TABLE_WORDWRAP)
{
ExpandChars (nLineIndex, blocks[i].m_nCharPos, blocks[i + 1].m_nCharPos - blocks[i].m_nCharPos, strExpanded, 0);
if (!strExpanded.IsEmpty())
strHTML += MakeSpan(blocks[i], strExpanded);
std::vector<int> anBreaks;
if (layoutMode == TEXTLAYOUT_TABLE_WORDWRAP)
{
int nBreaks = 0;
anBreaks.resize (GetLineLength(nLineIndex) + 1);
WrapLineCached ( nLineIndex, nScreenChars, &anBreaks, nBreaks );
}
anBreaks.push_back (-nLength);

const tchar_t* pszChars = GetLineChars (nLineIndex);
const int sep = m_pTextBuffer->GetFieldDelimiter ();
const int quote = m_pTextBuffer->GetFieldEnclosure ();
bool bInQuote = false;

strHTML += _T("<");
strHTML += pszTag;
strHTML += _T(" ");
if (nColumn + 1 == nColumnCount && (nColumnCountMax - nColumn) > 1)
{
CString colspan;
colspan.Format (_T("colspan=\"%d\" "), nColumnCountMax - nColumn);
strHTML += colspan;
}
strHTML += GetHTMLAttribute (COLORINDEX_NORMALTEXT, COLORINDEX_BKGND, crText, crBkgnd);
strHTML += _T("><code>");
int k = 0;
for (size_t j = 0; j < blocks.size(); j++)
{
int blockBegin = blocks[j].m_nCharPos;
int blockEnd = (j + 1 < blocks.size()) ? blocks[j + 1].m_nCharPos : nLength;
for (int i = blockBegin; i < blockEnd; i++)
{
tchar_t c = pszChars[i];
if (abs(anBreaks[k]) == i)
{
if (anBreaks[k] >= 0)
{
ExpandChars (nLineIndex, blockBegin, i - blockBegin, strExpanded, 0);
strHTML += MakeSpan (blocks[j], strExpanded);
strHTML += _T("<br />");
blockBegin = i;
}
k++;
}
if (!bInQuote && c == sep)
{
ExpandChars (nLineIndex, blockBegin, i + 1 - blockBegin, strExpanded, 0);
strHTML += MakeSpan (blocks[j], strExpanded);
blockBegin = i + 1;
bLastCharSpace = false;
nNonbreakChars = 0;
nColumn++;
strHTML += _T("</code></");
strHTML += pszTag;
strHTML += _T("><");
strHTML += pszTag;
strHTML += _T(" ");
if (nColumn + 1 == nColumnCount && (nColumnCountMax - nColumn) > 1)
{
CString colspan;
colspan.Format (_T("colspan=\"%d\" "), nColumnCountMax - nColumn);
strHTML += colspan;
}
strHTML += GetHTMLAttribute (COLORINDEX_NORMALTEXT, COLORINDEX_BKGND, crText, crBkgnd);
strHTML += _T("><code>");
}
else if (c == quote)
{
bInQuote = !bInQuote;
}
}
ExpandChars (nLineIndex, blockBegin, blockEnd - blockBegin, strExpanded, 0);
strHTML += MakeSpan (blocks[j], strExpanded);
}
strHTML += _T("</code></");
strHTML += pszTag;
strHTML += _T(">");
}
if (blocks.size() > 0)
else
{
ExpandChars (nLineIndex, blocks[i].m_nCharPos, nLength - blocks[i].m_nCharPos, strExpanded, 0);
if (!strExpanded.IsEmpty())
strHTML += MakeSpan(blocks[i], strExpanded);
if (strExpanded.Compare (CString (' ', strExpanded.GetLength())) == 0)
strHTML += _T("&nbsp;");
strHTML += _T("<");
strHTML += pszTag;
strHTML += _T(" ");
strHTML += GetHTMLAttribute (COLORINDEX_NORMALTEXT, COLORINDEX_BKGND, crText, crBkgnd);
strHTML += _T("><code>");

size_t i;
for (i = 0; i < blocks.size() - 1; i++)
{
ExpandChars (nLineIndex, blocks[i].m_nCharPos, blocks[i + 1].m_nCharPos - blocks[i].m_nCharPos, strExpanded, 0);
if (!strExpanded.IsEmpty())
strHTML += MakeSpan(blocks[i], strExpanded);
}
if (blocks.size() > 0)
{
ExpandChars (nLineIndex, blocks[i].m_nCharPos, nLength - blocks[i].m_nCharPos, strExpanded, 0);
if (!strExpanded.IsEmpty())
strHTML += MakeSpan(blocks[i], strExpanded);
if (strExpanded.Compare (CString (' ', strExpanded.GetLength())) == 0)
strHTML += _T("&nbsp;");
}
strHTML += _T("</code></");
strHTML += pszTag;
strHTML += _T(">");
}
strHTML += _T("</code></");
strHTML += pszTag;
strHTML += _T(">");

return strHTML;
}
Expand Down Expand Up @@ -2364,20 +2469,6 @@ GetLineFlags (int nLineIndex) const
void CCrystalTextView::
GetTopMarginText (const CRect& rect, CString& text, std::vector<int>& nWidths)
{
auto getColumnName = [](int nColumn) -> CString
{
CString columnName;
for (int i = 0; ; ++i)
{
tchar_t c = 'A' + (nColumn % 26) - (i == 0 ? 0 : 1);
columnName.Insert (0, c);
nColumn /= 26;
if (nColumn == 0)
break;
}
return columnName;
};

auto replaceControlChars = [](const CString& text) -> CString
{
CString result;
Expand All @@ -2403,7 +2494,7 @@ GetTopMarginText (const CRect& rect, CString& text, std::vector<int>& nWidths)
if (m_nTopSubLine > 0 && m_nLineNumberUsedAsHeaders >= 0 && m_nLineNumberUsedAsHeaders < m_pTextBuffer->GetLineCount())
columnName = replaceControlChars (m_pTextBuffer->GetCellText (m_nLineNumberUsedAsHeaders, nColumn).c_str ()); // Use std::basic_string<tchar_t> instead of CString
if (columnName.IsEmpty())
columnName = getColumnName (nColumn);
columnName = GetColumnName (nColumn);
int columnNameLen = 0;
std::vector<int> nCharWidths;
for (int i = 0; i < columnName.GetLength(); ++i)
Expand Down
3 changes: 2 additions & 1 deletion Externals/crystaledit/editlib/ccrystaltextview.h
Original file line number Diff line number Diff line change
Expand Up @@ -628,7 +628,8 @@ protected :
virtual std::vector<CrystalLineParser::TEXTBLOCK> GetAdditionalTextBlocks (int nLineIndex);

public:
virtual CString GetHTMLLine (int nLineIndex, const tchar_t* pszTag);
virtual CString GetColumnName(int nColumn);
virtual CString GetHTMLLine (int nLineIndex, const tchar_t* pszTag, int nColumnCountMax);
virtual CString GetHTMLStyles ();
std::vector<CrystalLineParser::TEXTBLOCK> GetTextBlocks(int nLineIndex);
protected:
Expand Down
2 changes: 1 addition & 1 deletion Src/ImgMergeFrm.cpp
Original file line number Diff line number Diff line change
Expand Up @@ -2309,7 +2309,7 @@ bool CImgMergeFrame::GenerateReport(const String& sFileName, bool allPages) cons
_T("<!DOCTYPE html>\n")
_T("<html>\n")
_T("<head>\n")
_T("<meta http-equiv=\"Content-Type\" content=\"text/html; charset=UTF-8\">\n")
_T("<meta charset=\"UTF-8\">\n")
_T("<title>WinMerge Image Compare Report</title>\n")
_T("<style type=\"text/css\">\n")
_T("table { table-layout: fixed; width: 100%; height: 100%; border-collapse: collapse; }\n")
Expand Down
Loading

0 comments on commit 409280b

Please sign in to comment.