From 2c3064fb562ab3bba8d18f0780f606db85272998 Mon Sep 17 00:00:00 2001 From: Alexey Sokolov Date: Wed, 8 Apr 2015 23:39:50 +0100 Subject: [PATCH] Make tables... not so tabular. Fix #743 Fix #914 Close #922 --- include/znc/Utils.h | 1 + src/Utils.cpp | 143 +++----------------------------------------- 2 files changed, 9 insertions(+), 135 deletions(-) diff --git a/include/znc/Utils.h b/include/znc/Utils.h index 2322a8aa..ceb3bb36 100644 --- a/include/znc/Utils.h +++ b/include/znc/Utils.h @@ -199,6 +199,7 @@ private: static VCString WrapWords(const CString& s, size_type uWidth); protected: + // TODO: cleanup these fields before 1.7.0 (I don't want to break ABI) VCString m_vsHeaders; std::vector m_vuMaxWidths; // Column don't need to be bigger than this std::vector m_vuMinWidths; // Column can't be thiner than this diff --git a/src/Utils.cpp b/src/Utils.cpp index 963a4e4d..9e977afe 100644 --- a/src/Utils.cpp +++ b/src/Utils.cpp @@ -555,9 +555,6 @@ bool CTable::AddColumn(const CString& sName, bool bWrappable) { } m_vsHeaders.push_back(sName); - m_vuMaxWidths.push_back(sName.size()); - // TODO: Maybe headers can be wrapped too? - m_vuMinWidths.push_back(sName.size()); m_vbWrappable.push_back(bWrappable); return true; @@ -590,27 +587,6 @@ bool CTable::SetCell(const CString& sColumn, const CString& sValue, size_type uR (*this)[uRowIdx][uColIdx] = sValue; - if (sValue.length() > m_vuMaxWidths[uColIdx]) { - m_vuMaxWidths[uColIdx] = sValue.length(); - } - - if (m_vbWrappable[uColIdx]) { - VCString vsWords; - sValue.Split(" ", vsWords); - size_type uMaxWord = 0; - for (const CString& sWord : vsWords) { - if (sWord.length() > uMaxWord) { - uMaxWord = sWord.length(); - } - } - // We can't shrink column further than the longest word in it - if (uMaxWord > m_vuMinWidths[uColIdx]) { - m_vuMinWidths[uColIdx] = uMaxWord; - } - } else { - m_vuMinWidths[uColIdx] = m_vuMaxWidths[uColIdx]; - } - return true; } @@ -629,122 +605,22 @@ bool CTable::GetLine(unsigned int uIdx, CString& sLine) const { } VCString CTable::Render() const { - size_type uTotalWidth = 1; // '|' - for (size_type uWidth : m_vuMaxWidths) { - uTotalWidth += uWidth + 3; // '|', ' 'x2 - } - - std::vector vuWidth = m_vuMaxWidths; - - std::map miColumnSpace; - for (unsigned int i = 0; i < m_vsHeaders.size(); ++i) { - int iSpace = m_vuMaxWidths[i] - m_vuMinWidths[i]; - if (iSpace > 0) { - miColumnSpace[i] = iSpace; - } - } - - // Not very efficient algorithm, and doesn't produce very good results... - while (uTotalWidth > m_uPreferredWidth) { - std::vector viToErase; - for (auto& i : miColumnSpace) { - uTotalWidth--; - i.second--; - vuWidth[i.first]--; - if (i.second == 0) { - viToErase.push_back(i.first); - } - if (uTotalWidth == m_uPreferredWidth) { - break; - } - } - for (int iCol : viToErase) { - miColumnSpace.erase(iCol); - } - if (miColumnSpace.empty()) { - // Every column is at its minimum width now, but total width is still more than preferred width - break; - } - } - - CString sHorizontal; - { - std::ostringstream ssLine; - ssLine << std::setfill('-'); - ssLine << "+"; - for (size_type uWidth : vuWidth) { - ssLine << std::setw(uWidth + 2) << std::left << "-"; - ssLine << "+"; - } - sHorizontal = ssLine.str(); - } VCString vsOutput; - vsOutput.emplace_back(sHorizontal.Replace_n("-", "=")); - { - std::ostringstream ssLine; - ssLine << "|"; - for (unsigned int iCol = 0; iCol < vuWidth.size(); ++iCol) { - ssLine << " "; - ssLine << std::setw(vuWidth[iCol]) << std::left; - ssLine << m_vsHeaders[iCol] << " |"; - } - vsOutput.emplace_back(ssLine.str()); - } - vsOutput.emplace_back(vsOutput[0]); + vsOutput.reserve((m_vsHeaders.size() + 1) * size() + 1); for (const VCString& vsRow : *this) { - // Wrap words - std::vector vvsColumns; - vvsColumns.reserve(m_vsHeaders.size()); - unsigned int uRowNum = 1; - for (unsigned int iCol = 0; iCol < vuWidth.size(); ++iCol) { - if (m_vbWrappable[iCol]) { - vvsColumns.emplace_back(WrapWords(vsRow[iCol], vuWidth[iCol])); - } else { - vvsColumns.push_back({vsRow[iCol]}); - } - if (vvsColumns.back().size() > uRowNum) { - uRowNum = vvsColumns.back().size(); + vsOutput.emplace_back("------"); + for (unsigned int i = 0; i < m_vsHeaders.size(); ++i) { + if (!vsRow[i].empty()) { + vsOutput.emplace_back(m_vsHeaders[i] + ": " + vsRow[i]); } } - CString sEmpty; - for (size_type uCurrentLine = 0; uCurrentLine < uRowNum; ++uCurrentLine) { - std::ostringstream ssLine; - ssLine << "|"; - for (unsigned int iCol = 0; iCol < vvsColumns.size(); ++iCol) { - const CString& sData = uCurrentLine < vvsColumns[iCol].size() ? vvsColumns[iCol][uCurrentLine] : sEmpty; - ssLine << " "; - ssLine << std::setw(vuWidth[iCol]) << std::left; - ssLine << sData << " |"; - } - vsOutput.emplace_back(ssLine.str()); - } - vsOutput.emplace_back(sHorizontal); } - vsOutput.pop_back(); - vsOutput.emplace_back(vsOutput[0]); + vsOutput.emplace_back("------"); return vsOutput; } VCString CTable::WrapWords(const CString& s, size_type uWidth) { - VCString vsWords; - s.Split(" ", vsWords); - VCString vsResult; - vsResult.emplace_back(""); - for (const CString& sWord : vsWords) { - size_type uOldLen = vsResult.back().length(); - if (uOldLen != 0) { - uOldLen++; // ' ' - } - if (uOldLen + sWord.length() > uWidth) { - vsResult.emplace_back(sWord); - } else { - if (uOldLen != 0) { - vsResult.back() += " "; - } - vsResult.back() += sWord; - } - } - return vsResult; + return VCString(); } unsigned int CTable::GetColumnIndex(const CString& sName) const { @@ -759,10 +635,7 @@ unsigned int CTable::GetColumnIndex(const CString& sName) const { } CString::size_type CTable::GetColumnWidth(unsigned int uIdx) const { - if (uIdx >= m_vsHeaders.size()) { - return 0; - } - return m_vuMaxWidths[uIdx]; + return 0; } void CTable::Clear() {