1 /*
2  * Copyright © 2004-2008 Jens Oknelid, paskharen@gmail.com
3  *
4  * This program is free software; you can redistribute it and/or modify
5  * it under the terms of the GNU General Public License as published by
6  * the Free Software Foundation; either version 2 of the License, or
7  * (at your option) any later version.
8  *
9  * This program is distributed in the hope that it will be useful,
10  * but WITHOUT ANY WARRANTY; without even the implied warranty of
11  * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
12  * GNU General Public License for more details.
13  *
14  * You should have received a copy of the GNU General Public License
15  * along with this program; if not, write to the Free Software
16  * Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301 USA.
17  *
18  * In addition, as a special exception, compiling, linking, and/or
19  * using OpenSSL with this program is allowed.
20  */
21 
22 #include "downloadqueue.hh"
23 
24 #include <dcpp/ResourceManager.h>
25 #include "search.hh"
26 #include "settingsmanager.hh"
27 #include "wulformanager.hh"
28 #include "WulforUtil.hh"
29 
30 using namespace std;
31 using namespace dcpp;
32 
DownloadQueue()33 DownloadQueue::DownloadQueue():
34 	BookEntry(Entry::DOWNLOAD_QUEUE, _("Download Queue"), "downloadqueue.glade"),
35 	currentItems(0),
36 	totalItems(0),
37 	currentSize(0),
38 	totalSize(0)
39 {
40 	// Configure the dialogs
41 	File::ensureDirectory(SETTING(DOWNLOAD_DIRECTORY));
42 	gtk_file_chooser_set_current_folder(GTK_FILE_CHOOSER(getWidget("dirChooserDialog")), Text::fromUtf8(SETTING(DOWNLOAD_DIRECTORY)).c_str());
43 	gtk_dialog_set_alternative_button_order(GTK_DIALOG(getWidget("dirChooserDialog")), GTK_RESPONSE_OK, GTK_RESPONSE_CANCEL, -1);
44 
45 	// Initialize directory treeview
46 	dirView.setView(GTK_TREE_VIEW(getWidget("dirView")));
47 	dirView.insertColumn("Dir", G_TYPE_STRING, TreeView::STRING, -1);
48 	dirView.insertHiddenColumn("Path", G_TYPE_STRING);
49 	dirView.insertHiddenColumn("File Count", G_TYPE_INT);
50 	dirView.finalize();
51 	dirStore = gtk_tree_store_newv(dirView.getColCount(), dirView.getGTypes());
52 	gtk_tree_view_set_model(dirView.get(), GTK_TREE_MODEL(dirStore));
53 	g_object_unref(dirStore);
54 	dirSelection = gtk_tree_view_get_selection(dirView.get());
55 	gtk_tree_sortable_set_sort_column_id(GTK_TREE_SORTABLE(dirStore), dirView.col("Dir"), GTK_SORT_ASCENDING);
56 	gtk_tree_view_set_enable_tree_lines(dirView.get(), TRUE);
57 
58 	// Initialize file treeview
59 	fileView.setView(GTK_TREE_VIEW(getWidget("fileView")), TRUE, "downloadqueue");
60 	fileView.insertColumn(N_("Filename"), G_TYPE_STRING, TreeView::STRING, 200);
61 	fileView.insertColumn(N_("Status"), G_TYPE_STRING, TreeView::STRING, 100);
62 	fileView.insertColumn(N_("Size"), G_TYPE_STRING, TreeView::STRING, 100);
63 	fileView.insertColumn(N_("Downloaded"), G_TYPE_STRING, TreeView::STRING, 150);
64 	fileView.insertColumn(N_("Priority"), G_TYPE_STRING, TreeView::STRING, 75);
65 	fileView.insertColumn(N_("Users"), G_TYPE_STRING, TreeView::STRING, 200);
66 	fileView.insertColumn(N_("Path"), G_TYPE_STRING, TreeView::STRING, 200);
67 	fileView.insertColumn(N_("Exact Size"), G_TYPE_STRING, TreeView::STRING, 100);
68 	fileView.insertColumn(N_("Errors"), G_TYPE_STRING, TreeView::STRING, 200);
69 	fileView.insertColumn(N_("Added"), G_TYPE_STRING, TreeView::STRING, 120);
70 	fileView.insertColumn(N_("TTH"), G_TYPE_STRING, TreeView::STRING, 125);
71 	fileView.insertHiddenColumn("Size Sort", G_TYPE_INT64);
72 	fileView.insertHiddenColumn("Downloaded Sort", G_TYPE_INT64);
73 	fileView.insertHiddenColumn("Target", G_TYPE_STRING);
74 	fileView.finalize();
75 	fileStore = gtk_list_store_newv(fileView.getColCount(), fileView.getGTypes());
76 	gtk_tree_view_set_model(fileView.get(), GTK_TREE_MODEL(fileStore));
77 	g_object_unref(fileStore);
78 	gtk_tree_selection_set_mode(gtk_tree_view_get_selection(fileView.get()), GTK_SELECTION_MULTIPLE);
79 	fileSelection = gtk_tree_view_get_selection(fileView.get());
80 	fileView.setSortColumn_gui("Size", "Size Sort");
81 	fileView.setSortColumn_gui("Exact Size", "Size Sort");
82 	fileView.setSortColumn_gui("Downloaded", "Downloaded Sort");
83 	gtk_tree_sortable_set_sort_column_id(GTK_TREE_SORTABLE(fileStore), fileView.col("Filename"), GTK_SORT_ASCENDING);
84 	gtk_tree_view_column_set_sort_indicator(gtk_tree_view_get_column(fileView.get(), fileView.col("Filename")), TRUE);
85 
86 	// Connect the signals to their callback functions.
87 	g_signal_connect(getWidget("pausedPriorityItem"), "activate", G_CALLBACK(onDirPriorityClicked_gui), (gpointer)this);
88 	g_signal_connect(getWidget("lowestPriorityItem"), "activate", G_CALLBACK(onDirPriorityClicked_gui), (gpointer)this);
89 	g_signal_connect(getWidget("lowPrioritytem"), "activate", G_CALLBACK(onDirPriorityClicked_gui), (gpointer)this);
90 	g_signal_connect(getWidget("normalPriorityItem"), "activate", G_CALLBACK(onDirPriorityClicked_gui), (gpointer)this);
91 	g_signal_connect(getWidget("highPriorityItem"), "activate", G_CALLBACK(onDirPriorityClicked_gui), (gpointer)this);
92 	g_signal_connect(getWidget("highestPriorityItem"), "activate", G_CALLBACK(onDirPriorityClicked_gui), (gpointer)this);
93 	g_signal_connect(getWidget("moveDirItem"), "activate", G_CALLBACK(onDirMoveClicked_gui), (gpointer)this);
94 	g_signal_connect(getWidget("removeDirItem"), "activate", G_CALLBACK(onDirRemoveClicked_gui), (gpointer)this);
95 	g_signal_connect(getWidget("searchForAlternatesItem"), "activate", G_CALLBACK(onFileSearchAlternatesClicked_gui), (gpointer)this);
96 	g_signal_connect(getWidget("moveFileItem"), "activate", G_CALLBACK(onFileMoveClicked_gui), (gpointer)this);
97 	g_signal_connect(getWidget("filePausedItem"), "activate", G_CALLBACK(onFilePriorityClicked_gui), (gpointer)this);
98 	g_signal_connect(getWidget("fileLowestPriorityItem"), "activate", G_CALLBACK(onFilePriorityClicked_gui), (gpointer)this);
99 	g_signal_connect(getWidget("fileLowPriorityItem"), "activate", G_CALLBACK(onFilePriorityClicked_gui), (gpointer)this);
100 	g_signal_connect(getWidget("fileNormalPriorityItem"), "activate", G_CALLBACK(onFilePriorityClicked_gui), (gpointer)this);
101 	g_signal_connect(getWidget("fileHighPriorityItem"), "activate", G_CALLBACK(onFilePriorityClicked_gui), (gpointer)this);
102 	g_signal_connect(getWidget("fileHighestPriorityItem"), "activate", G_CALLBACK(onFilePriorityClicked_gui), (gpointer)this);
103 	g_signal_connect(getWidget("fileRemoveItem"), "activate", G_CALLBACK(onFileRemoveClicked_gui), (gpointer)this);
104  	g_signal_connect(getWidget("copyMagnetItem"), "activate", G_CALLBACK(onCopyMagnetClicked_gui), (gpointer)this);
105  	g_signal_connect(dirView.get(), "button-press-event", G_CALLBACK(onDirButtonPressed_gui), (gpointer)this);
106 	g_signal_connect(dirView.get(), "button-release-event", G_CALLBACK(onDirButtonReleased_gui), (gpointer)this);
107 	g_signal_connect(dirView.get(), "key-release-event", G_CALLBACK(onDirKeyReleased_gui), (gpointer)this);
108 	g_signal_connect(fileView.get(), "button-press-event", G_CALLBACK(onFileButtonPressed_gui), (gpointer)this);
109 	g_signal_connect(fileView.get(), "button-release-event", G_CALLBACK(onFileButtonReleased_gui), (gpointer)this);
110 	g_signal_connect(fileView.get(), "key-release-event", G_CALLBACK(onFileKeyReleased_gui), (gpointer)this);
111 
112 	// Set the pane position
113 	gtk_paned_set_position(GTK_PANED(getWidget("pane")), WGETI("downloadqueue-pane-position"));
114 	int panePosition = WGETI("downloadqueue-pane-position");
115 	if (panePosition > 10)
116 		gtk_paned_set_position(GTK_PANED(getWidget("pane")), panePosition);
117 }
118 
~DownloadQueue()119 DownloadQueue::~DownloadQueue()
120 {
121 	QueueManager::getInstance()->removeListener(this);
122 
123 	// Save the pane position
124 	int panePosition = gtk_paned_get_position(GTK_PANED(getWidget("pane")));
125 	if (panePosition > 10)
126 		WSET("downloadqueue-pane-position", panePosition);
127 
128 	gtk_widget_destroy(getWidget("dirChooserDialog"));
129 }
130 
show()131 void DownloadQueue::show()
132 {
133 	buildList_client();
134 	QueueManager::getInstance()->addListener(this);
135 }
136 
buildDynamicMenu_gui()137 void DownloadQueue::buildDynamicMenu_gui()
138 {
139 	bool showMenus = FALSE;
140 	bool showReAddMenu = FALSE;
141 	int count = gtk_tree_selection_count_selected_rows(fileSelection);
142 
143 	if (count == 1)
144 	{
145 		GtkTreeIter iter;
146 		GList *list = gtk_tree_selection_get_selected_rows(fileSelection, NULL);
147 		GtkTreePath *path = (GtkTreePath *)g_list_nth_data(list, 0);
148 
149 		gtk_container_foreach(GTK_CONTAINER(getWidget("browseMenu")), (GtkCallback)gtk_widget_destroy, NULL);
150 		gtk_container_foreach(GTK_CONTAINER(getWidget("pmMenu")), (GtkCallback)gtk_widget_destroy, NULL);
151 		gtk_container_foreach(GTK_CONTAINER(getWidget("reAddMenu")), (GtkCallback)gtk_widget_destroy, NULL);
152 		gtk_container_foreach(GTK_CONTAINER(getWidget("removeMenu")), (GtkCallback)gtk_widget_destroy, NULL);
153 		gtk_container_foreach(GTK_CONTAINER(getWidget("removeAllMenu")), (GtkCallback)gtk_widget_destroy, NULL);
154 
155 		if (gtk_tree_model_get_iter(GTK_TREE_MODEL(fileStore), &iter, path))
156 		{
157 			GtkWidget *menuItem;
158 			string target = fileView.getString(&iter, "Target");
159 
160 			///@todo: Fix this. sources & badSources should not be accessible from gui thread.
161 			for (SourceIter it = sources[target].begin(); it != sources[target].end(); ++it)
162 			{
163 				showMenus = TRUE;
164 				menuItem = gtk_menu_item_new_with_label(it->first.c_str());
165 				gtk_menu_shell_append(GTK_MENU_SHELL(getWidget("browseMenu")), menuItem);
166 				g_signal_connect(menuItem, "activate", G_CALLBACK(onFileGetListClicked_gui), (gpointer)this);
167 
168 				menuItem = gtk_menu_item_new_with_label(it->first.c_str());
169 				gtk_menu_shell_append(GTK_MENU_SHELL(getWidget("pmMenu")), menuItem);
170 				g_signal_connect(menuItem, "activate", G_CALLBACK(onFileSendPMClicked_gui), (gpointer)this);
171 
172 				menuItem = gtk_menu_item_new_with_label(it->first.c_str());
173 				gtk_menu_shell_append(GTK_MENU_SHELL(getWidget("removeMenu")), menuItem);
174 				g_signal_connect(menuItem, "activate", G_CALLBACK(onFileRemoveSourceClicked_gui), (gpointer)this);
175 
176 				menuItem = gtk_menu_item_new_with_label(it->first.c_str());
177 				gtk_menu_shell_append(GTK_MENU_SHELL(getWidget("removeAllMenu")), menuItem);
178 				g_signal_connect(menuItem, "activate", G_CALLBACK(onFileRemoveUserFromQueueClicked_gui), (gpointer)this);
179 			}
180 
181 			for (SourceIter it = badSources[target].begin(); it != badSources[target].end(); ++it)
182 			{
183 				showReAddMenu = TRUE;
184 				menuItem = gtk_menu_item_new_with_label(it->first.c_str());
185 				gtk_menu_shell_append(GTK_MENU_SHELL(getWidget("reAddMenu")), menuItem);
186 				g_signal_connect(menuItem, "activate", G_CALLBACK(onFileReAddSourceClicked_gui), (gpointer)this);
187 			}
188 		}
189 		gtk_tree_path_free(path);
190 		g_list_free(list);
191 
192 		gtk_widget_set_sensitive(getWidget("searchForAlternatesItem"), TRUE);
193 	}
194 	else
195 		gtk_widget_set_sensitive(getWidget("searchForAlternatesItem"), FALSE);
196 
197 	if (showMenus)
198 	{
199 		gtk_widget_show_all(getWidget("browseMenu"));
200 		gtk_widget_show_all(getWidget("pmMenu"));
201 		gtk_widget_show_all(getWidget("removeMenu"));
202 		gtk_widget_show_all(getWidget("removeAllMenu"));
203 	}
204 	if (showReAddMenu)
205 		gtk_widget_show_all(getWidget("reAddMenu"));
206 
207 	gtk_widget_set_sensitive(getWidget("getFileListItem"), showMenus);
208 	gtk_widget_set_sensitive(getWidget("sendPrivateMessageItem"), showMenus);
209 	gtk_widget_set_sensitive(getWidget("removeSourceItem"), showMenus);
210 	gtk_widget_set_sensitive(getWidget("removeUserFromQueueItem"), showMenus);
211 	gtk_widget_set_sensitive(getWidget("reAddSourceItem"), showReAddMenu);
212 }
213 
setStatus_gui(string text,string statusItem)214 void DownloadQueue::setStatus_gui(string text, string statusItem)
215 {
216 	if (!text.empty() && !statusItem.empty())
217 	{
218 		if (statusItem == "statusMain")
219 			text = "[" + Util::getShortTimeString() + "] " + text;
220 
221 		gtk_statusbar_pop(GTK_STATUSBAR(getWidget(statusItem)), 0);
222 		gtk_statusbar_push(GTK_STATUSBAR(getWidget(statusItem)), 0, text.c_str());
223 	}
224 }
225 
updateStatus_gui()226 void DownloadQueue::updateStatus_gui()
227 {
228 	setStatus_gui(F_("Items: %1%", % currentItems), "statusItems");
229 	setStatus_gui(F_("Size: %1%", % Util::formatBytes(currentSize)), "statusFileSize");
230 	setStatus_gui(F_("Files: %1%", % totalItems), "statusFiles");
231 	setStatus_gui(F_("Size: %1%", % Util::formatBytes(totalSize)), "statusTotalSize");
232 }
233 
addFiles_gui(vector<StringMap> files,bool firstUpdate)234 void DownloadQueue::addFiles_gui(vector<StringMap> files, bool firstUpdate)
235 {
236 	if (files.size() > 0 && currentDir == files[0]["Path"] &&
237 	    gtk_tree_selection_get_selected(dirSelection, NULL, NULL))
238 	{
239 		if (firstUpdate)
240 			gtk_list_store_clear(fileStore);
241 
242 		gint sortColumn;
243 		GtkSortType sortType;
244 		gtk_tree_sortable_get_sort_column_id(GTK_TREE_SORTABLE(fileStore), &sortColumn, &sortType);
245 		gtk_tree_sortable_set_sort_column_id(GTK_TREE_SORTABLE(fileStore), GTK_TREE_SORTABLE_UNSORTED_SORT_COLUMN_ID, sortType);
246 
247 		for (vector<StringMap>::const_iterator it = files.begin(); it != files.end(); ++it)
248 			addFile_gui(*it, FALSE);
249 
250 		gtk_tree_sortable_set_sort_column_id(GTK_TREE_SORTABLE(fileStore), sortColumn, sortType);
251 		gtk_tree_view_scroll_to_point(fileView.get(), 0, 0);
252 	}
253 }
254 
addFile_gui(StringMap params,bool updateDirs)255 void DownloadQueue::addFile_gui(StringMap params, bool updateDirs)
256 {
257 	GtkTreeIter iter;
258 	int64_t size = Util::toInt64(params["Size Sort"]);
259 
260 	if (gtk_tree_selection_get_selected(dirSelection, NULL, NULL) && currentDir == params["Path"])
261 	{
262 		++currentItems;
263 		currentSize += size;
264 
265 		gtk_list_store_append(fileStore, &iter);
266 		gtk_list_store_set(fileStore, &iter,
267 			fileView.col("Filename"), params["Filename"].c_str(),
268 			fileView.col("Users"), params["Users"].c_str(),
269 			fileView.col("Status"), params["Status"].c_str(),
270 			fileView.col("Size"), params["Size"].c_str(),
271 			fileView.col("Exact Size"), params["Exact Size"].c_str(),
272 			fileView.col("Size Sort"), size,
273 			fileView.col("Downloaded"), params["Downloaded"].c_str(),
274 			fileView.col("Downloaded Sort"), Util::toInt64(params["Downloaded Sort"]),
275 			fileView.col("Priority"), params["Priority"].c_str(),
276 			fileView.col("Path"), params["Path"].c_str(),
277 			fileView.col("Errors"), params["Errors"].c_str(),
278 			fileView.col("Added"), params["Added"].c_str(),
279 			fileView.col("TTH"), params["TTH"].c_str(),
280 			fileView.col("Target"), params["Target"].c_str(),
281 			-1);
282 
283 		if (BOOLSETTING(BOLD_QUEUE))
284 			setBold_gui();
285 	}
286 
287 	if (updateDirs)
288 	{
289 		++totalItems;
290 		totalSize += size;
291 
292 		// Ensure root node
293 		if (!gtk_tree_model_get_iter_first(GTK_TREE_MODEL(dirStore), &iter))
294 		{
295 			gtk_tree_store_append(dirStore, &iter, NULL);
296 			gtk_tree_store_set(dirStore, &iter,
297 				dirView.col("Dir"), "/",
298 				dirView.col("Path"), "/",
299 				dirView.col("File Count"), 0,
300 				-1);
301 		}
302 
303 		if (params["Path"].length() > 1)
304 			addDir_gui(params["Path"].substr(1), &iter);
305 	}
306 
307 	updateStatus_gui();
308 }
309 
addDir_gui(const string & path,GtkTreeIter * parent)310 void DownloadQueue::addDir_gui(const string &path, GtkTreeIter *parent)
311 {
312 	if (path.empty() || parent == NULL)
313 		return;
314 
315 	GtkTreeIter iter;
316 	string::size_type i = path.find_first_of(PATH_SEPARATOR);
317 	const string &dir = path.substr(0, i);
318 	const string &fullpath = dirView.getString(parent, "Path") + dir + PATH_SEPARATOR_STR;
319 	bool valid = gtk_tree_model_iter_children(GTK_TREE_MODEL(dirStore), &iter, parent);
320 
321 	while (valid)
322 	{
323 		if (dir == dirView.getString(&iter, "Dir"))
324 		{
325 			addDir_gui(path.substr(i + 1), &iter);
326 
327 			if (fullpath == dirView.getString(parent, "Path") + path)
328 			{
329 				int count = dirView.getValue<gint>(&iter, "File Count");
330 				gtk_tree_store_set(dirStore, &iter, dirView.col("File Count"), ++count, -1);
331 			}
332 
333 			return;
334 		}
335 		valid = gtk_tree_model_iter_next(GTK_TREE_MODEL(dirStore), &iter);
336 	}
337 
338 	gtk_tree_store_append(dirStore, &iter, parent);
339 	gtk_tree_store_set(dirStore, &iter,
340 		dirView.col("Dir"), dir.c_str(),
341 		dirView.col("Path"), fullpath.c_str(),
342 		dirView.col("File Count"), 0,
343 		-1);
344 
345 	GtkTreePath *treePath = gtk_tree_model_get_path(GTK_TREE_MODEL(dirStore), parent);
346 	gtk_tree_view_expand_row(dirView.get(), treePath, FALSE);
347 	gtk_tree_path_free(treePath);
348 
349 	if (fullpath == dirView.getString(parent, "Path") + path)
350 	{
351 		int count = dirView.getValue<gint>(&iter, "File Count");
352 		gtk_tree_store_set(dirStore, &iter, dirView.col("File Count"), ++count, -1);
353 	}
354 
355 	addDir_gui(path.substr(i + 1), &iter);
356 }
357 
updateFile_gui(StringMap params)358 void DownloadQueue::updateFile_gui(StringMap params)
359 {
360 	if (gtk_tree_selection_get_selected(dirSelection, NULL, NULL) && currentDir == params["Path"])
361 	{
362 		GtkTreeIter iter;
363 		GtkTreeModel *m = GTK_TREE_MODEL(fileStore);
364 		bool valid = gtk_tree_model_get_iter_first(m, &iter);
365 
366 		while (valid)
367 		{
368 			if (fileView.getString(&iter, "Target") == params["Target"])
369 			{
370 				gtk_list_store_set(fileStore, &iter,
371 					fileView.col("Filename"), params["Filename"].c_str(),
372 					fileView.col("Users"), params["Users"].c_str(),
373 					fileView.col("Status"), params["Status"].c_str(),
374 					fileView.col("Size"), params["Size"].c_str(),
375 					fileView.col("Exact Size"), params["Exact Size"].c_str(),
376 					fileView.col("Size Sort"), Util::toInt64(params["Size Sort"]),
377 					fileView.col("Downloaded"), params["Downloaded"].c_str(),
378 					fileView.col("Downloaded Sort"), Util::toInt64(params["Downloaded Sort"]),
379 					fileView.col("Priority"), params["Priority"].c_str(),
380 					fileView.col("Path"), params["Path"].c_str(),
381 					fileView.col("Errors"), params["Errors"].c_str(),
382 					fileView.col("Added"), params["Added"].c_str(),
383 					fileView.col("TTH"), params["TTH"].c_str(),
384 					fileView.col("Target"), params["Target"].c_str(),
385 					-1);
386 				return;
387 			}
388 			valid = gtk_tree_model_iter_next(m, &iter);
389 		}
390 	}
391 }
392 
removeFile_gui(string target,int64_t size)393 void DownloadQueue::removeFile_gui(string target, int64_t size)
394 {
395 	GtkTreeIter iter;
396 	bool valid = gtk_tree_model_get_iter_first(GTK_TREE_MODEL(fileStore), &iter);
397 	string path = Util::getFilePath(target);
398 
399 	while (valid)
400 	{
401 		if (target == fileView.getString(&iter, "Target"))
402 		{
403 			--currentItems;
404 			currentSize -= size;
405 			gtk_list_store_remove(fileStore, &iter);
406 			break;
407 		}
408 		valid = gtk_tree_model_iter_next(GTK_TREE_MODEL(fileStore), &iter);
409 	}
410 
411 	--totalItems;
412 	totalSize -= size;
413 
414 	if (path.length() > 1 && gtk_tree_model_get_iter_first(GTK_TREE_MODEL(dirStore), &iter))
415 		removeDir_gui(path.substr(1), &iter);
416 
417 	updateStatus_gui();
418 
419 	if (BOOLSETTING(BOLD_QUEUE))
420 		setBold_gui();
421 }
422 
removeDir_gui(const string & path,GtkTreeIter * parent)423 void DownloadQueue::removeDir_gui(const string &path, GtkTreeIter *parent)
424 {
425 	if (path.empty() || parent == NULL)
426 		return;
427 
428 	GtkTreeIter iter;
429 	string curPath;
430 	int count = 0;
431 	string::size_type i = path.find_first_of(PATH_SEPARATOR);
432 	string dir = path.substr(0, i);
433 	string fullpath = dirView.getString(parent, "Path") + path;
434 	bool valid = gtk_tree_model_iter_children(GTK_TREE_MODEL(dirStore), &iter, parent);
435 
436 	while (valid)
437 	{
438 		if (dir == dirView.getString(&iter, "Dir"))
439 		{
440 			removeDir_gui(path.substr(i + 1), &iter);
441 
442 			curPath = dirView.getString(&iter, "Path");
443 			count = dirView.getValue<gint>(&iter, "File Count");
444 			if (curPath == fullpath)
445 				gtk_tree_store_set(dirStore, &iter, dirView.col("File Count"), --count, -1);
446 
447 			// No files in leaf node
448 			if (count <= 0 && !gtk_tree_model_iter_has_child(GTK_TREE_MODEL(dirStore), &iter))
449 			{
450 				gtk_tree_store_remove(dirStore, &iter);
451 				if (currentDir == curPath)
452 				{
453 					gtk_list_store_clear(fileStore);
454 					currentDir.clear();
455 				}
456 			}
457 
458 			break;
459 		}
460 		valid = gtk_tree_model_iter_next(GTK_TREE_MODEL(dirStore), &iter);
461 	}
462 }
463 
updateFileView_gui()464 void DownloadQueue::updateFileView_gui()
465 {
466 	GtkTreeIter iter;
467 
468 	if (gtk_tree_selection_get_selected(dirSelection, NULL, &iter))
469 	{
470 		string dir = dirView.getString(&iter, "Path");
471 		if (dir != currentDir)
472 		{
473 			gtk_list_store_clear(fileStore);
474 			currentDir = dir;
475 			currentItems = 0;
476 			currentSize = 0;
477 
478 			typedef Func1<DownloadQueue, string> F1;
479 			F1 *func = new F1(this, &DownloadQueue::updateFileView_client, currentDir);
480 			WulforManager::get()->dispatchClientFunc(func);
481 		}
482 	}
483 }
484 
sendMessage_gui(string cid)485 void DownloadQueue::sendMessage_gui(string cid)
486 {
487 	if (!cid.empty())
488 		WulforManager::get()->getMainWindow()->addPrivateMessage_gui(cid);
489 }
490 
onDirButtonPressed_gui(GtkWidget * widget,GdkEventButton * event,gpointer data)491 gboolean DownloadQueue::onDirButtonPressed_gui(GtkWidget *widget, GdkEventButton *event, gpointer data)
492 {
493 	DownloadQueue *dq = (DownloadQueue *)data;
494 	dq->dirPrevious = event->type;
495 
496 	return FALSE;
497 }
498 
onDirButtonReleased_gui(GtkWidget * widget,GdkEventButton * event,gpointer data)499 gboolean DownloadQueue::onDirButtonReleased_gui(GtkWidget *widget, GdkEventButton *event, gpointer data)
500 {
501 	DownloadQueue *dq = (DownloadQueue *)data;
502 
503 	if (dq->dirPrevious == GDK_BUTTON_PRESS && gtk_tree_selection_get_selected(dq->dirSelection, NULL, NULL))
504 	{
505 		if (event->button == 1)
506 		{
507 			dq->updateFileView_gui();
508 		}
509 		else if (event->button == 3)
510 		{
511 			dq->updateFileView_gui();
512 			gtk_menu_popup(GTK_MENU(dq->getWidget("dirMenu")), NULL, NULL,
513 				NULL, NULL, 0, gtk_get_current_event_time());
514 		}
515 	}
516 
517 	return FALSE;
518 }
519 
onDirKeyReleased_gui(GtkWidget * widget,GdkEventKey * event,gpointer data)520 gboolean DownloadQueue::onDirKeyReleased_gui(GtkWidget *widget, GdkEventKey *event, gpointer data)
521 {
522 	DownloadQueue *dq = (DownloadQueue *)data;
523 	GtkTreeIter iter;
524 
525 	if (gtk_tree_selection_get_selected(dq->dirSelection, NULL, &iter))
526 	{
527 		if (event->keyval == GDK_Delete || event->keyval == GDK_BackSpace)
528 		{
529 			dq->onDirRemoveClicked_gui(NULL, data);
530 		}
531 		else if (event->keyval == GDK_Menu || (event->keyval == GDK_F10 && event->state & GDK_SHIFT_MASK))
532 		{
533 			gtk_menu_popup(GTK_MENU(dq->getWidget("dirMenu")), NULL, NULL,
534 				NULL, NULL, 0, gtk_get_current_event_time());
535 		}
536 		else if (event->keyval == GDK_Up || event->keyval == GDK_KP_Up ||
537 			event->keyval == GDK_Down || event->keyval == GDK_KP_Down)
538 		{
539 			dq->updateFileView_gui();
540 		}
541 		else if (event->keyval == GDK_Return || event->keyval == GDK_KP_Enter)
542 		{
543 			GtkTreePath *path = gtk_tree_model_get_path(GTK_TREE_MODEL(dq->dirStore), &iter);
544 			if (gtk_tree_view_row_expanded(dq->dirView.get(), path))
545 				gtk_tree_view_collapse_row(dq->dirView.get(), path);
546 			else
547 				gtk_tree_view_expand_row(dq->dirView.get(), path, FALSE);
548 			gtk_tree_path_free(path);
549 		}
550 	}
551 
552 	return FALSE;
553 }
554 
onFileButtonPressed_gui(GtkWidget * widget,GdkEventButton * event,gpointer data)555 gboolean DownloadQueue::onFileButtonPressed_gui(GtkWidget *widget, GdkEventButton *event, gpointer data)
556 {
557 	DownloadQueue *dq = (DownloadQueue *)data;
558 
559 	if (event->button == 3)
560 	{
561 		GtkTreePath *path;
562 		if (gtk_tree_view_get_path_at_pos(dq->fileView.get(), (gint)event->x, (gint)event->y, &path, NULL, NULL, NULL))
563 		{
564 			bool selected = gtk_tree_selection_path_is_selected(dq->fileSelection, path);
565 			gtk_tree_path_free(path);
566 
567 			if (selected)
568 				return TRUE;
569 		}
570 	}
571 	return FALSE;
572 }
573 
onFileButtonReleased_gui(GtkWidget * widget,GdkEventButton * event,gpointer data)574 gboolean DownloadQueue::onFileButtonReleased_gui(GtkWidget *widget, GdkEventButton *event, gpointer data)
575 {
576 	DownloadQueue *dq = (DownloadQueue *)data;
577 
578 	if (event->button == 3 && event->type == GDK_BUTTON_RELEASE)
579 	{
580 		if (gtk_tree_selection_count_selected_rows(dq->fileSelection) > 0)
581 		{
582 			dq->buildDynamicMenu_gui();
583 			gtk_menu_popup(GTK_MENU(dq->getWidget("fileMenu")), NULL, NULL,
584 				NULL, NULL, 0, gtk_get_current_event_time());
585 			return TRUE;
586 		}
587 	}
588 	return FALSE;
589 }
590 
onFileKeyReleased_gui(GtkWidget * widget,GdkEventKey * event,gpointer data)591 gboolean DownloadQueue::onFileKeyReleased_gui(GtkWidget *widget, GdkEventKey *event, gpointer data)
592 {
593 	DownloadQueue *dq = (DownloadQueue *)data;
594 	int count = gtk_tree_selection_count_selected_rows(dq->fileSelection);
595 
596 	if (count > 0)
597 	{
598 		if (event->keyval == GDK_Delete || event->keyval == GDK_BackSpace)
599 		{
600 			dq->onFileRemoveClicked_gui(NULL, data);
601 		}
602 		else if (event->keyval == GDK_Menu || (event->keyval == GDK_F10 && event->state & GDK_SHIFT_MASK))
603 		{
604 			dq->buildDynamicMenu_gui();
605 			gtk_menu_popup(GTK_MENU(dq->getWidget("fileMenu")), NULL, NULL,
606 				NULL, NULL, 0, gtk_get_current_event_time());
607 		}
608 	}
609 
610 	return FALSE;
611 }
612 
onDirPriorityClicked_gui(GtkMenuItem * item,gpointer data)613 void DownloadQueue::onDirPriorityClicked_gui(GtkMenuItem *item, gpointer data)
614 {
615 	DownloadQueue *dq = (DownloadQueue *)data;
616 	GtkTreeIter iter;
617 
618 	if (gtk_tree_selection_get_selected(dq->dirSelection, NULL, &iter))
619 	{
620 		string path = dq->dirView.getString(&iter, "Path");
621 		QueueItem::Priority priority;
622 
623 		if (item == GTK_MENU_ITEM(dq->getWidget("pausedPriorityItem")))
624 			priority = QueueItem::PAUSED;
625 		else if (item == GTK_MENU_ITEM(dq->getWidget("lowestPriorityItem")))
626 			priority = QueueItem::LOWEST;
627 		else if (item == GTK_MENU_ITEM(dq->getWidget("lowPrioritytem")))
628 			priority = QueueItem::LOW;
629 		else if (item == GTK_MENU_ITEM(dq->getWidget("highPriorityItem")))
630 			priority = QueueItem::HIGH;
631 		else if (item == GTK_MENU_ITEM(dq->getWidget("highestPriorityItem")))
632 			priority = QueueItem::HIGHEST;
633 		else
634 			priority = QueueItem::NORMAL;
635 
636 		typedef Func2<DownloadQueue, string, QueueItem::Priority> F2;
637 		F2 *func = new F2(dq, &DownloadQueue::setPriorityDir_client, path, priority);
638 		WulforManager::get()->dispatchClientFunc(func);
639 	}
640 }
641 
onDirMoveClicked_gui(GtkMenuItem * menuItem,gpointer data)642 void DownloadQueue::onDirMoveClicked_gui(GtkMenuItem *menuItem, gpointer data)
643 {
644 	DownloadQueue *dq = (DownloadQueue *)data;
645 	GtkTreeIter iter;
646 
647 	if (gtk_tree_selection_get_selected(dq->dirSelection, NULL, &iter))
648 	{
649 		string path = Text::fromUtf8(dq->dirView.getString(&iter, "Path"));
650 		GtkWidget *dialog = dq->getWidget("dirChooserDialog");
651 		gtk_file_chooser_set_action(GTK_FILE_CHOOSER(dialog), GTK_FILE_CHOOSER_ACTION_SELECT_FOLDER);
652 		gtk_file_chooser_set_current_folder(GTK_FILE_CHOOSER(dialog), path.c_str());
653 		int response = gtk_dialog_run(GTK_DIALOG(dialog));
654 		gtk_widget_hide(dialog);
655 
656 		if (response == GTK_RESPONSE_OK)
657 		{
658 			gchar *temp = gtk_file_chooser_get_current_folder(GTK_FILE_CHOOSER(dialog));
659 			if (temp)
660 			{
661 				string target = Text::toUtf8(temp);
662 				g_free(temp);
663 
664 				if (target[target.length() - 1] != PATH_SEPARATOR)
665 					target += PATH_SEPARATOR;
666 
667 				typedef Func2<DownloadQueue, string, string> F2;
668 				F2 *func = new F2(dq, &DownloadQueue::moveDir_client, path, target);
669 				WulforManager::get()->dispatchClientFunc(func);
670 			}
671 		}
672 	}
673 }
674 
onDirRemoveClicked_gui(GtkMenuItem * menuitem,gpointer data)675 void DownloadQueue::onDirRemoveClicked_gui(GtkMenuItem *menuitem, gpointer data)
676 {
677 	DownloadQueue *dq = (DownloadQueue *)data;
678 	GtkTreeIter iter;
679 
680 	if (gtk_tree_selection_get_selected(dq->dirSelection, NULL, &iter))
681 	{
682 		string path = dq->dirView.getString(&iter, "Path");
683 		gtk_list_store_clear(dq->fileStore);
684 
685 		typedef Func1<DownloadQueue, string> F1;
686 		F1 *func = new F1(dq, &DownloadQueue::removeDir_client, path);
687 		WulforManager::get()->dispatchClientFunc(func);
688 	}
689 }
690 
onFileSearchAlternatesClicked_gui(GtkMenuItem * item,gpointer data)691 void DownloadQueue::onFileSearchAlternatesClicked_gui(GtkMenuItem *item, gpointer data)
692 {
693 	DownloadQueue *dq = (DownloadQueue *)data;
694 	string tth;
695 	GtkTreePath *path;
696 	GtkTreeIter iter;
697 	Search *s;
698 	GList *list = gtk_tree_selection_get_selected_rows(dq->fileSelection, NULL);
699 
700 	for (GList *i = list; i; i = i->next)
701 	{
702 		path = (GtkTreePath *)i->data;
703 		if (gtk_tree_model_get_iter(GTK_TREE_MODEL(dq->fileStore), &iter, path))
704 		{
705 			tth = dq->fileView.getString(&iter, "TTH");
706 			if (!tth.empty())
707 			{
708 				s = WulforManager::get()->getMainWindow()->addSearch_gui();
709 				s->putValue_gui(tth, 0, SearchManager::SIZE_DONTCARE, SearchManager::TYPE_TTH);
710 			}
711 		}
712 		gtk_tree_path_free(path);
713 	}
714 	g_list_free(list);
715 }
716 
onCopyMagnetClicked_gui(GtkMenuItem * item,gpointer data)717 void DownloadQueue::onCopyMagnetClicked_gui(GtkMenuItem* item, gpointer data)
718 {
719 	DownloadQueue *dq = (DownloadQueue *)data;
720 	GtkTreePath *path;
721 	GtkTreeIter iter;
722 	string magnets, magnet, filename, tth;
723 	int64_t size;
724 	GList *list = gtk_tree_selection_get_selected_rows(dq->fileSelection, NULL);
725 
726 	for (GList *i = list; i; i = i->next)
727 	{
728 		path = (GtkTreePath *)i->data;
729 		if (gtk_tree_model_get_iter(GTK_TREE_MODEL(dq->fileStore), &iter, path))
730 		{
731 			filename = dq->fileView.getString(&iter, "Filename");
732 			size = dq->fileView.getValue<int64_t>(&iter, "Size Sort");
733 			tth = dq->fileView.getString(&iter, "TTH");
734 			magnet = WulforUtil::makeMagnet(filename, size, tth);
735 
736 			if (!magnet.empty())
737 			{
738 				if (!magnets.empty())
739 					magnets += '\n';
740 				magnets += magnet;
741 			}
742 		}
743 		gtk_tree_path_free(path);
744 	}
745 	g_list_free(list);
746 
747 	if (!magnets.empty())
748 		gtk_clipboard_set_text(gtk_clipboard_get(GDK_SELECTION_CLIPBOARD), magnets.c_str(), magnets.length());
749 }
750 
onFileMoveClicked_gui(GtkMenuItem * menuItem,gpointer data)751 void DownloadQueue::onFileMoveClicked_gui(GtkMenuItem *menuItem, gpointer data)
752 {
753 	DownloadQueue *dq = (DownloadQueue *)data;
754 	typedef Func2<DownloadQueue, string, string> F2;
755 	F2 *func;
756 	string source;
757 	GtkTreePath *path;
758 	GtkTreeIter iter;
759 	int count = gtk_tree_selection_count_selected_rows(dq->fileSelection);
760 	GList *list = gtk_tree_selection_get_selected_rows(dq->fileSelection, NULL);
761 	GtkWidget *dialog = dq->getWidget("dirChooserDialog");
762 
763 	if (gtk_tree_selection_get_selected(dq->dirSelection, NULL, &iter))
764 	{
765 		string filepath = Text::fromUtf8(dq->dirView.getString(&iter, "Path"));
766 		gtk_file_chooser_set_current_folder(GTK_FILE_CHOOSER(dialog), filepath.c_str());
767 	}
768 
769 	if (count == 1)
770 	{
771 		path = (GtkTreePath *)list->data;
772 		if (gtk_tree_model_get_iter(GTK_TREE_MODEL(dq->fileStore), &iter, path))
773 		{
774 			string target = Text::fromUtf8(dq->fileView.getString(&iter, "Filename"));
775 			gtk_file_chooser_set_action(GTK_FILE_CHOOSER(dialog), GTK_FILE_CHOOSER_ACTION_SAVE);
776 			gtk_file_chooser_set_current_name(GTK_FILE_CHOOSER(dialog), target.c_str());
777 			int response = gtk_dialog_run(GTK_DIALOG(dialog));
778 			gtk_widget_hide(dialog);
779 
780 			if (response == GTK_RESPONSE_OK)
781 			{
782 				gchar *tmp = gtk_file_chooser_get_filename(GTK_FILE_CHOOSER(dialog));
783 				if (tmp)
784 				{
785 					target = Text::toUtf8(tmp);
786 					g_free(tmp);
787 					source = dq->fileView.getString(&iter, "Target");
788 					func = new F2(dq, &DownloadQueue::move_client, source, target);
789 					WulforManager::get()->dispatchClientFunc(func);
790 				}
791 			}
792 		}
793 		gtk_tree_path_free(path);
794 	}
795 	else if (count > 1)
796 	{
797 		gtk_file_chooser_set_action(GTK_FILE_CHOOSER(dialog), GTK_FILE_CHOOSER_ACTION_SELECT_FOLDER);
798 		int response = gtk_dialog_run(GTK_DIALOG(dialog));
799 		gtk_widget_hide(dialog);
800 
801 		if (response == GTK_RESPONSE_OK)
802 		{
803 			gchar *tmp = gtk_file_chooser_get_current_folder(GTK_FILE_CHOOSER(dialog));
804 			if (tmp)
805 			{
806 				string filename;
807 				string target = Text::toUtf8(tmp);
808 				g_free(tmp);
809 
810 				if (target[target.length() - 1] != PATH_SEPARATOR)
811 					target += PATH_SEPARATOR;
812 
813 				for (GList *i = list; i; i = i->next)
814 				{
815 					path = (GtkTreePath *)i->data;
816 					if (gtk_tree_model_get_iter(GTK_TREE_MODEL(dq->fileStore), &iter, path))
817 					{
818 						source = dq->fileView.getString(&iter, "Target");
819 						filename = dq->fileView.getString(&iter, "Filename");
820 						func = new F2(dq, &DownloadQueue::move_client, source, target + filename);
821 						WulforManager::get()->dispatchClientFunc(func);
822 					}
823 					gtk_tree_path_free(path);
824 				}
825 			}
826 		}
827 	}
828 	g_list_free(list);
829 }
830 
onFilePriorityClicked_gui(GtkMenuItem * item,gpointer data)831 void DownloadQueue::onFilePriorityClicked_gui(GtkMenuItem *item, gpointer data)
832 {
833 	DownloadQueue *dq = (DownloadQueue *)data;
834 	typedef Func2<DownloadQueue, string, QueueItem::Priority> F2;
835 	F2 *func;
836 	string target;
837 	GtkTreePath *path;
838 	GtkTreeIter iter;
839 	QueueItem::Priority priority;
840 	GList *list = gtk_tree_selection_get_selected_rows(dq->fileSelection, NULL);
841 
842 	for (GList *i = list; i; i = i->next)
843 	{
844 		path = (GtkTreePath *)i->data;
845 		if (gtk_tree_model_get_iter(GTK_TREE_MODEL(dq->fileStore), &iter, path))
846 		{
847 			target = dq->fileView.getString(&iter, "Target");
848 
849 			if (item == GTK_MENU_ITEM(dq->getWidget("filePausedItem")))
850 				priority = QueueItem::PAUSED;
851 			else if (item == GTK_MENU_ITEM(dq->getWidget("fileLowestPriorityItem")))
852 				priority = QueueItem::LOWEST;
853 			else if (item == GTK_MENU_ITEM(dq->getWidget("fileLowPriorityItem")))
854 				priority = QueueItem::LOW;
855 			else if (item == GTK_MENU_ITEM(dq->getWidget("fileHighPriorityItem")))
856 				priority = QueueItem::HIGH;
857 			else if (item == GTK_MENU_ITEM(dq->getWidget("fileHighestPriorityItem")))
858 				priority = QueueItem::HIGHEST;
859 			else
860 				priority = QueueItem::NORMAL;
861 
862 			func = new F2(dq, &DownloadQueue::setPriority_client, target, priority);
863 			WulforManager::get()->dispatchClientFunc(func);
864 		}
865 		gtk_tree_path_free(path);
866 	}
867 	g_list_free(list);
868 }
869 
onFileGetListClicked_gui(GtkMenuItem * item,gpointer data)870 void DownloadQueue::onFileGetListClicked_gui(GtkMenuItem *item, gpointer data)
871 {
872 	DownloadQueue *dq = (DownloadQueue *)data;
873 	typedef Func2<DownloadQueue, string, string> F2;
874 	F2 *func;
875 	string nick, target;
876 	GtkTreePath *path;
877 	GtkTreeIter iter;
878 	GList *list = gtk_tree_selection_get_selected_rows(dq->fileSelection, NULL);
879 
880 	for (GList *i = list; i; i = i->next)
881 	{
882 		path = (GtkTreePath *)i->data;
883 		if (gtk_tree_model_get_iter(GTK_TREE_MODEL(dq->fileStore), &iter, path))
884 		{
885 			target = dq->fileView.getString(&iter, "Target");
886 			nick = WulforUtil::getTextFromMenu(item);
887 
888 			func = new F2(dq, &DownloadQueue::addList_client, target, nick);
889 			WulforManager::get()->dispatchClientFunc(func);
890 		}
891 		gtk_tree_path_free(path);
892 	}
893 	g_list_free(list);
894 }
895 
onFileSendPMClicked_gui(GtkMenuItem * item,gpointer data)896 void DownloadQueue::onFileSendPMClicked_gui(GtkMenuItem *item, gpointer data)
897 {
898 	DownloadQueue *dq = (DownloadQueue *)data;
899 	typedef Func2<DownloadQueue, string, string> F2;
900 	F2 *func;
901 	string nick, target;
902 	GtkTreePath *path;
903 	GtkTreeIter iter;
904 	GList *list = gtk_tree_selection_get_selected_rows(dq->fileSelection, NULL);
905 
906 	for (GList *i = list; i; i = i->next)
907 	{
908 		path = (GtkTreePath *)i->data;
909 		if (gtk_tree_model_get_iter(GTK_TREE_MODEL(dq->fileStore), &iter, path))
910 		{
911 			target = dq->fileView.getString(&iter, "Target");
912 			nick = WulforUtil::getTextFromMenu(item);
913 
914 			func = new F2(dq, &DownloadQueue::sendMessage_client, target, nick);
915 			WulforManager::get()->dispatchClientFunc(func);
916 		}
917 		gtk_tree_path_free(path);
918 	}
919 	g_list_free(list);
920 }
921 
onFileReAddSourceClicked_gui(GtkMenuItem * item,gpointer data)922 void DownloadQueue::onFileReAddSourceClicked_gui(GtkMenuItem *item, gpointer data)
923 {
924 	DownloadQueue *dq = (DownloadQueue *)data;
925 	typedef Func2<DownloadQueue, string, string> F2;
926 	F2 *func;
927 	string nick, target;
928 	GtkTreePath *path;
929 	GtkTreeIter iter;
930 	GList *list = gtk_tree_selection_get_selected_rows(dq->fileSelection, NULL);
931 
932 	for (GList *i = list; i; i = i->next)
933 	{
934 		path = (GtkTreePath *)i->data;
935 		if (gtk_tree_model_get_iter(GTK_TREE_MODEL(dq->fileStore), &iter, path))
936 		{
937 			target = dq->fileView.getString(&iter, "Target");
938 			nick = WulforUtil::getTextFromMenu(item);
939 
940 			func = new F2(dq, &DownloadQueue::reAddSource_client, target, nick);
941 			WulforManager::get()->dispatchClientFunc(func);
942 		}
943 		gtk_tree_path_free(path);
944 	}
945 	g_list_free(list);
946 }
947 
onFileRemoveSourceClicked_gui(GtkMenuItem * item,gpointer data)948 void DownloadQueue::onFileRemoveSourceClicked_gui(GtkMenuItem *item, gpointer data)
949 {
950 	DownloadQueue *dq = (DownloadQueue *)data;
951 	typedef Func2<DownloadQueue, string, string> F2;
952 	F2 *func;
953 	string nick, target;
954 	GtkTreePath *path;
955 	GtkTreeIter iter;
956 	GList *list = gtk_tree_selection_get_selected_rows(dq->fileSelection, NULL);
957 
958 	for (GList *i = list; i; i = i->next)
959 	{
960 		path = (GtkTreePath *)i->data;
961 		if (gtk_tree_model_get_iter(GTK_TREE_MODEL(dq->fileStore), &iter, path))
962 		{
963 			target = dq->fileView.getString(&iter, "Target");
964 			nick = WulforUtil::getTextFromMenu(item);
965 
966 			func = new F2(dq, &DownloadQueue::removeSource_client, target, nick);
967 			WulforManager::get()->dispatchClientFunc(func);
968 		}
969 		gtk_tree_path_free(path);
970 	}
971 	g_list_free(list);
972 }
973 
onFileRemoveUserFromQueueClicked_gui(GtkMenuItem * item,gpointer data)974 void DownloadQueue::onFileRemoveUserFromQueueClicked_gui(GtkMenuItem *item, gpointer data)
975 {
976 	DownloadQueue *dq = (DownloadQueue *)data;
977 	typedef Func2<DownloadQueue, string, string> F2;
978 	F2 *func;
979 	string nick, target;
980 	GtkTreePath *path;
981 	GtkTreeIter iter;
982 	GList *list = gtk_tree_selection_get_selected_rows(dq->fileSelection, NULL);
983 
984 	for (GList *i = list; i; i = i->next)
985 	{
986 		path = (GtkTreePath *)i->data;
987 		if (gtk_tree_model_get_iter(GTK_TREE_MODEL(dq->fileStore), &iter, path))
988 		{
989 			target = dq->fileView.getString(&iter, "Target");
990 			nick = WulforUtil::getTextFromMenu(item);
991 
992 			func = new F2(dq, &DownloadQueue::removeSources_client, target, nick);
993 			WulforManager::get()->dispatchClientFunc(func);
994 		}
995 		gtk_tree_path_free(path);
996 	}
997 	g_list_free(list);
998 }
999 
onFileRemoveClicked_gui(GtkMenuItem * menuitem,gpointer data)1000 void DownloadQueue::onFileRemoveClicked_gui(GtkMenuItem *menuitem, gpointer data)
1001 {
1002 	DownloadQueue *dq = (DownloadQueue *)data;
1003 	typedef Func1<DownloadQueue, string> F1;
1004 	F1 *func;
1005 	string target;
1006 	GtkTreePath *path;
1007 	GtkTreeIter iter;
1008 	GList *list = gtk_tree_selection_get_selected_rows(dq->fileSelection, NULL);
1009 
1010 	for (GList *i = list; i; i = i->next)
1011 	{
1012 		path = (GtkTreePath *)i->data;
1013 		if (gtk_tree_model_get_iter(GTK_TREE_MODEL(dq->fileStore), &iter, path))
1014 		{
1015 			target = dq->fileView.getString(&iter, "Target");
1016 			func = new F1(dq, &DownloadQueue::remove_client, target);
1017 			WulforManager::get()->dispatchClientFunc(func);
1018 		}
1019 		gtk_tree_path_free(path);
1020 	}
1021 	g_list_free(list);
1022 }
1023 
buildList_client()1024 void DownloadQueue::buildList_client()
1025 {
1026 	StringMap params;
1027 	typedef Func2<DownloadQueue, StringMap, bool> F2;
1028 	//F2 *func;
1029 	const QueueItem::StringMap &ll = QueueManager::getInstance()->lockQueue();
1030 
1031 	for (QueueItem::StringMap::const_iterator it = ll.begin(); it != ll.end(); ++it)
1032 	{
1033 		params["Size Sort"] = Util::toString(it->second->getSize());
1034 		params["Path"] = Util::getFilePath(*it->first);
1035 
1036 		addFile_gui(params, TRUE);
1037 		//func = new F2(this, &DownloadQueue::addFile_gui, params, TRUE);
1038 		//WulforManager::get()->dispatchGuiFunc(func);
1039 	}
1040 
1041 	QueueManager::getInstance()->unlockQueue();
1042 }
1043 
move_client(string source,string target)1044 void DownloadQueue::move_client(string source, string target)
1045 {
1046 	if (!source.empty() && !target.empty())
1047 		QueueManager::getInstance()->move(source, target);
1048 }
1049 
moveDir_client(string source,string target)1050 void DownloadQueue::moveDir_client(string source, string target)
1051 {
1052 	if (!source.empty() && !target.empty() && target[target.length() - 1] == PATH_SEPARATOR)
1053 	{
1054 		// Can't modify QueueItem::StringMap in the loop, so we have to queue them.
1055 		vector<string> targets;
1056 		string *file;
1057 		const QueueItem::StringMap &ll = QueueManager::getInstance()->lockQueue();
1058 
1059 		for (QueueItem::StringMap::const_iterator it = ll.begin(); it != ll.end(); ++it)
1060 		{
1061 			file = it->first;
1062 			if (file->length() >= source.length() && file->substr(0, source.length()) == source)
1063 				targets.push_back(*file);
1064 		}
1065 		QueueManager::getInstance()->unlockQueue();
1066 
1067 		for (vector<string>::const_iterator it = targets.begin(); it != targets.end(); ++it)
1068 			QueueManager::getInstance()->move(*it, target + it->substr(source.length()));
1069 	}
1070 }
1071 
setPriority_client(string target,QueueItem::Priority p)1072 void DownloadQueue::setPriority_client(string target, QueueItem::Priority p)
1073 {
1074 	if (!target.empty())
1075 		QueueManager::getInstance()->setPriority(target, p);
1076 }
1077 
setPriorityDir_client(string path,QueueItem::Priority p)1078 void DownloadQueue::setPriorityDir_client(string path, QueueItem::Priority p)
1079 {
1080 	if (!path.empty() && path[path.length() - 1] == PATH_SEPARATOR)
1081 	{
1082 		string *file;
1083 		const QueueItem::StringMap &ll = QueueManager::getInstance()->lockQueue();
1084 
1085 		for (QueueItem::StringMap::const_iterator it = ll.begin(); it != ll.end(); ++it)
1086 		{
1087 			file = it->first;
1088 			if (file->length() >= path.length() && file->substr(0, path.length()) == path)
1089 				QueueManager::getInstance()->setPriority(*file, p);
1090 		}
1091 		QueueManager::getInstance()->unlockQueue();
1092 	}
1093 }
1094 
addList_client(string target,string nick)1095 void DownloadQueue::addList_client(string target, string nick)
1096 {
1097 	try
1098 	{
1099 		if (!target.empty() && !nick.empty() && sources.find(target) != sources.end())
1100 		{
1101 			SourceIter it = sources[target].find(nick);
1102 			if (it != sources[target].end())
1103 			{
1104 				UserPtr user = ClientManager::getInstance()->findUser(CID(it->second));
1105 				if (user)
1106 					QueueManager::getInstance()->addList(user, "", QueueItem::FLAG_CLIENT_VIEW);
1107 			}
1108 		}
1109 	}
1110 	catch (const Exception &e)
1111 	{
1112 		typedef Func2<DownloadQueue, string, string> F2;
1113 		F2 *func = new F2(this, &DownloadQueue::setStatus_gui, e.getError(), "statusMain");
1114 		WulforManager::get()->dispatchGuiFunc(func);
1115 	}
1116 }
1117 
sendMessage_client(string target,string nick)1118 void DownloadQueue::sendMessage_client(string target, string nick)
1119 {
1120 	if (!target.empty() && !nick.empty() && sources.find(target) != sources.end())
1121 	{
1122 		SourceIter it = sources[target].find(nick);
1123 		if (it != sources[target].end())
1124 		{
1125 			typedef Func1<DownloadQueue, string> F1;
1126 			F1 *func = new F1(this, &DownloadQueue::sendMessage_gui, it->second);
1127 			WulforManager::get()->dispatchGuiFunc(func);
1128 		}
1129 	}
1130 }
1131 
reAddSource_client(string target,string nick)1132 void DownloadQueue::reAddSource_client(string target, string nick)
1133 {
1134 	try
1135 	{
1136 		if (!target.empty() && !nick.empty() && badSources.find(target) != sources.end())
1137 		{
1138 			SourceIter it = badSources[target].find(nick);
1139 			if (it != badSources[target].end())
1140 			{
1141 				UserPtr user = ClientManager::getInstance()->findUser(CID(it->second));
1142 				if (user)
1143 					QueueManager::getInstance()->readd(target, user, "");
1144 			}
1145 		}
1146 	}
1147 	catch (const Exception &e)
1148 	{
1149 		typedef Func2<DownloadQueue, string, string> F2;
1150 		F2 *func = new F2(this, &DownloadQueue::setStatus_gui, e.getError(), "statusMain");
1151 		WulforManager::get()->dispatchGuiFunc(func);
1152 	}
1153 }
1154 
removeSource_client(string target,string nick)1155 void DownloadQueue::removeSource_client(string target, string nick)
1156 {
1157 	if (!target.empty() && !nick.empty() && sources.find(target) != sources.end())
1158 	{
1159 		SourceIter it = sources[target].find(nick);
1160 		if (it != sources[target].end())
1161 		{
1162 			UserPtr user = ClientManager::getInstance()->findUser(CID(it->second));
1163 			if (user)
1164 				QueueManager::getInstance()->removeSource(target, user, QueueItem::Source::FLAG_REMOVED);
1165 		}
1166 	}
1167 }
1168 
removeSources_client(string target,string nick)1169 void DownloadQueue::removeSources_client(string target, string nick)
1170 {
1171 	if (!target.empty() && !nick.empty() && sources.find(target) != sources.end())
1172 	{
1173 		SourceIter it = sources[target].find(nick);
1174 		if (it != sources[target].end())
1175 		{
1176 			UserPtr user = ClientManager::getInstance()->findUser(CID(it->second));
1177 			if (user)
1178 				QueueManager::getInstance()->removeSource(user, QueueItem::Source::FLAG_REMOVED);
1179 		}
1180 	}
1181 }
1182 
remove_client(string target)1183 void DownloadQueue::remove_client(string target)
1184 {
1185 	if (!target.empty())
1186 		QueueManager::getInstance()->remove(target);
1187 }
1188 
removeDir_client(string path)1189 void DownloadQueue::removeDir_client(string path)
1190 {
1191 	if (!path.empty())
1192 	{
1193 		string *file;
1194 		vector<string> targets;
1195 		const QueueItem::StringMap &ll = QueueManager::getInstance()->lockQueue();
1196 
1197 		for (QueueItem::StringMap::const_iterator it = ll.begin(); it != ll.end(); ++it)
1198 		{
1199 			file = it->first;
1200 			if (file->length() >= path.length() && file->substr(0, path.length()) == path)
1201 				targets.push_back(*file);
1202 		}
1203 		QueueManager::getInstance()->unlockQueue();
1204 
1205 		for (vector<string>::const_iterator it = targets.begin(); it != targets.end(); ++it)
1206 			QueueManager::getInstance()->remove(*it);
1207 	}
1208 }
1209 
updateFileView_client(string path)1210 void DownloadQueue::updateFileView_client(string path)
1211 {
1212 	if (!path.empty())
1213 	{
1214 		vector<StringMap> files;
1215 		const QueueItem::StringMap &ll = QueueManager::getInstance()->lockQueue();
1216 
1217 		for (QueueItem::StringMap::const_iterator it = ll.begin(); it != ll.end(); ++it)
1218 		{
1219 			if (it->first->length() >= path.length() && it->first->substr(0, it->first->rfind('/') + 1) == path)
1220 			{
1221 				StringMap params;
1222 				getQueueParams_client(it->second, params);
1223 				files.push_back(params);
1224 			}
1225 		}
1226 		QueueManager::getInstance()->unlockQueue();
1227 
1228 		// Updating gui is smoother if we do it in large chunks.
1229 		typedef Func2<DownloadQueue, vector<StringMap>, bool> F2;
1230 		F2 *func = new F2(this, &DownloadQueue::addFiles_gui, files, TRUE);
1231 		WulforManager::get()->dispatchGuiFunc(func);
1232 	}
1233 }
1234 
getQueueParams_client(QueueItem * item,StringMap & params)1235 void DownloadQueue::getQueueParams_client(QueueItem *item, StringMap &params)
1236 {
1237 	string nick;
1238 	map<string, string> source;
1239 	int online = 0;
1240 	int totalSources = item->getSources().size();
1241 
1242 	params["Filename"] = item->getTargetFileName();
1243 	params["Path"] = Util::getFilePath(item->getTarget());
1244 	params["Target"] = item->getTarget();
1245 
1246 	params["Users"] = "";
1247 	for (QueueItem::SourceConstIter it = item->getSources().begin(); it != item->getSources().end(); ++it)
1248 	{
1249 		if (it->getUser()->isOnline())
1250 			++online;
1251 
1252 		if (params["Users"].size() > 0)
1253 			params["Users"] += ", ";
1254 
1255 		nick = WulforUtil::getNicks(it->getUser());
1256 		source[nick] = it->getUser()->getCID().toBase32();
1257 		params["Users"] += nick;
1258 	}
1259 	if (params["Users"].empty())
1260 		params["Users"] = _("No users");
1261 	sources[item->getTarget()] = source;
1262 
1263 	// Status
1264 	if (item->isWaiting())
1265 		params["Status"] = P_("%1% of %2% user online", "%1% of %2% users online", % online % totalSources, totalSources);
1266 	else
1267 		params["Status"] = _("Running...");
1268 
1269 	// Size
1270 	params["Size Sort"] = Util::toString(item->getSize());
1271 	if (item->getSize() < 0)
1272 	{
1273 		params["Size"] = _("Unknown");
1274 		params["Exact Size"] = _("Unknown");
1275 	}
1276 	else
1277 	{
1278 		params["Size"] = Util::formatBytes(item->getSize());
1279 		params["Exact Size"] = Util::formatExactSize(item->getSize());
1280 	}
1281 
1282 	// Downloaded
1283 	params["Downloaded Sort"] = Util::toString(item->getDownloadedBytes());
1284 	if (item->getSize() > 0)
1285 	{
1286 		double percent = (double)item->getDownloadedBytes() * 100.0 / (double)item->getSize();
1287 		params["Downloaded"] = Util::formatBytes(item->getDownloadedBytes()) + " (" + Util::toString(percent) + "%)";
1288 	}
1289 	else
1290 	{
1291 		params["Downloaded"] = "0 B (0.00%)";
1292 	}
1293 
1294 	// Priority
1295 	switch (item->getPriority())
1296 	{
1297 		case QueueItem::PAUSED:
1298 			params["Priority"] = C_("Priority", "Paused");
1299 			break;
1300 		case QueueItem::LOWEST:
1301 			params["Priority"] = C_("Priority", "Lowest");
1302 			break;
1303 		case QueueItem::LOW:
1304 			params["Priority"] = C_("Priority", "Low");
1305 			break;
1306 		case QueueItem::HIGH:
1307 			params["Priority"] = C_("Priority", "High");
1308 			break;
1309 		case QueueItem::HIGHEST:
1310 			params["Priority"] = C_("Priority", "Highest");
1311 			break;
1312 		default:
1313 			params["Priority"] = C_("Priority", "Normal");
1314 	}
1315 
1316 	// Error
1317 	source.clear();
1318 	params["Errors"] = "";
1319 	for (QueueItem::SourceConstIter it = item->getBadSources().begin(); it != item->getBadSources().end(); ++it)
1320 	{
1321 		nick = WulforUtil::getNicks(it->getUser());
1322 		source[nick] = it->getUser()->getCID().toBase32();
1323 
1324 		if (!it->isSet(QueueItem::Source::FLAG_REMOVED))
1325 		{
1326 			if (params["Errors"].size() > 0)
1327 				params["Errors"] += ", ";
1328 			params["Errors"] += nick + " (";
1329 
1330 			if (it->isSet(QueueItem::Source::FLAG_FILE_NOT_AVAILABLE))
1331 				params["Errors"] += _("File not available");
1332 			else if (it->isSet(QueueItem::Source::FLAG_PASSIVE))
1333 				params["Errors"] += _("Passive user");
1334 			else if (it->isSet(QueueItem::Source::FLAG_CRC_FAILED))
1335 				params["Errors"] += _("CRC32 inconsistency (SFV-Check)");
1336 			else if (it->isSet(QueueItem::Source::FLAG_BAD_TREE))
1337 				params["Errors"] += _("Full tree does not match TTH root");
1338 			else if (it->isSet(QueueItem::Source::FLAG_SLOW_SOURCE))
1339 				params["Errors"] += _("Source too slow");
1340 			else if (it->isSet(QueueItem::Source::FLAG_NO_TTHF))
1341 				params["Errors"] += _("Remote client does not fully support TTH - cannot download");
1342 
1343 			params["Errors"] += ")";
1344 		}
1345 	}
1346 	if (params["Errors"].empty())
1347 		params["Errors"] = _("No errors");
1348 	badSources[item->getTarget()] = source;
1349 
1350 	// Added
1351 	params["Added"] = Util::formatTime("%Y-%m-%d %H:%M", item->getAdded());
1352 
1353 	// TTH
1354 	params["TTH"] = item->getTTH().toBase32();
1355 }
1356 
on(QueueManagerListener::Added,QueueItem * item)1357 void DownloadQueue::on(QueueManagerListener::Added, QueueItem *item) throw()
1358 {
1359 	StringMap params;
1360 	getQueueParams_client(item, params);
1361 
1362 	typedef Func2<DownloadQueue, StringMap, bool> F2;
1363 	F2 *func = new F2(this, &DownloadQueue::addFile_gui, params, TRUE);
1364 	WulforManager::get()->dispatchGuiFunc(func);
1365 }
1366 
on(QueueManagerListener::Moved,QueueItem * item,const string & oldTarget)1367 void DownloadQueue::on(QueueManagerListener::Moved, QueueItem *item, const string &oldTarget) throw()
1368 {
1369 	// Remove the old file
1370 	typedef Func2<DownloadQueue, string, int64_t> F2a;
1371 	F2a *func1 = new F2a(this, &DownloadQueue::removeFile_gui, oldTarget, item->getSize());
1372 	WulforManager::get()->dispatchGuiFunc(func1);
1373 
1374 	// Add the new file
1375 	StringMap params;
1376 	getQueueParams_client(item, params);
1377 
1378 	typedef Func2<DownloadQueue, StringMap, bool> F2b;
1379 	F2b *func2 = new F2b(this, &DownloadQueue::addFile_gui, params, TRUE);
1380 	WulforManager::get()->dispatchGuiFunc(func2);
1381 }
1382 
on(QueueManagerListener::Removed,QueueItem * item)1383 void DownloadQueue::on(QueueManagerListener::Removed, QueueItem *item) throw()
1384 {
1385 	typedef Func2<DownloadQueue, string, int64_t> F2;
1386 	F2 *func = new F2(this, &DownloadQueue::removeFile_gui, item->getTarget(), item->getSize());
1387 	WulforManager::get()->dispatchGuiFunc(func);
1388 }
1389 
on(QueueManagerListener::SourcesUpdated,QueueItem * item)1390 void DownloadQueue::on(QueueManagerListener::SourcesUpdated, QueueItem *item) throw()
1391 {
1392 	StringMap params;
1393 	getQueueParams_client(item, params);
1394 
1395 	typedef Func1<DownloadQueue, StringMap> F1;
1396 	F1 *func = new F1(this, &DownloadQueue::updateFile_gui, params);
1397 	WulforManager::get()->dispatchGuiFunc(func);
1398 }
1399 
on(QueueManagerListener::StatusUpdated,QueueItem * item)1400 void DownloadQueue::on(QueueManagerListener::StatusUpdated, QueueItem *item) throw()
1401 {
1402 	StringMap params;
1403 	getQueueParams_client(item, params);
1404 
1405 	typedef Func1<DownloadQueue, StringMap> F1;
1406 	F1 *func = new F1(this, &DownloadQueue::updateFile_gui, params);
1407 	WulforManager::get()->dispatchGuiFunc(func);
1408 }
1409