Files
pip/utils/system_daemon/file_manager.cpp
peri4 caa7880cc4 get rid of piForeach
apply some code analyzer recommendations
ICU flag now check if libicu exists
prepare for more accurate growth of containers (limited PoT, then constantly increase size)
2024-11-20 20:01:47 +03:00

343 lines
8.4 KiB
C++

#include "file_manager.h"
#include "shared.h"
FileManager::TileDir::TileDir(): TileList() {
label_path = 0;
selection_mode = TileList::MultiSelection;
dir = PIDir::current();
resized = is_right = remote_mode = false;
}
PIStringList FileManager::TileDir::selectedNames() const {
PIStringList ret;
PIMutexLocker ml(e_mutex);
PIVector<int> sind = selected.toVector();
for (const auto i: sind)
ret << entries[i].name();
ret.removeOne("..");
return ret;
}
bool FileManager::TileDir::keyEvent(PIKbdListener::KeyEvent key) {
bool pass = false;
PIString nd;
switch (key.key) {
case 'R':
if (!(is_right && remote_mode)) updateDir();
pass = true;
break;
case PIKbdListener::F5:
if (selected.isEmpty()) selected << cur;
if (!askQuestion("Copy selected files?")) return true;
setFocus();
// piCoutObj << "remote" << remote_mode;
if (remote_mode)
actionRequest(is_right, Copy, selectedNames());
else
actionRequest(is_right, LocalCopy, selectedNames());
break;
case PIKbdListener::F6:
if (key.modifiers[PIKbdListener::Shift]) {
if (selected.isEmpty()) selected << cur;
if (!askQuestion("Crypt selected files?")) return true;
setFocus();
if (remote_mode)
actionRequest(is_right, Crypt, selectedNames());
else
actionRequest(is_right, LocalCrypt, selectedNames());
}
break;
case PIKbdListener::F7:
nd = askUserInput("Enter new directory name:");
setFocus();
if (nd.isEmpty()) return true;
if (is_right && remote_mode)
actionRequest(is_right, MkDir, nd);
else {
PIDir::make(dir.absolutePath() + PIDir::separator + nd);
updateDir();
}
pass = true;
break;
case PIKbdListener::F8:
if (selected.isEmpty()) selected << cur;
if (!askQuestion("Delete selected?")) {
setFocus();
return false;
}
setFocus();
if (is_right && remote_mode) {
actionRequest(is_right, Remove, selectedNames());
} else {
removeFiles(dir, selectedNames());
selected.clear();
updateDir();
}
pass = true;
break;
case PIKbdListener::Return: {
e_mutex.lock();
bool ud = false;
if (cur < entries.size_s() && cur >= 0) {
if (!(is_right && remote_mode)) {
// piCout << entries[cur];
if (entries[cur].isDir()) {
prev_pos[dir.path()] = PIPair<int, int>(cur, offset);
dir.cd(entries[cur].name());
PIPair<int, int> cp = prev_pos.value(dir.path());
cur = cp.first;
offset = cp.second;
selected.clear();
ud = true;
}
}
pass = true;
}
e_mutex.unlock();
if (ud) updateDir();
} break;
}
// piCout << is_right << remote_mode << pass;
if (is_right && remote_mode && pass) {
((void (*)(void *, PIKbdListener::KeyEvent))key_func)(fm, key);
return true;
}
return TileList::keyEvent(key);
}
void FileManager::TileDir::lock() {
if (screen && !resized) ((PIScreen *)screen)->lock();
}
void FileManager::TileDir::unlock() {
if (screen && !resized) ((PIScreen *)screen)->unlock();
}
void FileManager::TileDir::showReading() {
PIMutexLocker ml(e_mutex);
cur = -1;
offset = 0;
entries.clear();
content.resize(1);
content[0] = Row("... Reading ...", CellFormat());
}
void FileManager::TileDir::setContent(const PIVector<PIFile::FileInfo> & l) {
PIMutexLocker ml(e_mutex);
PIVector<PIFile::FileInfo> fl, dl;
entries.clear();
if (l.isEmpty()) {
PIFile::FileInfo fi;
fi.path = "..";
fi.flags |= PIFile::FileInfo::DotDot | PIFile::FileInfo::Dir;
entries << fi;
} else {
bool root = dir.path() == PIDir::separator;
for (int i = 0; i < l.size_s(); ++i) {
if (l[i].name() == ".") continue;
if (l[i].name() == "..") {
if (!root) dl.push_front(l[i]);
continue;
}
if (l[i].isDir())
dl << l[i];
else
fl << l[i];
}
entries << dl << fl;
}
}
void FileManager::TileDir::updateDir() {
lock();
int pc = cur, po = offset;
showReading();
unlock();
setContent(dir.entries());
if (label_path) {
label_path->content.resize(1);
label_path->content[0].first = dir.absolutePath();
}
cur = pc;
offset = po;
buildNames();
}
void FileManager::TileDir::buildNames() {
lock();
PIMutexLocker ml(e_mutex);
content.clear();
PIChar t;
CharFlags cf = 0;
Color cc = Default;
PIString fcol, scol;
for (const auto & e: entries) {
if (e.isDir()) {
t = '/';
cf = Bold;
scol = " dir";
} else {
if (e.perm_user.exec || e.perm_group.exec || e.perm_other.exec) {
cf = Bold;
cc = Green;
t = '*';
} else {
t = ' ';
cc = Default;
cf = 0;
}
scol = PIString::readableSize(e.size);
}
if (e.isSymbolicLink() && (t != '*')) t = '~';
scol = scol.expandRightTo(9, ' ') + "| " + e.time_modification.toString("dd.MM hh:mm:ss") + " | " + e.perm_user.toString() + " " +
e.perm_group.toString() + " " + e.perm_other.toString();
fcol = t + e.name();
if (fcol.size_s() >= width_ - 2 - scol.size_s()) fcol = fcol.left(width_ - 5 - scol.size_s()) + "...";
fcol.expandRightTo(width_ - 1 - scol.size_s(), ' ');
content << Row(fcol + scol, CellFormat(cc, Transparent, cf));
}
unlock();
}
void FileManager::TileDir::sizeHint(int & w, int & h) const {
w = h = 4;
}
void FileManager::TileDir::resizeEvent(int w, int h) {
resized = true;
buildNames();
resized = false;
TileList::resizeEvent(w, h);
}
FileManager::FileManager() {
setName("FileManager");
TileSimple * tl;
tile_root = new PIScreenTile();
tile_root->direction = Vertical;
PIScreenTile * pt = new PIScreenTile();
pt->direction = Horizontal;
pt->spacing = 1;
pt->back_format.color_back = Cyan;
for (int i = 0; i < 2; ++i) {
PIScreenTile * panel = new PIScreenTile();
TileSimple * plabel = new TileSimple();
plabel->size_policy = Fixed;
plabel->maximumWidth = 1;
panel->direction = Vertical;
panels[i] = new TileDir();
panels[i]->fm = this;
panels[i]->key_func = (void *)tileKey_s;
panels[i]->setName("file panel " + PIString::fromNumber(i));
panels[i]->label_path = plabel;
CONNECTU(panels[i], actionRequest, this, actionRequest)
panel->addTile(plabel);
panel->addTile(panels[i]);
panels[i]->updateDir();
pt->addTile(panel);
}
panels[1]->is_right = true;
tile_root->addTile(pt);
PIScreenTile * labels = new PIScreenTile();
labels->size_policy = Fixed;
labels->direction = Horizontal;
PIVector<SSPair> ll;
ll << SSPair(" Esc", "Exit") << SSPair(" F5", "Copy") << SSPair(" F6", "Move") << SSPair(" F7", "MkDir") << SSPair(" F8", "Delete");
for (const auto & l: ll) {
tl = new TileSimple();
labels->addTile(tl);
tl->content << TileSimple::Row(l.first, CellFormat(White, Transparent, Bold));
tl = new TileSimple();
labels->addTile(tl);
tl->content << TileSimple::Row(l.second, CellFormat(Black, Cyan));
}
tl = new TileSimple();
labels->addTile(tl);
tl->size_policy = Expanding;
tile_root->addTile(labels);
}
PIScreenTile * FileManager::tile() const {
return tile_root;
}
void FileManager::setLocal() {
if (panels[1]->remote_mode) setRemoteDir(panels[0]->dir.absolutePath());
panels[0]->remote_mode = panels[1]->remote_mode = false;
}
void FileManager::setRemote() {
panels[0]->remote_mode = panels[1]->remote_mode = true;
}
void FileManager::setRemoteDir(const PIString & d) {
panels[1]->dir.setDir(d);
if (panels[1]->label_path) {
panels[1]->label_path->content.resize(1);
panels[1]->label_path->content[0].first = panels[1]->dir.path();
}
}
void FileManager::setRemoteContent(const PIVector<PIFile::FileInfo> & el) {
panels[1]->setContent(el);
panels[1]->buildNames();
}
int FileManager::selectedPanel() const {
for (int i = 0; i < 2; i++)
if (panels[i]->hasFocus()) return i;
return -1;
}
PIStringList FileManager::selectedRemote() const {
PIStringList ret;
panels[1]->lock();
PIVector<int> sil = panels[1]->selected.toVector();
for (const auto i: sil)
ret << panels[1]->entries[i].path;
panels[1]->unlock();
return ret;
}
PIFile::FileInfo FileManager::currentRemoteEntry() const {
if ((panels[1]->cur < 0) || (panels[1]->cur >= panels[1]->content.size_s())) return PIFile::FileInfo();
return panels[1]->entries[panels[1]->cur];
}
void FileManager::remoteSaveDir() {
panels[1]->prev_pos[panels[1]->dir.path()] = PIPair<int, int>(panels[1]->cur, panels[1]->offset);
}
void FileManager::remoteRestoreDir() {
PIPair<int, int> cp = panels[1]->prev_pos.value(panels[1]->dir.path());
panels[1]->selected.clear();
panels[1]->cur = cp.first;
panels[1]->offset = cp.second;
if ((panels[1]->cur < 0) || (panels[1]->cur >= panels[1]->content.size_s())) panels[1]->cur = 0;
}