← Back to team overview

linuxdcpp-team team mailing list archive

[Branch ~dcplusplus-team/dcplusplus/trunk] Rev 3207: Display progress information when DC++ starts

 

------------------------------------------------------------
revno: 3207
committer: poy <poy@xxxxxxxxxx>
branch nick: trunk
timestamp: Thu 2013-02-14 17:25:20 +0100
message:
  Display progress information when DC++ starts
modified:
  changelog.txt
  dcpp/DCPlusPlus.cpp
  dcpp/DCPlusPlus.h
  dcpp/HashManager.cpp
  dcpp/HashManager.h
  dcpp/QueueManager.cpp
  dcpp/QueueManager.h
  dcpp/ShareManager.cpp
  dcpp/ShareManager.h
  dcpp/Streams.h
  win32/SplashWindow.cpp
  win32/SplashWindow.h
  win32/main.cpp


--
lp:dcplusplus
https://code.launchpad.net/~dcplusplus-team/dcplusplus/trunk

Your team Dcplusplus-team is subscribed to branch lp:dcplusplus.
To unsubscribe from this branch go to https://code.launchpad.net/~dcplusplus-team/dcplusplus/trunk/+edit-subscription
=== modified file 'changelog.txt'
--- changelog.txt	2013-02-12 22:22:05 +0000
+++ changelog.txt	2013-02-14 16:25:20 +0000
@@ -1,7 +1,7 @@
 * Fix status bar parts when the window is too small (poy)
 * [L#534440] [NMDC] Preserve encodings in some search results (poy)
 * [ADC] Fix problems after marking oneself as a favorite user
-* Cancel the v2->v3 hash upgrade if it takes longer than 26sec (poy)
+* Display progress information when DC++ starts (poy)
 
 -- 0.810 2013-01-30 --
 * Fix a race condition on file list download (thanks bigmuscle)

=== modified file 'dcpp/DCPlusPlus.cpp'
--- dcpp/DCPlusPlus.cpp	2013-01-18 21:28:38 +0000
+++ dcpp/DCPlusPlus.cpp	2013-02-14 16:25:20 +0000
@@ -88,7 +88,7 @@
 	PluginApiImpl::init();
 }
 
-void load(function<void (const string&)> f) {
+void load(function<void (const string&)> stepF, function<void (float)> progressF) {
 	SettingsManager::getInstance()->load();
 
 #ifdef _WIN32
@@ -101,9 +101,9 @@
 	}
 #endif
 
-	auto announce = [&f](const string& str) {
-		if(f) {
-			f(str);
+	auto announce = [&stepF](const string& str) {
+		if(stepF) {
+			stepF(str);
 		}
 	};
 
@@ -111,19 +111,19 @@
 	ClientManager::getInstance()->loadUsers();
 	FavoriteManager::getInstance()->load();
 
-	PluginManager::getInstance()->loadPlugins(f);
+	PluginManager::getInstance()->loadPlugins(stepF);
 
 	announce(_("Security certificates"));
 	CryptoManager::getInstance()->loadCertificates();
 
 	announce(_("Hash database"));
-	HashManager::getInstance()->startup();
+	HashManager::getInstance()->startup(progressF);
 
 	announce(_("Shared Files"));
-	ShareManager::getInstance()->refresh(true, false, true);
+	ShareManager::getInstance()->refresh(true, false, true, progressF);
 
 	announce(_("Download Queue"));
-	QueueManager::getInstance()->loadQueue();
+	QueueManager::getInstance()->loadQueue(progressF);
 
 	if(SETTING(GET_USER_COUNTRY)) {
 		announce(_("Country information"));

=== modified file 'dcpp/DCPlusPlus.h'
--- dcpp/DCPlusPlus.h	2013-01-18 21:28:38 +0000
+++ dcpp/DCPlusPlus.h	2013-02-14 16:25:20 +0000
@@ -28,7 +28,7 @@
 using std::string;
 
 void startup();
-void load(function<void (const string&)> f);
+void load(function<void (const string&)> stepF, function<void (float)> progressF);
 void shutdown();
 
 } // namespace dcpp

=== modified file 'dcpp/HashManager.cpp'
--- dcpp/HashManager.cpp	2013-02-12 22:22:05 +0000
+++ dcpp/HashManager.cpp	2013-02-14 16:25:20 +0000
@@ -21,12 +21,13 @@
 
 #include <boost/scoped_array.hpp>
 
-#include "SimpleXML.h"
-#include "LogManager.h"
 #include "File.h"
 #include "FileReader.h"
+#include "LogManager.h"
+#include "ScopedFunctor.h"
+#include "SimpleXML.h"
+#include "SFVReader.h"
 #include "ZUtils.h"
-#include "SFVReader.h"
 
 namespace dcpp {
 
@@ -322,14 +323,27 @@
 
 class HashLoader: public SimpleXMLReader::CallBack {
 public:
-	HashLoader(HashManager::HashStore& s) :
-		store(s), version(HASH_FILE_VERSION), inTrees(false), inFiles(false), inHashStore(false) {
-	}
+	HashLoader(HashManager::HashStore& s, const CountedInputStream<false>& countedStream, uint64_t fileSize, function<void (float)> progressF) :
+		store(s),
+		countedStream(countedStream),
+		streamPos(0),
+		fileSize(fileSize),
+		progressF(progressF),
+		version(HASH_FILE_VERSION),
+		inTrees(false),
+		inFiles(false),
+		inHashStore(false)
+	{ }
 	void startTag(const string& name, StringPairList& attribs, bool simple);
 
 private:
 	HashManager::HashStore& store;
 
+	const CountedInputStream<false>& countedStream;
+	uint64_t streamPos;
+	uint64_t fileSize;
+	function<void (float)> progressF;
+
 	int version;
 	string file;
 
@@ -338,13 +352,14 @@
 	bool inHashStore;
 };
 
-void HashManager::HashStore::load() {
+void HashManager::HashStore::load(function<void (float)> progressF) {
 	try {
 		Util::migrate(getIndexFile());
 
-		HashLoader l(*this);
 		File f(getIndexFile(), File::READ, File::OPEN);
-		SimpleXMLReader(&l).parse(f);
+		CountedInputStream<false> countedStream(&f);
+		HashLoader l(*this, countedStream, f.getSize(), progressF);
+		SimpleXMLReader(&l).parse(countedStream);
 	} catch (const Exception&) {
 		// ...
 	}
@@ -383,14 +398,6 @@
 		return false;
 	}
 
-	static auto upgradeStart = GET_TICK();
-	static auto cancelled = false;
-	if(cancelled || GET_TICK() > upgradeStart + 26 * 1000) {
-		// the upgrade is taking too long - cancel the process; the files will be re-hashed.
-		cancelled = true;
-		return false;
-	}
-
 	WIN32_FIND_DATA data;
 	// FindFirstFile does a case-insensitive search by default
 	auto handle = ::FindFirstFile(Text::toT(file).c_str(), &data);
@@ -462,6 +469,14 @@
 static const string sRoot = "Root";
 
 void HashLoader::startTag(const string& name, StringPairList& attribs, bool simple) {
+	ScopedFunctor([this] {
+		auto readBytes = countedStream.getReadBytes();
+		if(readBytes != streamPos) {
+			streamPos = readBytes;
+			progressF(static_cast<float>(readBytes) / static_cast<float>(fileSize));
+		}
+	});
+
 	if (!inHashStore && name == sHashStore) {
 		version = Util::toInt(getAttrib(attribs, sVersion, 0));
 		if (version == 0) {

=== modified file 'dcpp/HashManager.h'
--- dcpp/HashManager.h	2013-01-18 21:28:38 +0000
+++ dcpp/HashManager.h	2013-02-14 16:25:20 +0000
@@ -19,6 +19,7 @@
 #ifndef DCPLUSPLUS_DCPP_HASH_MANAGER_H
 #define DCPLUSPLUS_DCPP_HASH_MANAGER_H
 
+#include <functional>
 #include <map>
 
 #include <boost/optional.hpp>
@@ -34,6 +35,7 @@
 
 namespace dcpp {
 
+using std::function;
 using std::map;
 
 using boost::optional;
@@ -83,7 +85,7 @@
 	 */
 	void rebuild() { hasher.scheduleRebuild(); }
 
-	void startup() { hasher.start(); store.load(); }
+	void startup(function<void (float)> progressF) { hasher.start(); store.load(progressF); }
 
 	void shutdown() {
 		hasher.shutdown();
@@ -148,7 +150,7 @@
 		HashStore();
 		void addFile(const string& aFileName, uint32_t aTimeStamp, const TigerTree& tth, bool aUsed);
 
-		void load();
+		void load(function<void (float)> progressF);
 		void save();
 
 		void rebuild();

=== modified file 'dcpp/QueueManager.cpp'
--- dcpp/QueueManager.cpp	2013-01-28 21:32:53 +0000
+++ dcpp/QueueManager.cpp	2013-02-14 16:25:20 +0000
@@ -1302,6 +1302,20 @@
 	}
 }
 
+int QueueManager::countOnlineSources(const string& aTarget) {
+	Lock l(cs);
+
+	QueueItem* qi = fileQueue.find(aTarget);
+	if(!qi)
+		return 0;
+	int onlineSources = 0;
+	for(auto& i: qi->getSources()) {
+		if(i.getUser().user->isOnline())
+			onlineSources++;
+	}
+	return onlineSources;
+}
+
 void QueueManager::saveQueue(bool force) noexcept {
 	if(!dirty && !force)
 		return;
@@ -1383,43 +1397,43 @@
 
 class QueueLoader : public SimpleXMLReader::CallBack {
 public:
-	QueueLoader() : cur(NULL), inDownloads(false) { }
+	QueueLoader(const CountedInputStream<false>& countedStream, uint64_t fileSize, function<void (float)> progressF) :
+		countedStream(countedStream),
+		streamPos(0),
+		fileSize(fileSize),
+		progressF(progressF),
+		cur(nullptr),
+		inDownloads(false)
+	{ }
 	void startTag(const string& name, StringPairList& attribs, bool simple);
 	void endTag(const string& name);
+
 private:
+	const CountedInputStream<false>& countedStream;
+	uint64_t streamPos;
+	uint64_t fileSize;
+	function<void (float)> progressF;
+
 	string target;
 
 	QueueItem* cur;
 	bool inDownloads;
 };
 
-void QueueManager::loadQueue() noexcept {
+void QueueManager::loadQueue(function<void (float)> progressF) noexcept {
 	try {
-		QueueLoader l;
 		Util::migrate(getQueueFile());
 
 		File f(getQueueFile(), File::READ, File::OPEN);
-		SimpleXMLReader(&l).parse(f);
+		CountedInputStream<false> countedStream(&f);
+		QueueLoader l(countedStream, f.getSize(), progressF);
+		SimpleXMLReader(&l).parse(countedStream);
 		dirty = false;
 	} catch(const Exception&) {
 		// ...
 	}
 }
 
-int QueueManager::countOnlineSources(const string& aTarget) {
-	Lock l(cs);
-
-	QueueItem* qi = fileQueue.find(aTarget);
-	if(!qi)
-		return 0;
-	int onlineSources = 0;
-	for(auto& i: qi->getSources()) {
-		if(i.getUser().user->isOnline())
-			onlineSources++;
-	}
-	return onlineSources;
-}
-
 static const string sDownloads = "Downloads";
 static const string sDownload = "Download";
 static const string sTempTarget = "TempTarget";
@@ -1436,11 +1450,19 @@
 static const string sStart = "Start";
 
 void QueueLoader::startTag(const string& name, StringPairList& attribs, bool simple) {
+	ScopedFunctor([this] {
+		auto readBytes = countedStream.getReadBytes();
+		if(readBytes != streamPos) {
+			streamPos = readBytes;
+			progressF(static_cast<float>(readBytes) / static_cast<float>(fileSize));
+		}
+	});
+
 	QueueManager* qm = QueueManager::getInstance();
 	if(!inDownloads && name == sDownloads) {
 		inDownloads = true;
 	} else if(inDownloads) {
-		if(cur == NULL && name == sDownload) {
+		if(cur == nullptr && name == sDownload) {
 			int64_t size = Util::toInt64(getAttrib(attribs, sSize, 1));
 			if(size == 0)
 				return;
@@ -1469,7 +1491,7 @@
 
 			QueueItem* qi = qm->fileQueue.find(target);
 
-			if(qi == NULL) {
+			if(qi == nullptr) {
 				qi = qm->fileQueue.add(target, size, 0, p, tempTarget, added, TTHValue(tthRoot));
 				if(downloaded > 0) {
 					qi->addSegment(Segment(0, downloaded));
@@ -1508,7 +1530,7 @@
 void QueueLoader::endTag(const string& name) {
 	if(inDownloads) {
 		if(name == sDownload) {
-			cur = NULL;
+			cur = nullptr;
 		} else if(name == sDownloads) {
 			inDownloads = false;
 		}

=== modified file 'dcpp/QueueManager.h'
--- dcpp/QueueManager.h	2013-01-27 17:45:34 +0000
+++ dcpp/QueueManager.h	2013-02-14 16:25:20 +0000
@@ -132,7 +132,7 @@
 
 	int countOnlineSources(const string& aTarget);
 
-	void loadQueue() noexcept;
+	void loadQueue(function<void (float)> progressF) noexcept;
 	void saveQueue(bool force = false) noexcept;
 
 	string getListPath(const HintedUser& user);

=== modified file 'dcpp/ShareManager.cpp'
--- dcpp/ShareManager.cpp	2013-01-25 20:29:34 +0000
+++ dcpp/ShareManager.cpp	2013-02-14 16:25:20 +0000
@@ -693,7 +693,7 @@
 	bloom.add(Text::toLower(f.getName()));
 }
 
-void ShareManager::refresh(bool dirs /* = false */, bool aUpdate /* = true */, bool block /* = false */) noexcept {
+void ShareManager::refresh(bool dirs, bool aUpdate, bool block, function<void (float)> progressF) noexcept {
 	if(refreshing.test_and_set()) {
 		LogManager::getInstance()->message(_("File list refresh in progress, please wait for it to finish before trying to refresh again"));
 		return;
@@ -701,16 +701,19 @@
 
 	update = aUpdate;
 	refreshDirs = dirs;
+
 	join();
-	try {
-		start();
-		if(block) {
-			join();
-		} else {
+
+	if(block) {
+		runRefresh(progressF);
+
+	} else {
+		try {
+			start();
 			setThreadPriority(Thread::LOW);
+		} catch(const ThreadException& e) {
+			LogManager::getInstance()->message(str(F_("File list refresh failed: %1%") % e.getError()));
 		}
-	} catch(const ThreadException& e) {
-		LogManager::getInstance()->message(str(F_("File list refresh failed: %1%") % e.getError()));
 	}
 }
 
@@ -724,8 +727,12 @@
 }
 
 int ShareManager::run() {
+	runRefresh();
+	return 0;
+}
 
-	StringPairList dirs = getDirectories();
+void ShareManager::runRefresh(function<void (float)> progressF) {
+	auto dirs = getDirectories();
 	// Don't need to refresh if no directories are shared
 	if(dirs.empty())
 		refreshDirs = false;
@@ -738,12 +745,19 @@
 		lastFullUpdate = GET_TICK();
 
 		vector<pair<Directory::Ptr, string>> newDirs;
+
+		float progressCounter = 0, dirCount = dirs.size();
+
 		for(auto& i: dirs) {
-			if (checkHidden(i.second)) {
+			if(checkHidden(i.second)) {
 				auto dp = buildTree(i.second);
 				dp->setName(i.first);
 				newDirs.emplace_back(dp, i.second);
 			}
+
+			if(progressF) {
+				progressF(++progressCounter / dirCount);
+			}
 		}
 
 		{
@@ -766,7 +780,6 @@
 	}
 
 	refreshing.clear();
-	return 0;
 }
 
 void ShareManager::getBloom(ByteVector& v, size_t k, size_t m, size_t h) const {

=== modified file 'dcpp/ShareManager.h'
--- dcpp/ShareManager.h	2013-01-25 20:29:34 +0000
+++ dcpp/ShareManager.h	2013-02-14 16:25:20 +0000
@@ -19,6 +19,7 @@
 #ifndef DCPLUSPLUS_DCPP_SHARE_MANAGER_H
 #define DCPLUSPLUS_DCPP_SHARE_MANAGER_H
 
+#include <functional>
 #include <map>
 #include <memory>
 #include <set>
@@ -45,6 +46,7 @@
 
 namespace dcpp {
 
+using std::function;
 using std::map;
 using std::set;
 using std::unique_ptr;
@@ -80,7 +82,7 @@
 	StringList getRealPaths(const string& virtualPath);
 	optional<TTHValue> getTTH(const string& virtualFile) const;
 
-	void refresh(bool dirs = false, bool aUpdate = true, bool block = false) noexcept;
+	void refresh(bool dirs = false, bool aUpdate = true, bool block = false, function<void (float)> progressF = nullptr) noexcept;
 	void setDirty() { xmlDirty = true; }
 
 	void search(SearchResultList& l, const string& aString, int aSearchType, int64_t aSize, int aFileType, Client* aClient, StringList::size_type maxResults) noexcept;
@@ -297,6 +299,7 @@
 	optional<const ShareManager::Directory::File&> getFile(const string& realPath, Directory::Ptr d = nullptr) noexcept;
 
 	virtual int run();
+	void runRefresh(function<void (float)> progressF = nullptr);
 
 	// QueueManagerListener
 	virtual void on(QueueManagerListener::FileMoved, const string& realPath) noexcept;

=== modified file 'dcpp/Streams.h'
--- dcpp/Streams.h	2013-01-18 21:28:38 +0000
+++ dcpp/Streams.h	2013-02-14 16:25:20 +0000
@@ -108,6 +108,26 @@
 class IOStream : public InputStream, public OutputStream {
 };
 
+/** Count how many bytes have been read. */
+template<bool managed>
+class CountedInputStream : public InputStream {
+public:
+	CountedInputStream(InputStream* is) : s(is), readBytes(0) { }
+	virtual ~CountedInputStream() { if(managed) delete s; }
+
+	size_t read(void* buf, size_t& len) {
+		auto ret = s->read(buf, len);
+		readBytes += len;
+		return ret;
+	}
+
+	uint64_t getReadBytes() const { return readBytes; }
+
+private:
+	InputStream* s;
+	uint64_t readBytes;
+};
+
 template<bool managed>
 class LimitedInputStream : public InputStream {
 public:

=== modified file 'win32/SplashWindow.cpp'
--- win32/SplashWindow.cpp	2013-01-18 21:28:38 +0000
+++ win32/SplashWindow.cpp	2013-02-14 16:25:20 +0000
@@ -24,12 +24,14 @@
 #include <dcpp/version.h>
 
 #include <dwt/DWTException.h>
+#include <dwt/widgets/ProgressBar.h>
 
 #include "resource.h"
 #include "WinUtil.h"
 
 SplashWindow::SplashWindow() :
-dwt::Window(0)
+	dwt::Window(0),
+	progress(0)
 {
 	// 256x icons only work on >= Vista. on failure, try loading a 48x image.
 	try {
@@ -58,7 +60,19 @@
 }
 
 void SplashWindow::operator()(const string& status) {
-	auto text = str(TF_("Loading DC++, please wait... (%1%)") % Text::toT(status));
+	this->status = str(TF_("Loading DC++, please wait... (%1%)") % Text::toT(status));
+	progress = 0;
+	draw();
+}
+
+void SplashWindow::operator()(float progress) {
+	this->progress = progress;
+	draw();
+}
+
+void SplashWindow::draw() {
+	auto text = status;
+	if(progress) { text += _T(" [") + Text::toT(Util::toString(progress * 100.)) + _T("%]"); }
 
 	// set up sizes.
 	const long spacing { 6 }; // space between the icon and the text
@@ -90,8 +104,13 @@
 	canvas.drawText(text.c_str(), textRect, DT_CENTER | DT_VCENTER | DT_SINGLELINE | DT_NOPREFIX);
 
 	// set bits within the text rectangle to not be transparent. rgbReserved is the alpha value.
-	for(long x = textRect.left(), xn = textRect.right(); x < xn; ++x) {
-		for(long y = textRect.top(), yn = textRect.bottom(); y < yn; ++y) {
+	// to simulate a progress bar, some bits are made to be semi-opaque.
+	long pos = textRect.left() + progress * static_cast<float>(textRect.width());
+	for(long y = textRect.top(), yn = textRect.bottom(); y < yn; ++y) {
+		for(long x = textRect.left(); x < pos; ++x) {
+			bits[x + y * size.cx].rgbReserved = 191;
+		}
+		for(long x = pos, xn = textRect.right(); x < xn; ++x) {
 			bits[x + y * size.cx].rgbReserved = 255;
 		}
 	}

=== modified file 'win32/SplashWindow.h'
--- win32/SplashWindow.h	2013-01-18 21:28:38 +0000
+++ win32/SplashWindow.h	2013-02-14 16:25:20 +0000
@@ -27,10 +27,16 @@
 	virtual ~SplashWindow();
 
 	void operator()(const string& status);
+	void operator()(float progress);
 
 private:
+	void draw();
+
 	long iconSize;
 	dwt::IconPtr icon;
+
+	tstring status;
+	float progress;
 };
 
 #endif

=== modified file 'win32/main.cpp'
--- win32/main.cpp	2013-01-18 21:28:38 +0000
+++ win32/main.cpp	2013-02-14 16:25:20 +0000
@@ -133,12 +133,12 @@
 	}
 
 	try {
-		SplashWindow* splash(new SplashWindow);
+		auto splash = new SplashWindow();
 
 		startup();
 		PluginApiWin::init();
 
-		load([splash](const string& str) { (*splash)(str); });
+		load([splash](const string& str) { (*splash)(str); }, [splash](float progress) { (*splash)(progress); });
 
 		bindtextdomain(PACKAGE, LOCALEDIR);
 		textdomain(PACKAGE);