Esempio n. 1
0
void
DownloadProgressView::MessageReceived(BMessage* message)
{
	switch (message->what) {
		case B_DOWNLOAD_STARTED:
		{
			BString path;
			if (message->FindString("path", &path) != B_OK)
				break;
			fPath.SetTo(path);
			BEntry entry(fPath.Path());
			fIconView->SetTo(entry);
			fStatusBar->Reset(fPath.Leaf());
			_StartNodeMonitor(entry);

			// Immediately switch to speed display whenever a new download
			// starts.
			sShowSpeed = true;
			sLastEstimatedFinishSpeedToggleTime
				= fProcessStartTime = fLastSpeedReferenceTime
				= fEstimatedFinishReferenceTime = system_time();
			break;
		}
		case B_DOWNLOAD_PROGRESS:
		{
			int64 currentSize;
			int64 expectedSize;
			if (message->FindInt64("current size", &currentSize) == B_OK
				&& message->FindInt64("expected size", &expectedSize) == B_OK) {
				_UpdateStatus(currentSize, expectedSize);
			}
			break;
		}
		case B_DOWNLOAD_REMOVED:
			// TODO: This is a bit asymetric. The removed notification
			// arrives here, but it would be nicer if it arrived
			// at the window...
			Window()->PostMessage(message);
			break;
		case OPEN_DOWNLOAD:
		{
			// TODO: In case of executable files, ask the user first!
			entry_ref ref;
			status_t status = get_ref_for_path(fPath.Path(), &ref);
			if (status == B_OK)
				status = be_roster->Launch(&ref);
			if (status != B_OK && status != B_ALREADY_RUNNING) {
				BAlert* alert = new BAlert("Open download error",
					"The download could not be opened.", "OK");
				alert->Go(NULL);
			}
			break;
		}
		case RESTART_DOWNLOAD:
			BWebPage::RequestDownload(fURL);
			break;

		case CANCEL_DOWNLOAD:
			fDownload->Cancel();
			DownloadCanceled();
			break;

		case REMOVE_DOWNLOAD:
		{
			Window()->PostMessage(SAVE_SETTINGS);
			RemoveSelf();
			delete this;
			// TOAST!
			return;
		}
		case B_NODE_MONITOR:
		{
			int32 opCode;
			if (message->FindInt32("opcode", &opCode) != B_OK)
				break;
			switch (opCode) {
				case B_ENTRY_REMOVED:
					fIconView->SetIconDimmed(true);
					DownloadCanceled();
					break;
				case B_ENTRY_MOVED:
				{
					// Follow the entry to the new location
					dev_t device;
					ino_t directory;
					const char* name;
					if (message->FindInt32("device",
							reinterpret_cast<int32*>(&device)) != B_OK
						|| message->FindInt64("to directory",
							reinterpret_cast<int64*>(&directory)) != B_OK
						|| message->FindString("name", &name) != B_OK
						|| strlen(name) == 0) {
						break;
					}
					// Construct the BEntry and update fPath
					entry_ref ref(device, directory, name);
					BEntry entry(&ref);
					if (entry.GetPath(&fPath) != B_OK)
						break;

					// Find out if the directory is the Trash for this
					// volume
					char trashPath[B_PATH_NAME_LENGTH];
					if (find_directory(B_TRASH_DIRECTORY, device, false,
							trashPath, B_PATH_NAME_LENGTH) == B_OK) {
						BPath trashDirectory(trashPath);
						BPath parentDirectory;
						fPath.GetParent(&parentDirectory);
						if (parentDirectory == trashDirectory) {
							// The entry was moved into the Trash.
							// If the download is still in progress,
							// cancel it.
							if (fDownload)
								fDownload->Cancel();
							fIconView->SetIconDimmed(true);
							DownloadCanceled();
							break;
						} else if (fIconView->IsIconDimmed()) {
							// Maybe it was moved out of the trash.
							fIconView->SetIconDimmed(false);
						}
					}

					// Inform download of the new path
					if (fDownload)
						fDownload->HasMovedTo(fPath);

					float value = fStatusBar->CurrentValue();
					fStatusBar->Reset(name);
					fStatusBar->SetTo(value);
					Window()->PostMessage(SAVE_SETTINGS);
					break;
				}
				case B_ATTR_CHANGED:
				{
					BEntry entry(fPath.Path());
					fIconView->SetIconDimmed(false);
					fIconView->SetTo(entry);
					break;
				}
			}
			break;
		}

		// Context menu messages
		case COPY_URL_TO_CLIPBOARD:
			if (be_clipboard->Lock()) {
				BMessage* data = be_clipboard->Data();
				if (data != NULL) {
					be_clipboard->Clear();
					data->AddData("text/plain", B_MIME_TYPE, fURL.String(),
						fURL.Length());
				}
				be_clipboard->Commit();
				be_clipboard->Unlock();
			}
			break;
		case OPEN_CONTAINING_FOLDER:
			if (fPath.InitCheck() == B_OK) {
				BPath containingFolder;
				if (fPath.GetParent(&containingFolder) != B_OK)
					break;
				BEntry entry(containingFolder.Path());
				if (!entry.Exists())
					break;
				entry_ref ref;
				if (entry.GetRef(&ref) != B_OK)
					break;
				be_roster->Launch(&ref);

				// Use Tracker scripting and select the download pose
				// in the window.
				// TODO: We should somehow get the window that just openend.
				// Using the name like this is broken when there are multiple
				// windows open with this name. Also Tracker does not scroll
				// to this entry.
				BString windowName = ref.name;
				BString fullWindowName = containingFolder.Path();

				BMessenger trackerMessenger("application/x-vnd.Be-TRAK");
				if (trackerMessenger.IsValid()
					&& get_ref_for_path(fPath.Path(), &ref) == B_OK) {
					// We need to wait a bit until the folder is open.
					// TODO: This is also too fragile... we should be able
					// to wait for the roster message.
					snooze(250000);
					int32 tries = 2;
					while (tries > 0) {
						BMessage selectionCommand(B_SET_PROPERTY);
						selectionCommand.AddSpecifier("Selection");
						selectionCommand.AddSpecifier("Poses");
						selectionCommand.AddSpecifier("Window",
							windowName.String());
						selectionCommand.AddRef("data", &ref);
						BMessage reply;
						trackerMessenger.SendMessage(&selectionCommand, &reply);
						int32 error;
						if (reply.FindInt32("error", &error) != B_OK
							|| error == B_OK) {
							break;
						}
						windowName = fullWindowName;
						tries--;
					}
				}
			}
			break;

		default:
			BGroupView::MessageReceived(message);
	}
}
Esempio n. 2
0
void
DownloadProgressView::MessageReceived(BMessage* message)
{
	switch (message->what) {
		case B_DOWNLOAD_STARTED:
		{
			BString path;
			if (message->FindString("path", &path) != B_OK)
				break;
			fPath.SetTo(path);
			BEntry entry(fPath.Path());
			fIconView->SetTo(entry);
			fStatusBar->Reset(fPath.Leaf());
			_StartNodeMonitor(entry);

			// Immediately switch to speed display whenever a new download
			// starts.
			sShowSpeed = true;
			sLastEstimatedFinishSpeedToggleTime
				= fProcessStartTime = fLastSpeedReferenceTime
				= fEstimatedFinishReferenceTime = system_time();
			break;
		}
		case B_DOWNLOAD_PROGRESS:
		{
			int64 currentSize;
			int64 expectedSize;
			if (message->FindInt64("current size", &currentSize) == B_OK
				&& message->FindInt64("expected size", &expectedSize) == B_OK) {
				_UpdateStatus(currentSize, expectedSize);
			}
			break;
		}
		case B_DOWNLOAD_REMOVED:
			// TODO: This is a bit asymetric. The removed notification
			// arrives here, but it would be nicer if it arrived
			// at the window...
			Window()->PostMessage(message);
			break;
		case OPEN_DOWNLOAD:
		{
			// TODO: In case of executable files, ask the user first!
			entry_ref ref;
			status_t status = get_ref_for_path(fPath.Path(), &ref);
			if (status == B_OK)
				status = be_roster->Launch(&ref);
			if (status != B_OK && status != B_ALREADY_RUNNING) {
				BAlert* alert = new BAlert(B_TRANSLATE("Open download error"),
					B_TRANSLATE("The download could not be opened."),
					B_TRANSLATE("OK"));
				alert->SetFlags(alert->Flags() | B_CLOSE_ON_ESCAPE);
				alert->Go(NULL);
			}
			break;
		}
		case RESTART_DOWNLOAD:
		{
			// We can't create a download without a full web context (mainly
			// because it needs to access the cookie jar), and when we get here
			// the original context is long gone (possibly the browser was
			// restarted). So we create a new window to restart the download
			// in a fresh context.
			// FIXME this has of course the huge downside of leaving the new
			// window open with a blank page. I can't think of a better
			// solution right now...
			BMessage* request = new BMessage(NEW_WINDOW);
			request->AddString("url", fURL);
			be_app->PostMessage(request);
			break;
		}

		case CANCEL_DOWNLOAD:
			CancelDownload();
			break;

		case REMOVE_DOWNLOAD:
		{
			Window()->PostMessage(SAVE_SETTINGS);
			RemoveSelf();
			delete this;
			// TOAST!
			return;
		}
		case B_NODE_MONITOR:
		{
			int32 opCode;
			if (message->FindInt32("opcode", &opCode) != B_OK)
				break;
			switch (opCode) {
				case B_ENTRY_REMOVED:
					fIconView->SetIconDimmed(true);
					CancelDownload();
					break;
				case B_ENTRY_MOVED:
				{
					// Follow the entry to the new location
					dev_t device;
					ino_t directory;
					const char* name;
					if (message->FindInt32("device",
							reinterpret_cast<int32*>(&device)) != B_OK
						|| message->FindInt64("to directory",
							reinterpret_cast<int64*>(&directory)) != B_OK
						|| message->FindString("name", &name) != B_OK
						|| strlen(name) == 0) {
						break;
					}
					// Construct the BEntry and update fPath
					entry_ref ref(device, directory, name);
					BEntry entry(&ref);
					if (entry.GetPath(&fPath) != B_OK)
						break;

					// Find out if the directory is the Trash for this
					// volume
					char trashPath[B_PATH_NAME_LENGTH];
					if (find_directory(B_TRASH_DIRECTORY, device, false,
							trashPath, B_PATH_NAME_LENGTH) == B_OK) {
						BPath trashDirectory(trashPath);
						BPath parentDirectory;
						fPath.GetParent(&parentDirectory);
						if (parentDirectory == trashDirectory) {
							// The entry was moved into the Trash.
							// If the download is still in progress,
							// cancel it.
							fIconView->SetIconDimmed(true);
							CancelDownload();
							break;
						} else if (fIconView->IsIconDimmed()) {
							// Maybe it was moved out of the trash.
							fIconView->SetIconDimmed(false);
						}
					}

					// Inform download of the new path
					if (fDownload)
						fDownload->HasMovedTo(fPath);

					float value = fStatusBar->CurrentValue();
					fStatusBar->Reset(name);
					fStatusBar->SetTo(value);
					Window()->PostMessage(SAVE_SETTINGS);
					break;
				}
				case B_ATTR_CHANGED:
				{
					BEntry entry(fPath.Path());
					fIconView->SetIconDimmed(false);
					fIconView->SetTo(entry);
					break;
				}
			}
			break;
		}

		// Context menu messages
		case COPY_URL_TO_CLIPBOARD:
			if (be_clipboard->Lock()) {
				BMessage* data = be_clipboard->Data();
				if (data != NULL) {
					be_clipboard->Clear();
					data->AddData("text/plain", B_MIME_TYPE, fURL.String(),
						fURL.Length());
				}
				be_clipboard->Commit();
				be_clipboard->Unlock();
			}
			break;
		case OPEN_CONTAINING_FOLDER:
			if (fPath.InitCheck() == B_OK) {
				BEntry selected(fPath.Path());
				if (!selected.Exists())
					break;

				BPath containingFolder;
				if (fPath.GetParent(&containingFolder) != B_OK)
					break;
				entry_ref ref;
				if (get_ref_for_path(containingFolder.Path(), &ref) != B_OK)
					break;

				// Ask Tracker to open the containing folder and select the
				// file inside it.
				BMessenger trackerMessenger("application/x-vnd.Be-TRAK");

				if (trackerMessenger.IsValid()) {
					BMessage selectionCommand(B_REFS_RECEIVED);
					selectionCommand.AddRef("refs", &ref);

					node_ref selectedRef;
					if (selected.GetNodeRef(&selectedRef) == B_OK) {
						selectionCommand.AddData("nodeRefToSelect", B_RAW_TYPE,
							(void*)&selectedRef, sizeof(node_ref));
					}

					trackerMessenger.SendMessage(&selectionCommand);
				}
			}
			break;

		default:
			BGroupView::MessageReceived(message);
	}
}