~ubuntu-branches/ubuntu/hardy/transmission/hardy-updates

« back to all changes in this revision

Viewing changes to beos/TRWindow.cpp

  • Committer: Bazaar Package Importer
  • Author(s): Philipp Benner
  • Date: 2008-01-05 09:16:52 UTC
  • mto: This revision was merged to the branch mainline in revision 11.
  • Revision ID: james.westby@ubuntu.com-20080105091652-8cf0z4rb3pu8d6jt
Tags: upstream-1.00
ImportĀ upstreamĀ versionĀ 1.00

Show diffs side-by-side

added added

removed removed

Lines of Context:
 
1
/**
 
2
 * Copyright (C) 2007 Bryan Varner
 
3
 *
 
4
 * Permission is hereby granted, free of charge, to any person obtaining
 
5
 * a copy of this software and associated documentation files (the
 
6
 * "Software"), to deal in the Software without restriction, including
 
7
 * without limitation the rights to use, copy, modify, merge, publish,
 
8
 * distribute, sublicense, and/or sell copies of the Software, and to
 
9
 * permit persons to whom the Software is furnished to do so, subject to
 
10
 * the following conditions:
 
11
 * 
 
12
 * The above copyright notice and this permission notice shall be included
 
13
 * in all copies or substantial portions of the Software.
 
14
 * 
 
15
 * THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND,
 
16
 * EXPRESS OR IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF
 
17
 * MERCHANTABILITY, FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT.
 
18
 * IN NO EVENT SHALL THE AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY
 
19
 * CLAIM, DAMAGES OR OTHER LIABILITY, WHETHER IN AN ACTION OF CONTRACT,
 
20
 * TORT OR OTHERWISE, ARISING FROM, OUT OF OR IN CONNECTION WITH THE
 
21
 * SOFTWARE OR THE USE OR OTHER DEALINGS IN THE SOFTWARE.
 
22
 *
 
23
 * $Id: TRWindow.cpp 4182 2007-12-17 06:30:42Z charles $
 
24
 */
 
25
 
 
26
#include "TRWindow.h"
 
27
 
 
28
#include <stdio.h>
 
29
 
 
30
#include <Alert.h>
 
31
#include <Application.h>
 
32
#include <File.h>
 
33
#include <MenuBar.h>
 
34
#include <MenuItem.h>
 
35
#include <NodeMonitor.h>
 
36
#include <ScrollView.h>
 
37
#include <String.h>
 
38
 
 
39
#include <malloc.h>
 
40
#include <time.h> /* for time() */
 
41
#include <unistd.h> /* for sleep() */
 
42
 
 
43
#include "Prefs.h"
 
44
#include "TRApplication.h"
 
45
#include "TRTransfer.h"
 
46
#include "TRInfoWindow.h"
 
47
 
 
48
BListView *TRWindow::transfers = NULL;
 
49
 
 
50
/**
 
51
 * The Transmission Window! Yay!
 
52
 */
 
53
TRWindow::TRWindow() : BWindow(BRect(10, 40, 350, 110), "Transmission", B_TITLED_WINDOW,
 
54
                               B_ASYNCHRONOUS_CONTROLS , B_CURRENT_WORKSPACE)
 
55
{
 
56
        engine = NULL;
 
57
        stopping = false;
 
58
        quitter = NULL;
 
59
        Prefs prefs(TRANSMISSION_SETTINGS);
 
60
        
 
61
        BRect *rectFrame = new BRect();
 
62
        if (prefs.FindRect("window.frame", rectFrame) == B_OK) {
 
63
                MoveTo(rectFrame->LeftTop());
 
64
                ResizeTo(rectFrame->Width(), rectFrame->Height());
 
65
        } else {
 
66
                rectFrame->Set(10, 40, 350, 110);
 
67
        }
 
68
        Lock();
 
69
        
 
70
        BRect viewRect(0, 0, rectFrame->Width(), rectFrame->Height());
 
71
        
 
72
        BMenuBar *menubar = new BMenuBar(viewRect, "MenuBar");
 
73
        BMenu *menu = new BMenu("File");
 
74
        menu->AddItem(new BMenuItem("Open", new BMessage(TR_OPEN), 'O', B_COMMAND_KEY));
 
75
        menu->FindItem(TR_OPEN)->SetTarget(be_app_messenger); // send OPEN to the be_app.
 
76
        menu->AddSeparatorItem();
 
77
        menu->AddItem(new BMenuItem("Quit", new BMessage(B_QUIT_REQUESTED), 'Q', B_COMMAND_KEY));
 
78
        menubar->AddItem(menu);
 
79
        
 
80
        menu = new BMenu("Torrent");
 
81
        menu->AddItem(new BMenuItem("Get Info", new BMessage(TR_INFO), 'I', B_COMMAND_KEY));
 
82
        menu->FindItem(TR_INFO)->SetEnabled(false);
 
83
        menu->AddSeparatorItem();
 
84
        menu->AddItem(new BMenuItem("Resume", new BMessage(TR_RESUME)));
 
85
        menu->AddItem(new BMenuItem("Pause", new BMessage(TR_PAUSE)));
 
86
        menu->AddItem(new BMenuItem("Remove", new BMessage(TR_REMOVE)));
 
87
        menubar->AddItem(menu);
 
88
        
 
89
        menu = new BMenu("Tools");
 
90
        menu->AddItem(new BMenuItem("Settings", new BMessage(TR_SETTINGS)));
 
91
        menu->FindItem(TR_SETTINGS)->SetTarget(be_app_messenger);
 
92
        menu->AddSeparatorItem();
 
93
        menu->AddItem(new BMenuItem("About Transmission", new BMessage(B_ABOUT_REQUESTED)));
 
94
        menu->FindItem(B_ABOUT_REQUESTED)->SetTarget(be_app_messenger);
 
95
        menubar->AddItem(menu);
 
96
        
 
97
        AddChild(menubar);
 
98
        SetKeyMenuBar(menubar);
 
99
        
 
100
        // TODO: Tool Bar? (Well after everything is working based on Menus)
 
101
        
 
102
        // Setup the transfers ListView
 
103
        viewRect.Set(2, menubar->Frame().bottom + 3, rectFrame->Width() - 2 - B_V_SCROLL_BAR_WIDTH, rectFrame->Height() - 2);
 
104
        TRWindow::transfers = new BListView(viewRect, "TorrentList", B_SINGLE_SELECTION_LIST, B_FOLLOW_ALL);
 
105
        TRWindow::transfers->SetSelectionMessage(new BMessage(TR_SELECT));
 
106
        AddChild(new BScrollView("TransferScroller", transfers, B_FOLLOW_ALL, 0, false, true));
 
107
        
 
108
        Unlock();
 
109
        delete rectFrame;
 
110
        
 
111
        // Bring up the Transmission Engine
 
112
        engine = tr_init( "beos" );
 
113
        LoadSettings();
 
114
        
 
115
        UpdateList(-1, true);
 
116
        
 
117
        // Start the message loop without showing the window.
 
118
        Hide();
 
119
        Show();
 
120
}
 
121
 
 
122
static void torrentclose(tr_torrent_t *torrent, void *)
 
123
{
 
124
        tr_torrentClose(torrent);
 
125
}
 
126
 
 
127
TRWindow::~TRWindow() {
 
128
        tr_torrentIterate(engine, torrentclose, NULL);
 
129
        const int MAX_EXIT_WAIT_SECS = 10;
 
130
        const time_t deadline = time(0) + MAX_EXIT_WAIT_SECS;
 
131
        while (tr_torrentCount(engine) && time(NULL) < deadline) {
 
132
                snooze(100000);
 
133
        }
 
134
        /* XXX there's no way to make sure the torrent threads are running so this might crash */
 
135
        tr_close(engine);
 
136
        stop_watching(this);
 
137
        delete quitter;
 
138
}
 
139
 
 
140
 
 
141
void TRWindow::LoadSettings() {
 
142
        if (engine != NULL) {
 
143
                Prefs prefs(TRANSMISSION_SETTINGS);
 
144
                
 
145
                int32 bindPort;
 
146
                if (prefs.FindInt32("transmission.bindPort", &bindPort) != B_OK) {
 
147
                        bindPort = 9000;
 
148
                        prefs.SetInt32("transmission.bindPort", bindPort);
 
149
                }
 
150
                tr_setBindPort(engine, (int)bindPort);
 
151
                
 
152
                int32 uploadLimit;
 
153
                if (prefs.FindInt32("transmission.uploadLimit", &uploadLimit) != B_OK) {
 
154
                        uploadLimit = 20;
 
155
                        prefs.SetInt32("transmission.uploadLimit", uploadLimit);
 
156
                }
 
157
                tr_setGlobalSpeedLimit(engine, TR_UP, (int)uploadLimit);
 
158
        }
 
159
}
 
160
 
 
161
 
 
162
/**
 
163
 * Rescans the active Torrents folder, and will add all the torrents there to the
 
164
 * engine. Called during initial Application Start & Stop.
 
165
 */
 
166
void TRWindow::RescanTorrents() {
 
167
        if (Lock()) {
 
168
                TRApplication *app = dynamic_cast<TRApplication*>(be_app);
 
169
                BEntry *torrentEntry = new BEntry();
 
170
                status_t err;
 
171
                
 
172
                if (app->TorrentDir()->InitCheck() == B_OK) {
 
173
                        err = app->TorrentDir()->Rewind();
 
174
                        while (err == B_OK) {
 
175
                                err = app->TorrentDir()->GetNextEntry(torrentEntry, true);
 
176
                                if (err != B_ENTRY_NOT_FOUND) {
 
177
                                        AddEntry(torrentEntry);
 
178
                                }
 
179
                        }
 
180
                }
 
181
                delete torrentEntry;
 
182
                Unlock();
 
183
        }
 
184
}
 
185
 
 
186
 
 
187
/**
 
188
 * Adds the file specified by *torrent to the Transmission engine.
 
189
 * Then adds a new TRTransfer item in the transfers list.
 
190
 * This item holds cached information about the torrent entry and node.
 
191
 * These TRTransmission items are _NOT_ guaranteed to render the entry 
 
192
 * they were created from.
 
193
 */
 
194
void TRWindow::AddEntry(BEntry *torrent) {
 
195
        node_ref node;
 
196
        if (torrent->GetNodeRef(&node) == B_OK) {
 
197
                if (watch_node(&node, B_WATCH_NAME, this) == B_OK) {
 
198
                        BPath path;
 
199
                        torrent->GetPath(&path);
 
200
                        
 
201
                        // Try adding the torrent to the engine.
 
202
                        int error;
 
203
                        tr_torrent_t *nTorrent;
 
204
                        nTorrent = tr_torrentInit(engine, path.Path(), GetFolder().String(),
 
205
                                TR_FLAG_PAUSED, &error);
 
206
                        if (nTorrent != NULL && Lock()) { // Success. Add the TRTorrent item.
 
207
                                transfers->AddItem(new TRTransfer(path.Path(), node, nTorrent));
 
208
                                
 
209
                                bool autoStart = true;
 
210
                                
 
211
                                // Decide if we should auto-start this torrent or not.
 
212
                                BString prefName("download.");
 
213
                                prefName << path.Path() << ".running";
 
214
                                
 
215
                                Prefs *prefs = new Prefs(TRANSMISSION_SETTINGS);
 
216
                                if (prefs->FindBool(prefName.String(), &autoStart) != B_OK) {
 
217
                                        autoStart = true;
 
218
                                }
 
219
                                delete prefs;
 
220
                                
 
221
                                if (autoStart) {
 
222
                                        // Start the newly added torrent.
 
223
                                        worker_info *startData = (worker_info*)calloc(1, sizeof(worker_info));
 
224
                                        startData->window = this;
 
225
                                        startData->torrent = nTorrent;
 
226
                                        thread_id start_thread = spawn_thread(TRWindow::AsynchStartTorrent, "BirthCanal",
 
227
                                                                              B_NORMAL_PRIORITY, (void *)startData);
 
228
                                        if (!((start_thread) < B_OK)) {
 
229
                                                resume_thread(start_thread);
 
230
                                        } else { // Fallback and start the old way.
 
231
                                                StartTorrent(startData->torrent);
 
232
                                                free(startData);
 
233
                                        }
 
234
                                }
 
235
                                Unlock();
 
236
                        } else {
 
237
                                bool duplicate = false;
 
238
                                TRTransfer* tr;
 
239
                                for (int32 i = 0; i < transfers->CountItems(); i++) {
 
240
                                        tr = (TRTransfer*)transfers->ItemAt(i);
 
241
                                        if (tr->GetCachedNodeRef() == node) {
 
242
                                                duplicate = true;
 
243
                                        }
 
244
                                }
 
245
                                if (!duplicate) {
 
246
                                        BString errmsg("An error occurred trying to read ");
 
247
                                        char namebuf[B_FILE_NAME_LENGTH];
 
248
                                        torrent->GetName(namebuf);
 
249
                                        errmsg << namebuf;
 
250
                                        errmsg << ".";
 
251
                                        
 
252
                                        BAlert *error = new BAlert("Error Opening Torrent", 
 
253
                                               errmsg.String(), 
 
254
                                               "Ok", NULL, NULL, 
 
255
                                               B_WIDTH_AS_USUAL, B_WARNING_ALERT);
 
256
                                        error->Go();
 
257
                                        torrent->Remove();
 
258
                                }
 
259
                        }
 
260
                }
 
261
        }
 
262
}
 
263
 
 
264
 
 
265
void TRWindow::MessageReceived(BMessage *msg) {
 
266
        /*
 
267
         * The only messages we receive from the node_monitor are if we need to
 
268
         * stop watching the node. Basically, if it's been moved or removed we stop.
 
269
         */
 
270
        if (msg->what == B_NODE_MONITOR) {
 
271
                node_ref node;
 
272
                ino_t fromDir;
 
273
                ino_t toDir;
 
274
                int32 opcode;
 
275
                
 
276
                if ((msg->FindInt32("opcode", &opcode) == B_OK) &&
 
277
                        (msg->FindInt64("node", &node.node) == B_OK) &&
 
278
                    (msg->FindInt32("device", &node.device) == B_OK))
 
279
                {
 
280
                        bool stop = (opcode == B_ENTRY_REMOVED);
 
281
                        
 
282
                        if (stop) {
 
283
                                msg->FindInt64("directory", &toDir);
 
284
                        } else { // It must have moved.
 
285
                                stop = ((msg->FindInt64("from directory", &fromDir) == B_OK) &&
 
286
                                        (msg->FindInt64("to directory", &toDir) == B_OK) &&
 
287
                                        (toDir != fromDir));
 
288
                        }
 
289
                        
 
290
                        if (stop) {
 
291
                                watch_node(&node, B_STOP_WATCHING, this);
 
292
                                
 
293
                                /* Find the full path from the TRTorrents.
 
294
                                 * The index of the TRTorrent that is caching the information
 
295
                                 * IS NOT the index of the torrent in the engine. These are
 
296
                                 * Totally decoupled, due to the way transmission is written.
 
297
                                 */
 
298
                                remove_info *removeData = (remove_info*)calloc(1, sizeof(remove_info));
 
299
                                removeData->window = this;
 
300
                                TRTransfer* item;
 
301
                                for (int32 i = 0; i < transfers->CountItems(); i++) {
 
302
                                        item = (TRTransfer*)transfers->ItemAt(i);
 
303
                                        if (item->GetCachedNodeRef() == node) {
 
304
                                                strcpy(removeData->path, item->GetCachedPath());
 
305
                                        }
 
306
                                }
 
307
                                
 
308
                                transfers->DoForEach(TRWindow::RemovePath, (void *)removeData);
 
309
                                
 
310
                                free(removeData);
 
311
                        }
 
312
                }
 
313
        } else if (msg->what == TR_INFO) {
 
314
                // Display an Info Window.
 
315
                TRTransfer *transfer = dynamic_cast<TRTransfer*>(transfers->ItemAt(transfers->CurrentSelection()));
 
316
                const tr_stat_t *s = tr_torrentStat(transfer->GetTorrent());
 
317
                const tr_info_t *i = tr_torrentInfo(transfer->GetTorrent());
 
318
                
 
319
                TRInfoWindow *info = new TRInfoWindow(s, i, tr_torrentGetFolder(transfer->GetTorrent()));
 
320
                info->MoveTo(Frame().LeftTop() + BPoint(20, 25));
 
321
                info->Show();
 
322
        } else if (msg->what == TR_SELECT) {
 
323
                // Setup the Torrent Menu enabled / disabled state.
 
324
                int32 selection;
 
325
                msg->FindInt32("index", &selection);
 
326
                UpdateList(selection, true);
 
327
        } else if (msg->what == TR_RESUME) {
 
328
                worker_info *startData = (worker_info*)calloc(1, sizeof(worker_info));
 
329
                startData->window = this;
 
330
                startData->torrent = (dynamic_cast<TRTransfer*>(transfers->ItemAt(transfers->CurrentSelection())))->GetTorrent();
 
331
                thread_id start_thread = spawn_thread(TRWindow::AsynchStartTorrent, "BirthCanal",
 
332
                                                      B_NORMAL_PRIORITY, (void *)startData);
 
333
                if (!((start_thread) < B_OK)) {
 
334
                        resume_thread(start_thread);
 
335
                } else { // Fallback and start the old way.
 
336
                        StartTorrent(startData->torrent);
 
337
                        free(startData);
 
338
                }
 
339
        } else if (msg->what == TR_PAUSE) {
 
340
                worker_info *stopData = (worker_info*)calloc(1, sizeof(worker_info));
 
341
                stopData->window = this;
 
342
                stopData->torrent = (dynamic_cast<TRTransfer*>(transfers->ItemAt(transfers->CurrentSelection())))->GetTorrent();
 
343
                thread_id stop_thread = spawn_thread(TRWindow::AsynchStopTorrent, "InUtero",
 
344
                                                     B_NORMAL_PRIORITY, (void *)stopData);
 
345
                if (!((stop_thread) < B_OK)) {
 
346
                        resume_thread(stop_thread);
 
347
                } else { // Fallback and stop it the old way.
 
348
                        StopTorrent(stopData->torrent);
 
349
                        free(stopData);
 
350
                }
 
351
        } else if (msg->what == TR_REMOVE) {
 
352
                int32 index = transfers->CurrentSelection();
 
353
                
 
354
                // Remove the file from the filesystem.
 
355
                TRTransfer *item = (TRTransfer*)transfers->RemoveItem(index);
 
356
                tr_torrentClose(item->GetTorrent());
 
357
                BEntry *entry = new BEntry(item->GetCachedPath(), true);
 
358
                entry->Remove();
 
359
                delete entry;
 
360
                delete item;
 
361
                
 
362
                
 
363
                
 
364
                UpdateList(transfers->CurrentSelection(), true);
 
365
        } else if (msg->what == B_SIMPLE_DATA) {
 
366
                be_app->RefsReceived(msg);
 
367
        }
 
368
                
 
369
        BWindow::MessageReceived(msg);
 
370
}
 
371
 
 
372
/**
 
373
 * Handles QuitRequests.
 
374
 * Displays a BAlert asking if the user really wants to quit if torrents are running.
 
375
 * If affimative, then we'll stop all the running torrents.
 
376
 */
 
377
bool TRWindow::QuitRequested() {
 
378
        if (stopping)
 
379
                return true;
 
380
 
 
381
        bool quit = false;
 
382
        int running;
 
383
        
 
384
        quit_info *quitData = (quit_info*)calloc(1, sizeof(quit_info));
 
385
        quitData->running = 0;
 
386
        transfers->DoForEach(TRWindow::CheckQuitStatus, (void *)quitData);
 
387
        running = quitData->running;
 
388
        free(quitData);
 
389
        
 
390
        if (running > 0) {
 
391
                BString quitMsg("");
 
392
                quitMsg << "There's " << running << " torrent";
 
393
                if (running > 1) {
 
394
                        quitMsg << "s";
 
395
                }
 
396
                quitMsg << " currently running.\n"
 
397
                        << "What would you like to do?";
 
398
                
 
399
                BAlert *confirmQuit = new BAlert("Confirm Quit", quitMsg.String(),
 
400
                                                 "Cancel", "Quit", NULL,
 
401
                                                 B_WIDTH_AS_USUAL, B_WARNING_ALERT);
 
402
                quit = (confirmQuit->Go() == 1);
 
403
        } else {
 
404
                quit = true;
 
405
        }
 
406
        
 
407
        if (quit) {
 
408
                Prefs *prefs = new Prefs(TRANSMISSION_SETTINGS);
 
409
                prefs->SetRect("window.frame", Frame());
 
410
                
 
411
                BString strItem("");
 
412
                for (int i = 0; i < transfers->CountItems(); i++) {
 
413
                        strItem = "download.";
 
414
                        tr_torrent_t *torrent = (dynamic_cast<TRTransfer*>(transfers->ItemAt(i)))->GetTorrent(); 
 
415
                        const tr_info_t *info = tr_torrentInfo(torrent);
 
416
                        const tr_stat_t *stat = tr_torrentStat(torrent);
 
417
                        
 
418
                        strItem << info->torrent << ".running";
 
419
                        if (stat->status & (TR_STATUS_CHECK_WAIT | TR_STATUS_CHECK | TR_STATUS_DOWNLOAD | TR_STATUS_SEED)) {
 
420
                                prefs->SetBool(strItem.String(), true);
 
421
                                tr_torrentStop(torrent);
 
422
                        } else {
 
423
                                prefs->SetBool(strItem.String(), false);
 
424
                        }
 
425
                }
 
426
                delete prefs;
 
427
                
 
428
                if (running > 0) {
 
429
                        stopping = true;
 
430
                        BAlert *waiting = new BAlert("Stopping Torrents", "Waiting for torrents to stop...", "Quit");
 
431
                        quitter = new BInvoker(new BMessage(B_QUIT_REQUESTED), BMessenger(be_app));
 
432
                        waiting->Go(quitter);
 
433
                        quit = false;
 
434
                } else {
 
435
                        be_app->PostMessage(new BMessage(B_QUIT_REQUESTED));
 
436
                }
 
437
        }
 
438
        return quit;
 
439
}
 
440
 
 
441
void TRWindow::FrameResized(float, float) {
 
442
        transfers->Invalidate();
 
443
}
 
444
 
 
445
 
 
446
/**
 
447
 * Called from the StopTorrent thread.
 
448
 */
 
449
void TRWindow::StopTorrent(tr_torrent_t *torrent) {
 
450
        tr_torrentStop(torrent);
 
451
        
 
452
        UpdateList(transfers->CurrentSelection(), true);
 
453
}
 
454
 
 
455
BString TRWindow::GetFolder(void) {
 
456
        // Read the settings.
 
457
        BString folder("");
 
458
        Prefs *prefs = new Prefs(TRANSMISSION_SETTINGS);
 
459
        if (prefs->FindString("download.folder", &folder) != B_OK) {
 
460
                prefs->SetString("download.folder", "/boot/home/Downloads");
 
461
                folder << "/boot/home/Downloads";
 
462
        }
 
463
        delete prefs;
 
464
        return folder;
 
465
}
 
466
 
 
467
/**
 
468
 * Called from StartTorrent thread.
 
469
 */
 
470
void TRWindow::StartTorrent(tr_torrent_t *torrent) {
 
471
        tr_torrentSetFolder(torrent, GetFolder().String());
 
472
        tr_torrentStart(torrent);
 
473
        
 
474
        if (transfers->CurrentSelection() >= 0) {
 
475
                UpdateList(transfers->CurrentSelection(), true);
 
476
        }
 
477
}
 
478
 
 
479
/**
 
480
 * Called from the be_app Pulse();
 
481
 * This will update the data structures that the TRTorrents use to render,
 
482
 * and invalidate the view.
 
483
 */
 
484
void TRWindow::UpdateList(int32 selection = -1, bool menus = true) {
 
485
        if (stopping)
 
486
        {
 
487
                quit_info *quitData = (quit_info*)calloc(1, sizeof(quit_info));
 
488
                quitData->running = 0;
 
489
                transfers->DoForEach(TRWindow::CheckQuitStatus, (void *)quitData);
 
490
                if (quitData->running == 0)
 
491
                        be_app->PostMessage(new BMessage(B_QUIT_REQUESTED));
 
492
                free(quitData);
 
493
        }
 
494
 
 
495
        update_info *upData = (update_info*)calloc(1, sizeof(update_info));
 
496
        upData->running = false;
 
497
        upData->selected = selection;
 
498
        upData->invalid = 0;
 
499
        
 
500
        transfers->DoForEach(TRWindow::UpdateStats, (void *)upData);
 
501
        
 
502
        if (menus) {
 
503
                KeyMenuBar()->FindItem(TR_INFO)->SetEnabled(selection >= 0);
 
504
                KeyMenuBar()->FindItem(TR_RESUME)->SetEnabled(selection >= 0 && !upData->running);
 
505
                KeyMenuBar()->FindItem(TR_PAUSE)->SetEnabled(selection >= 0 && upData->running);
 
506
                KeyMenuBar()->FindItem(TR_REMOVE)->SetEnabled(selection >= 0 && !upData->running);
 
507
        }
 
508
        
 
509
        if (upData->invalid > 0 && transfers->LockLooper()) {
 
510
                transfers->Invalidate();
 
511
                transfers->UnlockLooper();
 
512
        }
 
513
        
 
514
        free(upData);
 
515
}
 
516
 
 
517
 
 
518
 
 
519
/**
 
520
 * Thread Function to stop Torrents. This can be expensive and causes the event loop to
 
521
 * choke.
 
522
 */
 
523
int32 TRWindow::AsynchStopTorrent(void *data) {
 
524
        worker_info* stopData = (worker_info*)data;
 
525
        stopData->window->StopTorrent(stopData->torrent);
 
526
        free(stopData);
 
527
        return B_OK;
 
528
}
 
529
 
 
530
/**
 
531
 * Thread Function to start Torrents. This can be expensive and causes the event loop to
 
532
 * choke.
 
533
 */
 
534
int32 TRWindow::AsynchStartTorrent(void *data) {
 
535
        worker_info* startData = (worker_info*)data;
 
536
        startData->window->StartTorrent(startData->torrent);
 
537
        free(startData);
 
538
        return B_OK;
 
539
}
 
540
 
 
541
/**
 
542
 * Invoked by DoForEach upon the transfers list. This will
 
543
 * remove the item that is caching the path specified by 
 
544
 * path.
 
545
 */
 
546
bool TRWindow::RemovePath(BListItem *item, void *data) {
 
547
        remove_info* removeData = (remove_info*)data;
 
548
        TRTransfer *transfer = dynamic_cast<TRTransfer*>(item);
 
549
        
 
550
        if (strcmp(transfer->GetCachedPath(), removeData->path) == 0) {
 
551
                removeData->window->transfers->RemoveItem(transfer);
 
552
                return true;
 
553
        }
 
554
        return false;
 
555
}
 
556
 
 
557
/**
 
558
 * Invoked during QuitRequested, iterates all Transfers and 
 
559
 * checks to see how many are running.
 
560
 */
 
561
bool TRWindow::CheckQuitStatus(BListItem *item, void *data) {
 
562
        quit_info* quitData = (quit_info*)data;
 
563
        TRTransfer *transfer = dynamic_cast<TRTransfer*>(item);
 
564
        
 
565
        if (transfer->IsRunning()) {
 
566
                quitData->running++;
 
567
        }
 
568
        return false;
 
569
}
 
570
 
 
571
/**
 
572
 * Invoked during UpdateList()
 
573
 */
 
574
bool TRWindow::UpdateStats(BListItem *item, void *data) {
 
575
        update_info* upData = (update_info*)data;
 
576
        TRTransfer *transfer = dynamic_cast<TRTransfer*>(item);
 
577
        
 
578
        int32 index = transfers->IndexOf(transfer);
 
579
        if (transfer->UpdateStatus(tr_torrentStat(transfer->GetTorrent()), index % 2 == 0)) {
 
580
                upData->invalid++;
 
581
        }
 
582
        
 
583
        if (index == upData->selected) {
 
584
                upData->running = transfer->IsRunning();
 
585
        }
 
586
        
 
587
        return false;
 
588
}