Not a member of Pastebin yet?
Sign Up,
it unlocks many cool features!
- #include "TRWindow.h"
- #include <Button.h>
- #include <View.h>
- #include <MenuBar.h>
- #include <Menu.h>
- #include <ListView.h>
- #include <ListItem.h>
- #include <Layout.h>
- #include <LayoutBuilder.h>
- #include <GroupLayout.h>
- #include <ScrollView.h>
- #include <StringView.h>
- #include <MenuItem.h>
- #include <String.h>
- #include <NodeMonitor.h>
- #include <Roster.h>
- #include <Alert.h>
- #include "libPrefs/Prefs.h"
- #include "TRApplication.h"
- #include "TRTransfer.h"
- #include "TRInfoWindow.h"
- #include <stdio.h>
- #include <stdlib.h>
- #include "libtransmission/transmission.h"
- #include "libtransmission/utils.h"
- #include "libtransmission/bencode.h"
- enum
- {
- M_OPEN_TORRENT = 'tope'
- };
- #define MENU_HEIGHT 20
- TRWindow::TRWindow(void)
- : BWindow(BRect(100,100,400,300), "Transmission", B_TITLED_WINDOW,
- B_ASYNCHRONOUS_CONTROLS | B_AUTO_UPDATE_SIZE_LIMITS | B_QUIT_ON_WINDOW_CLOSE)
- {
- tr_benc settings;
- const char *configDir = tr_getDefaultConfigDir("Transmission");
- tr_bencInitDict(&settings, 0);
- tr_sessionGetDefaultSettings(&settings);
- fSession = tr_sessionInit("haiku", configDir, true, &settings);
- tr_bencFree(&settings);
- fCtor = tr_ctorNew(fSession);
- BMenuBar *menuBar = new BMenuBar("menubar");
- BMenu *menu = new BMenu("File");
- menu->AddItem(new BMenuItem("Quit", new BMessage(B_QUIT_REQUESTED), 'Q'));
- menu->AddItem(new BMenuItem("Open", new BMessage(M_OPEN_TORRENT), 'O'));
- menuBar->AddItem(menu);
- fTorrentList = static_cast<TRListView*>(new BListView(Bounds(), "torrents", B_SINGLE_SELECTION_LIST));
- BStringView *cmd = new BStringView("cmd", "hey you!");
- BScrollView *scrollView = new BScrollView("scrollview", fTorrentList, B_FOLLOW_ALL, 0, true, true);
- BLayoutBuilder::Group<>(this, B_VERTICAL, 0)
- .SetInsets(0, 0, 0, 0)
- .Add(menuBar)
- .Add(cmd)
- .Add(scrollView);
- }
- TRWindow::~TRWindow(void)
- {
- tr_ctorFree(fCtor);
- tr_sessionClose(fSession);
- }
- void TRWindow::LoadSettings() {
- if (fSession != NULL) {
- Prefs prefs(TRANSMISSION_SETTINGS);
- int32 bindPort;
- if (prefs.FindInt32("transmission.bindPort", &bindPort) != B_OK) {
- bindPort = atoi(PORT);
- prefs.SetInt32("transmission.bindPort", bindPort);
- }
- //tr_setBindPort(fSession, (int)bindPort);
- //---------------------------------------------------------------------
- int32 totalUploadLimit;
- if (prefs.FindInt32("transmission.totalUploadLimit", &totalUploadLimit) != B_OK){
- totalUploadLimit = atoi(TOTALUPLOADLIMIT);
- prefs.SetInt32("transmission.totalUploadLimit", totalUploadLimit);
- }
- //-------------------------------------------------------------------------
- int32 totalDownloadLimit;
- if (prefs.FindInt32("transmission.totalDownloadLimit", &totalDownloadLimit) != B_OK){
- totalDownloadLimit = atoi(TOTALDOWNLOADLIMIT);
- prefs.SetInt32("transmission.totalDownloadLimit", totalDownloadLimit);
- }
- tr_sessionSetSpeedLimit_KBps(fSession, TR_DOWN, (int)totalDownloadLimit);
- tr_sessionSetSpeedLimit_KBps(fSession, TR_UP, (int)totalUploadLimit);
- }
- }
- /**
- * Rescans the active Torrents folder, and will add all the torrents there to the
- * engine. Called during initial Application Start & Stop.
- */
- void TRWindow::RescanTorrents() {
- if (Lock()) {
- TRApplication *app = dynamic_cast<TRApplication*>(be_app);
- BEntry *torrentEntry = new BEntry();
- status_t err;
- if (app->TorrentDir()->InitCheck() == B_OK) {
- err = app->TorrentDir()->Rewind();
- while (err == B_OK) {
- err = app->TorrentDir()->GetNextEntry(torrentEntry, true);
- if (err != B_ENTRY_NOT_FOUND) {
- AddEntry(torrentEntry);
- }
- }
- }
- delete torrentEntry;
- Unlock();
- }
- }
- /**
- * Adds the file specified by *torrent to the Transmission engine.
- * Then adds a new TRTransfer item in the fTorrentList.
- * This item holds cached information about the torrent entry and node.
- * These TRTransmission items are _NOT_ guaranteed to render the entry
- * they were created from.
- */
- void TRWindow::AddEntry(BEntry *torrent) {
- node_ref node;
- if (torrent->GetNodeRef(&node) == B_OK) {
- if (watch_node(&node, B_WATCH_NAME, this) == B_OK) {
- BPath path;
- torrent->GetPath(&path);
- // Try adding the torrent to the engine.
- int error;
- tr_ctorSetMetainfoFromFile(fCtor, path.Path());
- tr_torrent *nTorrent = tr_torrentNew(fCtor, &error);
- if (nTorrent != NULL && Lock()) { // Success. Add the TRTorrent item.
- fTorrentList->AddItem(new TRTransfer(path.Path(), node, nTorrent));
- bool autoStart = true;
- // Decide if we should auto-start this torrent or not.
- BString prefName("download.");
- prefName << path.Path() << ".running";
- Prefs *prefs = new Prefs(TRANSMISSION_SETTINGS);
- if (prefs->FindBool(prefName.String(), &autoStart) != B_OK) {
- autoStart = true;
- }
- delete prefs;
- if (autoStart) {
- // Start the newly added torrent.
- worker_info *startData = (worker_info*)calloc(1, sizeof(worker_info));
- startData->window = this;
- startData->torrent = nTorrent;
- thread_id start_thread = spawn_thread(TRWindow::AsynchStartTorrent, "BirthCanal",
- B_NORMAL_PRIORITY, (void *)startData);
- if (!((start_thread) < B_OK)) {
- resume_thread(start_thread);
- } else { // Fallback and start the old way.
- StartTorrent(startData->torrent);
- free(startData);
- }
- }
- Unlock();
- } else {
- bool duplicate = false;
- TRTransfer* tr;
- for (int32 i = 0; i < fTorrentList->CountItems(); i++) {
- tr = (TRTransfer*)fTorrentList->ItemAt(i);
- if (tr->GetCachedNodeRef() == node) {
- duplicate = true;
- }
- }
- if (!duplicate) {
- BString errmsg("An error occurred trying to read ");
- char namebuf[B_FILE_NAME_LENGTH];
- torrent->GetName(namebuf);
- errmsg << namebuf;
- errmsg << ".";
- BAlert *error = new BAlert("Error Opening Torrent",
- errmsg.String(),
- "Ok", NULL, NULL,
- B_WIDTH_AS_USUAL, B_WARNING_ALERT);
- error->Go();
- torrent->Remove();
- }
- }
- }
- }
- }
- void TRWindow::MessageReceived(BMessage *msg) {
- // msg->PrintToStream();
- switch(msg->what){
- case B_NODE_MONITOR:{
- /*
- * The only messages we receive from the node_monitor are if we need to
- * stop watching the node. Basically, if it's been moved or removed we stop.
- */
- node_ref node;
- ino_t fromDir;
- ino_t toDir;
- int32 opcode;
- if ((msg->FindInt32("opcode", &opcode) == B_OK) &&
- (msg->FindInt64("node", &node.node) == B_OK) &&
- (msg->FindInt32("device", &node.device) == B_OK))
- {
- bool stop = (opcode == B_ENTRY_REMOVED);
- if (stop) {
- msg->FindInt64("directory", &toDir);
- } else { // It must have moved.
- stop = ((msg->FindInt64("from directory", &fromDir) == B_OK) &&
- (msg->FindInt64("to directory", &toDir) == B_OK) &&
- (toDir != fromDir));
- }
- if (stop) {
- watch_node(&node, B_STOP_WATCHING, this);
- /* Find the full path from the TRTorrents. The index of the
- * TRTorrent that is caching the information IS NOT the
- * index of the torrent in the engine. These are Totally
- * decoupled, due to the way transmission is written.
- */
- remove_info *removeData = (remove_info*)calloc(1, sizeof(remove_info));
- removeData->window = this;
- TRTransfer* item;
- for (int32 i = 0; i < fTorrentList->CountItems(); i++) {
- item = (TRTransfer*)fTorrentList->ItemAt(i);
- if (item->GetCachedNodeRef() == node) {
- strcpy(removeData->path, item->GetCachedPath());
- }
- }
- fTorrentList->DoForEach(TRWindow::RemovePath, (void *)removeData);
- free(removeData);
- }
- }
- }break;
- case TR_INFO: {
- GetTorrentInfo();
- }break;
- case TR_RESUME: {
- ResumeTorrent();
- }break;
- case TR_PAUSE:{
- PauseTorrent();
- }break;
- case TR_REMOVE: {
- RemoveTorrent();
- }break;
- case B_SIMPLE_DATA:{
- be_app->RefsReceived(msg);
- }break;
- default: {
- //msg->PrintToStream();
- BWindow::MessageReceived(msg);
- }break;
- }
- }
- /**
- * Handles QuitRequests.
- * Displays a BAlert asking if the user really wants to quit if torrents are running.
- * If affimative, then we'll stop all the running torrents.
- */
- bool TRWindow::QuitRequested() {
- if (stopping)
- return true;
- bool quit = false;
- int running;
- quit_info *quitData = (quit_info*)calloc(1, sizeof(quit_info));
- quitData->running = 0;
- fTorrentList->DoForEach(TRWindow::CheckQuitStatus, (void *)quitData);
- running = quitData->running;
- free(quitData);
- if (running > 0) {
- BString quitMsg("");
- quitMsg << "There's " << running << " torrent";
- if (running > 1) {
- quitMsg << "s";
- }
- quitMsg << " currently running.\n"
- << "What would you like to do?";
- BAlert *confirmQuit = new BAlert("Confirm Quit", quitMsg.String(),
- "Cancel", "Quit", NULL,
- B_WIDTH_AS_USUAL, B_WARNING_ALERT);
- quit = (confirmQuit->Go() == 1);
- } else {
- quit = true;
- }
- if (quit) {
- Prefs *prefs = new Prefs(TRANSMISSION_SETTINGS);
- prefs->SetRect("window.frame", Frame());
- BString strItem("");
- for (int i = 0; i < fTorrentList->CountItems(); i++) {
- strItem = "download.";
- tr_torrent *torrent = (dynamic_cast<TRTransfer*>(fTorrentList->ItemAt(i)))->GetTorrent();
- const tr_info *info = tr_torrentInfo(torrent);
- const tr_stat *stat = tr_torrentStat(torrent);
- strItem << info->torrent << ".running";
- if (stat->activity & (TR_STATUS_CHECK_WAIT | TR_STATUS_CHECK | TR_STATUS_DOWNLOAD | TR_STATUS_SEED)) {
- prefs->SetBool(strItem.String(), true);
- tr_torrentStop(torrent);
- } else {
- prefs->SetBool(strItem.String(), false);
- }
- }
- delete prefs;
- if (running > 0) {
- stopping = true;
- BAlert *waiting = new BAlert("Stopping Torrents", "Waiting for torrents to stop...", "Quit");
- quitter = new BInvoker(new BMessage(B_QUIT_REQUESTED), BMessenger(be_app));
- waiting->Go(quitter);
- quit = false;
- } else {
- be_app->PostMessage(new BMessage(B_QUIT_REQUESTED));
- }
- }
- return quit;
- }
- void TRWindow::FrameResized(float, float) {
- fTorrentList->Invalidate();
- }
- /**
- * Called from the StopTorrent thread.
- */
- void TRWindow::StopTorrent(tr_torrent *torrent) {
- tr_torrentStop(torrent);
- UpdateList(fTorrentList->CurrentSelection(), true, NULL);
- }
- BString TRWindow::GetFolder(void) {
- // Read the settings.
- BString folder("");
- Prefs *prefs = new Prefs(TRANSMISSION_SETTINGS);
- if (prefs->FindString("download.folder", &folder) != B_OK) {
- prefs->SetString("download.folder", "/boot/home/Downloads");
- folder << "/boot/home/Downloads";
- }
- delete prefs;
- return folder;
- }
- /**
- * Called from StartTorrent thread.
- */
- void TRWindow::StartTorrent(tr_torrent *torrent) {
- // transmission.h comments recommend NOT to use tr_torrentSetDownloadDir
- tr_torrentSetDownloadDir(torrent, GetFolder().String());
- tr_torrentStart(torrent);
- if (fTorrentList->CurrentSelection() >= 0) {
- UpdateList(fTorrentList->CurrentSelection(), true, NULL);
- }
- }
- /**
- * Called from the be_app Pulse();
- * This will update the data structures that the TRTorrents use to render,
- * and invalidate the view.
- */
- void TRWindow::UpdateList(int32 selection = -1, bool menus = true, BPopUpMenu *popUpMenu = NULL) {
- if (stopping)
- {
- quit_info *quitData = (quit_info*)calloc(1, sizeof(quit_info));
- quitData->running = 0;
- fTorrentList->DoForEach(TRWindow::CheckQuitStatus, (void *)quitData);
- if (quitData->running == 0)
- be_app->PostMessage(new BMessage(B_QUIT_REQUESTED));
- free(quitData);
- }
- update_info *upData = (update_info*)calloc(1, sizeof(update_info));
- upData->running = false;
- upData->selected = selection;
- upData->invalid = 0;
- fTorrentList->DoForEach(TRWindow::UpdateStats, (void *)upData);
- if (menus) {
- KeyMenuBar()->FindItem(TR_INFO)->SetEnabled(selection >= 0);
- KeyMenuBar()->FindItem(TR_RESUME)->SetEnabled(selection >= 0 && !upData->running);
- KeyMenuBar()->FindItem(TR_PAUSE)->SetEnabled(selection >= 0 && upData->running);
- KeyMenuBar()->FindItem(TR_REMOVE)->SetEnabled(selection >= 0 && !upData->running);
- }
- if(popUpMenu != NULL)
- {
- popUpMenu->FindItem(TR_INFO)->SetEnabled(selection >= 0);
- popUpMenu->FindItem(TR_RESUME)->SetEnabled(selection >= 0 && !upData->running);
- popUpMenu->FindItem(TR_PAUSE)->SetEnabled(selection >= 0 && upData->running);
- popUpMenu->FindItem(TR_REMOVE)->SetEnabled(selection >= 0 && !upData->running);
- }
- if (upData->invalid > 0 && fTorrentList->LockLooper()) {
- fTorrentList->Invalidate();
- fTorrentList->UnlockLooper();
- }
- free(upData);
- }
- /**
- * Thread Function to stop Torrents. This can be expensive and causes the event loop to
- * choke.
- */
- int32 TRWindow::AsynchStopTorrent(void *data)
- {
- worker_info* stopData = (worker_info*)data;
- stopData->window->StopTorrent(stopData->torrent);
- free(stopData);
- return B_OK;
- }
- /*
- bool TRWindow::SetMenuItemEnabled(uint32 comman)
- {
- uint32 comman
- }
- */
- /**
- * Thread Function to start Torrents. This can be expensive and causes the event loop to
- * choke.
- */
- int32 TRWindow::AsynchStartTorrent(void *data) {
- worker_info* startData = (worker_info*)data;
- startData->window->StartTorrent(startData->torrent);
- free(startData);
- return B_OK;
- }
- /**
- * Invoked by DoForEach upon the fTorrentList list. This will
- * remove the item that is caching the path specified by
- * path.
- */
- bool TRWindow::RemovePath(BListItem *item, void *data) {
- remove_info* removeData = (remove_info*)data;
- TRTransfer *transfer = dynamic_cast<TRTransfer*>(item);
- if (strcmp(transfer->GetCachedPath(), removeData->path) == 0) {
- removeData->window->fTorrentList->RemoveItem(transfer);
- return true;
- }
- return false;
- }
- /**
- * Invoked during QuitRequested, iterates all Transfers and
- * checks to see how many are running.
- */
- bool TRWindow::CheckQuitStatus(BListItem *item, void *data) {
- quit_info* quitData = (quit_info*)data;
- TRTransfer *transfer = dynamic_cast<TRTransfer*>(item);
- if (transfer->IsRunning()) {
- quitData->running++;
- }
- return false;
- }
- /**
- * Invoked during UpdateList()
- */
- bool TRWindow::UpdateStats(BListItem *item, void *data) {
- update_info* upData = (update_info*)data;
- TRTransfer *transfer = dynamic_cast<TRTransfer*>(item);
- int32 index = fTorrentList->IndexOf(transfer);
- if (transfer->UpdateStatus(tr_torrentStat(transfer->GetTorrent()), index % 2 == 0)) {
- upData->invalid++;
- }
- if (index == upData->selected) {
- upData->running = transfer->IsRunning();
- }
- return false;
- }
- BPopUpMenu * TRWindow::GetTorrentMenu()
- {
- BPopUpMenu * temp = new BPopUpMenu("Torrent");
- temp->AddItem(new BMenuItem("Get Info", new BMessage(TR_INFO), 'I', B_COMMAND_KEY));
- temp->FindItem(TR_INFO)->SetEnabled(false);
- temp->AddSeparatorItem();
- temp->AddItem(new BMenuItem("Resume", new BMessage(TR_RESUME)));
- temp->AddItem(new BMenuItem("Pause", new BMessage(TR_PAUSE)));
- temp->AddItem(new BMenuItem("Remove", new BMessage(TR_REMOVE)));
- temp->SetTargetForItems(this);
- return temp;
- }
- void TRWindow::GetTorrentInfo()
- {
- // Display an Info Window.
- TRTransfer *transfer = dynamic_cast<TRTransfer*>(fTorrentList->ItemAt(fTorrentList->CurrentSelection()));
- const tr_stat *s = tr_torrentStat(transfer->GetTorrent());
- const tr_info *i = tr_torrentInfo(transfer->GetTorrent());
- TRInfoWindow *info = new TRInfoWindow(s, i, transfer->GetTorrent(), tr_torrentGetDownloadDir(transfer->GetTorrent()));
- info->MoveTo(Frame().LeftTop() + BPoint(20, 25));
- info->Show();
- }
- void TRWindow::ResumeTorrent()
- {
- worker_info *startData = (worker_info*)calloc(1, sizeof(worker_info));
- startData->window = this;
- startData->torrent = (dynamic_cast<TRTransfer*>(fTorrentList->ItemAt(fTorrentList->CurrentSelection())))->GetTorrent();
- thread_id start_thread = spawn_thread(TRWindow::AsynchStartTorrent, "BirthCanal",B_NORMAL_PRIORITY, (void *)startData);
- if (!((start_thread) < B_OK)) {
- resume_thread(start_thread);
- } else { // Fallback and start the old way.
- StartTorrent(startData->torrent);
- free(startData);
- }
- }
- void TRWindow::PauseTorrent()
- {
- worker_info *stopData = (worker_info*)calloc(1, sizeof(worker_info));
- stopData->window = this;
- stopData->torrent = (dynamic_cast<TRTransfer*>(fTorrentList->ItemAt(fTorrentList->CurrentSelection())))->GetTorrent();
- thread_id stop_thread = spawn_thread(TRWindow::AsynchStopTorrent, "InUtero",
- B_NORMAL_PRIORITY, (void *)stopData);
- if (!((stop_thread) < B_OK)) {
- resume_thread(stop_thread);
- } else { // Fallback and stop it the old way.
- StopTorrent(stopData->torrent);
- free(stopData);
- }
- }
- int RemoveFile(const char *filename)
- {
- BEntry(filename).Remove();
- }
- void TRWindow::RemoveTorrent()
- {
- int32 index = fTorrentList->CurrentSelection();
- // Remove the file from the filesystem.
- TRTransfer *item = (TRTransfer*)fTorrentList->RemoveItem(index);
- tr_torrentRemove(item->GetTorrent(), false, RemoveFile);
- delete item;
- UpdateList(fTorrentList->CurrentSelection(), true, NULL);
- }
Advertisement
Add Comment
Please, Sign In to add comment