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 "finishedtransfers.hh"
23 #include <dcpp/Text.h>
24 #include <dcpp/ClientManager.h>
25 #include "wulformanager.hh"
26 #include "WulforUtil.hh"
27
28 using namespace std;
29 using namespace dcpp;
30
createFinishedDownloads()31 FinishedTransfers* FinishedTransfers::createFinishedDownloads()
32 {
33 return new FinishedTransfers(Entry::FINISHED_DOWNLOADS, _("Finished Downloads"), false);
34 }
35
createFinishedUploads()36 FinishedTransfers* FinishedTransfers::createFinishedUploads()
37 {
38 return new FinishedTransfers(Entry::FINISHED_UPLOADS, _("Finished Uploads"), true);
39 }
40
FinishedTransfers(const EntryType type,const string & title,bool isUpload)41 FinishedTransfers::FinishedTransfers(const EntryType type, const string &title, bool isUpload):
42 BookEntry(type, title, "finishedtransfers.glade"),
43 isUpload(isUpload),
44 totalFiles(0),
45 totalBytes(0),
46 totalTime(0)
47 {
48 // Initialize transfer treeview
49 fileView.setView(GTK_TREE_VIEW(getWidget("fileView")), true, "finished");
50 fileView.insertColumn(N_("Time"), G_TYPE_STRING, TreeView::STRING, 150);
51 fileView.insertColumn(N_("Filename"), G_TYPE_STRING, TreeView::STRING, 130);
52 fileView.insertColumn(N_("Path"), G_TYPE_STRING, TreeView::STRING, 200);
53 fileView.insertColumn(N_("Users"), G_TYPE_STRING, TreeView::STRING, 110);
54 fileView.insertColumn(N_("Size"), G_TYPE_INT64, TreeView::SIZE, 100);
55 fileView.insertColumn(N_("Average Speed"), G_TYPE_INT64, TreeView::SPEED, 135);
56 fileView.insertColumn(N_("CRC Checked"), G_TYPE_STRING, TreeView::STRING, 125);
57 fileView.insertHiddenColumn("Target", G_TYPE_STRING);
58 fileView.insertHiddenColumn("Elapsed Time", G_TYPE_INT64);
59 fileView.finalize();
60 fileStore = gtk_list_store_newv(fileView.getColCount(), fileView.getGTypes());
61 gtk_tree_view_set_model(fileView.get(), GTK_TREE_MODEL(fileStore));
62 g_object_unref(fileStore);
63 fileSelection = gtk_tree_view_get_selection(fileView.get());
64 gtk_tree_view_column_set_sort_indicator(gtk_tree_view_get_column(fileView.get(), fileView.col("Time")), TRUE);
65 gtk_tree_sortable_set_sort_column_id(GTK_TREE_SORTABLE(fileStore), fileView.col("Time"), GTK_SORT_ASCENDING);
66 gtk_tree_view_set_fixed_height_mode(fileView.get(), TRUE);
67 gtk_tree_selection_set_mode(gtk_tree_view_get_selection(fileView.get()), GTK_SELECTION_MULTIPLE);
68
69 // Connect the signals to their callback functions.
70 g_signal_connect(getWidget("openItem"), "activate", G_CALLBACK(onOpen_gui), (gpointer)this);
71 g_signal_connect(getWidget("openFolderItem"), "activate", G_CALLBACK(onOpenFolder_gui), (gpointer)this);
72 g_signal_connect(getWidget("removeItem"), "activate", G_CALLBACK(onRemoveItems_gui), (gpointer)this);
73 g_signal_connect(getWidget("removeAllItem"), "activate", G_CALLBACK(onRemoveAll_gui), (gpointer)this);
74 g_signal_connect(fileView.get(), "button-press-event", G_CALLBACK(onButtonPressed_gui), (gpointer)this);
75 g_signal_connect(fileView.get(), "button-release-event", G_CALLBACK(onButtonReleased_gui), (gpointer)this);
76 g_signal_connect(fileView.get(), "key-release-event", G_CALLBACK(onKeyReleased_gui), (gpointer)this);
77
78 }
79
~FinishedTransfers()80 FinishedTransfers::~FinishedTransfers()
81 {
82 FinishedManager::getInstance()->removeListener(this);
83 }
84
show()85 void FinishedTransfers::show()
86 {
87 initializeList_client();
88 //Func0<FinishedTransfers> *func = new Func0<FinishedTransfers>(this, &FinishedTransfers::initializeList_client);
89 //WulforManager::get()->dispatchClientFunc(func);
90 FinishedManager::getInstance()->addListener(this);
91 }
92
findFile_gui(GtkTreeIter * iter,const string & item)93 bool FinishedTransfers::findFile_gui(GtkTreeIter* iter, const string& item)
94 {
95 bool valid = gtk_tree_model_get_iter_first(GTK_TREE_MODEL(fileStore), iter);
96
97 while (valid)
98 {
99 if (fileView.getString(iter, "Target") == item)
100 return TRUE;
101
102 valid = gtk_tree_model_iter_next(GTK_TREE_MODEL(fileStore), iter);
103 }
104
105 return FALSE;
106 }
107
addFile_gui(StringMap params,bool update)108 void FinishedTransfers::addFile_gui(StringMap params, bool update)
109 {
110 GtkTreeIter iter;
111 int64_t size = Util::toInt64(params["Size"]);
112 int64_t speed = Util::toInt64(params["Average Speed"]);
113 int64_t time = Util::toInt64(params["Elapsed Time"]);
114
115 if (!isUpload || !findFile_gui(&iter, params["Target"]))
116 {
117 gtk_list_store_append(fileStore, &iter);
118 totalFiles++;
119 }
120
121 if (!isUpload)
122 {
123 totalTime += time;
124 totalBytes += size;
125 }
126 else
127 {
128 totalTime += (time - fileView.getValue<int64_t>(&iter, "Elapsed Time"));
129 totalBytes += (size - fileView.getValue<int64_t>(&iter, "Size"));
130
131 }
132
133 gtk_list_store_set(fileStore, &iter,
134 fileView.col("Time"), params["Time"].c_str(),
135 fileView.col("Filename"), params["Filename"].c_str(),
136 fileView.col("Path"), params["Path"].c_str(),
137 fileView.col("Users"), params["Users"].c_str(),
138 fileView.col("Size"), size,
139 fileView.col("Average Speed"), speed,
140 fileView.col("CRC Checked"), params["CRC Checked"].c_str(),
141 fileView.col("Target"), params["Target"].c_str(),
142 fileView.col("Elapsed Time"), time,
143 -1);
144
145 if (update)
146 {
147 updateStatus_gui();
148
149 if ((!isUpload && BOOLSETTING(BOLD_FINISHED_DOWNLOADS)) ||
150 (isUpload && BOOLSETTING(BOLD_FINISHED_UPLOADS)))
151 {
152 setBold_gui();
153 }
154 }
155 }
156
updateStatus_gui()157 void FinishedTransfers::updateStatus_gui()
158 {
159 // TRANSLATORS: Displays the total number of files in the status bar.
160 string status = P_("File: %1%", "Files: %1%", % totalFiles, totalFiles);
161
162 string size = Util::formatBytes(totalBytes);
163 string speed = Util::formatBytes((totalTime > 0) ? totalBytes * ((int64_t)1000) / totalTime : 0) + "/s";
164
165 gtk_statusbar_push(GTK_STATUSBAR(getWidget("totalItems")), 0, status.c_str());
166 gtk_statusbar_push(GTK_STATUSBAR(getWidget("totalSize")), 0, size.c_str());
167 gtk_statusbar_push(GTK_STATUSBAR(getWidget("averageSpeed")), 0, speed.c_str());
168 }
169
onButtonPressed_gui(GtkWidget * widget,GdkEventButton * event,gpointer data)170 gboolean FinishedTransfers::onButtonPressed_gui(GtkWidget *widget, GdkEventButton *event, gpointer data)
171 {
172 FinishedTransfers *ft = (FinishedTransfers *)data;
173
174 if (event->button == 3)
175 {
176 GtkTreePath *path;
177 if (gtk_tree_view_get_path_at_pos(ft->fileView.get(), (gint)event->x, (gint)event->y, &path, NULL, NULL, NULL))
178 {
179 bool selected = gtk_tree_selection_path_is_selected(ft->fileSelection, path);
180 gtk_tree_path_free(path);
181
182 if (selected)
183 return TRUE;
184 }
185 }
186
187
188 return FALSE;
189 }
190
onButtonReleased_gui(GtkWidget * widget,GdkEventButton * event,gpointer data)191 gboolean FinishedTransfers::onButtonReleased_gui(GtkWidget *widget, GdkEventButton *event, gpointer data)
192 {
193 FinishedTransfers *ft = (FinishedTransfers *)data;
194
195 int count = gtk_tree_selection_count_selected_rows(ft->fileSelection);
196
197 if (event->button == 3 && count > 0)
198 {
199 gtk_menu_popup(GTK_MENU(ft->getWidget("menu")), NULL, NULL, NULL, NULL, 0, gtk_get_current_event_time());
200 gtk_widget_show_all(ft->getWidget("menu"));
201 }
202
203 return FALSE;
204 }
205
onKeyReleased_gui(GtkWidget * widget,GdkEventKey * event,gpointer data)206 gboolean FinishedTransfers::onKeyReleased_gui(GtkWidget *widget, GdkEventKey *event, gpointer data)
207 {
208 FinishedTransfers *ft = (FinishedTransfers *)data;
209
210 int count = gtk_tree_selection_count_selected_rows(ft->fileSelection);
211
212 if (count > 0)
213 {
214 if (event->keyval == GDK_Return || event->keyval == GDK_KP_Enter)
215 {
216 onOpen_gui(NULL, data);
217 }
218 else if (event->keyval == GDK_Delete || event->keyval == GDK_BackSpace)
219 {
220 onRemoveItems_gui(NULL, data);
221 }
222 else if (event->keyval == GDK_Menu || (event->keyval == GDK_F10 && event->state & GDK_SHIFT_MASK))
223 {
224 gtk_menu_popup(GTK_MENU(ft->getWidget("menu")), NULL, NULL, NULL, NULL, 1, event->time);
225 gtk_widget_show_all(ft->getWidget("menu"));
226 }
227 }
228
229 return FALSE;
230 }
231
onOpen_gui(GtkMenuItem * item,gpointer data)232 void FinishedTransfers::onOpen_gui(GtkMenuItem *item, gpointer data)
233 {
234 FinishedTransfers *ft = (FinishedTransfers *)data;
235 int count = gtk_tree_selection_count_selected_rows(ft->fileSelection);
236
237 if (count <= 0)
238 return;
239
240 GtkTreeIter iter;
241 GtkTreePath *path;
242 GList *list = gtk_tree_selection_get_selected_rows(ft->fileSelection, NULL);
243 for (GList *i = list; i; i = i->next)
244 {
245 path = (GtkTreePath *)i->data;
246 if (gtk_tree_model_get_iter(GTK_TREE_MODEL(ft->fileStore), &iter, path))
247 {
248 string target = ft->fileView.getString(&iter, "Target");
249 if (!target.empty())
250 WulforUtil::openURI(target);
251 }
252 gtk_tree_path_free(path);
253 }
254 g_list_free(list);
255
256 }
257
onOpenFolder_gui(GtkMenuItem * item,gpointer data)258 void FinishedTransfers::onOpenFolder_gui(GtkMenuItem *item, gpointer data)
259 {
260 FinishedTransfers *ft = (FinishedTransfers *)data;
261 int count = gtk_tree_selection_count_selected_rows(ft->fileSelection);
262
263 if (count <= 0)
264 return;
265
266 GtkTreeIter iter;
267 GtkTreePath *path;
268 GList *list = gtk_tree_selection_get_selected_rows(ft->fileSelection, NULL);
269
270 for (GList *i = list; i; i = i->next)
271 {
272 path = (GtkTreePath *)i->data;
273 if (gtk_tree_model_get_iter(GTK_TREE_MODEL(ft->fileStore), &iter, path))
274 {
275 string target = ft->fileView.getString(&iter, "Path");
276 if (!target.empty())
277 WulforUtil::openURI(target);
278 }
279 gtk_tree_path_free(path);
280 }
281 g_list_free(list);
282 }
283
onRemoveItems_gui(GtkMenuItem * item,gpointer data)284 void FinishedTransfers::onRemoveItems_gui(GtkMenuItem *item, gpointer data)
285 {
286 FinishedTransfers *ft = (FinishedTransfers *)data;
287
288 string target;
289 GtkTreeIter iter;
290 GtkTreePath *path;
291 GList *list = gtk_tree_selection_get_selected_rows(ft->fileSelection, NULL);
292
293 typedef Func1<FinishedTransfers, string> F1;
294 F1 *func;
295
296 for (GList *i = list; i; i = i->next)
297 {
298 path = (GtkTreePath *)i->data;
299 if (gtk_tree_model_get_iter(GTK_TREE_MODEL(ft->fileStore), &iter, path))
300 {
301 target = ft->fileView.getString(&iter, "Target");
302 func = new F1(ft, &FinishedTransfers::removeFile_client, target);
303 WulforManager::get()->dispatchClientFunc(func);
304 }
305 gtk_tree_path_free(path);
306 }
307 g_list_free(list);
308
309 ft->updateStatus_gui(); // Why? model won't change until after the _client call.
310 }
311
removeFile_gui(string target)312 void FinishedTransfers::removeFile_gui(string target)
313 {
314 GtkTreeIter iter;
315 GtkTreeModel *m = GTK_TREE_MODEL(fileStore);
316 bool valid = gtk_tree_model_get_iter_first(m, &iter);
317
318 while (valid)
319 {
320 if (target == fileView.getString(&iter, "Target"))
321 {
322 totalBytes -= fileView.getValue<gint64>(&iter, "Size");
323 totalTime -= fileView.getValue<gint64>(&iter, "Elapsed Time");
324 gtk_list_store_remove(fileStore, &iter);
325 totalFiles--;
326 updateStatus_gui();
327 return;
328 }
329 valid = gtk_tree_model_iter_next(m, &iter);
330 }
331 }
332
onRemoveAll_gui(GtkMenuItem * item,gpointer data)333 void FinishedTransfers::onRemoveAll_gui(GtkMenuItem *item, gpointer data)
334 {
335 FinishedTransfers *ft = (FinishedTransfers *)data;
336
337 gtk_list_store_clear(ft->fileStore);
338 ft->totalBytes = 0;
339 ft->totalTime = 0;
340 ft->totalFiles = 0;
341 ft->updateStatus_gui();
342
343 typedef Func0<FinishedTransfers> F0;
344 F0 *func = new F0(ft, &FinishedTransfers::removeAll_client);
345 WulforManager::get()->dispatchClientFunc(func);
346 }
347
initializeList_client()348 void FinishedTransfers::initializeList_client()
349 {
350 StringMap params;
351 typedef Func2<FinishedTransfers, StringMap, bool> F2;
352 //F2 *func;
353 FinishedManager::getInstance()->lockLists();
354 const FinishedManager::MapByFile &list = FinishedManager::getInstance()->getMapByFile(isUpload);
355
356 for (FinishedManager::MapByFile::const_iterator it = list.begin(); it != list.end(); ++it)
357 {
358 params.clear();
359 getFinishedParams_client(it->second, it->first, params);
360 addFile_gui(params, FALSE);
361 //func = new F2(this, &FinishedTransfers::addItem_gui, params, FALSE);
362 //WulforManager::get()->dispatchGuiFunc(func);
363 }
364
365 FinishedManager::getInstance()->unLockLists();
366
367 updateStatus_gui();
368 //WulforManager::get()->dispatchGuiFunc(new Func0<FinishedTransfers>(this, &FinishedTransfers::updateStatus_gui));
369 }
370
getFinishedParams_client(const FinishedFileItemPtr & item,const string & file,StringMap & params)371 void FinishedTransfers::getFinishedParams_client(const FinishedFileItemPtr& item, const string& file, StringMap ¶ms)
372 {
373 std::string nicks;
374 params["Filename"] = Util::getFileName(file);
375 params["Time"] = Util::formatTime("%Y-%m-%d %H:%M:%S", item->getTime());
376 params["Path"] = Util::getFilePath(file);
377 for (UserList::const_iterator it = item->getUsers().begin(); it != item->getUsers().end(); ++it)
378 {
379 nicks += WulforUtil::getNicks(it->get()->getCID()) + ", ";
380 }
381 params["Users"] = nicks.substr(0, nicks.length() - 2);
382 params["Size"] = Util::toString(item->getTransferred());
383 params["Average Speed"] = Util::toString(item->getAverageSpeed());
384 params["CRC Checked"] = item->getCrc32Checked() ? _("Yes") : _("No");
385 params["Target"] = file;
386 params["Elapsed Time"] = Util::toString(item->getMilliSeconds());
387 }
388
removeFile_client(std::string target)389 void FinishedTransfers::removeFile_client(std::string target)
390 {
391
392 if (!target.empty())
393 FinishedManager::getInstance()->remove(isUpload, target);
394
395 }
396
removeAll_client()397 void FinishedTransfers::removeAll_client()
398 {
399 FinishedManager::getInstance()->removeAll(isUpload);
400 }
401
on(FinishedManagerListener::AddedFile,bool upload,const string & file,const FinishedFileItemPtr & item)402 void FinishedTransfers::on(FinishedManagerListener::AddedFile, bool upload, const string& file, const FinishedFileItemPtr& item) throw()
403 {
404 // Show partial uploads, but only full downloads
405 if (isUpload == upload && (upload || item->isFull()))
406 {
407 StringMap params;
408 getFinishedParams_client(item, file, params);
409
410 typedef Func2<FinishedTransfers, StringMap, bool> F2;
411 F2* func = new F2(this, &FinishedTransfers::addFile_gui, params, TRUE);
412 WulforManager::get()->dispatchGuiFunc(func);
413 }
414 }
415
on(FinishedManagerListener::UpdatedFile,bool upload,const string & file,const FinishedFileItemPtr & item)416 void FinishedTransfers::on(FinishedManagerListener::UpdatedFile, bool upload, const string& file, const FinishedFileItemPtr& item) throw()
417 {
418 // Show partial uploads, but only full downloads
419 if (isUpload == upload && (upload || item->isFull()))
420 {
421 StringMap params;
422 getFinishedParams_client(item, file, params);
423
424 typedef Func2<FinishedTransfers, StringMap, bool> F2;
425 F2 *func = new F2(this, &FinishedTransfers::addFile_gui, params, TRUE);
426 WulforManager::get()->dispatchGuiFunc(func);
427 }
428 }
429
on(FinishedManagerListener::RemovedFile,bool upload,const string & item)430 void FinishedTransfers::on(FinishedManagerListener::RemovedFile, bool upload, const string& item) throw()
431 {
432 if (isUpload == upload)
433 {
434 typedef Func1<FinishedTransfers, string> F1;
435 F1 *func = new F1(this, &FinishedTransfers::removeFile_gui, item);
436 WulforManager::get()->dispatchGuiFunc(func);
437 }
438 }
439
440