1 /*
2 * Copyright © 2009-2010 freedcpp, http://code.google.com/p/freedcpp
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 "searchspy.hh"
23 #include <dcpp/SearchManager.h>
24 #include <dcpp/TimerManager.h>
25 #include <dcpp/Util.h>
26 #include "settingsmanager.hh"
27 #include "search.hh"
28 #include "wulformanager.hh"
29 #include "WulforUtil.hh"
30
31 using namespace std;
32 using namespace dcpp;
33
SearchSpy()34 SearchSpy::SearchSpy():
35 BookEntry(Entry::SEARCH_SPY, _("Search Spy"), "searchspy.ui")
36 {
37 #if !GTK_CHECK_VERSION(3,0,0)
38 gtk_statusbar_set_has_resize_grip (GTK_STATUSBAR(getWidget("statusbar")),FALSE);
39 #endif
40
41 FrameSize = (SearchType)WGETI("search-spy-frame");
42 Waiting = (guint)WGETI("search-spy-waiting");
43 Top = (guint)WGETI("search-spy-top");
44
45 // Configure the dialog
46 gtk_toggle_button_set_active(GTK_TOGGLE_BUTTON(getWidget("ignoreTTHSearchCheckButton")), WGETB("spyframe-ignore-tth-searches"));
47 gtk_window_set_transient_for(GTK_WINDOW(getWidget("TopSearchDialog")), GTK_WINDOW(WulforManager::get()->getMainWindow()->getContainer()));
48 gtk_spin_button_set_value(GTK_SPIN_BUTTON(getWidget("frameSpinButton")), (double)FrameSize);
49 gtk_spin_button_set_value(GTK_SPIN_BUTTON(getWidget("waitingSpinButton")), (double)Waiting);
50 gtk_spin_button_set_value(GTK_SPIN_BUTTON(getWidget("topSpinButton")), (double)Top);
51
52 // menu
53 g_object_ref_sink(getWidget("menu"));
54
55 // Initialize search list treeview
56 searchView.setView(GTK_TREE_VIEW(getWidget("searchSpyView")), TRUE, "searchspy");
57 searchView.insertColumn(_("Search String"), G_TYPE_STRING, TreeView::ICON_STRING_TEXT_COLOR, 305, "icon", "color");
58 searchView.insertColumn(_("Count"), G_TYPE_STRING, TreeView::STRING, 70);
59 searchView.insertColumn(_("Time"), G_TYPE_STRING, TreeView::STRING, 90);
60 searchView.insertColumn(_("Status"), G_TYPE_STRING, TreeView::STRING, 90);
61 searchView.insertHiddenColumn("type", G_TYPE_STRING);
62 searchView.insertHiddenColumn("count", G_TYPE_UINT);
63 searchView.insertHiddenColumn("tick", G_TYPE_UINT64);
64 searchView.insertHiddenColumn("icon", G_TYPE_STRING);
65 searchView.insertHiddenColumn("order", G_TYPE_STRING);
66 searchView.insertHiddenColumn("color", G_TYPE_STRING);
67 searchView.finalize();
68
69 searchStore = gtk_list_store_newv(searchView.getColCount(), searchView.getGTypes());
70 gtk_tree_view_set_model(searchView.get(), GTK_TREE_MODEL(searchStore));
71 g_object_unref(searchStore);
72
73 searchSelection = gtk_tree_view_get_selection(searchView.get());
74 gtk_tree_selection_set_mode(searchSelection, GTK_SELECTION_MULTIPLE);
75 searchView.setSortColumn_gui(_("Search String"), "count");
76 gtk_tree_sortable_set_sort_column_id(GTK_TREE_SORTABLE(searchStore), searchView.col("count"), GTK_SORT_DESCENDING);
77 gtk_tree_view_column_set_sort_indicator(gtk_tree_view_get_column(searchView.get(), searchView.col(_("Search String"))), TRUE);
78 gtk_tree_view_set_fixed_height_mode(searchView.get(), TRUE);
79
80 topView.setView(GTK_TREE_VIEW(getWidget("topView")));
81 topView.insertColumn(_("Search String"), G_TYPE_STRING, TreeView::STRING, -1);
82 topView.insertHiddenColumn("type", G_TYPE_STRING);
83 topView.finalize();
84
85 topStore = gtk_list_store_newv(topView.getColCount(), topView.getGTypes());
86 gtk_tree_view_set_model(topView.get(), GTK_TREE_MODEL(topStore));
87 g_object_unref(topStore);
88
89 g_signal_connect(getWidget("searchItem"), "activate", G_CALLBACK(onSearchItemClicked_gui), (gpointer)this);
90 g_signal_connect(getWidget("removeItem"), "activate", G_CALLBACK(onRemoveItemClicked_gui), (gpointer)this);
91 g_signal_connect(getWidget("clearFrameButton"), "clicked", G_CALLBACK(onClearFrameClicked_gui), (gpointer)this);
92 g_signal_connect(getWidget("updateFrameButton"), "clicked", G_CALLBACK(onUpdateFrameClicked_gui), (gpointer)this);
93 g_signal_connect(getWidget("showTopButton"), "clicked", G_CALLBACK(onShowTopClicked_gui), (gpointer)this);
94 g_signal_connect(getWidget("clearTopButton"), "clicked", G_CALLBACK(onClearTopClicked_gui), (gpointer)this);
95 g_signal_connect(getWidget("searchTopButton"), "clicked", G_CALLBACK(onSearchTopClicked_gui), (gpointer)this);
96 g_signal_connect(getWidget("removeTopButton"), "clicked", G_CALLBACK(onRemoveTopClicked_gui), (gpointer)this);
97 g_signal_connect(getWidget("ignoreTTHSearchCheckButton"), "toggled", G_CALLBACK(onIgnoreTTHSearchToggled_gui), (gpointer)this);
98 g_signal_connect(searchView.get(), "button-press-event", G_CALLBACK(onButtonPressed_gui), (gpointer)this);
99 g_signal_connect(searchView.get(), "button-release-event", G_CALLBACK(onButtonReleased_gui), (gpointer)this);
100 g_signal_connect(searchView.get(), "key-release-event", G_CALLBACK(onKeyReleased_gui), (gpointer)this);
101 g_signal_connect(getWidget("okButton"), "clicked", G_CALLBACK(onOKButtonClicked_gui), (gpointer)this);
102
103 aSearchColor = WGETS("search-spy-a-color");
104 tSearchColor = WGETS("search-spy-t-color");
105 qSearchColor = WGETS("search-spy-q-color");
106 cSearchColor = WGETS("search-spy-c-color");
107 rSearchColor = WGETS("search-spy-r-color");
108 }
109
~SearchSpy()110 SearchSpy::~SearchSpy()
111 {
112 WSET("search-spy-frame", (int)gtk_spin_button_get_value(GTK_SPIN_BUTTON(getWidget("frameSpinButton"))));
113 WSET("search-spy-waiting", (int)gtk_spin_button_get_value(GTK_SPIN_BUTTON(getWidget("waitingSpinButton"))));
114 WSET("search-spy-top", (int)gtk_spin_button_get_value(GTK_SPIN_BUTTON(getWidget("topSpinButton"))));
115
116 gtk_widget_destroy(getWidget("TopSearchDialog"));
117 g_object_unref(getWidget("menu"));
118
119 TimerManager::getInstance()->removeListener(this);
120 ClientManager::getInstance()->removeListener(this);
121 }
122
show()123 void SearchSpy::show()
124 {
125 ClientManager::getInstance()->addListener(this);
126 TimerManager::getInstance()->addListener(this);
127 }
128
preferences_gui()129 void SearchSpy::preferences_gui()
130 {
131 FrameSize = (SearchType)WGETI("search-spy-frame");
132 Waiting = (guint)WGETI("search-spy-waiting");
133 Top = (guint)WGETI("search-spy-top");
134
135 resetFrame();
136
137 // reset colors
138 aSearchColor = WGETS("search-spy-a-color");
139 tSearchColor = WGETS("search-spy-t-color");
140 qSearchColor = WGETS("search-spy-q-color");
141 cSearchColor = WGETS("search-spy-c-color");
142 rSearchColor = WGETS("search-spy-r-color");
143
144 string color, order;
145 GtkTreeIter iter;
146
147 for (auto it = searchIters.begin(); it != searchIters.end(); ++it)
148 {
149 iter = it->second;
150 order = searchView.getString(&iter, "order");
151 guint count = searchView.getValue<guint>(&iter, "count");
152
153 // reset count
154 if (count > Top)
155 {
156 gtk_list_store_set(searchStore, &iter,
157 searchView.col(_("Count")), Util::toString(Top).c_str(),
158 searchView.col("count"), Top,
159 -1);
160 }
161
162 switch (order[0])
163 {
164 case 'a': color = aSearchColor; break;
165 case 'c': color = cSearchColor; break;
166 case 'r': color = rSearchColor; break;
167 case 't': color = tSearchColor; break;
168 case 'q': color = qSearchColor; break;
169 }
170 gtk_list_store_set(searchStore, &iter, searchView.col("color"), color.c_str(), -1);
171 }
172
173 // reset spin button
174 gtk_spin_button_set_value(GTK_SPIN_BUTTON(getWidget("frameSpinButton")), (double)FrameSize);
175 gtk_spin_button_set_value(GTK_SPIN_BUTTON(getWidget("waitingSpinButton")), (double)Waiting);
176 gtk_spin_button_set_value(GTK_SPIN_BUTTON(getWidget("topSpinButton")), (double)Top);
177 }
178
resetFrame()179 void SearchSpy::resetFrame()
180 {
181 GtkTreeIter iter;
182
183 if (FrameSize > 0 && searchIters.size() > FrameSize)
184 {
185 SearchType i = 0;
186 gtk_tree_selection_select_all(searchSelection);
187
188 for (auto it = searchIters.begin(); it != searchIters.end(); ++it)
189 {
190 if (++i > FrameSize)
191 break;
192
193 iter = it->second;
194 gtk_tree_selection_unselect_iter(searchSelection, &iter);
195 }
196 onRemoveItemClicked_gui(NULL, (gpointer)this);
197 }
198 }
199
findIter_gui(const string & search,GtkTreeIter * iter)200 bool SearchSpy::findIter_gui(const string &search, GtkTreeIter *iter)
201 {
202 auto it = searchIters.find(search);
203
204 if (it != searchIters.end())
205 {
206 if (iter)
207 *iter = it->second;
208
209 return TRUE;
210 }
211
212 return FALSE;
213 }
214
addTop_gui(const string & search,const string & type)215 void SearchSpy::addTop_gui(const string &search, const string &type)
216 {
217 GtkTreeIter iter;
218 GtkTreeModel *m = GTK_TREE_MODEL(topStore);
219 gboolean valid = gtk_tree_model_get_iter_first(m, &iter);
220
221 while (valid)
222 {
223 string line = topView.getString(&iter, _("Search String"));
224
225 if (search == line)
226 {
227 return;
228 }
229 valid = gtk_tree_model_iter_next(m, &iter);
230 }
231
232 gtk_list_store_append(topStore, &iter);
233 gtk_list_store_set(topStore, &iter,
234 topView.col(_("Search String")), search.c_str(),
235 topView.col("type"), type.c_str(),
236 -1);
237
238 if (WGETB("bold-search-spy"))
239 setUrgent_gui();
240 }
241
updateFrameSearch_gui(const string search,const string type)242 void SearchSpy::updateFrameSearch_gui(const string search, const string type)
243 {
244 g_return_if_fail(FrameSize > 0 && FrameSize <= 256);
245
246 GtkTreeIter iter;
247
248 if (findIter_gui(search, &iter))
249 {
250 uint64_t tick = GET_TICK();
251
252 if (searchView.getString(&iter, "order")[0] == 't')
253 {
254 updateFrameStatus_gui(NULL, tick);
255 return;
256 }
257
258 string time = Util::formatTime("%H:%M:%S", GET_TIME());
259 guint count = searchView.getValue<guint>(&iter, "count");
260 string order = "c";
261
262 if (count >= Top)
263 {
264 addTop_gui(search, type);
265
266 count = 0;
267 order = "t";
268 }
269 count++;
270 gtk_list_store_set(searchStore, &iter,
271 searchView.col(_("Count")), Util::toString(count).c_str(),
272 searchView.col(_("Time")), time.c_str(),
273 searchView.col("count"), count,
274 searchView.col("tick"), tick,
275 searchView.col("order"), order.c_str(),
276 -1);
277 updateFrameStatus_gui(NULL, tick);
278 }
279 else
280 {
281 string time = Util::formatTime("%H:%M:%S", GET_TIME());
282 uint64_t tick = GET_TICK();
283
284 if (searchIters.size() >= FrameSize)
285 {
286 if (updateFrameStatus_gui(&iter, tick))
287 {
288 string oldstring = searchView.getString(&iter, _("Search String"));
289 searchIters.erase(oldstring);
290 searchIters.insert(SearchIters::value_type(search, iter));
291
292 tick = GET_TICK();
293
294 gtk_list_store_set(searchStore, &iter,
295 searchView.col(_("Search String")), search.c_str(),
296 searchView.col(_("Count")), "1",
297 searchView.col(_("Time")), time.c_str(),
298 searchView.col(_("Status")), _("waiting..."),
299 searchView.col("type"), type.c_str(),
300 searchView.col("count"), 1,
301 searchView.col("tick"), tick,
302 searchView.col("icon"), GTK_STOCK_FIND,
303 searchView.col("order"), "r",
304 searchView.col("color"), rSearchColor.c_str(),
305 -1);
306 }
307 return;
308 }
309
310 gtk_list_store_insert_with_values(searchStore, &iter, searchIters.size(),
311 searchView.col(_("Search String")), search.c_str(),
312 searchView.col(_("Count")), "1",
313 searchView.col(_("Time")), time.c_str(),
314 searchView.col("type"), type.c_str(),
315 searchView.col("count"), 1,
316 searchView.col("tick"), tick,
317 searchView.col("order"), "a",
318 -1);
319
320 searchIters.insert(SearchIters::value_type(search, iter));
321 updateFrameStatus_gui(NULL, tick);
322 }
323 }
324
updateFrameStatus_gui(GtkTreeIter * iter,uint64_t tick)325 bool SearchSpy::updateFrameStatus_gui(GtkTreeIter *iter, uint64_t tick)
326 {
327 if(!tick)
328 tick = GET_TICK();
329
330 uint64_t second = (uint64_t)Waiting * 1000;
331 bool n = FALSE;
332 string status, icon;
333 GtkTreeIter itree;
334 string color;
335
336 for (auto it = searchIters.begin(); it != searchIters.end(); ++it)
337 {
338 itree = it->second;
339 uint64_t gettick = searchView.getValue<uint64_t>(&itree, "tick");
340 string order = searchView.getString(&itree, "order");
341
342 dcassert(tick >= gettick);
343
344 if (tick - gettick > second)
345 {
346 if (iter)
347 {
348 *iter = itree;
349 n = TRUE;
350 }
351 status = "?";
352 icon = GTK_STOCK_DIALOG_QUESTION;
353
354 color = qSearchColor;
355 gtk_list_store_set(searchStore, &itree, searchView.col("order"), "q", -1);
356 }
357 else
358 {
359 if (order[0] == 't')
360 {
361 status = _("top...");
362 icon = GTK_STOCK_DIALOG_QUESTION;
363 }
364 else
365 {
366 status = _("waiting...");
367 icon = GTK_STOCK_FIND;
368 }
369
370 switch (order[0])
371 {
372 case 'a': color = aSearchColor; break;
373 case 'c': color = cSearchColor; break;
374 case 'r': color = rSearchColor; break;
375 case 't': color = tSearchColor; break;
376 default: color = qSearchColor; // fix don't know color
377 }
378 }
379 gtk_list_store_set(searchStore, &itree,
380 searchView.col(_("Status")), status.c_str(),
381 searchView.col("icon"), icon.c_str(),
382 searchView.col("color"), color.c_str(),
383 -1);
384 }
385
386 return n;
387 }
388
updateFrameStatus_gui()389 void SearchSpy::updateFrameStatus_gui()
390 {
391 updateFrameStatus_gui(NULL, uint64_t(0));
392 setStatus_gui(_("Update frame search"));
393 }
394
setStatus_gui(const string text)395 void SearchSpy::setStatus_gui(const string text)
396 {
397 if (!text.empty())
398 {
399 GtkWidget *status = getWidget("statusbar");
400 gtk_statusbar_pop(GTK_STATUSBAR(status), 0);
401 gtk_statusbar_push(GTK_STATUSBAR(status), 0, ("[" + Util::getShortTimeString() + "] " + text).c_str());
402 }
403 }
404
onOKButtonClicked_gui(GtkWidget * widget,gpointer data)405 void SearchSpy::onOKButtonClicked_gui(GtkWidget *widget, gpointer data)
406 {
407 SearchSpy *s = (SearchSpy *) data;
408
409 s->FrameSize = (SearchType)gtk_spin_button_get_value(GTK_SPIN_BUTTON(s->getWidget("frameSpinButton")));
410 s->Waiting = (guint)gtk_spin_button_get_value(GTK_SPIN_BUTTON(s->getWidget("waitingSpinButton")));
411 s->Top = (guint)gtk_spin_button_get_value(GTK_SPIN_BUTTON(s->getWidget("topSpinButton")));
412 s->resetFrame();
413 s->resetCount();
414
415 s->setStatus_gui(_("top/waiting/frame: ") + Util::toString(s->Top) + "/" + Util::toString(s->Waiting) + "/" +
416 Util::toString(s->FrameSize));
417
418 WSET("search-spy-frame", int(s->FrameSize));
419 WSET("search-spy-waiting", int(s->Waiting));
420 WSET("search-spy-top", int(s->Top));
421 }
422
resetCount()423 void SearchSpy::resetCount()
424 {
425 GtkTreeIter iter;
426 for (auto it = searchIters.begin(); it != searchIters.end(); ++it)
427 {
428 iter = it->second;
429 guint count = searchView.getValue<guint>(&iter, "count");
430
431 if (count > Top)
432 {
433 gtk_list_store_set(searchStore, &iter,
434 searchView.col(_("Count")), Util::toString(Top).c_str(),
435 searchView.col("count"), Top,
436 -1);
437 }
438 }
439 }
440
onShowTopClicked_gui(GtkWidget * widget,gpointer data)441 void SearchSpy::onShowTopClicked_gui(GtkWidget *widget, gpointer data)
442 {
443 SearchSpy *s = (SearchSpy *)data;
444
445 GtkWidget *dialog = s->getWidget("TopSearchDialog");
446 gint response = gtk_dialog_run(GTK_DIALOG(dialog));
447
448 // if the dialog gets programmatically destroyed.
449 if (response == GTK_RESPONSE_NONE)
450 return;
451 gtk_widget_hide(dialog);
452 }
453
onClearTopClicked_gui(GtkWidget * widget,gpointer data)454 void SearchSpy::onClearTopClicked_gui(GtkWidget *widget, gpointer data)
455 {
456 SearchSpy *s = (SearchSpy *)data;
457 gtk_list_store_clear(s->topStore);
458 }
459
onSearchTopClicked_gui(GtkWidget * widget,gpointer data)460 void SearchSpy::onSearchTopClicked_gui(GtkWidget *widget, gpointer data)
461 {
462 SearchSpy *s = (SearchSpy *)data;
463
464 GtkTreeIter iter;
465 GtkTreeSelection *selection = gtk_tree_view_get_selection(s->topView.get());
466
467 if (gtk_tree_selection_get_selected(selection, NULL, &iter))
468 {
469 string type = s->topView.getString(&iter, "type");
470 string search = s->topView.getString(&iter, _("Search String"));
471 Search *ss = WulforManager::get()->getMainWindow()->addSearch_gui();
472
473 if (type[0] == 't')
474 {
475 ss->putValue_gui(search, 0, SearchManager::SIZE_DONTCARE, SearchManager::TYPE_TTH);
476 }
477 else if (type[0] == 's')
478 {
479 ss->putValue_gui(search, 0, SearchManager::SIZE_DONTCARE, SearchManager::TYPE_ANY);
480 }
481 }
482 }
483
onRemoveTopClicked_gui(GtkWidget * widget,gpointer data)484 void SearchSpy::onRemoveTopClicked_gui(GtkWidget *widget, gpointer data)
485 {
486 SearchSpy *s = (SearchSpy *)data;
487
488 GtkTreeIter iter;
489 GtkTreeSelection *selection = gtk_tree_view_get_selection(s->topView.get());
490
491 if (gtk_tree_selection_get_selected(selection, NULL, &iter))
492 {
493 gtk_list_store_remove(s->topStore, &iter);
494 }
495 }
496
onClearFrameClicked_gui(GtkWidget * widget,gpointer data)497 void SearchSpy::onClearFrameClicked_gui(GtkWidget *widget, gpointer data)
498 {
499 SearchSpy *s = (SearchSpy *)data;
500
501 gtk_list_store_clear(s->searchStore);
502 s->searchIters.clear();
503 s->setStatus_gui(_("Clear frame search"));
504 }
505
onUpdateFrameClicked_gui(GtkWidget * widget,gpointer data)506 void SearchSpy::onUpdateFrameClicked_gui(GtkWidget *widget, gpointer data)
507 {
508 SearchSpy *s = (SearchSpy *)data;
509
510 s->updateFrameStatus_gui();
511 }
512
onIgnoreTTHSearchToggled_gui(GtkWidget * widget,gpointer data)513 void SearchSpy::onIgnoreTTHSearchToggled_gui(GtkWidget *widget, gpointer data)
514 {
515 gboolean toggle = gtk_toggle_button_get_active(GTK_TOGGLE_BUTTON(widget));
516 WSET("spyframe-ignore-tth-searches",toggle);
517 }
518
onRemoveItemClicked_gui(GtkMenuItem * item,gpointer data)519 void SearchSpy::onRemoveItemClicked_gui(GtkMenuItem *item, gpointer data)
520 {
521 SearchSpy *s = (SearchSpy *)data;
522
523 if (gtk_tree_selection_count_selected_rows(s->searchSelection) > 0)
524 {
525 StringList search;
526 GtkTreeIter iter;
527 GtkTreePath *path;
528 GList *list = gtk_tree_selection_get_selected_rows(s->searchSelection, NULL);
529
530 for (GList *i = list; i; i = i->next)
531 {
532 path = (GtkTreePath *) i->data;
533 if (gtk_tree_model_get_iter(GTK_TREE_MODEL(s->searchStore), &iter, path))
534 {
535 search.push_back(s->searchView.getString(&iter, _("Search String")));
536 }
537 gtk_tree_path_free(path);
538 }
539 g_list_free(list);
540
541 for (StringIterC it = search.begin(); it != search.end(); ++it)
542 {
543 if (s->findIter_gui(*it, &iter))
544 {
545 gtk_list_store_remove(s->searchStore, &iter);
546 s->searchIters.erase(*it);
547 }
548 }
549 }
550 }
551
onSearchItemClicked_gui(GtkMenuItem * item,gpointer data)552 void SearchSpy::onSearchItemClicked_gui(GtkMenuItem *item, gpointer data)
553 {
554 SearchSpy *s = (SearchSpy *)data;
555
556 if (gtk_tree_selection_count_selected_rows(s->searchSelection) == 1)
557 {
558 GList *list = gtk_tree_selection_get_selected_rows(s->searchSelection, NULL);
559
560 if (list)
561 {
562 GtkTreeIter iter;
563 GtkTreePath *path = (GtkTreePath *) list->data;
564
565 if (gtk_tree_model_get_iter(GTK_TREE_MODEL(s->searchStore), &iter, path))
566 {
567 string type = s->searchView.getString(&iter, "type");
568 string search = s->searchView.getString(&iter, _("Search String"));
569 Search *ss = WulforManager::get()->getMainWindow()->addSearch_gui();
570
571 if (type[0] == 't')
572 {
573 ss->putValue_gui(search, 0, SearchManager::SIZE_DONTCARE, SearchManager::TYPE_TTH);
574 }
575 else if (type[0] == 's')
576 {
577 ss->putValue_gui(search, 0, SearchManager::SIZE_DONTCARE, SearchManager::TYPE_ANY);
578 }
579 }
580 gtk_tree_path_free(path);
581 }
582 g_list_free(list);
583 }
584 }
585
onButtonPressed_gui(GtkWidget * widget,GdkEventButton * event,gpointer data)586 gboolean SearchSpy::onButtonPressed_gui(GtkWidget *widget, GdkEventButton *event, gpointer data)
587 {
588 SearchSpy *s = (SearchSpy *)data;
589 s->previous = event->type;
590
591 if (event->button == 3)
592 {
593 GtkTreePath *path;
594
595 if (gtk_tree_view_get_path_at_pos(s->searchView.get(), (gint)event->x, (gint)event->y, &path, NULL, NULL, NULL))
596 {
597 bool selected = gtk_tree_selection_path_is_selected(s->searchSelection, path);
598 gtk_tree_path_free(path);
599
600 if (selected)
601 return TRUE;
602 }
603 }
604 return FALSE;
605 }
606
onButtonReleased_gui(GtkWidget * widget,GdkEventButton * event,gpointer data)607 gboolean SearchSpy::onButtonReleased_gui(GtkWidget *widget, GdkEventButton *event, gpointer data)
608 {
609 SearchSpy *s = (SearchSpy *)data;
610
611 if (gtk_tree_selection_count_selected_rows(s->searchSelection) > 0)
612 {
613 if (event->button == 1 && s->previous == GDK_2BUTTON_PRESS)
614 {
615 // search string/tth
616 s->onSearchItemClicked_gui(NULL, data);
617 }
618 else if (event->button == 3 && event->type == GDK_BUTTON_RELEASE)
619 {
620 // show menu
621 gtk_menu_popup(GTK_MENU(s->getWidget("menu")), NULL, NULL, NULL, NULL, 0, gtk_get_current_event_time());
622 }
623 }
624
625 return FALSE;
626 }
627
onKeyReleased_gui(GtkWidget * widget,GdkEventKey * event,gpointer data)628 gboolean SearchSpy::onKeyReleased_gui(GtkWidget *widget, GdkEventKey *event, gpointer data)
629 {
630 SearchSpy *s = (SearchSpy *)data;
631
632 if (gtk_tree_selection_count_selected_rows(s->searchSelection) > 0)
633 {
634 if (event->keyval == GDK_Delete || event->keyval == GDK_BackSpace)
635 {
636 s->onRemoveItemClicked_gui(NULL, data);
637 }
638 else if (event->keyval == GDK_Menu || (event->keyval == GDK_F10 && event->state & GDK_SHIFT_MASK))
639 {
640 gtk_menu_popup(GTK_MENU(s->getWidget("menu")), NULL, NULL, NULL, NULL, 0, gtk_get_current_event_time());
641 }
642 }
643
644 return FALSE;
645 }
646
on(ClientManagerListener::IncomingSearch,const string & s)647 void SearchSpy::on(ClientManagerListener::IncomingSearch, const string& s) noexcept
648 {
649 if(!WGETB("spyframe-ignore-tth-searches") && s.compare(0, 4, "TTH:"))
650 return;
651
652 string search, type;
653 if(!s.compare(0, 4, "TTH:"))
654 {
655 type = "t";
656 search = s.substr(4);
657 }
658 else
659 {
660 type = "s";
661 search = s;
662 string::size_type i;
663 while((i = search.find("$")) != string::npos)
664 search[i] = ' ';
665 }
666 typedef Func2<SearchSpy, string, string> F2;
667 F2 *func = new F2(this, &SearchSpy::updateFrameSearch_gui, search, type);
668 WulforManager::get()->dispatchGuiFunc(func);
669 }
670
on(TimerManagerListener::Minute,uint64_t tick)671 void SearchSpy::on(TimerManagerListener::Minute, uint64_t tick) noexcept
672 {
673 typedef Func0<SearchSpy> F0;
674 F0 *func = new F0(this, &SearchSpy::updateFrameStatus_gui);
675 WulforManager::get()->dispatchGuiFunc(func);
676 }
677