OSDN Git Service

add Utils
[tortoisegit/TortoiseGitJp.git] / Utils / MiscUI / HTMLFormatter.cpp
diff --git a/Utils/MiscUI/HTMLFormatter.cpp b/Utils/MiscUI/HTMLFormatter.cpp
new file mode 100644 (file)
index 0000000..0318332
--- /dev/null
@@ -0,0 +1,481 @@
+// TortoiseSVN - a Windows shell extension for easy version control\r
+\r
+// Copyright (C) 2003-2006,2008 - TortoiseSVN\r
+\r
+// This program is free software; you can redistribute it and/or\r
+// modify it under the terms of the GNU General Public License\r
+// as published by the Free Software Foundation; either version 2\r
+// of the License, or (at your option) any later version.\r
+\r
+// This program is distributed in the hope that it will be useful,\r
+// but WITHOUT ANY WARRANTY; without even the implied warranty of\r
+// MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the\r
+// GNU General Public License for more details.\r
+\r
+// You should have received a copy of the GNU General Public License\r
+// along with this program; if not, write to the Free Software Foundation,\r
+// 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301 USA.\r
+//\r
+#include "StdAfx.h"\r
+#include "htmlformatter.h"\r
+\r
+CHTMLFormatter::CHTMLFormatter(void)\r
+{\r
+}\r
+\r
+CHTMLFormatter::~CHTMLFormatter(void)\r
+{\r
+}\r
+\r
+CSize CHTMLFormatter::DrawHTML(CDC * pDC, CRect rect, CString str, LOGFONT font, BOOL bCalculate /* = FALSE */)\r
+{\r
+       CUIntArray nLengthLines;\r
+       int nLine = 0;\r
+       int nCmd = NONE;\r
+       STATEMACHINE nState = BEGIN_TAG;\r
+       int nAlign = ALIGN_LEFT;\r
+       BOOL bCloseTag = FALSE;\r
+\r
+       m_arLinkRects.RemoveAll();\r
+       m_arLinkURLs.RemoveAll();\r
+\r
+       CSize sz(0, 0);\r
+\r
+       if (str.IsEmpty())\r
+               return sz;\r
+\r
+       CPoint  pt = rect.TopLeft();\r
+       CPoint  ptCur = pt;\r
+       \r
+\r
+       COLORREF crText = pDC->GetTextColor();\r
+       COLORREF crBg = pDC->GetBkColor();\r
+\r
+       LOGFONT lf;\r
+    memcpy(&lf, &font, sizeof(LOGFONT));\r
+\r
+       CFont tempFont;\r
+       tempFont.CreateFontIndirect(&lf);\r
+\r
+       CFont * pOldFont = pDC->SelectObject(&tempFont);\r
+\r
+       TEXTMETRIC textMetric;\r
+       pDC->GetTextMetrics(&textMetric);\r
+       int nHeight = textMetric.tmHeight;\r
+       int nWidth = textMetric.tmAveCharWidth;\r
+\r
+       CString strTag = _T("");\r
+       CString strText = _T("");\r
+       UINT nParam = 0;\r
+       \r
+       CRect linkRect;\r
+       linkRect.SetRectEmpty();\r
+\r
+       CUIntArray percent;\r
+       percent.Add(0);\r
+       \r
+       int nTemp = 0; //the temporary variable\r
+       BOOL bFirstOutput = TRUE;\r
+\r
+       //iterate through all characters of the string\r
+       for (int i = 0; i <= str.GetLength(); i++)\r
+       {\r
+               if (i < str.GetLength())\r
+               {\r
+                       //Searches the command and parameters in the string\r
+                       switch (nState)\r
+                       {\r
+                       case BEGIN_TAG:\r
+                               //waiting for the begin of a tag (<tag>), newline ('\n' or '\r') or tab ('\t')\r
+                               switch (str.GetAt(i))\r
+                               {\r
+                               case _T('<'):\r
+                                       nState = TEXT_TAG;      //statemachine to 'waiting for the tag'\r
+                                       bCloseTag = FALSE;              //opening bracket\r
+                                       strTag = _T("");\r
+                                       break;\r
+                               case _T('\n'):\r
+                                       nCmd = NEW_LINE;\r
+                                       nParam = 1;\r
+                                       break;\r
+                               case _T('\t'):\r
+                                       nCmd = TABULATION;\r
+                                       nParam = 1;\r
+                                       break;\r
+                               case _T('\r'):\r
+                                       break;\r
+                               default: \r
+                                       strText += str.GetAt(i);\r
+                                       break;\r
+                               }\r
+                               break;\r
+                       case TEXT_TAG:\r
+                               //get the tag itself (until the closing bracket ('>'))\r
+                               switch (str.GetAt(i))\r
+                               {\r
+                               case _T('/'):\r
+                                       if (strTag.IsEmpty())\r
+                                               bCloseTag = TRUE; //found the char's cancel tag\r
+                                       break;\r
+                               case _T('<'):\r
+                                       if (strTag.IsEmpty())\r
+                                       {\r
+                                               nState = BEGIN_TAG;\r
+                                               strText += str.GetAt(i);\r
+                                       }\r
+                                       else strTag += str.GetAt(i);\r
+                                       break;\r
+                               case _T('='):\r
+                               case _T('>'):\r
+                                       i--;\r
+                               //case _T(' '):\r
+                                       //Analyses tags\r
+                                       if (strTag.CompareNoCase(_T("b"))==0)\r
+                                       {\r
+                                               //Bold text\r
+                                               nCmd = BOLD;\r
+                                               nState = END_TAG;\r
+                                       }\r
+                                       else if (strTag.CompareNoCase(_T("i")) == 0)\r
+                                       {\r
+                                               //Italic text\r
+                                               nCmd = ITALIC;\r
+                                               nState = END_TAG;\r
+                                       }\r
+                                       else if (strTag.CompareNoCase(_T("s")) == 0)\r
+                                       {\r
+                                               //Strikeout text\r
+                                               nCmd = STRIKE;\r
+                                               nState = END_TAG;\r
+                                       }\r
+                                       else if (strTag.CompareNoCase(_T("u")) == 0)\r
+                                       {\r
+                                               //Underline text\r
+                                               nCmd = UNDERLINE;\r
+                                               nState = END_TAG;\r
+                                       }\r
+                                       else if (strTag.CompareNoCase(_T("t")) == 0)\r
+                                       {\r
+                                               //Tabulation\r
+                                               nCmd = TABULATION;\r
+                                               nParam = 1;\r
+                                               nState = BEGIN_NUMBER;\r
+                                       }\r
+                                       else if (strTag.CompareNoCase(_T("ct")) == 0)\r
+                                       {\r
+                                               //Color of the text\r
+                                               nCmd = COLOR_TEXT;\r
+                                               nParam = crText;\r
+                                               nState = BEGIN_NUMBER;\r
+                                       }\r
+                                       else if (strTag.CompareNoCase(_T("cb")) == 0)\r
+                                       {\r
+                                               //Color of the background\r
+                                               nCmd = COLOR_BK;\r
+                                               nParam = crBg;\r
+                                               nState = BEGIN_NUMBER;\r
+                                       }\r
+                                       else if (strTag.CompareNoCase(_T("al")) == 0)\r
+                                       {\r
+                                               //left align\r
+                                               nAlign = ALIGN_LEFT;\r
+                                               nState = END_TAG;\r
+                                       }\r
+                                       else if (strTag.CompareNoCase(_T("ac")) == 0)\r
+                                       {\r
+                                               //center align\r
+                                               if (!bCalculate)\r
+                                                       nAlign = bCloseTag ? ALIGN_LEFT : ALIGN_CENTER;\r
+                                               nState = END_TAG;\r
+                                       }\r
+                                       else if (strTag.CompareNoCase(_T("ar")) == 0)\r
+                                       {\r
+                                               //right align\r
+                                               if (!bCalculate)\r
+                                                       nAlign = bCloseTag ? ALIGN_LEFT : ALIGN_RIGHT;\r
+                                               nState = END_TAG;\r
+                                       }\r
+                                       else if (strTag.CompareNoCase(_T("hr")) == 0)\r
+                                       {\r
+                                               //horizontal line\r
+                                               nCmd = HORZ_LINE_PERCENT;\r
+                                               nParam = 100;\r
+                                               nState = BEGIN_NUMBER;\r
+                                       }\r
+                                       else if (strTag.CompareNoCase(_T("a")) == 0)\r
+                                       {\r
+                                               //link\r
+                                               nCmd = LINK;\r
+                                               nState = BEGIN_URL;     //wait for '='\r
+                                       }\r
+                                       else nState = END_TAG; //Unknown tag\r
+                                       break;\r
+                               default:\r
+                                       strTag += str.GetAt(i);\r
+                                       break;\r
+                               }\r
+                               break;\r
+                       case END_TAG:\r
+                               //waiting for the end of the tag\r
+                               if (str.GetAt(i) == _T('>'))\r
+                                       nState = BEGIN_TAG;\r
+                               break;\r
+                       case BEGIN_NUMBER:\r
+                               //waiting for the start of a number\r
+                               if (str.GetAt(i) == _T('='))\r
+                               {\r
+                                       strTag = _T("");\r
+                                       nState = TEXT_NUMBER;\r
+                               }\r
+                               else if (str.GetAt(i) == _T('>'))\r
+                                       nState = BEGIN_TAG; //not a number\r
+                               break;\r
+                       case BEGIN_URL:\r
+                               //waiting for the start of a number\r
+                               if (str.GetAt(i) == _T('='))\r
+                               {\r
+                                       strTag = _T("");\r
+                                       nState = TEXT_URL;\r
+                               }\r
+                               else if (str.GetAt(i) == _T('>'))\r
+                                       nState = BEGIN_TAG; //not a url\r
+                               break;\r
+                       case TEXT_NUMBER:\r
+                               //waiting for a number string\r
+                               switch (str.GetAt(i))\r
+                               {\r
+                               case _T('>'):\r
+                                       i --;\r
+                                       //intended fall through!\r
+                               case _T('%'):\r
+                                       //Gets the real number from the string\r
+                                       if (!strTag.IsEmpty())\r
+                                               nParam = _tcstoul(strTag, 0, 0);\r
+                                       nState = END_TAG;\r
+                                       break;\r
+                               default:\r
+                                       strTag += str.GetAt(i);\r
+                                       break;\r
+                               }\r
+                               break;\r
+                       case TEXT_URL:\r
+                               //waiting for a url\r
+                               switch (str.GetAt(i))\r
+                               {\r
+                               case _T('>'):\r
+                                       i--;\r
+                                       if (!strTag.IsEmpty())\r
+                                               m_arLinkURLs.Add(strTag);\r
+                                       nState = END_TAG;\r
+                                       break;\r
+                               default:\r
+                                       strTag += str.GetAt(i);\r
+                                       break;\r
+                               }\r
+                       } // switch (nState)\r
+               }\r
+               else\r
+               {\r
+                       //Immitates new line at the end of the string\r
+                       nState = BEGIN_TAG;\r
+                       nCmd = NEW_LINE;\r
+                       nParam = 1;\r
+               }\r
+\r
+               if ((nState == BEGIN_TAG) && (nCmd != NONE))\r
+               {\r
+                       //New Command with full parameters\r
+                       if (!strText.IsEmpty())\r
+                       {\r
+                               if (bFirstOutput)\r
+                               {\r
+                                       switch (nAlign)\r
+                                       {\r
+                                       case ALIGN_CENTER:\r
+                                               ptCur.x = pt.x + (rect.Width() - nLengthLines.GetAt(nLine)) / 2;\r
+                                               break;\r
+                                       case ALIGN_RIGHT:\r
+                                               ptCur.x = pt.x + rect.Width() - nLengthLines.GetAt(nLine);\r
+                                               break;\r
+                                       }\r
+                               }\r
+                               if (!bCalculate)\r
+                                       pDC->TextOut(ptCur.x, ptCur.y, strText);\r
+                               CSize s = pDC->GetTextExtent(strText);\r
+                               linkRect.left = ptCur.x;\r
+                               linkRect.top = ptCur.y;\r
+                               linkRect.right = linkRect.left + s.cx;\r
+                               linkRect.bottom = linkRect.top + s.cy;\r
+                               ptCur.x += s.cx;\r
+                               strText = _T("");\r
+                               bFirstOutput = FALSE;\r
+                       }\r
+                       \r
+                       //Executes command\r
+                       switch (nCmd)\r
+                       {\r
+                       case LINK:\r
+                               if (bCloseTag)\r
+                               {\r
+                                       //closing the link\r
+                                       m_arLinkRects.Add(linkRect);\r
+                                       linkRect.SetRectEmpty();\r
+                               }\r
+                               break;\r
+                       case BOLD:\r
+                               //Bold text\r
+                               pDC->SelectObject(pOldFont);\r
+                               tempFont.DeleteObject();\r
+                               lf.lfWeight = font.lfWeight;\r
+                               if (!bCloseTag)\r
+                               {\r
+                                       lf.lfWeight *= 2;\r
+                                       if (lf.lfWeight > FW_BLACK)\r
+                                               lf.lfWeight = FW_BLACK;\r
+                               }\r
+                               tempFont.CreateFontIndirect(&lf);\r
+                               pDC->SelectObject(&tempFont);\r
+                               break;\r
+                       case ITALIC:\r
+                               //Italic text\r
+                               pDC->SelectObject(pOldFont);\r
+                               tempFont.DeleteObject();\r
+                               lf.lfItalic = bCloseTag ? FALSE : TRUE;\r
+                               tempFont.CreateFontIndirect(&lf);\r
+                               pDC->SelectObject(&tempFont);\r
+                               break;\r
+                       case STRIKE:\r
+                               //Strikeout text\r
+                               pDC->SelectObject(pOldFont);\r
+                               tempFont.DeleteObject();\r
+                               lf.lfStrikeOut = bCloseTag ? FALSE : TRUE;\r
+                               tempFont.CreateFontIndirect(&lf);\r
+                               pDC->SelectObject(&tempFont);\r
+                               break;\r
+                       case UNDERLINE:\r
+                               //Underline text\r
+                               pDC->SelectObject(pOldFont);\r
+                               tempFont.DeleteObject();\r
+                               lf.lfUnderline = bCloseTag ? FALSE : TRUE;\r
+                               tempFont.CreateFontIndirect(&lf);\r
+                               pDC->SelectObject(&tempFont);\r
+                               break;\r
+                       case COLOR_TEXT:\r
+                               //Color of the text\r
+                               pDC->SetTextColor((COLORREF)nParam);\r
+                               break;\r
+                       case COLOR_BK:\r
+                               //Color of the background\r
+                               pDC->SetBkColor((COLORREF)nParam);\r
+                               pDC->SetBkMode(bCloseTag ? TRANSPARENT : OPAQUE);\r
+                               break;\r
+                       case HORZ_LINE_PERCENT:\r
+                               //Horizontal line with percent length\r
+                               if (bCalculate)\r
+                               {\r
+                                       percent.SetAt(nLine, percent.GetAt(nLine) + nParam);\r
+                                       nParam = 0;\r
+                               }\r
+                               else nParam = ::MulDiv(rect.Width(), nParam, 100);\r
+                       case HORZ_LINE:\r
+                               //Horizontal line with absolute length\r
+                               //If text to output is exist\r
+                               if (bFirstOutput)\r
+                               {\r
+                                       switch (nAlign)\r
+                                       {\r
+                                       case ALIGN_CENTER:\r
+                                               ptCur.x = pt.x + (rect.Width() - nLengthLines.GetAt(nLine)) / 2;\r
+                                               break;\r
+                                       case ALIGN_RIGHT:\r
+                                               ptCur.x = pt.x + rect.Width() - nLengthLines.GetAt(nLine);\r
+                                               break;\r
+                                       }\r
+                               }\r
+                               DrawHorzLine(pDC, ptCur.x, ptCur.x + nParam, ptCur.y + nHeight / 2);\r
+                               ptCur.x += nParam;\r
+                               bFirstOutput = FALSE;\r
+                               break;\r
+                       case NEW_LINE:\r
+                               //New line\r
+                               if (!nParam)\r
+                                       nParam = 1;\r
+                               sz.cx = max(sz.cx, ptCur.x - pt.x);\r
+                               nLengthLines.Add(ptCur.x - pt.x); //Adds the real length of the lines\r
+                               ptCur.y += nHeight * nParam;\r
+                               nLine ++;\r
+                               percent.Add(0);\r
+                               bFirstOutput = TRUE;\r
+                               ptCur.x = pt.x;\r
+                               break;\r
+                       case TABULATION:\r
+                               //Tabulation\r
+                               if (!nParam)\r
+                                       nParam = 1;\r
+                               nTemp = (ptCur.x - pt.x) % (nWidth * 4);\r
+                               if (nTemp)\r
+                               {\r
+                                       //aligns with tab\r
+                                       ptCur.x += (nWidth * 4) - nTemp;\r
+                                       nParam --;\r
+                               }\r
+                               ptCur.x += (nParam * nWidth * 4);\r
+                               break;\r
+                       }\r
+                       //Resets the last command\r
+                       nCmd = NONE;\r
+                       bCloseTag = FALSE;\r
+               }\r
+       }\r
+\r
+       //Gets real height of the tooltip\r
+       sz.cy = ptCur.y - pt.y;\r
+\r
+       pDC->SelectObject(pOldFont);\r
+       tempFont.DeleteObject();\r
+\r
+       //Adds the percent's length to the line's length\r
+       for (int i = 0; i < percent.GetSize(); i++)\r
+       {\r
+               if (percent.GetAt(i))\r
+                       nLengthLines.SetAt(i, nLengthLines.GetAt(i) + ::MulDiv(percent.GetAt(i), sz.cx, 100));\r
+       }\r
+\r
+       return sz;\r
+}\r
+\r
+void CHTMLFormatter::DrawHorzLine(CDC * pDC, int xStart, int xEnd, int y)\r
+{\r
+       CPen pen(PS_SOLID, 1, pDC->GetTextColor());\r
+       CPen * penOld = pDC->SelectObject(&pen);\r
+       pDC->MoveTo(xStart, y);\r
+       pDC->LineTo(xEnd, y);\r
+       pDC->SelectObject(penOld);\r
+       pen.DeleteObject();\r
+}\r
+\r
+BOOL CHTMLFormatter::IsPointOverALink(CPoint pt)\r
+{\r
+       CRect rect;\r
+       for (int i=0; i<m_arLinkRects.GetCount(); i++)\r
+       {\r
+               rect = m_arLinkRects.GetAt(i);\r
+               if (rect.PtInRect(pt))\r
+                       return TRUE;\r
+       }\r
+       return FALSE;\r
+}\r
+\r
+CString CHTMLFormatter::GetLinkForPoint(CPoint pt)\r
+{\r
+       CRect rect;\r
+       for (int i=0; i<m_arLinkRects.GetCount(); i++)\r
+       {\r
+               rect = m_arLinkRects.GetAt(i);\r
+               if (rect.PtInRect(pt))\r
+               {\r
+                       return m_arLinkURLs.GetAt(i);\r
+               }\r
+       }\r
+       return _T("");\r
+}\r