#include "stdafx.h" #include "column_inoutgraph.h" /* * ColInOutGraph */ ColInOutGraph::ColInOutGraph() : m_nSource(0), m_bAbsolute(false), m_nAbsTime(1), m_bShowSum(true), m_bDetail(true), m_bDetailPercent(false), m_bDetailInvert(false), m_bGraphPercent(true), m_hSource(NULL), m_hAbsolute(NULL), m_hAbsTime(NULL), m_hShowSum(NULL), m_hDetail(NULL), m_hDetailPercent(NULL), m_hDetailInvert(NULL), m_hGraphPercent(NULL) { } void ColInOutGraph::impl_copyConfig(const Column* pSource) { const ColInOutGraph& src = *reinterpret_cast(pSource); m_nSource = src.m_nSource; m_bAbsolute = src.m_bAbsolute; m_nAbsTime = src.m_nAbsTime; m_bShowSum = src.m_bShowSum; m_bDetail = src.m_bDetail; m_bDetailPercent = src.m_bDetailPercent; m_bDetailInvert = src.m_bDetailInvert; m_bGraphPercent = src.m_bGraphPercent; } void ColInOutGraph::impl_configRead(const SettingsTree& settings) { m_nSource = settings.readIntRanged(con::KeySource , 0, 0, 2); m_bAbsolute = settings.readBool (con::KeyAbsolute , false); m_nAbsTime = settings.readIntRanged(con::KeyAbsTime , 1, 0, 2); m_bShowSum = settings.readBool (con::KeyShowSum , true); m_bDetail = settings.readBool (con::KeyDetail , true); m_bDetailPercent = settings.readBool (con::KeyDetailPercent, false); m_bDetailInvert = settings.readBool (con::KeyDetailInvert , false); m_bGraphPercent = settings.readBool (con::KeyGraphPercent , true); } void ColInOutGraph::impl_configWrite(SettingsTree& settings) const { settings.writeInt (con::KeySource , m_nSource ); settings.writeBool(con::KeyAbsolute , m_bAbsolute ); settings.writeInt (con::KeyAbsTime , m_nAbsTime ); settings.writeBool(con::KeyShowSum , m_bShowSum ); settings.writeBool(con::KeyDetail , m_bDetail ); settings.writeBool(con::KeyDetailPercent, m_bDetailPercent); settings.writeBool(con::KeyDetailInvert , m_bDetailInvert ); settings.writeBool(con::KeyGraphPercent , m_bGraphPercent ); } void ColInOutGraph::impl_configToUI(OptionsCtrl& Opt, OptionsCtrl::Item hGroup) { OptionsCtrl::Group hTemp; hTemp = Opt.insertGroup(hGroup, TranslateT("Data source")); m_hSource = Opt.insertRadio(hTemp, NULL, TranslateT("Characters")); Opt.insertRadio(hTemp, m_hSource, TranslateT("Messages")); Opt.insertRadio(hTemp, m_hSource, TranslateT("Chats")); hTemp = Opt.insertGroup(hGroup, TranslateT("Display as")); m_hAbsolute = Opt.insertRadio(hTemp, NULL, TranslateT("Absolute")); m_hAbsolute = Opt.insertRadio(hTemp, m_hAbsolute, TranslateT("Average"), OptionsCtrl::OCF_DISABLECHILDSONUNCHECK); m_hAbsTime = Opt.insertRadio(m_hAbsolute, NULL, TranslateT("Units per day")); Opt.insertRadio(m_hAbsolute, m_hAbsTime, TranslateT("Units per week")); Opt.insertRadio(m_hAbsolute, m_hAbsTime, TranslateT("Units per month (30 days)")); m_hShowSum = Opt.insertCheck(hGroup, TranslateT("Show sum of incoming and outgoing")); m_hDetail = Opt.insertCheck(hGroup, TranslateT("In/out details (tooltip)"), OptionsCtrl::OCF_DISABLECHILDSONUNCHECK); m_hDetailPercent = Opt.insertCheck(m_hDetail, TranslateT("Percentage in tooltip")); m_hDetailInvert = Opt.insertCheck(m_hDetail, TranslateT("Absolute in tooltip if average selected and vice versa")); m_hGraphPercent = Opt.insertCheck(hGroup, TranslateT("Percentage in bar graph")); Opt.setRadioChecked(m_hSource , m_nSource ); Opt.setRadioChecked(m_hAbsolute , m_bAbsolute ? 0 : 1); Opt.setRadioChecked(m_hAbsTime , m_nAbsTime ); Opt.checkItem (m_hShowSum , m_bShowSum ); Opt.checkItem (m_hDetail , m_bDetail ); Opt.checkItem (m_hDetailPercent, m_bDetailPercent ); Opt.checkItem (m_hDetailInvert , m_bDetailInvert ); Opt.checkItem (m_hGraphPercent , m_bGraphPercent ); } void ColInOutGraph::impl_configFromUI(OptionsCtrl& Opt) { m_nSource = Opt.getRadioChecked(m_hSource); m_bAbsolute = (Opt.getRadioChecked(m_hAbsolute) == 0); m_nAbsTime = Opt.getRadioChecked(m_hAbsTime); m_bShowSum = Opt.isItemChecked(m_hShowSum); m_bDetail = Opt.isItemChecked(m_hDetail); m_bDetailPercent = Opt.isItemChecked(m_hDetailPercent); m_bDetailInvert = Opt.isItemChecked(m_hDetailInvert); m_bGraphPercent = Opt.isItemChecked(m_hGraphPercent); } Column::StyleList ColInOutGraph::impl_outputGetAdditionalStyles(IDProvider& idp) { StyleList l; m_CSS = idp.getID(); l.push_back(StylePair(_T("td.") + m_CSS, _T("vertical-align: middle; padding: 2px 2px 2px 2px;"))); if (m_bShowSum) { l.push_back(StylePair(_T("td.") + m_CSS + _T(" div.n"), _T("text-align: center;"))); } if (!usePNG()) { l.push_back(StylePair(_T("div.") + m_CSS, _T("position: relative; left: 50%; margin-left: -50px; width: 100px; height: 15px; background-color: ") + utils::colorToHTML(con::ColorBack) + _T(";"))); l.push_back(StylePair(_T("div.") + m_CSS + _T(" div"), _T("position: absolute; top: 0px; height: 15px; overflow: hidden; font-size: 80%; color: ") + utils::colorToHTML(con::ColorBack) + _T(";"))); l.push_back(StylePair(_T("div.") + m_CSS + _T(" div.obar"), _T("left: 0px; background-color: ") + utils::colorToHTML(con::ColorOut) + _T(";"))); l.push_back(StylePair(_T("div.") + m_CSS + _T(" div.ibar"), _T("right: 0px; background-color: ") + utils::colorToHTML(con::ColorIn) + _T(";"))); if (m_bGraphPercent) { l.push_back(StylePair(_T("div.") + m_CSS + _T(" div.otext"), _T("left: 2px; width: 48px; text-align: left; z-index: 9;"))); l.push_back(StylePair(_T("div.") + m_CSS + _T(" div.itext"), _T("right: 2px; width: 48px; text-align: right; z-index: 9;"))); } } return l; } SIZE ColInOutGraph::impl_outputMeasureHeader() const { SIZE colSize = { 2, 2 }; return colSize; } void ColInOutGraph::impl_outputRenderHeader(ext::ostream& tos, int row, int rowSpan) const { static const TCHAR* szSourceDesc[] = { LPGENT("Characters"), LPGENT("Messages"), LPGENT("Chats") }; static const TCHAR* szSourceUnit[] = { LPGENT("day"), LPGENT("week"), LPGENT("month"), }; if (row == 1) { ext::string strTitle; if (m_bAbsolute) { strTitle = TranslateTS(szSourceDesc[m_nSource]); } else { strTitle = str(ext::kformat(TranslateT("#{data} per #{unit}")) % _T("#{data}") * TranslateTS(szSourceDesc[m_nSource]) % _T("#{unit}") * TranslateTS(szSourceUnit[m_nAbsTime])); } writeRowspanTD(tos, getCustomTitle(TranslateTS(szSourceDesc[m_nSource]), strTitle) + _T("
"), 1, 2, rowSpan, 2); } else if (row == 2) { writeRowspanTD(tos, TranslateT("Outgoing"), 2, 2, rowSpan); writeRowspanTD(tos, TranslateT("Incoming"), 2, 2, rowSpan); } } void ColInOutGraph::impl_outputRenderRow(ext::ostream& tos, const Contact& contact, DisplayType) { // fetch absolute values static int (Contact::*getOut[3])() const = { &Contact::getOutBytes, &Contact::getOutMessages, &Contact::getOutChats }; static int (Contact::*getIn[3])() const = { &Contact::getInBytes, &Contact::getInMessages, &Contact::getInChats }; int numOut = (contact.*getOut[m_nSource])(); int numIn = (contact.*getIn[m_nSource])(); int numTotal = numOut + numIn; // fetch average values static double (Contact::*getAvgOut[3])() const = { &Contact::getOutBytesAvg, &Contact::getOutMessagesAvg, &Contact::getOutChatsAvg }; static double (Contact::*getAvgIn[3])() const = { &Contact::getInBytesAvg, &Contact::getInMessagesAvg, &Contact::getInChatsAvg }; static double (Contact::*getAvgTotal[3])() const = { &Contact::getTotalBytesAvg, &Contact::getTotalMessagesAvg, &Contact::getTotalChatsAvg }; static const double avgFactor[] = { 60.0 * 60.0 * 24.0, 60.0 * 60.0 * 24.0 * 7.0, 60.0 * 60.0 * 24.0 * 30.0, }; double avgOut = avgFactor[m_nAbsTime] * (contact.*getAvgOut[m_nSource])(); double avgIn = avgFactor[m_nAbsTime] * (contact.*getAvgIn[m_nSource])(); double avgTotal = avgFactor[m_nAbsTime] * (contact.*getAvgTotal[m_nSource])(); // begin output tos << _T(""); } else { tos << _T("\" title=\"") << utils::htmlEscape(ext::str(ext::kformat(TranslateT("[Out] #{out_amount} / [In] #{in_amount}")) % _T("#{out_amount}") * strOut % _T("#{in_amount}") * strIn)) << _T("\">"); } } else { tos << _T("\">"); } if (numOut + numIn == 0) { numOut = numIn = 1; } int allNum = numIn + numOut; int outW = (int) (99.0 * numOut / allNum); int inW = 99 - outW; if (outW == 99) { outW++; } if (inW == 99) { inW++; } if (usePNG()) { tos << _T("
"); if (m_bShowSum) { tos << (m_bAbsolute ? utils::intToGrouped(numTotal) : utils::floatToGrouped(avgTotal, 1)) << _T("
"); } // draw graph Canvas canvas(100, 15); canvas.fillBackground(con::ColorBack); HDC hDC = canvas.beginDraw(); SetBkColor(hDC, con::ColorOut); ExtTextOut(hDC, 0, 0, ETO_OPAQUE, &utils::rect(0, 0, outW, 15), NULL, 0, NULL); SetBkColor(hDC, con::ColorIn); ExtTextOut(hDC, 0, 0, ETO_OPAQUE, &utils::rect(100 - inW, 0, 100, 15), NULL, 0, NULL); if (m_bGraphPercent) { SetBkMode(hDC, TRANSPARENT); SetTextColor(hDC, con::ColorBack); RECT r = { 2, 0, 98, 14 }; LOGFONT lf = { -MulDiv(8, GetDeviceCaps(hDC, LOGPIXELSY), 72), 0, 0, 0, FW_NORMAL, FALSE, FALSE, FALSE, ANSI_CHARSET, OUT_DEFAULT_PRECIS, CLIP_DEFAULT_PRECIS, DEFAULT_QUALITY, DEFAULT_PITCH | FF_SWISS, _T("Verdana") }; HFONT hFont = CreateFontIndirect(&lf); HGDIOBJ hOldFont = SelectObject(hDC, hFont); DrawText(hDC, utils::ratioToPercent(numOut, allNum).c_str(), -1, &r, DT_LEFT | DT_VCENTER | DT_NOPREFIX | DT_SINGLELINE); DrawText(hDC, utils::ratioToPercent(numIn, allNum).c_str(), -1, &r, DT_RIGHT | DT_VCENTER | DT_NOPREFIX | DT_SINGLELINE); SelectObject(hDC, hOldFont); } canvas.endDraw(); // write PNG file ext::string strFinalFile; if (getStatistic()->newFilePNG(canvas, strFinalFile)) { tos << _T(""); } tos << _T("
"); } else { if (m_bShowSum) { tos << _T("
") << (m_bAbsolute ? utils::intToGrouped(numTotal) : utils::floatToGrouped(avgTotal, 1)) << _T("
"); } tos << _T("
"); if (outW != 0) { tos << _T("
"); } if (inW != 0) { tos << _T("
"); } if (m_bGraphPercent) { tos << _T("
") << utils::ratioToPercent(numOut, allNum) << _T("
"); tos << _T("
") << utils::ratioToPercent(numIn, allNum) << _T("
"); } tos << _T("
"); } tos << _T("") << ext::endl; }