1
0
mirror of https://github.com/openSUSE/snapper.git synced 2026-02-06 09:46:06 +01:00
Files
snapper/client/utils/Table.cc
2012-04-27 12:08:18 +02:00

271 lines
7.1 KiB
C++

#include <iostream>
#include <cstring>
#include <cstdlib>
// #include "zypp/base/Logger.h"
#include "console.h"
#include "text.h"
#include "Table.h"
// libzypp logger settings
// #undef ZYPP_BASE_LOGGER_LOGGROUP
// #define ZYPP_BASE_LOGGER_LOGGROUP "zypper"
using namespace std;
TableLineStyle Table::defaultStyle = Ascii;
static
const char * lines[][3] = {
{ "|", "-", "+"}, ///< Ascii
// utf 8
{ "\xE2\x94\x82", "\xE2\x94\x80", "\xE2\x94\xBC"}, ///< light
{ "\xE2\x94\x83", "\xE2\x94\x81", "\xE2\x95\x8B"}, ///< heavy
{ "\xE2\x95\x91", "\xE2\x95\x90", "\xE2\x95\xAC"}, ///< double
{ "\xE2\x94\x86", "\xE2\x94\x84", "\xE2\x94\xBC"}, ///< light 3
{ "\xE2\x94\x87", "\xE2\x94\x85", "\xE2\x94\x8B"}, ///< heavy 3
{ "\xE2\x94\x82", "\xE2\x94\x81", "\xE2\x94\xBF"}, ///< v light, h heavy
{ "\xE2\x94\x82", "\xE2\x95\x90", "\xE2\x95\xAA"}, ///< v light, h double
{ "\xE2\x94\x83", "\xE2\x94\x80", "\xE2\x95\x82"}, ///< v heavy, h light
{ "\xE2\x95\x91", "\xE2\x94\x80", "\xE2\x95\xAB"}, ///< v double, h light
{ ":", "-", "+" }, ///< colon separated values
};
void TableRow::add (const string& s) {
_columns.push_back (s);
}
unsigned int TableRow::cols( void ) const {
return _columns.size();
}
// 1st implementation: no width calculation, just tabs
void TableRow::dumbDumpTo (ostream &stream) const {
bool seen_first = false;
for (container::const_iterator i = _columns.begin (); i != _columns.end (); ++i) {
if (seen_first)
stream << '\t';
seen_first = true;
stream << *i;
}
stream << endl;
}
void TableRow::dumpTo (ostream &stream, const Table & parent) const
{
const char * vline = parent._style != none ? lines[parent._style][0] : "";
unsigned int ssize = 0; // string size in columns
bool seen_first = false;
container::const_iterator
i = _columns.begin (),
e = _columns.end ();
stream.setf (ios::left, ios::adjustfield);
stream << string(parent._margin, ' ');
// current position at currently printed line
int curpos = parent._margin;
// whether to break the line now in order to wrap it to screen width
bool do_wrap = false;
for (unsigned c = 0; i != e ; ++i, ++c)
{
if (seen_first)
{
do_wrap =
// user requested wrapping
parent._do_wrap &&
// table is wider than screen
parent._width > parent._screen_width && (
// the next table column would exceed the screen size
curpos + (int) parent._max_width[c] + (parent._style != none ? 2 : 3) >
parent._screen_width ||
// or the user wishes to first break after the previous column
parent._force_break_after == (int) (c - 1));
if (do_wrap)
{
// start printing the next table columns to new line,
// indent by 2 console columns
stream << endl << string(parent._margin + 2, ' ');
curpos = parent._margin + 2; // indent == 2
}
else
// vertical line, padded with spaces
stream << ' ' << vline << ' ';
stream.width (0);
}
else
seen_first = true;
// stream.width (widths[c]); // that does not work with multibyte chars
const string & s = *i;
ssize = mbs_width (s);
if (ssize > parent._max_width[c])
{
unsigned cutby = parent._max_width[c] - 2;
string cutstr = mbs_substr_by_width(s, 0, cutby);
stream << cutstr << string(cutby - mbs_width(cutstr), ' ') << "->";
}
else
{
stream << s;
stream.width (parent._max_width[c] - ssize);
}
stream << "";
curpos += parent._max_width[c] + (parent._style != none ? 2 : 3);
}
stream << endl;
}
// ----------------------( Table )---------------------------------------------
Table::Table()
: _has_header (false)
, _max_col (0)
, _max_width(1, 0)
, _width(0)
, _style (defaultStyle)
, _screen_width(get_screen_width())
, _margin(0)
, _force_break_after(-1)
, _do_wrap(false)
{}
void Table::add (const TableRow& tr) {
_rows.push_back (tr);
updateColWidths (tr);
}
void Table::setHeader (const TableHeader& tr) {
_has_header = true;
_header = tr;
updateColWidths (tr);
}
void Table::allowAbbrev(unsigned column) {
if (column >= _abbrev_col.size()) {
_abbrev_col.reserve(column + 1);
_abbrev_col.insert(_abbrev_col.end(), column - _abbrev_col.size() + 1, false);
}
_abbrev_col[column] = true;
}
void Table::updateColWidths (const TableRow& tr) {
// how much columns spearators add to the width of the table
int sepwidth = _style == none ? 2 : 3;
// initialize the width to -sepwidth (the first column does not have a line
// on the left)
_width = -sepwidth;
TableRow::container::const_iterator
i = tr._columns.begin (),
e = tr._columns.end ();
for (unsigned c = 0; i != e; ++i, ++c) {
// ensure that _max_width[c] exists
if (_max_col < c)
{
_max_col = c;
_max_width.resize (_max_col + 1);
_max_width[c] = 0;
}
unsigned &max = _max_width[c];
unsigned cur = mbs_width (*i);
if (max < cur)
max = cur;
_width += max + sepwidth;
}
_width += _margin * 2;
}
void Table::dumpRule (ostream &stream) const {
const char * hline = _style != none ? lines[_style][1] : " ";
const char * cross = _style != none ? lines[_style][2] : " ";
bool seen_first = false;
stream.width (0);
stream << string(_margin, ' ');
for (unsigned c = 0; c <= _max_col; ++c) {
if (seen_first) {
stream << hline << cross << hline;
}
seen_first = true;
// FIXME: could use fill character if hline were a (wide) character
for (unsigned i = 0; i < _max_width[c]; ++i) {
stream << hline;
}
}
stream << endl;
}
void Table::dumpTo (ostream &stream) const {
// reset column widths for columns that can be abbreviated
//! \todo allow abbrev of multiple columns?
unsigned c = 0;
for (vector<bool>::const_iterator it = _abbrev_col.begin();
it != _abbrev_col.end() && c <= _max_col; ++it, ++c) {
if (*it &&
_width > _screen_width &&
// don't resize the column to less than 3, or if the resulting table
// would still exceed the screen width (bnc #534795)
_max_width[c] > 3 &&
_width - _screen_width < ((int) _max_width[c]) - 3) {
_max_width[c] -= _width - _screen_width;
break;
}
}
if (_has_header) {
_header.dumpTo (stream, *this);
dumpRule (stream);
}
container::const_iterator
b = _rows.begin (),
e = _rows.end (),
i;
for (i = b; i != e; ++i) {
i->dumpTo (stream, *this);
}
}
void Table::wrap(int force_break_after)
{
if (force_break_after >= 0)
_force_break_after = force_break_after;
_do_wrap = true;
}
void Table::lineStyle (TableLineStyle st) {
if (st < _End)
_style = st;
}
void Table::margin(unsigned margin) {
if (margin < (unsigned) (_screen_width/2))
_margin = margin;
// else
// ERR << "margin of " << margin << " is greater than half of the screen" << endl;
}
void Table::sort (unsigned by_column) {
if (by_column > _max_col) {
// ERR << "by_column >= _max_col (" << by_column << ">=" << _max_col << ")" << endl;
// return;
}
TableRow::Less comp (by_column);
_rows.sort (comp);
}
// Local Variables:
// c-basic-offset: 2
// End: