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 "search.hh"
23
24 #include <dcpp/FavoriteManager.h>
25 #include <dcpp/QueueManager.h>
26 #include <dcpp/ShareManager.h>
27 #include <dcpp/StringTokenizer.h>
28 #include <dcpp/Text.h>
29 #include <dcpp/UserCommand.h>
30 #include "UserCommandMenu.hh"
31 #include "wulformanager.hh"
32 #include "WulforUtil.hh"
33
34 using namespace std;
35 using namespace dcpp;
36
37 GtkTreeModel* Search::searchEntriesModel = NULL;
38
Search()39 Search::Search():
40 BookEntry(Entry::SEARCH, _("Search"), "search.glade", generateID()),
41 droppedResult(0),
42 searchHits(0),
43 isHash(false),
44 onlyFree(BOOLSETTING(SEARCH_ONLY_FREE_SLOTS)),
45 previousGrouping(NOGROUPING)
46 {
47 // Initialize the search entries combo box
48 if (searchEntriesModel == NULL)
49 searchEntriesModel = gtk_combo_box_get_model(GTK_COMBO_BOX(getWidget("comboboxentrySearch")));
50 gtk_combo_box_set_model(GTK_COMBO_BOX(getWidget("comboboxentrySearch")), searchEntriesModel);
51 searchEntry = gtk_bin_get_child(GTK_BIN(getWidget("comboboxentrySearch")));
52 gtk_widget_grab_focus(getWidget("comboboxentrySearch"));
53
54 // Configure the dialog
55 File::ensureDirectory(SETTING(DOWNLOAD_DIRECTORY));
56 gtk_file_chooser_set_current_folder(GTK_FILE_CHOOSER(getWidget("dirChooserDialog")), Text::fromUtf8(SETTING(DOWNLOAD_DIRECTORY)).c_str());
57 gtk_dialog_set_alternative_button_order(GTK_DIALOG(getWidget("dirChooserDialog")), GTK_RESPONSE_OK, GTK_RESPONSE_CANCEL, -1);
58
59 // Initialize check button options.
60 gtk_toggle_button_set_active(GTK_TOGGLE_BUTTON(getWidget("checkbuttonSlots")), onlyFree);
61 gtk_widget_set_sensitive(GTK_WIDGET(getWidget("checkbuttonSlots")), FALSE);
62 gtk_widget_set_sensitive(GTK_WIDGET(getWidget("checkbuttonShared")), FALSE);
63
64 gtk_combo_box_set_active(GTK_COMBO_BOX(getWidget("comboboxSize")), 1);
65 gtk_combo_box_set_active(GTK_COMBO_BOX(getWidget("comboboxUnit")), 2);
66 gtk_combo_box_set_active(GTK_COMBO_BOX(getWidget("comboboxFile")), 0);
67 gtk_combo_box_set_active(GTK_COMBO_BOX(getWidget("comboboxGroupBy")), (int)NOGROUPING);
68
69 // Initialize hub list treeview
70 hubView.setView(GTK_TREE_VIEW(getWidget("treeviewHubs")));
71 hubView.insertColumn("Search", G_TYPE_BOOLEAN, TreeView::BOOL, -1);
72 hubView.insertColumn("Name", G_TYPE_STRING, TreeView::STRING, -1);
73 hubView.insertHiddenColumn("Url", G_TYPE_STRING);
74 hubView.finalize();
75 hubStore = gtk_list_store_newv(hubView.getColCount(), hubView.getGTypes());
76 gtk_tree_view_set_model(hubView.get(), GTK_TREE_MODEL(hubStore));
77 g_object_unref(hubStore);
78 GtkTreeViewColumn *col = gtk_tree_view_get_column(hubView.get(), hubView.col("Search"));
79 GList *list = gtk_tree_view_column_get_cell_renderers(col);
80 GtkCellRenderer *renderer = (GtkCellRenderer *)g_list_nth_data(list, 0);
81 g_list_free(list);
82
83 // Initialize search result treeview
84 resultView.setView(GTK_TREE_VIEW(getWidget("treeviewResult")), TRUE, "search");
85 resultView.insertColumn(N_("Filename"), G_TYPE_STRING, TreeView::ICON_STRING, 250, "Icon");
86 resultView.insertColumn(N_("User"), G_TYPE_STRING, TreeView::STRING, 100);
87 resultView.insertColumn(N_("Type"), G_TYPE_STRING, TreeView::STRING, 65);
88 resultView.insertColumn(N_("Size"), G_TYPE_STRING, TreeView::STRING, 90);
89 resultView.insertColumn(N_("Path"), G_TYPE_STRING, TreeView::STRING, 100);
90 resultView.insertColumn(N_("Slots"), G_TYPE_STRING, TreeView::STRING, 70);
91 resultView.insertColumn(N_("Connection"), G_TYPE_STRING, TreeView::STRING, 100);
92 resultView.insertColumn(N_("Hub"), G_TYPE_STRING, TreeView::STRING, 150);
93 resultView.insertColumn(N_("Exact Size"), G_TYPE_STRING, TreeView::STRING, 100);
94 resultView.insertColumn(N_("IP"), G_TYPE_STRING, TreeView::STRING, 100);
95 resultView.insertColumn(N_("TTH"), G_TYPE_STRING, TreeView::STRING, 125);
96 resultView.insertHiddenColumn("Icon", G_TYPE_STRING);
97 resultView.insertHiddenColumn("Real Size", G_TYPE_INT64);
98 resultView.insertHiddenColumn("Slots Order", G_TYPE_INT);
99 resultView.insertHiddenColumn("File Order", G_TYPE_STRING);
100 resultView.insertHiddenColumn("Hub URL", G_TYPE_STRING);
101 resultView.insertHiddenColumn("CID", G_TYPE_STRING);
102 resultView.insertHiddenColumn("Shared", G_TYPE_BOOLEAN);
103 resultView.insertHiddenColumn("Free Slots", G_TYPE_INT);
104 resultView.finalize();
105 resultStore = gtk_tree_store_newv(resultView.getColCount(), resultView.getGTypes());
106 searchFilterModel = gtk_tree_model_filter_new(GTK_TREE_MODEL(resultStore), NULL);
107 gtk_tree_model_filter_set_visible_func(GTK_TREE_MODEL_FILTER(searchFilterModel), &Search::searchFilterFunc_gui, (gpointer)this, NULL);
108 sortedFilterModel = gtk_tree_model_sort_new_with_model(searchFilterModel);
109 gtk_tree_view_set_model(resultView.get(), sortedFilterModel);
110 g_object_unref(resultStore);
111 g_object_unref(searchFilterModel);
112 g_object_unref(sortedFilterModel);
113 selection = gtk_tree_view_get_selection(resultView.get());
114 gtk_tree_selection_set_mode(selection, GTK_SELECTION_MULTIPLE);
115 resultView.setSortColumn_gui("Size", "Real Size");
116 resultView.setSortColumn_gui("Exact Size", "Real Size");
117 resultView.setSortColumn_gui("Slots", "Slots Order");
118 resultView.setSortColumn_gui("Filename", "File Order");
119 gtk_tree_view_set_fixed_height_mode(resultView.get(), TRUE);
120
121 // Initialize the user command menu
122 userCommandMenu = new UserCommandMenu(getWidget("usercommandMenu"), ::UserCommand::CONTEXT_SEARCH);
123 addChild(userCommandMenu);
124
125 // Connect the signals to their callback functions.
126 g_signal_connect(getContainer(), "focus-in-event", G_CALLBACK(onFocusIn_gui), (gpointer)this);
127 g_signal_connect(getWidget("checkbuttonFilter"), "toggled", G_CALLBACK(onFilterButtonToggled_gui), (gpointer)this);
128 g_signal_connect(getWidget("checkbuttonSlots"), "toggled", G_CALLBACK(onSlotsButtonToggled_gui), (gpointer)this);
129 g_signal_connect(getWidget("checkbuttonShared"), "toggled", G_CALLBACK(onSharedButtonToggled_gui), (gpointer)this);
130 g_signal_connect(renderer, "toggled", G_CALLBACK(onToggledClicked_gui), (gpointer)this);
131 g_signal_connect(resultView.get(), "button-press-event", G_CALLBACK(onButtonPressed_gui), (gpointer)this);
132 g_signal_connect(resultView.get(), "button-release-event", G_CALLBACK(onButtonReleased_gui), (gpointer)this);
133 g_signal_connect(resultView.get(), "key-release-event", G_CALLBACK(onKeyReleased_gui), (gpointer)this);
134 g_signal_connect(searchEntry, "key-press-event", G_CALLBACK(onSearchEntryKeyPressed_gui), (gpointer)this);
135 g_signal_connect(searchEntry, "key-release-event", G_CALLBACK(onKeyReleased_gui), (gpointer)this);
136 g_signal_connect(getWidget("entrySize"), "key-release-event", G_CALLBACK(onKeyReleased_gui), (gpointer)this);
137 g_signal_connect(getWidget("buttonSearch"), "clicked", G_CALLBACK(onSearchButtonClicked_gui), (gpointer)this);
138 g_signal_connect(getWidget("downloadItem"), "activate", G_CALLBACK(onDownloadClicked_gui), (gpointer)this);
139 g_signal_connect(getWidget("downloadWholeDirItem"), "activate", G_CALLBACK(onDownloadDirClicked_gui), (gpointer)this);
140 g_signal_connect(getWidget("searchByTTHItem"), "activate", G_CALLBACK(onSearchByTTHClicked_gui), (gpointer)this);
141 g_signal_connect(getWidget("copyMagnetItem"), "activate", G_CALLBACK(onCopyMagnetClicked_gui), (gpointer)this);
142 g_signal_connect(getWidget("getFileListItem"), "activate", G_CALLBACK(onGetFileListClicked_gui), (gpointer)this);
143 g_signal_connect(getWidget("matchQueueItem"), "activate", G_CALLBACK(onMatchQueueClicked_gui), (gpointer)this);
144 g_signal_connect(getWidget("sendPrivateMessageItem"), "activate", G_CALLBACK(onPrivateMessageClicked_gui), (gpointer)this);
145 g_signal_connect(getWidget("addToFavoritesItem"), "activate", G_CALLBACK(onAddFavoriteUserClicked_gui), (gpointer)this);
146 g_signal_connect(getWidget("grantExtraSlotItem"), "activate", G_CALLBACK(onGrantExtraSlotClicked_gui), (gpointer)this);
147 g_signal_connect(getWidget("removeUserFromQueueItem"), "activate", G_CALLBACK(onRemoveUserFromQueueClicked_gui), (gpointer)this);
148 g_signal_connect(getWidget("removeItem"), "activate", G_CALLBACK(onRemoveClicked_gui), (gpointer)this);
149 g_signal_connect(getWidget("comboboxSize"), "changed", G_CALLBACK(onComboBoxChanged_gui), (gpointer)this);
150 g_signal_connect(getWidget("comboboxentrySearch"), "changed", G_CALLBACK(onComboBoxChanged_gui), (gpointer)this);
151 g_signal_connect(getWidget("comboboxUnit"), "changed", G_CALLBACK(onComboBoxChanged_gui), (gpointer)this);
152 g_signal_connect(getWidget("comboboxFile"), "changed", G_CALLBACK(onComboBoxChanged_gui), (gpointer)this);
153 g_signal_connect(getWidget("comboboxGroupBy"), "changed", G_CALLBACK(onGroupByComboBoxChanged_gui), (gpointer)this);
154 }
155
~Search()156 Search::~Search()
157 {
158 ClientManager::getInstance()->removeListener(this);
159 SearchManager::getInstance()->removeListener(this);
160
161 gtk_widget_destroy(getWidget("dirChooserDialog"));
162 }
163
show()164 void Search::show()
165 {
166 initHubs_gui();
167 updateStats_gui();
168 ClientManager::getInstance()->addListener(this);
169 SearchManager::getInstance()->addListener(this);
170 }
171
putValue_gui(const string & str,int64_t size,SearchManager::SizeModes mode,SearchManager::TypeModes type)172 void Search::putValue_gui(const string &str, int64_t size, SearchManager::SizeModes mode, SearchManager::TypeModes type)
173 {
174 gtk_entry_set_text(GTK_ENTRY(searchEntry), str.c_str());
175 gtk_entry_set_text(GTK_ENTRY(getWidget("entrySize")), Util::toString(size).c_str());
176 gtk_combo_box_set_active(GTK_COMBO_BOX(getWidget("comboboxSize")), (int)mode);
177 gtk_combo_box_set_active(GTK_COMBO_BOX(getWidget("comboboxFile")), (int)type);
178
179 search_gui();
180 }
181
initHubs_gui()182 void Search::initHubs_gui()
183 {
184 ClientManager::getInstance()->lock();
185
186 Client::List& clients = ClientManager::getInstance()->getClients();
187
188 Client *client = NULL;
189 for (Client::List::iterator it = clients.begin(); it != clients.end(); ++it)
190 {
191 client = *it;
192 if (client->isConnected())
193 addHub_gui(client->getHubName(), client->getHubUrl());
194 }
195
196 ClientManager::getInstance()->unlock();
197 }
198
addHub_gui(string name,string url)199 void Search::addHub_gui(string name, string url)
200 {
201 GtkTreeIter iter;
202 gtk_list_store_append(hubStore, &iter);
203 gtk_list_store_set(hubStore, &iter,
204 hubView.col("Search"), TRUE,
205 hubView.col("Name"), name.empty() ? url.c_str() : name.c_str(),
206 hubView.col("Url"), url.c_str(),
207 -1);
208 }
209
modifyHub_gui(string name,string url)210 void Search::modifyHub_gui(string name, string url)
211 {
212 GtkTreeIter iter;
213 GtkTreeModel *m = GTK_TREE_MODEL(hubStore);
214 gboolean valid = gtk_tree_model_get_iter_first(m, &iter);
215
216 while (valid)
217 {
218 if (url == hubView.getString(&iter, "Url"))
219 {
220 gtk_list_store_set(hubStore, &iter,
221 hubView.col("Name"), name.empty() ? url.c_str() : name.c_str(),
222 hubView.col("Url"), url.c_str(),
223 -1);
224 return;
225 }
226 valid = gtk_tree_model_iter_next(m, &iter);
227 }
228 }
229
removeHub_gui(string url)230 void Search::removeHub_gui(string url)
231 {
232 GtkTreeIter iter;
233 GtkTreeModel *m = GTK_TREE_MODEL(hubStore);
234 gboolean valid = gtk_tree_model_get_iter_first(m, &iter);
235
236 while (valid)
237 {
238 if (url == hubView.getString(&iter, "Url"))
239 {
240 gtk_list_store_remove(hubStore, &iter);
241 return;
242 }
243 valid = gtk_tree_model_iter_next(m, &iter);
244 }
245 }
246
popupMenu_gui()247 void Search::popupMenu_gui()
248 {
249 GtkTreeIter iter;
250 GtkTreePath *path;
251 GList *list = gtk_tree_selection_get_selected_rows(selection, NULL);
252 guint count = g_list_length(list);
253
254 if (count == 1)
255 {
256 path = (GtkTreePath*)list->data; // This will be freed later
257
258 // If it is a parent effectively more than one row is selected
259 if (gtk_tree_model_get_iter(sortedFilterModel, &iter, path) &&
260 gtk_tree_model_iter_has_child(sortedFilterModel, &iter))
261 {
262 gtk_widget_set_sensitive(getWidget("searchByTTHItem"), FALSE);
263 }
264 else
265 {
266 gtk_widget_set_sensitive(getWidget("searchByTTHItem"), TRUE);
267 }
268 }
269 else if (count > 1)
270 {
271 gtk_widget_set_sensitive(getWidget("searchByTTHItem"), FALSE);
272 }
273
274 GtkWidget *menuItem;
275 string tth;
276 bool firstTTH;
277 bool hasTTH;
278
279 // Clean menus
280 gtk_container_foreach(GTK_CONTAINER(getWidget("downloadMenu")), (GtkCallback)gtk_widget_destroy, NULL);
281 gtk_container_foreach(GTK_CONTAINER(getWidget("downloadDirMenu")), (GtkCallback)gtk_widget_destroy, NULL);
282 userCommandMenu->cleanMenu_gui();
283
284 // Build "Download to..." submenu
285
286 // Add favorite download directories
287 StringPairList spl = FavoriteManager::getInstance()->getFavoriteDirs();
288 if (spl.size() > 0)
289 {
290 for (StringPairIter i = spl.begin(); i != spl.end(); i++)
291 {
292 menuItem = gtk_menu_item_new_with_label(i->second.c_str());
293 g_object_set_data_full(G_OBJECT(menuItem), "fav", g_strdup(i->first.c_str()), g_free);
294 g_signal_connect(menuItem, "activate", G_CALLBACK(onDownloadFavoriteClicked_gui), (gpointer)this);
295 gtk_menu_shell_append(GTK_MENU_SHELL(getWidget("downloadMenu")), menuItem);
296 }
297 menuItem = gtk_separator_menu_item_new();
298 gtk_menu_shell_append(GTK_MENU_SHELL(getWidget("downloadMenu")), menuItem);
299 }
300
301 // Add Browse item
302 menuItem = gtk_menu_item_new_with_label(_("_Browse..."));
303 gtk_menu_item_set_use_underline(GTK_MENU_ITEM(menuItem), TRUE);
304 g_signal_connect(menuItem, "activate", G_CALLBACK(onDownloadToClicked_gui), (gpointer)this);
305 gtk_menu_shell_append(GTK_MENU_SHELL(getWidget("downloadMenu")), menuItem);
306
307 // Add search results with the same TTH to menu
308 firstTTH = TRUE;
309 hasTTH = FALSE;
310
311 for (GList *i = list; i; i = i->next)
312 {
313 path = (GtkTreePath *)i->data;
314 if (gtk_tree_model_get_iter(sortedFilterModel, &iter, path))
315 {
316 userCommandMenu->addHub(resultView.getString(&iter, "Hub URL"));
317 userCommandMenu->addFile(resultView.getString(&iter, "CID"),
318 resultView.getString(&iter, "Filename"),
319 resultView.getString(&iter, "Path"),
320 resultView.getValue<int64_t>(&iter, "Real Size"),
321 resultView.getString(&iter, "TTH"));
322
323 if (firstTTH)
324 {
325 tth = resultView.getString(&iter, "TTH");
326 firstTTH = FALSE;
327 hasTTH = TRUE;
328 }
329 else if (hasTTH)
330 {
331 if (tth.empty() || tth != resultView.getString(&iter, "TTH"))
332 hasTTH = FALSE; // Can't break here since we have to free all the paths
333 }
334 }
335 gtk_tree_path_free(path);
336 }
337 g_list_free(list);
338
339 if (hasTTH)
340 {
341 StringList targets;
342 QueueManager::getInstance()->getTargets(TTHValue(tth), targets);
343
344 if (targets.size() > static_cast<size_t>(0))
345 {
346 menuItem = gtk_separator_menu_item_new();
347 gtk_menu_shell_append(GTK_MENU_SHELL(getWidget("downloadMenu")), menuItem);
348 for (StringIter i = targets.begin(); i != targets.end(); ++i)
349 {
350 menuItem = gtk_menu_item_new_with_label(i->c_str());
351 g_signal_connect(menuItem, "activate", G_CALLBACK(onDownloadToMatchClicked_gui), (gpointer)this);
352 gtk_menu_shell_append(GTK_MENU_SHELL(getWidget("downloadMenu")), menuItem);
353 }
354 }
355 }
356
357 // Build "Download whole directory to..." submenu
358
359 spl.clear();
360 spl = FavoriteManager::getInstance()->getFavoriteDirs();
361 if (spl.size() > 0)
362 {
363 for (StringPairIter i = spl.begin(); i != spl.end(); i++)
364 {
365 menuItem = gtk_menu_item_new_with_label(i->second.c_str());
366 g_object_set_data_full(G_OBJECT(menuItem), "fav", g_strdup(i->first.c_str()), g_free);
367 g_signal_connect(menuItem, "activate", G_CALLBACK(onDownloadFavoriteDirClicked_gui), (gpointer)this);
368 gtk_menu_shell_append(GTK_MENU_SHELL(getWidget("downloadDirMenu")), menuItem);
369 }
370 menuItem = gtk_separator_menu_item_new();
371 gtk_menu_shell_append(GTK_MENU_SHELL(getWidget("downloadDirMenu")), menuItem);
372 }
373
374 menuItem = gtk_menu_item_new_with_label(_("_Browse..."));
375 gtk_menu_item_set_use_underline(GTK_MENU_ITEM(menuItem), TRUE);
376 g_signal_connect(menuItem, "activate", G_CALLBACK(onDownloadDirToClicked_gui), (gpointer)this);
377 gtk_menu_shell_append(GTK_MENU_SHELL(getWidget("downloadDirMenu")), menuItem);
378
379 // Build user command menu
380 userCommandMenu->buildMenu_gui();
381
382 gtk_menu_popup(GTK_MENU(getWidget("mainMenu")), NULL, NULL, NULL, NULL, 0, gtk_get_current_event_time());
383 gtk_widget_show_all(getWidget("mainMenu"));
384 }
385
setStatus_gui(string statusBar,string text)386 void Search::setStatus_gui(string statusBar, string text)
387 {
388 gtk_statusbar_pop(GTK_STATUSBAR(getWidget(statusBar)), 0);
389 gtk_statusbar_push(GTK_STATUSBAR(getWidget(statusBar)), 0, text.c_str());
390 }
391
updateStats_gui()392 void Search::updateStats_gui()
393 {
394 // TRANSLATORS: Appears in the status bar when a valid search result is received.
395 setStatus_gui("statusbar2", P_("%1% Result", "%1% Results", % searchHits, searchHits));
396
397 // TRANSLATORS: Appears in the status bar when a search result is ignored/dropped.
398 setStatus_gui("statusbar3", F_("%1% Dropped", % droppedResult));
399 }
400
search_gui()401 void Search::search_gui()
402 {
403 StringList clients;
404 GtkTreeIter iter;
405
406 string text = gtk_entry_get_text(GTK_ENTRY(searchEntry));
407 if (text.empty())
408 return;
409
410 gboolean valid = gtk_tree_model_get_iter_first(GTK_TREE_MODEL(hubStore), &iter);
411 while (valid)
412 {
413 if (hubView.getValue<gboolean>(&iter, "Search"))
414 clients.push_back(hubView.getString(&iter, "Url"));
415 valid = gtk_tree_model_iter_next(GTK_TREE_MODEL(hubStore), &iter);
416 }
417
418 if (clients.size() < 1)
419 return;
420
421 double lsize = Util::toDouble(gtk_entry_get_text(GTK_ENTRY(getWidget("entrySize"))));
422
423 switch (gtk_combo_box_get_active(GTK_COMBO_BOX(getWidget("comboboxUnit"))))
424 {
425 case 1:
426 lsize *= 1024.0;
427 break;
428 case 2:
429 lsize *= 1024.0 * 1024.0;
430 break;
431 case 3:
432 lsize *= 1024.0 * 1024.0 * 1024.0;
433 break;
434 }
435
436 gtk_tree_store_clear(resultStore);
437 results.clear();
438 int64_t llsize = static_cast<int64_t>(lsize);
439 searchlist = StringTokenizer<string>(text, ' ').getTokens();
440
441 // Strip out terms beginning with -
442 text.clear();
443 for (StringList::const_iterator si = searchlist.begin(); si != searchlist.end(); ++si)
444 if ((*si)[0] != '-')
445 text += *si + ' ';
446 text = text.substr(0, std::max(text.size(), static_cast<string::size_type>(1)) - 1);
447
448 SearchManager::SizeModes mode((SearchManager::SizeModes)gtk_combo_box_get_active(GTK_COMBO_BOX(getWidget("comboboxSize"))));
449 if (llsize == 0)
450 mode = SearchManager::SIZE_DONTCARE;
451
452 int ftype = gtk_combo_box_get_active(GTK_COMBO_BOX(getWidget("comboboxFile")));
453 isHash = (ftype == SearchManager::TYPE_TTH);
454
455 // Add new searches to the dropdown list
456 GtkListStore *store = GTK_LIST_STORE(searchEntriesModel);
457 size_t max = std::max(SETTING(SEARCH_HISTORY) - 1, 0);
458 size_t count = 0;
459 gchar *entry;
460 valid = gtk_tree_model_get_iter_first(searchEntriesModel, &iter);
461 while (valid)
462 {
463 gtk_tree_model_get(searchEntriesModel, &iter, 0, &entry, -1);
464 if (text == string(entry) || count >= max)
465 valid = gtk_list_store_remove(store, &iter);
466 else
467 valid = gtk_tree_model_iter_next(searchEntriesModel, &iter);
468 count++;
469 g_free(entry);
470 }
471
472 gtk_list_store_prepend(store, &iter);
473 gtk_list_store_set(store, &iter, 0, text.c_str(), -1);
474
475 droppedResult = 0;
476 searchHits = 0;
477 setStatus_gui("statusbar1", F_("Searching for %1%...", % text));
478 updateStats_gui();
479 setLabel_gui(text);
480
481 if (SearchManager::getInstance()->okToSearch())
482 {
483 SearchManager::getInstance()->search(clients, text, llsize, (SearchManager::TypeModes)ftype, mode, "manual");
484
485 if (BOOLSETTING(CLEAR_SEARCH)) // Only clear if the search was sent.
486 gtk_entry_set_text(GTK_ENTRY(searchEntry), "");
487 }
488 else
489 {
490 int32_t waitFor = SearchManager::getInstance()->timeToSearch();
491 string line = F_("Searching too soon, retry in %1% s", % waitFor);
492 setStatus_gui("statusbar1", line);
493 }
494 }
495
addResult_gui(const SearchResultPtr result)496 void Search::addResult_gui(const SearchResultPtr result)
497 {
498 // Check that it's not a duplicate and find parent for grouping
499 GtkTreeIter iter;
500 GtkTreeIter parent;
501 GtkTreeModel *m = GTK_TREE_MODEL(resultStore);
502 bool foundParent = FALSE;
503
504 vector<SearchResultPtr> &existingResults = results[result->getUser()->getCID().toBase32()];
505 for (vector<SearchResultPtr>::iterator it = existingResults.begin(); it != existingResults.end(); it++)
506 {
507 // Check if it's a duplicate
508 if (result->getFile() == (*it)->getFile())
509 return;
510 }
511 existingResults.push_back(result);
512
513 dcpp::StringMap resultMap;
514 parseSearchResult_gui(result, resultMap);
515
516 // Find grouping parent
517 GroupType groupBy = (GroupType)gtk_combo_box_get_active(GTK_COMBO_BOX(getWidget("comboboxGroupBy")));
518 string groupColumn = getGroupingColumn(groupBy);
519 string groupStr = resultMap[groupColumn];
520 gboolean valid = gtk_tree_model_get_iter_first(m, &iter);
521
522 while (valid && groupBy != NOGROUPING && !foundParent && !groupStr.empty())
523 {
524 // Found a row which matches the grouping criteria
525 if (resultView.getString(&iter, groupColumn, m) == groupStr)
526 {
527 // Group the row under the existing parent row
528 if (gtk_tree_model_iter_has_child(m, &iter))
529 {
530 parent = iter;
531 }
532 else // Group the rows under a new parent row
533 {
534 parent = createParentRow_gui(&iter, groupStr);
535 }
536
537 foundParent = TRUE;
538 }
539
540 valid = WulforUtil::getNextIter_gui(m, &iter, FALSE, FALSE);
541 }
542
543 // Have to use insert with values since appending would cause searchFilterFunc to be
544 // called with empty row which in turn will cause assert failure in treeview::getString
545 gtk_tree_store_insert_with_values(resultStore, &iter, foundParent ? &parent : NULL, -1,
546 resultView.col("User"), resultMap["User"].c_str(),
547 resultView.col("Filename"), resultMap["Filename"].c_str(),
548 resultView.col("Slots"), resultMap["Slots"].c_str(),
549 resultView.col("Size"), resultMap["Size"].c_str(),
550 resultView.col("Path"), resultMap["Path"].c_str(),
551 resultView.col("Type"), resultMap["Type"].c_str(),
552 resultView.col("Connection"), resultMap["Connection"].c_str(),
553 resultView.col("Hub"), resultMap["Hub"].c_str(),
554 resultView.col("Exact Size"), resultMap["Exact Size"].c_str(),
555 resultView.col("IP"), resultMap["IP"].c_str(),
556 resultView.col("TTH"), resultMap["TTH"].c_str(),
557 resultView.col("Icon"), resultMap["Icon"].c_str(),
558 resultView.col("File Order"), resultMap["File Order"].c_str(),
559 resultView.col("Real Size"), Util::toInt64(resultMap["Real Size"]),
560 resultView.col("Slots Order"), Util::toInt(resultMap["Slots Order"]),
561 resultView.col("Hub URL"), resultMap["Hub URL"].c_str(),
562 resultView.col("CID"), resultMap["CID"].c_str(),
563 resultView.col("Shared"), Util::toInt(resultMap["Shared"]),
564 resultView.col("Free Slots"), Util::toInt(resultMap["Free Slots"]),
565 -1);
566
567 if (foundParent)
568 updateParentRow_gui(&parent, &iter);
569
570 ++searchHits;
571 updateStats_gui();
572
573 if (BOOLSETTING(BOLD_SEARCH))
574 setBold_gui();
575 }
576
577 /*
578 * Move top level row to be under a newly created grouping parent.
579 */
createParentRow_gui(GtkTreeIter * child,const string & groupStr,gint position)580 GtkTreeIter Search::createParentRow_gui(GtkTreeIter *child, const string &groupStr, gint position /* = -1 */)
581 {
582 GtkTreeIter parent;
583 GroupType groupBy = (GroupType)gtk_combo_box_get_active(GTK_COMBO_BOX(getWidget("comboboxGroupBy")));
584 string filename = groupStr;
585
586 // As a special case, use the first child's filename for TTH grouping
587 if (groupBy == TTH)
588 filename = resultView.getString(child, "Filename", GTK_TREE_MODEL(resultStore));
589
590 // Insert the new parent row
591 gtk_tree_store_insert_with_values(resultStore, &parent, NULL, position,
592 resultView.col("Icon"), GTK_STOCK_DND_MULTIPLE,
593 resultView.col("Filename"), filename.c_str(),
594 -1);
595
596 // Move the row to be a child of the new parent
597 GtkTreeIter newChild = WulforUtil::copyRow_gui(resultStore, child, &parent);
598 gtk_tree_store_remove(resultStore, child);
599 *child = newChild;
600
601 return parent;
602 }
603
updateParentRow_gui(GtkTreeIter * parent,GtkTreeIter * child)604 void Search::updateParentRow_gui(GtkTreeIter *parent, GtkTreeIter *child)
605 {
606 // Let's make sure we really have children...
607 gint children = gtk_tree_model_iter_n_children(GTK_TREE_MODEL(resultStore), parent);
608 dcassert(children != 0);
609
610 string users = P_("%1% User", "%1% Users", % children, children);
611 gtk_tree_store_set(resultStore, parent, resultView.col("User"), users.c_str(), -1);
612
613 if (child == NULL)
614 return;
615
616 GroupType groupType = (GroupType)gtk_combo_box_get_active(GTK_COMBO_BOX(getWidget("comboboxGroupBy")));
617
618 switch (groupType)
619 {
620 case NOGROUPING:
621 break;
622 case FILENAME:
623 WulforUtil::copyValue_gui(resultStore, child, parent, resultView.col("File Order"));
624 break;
625 case FILEPATH:
626 WulforUtil::copyValue_gui(resultStore, child, parent, resultView.col("Path"));
627 break;
628 case CONNECTION:
629 WulforUtil::copyValue_gui(resultStore, child, parent, resultView.col("Connection"));
630 break;
631 case TTH: // Copy size as well since files with the same TTH should have the same size
632 WulforUtil::copyValue_gui(resultStore, child, parent, resultView.col("TTH"));
633 case SIZE:
634 {
635 WulforUtil::copyValue_gui(resultStore, child, parent, resultView.col("Exact Size"));
636 WulforUtil::copyValue_gui(resultStore, child, parent, resultView.col("Size"));
637 WulforUtil::copyValue_gui(resultStore, child, parent, resultView.col("Real Size"));
638 break;
639 }
640 case USER:
641 WulforUtil::copyValue_gui(resultStore, child, parent, resultView.col("User"));
642 break;
643 case HUB:
644 {
645 WulforUtil::copyValue_gui(resultStore, child, parent, resultView.col("Hub"));
646 WulforUtil::copyValue_gui(resultStore, child, parent, resultView.col("Hub URL"));
647 break;
648 }
649 case TYPE:
650 WulforUtil::copyValue_gui(resultStore, child, parent, resultView.col("Type"));
651 break;
652 default:
653 ///@todo: throw an exception
654 break;
655 }
656 }
657
ungroup_gui()658 void Search::ungroup_gui()
659 {
660 GtkTreeIter iter;
661 gint position = 0;
662 GtkTreeModel *m = GTK_TREE_MODEL(resultStore);
663 gboolean valid = gtk_tree_model_get_iter_first(m, &iter);
664
665 while (valid)
666 {
667 // Ungroup parent rows and remove them
668 if (gtk_tree_model_iter_has_child(m, &iter))
669 {
670 GtkTreeIter child = iter;
671 valid = WulforUtil::getNextIter_gui(m, &child, TRUE, FALSE);
672
673 // Move all children out from under the old grouping parent
674 while (valid)
675 {
676 WulforUtil::copyRow_gui(resultStore, &child, NULL, position++);
677 valid = gtk_tree_store_remove(resultStore, &child);
678 }
679
680 // Delete the parent row
681 valid = gtk_tree_store_remove(resultStore, &iter);
682 }
683 else // Non-parent row
684 {
685 ++position;
686 valid = WulforUtil::getNextIter_gui(m, &iter);
687 }
688 }
689 }
690
regroup_gui()691 void Search::regroup_gui()
692 {
693 unordered_map<string, GtkTreeIter> iterMap; // Maps group string -> parent tree iter
694 GtkTreeIter iter;
695 gint position = 0;
696 GtkTreeModel *m = GTK_TREE_MODEL(resultStore);
697 GroupType groupBy = (GroupType)gtk_combo_box_get_active(GTK_COMBO_BOX(getWidget("comboboxGroupBy")));
698 string groupColumn = getGroupingColumn(groupBy);
699 gboolean valid = gtk_tree_model_get_iter_first(m, &iter);
700
701 while (valid)
702 {
703 string groupStr;
704 if (!groupColumn.empty())
705 groupStr = resultView.getString(&iter, groupColumn, m);
706
707 // Don't add parent rows
708 if (gtk_tree_model_iter_has_child(m, &iter) || groupStr.empty())
709 {
710 ++position;
711 valid = WulforUtil::getNextIter_gui(m, &iter);
712 continue;
713 }
714
715 unordered_map<std::string, GtkTreeIter>::iterator mapIter = iterMap.find(groupStr);
716
717 // New non-parent, top-level item
718 if (mapIter == iterMap.end())
719 {
720 ++position;
721 iterMap[groupStr] = iter;
722 valid = WulforUtil::getNextIter_gui(m, &iter);
723 }
724 else // Insert as a child under the grouping parent
725 {
726 GtkTreeIter parent = mapIter->second;
727
728 // If this is the first child to be appended, create a new parent row.
729 if (!gtk_tree_model_iter_has_child(GTK_TREE_MODEL(resultStore), &parent))
730 {
731 GtkTreeIter child = parent;
732 parent = createParentRow_gui(&child, groupStr, position);
733 mapIter->second = parent;
734 }
735
736 // Insert the row as a child
737 GtkTreeIter child = WulforUtil::copyRow_gui(resultStore, &iter, &parent);
738 valid = gtk_tree_store_remove(resultStore, &iter);
739 updateParentRow_gui(&parent, &child);
740 }
741 }
742 }
743
744 /*
745 * We can't rely on the string from the text box since it will be internationalized.
746 */
getGroupingColumn(GroupType groupBy)747 std::string Search::getGroupingColumn(GroupType groupBy)
748 {
749 string column;
750
751 switch (groupBy)
752 {
753 case Search::NOGROUPING:
754 break;
755 case Search::FILENAME:
756 column = "Filename";
757 break;
758 case Search::FILEPATH:
759 column = "Path";
760 break;
761 case Search::SIZE:
762 column = "Size";
763 break;
764 case Search::CONNECTION:
765 column = "Connection";
766 break;
767 case Search::TTH:
768 column = "TTH";
769 break;
770 case Search::USER:
771 column = "User";
772 break;
773 case Search::HUB:
774 column = "Hub";
775 break;
776 case Search::TYPE:
777 column = "Type";
778 break;
779 default:
780 ///@todo: throw an exception
781 break;
782 }
783
784 return column;
785 }
786
download_gui(const string & target)787 void Search::download_gui(const string &target)
788 {
789 if (target.empty() || gtk_tree_selection_count_selected_rows(selection) <= 0)
790 return;
791
792 GtkTreeIter iter;
793 GtkTreePath *path;
794 GroupType groupBy = (GroupType)gtk_combo_box_get_active(GTK_COMBO_BOX(getWidget("comboboxGroupBy")));
795 GList *list = gtk_tree_selection_get_selected_rows(selection, NULL);
796 typedef Func6<Search, string, string, string, int64_t, string, string> F6;
797
798 for (GList *i = list; i; i = i->next)
799 {
800 path = (GtkTreePath *)i->data;
801 if (gtk_tree_model_get_iter(sortedFilterModel, &iter, path))
802 {
803 bool parent = gtk_tree_model_iter_has_child(sortedFilterModel, &iter);
804 string filename = resultView.getString(&iter, "Filename");
805
806 do
807 {
808 if (!gtk_tree_model_iter_has_child(sortedFilterModel, &iter))
809 {
810 // Use parent filename when grouping by TTH to avoid downloading the same file multiple times
811 if (groupBy != TTH)
812 {
813 filename = resultView.getString(&iter, "Path");
814 filename += resultView.getString(&iter, "Filename");
815 }
816
817 string cid = resultView.getString(&iter, "CID");
818 int64_t size = resultView.getValue<int64_t>(&iter, "Real Size");
819 string tth = resultView.getString(&iter, "TTH");
820 string hubUrl = resultView.getString(&iter, "Hub URL");
821 F6 *func = new F6(this, &Search::download_client, target, cid, filename, size, tth, hubUrl);
822 WulforManager::get()->dispatchClientFunc(func);
823 }
824 }
825 while (parent && WulforUtil::getNextIter_gui(sortedFilterModel, &iter, TRUE, FALSE));
826 }
827 gtk_tree_path_free(path);
828 }
829 g_list_free(list);
830 }
831
onFocusIn_gui(GtkWidget * widget,GdkEventFocus * event,gpointer data)832 gboolean Search::onFocusIn_gui(GtkWidget *widget, GdkEventFocus *event, gpointer data)
833 {
834 Search *s = (Search *)data;
835
836 gtk_widget_grab_focus(s->getWidget("comboboxentrySearch"));
837
838 return TRUE;
839 }
840
onButtonPressed_gui(GtkWidget * widget,GdkEventButton * event,gpointer data)841 gboolean Search::onButtonPressed_gui(GtkWidget *widget, GdkEventButton *event, gpointer data)
842 {
843 Search *s = (Search *)data;
844 s->oldEventType = event->type;
845
846 if (event->button == 3)
847 {
848 GtkTreePath *path;
849 if (gtk_tree_view_get_path_at_pos(s->resultView.get(), (gint)event->x, (gint)event->y, &path, NULL, NULL, NULL))
850 {
851 bool selected = gtk_tree_selection_path_is_selected(s->selection, path);
852 gtk_tree_path_free(path);
853
854 if (selected)
855 return TRUE;
856 }
857 }
858 return FALSE;
859 }
860
onButtonReleased_gui(GtkWidget * widget,GdkEventButton * event,gpointer data)861 gboolean Search::onButtonReleased_gui(GtkWidget *widget, GdkEventButton *event, gpointer data)
862 {
863 Search *s = (Search *)data;
864 gint count = gtk_tree_selection_count_selected_rows(s->selection);
865
866 if (count > 0 && event->type == GDK_BUTTON_RELEASE && event->button == 3)
867 s->popupMenu_gui();
868 else if (count == 1 && s->oldEventType == GDK_2BUTTON_PRESS && event->button == 1)
869 s->onDownloadClicked_gui(NULL, data);
870
871 return FALSE;
872 }
873
onKeyReleased_gui(GtkWidget * widget,GdkEventKey * event,gpointer data)874 gboolean Search::onKeyReleased_gui(GtkWidget *widget, GdkEventKey *event, gpointer data)
875 {
876 Search *s = (Search *)data;
877 if (widget == GTK_WIDGET(s->resultView.get()))
878 {
879 gint count = gtk_tree_selection_count_selected_rows(s->selection);
880
881 if (count > 0)
882 {
883 if (event->keyval == GDK_Return || event->keyval == GDK_KP_Enter)
884 s->onDownloadClicked_gui(NULL, data);
885 else if (event->keyval == GDK_Delete || event->keyval == GDK_BackSpace)
886 s->onRemoveClicked_gui(NULL, data);
887 else if (event->keyval == GDK_Menu || (event->keyval == GDK_F10 && event->state & GDK_SHIFT_MASK))
888 s->popupMenu_gui();
889 }
890 }
891 else
892 {
893 if (gtk_toggle_button_get_active(GTK_TOGGLE_BUTTON(s->getWidget("checkbuttonFilter"))))
894 gtk_tree_model_filter_refilter(GTK_TREE_MODEL_FILTER(s->searchFilterModel));
895 }
896
897 return FALSE;
898 }
899
onSearchEntryKeyPressed_gui(GtkWidget * widget,GdkEventKey * event,gpointer data)900 gboolean Search::onSearchEntryKeyPressed_gui(GtkWidget *widget, GdkEventKey *event, gpointer data)
901 {
902 Search *s = (Search *)data;
903
904 if (event->keyval == GDK_Return || event->keyval == GDK_KP_Enter)
905 {
906 s->search_gui();
907 }
908 else if (event->keyval == GDK_Down || event->keyval == GDK_KP_Down)
909 {
910 gtk_combo_box_popup(GTK_COMBO_BOX(s->getWidget("comboboxentrySearch")));
911 return TRUE;
912 }
913
914 return FALSE;
915 }
916
onComboBoxChanged_gui(GtkWidget * widget,gpointer data)917 void Search::onComboBoxChanged_gui(GtkWidget* widget, gpointer data)
918 {
919 Search *s = (Search *)data;
920
921 if (gtk_toggle_button_get_active(GTK_TOGGLE_BUTTON(s->getWidget("checkbuttonFilter"))))
922 gtk_tree_model_filter_refilter(GTK_TREE_MODEL_FILTER(s->searchFilterModel));
923 }
924
onGroupByComboBoxChanged_gui(GtkWidget * comboBox,gpointer data)925 void Search::onGroupByComboBoxChanged_gui(GtkWidget *comboBox, gpointer data)
926 {
927 Search *s = (Search*)data;
928 GroupType groupBy = (GroupType)gtk_combo_box_get_active(GTK_COMBO_BOX(comboBox));
929
930 s->ungroup_gui();
931
932 if (groupBy != NOGROUPING)
933 {
934 gtk_widget_set_sensitive(s->getWidget("checkbuttonFilter"), FALSE);
935 gtk_widget_set_sensitive(s->getWidget("checkbuttonSlots"), FALSE);
936 gtk_widget_set_sensitive(s->getWidget("checkbuttonShared"), FALSE);
937 s->regroup_gui();
938 }
939 else
940 {
941 gtk_widget_set_sensitive(s->getWidget("checkbuttonFilter"), TRUE);
942 gtk_widget_set_sensitive(s->getWidget("checkbuttonSlots"), FALSE);
943 gtk_widget_set_sensitive(s->getWidget("checkbuttonShared"), FALSE);
944 }
945 }
946
onSearchButtonClicked_gui(GtkWidget * widget,gpointer data)947 void Search::onSearchButtonClicked_gui(GtkWidget *widget, gpointer data)
948 {
949 Search *s = (Search *)data;
950 s->search_gui();
951 }
952
onFilterButtonToggled_gui(GtkToggleButton * button,gpointer data)953 void Search::onFilterButtonToggled_gui(GtkToggleButton *button, gpointer data)
954 {
955 Search *s = (Search *)data;
956 GtkComboBox *comboBox = GTK_COMBO_BOX(s->getWidget("comboboxGroupBy"));
957
958 // Disable grouping when filtering within local results
959 if (gtk_toggle_button_get_active(button))
960 {
961 s->previousGrouping = (GroupType)gtk_combo_box_get_active(comboBox);
962 gtk_combo_box_set_active(comboBox, (int)NOGROUPING);
963 gtk_widget_set_sensitive(GTK_WIDGET(comboBox), FALSE);
964 gtk_widget_set_sensitive(s->getWidget("checkbuttonSlots"), TRUE);
965 gtk_widget_set_sensitive(s->getWidget("checkbuttonShared"), TRUE);
966 }
967 else
968 {
969 gtk_combo_box_set_active(comboBox, (int)s->previousGrouping);
970 gtk_widget_set_sensitive(GTK_WIDGET(comboBox), TRUE);
971 gtk_widget_set_sensitive(s->getWidget("checkbuttonSlots"), FALSE);
972 gtk_widget_set_sensitive(s->getWidget("checkbuttonShared"), FALSE);
973
974 }
975
976 gtk_tree_model_filter_refilter(GTK_TREE_MODEL_FILTER(s->searchFilterModel));
977 }
978
onSlotsButtonToggled_gui(GtkToggleButton * button,gpointer data)979 void Search::onSlotsButtonToggled_gui(GtkToggleButton *button, gpointer data)
980 {
981 Search *s = (Search *)data;
982
983 s->onlyFree = gtk_toggle_button_get_active(button);
984 if (s->onlyFree != BOOLSETTING(SEARCH_ONLY_FREE_SLOTS))
985 SettingsManager::getInstance()->set(SettingsManager::SEARCH_ONLY_FREE_SLOTS, s->onlyFree);
986
987 // Refilter current view only if "Search within local results" is enabled
988 if (gtk_toggle_button_get_active(GTK_TOGGLE_BUTTON(s->getWidget("checkbuttonFilter"))))
989 gtk_tree_model_filter_refilter(GTK_TREE_MODEL_FILTER(s->searchFilterModel));
990 }
991
onSharedButtonToggled_gui(GtkToggleButton * button,gpointer data)992 void Search::onSharedButtonToggled_gui(GtkToggleButton *button, gpointer data)
993 {
994 Search *s = (Search *)data;
995
996 // Refilter current view only if "Search within local results" is enabled
997 if (gtk_toggle_button_get_active(GTK_TOGGLE_BUTTON(s->getWidget("checkbuttonFilter"))))
998 gtk_tree_model_filter_refilter(GTK_TREE_MODEL_FILTER(s->searchFilterModel));
999 }
1000
onToggledClicked_gui(GtkCellRendererToggle * cell,gchar * path,gpointer data)1001 void Search::onToggledClicked_gui(GtkCellRendererToggle *cell, gchar *path, gpointer data)
1002 {
1003 Search *s = (Search *)data;
1004 GtkTreeIter iter;
1005
1006 if (gtk_tree_model_get_iter_from_string(GTK_TREE_MODEL(s->hubStore), &iter, path))
1007 {
1008 gboolean toggled = s->hubView.getValue<gboolean>(&iter, "Search");
1009 gtk_list_store_set(s->hubStore, &iter, s->hubView.col("Search"), !toggled, -1);
1010 }
1011
1012 // Refilter current view only if "Search within local results" is enabled
1013 if (gtk_toggle_button_get_active(GTK_TOGGLE_BUTTON(s->getWidget("checkbuttonFilter"))))
1014 gtk_tree_model_filter_refilter(GTK_TREE_MODEL_FILTER(s->searchFilterModel));
1015 }
1016
onDownloadClicked_gui(GtkMenuItem * item,gpointer data)1017 void Search::onDownloadClicked_gui(GtkMenuItem *item, gpointer data)
1018 {
1019 Search *s = (Search *)data;
1020 string target = SETTING(DOWNLOAD_DIRECTORY);
1021 s->download_gui(target);
1022 }
1023
onDownloadFavoriteClicked_gui(GtkMenuItem * item,gpointer data)1024 void Search::onDownloadFavoriteClicked_gui(GtkMenuItem *item, gpointer data)
1025 {
1026 Search *s = (Search *)data;
1027 string fav = string((gchar *)g_object_get_data(G_OBJECT(item), "fav"));
1028 s->download_gui(fav);
1029 }
1030
onDownloadToClicked_gui(GtkMenuItem * item,gpointer data)1031 void Search::onDownloadToClicked_gui(GtkMenuItem *item, gpointer data)
1032 {
1033 Search *s = (Search *)data;
1034
1035 int response = gtk_dialog_run(GTK_DIALOG(s->getWidget("dirChooserDialog")));
1036 gtk_widget_hide(s->getWidget("dirChooserDialog"));
1037
1038 if (response == GTK_RESPONSE_OK)
1039 {
1040 gchar *temp = gtk_file_chooser_get_current_folder(GTK_FILE_CHOOSER(s->getWidget("dirChooserDialog")));
1041
1042 if (temp)
1043 {
1044 string target = Text::toUtf8(temp);
1045 g_free(temp);
1046
1047 if (target[target.length() - 1] != PATH_SEPARATOR)
1048 target += PATH_SEPARATOR;
1049
1050 s->download_gui(target);
1051 }
1052 }
1053 }
1054
onDownloadToMatchClicked_gui(GtkMenuItem * item,gpointer data)1055 void Search::onDownloadToMatchClicked_gui(GtkMenuItem *item, gpointer data)
1056 {
1057 Search *s = (Search *)data;
1058
1059 if (gtk_tree_selection_count_selected_rows(s->selection) > 0)
1060 {
1061 string fileName = WulforUtil::getTextFromMenu(item);
1062 GtkTreeIter iter;
1063 GtkTreePath *path;
1064 GList *list = gtk_tree_selection_get_selected_rows(s->selection, NULL);
1065 typedef Func5<Search, string, string, int64_t, string, string> F5;
1066
1067 for (GList *i = list; i; i = i->next)
1068 {
1069 path = (GtkTreePath *)i->data;
1070 if (gtk_tree_model_get_iter(s->sortedFilterModel, &iter, path))
1071 {
1072 bool parent = gtk_tree_model_iter_has_child(s->sortedFilterModel, &iter);
1073
1074 do
1075 {
1076 if (!gtk_tree_model_iter_has_child(s->sortedFilterModel, &iter))
1077 {
1078 string cid = s->resultView.getString(&iter, "CID");
1079 int64_t size = s->resultView.getValue<int64_t>(&iter, "Real Size");
1080 string tth = s->resultView.getString(&iter, "TTH");
1081 string hubUrl = s->resultView.getString(&iter, "Hub URL");
1082 F5 *func = new F5(s, &Search::addSource_client, fileName, cid, size, tth, hubUrl);
1083 WulforManager::get()->dispatchClientFunc(func);
1084 }
1085 }
1086 while (parent && WulforUtil::getNextIter_gui(s->sortedFilterModel, &iter, TRUE, FALSE));
1087 }
1088 gtk_tree_path_free(path);
1089 }
1090 g_list_free(list);
1091 }
1092 }
1093
onDownloadDirClicked_gui(GtkMenuItem * item,gpointer data)1094 void Search::onDownloadDirClicked_gui(GtkMenuItem *item, gpointer data)
1095 {
1096 Search *s = (Search *)data;
1097
1098 if (gtk_tree_selection_count_selected_rows(s->selection) > 0)
1099 {
1100 GtkTreeIter iter;
1101 GtkTreePath *path;
1102 GList *list = gtk_tree_selection_get_selected_rows(s->selection, NULL);
1103 string target = SETTING(DOWNLOAD_DIRECTORY);
1104 typedef Func4<Search, string, string, string, string> F4;
1105
1106 for (GList *i = list; i; i = i->next)
1107 {
1108 path = (GtkTreePath *)i->data;
1109 if (gtk_tree_model_get_iter(s->sortedFilterModel, &iter, path))
1110 {
1111 bool parent = gtk_tree_model_iter_has_child(s->sortedFilterModel, &iter);
1112
1113 do
1114 {
1115 if (!gtk_tree_model_iter_has_child(s->sortedFilterModel, &iter))
1116 {
1117 string cid = s->resultView.getString(&iter, "CID");
1118 string filename = s->resultView.getString(&iter, "Path");
1119 filename += s->resultView.getString(&iter, "Filename");
1120 string hubUrl = s->resultView.getString(&iter, "Hub URL");
1121 F4 *func = new F4(s, &Search::downloadDir_client, target, cid, filename, hubUrl);
1122 WulforManager::get()->dispatchClientFunc(func);
1123 }
1124 }
1125 while (parent && WulforUtil::getNextIter_gui(s->sortedFilterModel, &iter, TRUE, FALSE));
1126 }
1127 gtk_tree_path_free(path);
1128 }
1129 g_list_free(list);
1130 }
1131 }
1132
onDownloadFavoriteDirClicked_gui(GtkMenuItem * item,gpointer data)1133 void Search::onDownloadFavoriteDirClicked_gui(GtkMenuItem *item, gpointer data)
1134 {
1135 Search *s = (Search *)data;
1136 string fav = (gchar *)g_object_get_data(G_OBJECT(item), "fav");
1137
1138 if (!fav.empty() && gtk_tree_selection_count_selected_rows(s->selection) > 0)
1139 {
1140 GtkTreeIter iter;
1141 GtkTreePath *path;
1142 GList *list = gtk_tree_selection_get_selected_rows(s->selection, NULL);
1143 typedef Func4<Search, string, string, string, string> F4;
1144
1145 for (GList *i = list; i; i = i->next)
1146 {
1147 path = (GtkTreePath *)i->data;
1148 if (gtk_tree_model_get_iter(s->sortedFilterModel, &iter, path))
1149 {
1150 bool parent = gtk_tree_model_iter_has_child(s->sortedFilterModel, &iter);
1151
1152 do
1153 {
1154 if (!gtk_tree_model_iter_has_child(s->sortedFilterModel, &iter))
1155 {
1156 string cid = s->resultView.getString(&iter, "CID");
1157 string filename = s->resultView.getString(&iter, "Path");
1158 filename += s->resultView.getString(&iter, "Filename");
1159 string hubUrl = s->resultView.getString(&iter, "Hub URL");
1160 F4 *func = new F4(s, &Search::downloadDir_client, fav, cid, filename, hubUrl);
1161 WulforManager::get()->dispatchClientFunc(func);
1162 }
1163 }
1164 while (parent && WulforUtil::getNextIter_gui(s->sortedFilterModel, &iter, TRUE, FALSE));
1165 }
1166 gtk_tree_path_free(path);
1167 }
1168 g_list_free(list);
1169 }
1170 }
1171
onDownloadDirToClicked_gui(GtkMenuItem * item,gpointer data)1172 void Search::onDownloadDirToClicked_gui(GtkMenuItem *item, gpointer data)
1173 {
1174 Search *s = (Search *)data;
1175
1176 gint response = gtk_dialog_run(GTK_DIALOG(s->getWidget("dirChooserDialog")));
1177 gtk_widget_hide(s->getWidget("dirChooserDialog"));
1178
1179 if (response == GTK_RESPONSE_OK)
1180 {
1181 int count = gtk_tree_selection_count_selected_rows(s->selection);
1182 gchar *temp = gtk_file_chooser_get_current_folder(GTK_FILE_CHOOSER(s->getWidget("dirChooserDialog")));
1183
1184 if (temp && count > 0)
1185 {
1186 string target = Text::toUtf8(temp);
1187 g_free(temp);
1188
1189 if (target[target.length() - 1] != PATH_SEPARATOR)
1190 target += PATH_SEPARATOR;
1191
1192 GtkTreeIter iter;
1193 GtkTreePath *path;
1194 GList *list = gtk_tree_selection_get_selected_rows(s->selection, NULL);
1195 typedef Func4<Search, string, string, string, string> F4;
1196
1197 for (GList *i = list; i; i = i->next)
1198 {
1199 path = (GtkTreePath *)i->data;
1200 if (gtk_tree_model_get_iter(s->sortedFilterModel, &iter, path))
1201 {
1202 bool parent = gtk_tree_model_iter_has_child(s->sortedFilterModel, &iter);
1203
1204 do
1205 {
1206 if (!gtk_tree_model_iter_has_child(s->sortedFilterModel, &iter))
1207 {
1208 string cid = s->resultView.getString(&iter, "CID");
1209 string filename = s->resultView.getString(&iter, "Path");
1210 filename += s->resultView.getString(&iter, "Filename");
1211 string hubUrl = s->resultView.getString(&iter, "Hub URL");
1212 F4 *func = new F4(s, &Search::downloadDir_client, target, cid, filename, hubUrl);
1213 WulforManager::get()->dispatchClientFunc(func);
1214 }
1215 }
1216 while (parent && WulforUtil::getNextIter_gui(s->sortedFilterModel, &iter, TRUE, FALSE));
1217 }
1218 gtk_tree_path_free(path);
1219 }
1220 g_list_free(list);
1221 }
1222 }
1223 }
1224
onSearchByTTHClicked_gui(GtkMenuItem * item,gpointer data)1225 void Search::onSearchByTTHClicked_gui(GtkMenuItem *item, gpointer data)
1226 {
1227 Search *s = (Search *)data;
1228
1229 if (gtk_tree_selection_count_selected_rows(s->selection) > 0)
1230 {
1231 GtkTreeIter iter;
1232 GtkTreePath *path;
1233 GList *list = gtk_tree_selection_get_selected_rows(s->selection, NULL);
1234
1235 for (GList *i = list; i; i = i->next)
1236 {
1237 path = (GtkTreePath *)i->data;
1238 if (gtk_tree_model_get_iter(s->sortedFilterModel, &iter, path))
1239 {
1240 string tth = s->resultView.getString(&iter, "TTH");
1241 if (!tth.empty())
1242 {
1243
1244 Search *ns = WulforManager::get()->getMainWindow()->addSearch_gui();
1245 ns->putValue_gui(tth, 0, SearchManager::SIZE_DONTCARE, SearchManager::TYPE_TTH);
1246 }
1247 }
1248 gtk_tree_path_free(path);
1249 }
1250 g_list_free(list);
1251 }
1252 }
1253
onGetFileListClicked_gui(GtkMenuItem * item,gpointer data)1254 void Search::onGetFileListClicked_gui(GtkMenuItem *item, gpointer data)
1255 {
1256 Search *s = (Search *)data;
1257
1258 if (gtk_tree_selection_count_selected_rows(s->selection) > 0)
1259 {
1260 GtkTreeIter iter;
1261 GtkTreePath *path;
1262 GList *list = gtk_tree_selection_get_selected_rows(s->selection, NULL);
1263 typedef Func4<Search, string, string, bool, string> F4;
1264
1265 for (GList *i = list; i; i = i->next)
1266 {
1267 path = (GtkTreePath *)i->data;
1268 if (gtk_tree_model_get_iter(s->sortedFilterModel, &iter, path))
1269 {
1270 bool parent = gtk_tree_model_iter_has_child(s->sortedFilterModel, &iter);
1271
1272 do
1273 {
1274 string cid = s->resultView.getString(&iter, "CID");
1275 string dir = s->resultView.getString(&iter, "Path");
1276 string hubUrl = s->resultView.getString(&iter, "Hub URL");
1277 F4 *func = new F4(s, &Search::getFileList_client, cid, dir, FALSE, hubUrl);
1278 WulforManager::get()->dispatchClientFunc(func);
1279 }
1280 while (parent && WulforUtil::getNextIter_gui(s->sortedFilterModel, &iter, TRUE, FALSE));
1281 }
1282 gtk_tree_path_free(path);
1283 }
1284 g_list_free(list);
1285 }
1286 }
1287
onMatchQueueClicked_gui(GtkMenuItem * item,gpointer data)1288 void Search::onMatchQueueClicked_gui(GtkMenuItem *item, gpointer data)
1289 {
1290 Search *s = (Search *)data;
1291
1292 if (gtk_tree_selection_count_selected_rows(s->selection) > 0)
1293 {
1294 GtkTreeIter iter;
1295 GtkTreePath *path;
1296 GList *list = gtk_tree_selection_get_selected_rows(s->selection, NULL);
1297 typedef Func4<Search, string, string, bool, string> F4;
1298
1299 for (GList *i = list; i; i = i->next)
1300 {
1301 path = (GtkTreePath *)i->data;
1302 if (gtk_tree_model_get_iter(s->sortedFilterModel, &iter, path))
1303 {
1304 bool parent = gtk_tree_model_iter_has_child(s->sortedFilterModel, &iter);
1305
1306 do
1307 {
1308 string cid = s->resultView.getString(&iter, "CID");
1309 string hubUrl = s->resultView.getString(&iter, "Hub URL");
1310 F4 *func = new F4(s, &Search::getFileList_client, cid, "", TRUE, hubUrl);
1311 WulforManager::get()->dispatchClientFunc(func);
1312 }
1313 while (parent && WulforUtil::getNextIter_gui(s->sortedFilterModel, &iter, TRUE, FALSE));
1314 }
1315 gtk_tree_path_free(path);
1316 }
1317 g_list_free(list);
1318 }
1319 }
1320
onPrivateMessageClicked_gui(GtkMenuItem * item,gpointer data)1321 void Search::onPrivateMessageClicked_gui(GtkMenuItem *item, gpointer data)
1322 {
1323 Search *s = (Search *)data;
1324
1325 if (gtk_tree_selection_count_selected_rows(s->selection) > 0)
1326 {
1327 GtkTreeIter iter;
1328 GtkTreePath *path;
1329 GList *list = gtk_tree_selection_get_selected_rows(s->selection, NULL);
1330
1331 for (GList *i = list; i; i = i->next)
1332 {
1333 path = (GtkTreePath *)i->data;
1334 if (gtk_tree_model_get_iter(s->sortedFilterModel, &iter, path))
1335 {
1336 bool parent = gtk_tree_model_iter_has_child(s->sortedFilterModel, &iter);
1337
1338 do
1339 {
1340 string cid = s->resultView.getString(&iter, "CID");
1341 string hubUrl = s->resultView.getString(&iter, "Hub URL");
1342 if (!cid.empty())
1343 WulforManager::get()->getMainWindow()->addPrivateMessage_gui(cid, hubUrl);
1344 }
1345 while (parent && WulforUtil::getNextIter_gui(s->sortedFilterModel, &iter, TRUE, FALSE));
1346 }
1347 gtk_tree_path_free(path);
1348 }
1349 g_list_free(list);
1350 }
1351 }
1352
onAddFavoriteUserClicked_gui(GtkMenuItem * item,gpointer data)1353 void Search::onAddFavoriteUserClicked_gui(GtkMenuItem *item, gpointer data)
1354 {
1355 Search *s = (Search *)data;
1356
1357 if (gtk_tree_selection_count_selected_rows(s->selection) > 0)
1358 {
1359 string cid;
1360 GtkTreeIter iter;
1361 GtkTreePath *path;
1362 GList *list = gtk_tree_selection_get_selected_rows(s->selection, NULL);
1363 typedef Func1<Search, string> F1;
1364 F1 *func;
1365
1366 for (GList *i = list; i; i = i->next)
1367 {
1368 path = (GtkTreePath *)i->data;
1369 if (gtk_tree_model_get_iter(s->sortedFilterModel, &iter, path))
1370 {
1371 bool parent = gtk_tree_model_iter_has_child(s->sortedFilterModel, &iter);
1372
1373 do
1374 {
1375 cid = s->resultView.getString(&iter, "CID");
1376 func = new F1(s, &Search::addFavUser_client, cid);
1377 WulforManager::get()->dispatchClientFunc(func);
1378 }
1379 while (parent && WulforUtil::getNextIter_gui(s->sortedFilterModel, &iter, TRUE, FALSE));
1380 }
1381 gtk_tree_path_free(path);
1382 }
1383 g_list_free(list);
1384 }
1385 }
1386
onGrantExtraSlotClicked_gui(GtkMenuItem * item,gpointer data)1387 void Search::onGrantExtraSlotClicked_gui(GtkMenuItem *item, gpointer data)
1388 {
1389 Search *s = (Search *)data;
1390
1391 if (gtk_tree_selection_count_selected_rows(s->selection) > 0)
1392 {
1393 GtkTreeIter iter;
1394 GtkTreePath *path;
1395 GList *list = gtk_tree_selection_get_selected_rows(s->selection, NULL);
1396 typedef Func2<Search, string, string> F2;
1397
1398 for (GList *i = list; i; i = i->next)
1399 {
1400 path = (GtkTreePath *)i->data;
1401 if (gtk_tree_model_get_iter(s->sortedFilterModel, &iter, path))
1402 {
1403 bool parent = gtk_tree_model_iter_has_child(s->sortedFilterModel, &iter);
1404
1405 do
1406 {
1407 string cid = s->resultView.getString(&iter, "CID");
1408 string hubUrl = s->resultView.getString(&iter, "Hub URL");
1409 F2 *func = new F2(s, &Search::grantSlot_client, cid, hubUrl);
1410 WulforManager::get()->dispatchClientFunc(func);
1411 }
1412 while (parent && WulforUtil::getNextIter_gui(s->sortedFilterModel, &iter, TRUE, FALSE));
1413 }
1414 gtk_tree_path_free(path);
1415 }
1416 g_list_free(list);
1417 }
1418 }
1419
onRemoveUserFromQueueClicked_gui(GtkMenuItem * item,gpointer data)1420 void Search::onRemoveUserFromQueueClicked_gui(GtkMenuItem *item, gpointer data)
1421 {
1422 Search *s = (Search *)data;
1423
1424 if (gtk_tree_selection_count_selected_rows(s->selection) > 0)
1425 {
1426 string cid;
1427 GtkTreeIter iter;
1428 GtkTreePath *path;
1429 GList *list = gtk_tree_selection_get_selected_rows(s->selection, NULL);
1430 typedef Func1<Search, string> F1;
1431 F1 *func;
1432
1433 for (GList *i = list; i; i = i->next)
1434 {
1435 path = (GtkTreePath *)i->data;
1436 if (gtk_tree_model_get_iter(s->sortedFilterModel, &iter, path))
1437 {
1438 bool parent = gtk_tree_model_iter_has_child(s->sortedFilterModel, &iter);
1439
1440 do
1441 {
1442 cid = s->resultView.getString(&iter, "CID");
1443 func = new F1(s, &Search::removeSource_client, cid);
1444 WulforManager::get()->dispatchClientFunc(func);
1445 }
1446 while (parent && WulforUtil::getNextIter_gui(s->sortedFilterModel, &iter, TRUE, FALSE));
1447 }
1448 gtk_tree_path_free(path);
1449 }
1450 g_list_free(list);
1451 }
1452 }
1453
1454 // Removing a row from treeStore still leaves the SearchResultPtr to results map. This way if a duplicate
1455 // result comes in later it won't be readded, before the results map is cleared with a new search.
onRemoveClicked_gui(GtkMenuItem * item,gpointer data)1456 void Search::onRemoveClicked_gui(GtkMenuItem *item, gpointer data)
1457 {
1458 Search *s = (Search *)data;
1459
1460 if (gtk_tree_selection_count_selected_rows(s->selection) > 0)
1461 {
1462 GtkTreeIter iter;
1463 GtkTreeIter filterIter;
1464 GtkTreePath *path;
1465 GList *list = gtk_tree_selection_get_selected_rows(s->selection, NULL);
1466 GList *refList = NULL;
1467
1468 // Convert it to list of GtkTreeRowReferences since modifying the model with a list of Paths is bad.
1469 for (GList *i = list; i; i = i->next)
1470 {
1471 path = (GtkTreePath *)i->data;
1472 refList = g_list_append(refList, gtk_tree_row_reference_new(s->sortedFilterModel, path));
1473 gtk_tree_path_free(path);
1474 }
1475 g_list_free(list);
1476
1477 for (GList *i = refList; i; i = i->next)
1478 {
1479 path = gtk_tree_row_reference_get_path((GtkTreeRowReference*)i->data);
1480 if (path != NULL)
1481 {
1482 if (gtk_tree_model_get_iter(s->sortedFilterModel, &iter, path))
1483 {
1484 // Remove the top-level node and it will remove any children nodes (if applicable)
1485 gtk_tree_model_sort_convert_iter_to_child_iter(GTK_TREE_MODEL_SORT(s->sortedFilterModel), &filterIter, &iter);
1486 gtk_tree_model_filter_convert_iter_to_child_iter(GTK_TREE_MODEL_FILTER(s->searchFilterModel), &iter, &filterIter);
1487 gtk_tree_store_remove(s->resultStore, &iter);
1488 }
1489 gtk_tree_path_free(path);
1490 }
1491 gtk_tree_row_reference_free((GtkTreeRowReference*)i->data);
1492 }
1493 g_list_free(refList);
1494 }
1495 }
1496
onCopyMagnetClicked_gui(GtkMenuItem * item,gpointer data)1497 void Search::onCopyMagnetClicked_gui(GtkMenuItem* item, gpointer data)
1498 {
1499 Search *s = (Search *)data;
1500
1501 if (gtk_tree_selection_count_selected_rows(s->selection) > 0)
1502 {
1503 int64_t size;
1504 string magnets, magnet, filename, tth;
1505 GtkTreeIter iter;
1506 GtkTreePath *path;
1507 GList *list = gtk_tree_selection_get_selected_rows(s->selection, NULL);
1508
1509 for (GList *i = list; i; i = i->next)
1510 {
1511 path = (GtkTreePath *)i->data;
1512 if (gtk_tree_model_get_iter(s->sortedFilterModel, &iter, path))
1513 {
1514 bool parent = gtk_tree_model_iter_has_child(s->sortedFilterModel, &iter);
1515
1516 do
1517 {
1518 filename = s->resultView.getString(&iter, "Filename");
1519 size = s->resultView.getValue<int64_t>(&iter, "Real Size");
1520 tth = s->resultView.getString(&iter, "TTH");
1521 magnet = WulforUtil::makeMagnet(filename, size, tth);
1522
1523 if (!magnet.empty())
1524 {
1525 if (!magnets.empty())
1526 magnets += '\n';
1527 magnets += magnet;
1528 }
1529 }
1530 while (parent && WulforUtil::getNextIter_gui(s->sortedFilterModel, &iter, TRUE, FALSE));
1531 }
1532 gtk_tree_path_free(path);
1533 }
1534 g_list_free(list);
1535
1536 if (!magnets.empty())
1537 gtk_clipboard_set_text(gtk_clipboard_get(GDK_SELECTION_CLIPBOARD), magnets.c_str(), magnets.length());
1538 }
1539 }
1540
parseSearchResult_gui(SearchResultPtr result,StringMap & resultMap)1541 void Search::parseSearchResult_gui(SearchResultPtr result, StringMap &resultMap)
1542 {
1543 if (result->getType() == SearchResult::TYPE_FILE)
1544 {
1545 string file = WulforUtil::linuxSeparator(result->getFile());
1546 if (file.rfind('/') == tstring::npos)
1547 {
1548 resultMap["Filename"] = file;
1549 }
1550 else
1551 {
1552 resultMap["Filename"] = Util::getFileName(file);
1553 resultMap["Path"] = Util::getFilePath(file);
1554 }
1555
1556 resultMap["File Order"] = "f" + resultMap["Filename"];
1557 resultMap["Type"] = Util::getFileExt(resultMap["Filename"]);
1558 if (!resultMap["Type"].empty() && resultMap["Type"][0] == '.')
1559 resultMap["Type"].erase(0, 1);
1560 resultMap["Size"] = Util::formatBytes(result->getSize());
1561 resultMap["Exact Size"] = Util::formatExactSize(result->getSize());
1562 resultMap["Icon"] = GTK_STOCK_FILE;
1563 resultMap["Shared"] = Util::toString(ShareManager::getInstance()->isTTHShared(result->getTTH()));
1564 }
1565 else
1566 {
1567 string path = WulforUtil::linuxSeparator(result->getFile());
1568 resultMap["Filename"] = WulforUtil::linuxSeparator(result->getFileName());
1569 resultMap["Path"] = Util::getFilePath(path.substr(0, path.length() - 1)); // getFilePath just returns path unless we chop the last / off
1570 if (resultMap["Path"].find("/") == string::npos)
1571 resultMap["Path"] = "";
1572 resultMap["File Order"] = "d" + resultMap["Filename"];
1573 resultMap["Type"] = _("Directory");
1574 resultMap["Icon"] = GTK_STOCK_DIRECTORY;
1575 resultMap["Shared"] = "0";
1576 if (result->getSize() > 0)
1577 {
1578 resultMap["Size"] = Util::formatBytes(result->getSize());
1579 resultMap["Exact Size"] = Util::formatExactSize(result->getSize());
1580 }
1581 }
1582
1583 resultMap["User"] = WulforUtil::getNicks(result->getUser());
1584 resultMap["CID"] = result->getUser()->getCID().toBase32();
1585 resultMap["Slots"] = result->getSlotString();
1586 resultMap["Connection"] = ClientManager::getInstance()->getConnection(result->getUser()->getCID());
1587 resultMap["Hub"] = result->getHubName().empty() ? result->getHubURL().c_str() : result->getHubName().c_str();
1588 resultMap["Hub URL"] = result->getHubURL();
1589 resultMap["IP"] = result->getIP();
1590 resultMap["Real Size"] = Util::toString(result->getSize());
1591 if (result->getType() == SearchResult::TYPE_FILE)
1592 resultMap["TTH"] = result->getTTH().toBase32();
1593
1594 // assumption: total slots is never above 999
1595 resultMap["Slots Order"] = Util::toString(-1000 * result->getFreeSlots() - result->getSlots());
1596 resultMap["Free Slots"] = Util::toString(result->getFreeSlots());
1597 }
1598
download_client(string target,string cid,string filename,int64_t size,string tth,string hubUrl)1599 void Search::download_client(string target, string cid, string filename, int64_t size, string tth, string hubUrl)
1600 {
1601 try
1602 {
1603 UserPtr user = ClientManager::getInstance()->findUser(CID(cid));
1604 if (user == NULL)
1605 return;
1606
1607 // Only files have a TTH
1608 if (!tth.empty())
1609 {
1610 string subdir = Util::getFileName(filename);
1611 QueueManager::getInstance()->add(target + subdir, size, TTHValue(tth), user, hubUrl);
1612 }
1613 else
1614 {
1615 string dir = WulforUtil::windowsSeparator(filename);
1616 QueueManager::getInstance()->addDirectory(dir, user, hubUrl, target);
1617 }
1618 }
1619 catch (const Exception&)
1620 {
1621 }
1622 }
1623
downloadDir_client(string target,string cid,string filename,string hubUrl)1624 void Search::downloadDir_client(string target, string cid, string filename, string hubUrl)
1625 {
1626 try
1627 {
1628 string dir;
1629
1630 // If it's a file (directories are assumed to end in '/')
1631 if (filename[filename.length() - 1] != PATH_SEPARATOR)
1632 {
1633 dir = WulforUtil::windowsSeparator(Util::getFilePath(filename));
1634 }
1635 else
1636 {
1637 dir = WulforUtil::windowsSeparator(filename);
1638 }
1639
1640 UserPtr user = ClientManager::getInstance()->findUser(CID(cid));
1641 if (user != NULL)
1642 {
1643 QueueManager::getInstance()->addDirectory(dir, user, hubUrl, target);
1644 }
1645 }
1646 catch (const Exception&)
1647 {
1648 }
1649 }
1650
addSource_client(string source,string cid,int64_t size,string tth,string hubUrl)1651 void Search::addSource_client(string source, string cid, int64_t size, string tth, string hubUrl)
1652 {
1653 try
1654 {
1655 UserPtr user = ClientManager::getInstance()->findUser(CID(cid));
1656 if (!tth.empty() && user != NULL)
1657 {
1658 QueueManager::getInstance()->add(source, size, TTHValue(tth), user, hubUrl);
1659 }
1660 }
1661 catch (const Exception&)
1662 {
1663 }
1664 }
1665
getFileList_client(string cid,string dir,bool match,string hubUrl)1666 void Search::getFileList_client(string cid, string dir, bool match, string hubUrl)
1667 {
1668 if (!cid.empty())
1669 {
1670 try
1671 {
1672 UserPtr user = ClientManager::getInstance()->findUser(CID(cid));
1673 if (user)
1674 {
1675 QueueItem::FileFlags flags;
1676 if (match)
1677 flags = QueueItem::FLAG_MATCH_QUEUE;
1678 else
1679 flags = QueueItem::FLAG_CLIENT_VIEW;
1680
1681 QueueManager::getInstance()->addList(user, hubUrl, flags, dir);
1682 }
1683 }
1684 catch (const Exception&)
1685 {
1686 }
1687 }
1688 }
1689
grantSlot_client(string cid,string hubUrl)1690 void Search::grantSlot_client(string cid, string hubUrl)
1691 {
1692 if (!cid.empty())
1693 {
1694 UserPtr user = ClientManager::getInstance()->findUser(CID(cid));
1695 if (user)
1696 UploadManager::getInstance()->reserveSlot(user, hubUrl);
1697 }
1698 }
1699
addFavUser_client(string cid)1700 void Search::addFavUser_client(string cid)
1701 {
1702 if (!cid.empty())
1703 {
1704 UserPtr user = ClientManager::getInstance()->findUser(CID(cid));
1705 if (user)
1706 FavoriteManager::getInstance()->addFavoriteUser(user);
1707 }
1708 }
1709
removeSource_client(string cid)1710 void Search::removeSource_client(string cid)
1711 {
1712 if (!cid.empty())
1713 {
1714 UserPtr user = ClientManager::getInstance()->findUser(CID(cid));
1715 if (user)
1716 QueueManager::getInstance()->removeSource(user, QueueItem::Source::FLAG_REMOVED);
1717 }
1718 }
1719
on(ClientManagerListener::ClientConnected,Client * client)1720 void Search::on(ClientManagerListener::ClientConnected, Client *client) throw()
1721 {
1722 if (client)
1723 {
1724 typedef Func2<Search, string, string> F2;
1725 F2 *func = new F2(this, &Search::addHub_gui, client->getHubName(), client->getHubUrl());
1726 WulforManager::get()->dispatchGuiFunc(func);
1727 }
1728 }
1729
on(ClientManagerListener::ClientUpdated,Client * client)1730 void Search::on(ClientManagerListener::ClientUpdated, Client *client) throw()
1731 {
1732 if (client)
1733 {
1734 typedef Func2<Search, string, string> F2;
1735 F2 *func = new F2(this, &Search::modifyHub_gui, client->getHubName(), client->getHubUrl());
1736 WulforManager::get()->dispatchGuiFunc(func);
1737 }
1738 }
1739
on(ClientManagerListener::ClientDisconnected,Client * client)1740 void Search::on(ClientManagerListener::ClientDisconnected, Client *client) throw()
1741 {
1742 if (client)
1743 {
1744 typedef Func1<Search, string> F1;
1745 F1 *func = new F1(this, &Search::removeHub_gui, client->getHubUrl());
1746 WulforManager::get()->dispatchGuiFunc(func);
1747 }
1748 }
1749
on(SearchManagerListener::SR,const SearchResultPtr & result)1750 void Search::on(SearchManagerListener::SR, const SearchResultPtr& result) throw()
1751 {
1752 if (searchlist.empty() || result == NULL)
1753 return;
1754
1755 if (isHash)
1756 {
1757 if (result->getType() != SearchResult::TYPE_FILE || TTHValue(searchlist[0]) != result->getTTH())
1758 {
1759 ++droppedResult;
1760 Func0<Search> *func = new Func0<Search>(this, &Search::updateStats_gui);
1761 WulforManager::get()->dispatchGuiFunc(func);
1762 return;
1763 }
1764 }
1765 else
1766 {
1767 for (TStringIter i = searchlist.begin(); i != searchlist.end(); ++i)
1768 {
1769 if ((*i->begin() != '-' && Util::findSubString(result->getFile(), *i) == (string::size_type)-1) ||
1770 (*i->begin() == '-' && i->size() != 1 && Util::findSubString(result->getFile(), i->substr(1)) != (string::size_type)-1))
1771 {
1772 ++droppedResult;
1773 Func0<Search> *func = new Func0<Search>(this, &Search::updateStats_gui);
1774 WulforManager::get()->dispatchGuiFunc(func);
1775 return;
1776 }
1777 }
1778 }
1779
1780 typedef Func1<Search, SearchResultPtr> F1;
1781 F1 *func = new F1(this, &Search::addResult_gui, result);
1782 WulforManager::get()->dispatchGuiFunc(func);
1783 }
1784
1785 // Filtering causes Gtk-CRITICAL assertion failure, when last item is removed
1786 // see. http://bugzilla.gnome.org/show_bug.cgi?id=464173
searchFilterFunc_gui(GtkTreeModel * model,GtkTreeIter * iter,gpointer data)1787 gboolean Search::searchFilterFunc_gui(GtkTreeModel *model, GtkTreeIter *iter, gpointer data)
1788 {
1789 Search *s = (Search *)data;
1790 dcassert(model == GTK_TREE_MODEL(s->resultStore));
1791
1792 // Enabler filtering only if search within local results is checked
1793 if (!gtk_toggle_button_get_active(GTK_TOGGLE_BUTTON(s->getWidget("checkbuttonFilter"))))
1794 return TRUE;
1795
1796 // Grouping shouldn't be enabled while filtering, but just in case...
1797 if (gtk_tree_model_iter_has_child(model, iter))
1798 return TRUE;
1799
1800 string hub = s->resultView.getString(iter, "Hub URL", model);
1801 GtkTreeIter hubIter;
1802 bool valid = gtk_tree_model_get_iter_first(GTK_TREE_MODEL(s->hubStore), &hubIter);
1803 while (valid)
1804 {
1805 if (hub == s->hubView.getString(&hubIter, "Url"))
1806 {
1807 if (!s->hubView.getValue<gboolean>(&hubIter, "Search"))
1808 return FALSE;
1809 else
1810 break;
1811 }
1812 valid = gtk_tree_model_iter_next(GTK_TREE_MODEL(s->hubStore), &hubIter);
1813 }
1814
1815 // Filter based on free slots.
1816 gint freeSlots = s->resultView.getValue<gint>(iter, "Free Slots", model);
1817 if (s->onlyFree && freeSlots < 1)
1818 return FALSE;
1819
1820 // Hide results already in share
1821 if (gtk_toggle_button_get_active(GTK_TOGGLE_BUTTON(s->getWidget("checkbuttonShared"))) &&
1822 s->resultView.getValue<gboolean>(iter, "Shared", model) == TRUE)
1823 return FALSE;
1824
1825 // Filter based on search terms.
1826 string filter = Text::toLower(gtk_entry_get_text(GTK_ENTRY(s->searchEntry)));
1827 TStringList filterList = StringTokenizer<tstring>(filter, ' ').getTokens();
1828 string filename = Text::toLower(s->resultView.getString(iter, "Filename", model));
1829 string path = Text::toLower(s->resultView.getString(iter, "Path", model));
1830 for (TStringList::const_iterator term = filterList.begin(); term != filterList.end(); ++term)
1831 {
1832 if ((*term)[0] == '-')
1833 {
1834 if (filename.find((*term).substr(1)) != string::npos)
1835 return FALSE;
1836 else if (path.find((*term).substr(1)) != string::npos)
1837 return FALSE;
1838 }
1839 else if (filename.find(*term) == string::npos && path.find(*term) == string::npos)
1840 return FALSE;
1841 }
1842
1843 // Filter based on file size.
1844 double filterSize = Util::toDouble(gtk_entry_get_text(GTK_ENTRY(s->getWidget("entrySize"))));
1845 if (filterSize > 0)
1846 {
1847 switch (gtk_combo_box_get_active(GTK_COMBO_BOX(s->getWidget("comboboxUnit"))))
1848 {
1849 case 1:
1850 filterSize *= 1024.0;
1851 break;
1852 case 2:
1853 filterSize *= 1024.0 * 1024.0;
1854 break;
1855 case 3:
1856 filterSize *= 1024.0 * 1024.0 * 1024.0;
1857 break;
1858 }
1859
1860 int64_t size = s->resultView.getValue<int64_t>(iter, "Real Size", model);
1861
1862 switch (gtk_combo_box_get_active(GTK_COMBO_BOX(s->getWidget("comboboxSize"))))
1863 {
1864 case 0:
1865 if (size != filterSize)
1866 return FALSE;
1867 break;
1868 case 1:
1869 if (size < filterSize)
1870 return FALSE;
1871 break;
1872 case 2:
1873 if (size > filterSize)
1874 return FALSE;
1875 }
1876 }
1877
1878 int type = gtk_combo_box_get_active(GTK_COMBO_BOX(s->getWidget("comboboxFile")));
1879 if (type != SearchManager::TYPE_ANY && type != ShareManager::getInstance()->getType(filename))
1880 return FALSE;
1881
1882 return TRUE;
1883 }
1884
1885