Display of a tree node for interactive mode.
This commit is contained in:
parent
89f0f6094e
commit
63a7ca456e
6 changed files with 134 additions and 31 deletions
|
|
@ -1,16 +1,20 @@
|
||||||
#ifndef H_Display
|
#ifndef H_Display
|
||||||
#define H_Display
|
#define H_Display
|
||||||
|
|
||||||
|
#include <cstdlib>
|
||||||
#include <iostream>
|
#include <iostream>
|
||||||
#include <iomanip>
|
#include <iomanip>
|
||||||
#include <vector>
|
#include <vector>
|
||||||
#include <string>
|
#include <string>
|
||||||
|
#include <sstream>
|
||||||
|
|
||||||
#include <sys/ioctl.h> //ioctl() and TIOCGWINSZ
|
#include <sys/ioctl.h> //ioctl() and TIOCGWINSZ
|
||||||
#include <unistd.h> // for STDOUT_FILENO
|
#include <unistd.h> // for STDOUT_FILENO
|
||||||
|
|
||||||
#include <AnsiTerminal.hpp>
|
#include <AnsiTerminal.hpp>
|
||||||
|
|
||||||
|
class TreeNodeDiskUsage;
|
||||||
|
|
||||||
class Display
|
class Display
|
||||||
{
|
{
|
||||||
public:
|
public:
|
||||||
|
|
@ -46,6 +50,9 @@ class Display
|
||||||
/// Highlights the line i by inverting its colors (black on white background).
|
/// Highlights the line i by inverting its colors (black on white background).
|
||||||
void HighlightLine(unsigned int i, bool highlight);
|
void HighlightLine(unsigned int i, bool highlight);
|
||||||
|
|
||||||
|
/// Fills the internal lines buffer with the formatted contents of the tree node.
|
||||||
|
void DisplayTreeNode(TreeNodeDiskUsage const& treeNode, size_t topLine = 0, bool SI_units = true);
|
||||||
|
|
||||||
/// Returns a winsize structure with size.ws_row is the number of rows, size.ws_col is the number of columns.
|
/// Returns a winsize structure with size.ws_row is the number of rows, size.ws_col is the number of columns.
|
||||||
static winsize GetTerminalSize();
|
static winsize GetTerminalSize();
|
||||||
|
|
||||||
|
|
@ -74,6 +81,6 @@ std::string GenerateProgressBar(size_t width, size_t current, size_t total, bool
|
||||||
/// Converts a size in bytes to a human readable size (To, Go, Mo, ko, o).
|
/// Converts a size in bytes to a human readable size (To, Go, Mo, ko, o).
|
||||||
/// If SI_units is false, the size will be displayed using powers of 1024 instead of 1000, producing Mio, kio etc.
|
/// If SI_units is false, the size will be displayed using powers of 1024 instead of 1000, producing Mio, kio etc.
|
||||||
/// The suffix can be specified. Default is 'o' for 'octet'. Use 'b' for bits or 'B' for bytes.
|
/// The suffix can be specified. Default is 'o' for 'octet'. Use 'b' for bits or 'B' for bytes.
|
||||||
std::string Bytes2HumanReadable(uint64_t size, bool SI_units = true, const char* suffix = "o");
|
std::string Bytes2HumanReadable(uint64_t size, bool SI_units = true, std::string const& suffix = "o");
|
||||||
|
|
||||||
#endif
|
#endif
|
||||||
|
|
|
||||||
|
|
@ -37,8 +37,10 @@ class EventManager
|
||||||
Display & display;
|
Display & display;
|
||||||
TreeNodeDiskUsage & rootNode;
|
TreeNodeDiskUsage & rootNode;
|
||||||
|
|
||||||
int currentLine;
|
int topLine; //<! Index of top displayed line (for scrolling)
|
||||||
|
int currentLine; //<! Currently selected line
|
||||||
TreeNodeDiskUsage *currentNode;
|
TreeNodeDiskUsage *currentNode;
|
||||||
|
TreeNodeDiskUsage *parentNode;
|
||||||
};
|
};
|
||||||
|
|
||||||
#endif
|
#endif
|
||||||
|
|
|
||||||
|
|
@ -22,6 +22,8 @@ struct PathFilters
|
||||||
/// \class TreeNodeDiskUsage Implements a node of a tree of the files and folders on a system.
|
/// \class TreeNodeDiskUsage Implements a node of a tree of the files and folders on a system.
|
||||||
class TreeNodeDiskUsage
|
class TreeNodeDiskUsage
|
||||||
{
|
{
|
||||||
|
friend class Display;
|
||||||
|
|
||||||
public:
|
public:
|
||||||
TreeNodeDiskUsage(std::string const& path_, PathFilters const* pathFilters_ = NULL);
|
TreeNodeDiskUsage(std::string const& path_, PathFilters const* pathFilters_ = NULL);
|
||||||
~TreeNodeDiskUsage();
|
~TreeNodeDiskUsage();
|
||||||
|
|
|
||||||
124
src/Display.cpp
124
src/Display.cpp
|
|
@ -1,4 +1,12 @@
|
||||||
#include <Display.hpp>
|
#include <Display.hpp>
|
||||||
|
#include <TreeNodeDiskUsage.hpp>
|
||||||
|
|
||||||
|
// DEBUG
|
||||||
|
#ifndef PRINT_VAR
|
||||||
|
#define PRINT_VAR(x); std::cout << #x << "\t= " << (x) << "\n";
|
||||||
|
#endif
|
||||||
|
|
||||||
|
#define MIN(a,b) (((a) < (b)) ? (a) : (b))
|
||||||
|
|
||||||
using std::cout;
|
using std::cout;
|
||||||
|
|
||||||
|
|
@ -15,14 +23,14 @@ std::string const& Display::GetLine(unsigned int i) const { return lines[i]; }
|
||||||
|
|
||||||
void Display::SetLine(unsigned int i, std::string const& str)
|
void Display::SetLine(unsigned int i, std::string const& str)
|
||||||
{
|
{
|
||||||
if(str.size() <= Cols())
|
if(str.size() <= screenCols)
|
||||||
lines[i] = str + std::string(Cols() - str.size(), ' ');
|
lines[i] = str + std::string(screenCols - str.size(), ' ');
|
||||||
else
|
else
|
||||||
lines[i] = str.substr(0, Cols());
|
lines[i] = str.substr(0, screenCols);
|
||||||
}
|
}
|
||||||
|
|
||||||
void Display::SetLineCentered(unsigned int i, std::string const& str, char fillChar) { lines[i] = CenterString(str, Cols(), fillChar); }
|
void Display::SetLineCentered(unsigned int i, std::string const& str, char fillChar) { lines[i] = CenterString(str, screenCols, fillChar); }
|
||||||
void Display::SetLineRjustified(unsigned int i, std::string const& str, char fillChar) { lines[i] = RightJustify(str, Cols(), fillChar); }
|
void Display::SetLineRjustified(unsigned int i, std::string const& str, char fillChar) { lines[i] = RightJustify(str, screenCols, fillChar); }
|
||||||
|
|
||||||
char & Display::GetPixel(unsigned int i, unsigned int j) { return lines[i][j]; }
|
char & Display::GetPixel(unsigned int i, unsigned int j) { return lines[i][j]; }
|
||||||
|
|
||||||
|
|
@ -61,6 +69,81 @@ void Display::HighlightLine(unsigned int i, bool highlight)
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
|
void Display::DisplayTreeNode(TreeNodeDiskUsage const& treeNode, size_t topLine, bool SI_units)
|
||||||
|
{
|
||||||
|
ClearScreenLines();
|
||||||
|
// Write header
|
||||||
|
lines[0] = std::string(C_INVERT_FG_BG) + CenterString("DiskUsageInteractive ~ Use the arrow keys to navigate, press ? or 'h' for help", screenCols) + C_RESET;
|
||||||
|
|
||||||
|
// Write currently displayed directory using its absolute path. If the path resolution does not succeed, the relative path is displayed
|
||||||
|
char absoluteNodePathCstr[4096+1];
|
||||||
|
char *ptr = realpath(treeNode.path.c_str(), absoluteNodePathCstr);
|
||||||
|
std::string absoluteNodePath = (ptr != NULL) ? absoluteNodePathCstr : treeNode.path;
|
||||||
|
lines[1] = "--- " + LeftJustify(absoluteNodePath + " ", screenCols-5, '-');
|
||||||
|
|
||||||
|
size_t availableLines = screenRows - 3;// Number of available lines for the listing
|
||||||
|
|
||||||
|
size_t fieldWidth1 = 10;
|
||||||
|
size_t fieldWidth2 = screenCols/3;
|
||||||
|
size_t fieldWidth3 = screenCols - fieldWidth1 - fieldWidth2;
|
||||||
|
|
||||||
|
if(lines.size() < 3)// Not enough space !
|
||||||
|
return;
|
||||||
|
|
||||||
|
for(size_t i = 0 ; i < MIN(availableLines, treeNode.GetChildrenCount()-topLine) ; i++)
|
||||||
|
{
|
||||||
|
TreeNodeDiskUsage const& node = treeNode.children[i+topLine];
|
||||||
|
std::stringstream lineStream;
|
||||||
|
lineStream << RightJustify(Bytes2HumanReadable(node.totalSize, SI_units), fieldWidth1);
|
||||||
|
lineStream << GenerateProgressBar(fieldWidth2, node.totalSize, treeNode.totalSize, true, "#");
|
||||||
|
lineStream << " " << LeftJustify(node.GetNodeName() + ((node.isFolder) ? "/" : " "), fieldWidth3-1);
|
||||||
|
lines[i+2] = LeftJustify(lineStream.str(), screenCols);
|
||||||
|
}
|
||||||
|
|
||||||
|
// Write footer
|
||||||
|
std::stringstream footerSstream; footerSstream << "Total disk usage: " << Bytes2HumanReadable(treeNode.totalSizeOnDisk, SI_units)
|
||||||
|
<< " Apparent size: " << Bytes2HumanReadable(treeNode.totalSize, SI_units)
|
||||||
|
<< " Items: " << treeNode.totalElements;
|
||||||
|
lines[screenRows-1] = std::string(C_INVERT_FG_BG) + LeftJustify(footerSstream.str(), screenCols) + C_RESET;
|
||||||
|
}
|
||||||
|
|
||||||
|
/*
|
||||||
|
ncdu 1.14.1 ~ Use the arrow keys to navigate, press ? for help
|
||||||
|
--- /home/jerome/codeserver/config/workspace/DiskUsageInteractive ------------------------------------------------
|
||||||
|
952.0 KiB [##########] /build
|
||||||
|
536.0 KiB [##### ] /.git
|
||||||
|
24.0 KiB [ ] /src
|
||||||
|
16.0 KiB [ ] /include
|
||||||
|
e 4.0 KiB [ ] /workspace
|
||||||
|
4.0 KiB [ ] Makefile
|
||||||
|
4.0 KiB [ ] .gitignore
|
||||||
|
@ 0.0 B [ ] DiskUsageInteractive
|
||||||
|
┌───ncdu help─────────────────1:Keys───2:Format───3:About──┐
|
||||||
|
│ │
|
||||||
|
│ up, k Move cursor up │
|
||||||
|
│ down, j Move cursor down │
|
||||||
|
│ right/enter Open selected directory │
|
||||||
|
│ left, <, h Open parent directory │
|
||||||
|
│ n Sort by name (ascending/descending) │
|
||||||
|
│ s Sort by size (ascending/descending) │
|
||||||
|
│ C Sort by items (ascending/descending) │
|
||||||
|
│ M Sort by mtime (-e flag) │
|
||||||
|
│ d Delete selected file or directory │
|
||||||
|
│ t Toggle dirs before files when sorting │
|
||||||
|
│ -- more -- │
|
||||||
|
│ Press q to close │
|
||||||
|
└──────────────────────────────────────────────────────────┘
|
||||||
|
|
||||||
|
|
||||||
|
|
||||||
|
|
||||||
|
|
||||||
|
|
||||||
|
|
||||||
|
|
||||||
|
Total disk usage: 1.5 MiB Apparent size: 1.3 MiB Items: 131
|
||||||
|
*/
|
||||||
|
|
||||||
winsize Display::GetTerminalSize()
|
winsize Display::GetTerminalSize()
|
||||||
{
|
{
|
||||||
winsize size;
|
winsize size;
|
||||||
|
|
@ -128,7 +211,7 @@ std::string GenerateProgressBar(size_t width, size_t current, size_t total, bool
|
||||||
return progressBar;
|
return progressBar;
|
||||||
}
|
}
|
||||||
|
|
||||||
std::string Bytes2HumanReadable(uint64_t size, bool SI_units, const char* suffix)
|
std::string Bytes2HumanReadable(uint64_t size, bool SI_units, std::string const& suffix)
|
||||||
{
|
{
|
||||||
const uint64_t kilo = (SI_units) ? 1000ULL : 1024ULL;
|
const uint64_t kilo = (SI_units) ? 1000ULL : 1024ULL;
|
||||||
const uint64_t mega = kilo*kilo;
|
const uint64_t mega = kilo*kilo;
|
||||||
|
|
@ -136,32 +219,27 @@ std::string Bytes2HumanReadable(uint64_t size, bool SI_units, const char* suffix
|
||||||
const uint64_t tera = giga*kilo;
|
const uint64_t tera = giga*kilo;
|
||||||
const uint64_t peta = tera*kilo;
|
const uint64_t peta = tera*kilo;
|
||||||
const uint64_t exa = peta*kilo;
|
const uint64_t exa = peta*kilo;
|
||||||
//const uint64_t zetta = exa*kilo;
|
|
||||||
//const uint64_t yotta = zetta*kilo;
|
|
||||||
|
|
||||||
char buf[16];
|
std::string fullSuffix = (SI_units) ? suffix : (std::string("i") + suffix);
|
||||||
std::string fullSuffix = (SI_units) ? std::string(suffix) : (std::string("i") + suffix);
|
|
||||||
|
|
||||||
//if(size >= yotta)
|
std::stringstream out;
|
||||||
// sprintf(buf, "%5.1f Y%s", (double)size/yotta, fullSuffix.c_str());
|
out.precision(1);
|
||||||
//else if(size >= zetta)
|
out << std::fixed << std::setw(5) << std::right;
|
||||||
// sprintf(buf, "%5.1f Z%s", (double)size/zetta, fullSuffix.c_str());
|
|
||||||
|
|
||||||
if(size >= exa)
|
if(size >= exa)
|
||||||
sprintf(buf, "%5.1f E%s", (double)size/exa, fullSuffix.c_str());
|
out << (double)size/exa << " E" << fullSuffix;
|
||||||
else if(size >= peta)
|
else if(size >= peta)
|
||||||
sprintf(buf, "%5.1f P%s", (double)size/peta, fullSuffix.c_str());
|
out << (double)size/peta << " P" << fullSuffix;
|
||||||
else if(size >= tera)
|
else if(size >= tera)
|
||||||
sprintf(buf, "%5.1f T%s", (double)size/tera, fullSuffix.c_str());
|
out << (double)size/tera << " T" << fullSuffix;
|
||||||
else if(size >= giga)
|
else if(size >= giga)
|
||||||
sprintf(buf, "%5.1f G%s", (double)size/giga, fullSuffix.c_str());
|
out << (double)size/giga << " G" << fullSuffix;
|
||||||
else if(size >= mega)
|
else if(size >= mega)
|
||||||
sprintf(buf, "%5.1f M%s", (double)size/mega, fullSuffix.c_str());
|
out << (double)size/mega << " M" << fullSuffix;
|
||||||
else if(size >= kilo)
|
else if(size >= kilo)
|
||||||
sprintf(buf, "%5.1f k%s", (double)size/kilo, fullSuffix.c_str());
|
out << (double)size/kilo << " k" << fullSuffix;
|
||||||
else
|
else
|
||||||
sprintf(buf, "%5.1f %s", (double)size, suffix);
|
out << (double)size << " " << suffix;
|
||||||
|
return out.str();
|
||||||
return std::string(buf);
|
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|
|
||||||
|
|
@ -11,14 +11,17 @@
|
||||||
|
|
||||||
EventManager::EventManager(Display & display_, TreeNodeDiskUsage & rootNode_)
|
EventManager::EventManager(Display & display_, TreeNodeDiskUsage & rootNode_)
|
||||||
: display(display_),
|
: display(display_),
|
||||||
rootNode(rootNode_)
|
rootNode(rootNode_),
|
||||||
{}
|
topLine(0),
|
||||||
|
currentLine(0),
|
||||||
EventManager::~EventManager()
|
currentNode(&rootNode),
|
||||||
|
parentNode(&rootNode)
|
||||||
{
|
{
|
||||||
|
|
||||||
}
|
}
|
||||||
|
|
||||||
|
EventManager::~EventManager() {}
|
||||||
|
|
||||||
void EventManager::MainEventLoop()
|
void EventManager::MainEventLoop()
|
||||||
{
|
{
|
||||||
struct termios oldSettings, newSettings;
|
struct termios oldSettings, newSettings;
|
||||||
|
|
@ -46,7 +49,8 @@ void EventManager::MainEventLoop()
|
||||||
if(res > 0)
|
if(res > 0)
|
||||||
{
|
{
|
||||||
char c;
|
char c;
|
||||||
read(fileno(stdin), &c, 1);
|
if(read(fileno(stdin), &c, 1) != 1) // read character from stdin
|
||||||
|
break;
|
||||||
// std::cout << (int)c << " = \"" << c << "\"\n";// DEBUG
|
// std::cout << (int)c << " = \"" << c << "\"\n";// DEBUG
|
||||||
|
|
||||||
// Parse event
|
// Parse event
|
||||||
|
|
|
||||||
12
src/test.cpp
12
src/test.cpp
|
|
@ -189,7 +189,7 @@ void runTests(int argc, char *argv[])
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
//if(0)
|
if(0)
|
||||||
{// test EventManager
|
{// test EventManager
|
||||||
Display display;
|
Display display;
|
||||||
TreeNodeDiskUsage tree(rootpath);
|
TreeNodeDiskUsage tree(rootpath);
|
||||||
|
|
@ -197,4 +197,14 @@ void runTests(int argc, char *argv[])
|
||||||
EventManager eventManager(display, tree);
|
EventManager eventManager(display, tree);
|
||||||
eventManager.MainEventLoop();
|
eventManager.MainEventLoop();
|
||||||
}
|
}
|
||||||
|
//if(0)
|
||||||
|
{// test interactive display of tree node (without interactivity)
|
||||||
|
Display display;
|
||||||
|
TreeNodeDiskUsage tree(rootpath);
|
||||||
|
tree.BuildTree(false);
|
||||||
|
tree.SortBySizeDesc();
|
||||||
|
display.DisplayTreeNode(tree, 0, true);
|
||||||
|
//Display::ClearScreen();
|
||||||
|
display.DrawScreenLines();
|
||||||
|
}
|
||||||
}
|
}
|
||||||
|
|
|
||||||
Loading…
Add table
Reference in a new issue