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