haiku/src/apps/codycam/CodyCam.cpp

954 lines
24 KiB
C++

/*
* Copyright 1998-1999 Be, Inc. All Rights Reserved.
* Copyright 2003-2019 Haiku, Inc. All rights reserved.
* Distributed under the terms of the MIT License.
*/
#include "CodyCam.h"
#include <stdio.h>
#include <string.h>
#include <unistd.h>
#include <Alert.h>
#include <Button.h>
#include <Catalog.h>
#include <FindDirectory.h>
#include <LayoutBuilder.h>
#include <MediaDefs.h>
#include <MediaNode.h>
#include <MediaRoster.h>
#include <MediaTheme.h>
#include <Menu.h>
#include <MenuBar.h>
#include <MenuItem.h>
#include <Path.h>
#include <PopUpMenu.h>
#include <scheduler.h>
#include <TabView.h>
#include <TextControl.h>
#include <TimeSource.h>
#include <TranslationUtils.h>
#include <TranslatorFormats.h>
#undef B_TRANSLATION_CONTEXT
#define B_TRANSLATION_CONTEXT "CodyCam"
#define VIDEO_SIZE_X 320
#define VIDEO_SIZE_Y 240
#define WINDOW_SIZE_X (VIDEO_SIZE_X + 80)
#define WINDOW_SIZE_Y (VIDEO_SIZE_Y + 230)
#define WINDOW_OFFSET_X 28
#define WINDOW_OFFSET_Y 28
#define CALL printf
#define ERROR printf
#define FTPINFO printf
#define INFO printf
// Utility functions
namespace {
// functions for EnumeratedStringValueSettings
const char*
CaptureRateAt(int32 i)
{
return (i >= 0 && i < kCaptureRatesCount) ? kCaptureRates[i].name : NULL;
}
const char*
UploadClientAt(int32 i)
{
return (i >= 0 && i < kUploadClientsCount) ? kUploadClients[i] : NULL;
}
}; // end anonymous namespace
// #pragma mark -
CodyCam::CodyCam()
:
BApplication("application/x-vnd.Haiku-CodyCam"),
fMediaRoster(NULL),
fVideoConsumer(NULL),
fWindow(NULL),
fPort(0),
fVideoControlWindow(NULL)
{
int32 index = 0;
kCaptureRates[index++].name = B_TRANSLATE("Every 15 seconds");
kCaptureRates[index++].name = B_TRANSLATE("Every 30 seconds");
kCaptureRates[index++].name = B_TRANSLATE("Every minute");
kCaptureRates[index++].name = B_TRANSLATE("Every 5 minutes");
kCaptureRates[index++].name = B_TRANSLATE("Every 10 minutes");
kCaptureRates[index++].name = B_TRANSLATE("Every 15 minutes");
kCaptureRates[index++].name = B_TRANSLATE("Every 30 minutes");
kCaptureRates[index++].name = B_TRANSLATE("Every hour");
kCaptureRates[index++].name = B_TRANSLATE("Every 2 hours");
kCaptureRates[index++].name = B_TRANSLATE("Every 4 hours");
kCaptureRates[index++].name = B_TRANSLATE("Every 8 hours");
kCaptureRates[index++].name = B_TRANSLATE("Every 24 hours");
kCaptureRates[index++].name = B_TRANSLATE("Never");
index = 0;
kUploadClients[index++] = B_TRANSLATE("FTP");
kUploadClients[index++] = B_TRANSLATE("SFTP");
kUploadClients[index++] = B_TRANSLATE("Local");
BPath homeDir;
if (find_directory(B_USER_DIRECTORY, &homeDir) != B_OK)
homeDir.SetTo("/boot/home");
chdir(homeDir.Path());
}
CodyCam::~CodyCam()
{
CALL("CodyCam::~CodyCam\n");
// release the video consumer node
// the consumer node cleans up the window
if (fVideoConsumer) {
fVideoConsumer->Release();
fVideoConsumer = NULL;
}
CALL("CodyCam::~CodyCam - EXIT\n");
}
void
CodyCam::ReadyToRun()
{
fWindow = new VideoWindow(
(const char*) B_TRANSLATE_SYSTEM_NAME("CodyCam"), B_TITLED_WINDOW,
B_NOT_ZOOMABLE | B_NOT_V_RESIZABLE
| B_AUTO_UPDATE_SIZE_LIMITS, &fPort);
if (_SetUpNodes() != B_OK)
fWindow->ToggleMenuOnOff();
((VideoWindow*)fWindow)->ApplyControls();
}
bool
CodyCam::QuitRequested()
{
_TearDownNodes();
snooze(100000);
return true;
}
void
CodyCam::MessageReceived(BMessage* message)
{
switch (message->what) {
case msg_start:
{
BTimeSource* timeSource = fMediaRoster->MakeTimeSourceFor(
fTimeSourceNode);
bigtime_t real = BTimeSource::RealTime();
bigtime_t perf = timeSource->PerformanceTimeFor(real) + 10000;
status_t status = fMediaRoster->StartNode(fProducerNode, perf);
if (status != B_OK)
ERROR("error starting producer!");
timeSource->Release();
break;
}
case msg_stop:
fMediaRoster->StopNode(fProducerNode, 0, true);
break;
case msg_video:
{
if (fVideoControlWindow) {
fVideoControlWindow->Activate();
break;
}
BParameterWeb* web = NULL;
BView* view = NULL;
media_node node = fProducerNode;
status_t err = fMediaRoster->GetParameterWebFor(node, &web);
if (err >= B_OK && web != NULL) {
view = BMediaTheme::ViewFor(web);
view->SetResizingMode(B_FOLLOW_ALL_SIDES);
fVideoControlWindow = new ControlWindow(view, node);
fMediaRoster->StartWatching(BMessenger(NULL,
fVideoControlWindow), node, B_MEDIA_WEB_CHANGED);
fVideoControlWindow->Show();
}
break;
}
case msg_control_win:
// our control window is being asked to go away
// set our pointer to NULL
fVideoControlWindow = NULL;
break;
default:
BApplication::MessageReceived(message);
break;
}
}
status_t
CodyCam::_SetUpNodes()
{
status_t status = B_OK;
/* find the media roster */
fMediaRoster = BMediaRoster::Roster(&status);
if (status != B_OK) {
fWindow->ErrorAlert(B_TRANSLATE("Cannot find the media roster"),
status);
return status;
}
/* find the time source */
status = fMediaRoster->GetTimeSource(&fTimeSourceNode);
if (status != B_OK) {
fWindow->ErrorAlert(B_TRANSLATE("Cannot get a time source"), status);
return status;
}
/* find a video producer node */
INFO("CodyCam acquiring VideoInput node\n");
status = fMediaRoster->GetVideoInput(&fProducerNode);
if (status != B_OK) {
fWindow->ErrorAlert(B_TRANSLATE("Cannot find a video source.\n"
"You need a webcam to use CodyCam."), status);
return status;
}
/* create the video consumer node */
fVideoConsumer = new VideoConsumer("CodyCam",
((VideoWindow*)fWindow)->VideoView(),
((VideoWindow*)fWindow)->StatusLine(), NULL, 0);
if (fVideoConsumer == NULL) {
fWindow->ErrorAlert(B_TRANSLATE("Cannot create a video window"),
B_ERROR);
return B_ERROR;
}
/* register the node */
status = fMediaRoster->RegisterNode(fVideoConsumer);
if (status != B_OK) {
fWindow->ErrorAlert(B_TRANSLATE("Cannot register the video window"),
status);
return status;
}
fPort = fVideoConsumer->ControlPort();
/* find free producer output */
int32 cnt = 0;
status = fMediaRoster->GetFreeOutputsFor(fProducerNode, &fProducerOut, 1,
&cnt, B_MEDIA_RAW_VIDEO);
if (status != B_OK || cnt < 1) {
status = B_RESOURCE_UNAVAILABLE;
fWindow->ErrorAlert(
B_TRANSLATE("Cannot find an available video stream"), status);
return status;
}
/* find free consumer input */
cnt = 0;
status = fMediaRoster->GetFreeInputsFor(fVideoConsumer->Node(),
&fConsumerIn, 1, &cnt, B_MEDIA_RAW_VIDEO);
if (status != B_OK || cnt < 1) {
status = B_RESOURCE_UNAVAILABLE;
fWindow->ErrorAlert(B_TRANSLATE("Can't find an available connection to "
"the video window"), status);
return status;
}
/* Connect The Nodes!!! */
media_format format;
format.type = B_MEDIA_RAW_VIDEO;
media_raw_video_format vid_format = {0, 1, 0, 239, B_VIDEO_TOP_LEFT_RIGHT,
1, 1, {B_RGB32, VIDEO_SIZE_X, VIDEO_SIZE_Y, VIDEO_SIZE_X * 4, 0, 0}};
format.u.raw_video = vid_format;
/* connect producer to consumer */
status = fMediaRoster->Connect(fProducerOut.source,
fConsumerIn.destination, &format, &fProducerOut, &fConsumerIn);
if (status != B_OK) {
fWindow->ErrorAlert(B_TRANSLATE("Cannot connect the video source to "
"the video window"), status);
return status;
}
/* set time sources */
status = fMediaRoster->SetTimeSourceFor(fProducerNode.node,
fTimeSourceNode.node);
if (status != B_OK) {
fWindow->ErrorAlert(B_TRANSLATE("Cannot set the time source for the "
"video source"), status);
return status;
}
status = fMediaRoster->SetTimeSourceFor(fVideoConsumer->ID(),
fTimeSourceNode.node);
if (status != B_OK) {
fWindow->ErrorAlert(B_TRANSLATE("Cannot set the time source for the "
"video window"), status);
return status;
}
/* figure out what recording delay to use */
bigtime_t latency = 0;
status = fMediaRoster->GetLatencyFor(fProducerNode, &latency);
status = fMediaRoster->SetProducerRunModeDelay(fProducerNode, latency);
/* start the nodes */
bigtime_t initLatency = 0;
status = fMediaRoster->GetInitialLatencyFor(fProducerNode, &initLatency);
if (status < B_OK) {
fWindow->ErrorAlert(B_TRANSLATE("Error getting initial latency for the "
"capture node"), status);
return status;
}
initLatency += estimate_max_scheduling_latency();
BTimeSource* timeSource = fMediaRoster->MakeTimeSourceFor(fProducerNode);
bool running = timeSource->IsRunning();
/* workaround for people without sound cards */
/* because the system time source won't be running */
bigtime_t real = BTimeSource::RealTime();
if (!running) {
status = fMediaRoster->StartTimeSource(fTimeSourceNode, real);
if (status != B_OK) {
timeSource->Release();
fWindow->ErrorAlert(B_TRANSLATE("Cannot start time source!"),
status);
return status;
}
status = fMediaRoster->SeekTimeSource(fTimeSourceNode, 0, real);
if (status != B_OK) {
timeSource->Release();
fWindow->ErrorAlert(B_TRANSLATE("Cannot seek time source!"),
status);
return status;
}
}
bigtime_t perf = timeSource->PerformanceTimeFor(real + latency
+ initLatency);
timeSource->Release();
/* start the nodes */
status = fMediaRoster->StartNode(fProducerNode, perf);
if (status != B_OK) {
fWindow->ErrorAlert(B_TRANSLATE("Cannot start the video source"),
status);
return status;
}
status = fMediaRoster->StartNode(fVideoConsumer->Node(), perf);
if (status != B_OK) {
fWindow->ErrorAlert(B_TRANSLATE("Cannot start the video window"),
status);
return status;
}
return status;
}
void
CodyCam::_TearDownNodes()
{
CALL("CodyCam::_TearDownNodes\n");
if (fMediaRoster == NULL)
return;
if (fVideoConsumer) {
/* stop */
INFO("stopping nodes!\n");
// fMediaRoster->StopNode(fProducerNode, 0, true);
fMediaRoster->StopNode(fVideoConsumer->Node(), 0, true);
/* disconnect */
fMediaRoster->Disconnect(fProducerOut.node.node, fProducerOut.source,
fConsumerIn.node.node, fConsumerIn.destination);
if (fProducerNode != media_node::null) {
INFO("CodyCam releasing fProducerNode\n");
fMediaRoster->ReleaseNode(fProducerNode);
fProducerNode = media_node::null;
}
fMediaRoster->ReleaseNode(fVideoConsumer->Node());
fVideoConsumer = NULL;
}
}
// #pragma mark - Video Window Class
VideoWindow::VideoWindow(const char* title, window_type type,
uint32 flags, port_id* consumerPort)
:
BWindow(BRect(50, 50, 50, 50), title, type, flags),
fPortPtr(consumerPort),
fVideoView(NULL)
{
fFtpInfo.port = 0;
fFtpInfo.rate = 0x7fffffff;
fFtpInfo.imageFormat = 0;
fFtpInfo.translator = 0;
fFtpInfo.passiveFtp = true;
fFtpInfo.uploadClient = 0;
strcpy(fFtpInfo.fileNameText, "filename");
strcpy(fFtpInfo.serverText, "server");
strcpy(fFtpInfo.loginText, "login");
strcpy(fFtpInfo.passwordText, "password");
strcpy(fFtpInfo.directoryText, "directory");
_SetUpSettings("codycam", "");
BMenuBar* menuBar = new BMenuBar("menu bar");
BMenuItem* menuItem;
fMenu = new BMenu(B_TRANSLATE("File"));
menuItem = new BMenuItem(B_TRANSLATE("Video settings"),
new BMessage(msg_video), 'P');
menuItem->SetTarget(be_app);
fMenu->AddItem(menuItem);
fMenu->AddSeparatorItem();
menuItem = new BMenuItem(B_TRANSLATE("Start video"),
new BMessage(msg_start), 'A');
menuItem->SetTarget(be_app);
fMenu->AddItem(menuItem);
menuItem = new BMenuItem(B_TRANSLATE("Stop video"),
new BMessage(msg_stop), 'O');
menuItem->SetTarget(be_app);
fMenu->AddItem(menuItem);
fMenu->AddSeparatorItem();
menuItem = new BMenuItem(B_TRANSLATE("Quit"),
new BMessage(B_QUIT_REQUESTED), 'Q');
menuItem->SetTarget(be_app);
fMenu->AddItem(menuItem);
menuBar->AddItem(fMenu);
/* add some controls */
_BuildCaptureControls();
BBox* box = new BBox("box");
BGroupLayout* layout = new BGroupLayout(B_VERTICAL);
box->SetLayout(layout);
layout->SetInsets(2, 2, 2, 2);
box->AddChild(fVideoView);
box->AddChild(fErrorView);
BLayoutBuilder::Group<>(this, B_VERTICAL, 0)
.Add(menuBar)
.AddGroup(B_VERTICAL)
.SetInsets(B_USE_WINDOW_SPACING)
.AddGroup(B_HORIZONTAL)
.AddGlue()
.Add(box)
.AddGlue()
.End()
.AddGroup(B_HORIZONTAL, B_USE_DEFAULT_SPACING)
.Add(fCaptureSetupBox)
.Add(fFtpSetupBox)
.End()
.Add(fStatusLine)
.End()
.AddGlue();
Show();
}
VideoWindow::~VideoWindow()
{
_QuitSettings();
}
bool
VideoWindow::QuitRequested()
{
be_app->PostMessage(B_QUIT_REQUESTED);
return false;
}
void
VideoWindow::MessageReceived(BMessage* message)
{
BControl* control = NULL;
message->FindPointer((const char*)"source", (void**)&control);
switch (message->what) {
case msg_filename:
if (control != NULL) {
strlcpy(fFtpInfo.fileNameText,
((BTextControl*)control)->Text(), 64);
FTPINFO("file is '%s'\n", fFtpInfo.fileNameText);
}
break;
case msg_rate_changed: {
int32 seconds;
message->FindInt32("seconds", &seconds);
if (seconds == 0) {
FTPINFO("never\n");
fFtpInfo.rate = (bigtime_t)(B_INFINITE_TIMEOUT);
} else {
FTPINFO("%" B_PRId32 " seconds\n", seconds);
fFtpInfo.rate = (bigtime_t)(seconds * 1000000LL);
}
break;
}
case msg_translate:
message->FindInt32("be:type", (int32*)&(fFtpInfo.imageFormat));
message->FindInt32("be:translator", &(fFtpInfo.translator));
break;
case msg_upl_client:
message->FindInt32("client", &(fFtpInfo.uploadClient));
FTPINFO("upl client = %" B_PRId32 "\n", fFtpInfo.uploadClient);
_UploadClientChanged();
break;
case msg_server:
if (control != NULL) {
strlcpy(fFtpInfo.serverText,
((BTextControl*)control)->Text(), 64);
FTPINFO("server = '%s'\n", fFtpInfo.serverText);
}
break;
case msg_login:
if (control != NULL) {
strlcpy(fFtpInfo.loginText,
((BTextControl*)control)->Text(), 64);
FTPINFO("login = '%s'\n", fFtpInfo.loginText);
}
break;
case msg_password:
if (control != NULL) {
strlcpy(fFtpInfo.passwordText,
((BTextControl*)control)->Text(), 64);
FTPINFO("password = '%s'\n", fFtpInfo.passwordText);
}
break;
case msg_directory:
if (control != NULL) {
strlcpy(fFtpInfo.directoryText,
((BTextControl*)control)->Text(), 64);
FTPINFO("directory = '%s'\n", fFtpInfo.directoryText);
}
break;
case msg_passiveftp:
if (control != NULL) {
fFtpInfo.passiveFtp = ((BCheckBox*)control)->Value();
if (fFtpInfo.passiveFtp)
FTPINFO("using passive ftp\n");
}
break;
default:
BWindow::MessageReceived(message);
return;
}
if (*fPortPtr)
write_port(*fPortPtr, FTP_INFO, (void*)&fFtpInfo, sizeof(ftp_msg_info));
}
BView*
VideoWindow::VideoView()
{
return fVideoView;
}
BStringView*
VideoWindow::StatusLine()
{
return fStatusLine;
}
void
VideoWindow::_BuildCaptureControls()
{
// a view to hold the video image
fVideoView = new BView("Video preview", B_WILL_DRAW);
fVideoView->SetExplicitMinSize(BSize(VIDEO_SIZE_X, VIDEO_SIZE_Y));
fVideoView->SetExplicitMaxSize(BSize(VIDEO_SIZE_X, VIDEO_SIZE_Y));
fErrorView = new BTextView("error");
fErrorView->SetViewColor(ui_color(B_PANEL_BACKGROUND_COLOR));
// Capture controls
BGridLayout* controlsLayout = new BGridLayout(B_USE_DEFAULT_SPACING,
B_USE_SMALL_SPACING);
controlsLayout->SetInsets(B_USE_SMALL_SPACING);
BView* controlView = new BView("Controls", B_SUPPORTS_LAYOUT, NULL);
controlView->SetLayout(controlsLayout);
fCaptureSetupBox = new BBox("Capture Controls", B_WILL_DRAW);
fCaptureSetupBox->SetLabel(B_TRANSLATE("Capture controls"));
fCaptureSetupBox->AddChild(controlView);
// file name
fFileName = new BTextControl("File Name", B_TRANSLATE("File name:"),
fFilenameSetting->Value(), new BMessage(msg_filename));
fFileName->SetTarget(BMessenger(NULL, this));
// format menu
fImageFormatMenu = new BPopUpMenu(B_TRANSLATE("Image Format Menu"));
BTranslationUtils::AddTranslationItems(fImageFormatMenu,
B_TRANSLATOR_BITMAP);
fImageFormatMenu->SetTargetForItems(this);
if (fImageFormatSettings->Value()
&& fImageFormatMenu->FindItem(fImageFormatSettings->Value()) != NULL) {
fImageFormatMenu->FindItem(
fImageFormatSettings->Value())->SetMarked(true);
} else if (fImageFormatMenu->FindItem("JPEG image") != NULL)
fImageFormatMenu->FindItem("JPEG image")->SetMarked(true);
else
fImageFormatMenu->ItemAt(0)->SetMarked(true);
fImageFormatSelector = new BMenuField("Format", B_TRANSLATE("Format:"),
fImageFormatMenu);
// capture rate
fCaptureRateMenu = new BPopUpMenu(B_TRANSLATE("Capture Rate Menu"));
for (int32 i = 0; i < kCaptureRatesCount; i++) {
BMessage* itemMessage = new BMessage(msg_rate_changed);
itemMessage->AddInt32("seconds", kCaptureRates[i].seconds);
fCaptureRateMenu->AddItem(new BMenuItem(kCaptureRates[i].name,
itemMessage));
}
fCaptureRateMenu->SetTargetForItems(this);
fCaptureRateMenu->FindItem(fCaptureRateSetting->Value())->SetMarked(true);
fCaptureRateSelector = new BMenuField("Rate", B_TRANSLATE("Rate:"),
fCaptureRateMenu);
BLayoutBuilder::Grid<>(controlsLayout)
.AddTextControl(fFileName, 0, 0)
.AddMenuField(fImageFormatSelector, 0, 1)
.AddMenuField(fCaptureRateSelector, 0, 2)
.Add(BSpaceLayoutItem::CreateGlue(), 0, 3, 2, 1);
// FTP setup box
BGridLayout* ftpLayout = new BGridLayout(B_USE_DEFAULT_SPACING,
B_USE_SMALL_SPACING);
ftpLayout->SetInsets(B_USE_SMALL_SPACING);
BView* outputView = new BView("Output", B_SUPPORTS_LAYOUT, NULL);
outputView->SetLayout(ftpLayout);
fFtpSetupBox = new BBox("FTP Setup", B_WILL_DRAW);
fFtpSetupBox->SetLabel(B_TRANSLATE("Output"));
fFtpSetupBox->AddChild(outputView);
float minWidth = be_plain_font->StringWidth(
"The server label plus ftp.reasonably.com");
fFtpSetupBox->SetExplicitMinSize(BSize(minWidth, B_SIZE_UNSET));
fFtpSetupBox->SetExplicitMaxSize(BSize(B_SIZE_UNLIMITED, B_SIZE_UNSET));
fUploadClientMenu = new BPopUpMenu(B_TRANSLATE("Send to" B_UTF8_ELLIPSIS));
for (int i = 0; i < kUploadClientsCount; i++) {
BMessage* m = new BMessage(msg_upl_client);
m->AddInt32("client", i);
fUploadClientMenu->AddItem(new BMenuItem(kUploadClients[i], m));
}
fUploadClientMenu->SetTargetForItems(this);
fUploadClientMenu->FindItem(fUploadClientSetting->Value())->SetMarked(true);
fUploadClientSelector = new BMenuField("UploadClient", NULL,
fUploadClientMenu);
fUploadClientSelector->SetLabel(B_TRANSLATE("Type:"));
fServerName = new BTextControl("Server", B_TRANSLATE("Server:"),
fServerSetting->Value(), new BMessage(msg_server));
fServerName->SetTarget(this);
fLoginId = new BTextControl("Login", B_TRANSLATE("Login:"),
fLoginSetting->Value(), new BMessage(msg_login));
fLoginId->SetTarget(this);
fPassword = new BTextControl("Password", B_TRANSLATE("Password:"),
fPasswordSetting->Value(), new BMessage(msg_password));
fPassword->SetTarget(this);
fPassword->TextView()->HideTyping(true);
// BeOS HideTyping() seems broken, it empties the text
fPassword->SetText(fPasswordSetting->Value());
fDirectory = new BTextControl("Directory", B_TRANSLATE("Directory:"),
fDirectorySetting->Value(), new BMessage(msg_directory));
fDirectory->SetTarget(this);
fPassiveFtp = new BCheckBox("Passive FTP", B_TRANSLATE("Passive FTP"),
new BMessage(msg_passiveftp));
fPassiveFtp->SetTarget(this);
fPassiveFtp->SetValue(fPassiveFtpSetting->Value());
fPassiveFtp->SetExplicitMaxSize(BSize(B_SIZE_UNLIMITED, B_SIZE_UNSET));
BLayoutBuilder::Grid<>(ftpLayout)
.AddMenuField(fUploadClientSelector, 0, 0)
.AddTextControl(fServerName, 0, 1)
.AddTextControl(fLoginId, 0, 2)
.AddTextControl(fPassword, 0, 3)
.AddTextControl(fDirectory, 0, 4)
.Add(fPassiveFtp, 0, 5, 2, 1);
fStatusLine = new BStringView("Status Line",
B_TRANSLATE("Waiting" B_UTF8_ELLIPSIS));
fStatusLine->SetExplicitMaxSize(BSize(B_SIZE_UNLIMITED, B_SIZE_UNSET));
}
void
VideoWindow::ApplyControls()
{
if (!Lock())
return;
// apply controls
fFileName->Invoke();
PostMessage(fImageFormatMenu->FindMarked()->Message());
PostMessage(fCaptureRateMenu->FindMarked()->Message());
PostMessage(fUploadClientMenu->FindMarked()->Message());
fServerName->Invoke();
fLoginId->Invoke();
fPassword->Invoke();
fDirectory->Invoke();
fPassiveFtp->Invoke();
Unlock();
}
void
VideoWindow::ErrorAlert(const char* message, status_t err)
{
Lock();
fErrorView->SetText(message);
fErrorView->MakeEditable(false);
fErrorView->MakeSelectable(false);
fErrorView->SetWordWrap(true);
fErrorView->SetAlignment(B_ALIGN_CENTER);
fErrorView->SetExplicitMinSize(BSize(VIDEO_SIZE_X, VIDEO_SIZE_Y));
fErrorView->SetExplicitMaxSize(BSize(VIDEO_SIZE_X, VIDEO_SIZE_Y));
fErrorView->Show();
fVideoView->Hide();
Unlock();
printf("%s\n%s [%" B_PRIx32 "]", message, strerror(err), err);
}
void
VideoWindow::_SetUpSettings(const char* filename, const char* dirname)
{
fSettings = new Settings(filename, dirname);
fServerSetting = new StringValueSetting("Server", "ftp.my.server",
B_TRANSLATE("server address expected"));
fLoginSetting = new StringValueSetting("Login", "loginID",
B_TRANSLATE("login ID expected"));
fPasswordSetting = new StringValueSetting("Password",
B_TRANSLATE("password"), B_TRANSLATE("password expected"));
fDirectorySetting = new StringValueSetting("Directory", "web/images",
B_TRANSLATE("destination directory expected"));
fPassiveFtpSetting = new BooleanValueSetting("PassiveFtp", 1);
fFilenameSetting = new StringValueSetting("StillImageFilename",
"codycam.jpg", B_TRANSLATE("still image filename expected"));
fImageFormatSettings = new StringValueSetting("ImageFileFormat",
B_TRANSLATE("JPEG image"), B_TRANSLATE("image file format expected"));
fCaptureRateSetting = new EnumeratedStringValueSetting("CaptureRate",
kCaptureRates[3].name, &CaptureRateAt,
B_TRANSLATE("capture rate expected"),
"unrecognized capture rate specified");
fUploadClientSetting = new EnumeratedStringValueSetting("UploadClient",
B_TRANSLATE("FTP"), &UploadClientAt,
B_TRANSLATE("upload client name expected"),
B_TRANSLATE("unrecognized upload client specified"));
fSettings->Add(fServerSetting);
fSettings->Add(fLoginSetting);
fSettings->Add(fPasswordSetting);
fSettings->Add(fDirectorySetting);
fSettings->Add(fPassiveFtpSetting);
fSettings->Add(fFilenameSetting);
fSettings->Add(fImageFormatSettings);
fSettings->Add(fCaptureRateSetting);
fSettings->Add(fUploadClientSetting);
fSettings->TryReadingSettings();
}
void
VideoWindow::_UploadClientChanged()
{
bool enableServerControls = fFtpInfo.uploadClient < 2;
fServerName->SetEnabled(enableServerControls);
fLoginId->SetEnabled(enableServerControls);
fPassword->SetEnabled(enableServerControls);
fDirectory->SetEnabled(enableServerControls);
fPassiveFtp->SetEnabled(enableServerControls);
}
void
VideoWindow::_QuitSettings()
{
fServerSetting->ValueChanged(fServerName->Text());
fLoginSetting->ValueChanged(fLoginId->Text());
fPasswordSetting->ValueChanged(fFtpInfo.passwordText);
fDirectorySetting->ValueChanged(fDirectory->Text());
fPassiveFtpSetting->ValueChanged(fPassiveFtp->Value());
fFilenameSetting->ValueChanged(fFileName->Text());
fImageFormatSettings->ValueChanged(fImageFormatMenu->FindMarked()->Label());
fCaptureRateSetting->ValueChanged(fCaptureRateMenu->FindMarked()->Label());
fUploadClientSetting->ValueChanged(
fUploadClientMenu->FindMarked()->Label());
fSettings->SaveSettings();
delete fSettings;
}
void
VideoWindow::ToggleMenuOnOff()
{
BMenuItem* item = fMenu->FindItem(msg_video);
item->SetEnabled(!item->IsEnabled());
item = fMenu->FindItem(msg_start);
item->SetEnabled(!item->IsEnabled());
item = fMenu->FindItem(msg_stop);
item->SetEnabled(!item->IsEnabled());
}
// #pragma mark -
ControlWindow::ControlWindow(BView* controls,
media_node node)
:
BWindow(controls->Bounds().OffsetToSelf(100, 100),
B_TRANSLATE("Video settings"), B_TITLED_WINDOW,
B_ASYNCHRONOUS_CONTROLS)
{
fView = controls;
fNode = node;
AddChild(fView);
}
void
ControlWindow::MessageReceived(BMessage* message)
{
BParameterWeb* web = NULL;
status_t err;
switch (message->what) {
case B_MEDIA_WEB_CHANGED:
{
// If this is a tab view, find out which tab
// is selected
BTabView* tabView = dynamic_cast<BTabView*>(fView);
int32 tabNum = -1;
if (tabView)
tabNum = tabView->Selection();
RemoveChild(fView);
delete fView;
err = BMediaRoster::Roster()->GetParameterWebFor(fNode, &web);
if (err >= B_OK && web != NULL) {
fView = BMediaTheme::ViewFor(web);
AddChild(fView);
// Another tab view? Restore previous selection
if (tabNum > 0) {
BTabView* newTabView = dynamic_cast<BTabView*>(fView);
if (newTabView)
newTabView->Select(tabNum);
}
}
break;
}
default:
BWindow::MessageReceived(message);
break;
}
}
bool
ControlWindow::QuitRequested()
{
be_app->PostMessage(msg_control_win);
return true;
}
// #pragma mark -
int main()
{
CodyCam app;
app.Run();
return 0;
}