diff --git a/src/core/pistring.h b/src/core/pistring.h index 4f33148a..003d8645 100755 --- a/src/core/pistring.h +++ b/src/core/pistring.h @@ -912,9 +912,9 @@ inline PIByteArray & operator >>(PIByteArray & s, PIStringList & v) {int sz; s > //! \relatesalso PIStringList \brief Output operator to std::ostream (cout) -inline std::ostream & operator <<(std::ostream & s, const PIStringList & v) {s << "{"; for (uint i = 0; i < v.size(); ++i) {s << '\"' << v[i] << '\"'; if (i < v.size() - 1) s << ", ";} s << "}"; return s;} +inline std::ostream & operator <<(std::ostream & s, const PIStringList & v) {s << "{"; for (uint i = 0; i < v.size(); ++i) {s << "\"" << v[i] << "\""; if (i < v.size() - 1) s << ", ";} s << "}"; return s;} //! \relatesalso PIStringList \relatesalso PICout \brief Output operator to PICout -inline PICout operator <<(PICout s, const PIStringList & v) {s.space(); s.setControl(0, true); s << "{"; for (uint i = 0; i < v.size(); ++i) {s << '\"' << v[i] << '\"'; if (i < v.size() - 1) s << ", ";} s << "}"; s.restoreControl(); return s;} +inline PICout operator <<(PICout s, const PIStringList & v) {s.space(); s.setControl(0, true); s << "{"; for (uint i = 0; i < v.size(); ++i) {s << "\"" << v[i] << "\""; if (i < v.size() - 1) s << ", ";} s << "}"; s.restoreControl(); return s;} #endif // PISTRING_H diff --git a/src/io/pibasetransfer.cpp b/src/io/pibasetransfer.cpp index 753dcfd9..91e3095b 100644 --- a/src/io/pibasetransfer.cpp +++ b/src/io/pibasetransfer.cpp @@ -229,7 +229,7 @@ int PIBaseTransfer::checkSession() { void PIBaseTransfer::buildSession(PIVector parts) { - state_string = "calculating files... "; + state_string = "calculating parts ... "; session.clear(); header.session_id = rand(); bytes_all = 0; @@ -239,7 +239,7 @@ void PIBaseTransfer::buildSession(PIVector parts) { int min_size = packet_header_size + part_header_size; int cur_size = min_size; for (int i = 0; i < parts.size_s(); i++) { - state_string = "calculating files... " + PIString::fromNumber(i) + " of " + PIString::fromNumber(parts.size()); + state_string = "calculating parts ... " + PIString::fromNumber(i) + " of " + PIString::fromNumber(parts.size()); fi.id = parts[i].id; // piCout << fi.id << state_string; bytes_all += parts[i].size; diff --git a/src/io/pidir.cpp b/src/io/pidir.cpp index c7a4310c..97055328 100755 --- a/src/io/pidir.cpp +++ b/src/io/pidir.cpp @@ -282,7 +282,29 @@ PIVector PIDir::entries() { PIVector PIDir::allEntries() { - return allEntries(absolutePath()); + PIVector ret; + PIVector dirs; + PIStringList cdirs, ndirs; + cdirs << path(); + while (!cdirs.isEmpty()) { + piForeachC (PIString & d, cdirs) { + scan_ = d; + PIVector el = PIDir(d).entries(); + piForeachC (PIFile::FileInfo & de, el) { + if (de.name() == "." || de.name() == "..") continue; + if (de.isSymbolicLink()) continue; /// TODO: resolve symlinks + if (de.isDir()) { + dirs.push_front(de); + ndirs << de.path; + } else ret << de; + } + } + cdirs = ndirs; + ndirs.clear(); + } + ret.insert(0, dirs); + scan_.clear(); + return ret; } @@ -363,26 +385,7 @@ PIDir PIDir::temporary() { PIVector PIDir::allEntries(const PIString &path) { - PIVector ret; - PIVector dirs; - PIDir root; - root.setDir(path); - PIVector cds = root.entries(); - piForeachC (PIFile::FileInfo & de, cds) { - //piCout << " open" << de.name(); - if (de.name() == "." || de.name() == "..") continue; - if (de.isSymbolicLink()) continue; /// TODO: resolve symlinks - if (de.isDir()) { - dirs.push_front(de); - PIVector td = PIDir(de.path).allEntries(); - for (int i = 0; i < td.size_s(); i++) { - if (td[i].isDir()) dirs.push_front(td[i]); - else ret << td[i]; - } - } else ret << de; - } - ret.insert(0, dirs); - return ret; + return PIDir(path).allEntries(); } diff --git a/src/io/pidir.h b/src/io/pidir.h index b1e888ba..fbe0a795 100755 --- a/src/io/pidir.h +++ b/src/io/pidir.h @@ -46,6 +46,10 @@ public: //! Returns if path of this directory is relative bool isRelative() const {return !isAbsolute();} + //! Returns path of current reading directory. This path + //! valid only while \a allEntries functions + const PIString & scanDir() const {return scan_;} + //! Returns path of this directory PIString path() const; @@ -116,7 +120,7 @@ private: static bool removeDir(const PIString & path); static bool renameDir(const PIString & path, const PIString & new_name); - PIString path_; + PIString path_, scan_; }; diff --git a/src/io/pifiletransfer.cpp b/src/io/pifiletransfer.cpp index 6ec659d6..979613bd 100644 --- a/src/io/pifiletransfer.cpp +++ b/src/io/pifiletransfer.cpp @@ -9,7 +9,7 @@ PIFileTransfer::PIFileTransfer() { pftheader.session_id = 0; pftheader.step = pft_None; dir = PIDir::current(); - started_ = false; + started_ = scanning = false; bytes_file_all = bytes_file_cur = 0; // CONNECT(void, this, sendStarted, this, send_started); CONNECT(void, this, receiveStarted, this, receive_started); @@ -49,12 +49,13 @@ bool PIFileTransfer::send(PIVector entries) { allEntries << PFTFileInfo(entries[i]); allEntries.back().dest_path = entries[i].name(); if (entries[i].isDir()) { - cur_file_string = "scaning " + entries[i].name() + " (" + PIString::fromNumber(i) + "/" + PIString::fromNumber(entries.size()) + ")"; - PIDir d(entries[i].path); + cur_file_string = "scanning ... "; + d.setDir(entries[i].path); + scanning = true; PIVector fls = d.allEntries(); + scanning = false; d.up(); for (int j=0; j &files); void processFile(int id, ullong start, PIByteArray &data); diff --git a/utils/system_daemon/daemon.cpp b/utils/system_daemon/daemon.cpp index 259c0931..800ae3a8 100644 --- a/utils/system_daemon/daemon.cpp +++ b/utils/system_daemon/daemon.cpp @@ -2,28 +2,101 @@ #include "shared.h" #include "pisysteminfo.h" +const char pisd_prefix[] = "_pisd_"; extern PIScreen screen; Daemon::Remote::Remote(const PIString & n): PIThread() { setName(n); ft.setName(n); - ft.setPacketSize(4000); + ft.setPacketSize(3984); CONNECTU(&ft, sendRequest, this, ftSendRequest) - CONNECTU(&ft, receiveFinished, this, ftReceived) + CONNECTU(&ft, receiveFilesFinished, this, ftReceived) + CONNECTU(&ft, sendFilesFinished, this, ftSended) dir_my = PIDir::current(); } +void Daemon::Remote::sendFiles(const PIString & dir, const PIStringList & fl) { + _fl = fl; + piForeach (PIString & s, _fl) + s.prepend(dir); + piCout << "send" << _fl; + startOnce(); +} + + +void Daemon::Remote::run() { + ft.send(_fl); +} + + + +Daemon::TileFileProgress::TileFileProgress(): PIScreenTile() { + size_policy = PIScreenTypes::Fixed; + ft = 0; + setMargins(1, 1, 1, 1); + spacing = 1; + back_format.color_back = Yellow; + label_file = new TileSimple(""); + label_speed = new TileSimple(""); + prog_file = new TileProgress(); + prog_all = new TileProgress(); + buttons = new TileButtons(); + buttons->content << TileButtons::Button("Ok", CellFormat()); + buttons->content << TileButtons::Button("Cancel", CellFormat()); + buttons->back_format.color_back = label_file->back_format.color_back = label_speed->back_format.color_back = Yellow; + label_file->back_format.color_char = label_speed->back_format.color_char = Black; + label_file->content.resize(1); + label_speed->content.resize(1); + label_file->content[0].second = label_speed->content[0].second = CellFormat(Black, Transparent); + addTile(label_file); + addTile(label_speed); + addTile(prog_file); + addTile(prog_all); + addTile(buttons); +} + + +void Daemon::TileFileProgress::resizeEvent(int w, int h) { + PIScreenTile::resizeEvent(w, h); + w = ::screen.windowWidth() / 1.4; + minimumWidth = maximumWidth = w; +} + + +void Daemon::TileFileProgress::sizeHint(int & w, int & h) const { + PIScreenTile::sizeHint(w, h); + w = ::screen.windowWidth() / 1.4; +} + + +void Daemon::TileFileProgress::drawEvent(PIScreenDrawer * d) { + if (ft) { + label_file->content[0].first = ft->stateString() + ft->curFile(); + PIString spd; + if (ft->isReceiving()) spd = ft->diagnostic().receiveSpeed(); + else spd = ft->diagnostic().sendSpeed(); + label_speed->content[0].first = spd; + if (ft->bytesFileAll() > 0) + prog_file->value = piRoundd(ft->bytesFileCur() / double(ft->bytesFileAll()) * 100.); + if (ft->bytesAll() > 0) + prog_all->value = piRoundd(ft->bytesCur() / double(ft->bytesAll()) * 100.); + } + PIScreenTile::drawEvent(d); +} + + -Daemon::Daemon(): PIPeer("_pisd_" + PISystemInfo::instance()->hostname + "_" + PIString(rand() % 100)), fm(this) { +Daemon::Daemon(): PIPeer(pisd_prefix + PISystemInfo::instance()->hostname + "_" + PIString(rand() % 100)), fm(this) { setName("Daemon"); timer.setName("__S__Daemon_timer"); mode = offset = cur = height = 0; CONNECTU(&screen, keyPressed, this, keyEvent) CONNECTU(&timer, tickEvent, this, timerEvent) CONNECTU(&fm, tileKey, this, fmKeyEvent) + CONNECTU(&fm, actionRequest, this, fmActionRequest) timer.addDelimiter(5); timer.start(200); @@ -53,6 +126,9 @@ Daemon::Daemon(): PIPeer("_pisd_" + PISystemInfo::instance()->hostname + "_" + P tile_fm = fm.tile(); tile_fm->hide(); + tile_file_progress = new TileFileProgress(); + + tile_root->addTile(tile_header); tile_root->addTile(list_daemons); tile_root->addTile(list_actions); @@ -189,6 +265,24 @@ void Daemon::fmKeyEvent(PIKbdListener::KeyEvent key) { } +void Daemon::fmActionRequest(bool remote_tile, FileManager::Action type, PIVariant data) { + switch (type) { + case FileManager::Copy: + if (remote_tile) { + } else { + Remote * r = remotes.value(conn_name, 0); + if (!r) return; + r->sendFiles(fm.localDir() + PIDir::separator, data.toStringList()); + tile_file_progress->ft = &(r->ft); + screen.setDialogTile(tile_file_progress); + } + break; + default: break; + }; + piCout << remote_tile << type << data; +} + + void Daemon::timerEvent(void * _d, int delim) { screen.lock(); list_daemons->content.clear(); @@ -209,7 +303,7 @@ PIStringList Daemon::availableDaemons() { available_daemons.clear(); lock(); piForeachC (PIPeer::PeerInfo & p, allPeers()) { - if (!p.name.startsWith("_pisd_")) continue; + if (!p.name.startsWith(pisd_prefix)) continue; available_daemons << p.name.mid(6); } unlock(); @@ -219,7 +313,7 @@ PIStringList Daemon::availableDaemons() { void Daemon::connectToDaemon(const PIString & dn) { if (dn.isEmpty()) return; - conn_name = "_pisd_" + dn; + conn_name = pisd_prefix + dn; mode = 1; } @@ -240,9 +334,10 @@ void Daemon::peerConnected(const PIString & name) { /*piCout << "connected" << name; mode = 2; conn_name = name;*/ + if (!name.startsWith(pisd_prefix)) return; Remote * r = new Remote(name); - CONNECTU(&(r->ft), sendRequest, this, ftSendRequest) - CONNECTU(&(r->ft), receiveFinished, this, ftReceived) + CONNECTU(r, sendRequest, this, sendRequest) + CONNECTU(r, receiveFinished, this, filesReceived) remotes.insert(name, r); } @@ -251,26 +346,15 @@ void Daemon::peerDisconnected(const PIString & name) { if (name == conn_name) { disconnect(); } - Remote * dt = remotes.value(name); - if (dt) delete dt; + Remote * dt = remotes.value(name, 0); + if (!dt) return; + delete dt; remotes.remove(name); } -void Daemon::ftSendRequest(PIByteArray & data) { - PIDataTransfer * dt = (PIDataTransfer*)emitter(); - if (!dt) return; - PIByteArray hdr; hdr << int(DataTransfer); - data.insert(0, hdr); - send(dt->name(), data); -} - - -void Daemon::ftReceived(bool ok) { - if (!ok) return; - PIDataTransfer * dt = (PIDataTransfer*)emitter(); - if (!dt) return; - dataReceived(emitter()->name(), dt->data()); +void Daemon::filesReceived(const PIString & name, bool ok) { + } @@ -292,6 +376,8 @@ void Daemon::dataReceived(const PIString & from, const PIByteArray & data) { if (!r) break; ba >> dir; r->dir_my.cd(dir); + r->ft.setDirectory(r->dir_my); + piCout << "store to" << r->dir_my.absolutePath(); { PIVector fil = r->dir_my.entries(); piForeach (PIFile::FileInfo & f, fil) @@ -317,6 +403,10 @@ void Daemon::dataReceived(const PIString & from, const PIByteArray & data) { fm.remoteRestoreDir(); } break; + case FileTransfer: + r = remotes.value(from); + if (r) r->received(ba); + break; }; if (!rba.isEmpty()) send(from, rba); } diff --git a/utils/system_daemon/daemon.h b/utils/system_daemon/daemon.h index dd0fd806..1f920cba 100644 --- a/utils/system_daemon/daemon.h +++ b/utils/system_daemon/daemon.h @@ -59,8 +59,9 @@ private: ReplyHostInfo = 20, ReplyChangeDir, + CopyFiles, - DataTransfer = 30 + FileTransfer = 30 }; @@ -68,26 +69,41 @@ private: PIOBJECT_SUBCLASS(Remote, PIThread) public: Remote(const PIString & n = PIString()); - void sendData(const PIByteArray & d) {_d = d; startOnce();} - EVENT_HANDLER1(void, ftSendRequest, PIByteArray &, data) {sendRequest(name(), data);} + void sendFiles(const PIString & dir, const PIStringList & fl); + EVENT_HANDLER1(void, ftSendRequest, PIByteArray &, data) {PIByteArray h; h << int(FileTransfer); data.insert(0, h); sendRequest(name(), data);} EVENT_HANDLER1(void, ftReceived, bool, ok) {receiveFinished(name(), ok);} + EVENT_HANDLER1(void, ftSended, bool, ok) {sendFinished(name(), ok);} EVENT2(sendRequest, const PIString & , name, const PIByteArray &, data) EVENT2(receiveFinished, const PIString & , name, bool, ok) + EVENT2(sendFinished, const PIString & , name, bool, ok) EVENT_HANDLER1(void, received, const PIByteArray & , data) {ft.received(data);} PIDir dir_my, dir_remote; PIFileTransfer ft; - PIByteArray _d; - //void run() {ft.send(_d);} + PIStringList _fl; + void run(); + }; + + class TileFileProgress: public PIScreenTile { + public: + TileFileProgress(); + TileSimple * label_file, * label_speed; + TileProgress * prog_file, * prog_all; + TileButtons * buttons; + PIFileTransfer * ft; + void resizeEvent(int w, int h); + void sizeHint(int & w, int & h) const; + void drawEvent(PIScreenDrawer * d); }; EVENT_HANDLER2(void, tileEvent, PIScreenTile *, t, PIScreenTypes::TileEvent, e); EVENT_HANDLER1(void, keyEvent, PIKbdListener::KeyEvent, key); + EVENT_HANDLER2(void, sendRequest, const PIString & , name, const PIByteArray & , data) {send(name, data);} EVENT_HANDLER1(void, fmKeyEvent, PIKbdListener::KeyEvent, key); + EVENT_HANDLER3(void, fmActionRequest, bool, remote_tile, FileManager::Action, type, PIVariant, data); EVENT_HANDLER2(void, timerEvent, void * , _d, int, delim); - EVENT_HANDLER1(void, ftSendRequest, PIByteArray &, data); - EVENT_HANDLER1(void, ftReceived, bool, ok); + EVENT_HANDLER2(void, filesReceived, const PIString & , name, bool, ok); EVENT(menuRequest); void hideAll(); void showTile(PIScreenTile * t, const PIString & header = PIString()); @@ -116,6 +132,7 @@ private: PIScreenTile * tile_root, * tile_fm; TileSimple * tile_info, * tile_header; TileList * list_daemons, * list_actions; + TileFileProgress * tile_file_progress; int mode, offset, cur, height; diff --git a/utils/system_daemon/file_manager.cpp b/utils/system_daemon/file_manager.cpp index f8e0e9ab..dcf2006c 100644 --- a/utils/system_daemon/file_manager.cpp +++ b/utils/system_daemon/file_manager.cpp @@ -9,7 +9,16 @@ FileManager::TileDir::TileDir(): TileList() { label_path = 0; selection_mode = TileList::MultiSelection; dir = PIDir::current(); - resized = remote = false; + resized = remote = remote_mode = false; +} + + +PIStringList FileManager::TileDir::selectedNames() const { + PIStringList ret; + PIVector sind = selected.toVector(); + piForeachC (int i, sind) + ret << entries[i].name(); + return ret; } @@ -18,11 +27,22 @@ bool FileManager::TileDir::keyEvent(PIKbdListener::KeyEvent key) { PIString nd; switch (key.key) { case 'R': if (!remote) updateDir(); pass = true; break; + case PIKbdListener::F5: + if (remote_mode) { + if (selected.isEmpty()) + selected << cur; + if (!askQuestion("Copy selected files?")) return true; + setFocus(); + actionRequest(remote, Copy, selectedNames()); + } + break; case PIKbdListener::F7: nd = askNewDir(); setFocus(); if (nd.isEmpty()) return true; - if (!remote) { + if (remote) + actionRequest(remote, MkDir, nd); + else { PIDir::make(dir.absolutePath() + PIDir::separator + nd); updateDir(); } @@ -37,11 +57,7 @@ bool FileManager::TileDir::keyEvent(PIKbdListener::KeyEvent key) { } setFocus(); if (!remote) { - PIStringList sl; - PIVector sind = selected.toVector(); - piForeachC (int i, sind) - sl << entries[i].name(); - removeFiles(dir, sl); + removeFiles(dir, selectedNames()); selected.clear(); updateDir(); } @@ -210,6 +226,7 @@ FileManager::FileManager(Daemon * d) { panels[i]->key_func = (void*)tileKey_s; panels[i]->setName("file panel " + PIString(i)); panels[i]->label_path = plabel; + CONNECTU(panels[i], actionRequest, this, actionRequest) panel->addTile(plabel); panel->addTile(panels[i]); panels[i]->updateDir(); diff --git a/utils/system_daemon/file_manager.h b/utils/system_daemon/file_manager.h index 2cd3349c..f71b09fb 100644 --- a/utils/system_daemon/file_manager.h +++ b/utils/system_daemon/file_manager.h @@ -14,10 +14,13 @@ public: PIScreenTile * tile() const; PIScreenTile * remoteTile() const {return panels[1];} - void setRemote(bool r) {panels[1]->remote = r;} + enum Action {MkDir, Remove, Copy, Move}; + + void setRemote(bool r) {panels[1]->remote = r; panels[0]->remote_mode = panels[1]->remote_mode = true;} void setRemoteDir(const PIString & d); void setRemoteContent(const PIVector & el); PIString remoteDir() const {return panels[1]->dir.absolutePath();} + PIString localDir() const {return panels[0]->dir.absolutePath();} PIStringList selectedRemote() const; PIFile::FileInfo currentRemoteEntry() const; PIFile::FileInfo selectedRemoteEntry(int index) const {return panels[1]->entries[index];} @@ -25,8 +28,12 @@ public: void remoteRestoreDir(); void readingRemote() const {panels[1]->showReading();} + EVENT(menuRequest) + EVENT3(actionRequest, bool, remote_tile, FileManager::Action, type, PIVariant, data) + private: class TileDir: public TileList { + PIOBJECT_SUBCLASS(TileDir, TileList) public: TileDir(); void updateDir(); @@ -38,17 +45,18 @@ private: void unlock(); void showReading(); void setContent(const PIVector & l); + PIStringList selectedNames() const; TileSimple * label_path; PIVector entries; PIDir dir; PIMap > prev_pos; - bool resized, remote; + bool resized, remote, remote_mode; void * fm, * key_func; + EVENT3(actionRequest, bool, remote_tile, FileManager::Action, type, PIVariant, data) }; EVENT_HANDLER1(void, keyEvent, PIKbdListener::KeyEvent, key); EVENT1(tileKey, PIKbdListener::KeyEvent, key) - EVENT(menuRequest) static void tileKey_s(void * fm, PIKbdListener::KeyEvent key) {((FileManager*)fm)->tileKey(key);} void updateConsole();