update patch to work with build system changes
[AROS-Contrib.git] / Networking / Apps / OWB / downloadmanager.c
blob722ae228587608ff4262ac81449b4040f762f1b2
1 /*
2 Copyright © 2009, The AROS Development Team. All rights reserved.
3 $Id$
4 */
6 /* Process this class after all the base
7 * custom classes have been created
8 */
9 #define ZUNE_CUSTOMCLASS_PASS 101
11 #include <proto/alib.h>
12 #include <proto/exec.h>
13 #include <proto/muimaster.h>
14 #include <proto/asl.h>
15 #include <libraries/mui.h>
16 #include <libraries/asl.h>
17 #include <proto/intuition.h>
18 #include <proto/alib.h>
19 #include <proto/utility.h>
20 #include <proto/dos.h>
21 #include <string.h>
22 #include <stdio.h>
23 #include <aros/debug.h>
24 #include <aros/symbolsets.h>
25 #include <zune/customclasses.h>
27 #include "DownloadDelegateZune.h"
28 #include "browserpreferences.h"
30 #include "downloadmanager_private.h"
31 #include "downloadmanager.h"
33 #include "locale.h"
35 enum { DOWNLOAD_CREATED, DOWNLOAD_ACTIVE, DOWNLOAD_ERROR, DOWNLOAD_FINISHED, DOWNLOAD_DESTROYED };
37 static IPTR ManagerDisplayFunc(struct Hook *hook, char **columns, struct Download *download)
39 if(download == NULL)
41 columns[0] = (char*) _(MSG_DownloadFileName);
42 columns[1] = (char*) _(MSG_DownloadFileSize);
43 columns[2] = (char*) _(MSG_DownloadProgress);
44 columns[3] = (char*) _(MSG_DownloadSpeed);
45 columns[4] = (char*) _(MSG_DownloadState);
47 else
49 columns[0] = (download->filename ? download->filename : (char*) _(MSG_UnknownFileName));
50 columns[1] = (download->filesize ? download->filesize : (char*) _(MSG_UnknownFileSize));
51 columns[2] = download->progress;
52 columns[3] = (download->speed ? download->speed : (char*) _(MSG_UnknownDownloadSpeed));
53 switch(download->state)
55 case DOWNLOAD_CREATED:
56 columns[4] = (char*) _(MSG_DownloadState_Starting);
57 break;
58 case DOWNLOAD_ACTIVE:
59 columns[4] = (char*) _(MSG_DownloadState_Active);
60 break;
61 case DOWNLOAD_ERROR:
62 columns[4] = (char*) _(MSG_DownloadState_Failed);
63 break;
64 case DOWNLOAD_FINISHED:
65 columns[4] = (char*) _(MSG_DownloadState_Finished);
66 break;
67 default:
68 columns[4] = "";
69 break;
72 D(bug("displaying %s | %s | %s\n", columns[0], columns[1], columns[2]));
73 return 1;
76 static IPTR ManagerDestroyFunc(struct Hook *hook, APTR pool, struct Download *download)
78 if(!download)
79 return 0;
81 download->state = DOWNLOAD_DESTROYED;
82 FreeVec(download->filename);
83 FreeVec(download->filesize);
84 FreeVec(download->speed);
85 Remove((struct Node*) download);
86 FreeVec(download);
88 return 0;
91 static IPTR CancelFunc(struct Hook *hook, Object *list, void *data)
93 LONG active = 0;
94 get(list, MUIA_List_Active, &active);
96 if(active == MUIV_List_Active_Off)
97 return 0;
99 struct Download *download = NULL;
100 DoMethod(list, MUIM_List_GetEntry, active, &download);
102 if(download)
104 Object *manager = download->manager;
105 DoMethod(manager, MUIM_DownloadDelegate_CancelDownload, (IPTR) download->identifier);
106 DoMethod(list, MUIM_List_Remove, active);
107 DoMethod(manager, MUIM_DownloadManager_UpdateInterface);
110 return 0;
113 static IPTR ClearFinishedFunc(struct Hook *hook, Object *list, void *data)
115 int i;
116 for(i = XGET(list, MUIA_List_Entries) - 1; i>= 0; i--)
118 struct Download *download = NULL;
119 DoMethod(list, MUIM_List_GetEntry, i, &download);
120 if(download)
122 if(download->state == DOWNLOAD_FINISHED)
123 DoMethod(list, MUIM_List_Remove, i);
126 return 0;
129 static struct Download *GetDownload(struct DownloadManager_DATA *manager, void *downid)
131 struct Download *download;
132 ForeachNode(&manager->downloads, download)
134 if(download->identifier == downid)
135 return download;
137 return NULL;
140 IPTR DownloadManager__OM_NEW(struct IClass *cl, Object *self, struct opSet *msg)
142 Object *list = NULL, *bt_cancel, *bt_clearFinished;
143 Object *preferences = NULL;
144 struct TagItem *tag, *tags;
146 for (tags = msg->ops_AttrList; (tag = NextTagItem(&tags)); )
148 switch (tag->ti_Tag)
150 case MUIA_DownloadManager_Preferences:
151 preferences = (Object*) tag->ti_Data;
152 break;
153 default:
154 continue; /* Don't supress non-processed tags */
156 tag->ti_Tag = TAG_IGNORE;
159 if(!preferences) {
160 D(bug("DownloadManager: No preferences given\n"));
161 return (IPTR) NULL;
164 self = (Object *) DoSuperNewTags
166 cl, self, NULL,
168 MUIA_Window_Title, _(MSG_DownloadManager_Title),
169 WindowContents, (IPTR)(VGroup,
170 MUIA_InnerLeft, 5,
171 MUIA_InnerRight, 5,
172 MUIA_InnerTop, 5,
173 MUIA_InnerBottom, 5,
174 Child, (IPTR)(ListviewObject,
175 MUIA_Listview_List, (IPTR)(list = ListObject,
176 MUIA_List_Format, (IPTR)"BAR,BAR,BAR,BAR,",
177 MUIA_List_Title, TRUE,
178 End),
179 End),
180 Child, (IPTR)(HGroup,
181 Child, (IPTR)(bt_cancel = SimpleButton(_(MSG_DownloadManager_Cancel))),
182 Child, (IPTR)(bt_clearFinished = SimpleButton(_(MSG_DownloadManager_ClearFinished))),
183 End),
184 End),
185 TAG_MORE, (IPTR) msg->ops_AttrList
188 if(!self) {
189 D(bug("DownloadManager: Could not create self\n"));
190 return (IPTR) NULL;
193 struct DownloadManager_DATA *manager = (struct DownloadManager_DATA *) INST_DATA(cl, self);
195 NewList(&manager->downloads);
196 manager->displayHook.h_Entry = HookEntry;
197 manager->displayHook.h_SubEntry = (HOOKFUNC) ManagerDisplayFunc;
198 manager->destroyHook.h_Entry = HookEntry;
199 manager->destroyHook.h_SubEntry = (HOOKFUNC) ManagerDestroyFunc;
200 manager->cancelHook.h_Entry = HookEntry;
201 manager->cancelHook.h_SubEntry = (HOOKFUNC) CancelFunc;
202 manager->clearFinishedHook.h_Entry = HookEntry;
203 manager->clearFinishedHook.h_SubEntry = (HOOKFUNC) ClearFinishedFunc;
204 manager->list = list;
205 manager->preferences = preferences;
206 manager->bt_cancel = bt_cancel;
208 set(bt_cancel, MUIA_Disabled, TRUE);
209 set(list, MUIA_List_DisplayHook, &manager->displayHook);
210 set(list, MUIA_List_DestructHook, &manager->destroyHook);
212 /* Close window with close gadget */
213 DoMethod(self, MUIM_Notify, MUIA_Window_CloseRequest, (IPTR) TRUE,
214 (IPTR) self, (IPTR) 3,
215 MUIM_Set, MUIA_Window_Open, (IPTR) FALSE);
217 DoMethod(bt_cancel, MUIM_Notify, MUIA_Pressed, FALSE,
218 (IPTR) list, (IPTR) 3,
219 MUIM_CallHook, &manager->cancelHook, NULL);
221 DoMethod(bt_clearFinished, MUIM_Notify, MUIA_Pressed, FALSE,
222 (IPTR) list, (IPTR) 3,
223 MUIM_CallHook, &manager->clearFinishedHook, NULL);
225 DoMethod(list, MUIM_Notify, MUIA_List_Active, MUIV_EveryTime,
226 (IPTR) self, (IPTR) 1,
227 MUIM_DownloadManager_UpdateInterface);
229 return (IPTR) self;
232 IPTR DownloadManager__OM_DISPOSE(struct IClass *cl, Object *obj, Msg msg)
234 struct DownloadManager_DATA *manager = (struct DownloadManager_DATA *) INST_DATA(cl, obj);
236 /* Destroy all downloads, so they won't send notifications anymore */
237 DoMethod(manager->list, MUIM_List_Clear);
239 return DoSuperMethodA(cl,obj,msg);
242 IPTR DownloadManager__MUIM_DownloadDelegate_DidBeginDownload(Class *cl, Object *obj, struct MUIP_DownloadDelegate_DidBeginDownload* message)
244 struct DownloadManager_DATA *manager = (struct DownloadManager_DATA *) INST_DATA(cl, obj);
246 struct Download *download = (struct Download*) AllocVec(sizeof(struct Download), MEMF_ANY | MEMF_CLEAR);
247 download->identifier = message->download;
248 download->state = DOWNLOAD_CREATED;
249 download->sizeTotal = -1;
250 download->sizeDownloaded = 0;
251 download->manager = obj;
252 download->filename = NULL;
253 download->filesize = NULL;
254 download->speed = NULL;
255 download->speedMeasureTime = time(NULL);
256 download->listRedrawTime = time(NULL);
257 download->speedSizeDownloaded = 0;
258 sprintf(download->progress, "%ld %%", (long)0);
260 if(!download)
261 return FALSE;
263 AddHead(&manager->downloads, (struct Node*) download);
265 DoMethod(manager->list, MUIM_List_InsertSingle, download, 0);
266 SetAttrs(obj, MUIA_Window_Open, TRUE);
267 DoMethod(obj, MUIM_DownloadManager_UpdateInterface);
269 return TRUE;
272 IPTR DownloadManager__MUIM_DownloadDelegate_DidFinishDownload(Class *cl, Object *obj, struct MUIP_DownloadDelegate_DidFinishDownload* message)
274 struct DownloadManager_DATA *manager = (struct DownloadManager_DATA *) INST_DATA(cl, obj);
276 struct Download *download = GetDownload(manager, message->download);
277 if(!download)
278 return FALSE;
280 download->state = DOWNLOAD_FINISHED;
282 sprintf(download->progress, "%ld %%", (long) (download->sizeTotal > 0 ? 100 * download->sizeDownloaded / download->sizeTotal : 0));
284 /* Activate finished entry */
285 int i;
286 for (i=0;;i++)
288 struct Download *down;
289 DoMethod(manager->list, MUIM_List_GetEntry, i, &down);
290 if(!down)
291 break;
293 if(down == download)
295 set(manager->list, MUIA_List_Active, i);
296 break;
301 SetAttrs(obj, MUIA_Window_Open, TRUE);
302 DoMethod(manager->list, MUIM_List_Redraw, MUIV_List_Redraw_All);
303 DoMethod(obj, MUIM_DownloadManager_UpdateInterface);
305 return TRUE;
308 IPTR DownloadManager__MUIM_DownloadDelegate_DidFailWithError(Class *cl, Object *obj, struct MUIP_DownloadDelegate_DidFailWithError* message)
310 struct DownloadManager_DATA *manager = (struct DownloadManager_DATA *) INST_DATA(cl, obj);
312 struct Download *download = GetDownload(manager, message->download);
313 if(!download)
314 return FALSE;
316 download->state = DOWNLOAD_ERROR;
318 /* Activate failed entry */
319 int i;
320 for (i=0;;i++)
322 struct Download *down;
323 DoMethod(manager->list, MUIM_List_GetEntry, i, &down);
324 if(!down)
325 break;
327 if(down == download)
329 set(manager->list, MUIA_List_Active, i);
330 break;
334 SetAttrs(obj, MUIA_Window_Open, TRUE);
335 DoMethod(manager->list, MUIM_List_Redraw, MUIV_List_Redraw_All);
336 DoMethod(obj, MUIM_DownloadManager_UpdateInterface);
338 return TRUE;
341 IPTR DownloadManager__MUIM_DownloadDelegate_DecideDestinationWithSuggestedFilename(Class *cl, Object *obj, struct MUIP_DownloadDelegate_DecideDestinationWithSuggestedFilename* message)
343 struct DownloadManager_DATA *manager = (struct DownloadManager_DATA *) INST_DATA(cl, obj);
344 char *destination = NULL;
346 struct Download *download = GetDownload(manager, message->download);
347 if(!download)
348 return FALSE;
350 if(download->filename)
351 FreeVec(download->filename);
353 char *filename = message->filename;
355 const char *prefix = (const char*) XGET(manager->preferences, MUIA_BrowserPreferences_DownloadDestination);
356 if(strlen(filename) == 0)
357 filename = strdup(_(MSG_UnknownFileName));
359 BOOL requestFileName = XGET(manager->preferences, MUIA_BrowserPreferences_RequestDownloadedFileName);
360 if(requestFileName)
362 struct FileRequester *fr;
364 struct TagItem frtags[] =
366 { ASLFR_TitleText, (IPTR)_(MSG_DownloadManager_RequestDownloadedFileTitle) },
367 { ASLFR_InitialDrawer, (IPTR)prefix },
368 { ASLFR_InitialFile, (IPTR)filename },
369 { ASLFR_DoSaveMode, (BOOL)TRUE },
370 { TAG_END }
373 if((fr = (struct FileRequester *) AllocAslRequest(ASL_FileRequest, frtags)))
375 if(AslRequest(fr, NULL))
377 download->filename = StrDup(fr->fr_File);
378 destination = AllocVec(strlen(fr->fr_Drawer) + strlen(fr->fr_File) + 2, MEMF_ANY);
379 strcpy(destination, fr->fr_Drawer);
380 AddPart(destination, fr->fr_File, strlen(fr->fr_Drawer) + strlen(fr->fr_File) + 2);
382 else
384 destination = NULL;
386 FreeAslRequest(fr);
388 else
390 destination = NULL;
393 else
395 download->filename = StrDup(filename);
396 destination = AllocVec(strlen(filename) + strlen(prefix) + 2, MEMF_ANY);
397 strcpy(destination, prefix);
398 AddPart(destination, filename, strlen(filename) + strlen(prefix) + 2);
401 D(bug("setting destination %s\n", destination));
402 DoMethod(obj, MUIM_DownloadDelegate_SetDestination, download->identifier, destination);
403 FreeVec(destination);
405 if(destination == NULL)
407 // download is cancelled now, remove it
408 int i;
409 for(i = XGET(manager->list, MUIA_List_Entries) - 1; i>= 0; i--)
411 struct Download *download_entry = NULL;
412 DoMethod(manager->list, MUIM_List_GetEntry, i, &download_entry);
413 if(download == download_entry)
415 set(manager->list, MUIA_List_Active, i);
416 DoMethod(_app(obj), MUIM_Application_PushMethod, manager->list, 3, MUIM_CallHook, &manager->cancelHook, NULL);
417 break;
422 DoMethod(manager->list, MUIM_List_Redraw, MUIV_List_Redraw_All);
424 return TRUE;
427 IPTR DownloadManager__MUIM_DownloadDelegate_DidReceiveExpectedContentLength(Class *cl, Object *obj, struct MUIP_DownloadDelegate_DidReceiveExpectedContentLength* message)
429 struct DownloadManager_DATA *manager = (struct DownloadManager_DATA *) INST_DATA(cl, obj);
431 struct Download *download = GetDownload(manager, message->download);
432 if(!download)
433 return FALSE;
435 download->sizeTotal = message->length;
437 if(download->filesize)
438 FreeVec(download->filesize);
440 char *template;
441 double scaledsize;
443 if(download->sizeTotal < 1024)
445 template = "%.0lf b";
446 scaledsize = download->sizeTotal;
448 else if(download->sizeTotal < 1024 * 1024)
450 template = "%.2lf kB";
451 scaledsize = 1.0 * download->sizeTotal / 1024;
453 else
455 template = "%.2lf MB";
456 scaledsize = 1.0 * download->sizeTotal / (1024 * 1024);
459 char c;
460 int length = snprintf(&c, 0, template, scaledsize) + 1;
461 char *filesize = AllocVec(length, MEMF_ANY);
462 if(filesize)
464 snprintf(filesize, length, template, scaledsize);
465 download->filesize = filesize;
467 DoMethod(manager->list, MUIM_List_Redraw, MUIV_List_Redraw_All);
470 return TRUE;
473 IPTR DownloadManager__MUIM_DownloadDelegate_DidReceiveDataOfLength(Class *cl, Object *obj, struct MUIP_DownloadDelegate_DidReceiveDataOfLength* message)
475 struct DownloadManager_DATA *manager = (struct DownloadManager_DATA *) INST_DATA(cl, obj);
477 D(bug("DownloadProgressed(%d)\n", message->length));
478 struct Download *download = GetDownload(manager, message->download);
479 if(!download)
480 return FALSE;
482 if(download->state == DOWNLOAD_CREATED)
483 download->state = DOWNLOAD_ACTIVE;
485 download->sizeDownloaded += message->length;
487 time_t currentTime = time(NULL);
488 if(currentTime > download->speedMeasureTime)
490 long long downloaded = download->sizeDownloaded - download->speedSizeDownloaded;
491 download->speedSizeDownloaded = download->sizeDownloaded;
492 int elapsed = currentTime - download->speedMeasureTime;
493 download->speedMeasureTime = currentTime;
495 if(download->speed)
496 FreeVec(download->speed);
498 char *template;
499 double scaledspeed;
501 if(downloaded < 1024)
503 template = "%.0lf b/s";
504 scaledspeed = downloaded / elapsed;
506 else if(downloaded < 1024 * 1024)
508 template = "%.2lf kB/s";
509 scaledspeed = 1.0 * downloaded / (1024 * elapsed);
511 else
513 template = "%.2lf MB/s";
514 scaledspeed = 1.0 * downloaded / (1024 * 1024 * elapsed);
517 char c;
518 int length = snprintf(&c, 0, template, scaledspeed) + 1;
519 char *transferspeed = AllocVec(length, MEMF_ANY);
520 if(transferspeed)
522 snprintf(transferspeed, length, template, scaledspeed);
523 download->speed = transferspeed;
527 if(currentTime > download->listRedrawTime)
529 download->listRedrawTime = currentTime;
530 sprintf(download->progress, "%ld %%", (long) (download->sizeTotal > 0 ? 100 * download->sizeDownloaded / download->sizeTotal : 0));
531 DoMethod(manager->list, MUIM_List_Redraw, MUIV_List_Redraw_All);
534 return TRUE;
537 IPTR DownloadManager__MUIM_DownloadManager_UpdateInterface(Class *cl, Object *obj, Msg message)
539 struct DownloadManager_DATA *manager = (struct DownloadManager_DATA *) INST_DATA(cl, obj);
540 LONG active = XGET(manager->list, MUIA_List_Active);
541 struct Download *download = NULL;
543 if(active == MUIV_List_Active_Off)
545 set(manager->bt_cancel, MUIA_Disabled, TRUE);
546 return TRUE;
549 DoMethod(manager->list, MUIM_List_GetEntry, active, &download);
551 if(download && download->state == DOWNLOAD_ACTIVE)
552 set(manager->bt_cancel, MUIA_Disabled, FALSE);
553 else
554 set(manager->bt_cancel, MUIA_Disabled, TRUE);
556 return TRUE;
559 ZUNE_CUSTOMCLASS_9(
560 DownloadManager, NULL, NULL, DownloadDelegate_CLASS,
561 OM_NEW, struct opSet*,
562 OM_DISPOSE, Msg,
563 MUIM_DownloadDelegate_DidBeginDownload, struct MUIP_DownloadDelegate_DidBeginDownload*,
564 MUIM_DownloadDelegate_DidFinishDownload, struct MUIP_DownloadDelegate_DidFinishDownload*,
565 MUIM_DownloadDelegate_DidFailWithError, struct MUIP_DownloadDelegate_DidFailWithError*,
566 MUIM_DownloadDelegate_DidReceiveExpectedContentLength, struct MUIP_DownloadDelegate_DidReceiveExpectedContentLength*,
567 MUIM_DownloadDelegate_DidReceiveDataOfLength, struct MUIP_DownloadDelegate_DidReceiveDataOfLength*,
568 MUIM_DownloadDelegate_DecideDestinationWithSuggestedFilename, struct MUIP_DownloadDelegate_DecideDestinationWithSuggestedFilename*,
569 MUIM_DownloadManager_UpdateInterface, Msg